From 7720522a32d6736ac9d35bdf69c637d2c54829bb Mon Sep 17 00:00:00 2001 From: portakal Date: Mon, 25 May 2026 20:07:14 +0300 Subject: [PATCH] stage 0 database schema ready --- .gitignore | 6 +- backend/databaseDirect.go | 63 +- backend/db/config/queries.sql | 336 ++++++++ backend/db/config/queries.txt | 218 +++++ backend/db/config/schema.sql | 260 ++++++ backend/db/config/schema.txt | 254 ++++++ backend/db/config/sqlc.yml | 9 + backend/db/db.go | 31 + backend/db/models.go | 704 ++++++++++++++++ backend/db/queries.sql.go | 1436 ++++++++++++++++++++++++++++++++ backend/server/homepage.go | 204 +++++ backend/server/login.go | 205 +++++ backend/server/main.go | 182 +++++ backend/utils/packet_utils.go | 77 ++ backend/utils/packets.pb.go | 1441 +++++++++++++++++++++++++++++++++ go.mod | 33 + go.sum | 75 ++ shared/packets.proto | 47 ++ 18 files changed, 5577 insertions(+), 4 deletions(-) create mode 100644 backend/db/config/queries.sql create mode 100644 backend/db/config/queries.txt create mode 100644 backend/db/config/schema.sql create mode 100644 backend/db/config/schema.txt create mode 100644 backend/db/config/sqlc.yml create mode 100644 backend/db/db.go create mode 100644 backend/db/models.go create mode 100644 backend/db/queries.sql.go create mode 100644 backend/server/main.go create mode 100644 backend/utils/packets.pb.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 shared/packets.proto diff --git a/.gitignore b/.gitignore index 72af65e..6f83418 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,6 @@ go.work.sum .env # Editor/IDE -# .idea/ -# .vscode/ - +.idea/ +.vscode/ +gitpushlink diff --git a/backend/databaseDirect.go b/backend/databaseDirect.go index 2480943..a7d79e9 100644 --- a/backend/databaseDirect.go +++ b/backend/databaseDirect.go @@ -1 +1,62 @@ -package backend +package main + +import ( + "context" + "database/sql" + "fmt" + "os" + "skyrama_clone_backend/backend/db" + + _ "github.com/go-sql-driver/mysql" // MySQL Driver + "golang.org/x/crypto/bcrypt" +) + +func create_user(queries *db.Queries, ctx context.Context, username string, password string) { + + hashedPass, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + + resultt, err := queries.CreateUser(ctx, db.CreateUserParams{ + Username: username, + PasswordHash: string(hashedPass), + }) + if err != nil { + fmt.Printf("Error at operation : %v\n", err) + os.Exit(1) + } + fmt.Println(resultt) + fmt.Printf("added user : %s ", username) +} +func update_user(queries *db.Queries, ctx context.Context, username string, password string) { + + hashed_pass, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + + err := queries.UpdateUserPasswordByUserName(ctx, db.UpdateUserPasswordByUserNameParams{ + PasswordHash: string(hashed_pass), + Username: username, + }) + if err != nil { + fmt.Printf("Error at operation : %v\n", err) + os.Exit(1) + } + fmt.Printf("updated user : %s with %s \n", username, string(hashed_pass)) + fmt.Println("successfully updated user") +} + +func main() { + + dsn := "skyramaUser:Skyrama1234.@tcp(127.0.0.1:3306)/skyrama_clone?parseTime=true" + dbConn, err := sql.Open("mysql", dsn) + if err != nil { + fmt.Printf("Error opening database pool: %v\n", err) + os.Exit(1) + } + defer dbConn.Close() + if err := dbConn.Ping(); err != nil { + fmt.Printf("Database unreachable: %v\n", err) + os.Exit(1) + } + ctx := context.Background() + queries := db.New(dbConn) + create_user(queries, ctx, "tester_adnan", "a") + //update_user(queries, ctx, "tester_adnan", "a") +} diff --git a/backend/db/config/queries.sql b/backend/db/config/queries.sql new file mode 100644 index 0000000..29e807a --- /dev/null +++ b/backend/db/config/queries.sql @@ -0,0 +1,336 @@ +-- ============================================================================ +-- 1. AUTHENTICATION & USERS +-- ============================================================================ + +-- name: CreateUser :execresult +INSERT INTO users (username, password_hash) +VALUES (?, ?); + +-- name: UpdateUserPasswordByUserName :exec +UPDATE users +SET password_hash = ? +WHERE username = ?; + +-- name: GetUserByUsername :one +SELECT id, username, password_hash +FROM users +WHERE username = ? LIMIT 1; + +-- name: GetUserIdByUsername :one +SELECT id +FROM users +WHERE username = ? LIMIT 1; + +-- name: DeleteUserByUsername :exec +UPDATE users +SET deleted_at = CURRENT_TIMESTAMP +WHERE username = ?; + + +-- name: DeleteAirportByUserName :exec +UPDATE airports +SET is_deleted = TRUE +WHERE user_id = (SELECT id FROM users WHERE username = ?); + +-- ============================================================================ +-- 2. AIRPORT CORE MANAGEMENT +-- ============================================================================ + +-- airport row management + +-- name: CreateAirportByUserName :execresult +INSERT INTO airports (name, user_id, origin_country_id) +VALUES (?, (SELECT id FROM users WHERE username = ?), ?); + + +-- name: GetAirportByUserId :one +SELECT id, name, user_id, origin_country_id, cash, current_passengers, max_passenger_capacity, current_fuel, max_fuel_capacity, is_available, player_level, experience_points, passenger_generation_rate, fuel_generation_rate, resources_last_updated_at, is_deleted +FROM airports +WHERE user_id = ? LIMIT 1; +-- name: GetAirportByUserName :one +SELECT id, name, user_id, origin_country_id, cash, current_passengers, max_passenger_capacity, current_fuel, max_fuel_capacity, is_available, player_level, experience_points ,passenger_generation_rate, fuel_generation_rate, resources_last_updated_at, is_deleted +FROM airports +WHERE user_id = (SELECT id FROM users WHERE username = ?) LIMIT 1; + + +-- airport resource management + + +-- name: UpdateAirportCurrencies :exec +UPDATE airports +SET cash = ?, + current_passengers = ?, + current_fuel = ? +WHERE id = ?; + +-- name: UpdateAirportResources :exec +UPDATE airports +SET + current_fuel = LEAST( + max_fuel_capacity, + current_fuel + (fuel_generation_rate * TIMESTAMPDIFF(SECOND, resources_last_updated_at, NOW())) + ), + current_passengers = LEAST( + max_passenger_capacity, + current_passengers + (passenger_generation_rate * TIMESTAMPDIFF(SECOND, resources_last_updated_at, NOW())) + ), + resources_last_updated_at = NOW() +WHERE id = ?; + +-- name: UpdateAirportCash :exec +UPDATE airports +SET cash = ? +WHERE id = ?; +-- name: UpdateAirportpassengers :exec +UPDATE airports +SET current_passengers = ? +WHERE id = ?; +-- name: UpdateAirportFuel :exec +UPDATE airports +SET current_fuel = ? +WHERE id = ?; +-- name: UpdateAirportmaxPassengers :exec +UPDATE airports +SET max_passenger_capacity = ? +WHERE id = ?; +-- name: UpdateAirportMaxFuel :exec +UPDATE airports +SET max_fuel_capacity = ? +WHERE id = ?; + +-- name: UpdateAirportFuelRate :exec +UPDATE airports +SET fuel_generation_rate = ? +WHERE id = ?; +-- name: UpdateAirportPassengerRate :exec +UPDATE airports +SET passenger_generation_rate = ? +WHERE id = ?; + +-- name: UpdateAirportResourcesUpdated :exec +update airports +set resources_last_updated_at = ? +where id = ?; + + +-- name: updatePlayerExperience :exec +UPDATE airports +SET experience_points = ? +WHERE id = ?; + +-- name: updatePlayerLevel :exec +UPDATE airports +SET player_level = ? +WHERE id = ?; + + + +-- ============================================================================ +-- 3. WAREHOUSE & INVENTORY SYSTEM +-- ============================================================================ + + +-- ============================================================================ +-- 4. BUILDINGS & PRODUCTION ENGINE +-- ============================================================================ + +-- name: addStorageBuilding :execresult +INSERT INTO buildings (name,min_level,construction_cost_cash,capacity,storage_type,storage_subtype) +VALUES (?, ?, ?, ?, ?, ?); + +-- name: addOperationalBuilding :execresult +INSERT INTO buildings (name,min_level,construction_cost_cash,operation_type,operation_size) +VALUES (?, ?, ?, ?, ?); + +-- name: addPassiveProductionBuilding :execresult +INSERT INTO buildings (name,min_level,construction_cost_cash,passive_type,passive_rate) +VALUES (?, ?, ?, ?, ?); + +-- name: addBuilding :execresult +INSERT INTO buildings (name,min_level,construction_cost_cash) +VALUES (?, ?, ?); + + +-- name: AddBuildingToAirportByUsername :execresult +INSERT INTO airport_buildings (airport_id, building_id) +VALUES ((select id from airports where user_id = (select id from users where username = ?)), ?); + +-- name: GetAirportBuildingsByUsername :many +SELECT ab.id AS airport_building_id,b.building_type , b.* +FROM airport_buildings ab +JOIN buildings b ON ab.building_id = b.id +WHERE ab.airport_id = (select id from airports where user_id = (select id from users where username = ?)); + + + +-- planes & fleet management + +-- name: addPlane :execresult +INSERT INTO planes (name, aircraft_size,operation_type,aircraft_type ,min_level, operation_cost_fuel, operation_cost_cash, max_passengers, travel_time_inSeconds,buying_cost_cash, completed_flight_experience, completed_flight_cash_reward, completed_flight_cargo_reward) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + +-- name: GetPlaneById :one +SELECT * FROM planes WHERE id = ?; + +-- name: GetAllPlanes :many +SELECT * FROM planes; + +-- name: GetPlanesByOperationType :many +SELECT * FROM planes WHERE operation_type = ?; + +-- name: GetPlanesByMinLevel :many +SELECT * FROM planes WHERE min_level <= ?; + +-- name: GetPlanesByAircraftSize :many +SELECT * FROM planes WHERE aircraft_size = ?; + +-- name: GetPlanesByAircraftType :many +SELECT * FROM planes WHERE aircraft_type = ?; + +-- name: addPlaneToAirportByUsername :execresult +INSERT INTO player_planes (airport_id, plane_id, assigned_hangar_id, current_building_id, status) +VALUES ((select id from airports where user_id = (select id from users where username = ?)), ?, ?, ?, 'idle'); + +-- name: GetPlayerPlanesByUsername :many +SELECT pp.id AS player_plane_id, pp.* +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.airport_id = (select id from airports where user_id = (select id from users where username = ?)); + + +-- name: FindAvailableInfrastructureForPlane :one +SELECT ab.id +FROM airport_buildings ab +JOIN buildings b ON ab.building_id = b.id +LEFT JOIN player_planes pp ON ab.id = pp.current_building_id +WHERE ab.airport_id = (select id from airports where user_id = (select id from users where username = ?)) + AND b.operation_type = ? -- 'runway' or 'service' (service bay) + AND b.operation_size = ? -- matches plane's aircraft_size requirement + AND pp.id IS NULL -- Ensures no other plane is physically here right now +LIMIT 1; + +-- name: UpdatePlayerPlaneState :exec +UPDATE player_planes +SET current_building_id = ?, + status = ?, + flight_start_time = ? +WHERE id = ?; + +-- name: CheckHangarOccupancyByUsername :one +SELECT COUNT(*) AS total_parked +FROM player_planes pp +JOIN airport_buildings ab ON pp.current_building_id = ab.id +WHERE ab.airport_id = (select id from airports where user_id = (select id from users where username = ?)) + AND ab.building_id = ?; -- specific hangar + + -- +-- name: CheckRunwayOccupancyByUsername :one +SELECT COUNT(*) AS total_occupied +FROM player_planes pp +JOIN airport_buildings ab ON pp.current_building_id = ab.id +WHERE ab.airport_id = (select id from airports where user_id = (select id from users where username = ?)) + AND ab.building_id = ?; -- specific runway + +-- name: GetPlanesReadyToLandByUsername :many +SELECT pp.id AS player_plane_id, pp.airport_id, pp.assigned_hangar_id, + p.completed_flight_experience, p.completed_flight_cash_reward, p.completed_flight_cargo_reward, p.operation_type +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.status = 'flying' + AND ADDTIME(pp.flight_start_time, p.travel_time) <= NOW() + AND pp.airport_id = (select id from airports where user_id = (select id from users where username = ?)); + + + + + + + + + + + + + + + +-- ============================================================================ +-- 5. FLEET & DYNAMIC INFRASTRUCTURE OPERATIONS +-- ============================================================================ + +-- name: BuyPlaneForPlayer :execresult +INSERT INTO player_planes (airport_id, plane_id, assigned_hangar_id, current_building_id, status) +VALUES (?, ?, ?, ?, 'idle'); + +-- name: GetPlayerFleet :many +SELECT pp.id AS player_plane_id, pp.status, pp.updated_at, pp.flight_start_time, pp.current_building_id, pp.assigned_hangar_id,p.* +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.airport_id = ?; + +-- name: FindAvailableInfrastructure :one +SELECT ab.id +FROM airport_buildings ab +JOIN buildings b ON ab.building_id = b.id +LEFT JOIN player_planes pp ON ab.id = pp.current_building_id +WHERE ab.airport_id = ? + AND b.operation_type = ? -- 'runway' or 'service' (service bay) + AND b.operation_size = ? -- matches plane's aircraft_size requirement + AND pp.id IS NULL -- Ensures no other plane is physically here right now +LIMIT 1; + +-- name: UpdatePlaneState :exec +UPDATE player_planes +SET current_building_id = ?, + status = ?, + + flight_start_time = ? +WHERE id = ?; + +-- name: CheckHangarOccupancy :one +SELECT COUNT(*) AS total_parked +FROM player_planes +WHERE current_building_id = ?; + + +-- ============================================================================ +-- 6. TIME-BASED FLIGHT ENGINE +-- ============================================================================ + +-- name: GetPlanesReadyToLand :many +SELECT pp.id AS player_plane_id, pp.airport_id, pp.assigned_hangar_id, + p.completed_flight_experience, p.completed_flight_cash_reward, p.completed_flight_cargo_reward, p.operation_type +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.status = 'flying' + -- Uses your logic: flight_start_time + plane travel duration <= current clock + AND ADDTIME(pp.flight_start_time, p.travel_time) <= NOW(); + + +-- ============================================================================ +-- 7. PROGRESSION CONTRACTS & ECONOMY LOGS +-- ============================================================================ + +-- name: GetActiveContracts :many +SELECT id, title, required_product_id, required_amount, current_amount_delivered, is_completed, expires_at +FROM airport_contracts +WHERE airport_id = ? AND is_completed = FALSE AND expires_at > NOW(); + +-- name: UpdateContractDelivery :exec +UPDATE airport_contracts +SET current_amount_delivered = current_amount_delivered + ? +WHERE id = ? AND is_completed = FALSE; + +-- name: CompleteContract :exec +UPDATE airport_contracts +SET is_completed = TRUE +WHERE id = ?; + +-- name: LogCurrencyTransaction :exec +INSERT INTO currency_transaction_logs (airport_id, amount_changed, currency_type, reason) +VALUES (?, ?, ?, ?); + +-- name: LogCompletedFlightRoute :exec +INSERT INTO completed_flight_routes_log (origin_airport_id, destination_airport_id, start_time, end_time) +VALUES (?, ?, ?, NOW()); \ No newline at end of file diff --git a/backend/db/config/queries.txt b/backend/db/config/queries.txt new file mode 100644 index 0000000..d05a031 --- /dev/null +++ b/backend/db/config/queries.txt @@ -0,0 +1,218 @@ +-- ============================================================================ +-- 1. AUTHENTICATION & USERS +-- ============================================================================ + +-- name: CreateUser :execresult +INSERT INTO users (username, password_hash) +VALUES (?, ?); + +-- name: UpdateUserPasswordByUserName :exec +UPDATE users +SET password_hash = ? +WHERE username = ?; + +-- name: GetUserByUsername :one +SELECT id, username, password_hash, created_at +FROM users +WHERE username = ? LIMIT 1; + +-- name: GetUserIdByUsername :one +SELECT id +FROM users +WHERE username = ? LIMIT 1; + +-- ============================================================================ +-- 2. AIRPORT CORE MANAGEMENT +-- ============================================================================ + +-- airport row management + +-- name: CreateAirportByUserName :execresult +INSERT INTO airports (name, user_id, origin_country_id) +VALUES (?, (SELECT id FROM users WHERE username = ?), ?); + + +-- name: GetAirportByUserId :one +SELECT id, name, user_id, origin_country_id, cash, current_passengers, max_passenger_capacity, current_fuel, max_fuel_capacity, is_available, player_level, experience_points, passenger_generation_rate, fuel_generation_rate, resources_last_updated_at +FROM airports +WHERE user_id = ? LIMIT 1; +-- name: GetAirportByUserName :one +SELECT id, name, user_id, origin_country_id, cash, current_passengers, max_passenger_capacity, current_fuel, max_fuel_capacity, is_available, player_level, experience_points ,passenger_generation_rate, fuel_generation_rate, resources_last_updated_at +FROM airports +WHERE user_id = (SELECT id FROM users WHERE username = ?) LIMIT 1; + + +-- airport resource management + + +-- name: UpdateAirportCurrencies :exec +UPDATE airports +SET cash = ?, + current_passengers = ?, + current_fuel = ? +WHERE id = ?; + +-- name: UpdateAirportCash :exec +UPDATE airports +SET cash = ? +WHERE id = ?; +-- name: UpdateAirportpassengers :exec +UPDATE airports +SET current_passengers = ? +WHERE id = ?; +-- name: UpdateAirportFuel :exec +UPDATE airports +SET current_fuel = ? +WHERE id = ?; +-- name: UpdateAirportmaxPassengers :exec +UPDATE airports +SET max_passenger_capacity = ? +WHERE id = ?; +-- name: UpdateAirportMaxFuel :exec +UPDATE airports +SET max_fuel_capacity = ? +WHERE id = ?; + +-- name: UpdateAirportFuelRate :exec +UPDATE airports +SET fuel_generation_rate = ? +WHERE id = ?; +-- name: UpdateAirportPassengerRate :exec +UPDATE airports +SET passenger_generation_rate = ? +WHERE id = ?; + +-- name: UpdateAirportResourcesUpdated :exec +update airports +set resources_last_updated_at = ? +where id = ?; + + +-- name: updatePlayerExperience :exec +UPDATE airports +SET experience_points = ?, +WHERE id = ?; + +-- name: updatePlayerLevel :exec +UPDATE airports +SET player_level = ? +WHERE id = ?; + + + +-- ============================================================================ +-- 3. WAREHOUSE & INVENTORY SYSTEM +-- ============================================================================ + + +-- ============================================================================ +-- 4. BUILDINGS & PRODUCTION ENGINE +-- ============================================================================ + +-- name: addStorageBuilding:execresult +INSERT INTO buildings (name,min_level,construction_cost_cash,capacity,storage_type,storage_subtype) +VALUES (?, ?, ?, ?, ?, ?); + +-- name: addOperationalBuilding:execresult +INSERT INTO buildings (name,min_level,construction_cost_cash,operation_type,operation_size) +VALUES (?, ?, ?, ?, ?); + +-- name: addPassiveProductionBuilding:execresult +INSERT INTO buildings (name,min_level,construction_cost_cash,currency_type,income_rate) +VALUES (?, ?, ?, ?, ?); + +-- name: addProductionBuilding:execresult +INSERT INTO buildings (name,min_level,construction_cost_cash,recipe_id,storage_1,storage_2,storage_3) +VALUES (?, ?, ?, ?, ?, ?, ?); + + +-- name: AddBuildingToAirport :execresult +INSERT INTO airport_buildings (airport_id, building_id, level) +VALUES ((select id from airports where user_id = (select id from users where username = ?)), ?, 1); + +-- name: GetAirportBuildings :many +SELECT ab.id AS airport_building_id, ab.level, b.* +FROM airport_buildings ab +JOIN buildings b ON ab.building_id = b.id +WHERE ab.airport_id = (select id from airports where user_id = (select id from users where username = ?)); + +-- ============================================================================ +-- 5. FLEET & DYNAMIC INFRASTRUCTURE OPERATIONS +-- ============================================================================ + +-- name: BuyPlaneForPlayer :execresult +INSERT INTO player_planes (airport_id, plane_id, assigned_hangar_id, current_building_id, status) +VALUES (?, ?, ?, ?, 'idle'); + +-- name: GetPlayerFleet :many +SELECT pp.id AS player_plane_id, pp.status, pp.updated_at, pp.flight_start_time, pp.current_building_id, pp.assigned_hangar_id, pp.assigned_cargo_id, + p.* +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.airport_id = ?; + +-- name: FindAvailableInfrastructure :one +SELECT ab.id +FROM airport_buildings ab +JOIN buildings b ON ab.building_id = b.id +LEFT JOIN player_planes pp ON ab.id = pp.current_building_id +WHERE ab.airport_id = ? + AND b.operation_type = ? -- 'runway' or 'service' (service bay) + AND b.operation_size = ? -- matches plane's aircraft_size requirement + AND pp.id IS NULL -- Ensures no other plane is physically here right now +LIMIT 1; + +-- name: UpdatePlaneState :exec +UPDATE player_planes +SET current_building_id = ?, + status = ?, + assigned_cargo_id = ?, + flight_start_time = ? +WHERE id = ?; + +-- name: CheckHangarOccupancy :one +SELECT COUNT(*) AS total_parked +FROM player_planes +WHERE current_building_id = ?; + + +-- ============================================================================ +-- 6. TIME-BASED FLIGHT ENGINE +-- ============================================================================ + +-- name: GetPlanesReadyToLand :many +SELECT pp.id AS player_plane_id, pp.airport_id, pp.assigned_hangar_id, + p.completed_flight_experience, p.completed_flight_cash_reward, p.completed_flight_cargo_reward, p.operation_type, pp.assigned_cargo_id +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.status = 'flying' + -- Uses your logic: flight_start_time + plane travel duration <= current clock + AND ADDTIME(pp.flight_start_time, p.travel_time) <= NOW(); + + +-- ============================================================================ +-- 7. PROGRESSION CONTRACTS & ECONOMY LOGS +-- ============================================================================ + +-- name: GetActiveContracts :many +SELECT id, title, required_product_id, required_amount, current_amount_delivered, is_completed, expires_at +FROM airport_contracts +WHERE airport_id = ? AND is_completed = FALSE AND expires_at > NOW(); + +-- name: UpdateContractDelivery :exec +UPDATE airport_contracts +SET current_amount_delivered = current_amount_delivered + ? +WHERE id = ? AND is_completed = FALSE; + +-- name: CompleteContract :exec +UPDATE airport_contracts +SET is_completed = TRUE +WHERE id = ?; + +-- name: LogCurrencyTransaction :exec +INSERT INTO currency_transaction_logs (airport_id, amount_changed, currency_type, reason) +VALUES (?, ?, ?, ?); + +-- name: LogCompletedFlightRoute :exec +INSERT INTO completed_flight_routes_log (origin_airport_id, destination_country_id, start_time, end_time) +VALUES (?, ?, ?, NOW()); \ No newline at end of file diff --git a/backend/db/config/schema.sql b/backend/db/config/schema.sql new file mode 100644 index 0000000..2df8931 --- /dev/null +++ b/backend/db/config/schema.sql @@ -0,0 +1,260 @@ +-- stages +-- stage 0 : launch planes to country's base airport (accepts everyhing sendds nothing back) +-- stage 1 : add NPCs and cargo planes and shop buildings. +-- stage 2 : add player progression, building upgrades, effects and more complex recipes. +-- stage 3 : TBD + + + +-- good +CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + username varchar(255) NOT NULL UNIQUE, + password_hash TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP DEFAULT NULL +); + +-- product table act as a product identifier ie egg, milk, flour etc +create table if not exists products ( + id smallint unsigned primary key auto_increment, + name varchar(255) not null +); + +-- for stage 2 will not be used +-- increasing speed (crafting,currency type generation etc)), +CREATE table if not exists effects ( + id smallint unsigned primary key auto_increment, + name varchar(255) not null +); + +-- used airport grouping and for contracts, each country has 3 produce they can export there will not be cap +create table if not exists countries ( + id smallint unsigned primary key auto_increment, + name varchar(255) not null, + continent ENUM('void','Africa', 'Antarctica', 'Asia', 'Europe', 'North America', 'Oceania', 'South America') NOT NULL, -- universal enum + produce_1_id smallint unsigned not null, + produce_2_id smallint unsigned not null, + produce_3_id smallint unsigned not null, + foreign key (produce_1_id) references products(id), + foreign key (produce_2_id) references products(id), + foreign key (produce_3_id) references products(id) +); + +-- main table +-- primary access table act as a player identifier, each player can only have one airport, but they can have multiple planes and buildings +create table if not exists airports ( + id integer unsigned primary key auto_increment, + name varchar(255) not null, + user_id integer unique not null, + origin_country_id smallint unsigned not null, + -- resources + cash bigint unsigned not null default 100, + current_passengers INTEGER UNSIGNED NOT NULL DEFAULT 100, + max_passenger_capacity INTEGER UNSIGNED NOT NULL DEFAULT 100, + current_fuel INTEGER UNSIGNED NOT NULL DEFAULT 500, + max_fuel_capacity INTEGER UNSIGNED NOT NULL DEFAULT 1000, + -- resource generation + fuel_generation_rate INT UNSIGNED NOT NULL DEFAULT 20, + passenger_generation_rate INT UNSIGNED NOT NULL DEFAULT 5, + resources_last_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + -- progression + is_available boolean not null default true, -- if true can be sent planes from anyone + player_level integer unsigned not null default 1, + experience_points bigint unsigned not null default 0, + is_deleted BOOLEAN DEFAULT FALSE, + foreign key (origin_country_id) references countries(id), + foreign key (user_id) references users(id), + constraint chk_fuel_capacity CHECK (current_fuel <= max_fuel_capacity), + constraint chk_positive_fuel CHECK (current_fuel >= 0), + CONSTRAINT chk_passenger_capacity CHECK (current_passengers <= max_passenger_capacity), + CONSTRAINT chk_positive_passenger CHECK (current_passengers >= 0) +); + + +-- for stage 1, used as template for recipes. +create table if not exists recipes ( + id integer unsigned primary key auto_increment, + name varchar(255) not null, + ingredient_1_id smallint unsigned , + ingredient_1_amount integer unsigned , + ingredient_2_id smallint unsigned, + ingredient_2_amount integer unsigned , + ingredient_3_id smallint unsigned , + ingredient_3_amount integer unsigned , + product_id smallint unsigned not null, + yield_amount integer unsigned not null, + foreign key (ingredient_1_id) references products(id), + foreign key (ingredient_2_id) references products(id), + foreign key (ingredient_3_id) references products(id), + foreign key (product_id) references products(id) +); + + + + + +-- BUILDNGS + +-- hangars fuel tanks etc +CREATE table if not exists buildings ( + -- shared + id integer unsigned primary key auto_increment, + name varchar(255) not null, + min_level integer unsigned not null DEfAULT 1, + construction_cost_cash integer unsigned not null default 100, + upgrade_tier TINYINT UNSIGNED DEFAULT 0, + upgrade_cost_cash_to_uptier integer unsigned default null, + building_type ENUM('none','storage', 'support', 'operation', 'passive', 'shop', 'production') not null, + -- production specific + -- storage + capacity integer unsigned , + storage_type ENUM( 'fuel' , 'plane', 'product'), + storage_subtype ENUM('none', 'airplane', 'helicopter', 'seaplane','spaceship'), + -- support + effect_id smallint unsigned, + effect_value integer, + -- operation + operation_size enum('small','medium' ,'large', 'huge'), + operation_type enum('runway', 'service', 'production'), + + -- passive income + passive_type enum('passengers', 'fuel'), + passive_rate integer , + + foreign key (effect_id) references effects(id) + + ); + +-- stage 1 +create table if not exists building_products ( + id integer unsigned primary key auto_increment, + building_id integer unsigned not null, + + recipe_id integer unsigned, + storage_product integer unsigned , + storage_1 integer unsigned , + storage_2 integer unsigned , + storage_3 integer unsigned , + foreign key (building_id) references buildings(id), + foreign key (recipe_id) references recipes(id) +); + + +-- many to many relation between airport and buildings +create table if not exists airport_buildings ( + id integer unsigned primary key auto_increment, + airport_id integer unsigned not null, + building_id integer unsigned not null, + -- shop specific + recipe_id integer unsigned , + storage_product integer unsigned , + storage_1 integer unsigned , + storage_2 integer unsigned , + storage_3 integer unsigned , + level integer unsigned not null default 1, + foreign key (airport_id) references airports(id) , + foreign key (building_id) references buildings(id) +); + + + + +-- planes +-- template for planes +create table if not exists planes ( + id integer unsigned primary key auto_increment, + name varchar(255) not null, + min_level integer unsigned not null default 1, + operation_cost_fuel integer unsigned not null, + operation_cost_cash integer unsigned not null DEFAULT 10, + max_passengers integer unsigned, + travel_time_inSeconds integer unsigned not null, + operation_type enum('passenger', 'cargo') not null, + aircraft_size enum('small', 'medium', 'large', 'huge') not null, + aircraft_type enum('plane', 'helicopter', 'seaplane','spaceship') not null, + buying_cost_cash integer unsigned not null DEFAULT 100, + completed_flight_experience integer unsigned not null DEFAULT 20, + completed_flight_cash_reward integer unsigned DEFAULT 50, + completed_flight_cargo_reward integer unsigned DEFAULT null + +); + +-- actual planes owned by players, tracks location, status, assigned hangar etc +CREATE TABLE IF NOT EXISTS player_planes ( + id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + airport_id INT UNSIGNED NOT NULL, + plane_id INTEGER UNSIGNED NOT NULL, + + -- 1. assignment (Must always point to a hangar they own they move between suitable hangars) + assigned_hangar_id INT UNSIGNED NOT NULL, + + -- 2. Real-time physical location (stored, Service Bay, Runway, or NULL if flying) + current_building_id INT UNSIGNED DEFAULT NULL, + -- assigned_cargo_id INTEGER UNSIGNED DEFAULT NULL, -- stage 1 For cargo planes, track what they're carrying + + status ENUM('idle', 'maintenance', 'boarding', 'taxiing', 'flying') NOT NULL DEFAULT 'idle', + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + flight_start_time TIMESTAMP NULL DEFAULT NULL, + + + FOREIGN KEY (airport_id) REFERENCES airports(id), + FOREIGN KEY (plane_id) REFERENCES planes(id), + FOREIGN KEY (assigned_hangar_id) REFERENCES airport_buildings(id), + FOREIGN KEY (current_building_id) REFERENCES airport_buildings(id) + +); + +-- stage 1 +CREATE TABLE IF NOT EXISTS airport_inventory ( + airport_id INTEGER unsigned NOT NULL, + product_id SMALLINT UNSIGNED NOT NULL, + quantity INTEGER UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (airport_id, product_id), + FOREIGN KEY (airport_id) REFERENCES airports(id), + FOREIGN KEY (product_id) REFERENCES products(id) +); + + +-- stage ? tbd +CREATE TABLE IF NOT EXISTS airport_contracts ( + id INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT, + airport_id INTEGER unsigned NOT NULL, + title VARCHAR(255) NOT NULL, + + -- What they need to deliver + required_product_id SMALLINT UNSIGNED NOT NULL, + required_amount INTEGER UNSIGNED NOT NULL, + current_amount_delivered INTEGER UNSIGNED NOT NULL DEFAULT 0, + + + -- Status + is_completed BOOLEAN NOT NULL DEFAULT FALSE, + expires_at TIMESTAMP NOT NULL, + + FOREIGN KEY (airport_id) REFERENCES airports(id), + FOREIGN KEY (required_product_id) REFERENCES products(id) + +); + + +-- logs + +create table if not exists completed_flight_routes_log ( + id integer unsigned primary key auto_increment, + origin_airport_id integer unsigned not null, + destination_airport_id integer unsigned not null, + start_time timestamp not null default current_timestamp, + end_time timestamp default null, + foreign key (origin_airport_id) references airports(id), + foreign key (destination_airport_id) references airports(id) +); +CREATE TABLE IF NOT EXISTS currency_transaction_logs ( + id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + airport_id INT UNSIGNED NOT NULL, + amount_changed INT NOT NULL, -- Negative for buying, positive for earning + currency_type ENUM('cash', 'fuel', 'passengers') NOT NULL, + reason VARCHAR(255) NOT NULL, -- e.g., 'bought_plane_id_12', 'completed_flight_34' + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (airport_id) REFERENCES airports(id) +); \ No newline at end of file diff --git a/backend/db/config/schema.txt b/backend/db/config/schema.txt new file mode 100644 index 0000000..9509b93 --- /dev/null +++ b/backend/db/config/schema.txt @@ -0,0 +1,254 @@ +-- stages +-- stage 0 : launch planes to country's base airport (accepts everyhing sendds nothing back) +-- stage 1 : add NPCs and cargo planes and shop buildings. +-- stage 2 : add player progression, building upgrades, effects and more complex recipes. +-- stage 3 : TBD + + + +-- good +CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + username varchar(255) NOT NULL UNIQUE, + password_hash TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- product table act as a product identifier ie egg, milk, flour etc +create table if not exists products ( + id smallint unsigned primary key auto_increment, + name varchar(255) not null +); + +-- for stage 2 will not be used +-- increasing speed (crafting,currency type generation etc)), +CREATE table if not exists effects ( + id smallint unsigned primary key auto_increment, + name varchar(255) not null +); + +-- used airport grouping and for contracts, each country has 3 produce they can export there will not be cap +create table if not exists countries ( + id smallint unsigned primary key auto_increment, + name varchar(255) not null, + continent ENUM('void','Africa', 'Antarctica', 'Asia', 'Europe', 'North America', 'Oceania', 'South America') NOT NULL, -- universal enum + produce_1_id smallint unsigned not null, + produce_2_id smallint unsigned not null, + produce_3_id smallint unsigned not null, + foreign key (produce_1_id) references products(id), + foreign key (produce_2_id) references products(id), + foreign key (produce_3_id) references products(id) +); + +-- main table +-- primary access table act as a player identifier, each player can only have one airport, but they can have multiple planes and buildings +create table if not exists airports ( + id integer unsigned primary key auto_increment, + name varchar(255) not null, + user_id integer unique not null, + origin_country_id smallint unsigned not null, + -- resources + cash bigint unsigned not null default 100, + current_passengers INTEGER UNSIGNED NOT NULL DEFAULT 100, + max_passenger_capacity INTEGER UNSIGNED NOT NULL DEFAULT 100, + current_fuel INTEGER UNSIGNED NOT NULL DEFAULT 500, + max_fuel_capacity INTEGER UNSIGNED NOT NULL DEFAULT 1000, + -- resource generation + fuel_generation_rate INT UNSIGNED NOT NULL DEFAULT 20, + passenger_generation_rate INT UNSIGNED NOT NULL DEFAULT 5, + resources_last_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + -- progression + is_available boolean not null default true, -- if true can be sent planes from anyone + player_level integer unsigned not null default 1, + experience_points bigint unsigned not null default 0, + foreign key (origin_country_id) references countries(id), + foreign key (user_id) references users(id), + constraint chk_fuel_capacity CHECK (current_fuel <= max_fuel_capacity), + constraint chk_positive_fuel CHECK (current_fuel >= 0) +); + + +-- for stage 1, used as template for recipes. +create table if not exists recipes ( + id integer unsigned primary key auto_increment, + name varchar(255) not null, + ingredient_1_id smallint unsigned , + ingredient_1_amount integer unsigned , + ingredient_2_id smallint unsigned, + ingredient_2_amount integer unsigned , + ingredient_3_id smallint unsigned , + ingredient_3_amount integer unsigned , + product_id smallint unsigned not null, + yield_amount integer unsigned not null, + foreign key (ingredient_1_id) references products(id), + foreign key (ingredient_2_id) references products(id), + foreign key (ingredient_3_id) references products(id), + foreign key (product_id) references products(id) +); + + + + + +-- BUILDNGS + +-- hangars fuel tanks etc +CREATE table if not exists buildings ( + -- shared + id integer unsigned primary key auto_increment, + name varchar(255) not null, + min_level integer unsigned not null DEfAULT 1, + construction_cost_cash integer unsigned not null default 100, + upgrade_tier TINYINT UNSIGNED DEFAULT 0, + upgrade_cost_cash_to_uptier integer unsigned default null, + -- storage + capacity integer unsigned , + storage_type ENUM( 'fuel' , 'plane', 'product'), + storage_subtype ENUM('none', 'airplane', 'helicopter', 'seaplane','spaceship'), + -- support + effect_id smallint unsigned, + effect_value integer, + -- operation + operation_size enum('small','medium' ,'large', 'huge'), + operation_type enum('runway', 'service', 'production'), + + -- passive income + passive_type enum('passengers', 'fuel'), + passive_rate integer , + + foreign key (effect_id) references effects(id) + + ); + +--stage 1 +create table if not exists building_products ( + id integer unsigned primary key auto_increment, + building_id integer unsigned not null, + + recipe_id integer unsigned, + storage_product integer unsigned , + storage_1 integer unsigned , + storage_2 integer unsigned , + storage_3 integer unsigned , + foreign key (building_id) references buildings(id), + foreign key (recipe_id) references recipes(id) +); + + +-- many to many relation between airport and buildings +create table if not exists airport_buildings ( + id integer unsigned primary key auto_increment, + airport_id integer unsigned not null, + building_id integer unsigned not null, + -- shop specific + recipe_id integer unsigned , + storage_product integer unsigned , + storage_1 integer unsigned , + storage_2 integer unsigned , + storage_3 integer unsigned , + level integer unsigned not null default 1, + foreign key (airport_id) references airports(id) , + foreign key (building_id) references buildings(id) +); + + + + +-- planes +-- template for planes +create table if not exists planes ( + id integer unsigned primary key auto_increment, + name varchar(255) not null, + min_level integer unsigned not null default 1, + operation_cost_fuel integer unsigned not null, + operation_cost_cash integer unsigned not null DEFAULT 10, + max_passengers integer unsigned, + travel_time_inSeconds integer unsigned not null, + operation_type enum('passenger', 'cargo') not null, + aircraft_size enum('small', 'medium', 'large', 'huge') not null, + aircraft_type enum('plane', 'helicopter', 'seaplane','spaceship') not null, + buying_cost_cash integer unsigned not null DEFAULT 100, + completed_flight_experience integer unsigned not null DEFAULT 20, + completed_flight_cash_reward integer unsigned DEFAULT 50, + completed_flight_cargo_reward integer unsigned DEFAULT 10 + +); + +-- actual planes owned by players, tracks location, status, assigned hangar etc +CREATE TABLE IF NOT EXISTS player_planes ( + id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + airport_id INT UNSIGNED NOT NULL, + plane_id INTEGER UNSIGNED NOT NULL, + + -- 1. assignment (Must always point to a hangar they own they move between suitable hangars) + assigned_hangar_id INT UNSIGNED NOT NULL, + + -- 2. Real-time physical location (stored, Service Bay, Runway, or NULL if flying) + current_building_id INT UNSIGNED DEFAULT NULL, + -- assigned_cargo_id INTEGER UNSIGNED DEFAULT NULL, -- stage 1 For cargo planes, track what they're carrying + + status ENUM('idle', 'maintenance', 'boarding', 'taxiing', 'flying') NOT NULL DEFAULT 'idle', + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + flight_start_time TIMESTAMP NULL DEFAULT NULL, + + + FOREIGN KEY (airport_id) REFERENCES airports(id), + FOREIGN KEY (plane_id) REFERENCES planes(id), + FOREIGN KEY (assigned_hangar_id) REFERENCES airport_buildings(id), + FOREIGN KEY (current_building_id) REFERENCES airport_buildings(id) + --foreign key (assigned_cargo_id) references products(id) -- stage 1 +); + +-- stage 1 +CREATE TABLE IF NOT EXISTS airport_inventory ( + airport_id INTEGER unsigned NOT NULL, + product_id SMALLINT UNSIGNED NOT NULL, + quantity INTEGER UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (airport_id, product_id), + FOREIGN KEY (airport_id) REFERENCES airports(id), + FOREIGN KEY (product_id) REFERENCES products(id) +); + + +-- stage ? tbd +CREATE TABLE IF NOT EXISTS airport_contracts ( + id INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT, + airport_id INTEGER unsigned NOT NULL, + title VARCHAR(255) NOT NULL, + + -- What they need to deliver + required_product_id SMALLINT UNSIGNED NOT NULL, + required_amount INTEGER UNSIGNED NOT NULL, + current_amount_delivered INTEGER UNSIGNED NOT NULL DEFAULT 0, + + + -- Status + is_completed BOOLEAN NOT NULL DEFAULT FALSE, + expires_at TIMESTAMP NOT NULL, + + FOREIGN KEY (airport_id) REFERENCES airports(id), + FOREIGN KEY (required_product_id) REFERENCES products(id) + +); + + +-- logs + +create table if not exists completed_flight_routes_log ( + id integer unsigned primary key auto_increment, + origin_airport_id integer unsigned not null, + destination_airport_id integer unsigned not null, + start_time timestamp not null default current_timestamp, + end_time timestamp default null, + foreign key (origin_airport_id) references airports(id), + foreign key (destination_airport_id) references airports(id) +); +CREATE TABLE IF NOT EXISTS currency_transaction_logs ( + id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + airport_id INT UNSIGNED NOT NULL, + amount_changed INT NOT NULL, -- Negative for buying, positive for earning + currency_type ENUM('cash', 'fuel', 'passengers') NOT NULL, + reason VARCHAR(255) NOT NULL, -- e.g., 'bought_plane_id_12', 'completed_flight_34' + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (airport_id) REFERENCES airports(id) +); \ No newline at end of file diff --git a/backend/db/config/sqlc.yml b/backend/db/config/sqlc.yml new file mode 100644 index 0000000..aa8f9a9 --- /dev/null +++ b/backend/db/config/sqlc.yml @@ -0,0 +1,9 @@ +version: "2" +sql: + - engine: "mysql" + queries: "queries.sql" + schema: "schema.sql" + gen: + go: + package: "db" + out: "../" \ No newline at end of file diff --git a/backend/db/db.go b/backend/db/db.go new file mode 100644 index 0000000..f43598b --- /dev/null +++ b/backend/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/backend/db/models.go b/backend/db/models.go new file mode 100644 index 0000000..0f3f987 --- /dev/null +++ b/backend/db/models.go @@ -0,0 +1,704 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package db + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "time" +) + +type BuildingsBuildingType string + +const ( + BuildingsBuildingTypeNone BuildingsBuildingType = "none" + BuildingsBuildingTypeStorage BuildingsBuildingType = "storage" + BuildingsBuildingTypeSupport BuildingsBuildingType = "support" + BuildingsBuildingTypeOperation BuildingsBuildingType = "operation" + BuildingsBuildingTypePassive BuildingsBuildingType = "passive" + BuildingsBuildingTypeShop BuildingsBuildingType = "shop" + BuildingsBuildingTypeProduction BuildingsBuildingType = "production" +) + +func (e *BuildingsBuildingType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = BuildingsBuildingType(s) + case string: + *e = BuildingsBuildingType(s) + default: + return fmt.Errorf("unsupported scan type for BuildingsBuildingType: %T", src) + } + return nil +} + +type NullBuildingsBuildingType struct { + BuildingsBuildingType BuildingsBuildingType + Valid bool // Valid is true if BuildingsBuildingType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBuildingsBuildingType) Scan(value interface{}) error { + if value == nil { + ns.BuildingsBuildingType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BuildingsBuildingType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBuildingsBuildingType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BuildingsBuildingType), nil +} + +type BuildingsOperationSize string + +const ( + BuildingsOperationSizeSmall BuildingsOperationSize = "small" + BuildingsOperationSizeMedium BuildingsOperationSize = "medium" + BuildingsOperationSizeLarge BuildingsOperationSize = "large" + BuildingsOperationSizeHuge BuildingsOperationSize = "huge" +) + +func (e *BuildingsOperationSize) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = BuildingsOperationSize(s) + case string: + *e = BuildingsOperationSize(s) + default: + return fmt.Errorf("unsupported scan type for BuildingsOperationSize: %T", src) + } + return nil +} + +type NullBuildingsOperationSize struct { + BuildingsOperationSize BuildingsOperationSize + Valid bool // Valid is true if BuildingsOperationSize is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBuildingsOperationSize) Scan(value interface{}) error { + if value == nil { + ns.BuildingsOperationSize, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BuildingsOperationSize.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBuildingsOperationSize) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BuildingsOperationSize), nil +} + +type BuildingsOperationType string + +const ( + BuildingsOperationTypeRunway BuildingsOperationType = "runway" + BuildingsOperationTypeService BuildingsOperationType = "service" + BuildingsOperationTypeProduction BuildingsOperationType = "production" +) + +func (e *BuildingsOperationType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = BuildingsOperationType(s) + case string: + *e = BuildingsOperationType(s) + default: + return fmt.Errorf("unsupported scan type for BuildingsOperationType: %T", src) + } + return nil +} + +type NullBuildingsOperationType struct { + BuildingsOperationType BuildingsOperationType + Valid bool // Valid is true if BuildingsOperationType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBuildingsOperationType) Scan(value interface{}) error { + if value == nil { + ns.BuildingsOperationType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BuildingsOperationType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBuildingsOperationType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BuildingsOperationType), nil +} + +type BuildingsPassiveType string + +const ( + BuildingsPassiveTypePassengers BuildingsPassiveType = "passengers" + BuildingsPassiveTypeFuel BuildingsPassiveType = "fuel" +) + +func (e *BuildingsPassiveType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = BuildingsPassiveType(s) + case string: + *e = BuildingsPassiveType(s) + default: + return fmt.Errorf("unsupported scan type for BuildingsPassiveType: %T", src) + } + return nil +} + +type NullBuildingsPassiveType struct { + BuildingsPassiveType BuildingsPassiveType + Valid bool // Valid is true if BuildingsPassiveType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBuildingsPassiveType) Scan(value interface{}) error { + if value == nil { + ns.BuildingsPassiveType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BuildingsPassiveType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBuildingsPassiveType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BuildingsPassiveType), nil +} + +type BuildingsStorageSubtype string + +const ( + BuildingsStorageSubtypeNone BuildingsStorageSubtype = "none" + BuildingsStorageSubtypeAirplane BuildingsStorageSubtype = "airplane" + BuildingsStorageSubtypeHelicopter BuildingsStorageSubtype = "helicopter" + BuildingsStorageSubtypeSeaplane BuildingsStorageSubtype = "seaplane" + BuildingsStorageSubtypeSpaceship BuildingsStorageSubtype = "spaceship" +) + +func (e *BuildingsStorageSubtype) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = BuildingsStorageSubtype(s) + case string: + *e = BuildingsStorageSubtype(s) + default: + return fmt.Errorf("unsupported scan type for BuildingsStorageSubtype: %T", src) + } + return nil +} + +type NullBuildingsStorageSubtype struct { + BuildingsStorageSubtype BuildingsStorageSubtype + Valid bool // Valid is true if BuildingsStorageSubtype is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBuildingsStorageSubtype) Scan(value interface{}) error { + if value == nil { + ns.BuildingsStorageSubtype, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BuildingsStorageSubtype.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBuildingsStorageSubtype) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BuildingsStorageSubtype), nil +} + +type BuildingsStorageType string + +const ( + BuildingsStorageTypeFuel BuildingsStorageType = "fuel" + BuildingsStorageTypePlane BuildingsStorageType = "plane" + BuildingsStorageTypeProduct BuildingsStorageType = "product" +) + +func (e *BuildingsStorageType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = BuildingsStorageType(s) + case string: + *e = BuildingsStorageType(s) + default: + return fmt.Errorf("unsupported scan type for BuildingsStorageType: %T", src) + } + return nil +} + +type NullBuildingsStorageType struct { + BuildingsStorageType BuildingsStorageType + Valid bool // Valid is true if BuildingsStorageType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullBuildingsStorageType) Scan(value interface{}) error { + if value == nil { + ns.BuildingsStorageType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.BuildingsStorageType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullBuildingsStorageType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.BuildingsStorageType), nil +} + +type CountriesContinent string + +const ( + CountriesContinentVoid CountriesContinent = "void" + CountriesContinentAfrica CountriesContinent = "Africa" + CountriesContinentAntarctica CountriesContinent = "Antarctica" + CountriesContinentAsia CountriesContinent = "Asia" + CountriesContinentEurope CountriesContinent = "Europe" + CountriesContinentNorthAmerica CountriesContinent = "North America" + CountriesContinentOceania CountriesContinent = "Oceania" + CountriesContinentSouthAmerica CountriesContinent = "South America" +) + +func (e *CountriesContinent) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = CountriesContinent(s) + case string: + *e = CountriesContinent(s) + default: + return fmt.Errorf("unsupported scan type for CountriesContinent: %T", src) + } + return nil +} + +type NullCountriesContinent struct { + CountriesContinent CountriesContinent + Valid bool // Valid is true if CountriesContinent is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullCountriesContinent) Scan(value interface{}) error { + if value == nil { + ns.CountriesContinent, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.CountriesContinent.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullCountriesContinent) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.CountriesContinent), nil +} + +type CurrencyTransactionLogsCurrencyType string + +const ( + CurrencyTransactionLogsCurrencyTypeCash CurrencyTransactionLogsCurrencyType = "cash" + CurrencyTransactionLogsCurrencyTypeFuel CurrencyTransactionLogsCurrencyType = "fuel" + CurrencyTransactionLogsCurrencyTypePassengers CurrencyTransactionLogsCurrencyType = "passengers" +) + +func (e *CurrencyTransactionLogsCurrencyType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = CurrencyTransactionLogsCurrencyType(s) + case string: + *e = CurrencyTransactionLogsCurrencyType(s) + default: + return fmt.Errorf("unsupported scan type for CurrencyTransactionLogsCurrencyType: %T", src) + } + return nil +} + +type NullCurrencyTransactionLogsCurrencyType struct { + CurrencyTransactionLogsCurrencyType CurrencyTransactionLogsCurrencyType + Valid bool // Valid is true if CurrencyTransactionLogsCurrencyType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullCurrencyTransactionLogsCurrencyType) Scan(value interface{}) error { + if value == nil { + ns.CurrencyTransactionLogsCurrencyType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.CurrencyTransactionLogsCurrencyType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullCurrencyTransactionLogsCurrencyType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.CurrencyTransactionLogsCurrencyType), nil +} + +type PlanesAircraftSize string + +const ( + PlanesAircraftSizeSmall PlanesAircraftSize = "small" + PlanesAircraftSizeMedium PlanesAircraftSize = "medium" + PlanesAircraftSizeLarge PlanesAircraftSize = "large" + PlanesAircraftSizeHuge PlanesAircraftSize = "huge" +) + +func (e *PlanesAircraftSize) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = PlanesAircraftSize(s) + case string: + *e = PlanesAircraftSize(s) + default: + return fmt.Errorf("unsupported scan type for PlanesAircraftSize: %T", src) + } + return nil +} + +type NullPlanesAircraftSize struct { + PlanesAircraftSize PlanesAircraftSize + Valid bool // Valid is true if PlanesAircraftSize is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullPlanesAircraftSize) Scan(value interface{}) error { + if value == nil { + ns.PlanesAircraftSize, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.PlanesAircraftSize.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullPlanesAircraftSize) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.PlanesAircraftSize), nil +} + +type PlanesAircraftType string + +const ( + PlanesAircraftTypePlane PlanesAircraftType = "plane" + PlanesAircraftTypeHelicopter PlanesAircraftType = "helicopter" + PlanesAircraftTypeSeaplane PlanesAircraftType = "seaplane" + PlanesAircraftTypeSpaceship PlanesAircraftType = "spaceship" +) + +func (e *PlanesAircraftType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = PlanesAircraftType(s) + case string: + *e = PlanesAircraftType(s) + default: + return fmt.Errorf("unsupported scan type for PlanesAircraftType: %T", src) + } + return nil +} + +type NullPlanesAircraftType struct { + PlanesAircraftType PlanesAircraftType + Valid bool // Valid is true if PlanesAircraftType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullPlanesAircraftType) Scan(value interface{}) error { + if value == nil { + ns.PlanesAircraftType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.PlanesAircraftType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullPlanesAircraftType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.PlanesAircraftType), nil +} + +type PlanesOperationType string + +const ( + PlanesOperationTypePassenger PlanesOperationType = "passenger" + PlanesOperationTypeCargo PlanesOperationType = "cargo" +) + +func (e *PlanesOperationType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = PlanesOperationType(s) + case string: + *e = PlanesOperationType(s) + default: + return fmt.Errorf("unsupported scan type for PlanesOperationType: %T", src) + } + return nil +} + +type NullPlanesOperationType struct { + PlanesOperationType PlanesOperationType + Valid bool // Valid is true if PlanesOperationType is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullPlanesOperationType) Scan(value interface{}) error { + if value == nil { + ns.PlanesOperationType, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.PlanesOperationType.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullPlanesOperationType) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.PlanesOperationType), nil +} + +type PlayerPlanesStatus string + +const ( + PlayerPlanesStatusIdle PlayerPlanesStatus = "idle" + PlayerPlanesStatusMaintenance PlayerPlanesStatus = "maintenance" + PlayerPlanesStatusBoarding PlayerPlanesStatus = "boarding" + PlayerPlanesStatusTaxiing PlayerPlanesStatus = "taxiing" + PlayerPlanesStatusFlying PlayerPlanesStatus = "flying" +) + +func (e *PlayerPlanesStatus) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = PlayerPlanesStatus(s) + case string: + *e = PlayerPlanesStatus(s) + default: + return fmt.Errorf("unsupported scan type for PlayerPlanesStatus: %T", src) + } + return nil +} + +type NullPlayerPlanesStatus struct { + PlayerPlanesStatus PlayerPlanesStatus + Valid bool // Valid is true if PlayerPlanesStatus is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullPlayerPlanesStatus) Scan(value interface{}) error { + if value == nil { + ns.PlayerPlanesStatus, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.PlayerPlanesStatus.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullPlayerPlanesStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.PlayerPlanesStatus), nil +} + +type Airport struct { + ID uint32 + Name string + UserID int32 + OriginCountryID uint16 + Cash uint64 + CurrentPassengers uint32 + MaxPassengerCapacity uint32 + CurrentFuel uint32 + MaxFuelCapacity uint32 + FuelGenerationRate uint32 + PassengerGenerationRate uint32 + ResourcesLastUpdatedAt time.Time + IsAvailable bool + PlayerLevel uint32 + ExperiencePoints uint64 + IsDeleted sql.NullBool +} + +type AirportBuilding struct { + ID uint32 + AirportID uint32 + BuildingID uint32 + RecipeID sql.NullInt32 + StorageProduct sql.NullInt32 + Storage1 sql.NullInt32 + Storage2 sql.NullInt32 + Storage3 sql.NullInt32 + Level uint32 +} + +type AirportContract struct { + ID uint32 + AirportID uint32 + Title string + RequiredProductID uint16 + RequiredAmount uint32 + CurrentAmountDelivered uint32 + IsCompleted bool + ExpiresAt time.Time +} + +type AirportInventory struct { + AirportID uint32 + ProductID uint16 + Quantity uint32 +} + +type Building struct { + ID uint32 + Name string + MinLevel uint32 + ConstructionCostCash uint32 + UpgradeTier sql.NullInt16 + UpgradeCostCashToUptier sql.NullInt32 + BuildingType BuildingsBuildingType + Capacity sql.NullInt32 + StorageType NullBuildingsStorageType + StorageSubtype NullBuildingsStorageSubtype + EffectID sql.NullInt16 + EffectValue sql.NullInt32 + OperationSize NullBuildingsOperationSize + OperationType NullBuildingsOperationType + PassiveType NullBuildingsPassiveType + PassiveRate sql.NullInt32 +} + +type BuildingProduct struct { + ID uint32 + BuildingID uint32 + RecipeID sql.NullInt32 + StorageProduct sql.NullInt32 + Storage1 sql.NullInt32 + Storage2 sql.NullInt32 + Storage3 sql.NullInt32 +} + +type CompletedFlightRoutesLog struct { + ID uint32 + OriginAirportID uint32 + DestinationAirportID uint32 + StartTime time.Time + EndTime sql.NullTime +} + +type Country struct { + ID uint16 + Name string + Continent CountriesContinent + Produce1ID uint16 + Produce2ID uint16 + Produce3ID uint16 +} + +type CurrencyTransactionLog struct { + ID uint64 + AirportID uint32 + AmountChanged int32 + CurrencyType CurrencyTransactionLogsCurrencyType + Reason string + CreatedAt sql.NullTime +} + +type Effect struct { + ID uint16 + Name string +} + +type Plane struct { + ID uint32 + Name string + MinLevel uint32 + OperationCostFuel uint32 + OperationCostCash uint32 + MaxPassengers sql.NullInt32 + TravelTimeInseconds uint32 + OperationType PlanesOperationType + AircraftSize PlanesAircraftSize + AircraftType PlanesAircraftType + BuyingCostCash uint32 + CompletedFlightExperience uint32 + CompletedFlightCashReward sql.NullInt32 + CompletedFlightCargoReward sql.NullInt32 +} + +type PlayerPlane struct { + ID uint32 + AirportID uint32 + PlaneID uint32 + AssignedHangarID uint32 + CurrentBuildingID sql.NullInt32 + Status PlayerPlanesStatus + UpdatedAt sql.NullTime + FlightStartTime sql.NullTime +} + +type Product struct { + ID uint16 + Name string +} + +type Recipe struct { + ID uint32 + Name string + Ingredient1ID sql.NullInt16 + Ingredient1Amount sql.NullInt32 + Ingredient2ID sql.NullInt16 + Ingredient2Amount sql.NullInt32 + Ingredient3ID sql.NullInt16 + Ingredient3Amount sql.NullInt32 + ProductID uint16 + YieldAmount uint32 +} + +type User struct { + ID int32 + Username string + PasswordHash string + CreatedAt sql.NullTime + DeletedAt sql.NullTime +} diff --git a/backend/db/queries.sql.go b/backend/db/queries.sql.go new file mode 100644 index 0000000..d00bb9d --- /dev/null +++ b/backend/db/queries.sql.go @@ -0,0 +1,1436 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: queries.sql + +package db + +import ( + "context" + "database/sql" + "time" +) + +const addBuildingToAirportByUsername = `-- name: AddBuildingToAirportByUsername :execresult +INSERT INTO airport_buildings (airport_id, building_id) +VALUES ((select id from airports where user_id = (select id from users where username = ?)), ?) +` + +type AddBuildingToAirportByUsernameParams struct { + Username string + BuildingID uint32 +} + +func (q *Queries) AddBuildingToAirportByUsername(ctx context.Context, arg AddBuildingToAirportByUsernameParams) (sql.Result, error) { + return q.db.ExecContext(ctx, addBuildingToAirportByUsername, arg.Username, arg.BuildingID) +} + +const buyPlaneForPlayer = `-- name: BuyPlaneForPlayer :execresult + +INSERT INTO player_planes (airport_id, plane_id, assigned_hangar_id, current_building_id, status) +VALUES (?, ?, ?, ?, 'idle') +` + +type BuyPlaneForPlayerParams struct { + AirportID uint32 + PlaneID uint32 + AssignedHangarID uint32 + CurrentBuildingID sql.NullInt32 +} + +// ============================================================================ +// 5. FLEET & DYNAMIC INFRASTRUCTURE OPERATIONS +// ============================================================================ +func (q *Queries) BuyPlaneForPlayer(ctx context.Context, arg BuyPlaneForPlayerParams) (sql.Result, error) { + return q.db.ExecContext(ctx, buyPlaneForPlayer, + arg.AirportID, + arg.PlaneID, + arg.AssignedHangarID, + arg.CurrentBuildingID, + ) +} + +const checkHangarOccupancy = `-- name: CheckHangarOccupancy :one +SELECT COUNT(*) AS total_parked +FROM player_planes +WHERE current_building_id = ? +` + +func (q *Queries) CheckHangarOccupancy(ctx context.Context, currentBuildingID sql.NullInt32) (int64, error) { + row := q.db.QueryRowContext(ctx, checkHangarOccupancy, currentBuildingID) + var total_parked int64 + err := row.Scan(&total_parked) + return total_parked, err +} + +const checkHangarOccupancyByUsername = `-- name: CheckHangarOccupancyByUsername :one +SELECT COUNT(*) AS total_parked +FROM player_planes pp +JOIN airport_buildings ab ON pp.current_building_id = ab.id +WHERE ab.airport_id = (select id from airports where user_id = (select id from users where username = ?)) + AND ab.building_id = ? +` + +type CheckHangarOccupancyByUsernameParams struct { + Username string + BuildingID uint32 +} + +func (q *Queries) CheckHangarOccupancyByUsername(ctx context.Context, arg CheckHangarOccupancyByUsernameParams) (int64, error) { + row := q.db.QueryRowContext(ctx, checkHangarOccupancyByUsername, arg.Username, arg.BuildingID) + var total_parked int64 + err := row.Scan(&total_parked) + return total_parked, err +} + +const checkRunwayOccupancyByUsername = `-- name: CheckRunwayOccupancyByUsername :one + + -- +SELECT COUNT(*) AS total_occupied +FROM player_planes pp +JOIN airport_buildings ab ON pp.current_building_id = ab.id +WHERE ab.airport_id = (select id from airports where user_id = (select id from users where username = ?)) + AND ab.building_id = ? +` + +type CheckRunwayOccupancyByUsernameParams struct { + Username string + BuildingID uint32 +} + +// specific hangar +func (q *Queries) CheckRunwayOccupancyByUsername(ctx context.Context, arg CheckRunwayOccupancyByUsernameParams) (int64, error) { + row := q.db.QueryRowContext(ctx, checkRunwayOccupancyByUsername, arg.Username, arg.BuildingID) + var total_occupied int64 + err := row.Scan(&total_occupied) + return total_occupied, err +} + +const completeContract = `-- name: CompleteContract :exec +UPDATE airport_contracts +SET is_completed = TRUE +WHERE id = ? +` + +func (q *Queries) CompleteContract(ctx context.Context, id uint32) error { + _, err := q.db.ExecContext(ctx, completeContract, id) + return err +} + +const createAirportByUserName = `-- name: CreateAirportByUserName :execresult + + +INSERT INTO airports (name, user_id, origin_country_id) +VALUES (?, (SELECT id FROM users WHERE username = ?), ?) +` + +type CreateAirportByUserNameParams struct { + Name string + Username string + OriginCountryID uint16 +} + +// ============================================================================ +// 2. AIRPORT CORE MANAGEMENT +// ============================================================================ +// airport row management +func (q *Queries) CreateAirportByUserName(ctx context.Context, arg CreateAirportByUserNameParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createAirportByUserName, arg.Name, arg.Username, arg.OriginCountryID) +} + +const createUser = `-- name: CreateUser :execresult + +INSERT INTO users (username, password_hash) +VALUES (?, ?) +` + +type CreateUserParams struct { + Username string + PasswordHash string +} + +// ============================================================================ +// 1. AUTHENTICATION & USERS +// ============================================================================ +func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createUser, arg.Username, arg.PasswordHash) +} + +const deleteAirportByUserName = `-- name: DeleteAirportByUserName :exec +UPDATE airports +SET is_deleted = TRUE +WHERE user_id = (SELECT id FROM users WHERE username = ?) +` + +func (q *Queries) DeleteAirportByUserName(ctx context.Context, username string) error { + _, err := q.db.ExecContext(ctx, deleteAirportByUserName, username) + return err +} + +const deleteUserByUsername = `-- name: DeleteUserByUsername :exec +UPDATE users +SET deleted_at = CURRENT_TIMESTAMP +WHERE username = ? +` + +func (q *Queries) DeleteUserByUsername(ctx context.Context, username string) error { + _, err := q.db.ExecContext(ctx, deleteUserByUsername, username) + return err +} + +const findAvailableInfrastructure = `-- name: FindAvailableInfrastructure :one +SELECT ab.id +FROM airport_buildings ab +JOIN buildings b ON ab.building_id = b.id +LEFT JOIN player_planes pp ON ab.id = pp.current_building_id +WHERE ab.airport_id = ? + AND b.operation_type = ? -- 'runway' or 'service' (service bay) + AND b.operation_size = ? -- matches plane's aircraft_size requirement + AND pp.id IS NULL -- Ensures no other plane is physically here right now +LIMIT 1 +` + +type FindAvailableInfrastructureParams struct { + AirportID uint32 + OperationType NullBuildingsOperationType + OperationSize NullBuildingsOperationSize +} + +func (q *Queries) FindAvailableInfrastructure(ctx context.Context, arg FindAvailableInfrastructureParams) (uint32, error) { + row := q.db.QueryRowContext(ctx, findAvailableInfrastructure, arg.AirportID, arg.OperationType, arg.OperationSize) + var id uint32 + err := row.Scan(&id) + return id, err +} + +const findAvailableInfrastructureForPlane = `-- name: FindAvailableInfrastructureForPlane :one +SELECT ab.id +FROM airport_buildings ab +JOIN buildings b ON ab.building_id = b.id +LEFT JOIN player_planes pp ON ab.id = pp.current_building_id +WHERE ab.airport_id = (select id from airports where user_id = (select id from users where username = ?)) + AND b.operation_type = ? -- 'runway' or 'service' (service bay) + AND b.operation_size = ? -- matches plane's aircraft_size requirement + AND pp.id IS NULL -- Ensures no other plane is physically here right now +LIMIT 1 +` + +type FindAvailableInfrastructureForPlaneParams struct { + Username string + OperationType NullBuildingsOperationType + OperationSize NullBuildingsOperationSize +} + +func (q *Queries) FindAvailableInfrastructureForPlane(ctx context.Context, arg FindAvailableInfrastructureForPlaneParams) (uint32, error) { + row := q.db.QueryRowContext(ctx, findAvailableInfrastructureForPlane, arg.Username, arg.OperationType, arg.OperationSize) + var id uint32 + err := row.Scan(&id) + return id, err +} + +const getActiveContracts = `-- name: GetActiveContracts :many + +SELECT id, title, required_product_id, required_amount, current_amount_delivered, is_completed, expires_at +FROM airport_contracts +WHERE airport_id = ? AND is_completed = FALSE AND expires_at > NOW() +` + +type GetActiveContractsRow struct { + ID uint32 + Title string + RequiredProductID uint16 + RequiredAmount uint32 + CurrentAmountDelivered uint32 + IsCompleted bool + ExpiresAt time.Time +} + +// ============================================================================ +// 7. PROGRESSION CONTRACTS & ECONOMY LOGS +// ============================================================================ +func (q *Queries) GetActiveContracts(ctx context.Context, airportID uint32) ([]GetActiveContractsRow, error) { + rows, err := q.db.QueryContext(ctx, getActiveContracts, airportID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetActiveContractsRow + for rows.Next() { + var i GetActiveContractsRow + if err := rows.Scan( + &i.ID, + &i.Title, + &i.RequiredProductID, + &i.RequiredAmount, + &i.CurrentAmountDelivered, + &i.IsCompleted, + &i.ExpiresAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAirportBuildingsByUsername = `-- name: GetAirportBuildingsByUsername :many +SELECT ab.id AS airport_building_id,b.building_type , b.id, b.name, b.min_level, b.construction_cost_cash, b.upgrade_tier, b.upgrade_cost_cash_to_uptier, b.building_type, b.capacity, b.storage_type, b.storage_subtype, b.effect_id, b.effect_value, b.operation_size, b.operation_type, b.passive_type, b.passive_rate +FROM airport_buildings ab +JOIN buildings b ON ab.building_id = b.id +WHERE ab.airport_id = (select id from airports where user_id = (select id from users where username = ?)) +` + +type GetAirportBuildingsByUsernameRow struct { + AirportBuildingID uint32 + BuildingType BuildingsBuildingType + ID uint32 + Name string + MinLevel uint32 + ConstructionCostCash uint32 + UpgradeTier sql.NullInt16 + UpgradeCostCashToUptier sql.NullInt32 + BuildingType_2 BuildingsBuildingType + Capacity sql.NullInt32 + StorageType NullBuildingsStorageType + StorageSubtype NullBuildingsStorageSubtype + EffectID sql.NullInt16 + EffectValue sql.NullInt32 + OperationSize NullBuildingsOperationSize + OperationType NullBuildingsOperationType + PassiveType NullBuildingsPassiveType + PassiveRate sql.NullInt32 +} + +func (q *Queries) GetAirportBuildingsByUsername(ctx context.Context, username string) ([]GetAirportBuildingsByUsernameRow, error) { + rows, err := q.db.QueryContext(ctx, getAirportBuildingsByUsername, username) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAirportBuildingsByUsernameRow + for rows.Next() { + var i GetAirportBuildingsByUsernameRow + if err := rows.Scan( + &i.AirportBuildingID, + &i.BuildingType, + &i.ID, + &i.Name, + &i.MinLevel, + &i.ConstructionCostCash, + &i.UpgradeTier, + &i.UpgradeCostCashToUptier, + &i.BuildingType_2, + &i.Capacity, + &i.StorageType, + &i.StorageSubtype, + &i.EffectID, + &i.EffectValue, + &i.OperationSize, + &i.OperationType, + &i.PassiveType, + &i.PassiveRate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAirportByUserId = `-- name: GetAirportByUserId :one +SELECT id, name, user_id, origin_country_id, cash, current_passengers, max_passenger_capacity, current_fuel, max_fuel_capacity, is_available, player_level, experience_points, passenger_generation_rate, fuel_generation_rate, resources_last_updated_at, is_deleted +FROM airports +WHERE user_id = ? LIMIT 1 +` + +type GetAirportByUserIdRow struct { + ID uint32 + Name string + UserID int32 + OriginCountryID uint16 + Cash uint64 + CurrentPassengers uint32 + MaxPassengerCapacity uint32 + CurrentFuel uint32 + MaxFuelCapacity uint32 + IsAvailable bool + PlayerLevel uint32 + ExperiencePoints uint64 + PassengerGenerationRate uint32 + FuelGenerationRate uint32 + ResourcesLastUpdatedAt time.Time + IsDeleted sql.NullBool +} + +func (q *Queries) GetAirportByUserId(ctx context.Context, userID int32) (GetAirportByUserIdRow, error) { + row := q.db.QueryRowContext(ctx, getAirportByUserId, userID) + var i GetAirportByUserIdRow + err := row.Scan( + &i.ID, + &i.Name, + &i.UserID, + &i.OriginCountryID, + &i.Cash, + &i.CurrentPassengers, + &i.MaxPassengerCapacity, + &i.CurrentFuel, + &i.MaxFuelCapacity, + &i.IsAvailable, + &i.PlayerLevel, + &i.ExperiencePoints, + &i.PassengerGenerationRate, + &i.FuelGenerationRate, + &i.ResourcesLastUpdatedAt, + &i.IsDeleted, + ) + return i, err +} + +const getAirportByUserName = `-- name: GetAirportByUserName :one +SELECT id, name, user_id, origin_country_id, cash, current_passengers, max_passenger_capacity, current_fuel, max_fuel_capacity, is_available, player_level, experience_points ,passenger_generation_rate, fuel_generation_rate, resources_last_updated_at, is_deleted +FROM airports +WHERE user_id = (SELECT id FROM users WHERE username = ?) LIMIT 1 +` + +type GetAirportByUserNameRow struct { + ID uint32 + Name string + UserID int32 + OriginCountryID uint16 + Cash uint64 + CurrentPassengers uint32 + MaxPassengerCapacity uint32 + CurrentFuel uint32 + MaxFuelCapacity uint32 + IsAvailable bool + PlayerLevel uint32 + ExperiencePoints uint64 + PassengerGenerationRate uint32 + FuelGenerationRate uint32 + ResourcesLastUpdatedAt time.Time + IsDeleted sql.NullBool +} + +func (q *Queries) GetAirportByUserName(ctx context.Context, username string) (GetAirportByUserNameRow, error) { + row := q.db.QueryRowContext(ctx, getAirportByUserName, username) + var i GetAirportByUserNameRow + err := row.Scan( + &i.ID, + &i.Name, + &i.UserID, + &i.OriginCountryID, + &i.Cash, + &i.CurrentPassengers, + &i.MaxPassengerCapacity, + &i.CurrentFuel, + &i.MaxFuelCapacity, + &i.IsAvailable, + &i.PlayerLevel, + &i.ExperiencePoints, + &i.PassengerGenerationRate, + &i.FuelGenerationRate, + &i.ResourcesLastUpdatedAt, + &i.IsDeleted, + ) + return i, err +} + +const getAllPlanes = `-- name: GetAllPlanes :many +SELECT id, name, min_level, operation_cost_fuel, operation_cost_cash, max_passengers, travel_time_inseconds, operation_type, aircraft_size, aircraft_type, buying_cost_cash, completed_flight_experience, completed_flight_cash_reward, completed_flight_cargo_reward FROM planes +` + +func (q *Queries) GetAllPlanes(ctx context.Context) ([]Plane, error) { + rows, err := q.db.QueryContext(ctx, getAllPlanes) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Plane + for rows.Next() { + var i Plane + if err := rows.Scan( + &i.ID, + &i.Name, + &i.MinLevel, + &i.OperationCostFuel, + &i.OperationCostCash, + &i.MaxPassengers, + &i.TravelTimeInseconds, + &i.OperationType, + &i.AircraftSize, + &i.AircraftType, + &i.BuyingCostCash, + &i.CompletedFlightExperience, + &i.CompletedFlightCashReward, + &i.CompletedFlightCargoReward, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPlaneById = `-- name: GetPlaneById :one +SELECT id, name, min_level, operation_cost_fuel, operation_cost_cash, max_passengers, travel_time_inseconds, operation_type, aircraft_size, aircraft_type, buying_cost_cash, completed_flight_experience, completed_flight_cash_reward, completed_flight_cargo_reward FROM planes WHERE id = ? +` + +func (q *Queries) GetPlaneById(ctx context.Context, id uint32) (Plane, error) { + row := q.db.QueryRowContext(ctx, getPlaneById, id) + var i Plane + err := row.Scan( + &i.ID, + &i.Name, + &i.MinLevel, + &i.OperationCostFuel, + &i.OperationCostCash, + &i.MaxPassengers, + &i.TravelTimeInseconds, + &i.OperationType, + &i.AircraftSize, + &i.AircraftType, + &i.BuyingCostCash, + &i.CompletedFlightExperience, + &i.CompletedFlightCashReward, + &i.CompletedFlightCargoReward, + ) + return i, err +} + +const getPlanesByAircraftSize = `-- name: GetPlanesByAircraftSize :many +SELECT id, name, min_level, operation_cost_fuel, operation_cost_cash, max_passengers, travel_time_inseconds, operation_type, aircraft_size, aircraft_type, buying_cost_cash, completed_flight_experience, completed_flight_cash_reward, completed_flight_cargo_reward FROM planes WHERE aircraft_size = ? +` + +func (q *Queries) GetPlanesByAircraftSize(ctx context.Context, aircraftSize PlanesAircraftSize) ([]Plane, error) { + rows, err := q.db.QueryContext(ctx, getPlanesByAircraftSize, aircraftSize) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Plane + for rows.Next() { + var i Plane + if err := rows.Scan( + &i.ID, + &i.Name, + &i.MinLevel, + &i.OperationCostFuel, + &i.OperationCostCash, + &i.MaxPassengers, + &i.TravelTimeInseconds, + &i.OperationType, + &i.AircraftSize, + &i.AircraftType, + &i.BuyingCostCash, + &i.CompletedFlightExperience, + &i.CompletedFlightCashReward, + &i.CompletedFlightCargoReward, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPlanesByAircraftType = `-- name: GetPlanesByAircraftType :many +SELECT id, name, min_level, operation_cost_fuel, operation_cost_cash, max_passengers, travel_time_inseconds, operation_type, aircraft_size, aircraft_type, buying_cost_cash, completed_flight_experience, completed_flight_cash_reward, completed_flight_cargo_reward FROM planes WHERE aircraft_type = ? +` + +func (q *Queries) GetPlanesByAircraftType(ctx context.Context, aircraftType PlanesAircraftType) ([]Plane, error) { + rows, err := q.db.QueryContext(ctx, getPlanesByAircraftType, aircraftType) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Plane + for rows.Next() { + var i Plane + if err := rows.Scan( + &i.ID, + &i.Name, + &i.MinLevel, + &i.OperationCostFuel, + &i.OperationCostCash, + &i.MaxPassengers, + &i.TravelTimeInseconds, + &i.OperationType, + &i.AircraftSize, + &i.AircraftType, + &i.BuyingCostCash, + &i.CompletedFlightExperience, + &i.CompletedFlightCashReward, + &i.CompletedFlightCargoReward, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPlanesByMinLevel = `-- name: GetPlanesByMinLevel :many +SELECT id, name, min_level, operation_cost_fuel, operation_cost_cash, max_passengers, travel_time_inseconds, operation_type, aircraft_size, aircraft_type, buying_cost_cash, completed_flight_experience, completed_flight_cash_reward, completed_flight_cargo_reward FROM planes WHERE min_level <= ? +` + +func (q *Queries) GetPlanesByMinLevel(ctx context.Context, minLevel uint32) ([]Plane, error) { + rows, err := q.db.QueryContext(ctx, getPlanesByMinLevel, minLevel) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Plane + for rows.Next() { + var i Plane + if err := rows.Scan( + &i.ID, + &i.Name, + &i.MinLevel, + &i.OperationCostFuel, + &i.OperationCostCash, + &i.MaxPassengers, + &i.TravelTimeInseconds, + &i.OperationType, + &i.AircraftSize, + &i.AircraftType, + &i.BuyingCostCash, + &i.CompletedFlightExperience, + &i.CompletedFlightCashReward, + &i.CompletedFlightCargoReward, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPlanesByOperationType = `-- name: GetPlanesByOperationType :many +SELECT id, name, min_level, operation_cost_fuel, operation_cost_cash, max_passengers, travel_time_inseconds, operation_type, aircraft_size, aircraft_type, buying_cost_cash, completed_flight_experience, completed_flight_cash_reward, completed_flight_cargo_reward FROM planes WHERE operation_type = ? +` + +func (q *Queries) GetPlanesByOperationType(ctx context.Context, operationType PlanesOperationType) ([]Plane, error) { + rows, err := q.db.QueryContext(ctx, getPlanesByOperationType, operationType) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Plane + for rows.Next() { + var i Plane + if err := rows.Scan( + &i.ID, + &i.Name, + &i.MinLevel, + &i.OperationCostFuel, + &i.OperationCostCash, + &i.MaxPassengers, + &i.TravelTimeInseconds, + &i.OperationType, + &i.AircraftSize, + &i.AircraftType, + &i.BuyingCostCash, + &i.CompletedFlightExperience, + &i.CompletedFlightCashReward, + &i.CompletedFlightCargoReward, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPlanesReadyToLand = `-- name: GetPlanesReadyToLand :many + +SELECT pp.id AS player_plane_id, pp.airport_id, pp.assigned_hangar_id, + p.completed_flight_experience, p.completed_flight_cash_reward, p.completed_flight_cargo_reward, p.operation_type +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.status = 'flying' + -- Uses your logic: flight_start_time + plane travel duration <= current clock + AND ADDTIME(pp.flight_start_time, p.travel_time) <= NOW() +` + +type GetPlanesReadyToLandRow struct { + PlayerPlaneID uint32 + AirportID uint32 + AssignedHangarID uint32 + CompletedFlightExperience uint32 + CompletedFlightCashReward sql.NullInt32 + CompletedFlightCargoReward sql.NullInt32 + OperationType PlanesOperationType +} + +// ============================================================================ +// 6. TIME-BASED FLIGHT ENGINE +// ============================================================================ +func (q *Queries) GetPlanesReadyToLand(ctx context.Context) ([]GetPlanesReadyToLandRow, error) { + rows, err := q.db.QueryContext(ctx, getPlanesReadyToLand) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetPlanesReadyToLandRow + for rows.Next() { + var i GetPlanesReadyToLandRow + if err := rows.Scan( + &i.PlayerPlaneID, + &i.AirportID, + &i.AssignedHangarID, + &i.CompletedFlightExperience, + &i.CompletedFlightCashReward, + &i.CompletedFlightCargoReward, + &i.OperationType, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPlanesReadyToLandByUsername = `-- name: GetPlanesReadyToLandByUsername :many + +SELECT pp.id AS player_plane_id, pp.airport_id, pp.assigned_hangar_id, + p.completed_flight_experience, p.completed_flight_cash_reward, p.completed_flight_cargo_reward, p.operation_type +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.status = 'flying' + AND ADDTIME(pp.flight_start_time, p.travel_time) <= NOW() + AND pp.airport_id = (select id from airports where user_id = (select id from users where username = ?)) +` + +type GetPlanesReadyToLandByUsernameRow struct { + PlayerPlaneID uint32 + AirportID uint32 + AssignedHangarID uint32 + CompletedFlightExperience uint32 + CompletedFlightCashReward sql.NullInt32 + CompletedFlightCargoReward sql.NullInt32 + OperationType PlanesOperationType +} + +// specific runway +func (q *Queries) GetPlanesReadyToLandByUsername(ctx context.Context, username string) ([]GetPlanesReadyToLandByUsernameRow, error) { + rows, err := q.db.QueryContext(ctx, getPlanesReadyToLandByUsername, username) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetPlanesReadyToLandByUsernameRow + for rows.Next() { + var i GetPlanesReadyToLandByUsernameRow + if err := rows.Scan( + &i.PlayerPlaneID, + &i.AirportID, + &i.AssignedHangarID, + &i.CompletedFlightExperience, + &i.CompletedFlightCashReward, + &i.CompletedFlightCargoReward, + &i.OperationType, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPlayerFleet = `-- name: GetPlayerFleet :many +SELECT pp.id AS player_plane_id, pp.status, pp.updated_at, pp.flight_start_time, pp.current_building_id, pp.assigned_hangar_id,p.id, p.name, p.min_level, p.operation_cost_fuel, p.operation_cost_cash, p.max_passengers, p.travel_time_inseconds, p.operation_type, p.aircraft_size, p.aircraft_type, p.buying_cost_cash, p.completed_flight_experience, p.completed_flight_cash_reward, p.completed_flight_cargo_reward +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.airport_id = ? +` + +type GetPlayerFleetRow struct { + PlayerPlaneID uint32 + Status PlayerPlanesStatus + UpdatedAt sql.NullTime + FlightStartTime sql.NullTime + CurrentBuildingID sql.NullInt32 + AssignedHangarID uint32 + ID uint32 + Name string + MinLevel uint32 + OperationCostFuel uint32 + OperationCostCash uint32 + MaxPassengers sql.NullInt32 + TravelTimeInseconds uint32 + OperationType PlanesOperationType + AircraftSize PlanesAircraftSize + AircraftType PlanesAircraftType + BuyingCostCash uint32 + CompletedFlightExperience uint32 + CompletedFlightCashReward sql.NullInt32 + CompletedFlightCargoReward sql.NullInt32 +} + +func (q *Queries) GetPlayerFleet(ctx context.Context, airportID uint32) ([]GetPlayerFleetRow, error) { + rows, err := q.db.QueryContext(ctx, getPlayerFleet, airportID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetPlayerFleetRow + for rows.Next() { + var i GetPlayerFleetRow + if err := rows.Scan( + &i.PlayerPlaneID, + &i.Status, + &i.UpdatedAt, + &i.FlightStartTime, + &i.CurrentBuildingID, + &i.AssignedHangarID, + &i.ID, + &i.Name, + &i.MinLevel, + &i.OperationCostFuel, + &i.OperationCostCash, + &i.MaxPassengers, + &i.TravelTimeInseconds, + &i.OperationType, + &i.AircraftSize, + &i.AircraftType, + &i.BuyingCostCash, + &i.CompletedFlightExperience, + &i.CompletedFlightCashReward, + &i.CompletedFlightCargoReward, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPlayerPlanesByUsername = `-- name: GetPlayerPlanesByUsername :many +SELECT pp.id AS player_plane_id, pp.id, pp.airport_id, pp.plane_id, pp.assigned_hangar_id, pp.current_building_id, pp.status, pp.updated_at, pp.flight_start_time +FROM player_planes pp +JOIN planes p ON pp.plane_id = p.id +WHERE pp.airport_id = (select id from airports where user_id = (select id from users where username = ?)) +` + +type GetPlayerPlanesByUsernameRow struct { + PlayerPlaneID uint32 + ID uint32 + AirportID uint32 + PlaneID uint32 + AssignedHangarID uint32 + CurrentBuildingID sql.NullInt32 + Status PlayerPlanesStatus + UpdatedAt sql.NullTime + FlightStartTime sql.NullTime +} + +func (q *Queries) GetPlayerPlanesByUsername(ctx context.Context, username string) ([]GetPlayerPlanesByUsernameRow, error) { + rows, err := q.db.QueryContext(ctx, getPlayerPlanesByUsername, username) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetPlayerPlanesByUsernameRow + for rows.Next() { + var i GetPlayerPlanesByUsernameRow + if err := rows.Scan( + &i.PlayerPlaneID, + &i.ID, + &i.AirportID, + &i.PlaneID, + &i.AssignedHangarID, + &i.CurrentBuildingID, + &i.Status, + &i.UpdatedAt, + &i.FlightStartTime, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserByUsername = `-- name: GetUserByUsername :one +SELECT id, username, password_hash +FROM users +WHERE username = ? LIMIT 1 +` + +type GetUserByUsernameRow struct { + ID int32 + Username string + PasswordHash string +} + +func (q *Queries) GetUserByUsername(ctx context.Context, username string) (GetUserByUsernameRow, error) { + row := q.db.QueryRowContext(ctx, getUserByUsername, username) + var i GetUserByUsernameRow + err := row.Scan(&i.ID, &i.Username, &i.PasswordHash) + return i, err +} + +const getUserIdByUsername = `-- name: GetUserIdByUsername :one +SELECT id +FROM users +WHERE username = ? LIMIT 1 +` + +func (q *Queries) GetUserIdByUsername(ctx context.Context, username string) (int32, error) { + row := q.db.QueryRowContext(ctx, getUserIdByUsername, username) + var id int32 + err := row.Scan(&id) + return id, err +} + +const logCompletedFlightRoute = `-- name: LogCompletedFlightRoute :exec +INSERT INTO completed_flight_routes_log (origin_airport_id, destination_airport_id, start_time, end_time) +VALUES (?, ?, ?, NOW()) +` + +type LogCompletedFlightRouteParams struct { + OriginAirportID uint32 + DestinationAirportID uint32 + StartTime time.Time +} + +func (q *Queries) LogCompletedFlightRoute(ctx context.Context, arg LogCompletedFlightRouteParams) error { + _, err := q.db.ExecContext(ctx, logCompletedFlightRoute, arg.OriginAirportID, arg.DestinationAirportID, arg.StartTime) + return err +} + +const logCurrencyTransaction = `-- name: LogCurrencyTransaction :exec +INSERT INTO currency_transaction_logs (airport_id, amount_changed, currency_type, reason) +VALUES (?, ?, ?, ?) +` + +type LogCurrencyTransactionParams struct { + AirportID uint32 + AmountChanged int32 + CurrencyType CurrencyTransactionLogsCurrencyType + Reason string +} + +func (q *Queries) LogCurrencyTransaction(ctx context.Context, arg LogCurrencyTransactionParams) error { + _, err := q.db.ExecContext(ctx, logCurrencyTransaction, + arg.AirportID, + arg.AmountChanged, + arg.CurrencyType, + arg.Reason, + ) + return err +} + +const updateAirportCash = `-- name: UpdateAirportCash :exec +UPDATE airports +SET cash = ? +WHERE id = ? +` + +type UpdateAirportCashParams struct { + Cash uint64 + ID uint32 +} + +func (q *Queries) UpdateAirportCash(ctx context.Context, arg UpdateAirportCashParams) error { + _, err := q.db.ExecContext(ctx, updateAirportCash, arg.Cash, arg.ID) + return err +} + +const updateAirportCurrencies = `-- name: UpdateAirportCurrencies :exec + + +UPDATE airports +SET cash = ?, + current_passengers = ?, + current_fuel = ? +WHERE id = ? +` + +type UpdateAirportCurrenciesParams struct { + Cash uint64 + CurrentPassengers uint32 + CurrentFuel uint32 + ID uint32 +} + +// airport resource management +func (q *Queries) UpdateAirportCurrencies(ctx context.Context, arg UpdateAirportCurrenciesParams) error { + _, err := q.db.ExecContext(ctx, updateAirportCurrencies, + arg.Cash, + arg.CurrentPassengers, + arg.CurrentFuel, + arg.ID, + ) + return err +} + +const updateAirportFuel = `-- name: UpdateAirportFuel :exec +UPDATE airports +SET current_fuel = ? +WHERE id = ? +` + +type UpdateAirportFuelParams struct { + CurrentFuel uint32 + ID uint32 +} + +func (q *Queries) UpdateAirportFuel(ctx context.Context, arg UpdateAirportFuelParams) error { + _, err := q.db.ExecContext(ctx, updateAirportFuel, arg.CurrentFuel, arg.ID) + return err +} + +const updateAirportFuelRate = `-- name: UpdateAirportFuelRate :exec +UPDATE airports +SET fuel_generation_rate = ? +WHERE id = ? +` + +type UpdateAirportFuelRateParams struct { + FuelGenerationRate uint32 + ID uint32 +} + +func (q *Queries) UpdateAirportFuelRate(ctx context.Context, arg UpdateAirportFuelRateParams) error { + _, err := q.db.ExecContext(ctx, updateAirportFuelRate, arg.FuelGenerationRate, arg.ID) + return err +} + +const updateAirportMaxFuel = `-- name: UpdateAirportMaxFuel :exec +UPDATE airports +SET max_fuel_capacity = ? +WHERE id = ? +` + +type UpdateAirportMaxFuelParams struct { + MaxFuelCapacity uint32 + ID uint32 +} + +func (q *Queries) UpdateAirportMaxFuel(ctx context.Context, arg UpdateAirportMaxFuelParams) error { + _, err := q.db.ExecContext(ctx, updateAirportMaxFuel, arg.MaxFuelCapacity, arg.ID) + return err +} + +const updateAirportPassengerRate = `-- name: UpdateAirportPassengerRate :exec +UPDATE airports +SET passenger_generation_rate = ? +WHERE id = ? +` + +type UpdateAirportPassengerRateParams struct { + PassengerGenerationRate uint32 + ID uint32 +} + +func (q *Queries) UpdateAirportPassengerRate(ctx context.Context, arg UpdateAirportPassengerRateParams) error { + _, err := q.db.ExecContext(ctx, updateAirportPassengerRate, arg.PassengerGenerationRate, arg.ID) + return err +} + +const updateAirportResources = `-- name: UpdateAirportResources :exec +UPDATE airports +SET + current_fuel = LEAST( + max_fuel_capacity, + current_fuel + (fuel_generation_rate * TIMESTAMPDIFF(SECOND, resources_last_updated_at, NOW())) + ), + current_passengers = LEAST( + max_passenger_capacity, + current_passengers + (passenger_generation_rate * TIMESTAMPDIFF(SECOND, resources_last_updated_at, NOW())) + ), + resources_last_updated_at = NOW() +WHERE id = ? +` + +func (q *Queries) UpdateAirportResources(ctx context.Context, id uint32) error { + _, err := q.db.ExecContext(ctx, updateAirportResources, id) + return err +} + +const updateAirportResourcesUpdated = `-- name: UpdateAirportResourcesUpdated :exec +update airports +set resources_last_updated_at = ? +where id = ? +` + +type UpdateAirportResourcesUpdatedParams struct { + ResourcesLastUpdatedAt time.Time + ID uint32 +} + +func (q *Queries) UpdateAirportResourcesUpdated(ctx context.Context, arg UpdateAirportResourcesUpdatedParams) error { + _, err := q.db.ExecContext(ctx, updateAirportResourcesUpdated, arg.ResourcesLastUpdatedAt, arg.ID) + return err +} + +const updateAirportmaxPassengers = `-- name: UpdateAirportmaxPassengers :exec +UPDATE airports +SET max_passenger_capacity = ? +WHERE id = ? +` + +type UpdateAirportmaxPassengersParams struct { + MaxPassengerCapacity uint32 + ID uint32 +} + +func (q *Queries) UpdateAirportmaxPassengers(ctx context.Context, arg UpdateAirportmaxPassengersParams) error { + _, err := q.db.ExecContext(ctx, updateAirportmaxPassengers, arg.MaxPassengerCapacity, arg.ID) + return err +} + +const updateAirportpassengers = `-- name: UpdateAirportpassengers :exec +UPDATE airports +SET current_passengers = ? +WHERE id = ? +` + +type UpdateAirportpassengersParams struct { + CurrentPassengers uint32 + ID uint32 +} + +func (q *Queries) UpdateAirportpassengers(ctx context.Context, arg UpdateAirportpassengersParams) error { + _, err := q.db.ExecContext(ctx, updateAirportpassengers, arg.CurrentPassengers, arg.ID) + return err +} + +const updateContractDelivery = `-- name: UpdateContractDelivery :exec +UPDATE airport_contracts +SET current_amount_delivered = current_amount_delivered + ? +WHERE id = ? AND is_completed = FALSE +` + +type UpdateContractDeliveryParams struct { + CurrentAmountDelivered uint32 + ID uint32 +} + +func (q *Queries) UpdateContractDelivery(ctx context.Context, arg UpdateContractDeliveryParams) error { + _, err := q.db.ExecContext(ctx, updateContractDelivery, arg.CurrentAmountDelivered, arg.ID) + return err +} + +const updatePlaneState = `-- name: UpdatePlaneState :exec +UPDATE player_planes +SET current_building_id = ?, + status = ?, + + flight_start_time = ? +WHERE id = ? +` + +type UpdatePlaneStateParams struct { + CurrentBuildingID sql.NullInt32 + Status PlayerPlanesStatus + FlightStartTime sql.NullTime + ID uint32 +} + +func (q *Queries) UpdatePlaneState(ctx context.Context, arg UpdatePlaneStateParams) error { + _, err := q.db.ExecContext(ctx, updatePlaneState, + arg.CurrentBuildingID, + arg.Status, + arg.FlightStartTime, + arg.ID, + ) + return err +} + +const updatePlayerPlaneState = `-- name: UpdatePlayerPlaneState :exec +UPDATE player_planes +SET current_building_id = ?, + status = ?, + flight_start_time = ? +WHERE id = ? +` + +type UpdatePlayerPlaneStateParams struct { + CurrentBuildingID sql.NullInt32 + Status PlayerPlanesStatus + FlightStartTime sql.NullTime + ID uint32 +} + +func (q *Queries) UpdatePlayerPlaneState(ctx context.Context, arg UpdatePlayerPlaneStateParams) error { + _, err := q.db.ExecContext(ctx, updatePlayerPlaneState, + arg.CurrentBuildingID, + arg.Status, + arg.FlightStartTime, + arg.ID, + ) + return err +} + +const updateUserPasswordByUserName = `-- name: UpdateUserPasswordByUserName :exec +UPDATE users +SET password_hash = ? +WHERE username = ? +` + +type UpdateUserPasswordByUserNameParams struct { + PasswordHash string + Username string +} + +func (q *Queries) UpdateUserPasswordByUserName(ctx context.Context, arg UpdateUserPasswordByUserNameParams) error { + _, err := q.db.ExecContext(ctx, updateUserPasswordByUserName, arg.PasswordHash, arg.Username) + return err +} + +const addBuilding = `-- name: addBuilding :execresult +INSERT INTO buildings (name,min_level,construction_cost_cash) +VALUES (?, ?, ?) +` + +type addBuildingParams struct { + Name string + MinLevel uint32 + ConstructionCostCash uint32 +} + +func (q *Queries) addBuilding(ctx context.Context, arg addBuildingParams) (sql.Result, error) { + return q.db.ExecContext(ctx, addBuilding, arg.Name, arg.MinLevel, arg.ConstructionCostCash) +} + +const addOperationalBuilding = `-- name: addOperationalBuilding :execresult +INSERT INTO buildings (name,min_level,construction_cost_cash,operation_type,operation_size) +VALUES (?, ?, ?, ?, ?) +` + +type addOperationalBuildingParams struct { + Name string + MinLevel uint32 + ConstructionCostCash uint32 + OperationType NullBuildingsOperationType + OperationSize NullBuildingsOperationSize +} + +func (q *Queries) addOperationalBuilding(ctx context.Context, arg addOperationalBuildingParams) (sql.Result, error) { + return q.db.ExecContext(ctx, addOperationalBuilding, + arg.Name, + arg.MinLevel, + arg.ConstructionCostCash, + arg.OperationType, + arg.OperationSize, + ) +} + +const addPassiveProductionBuilding = `-- name: addPassiveProductionBuilding :execresult +INSERT INTO buildings (name,min_level,construction_cost_cash,passive_type,passive_rate) +VALUES (?, ?, ?, ?, ?) +` + +type addPassiveProductionBuildingParams struct { + Name string + MinLevel uint32 + ConstructionCostCash uint32 + PassiveType NullBuildingsPassiveType + PassiveRate sql.NullInt32 +} + +func (q *Queries) addPassiveProductionBuilding(ctx context.Context, arg addPassiveProductionBuildingParams) (sql.Result, error) { + return q.db.ExecContext(ctx, addPassiveProductionBuilding, + arg.Name, + arg.MinLevel, + arg.ConstructionCostCash, + arg.PassiveType, + arg.PassiveRate, + ) +} + +const addPlane = `-- name: addPlane :execresult + +INSERT INTO planes (name, aircraft_size,operation_type,aircraft_type ,min_level, operation_cost_fuel, operation_cost_cash, max_passengers, travel_time_inSeconds,buying_cost_cash, completed_flight_experience, completed_flight_cash_reward, completed_flight_cargo_reward) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type addPlaneParams struct { + Name string + AircraftSize PlanesAircraftSize + OperationType PlanesOperationType + AircraftType PlanesAircraftType + MinLevel uint32 + OperationCostFuel uint32 + OperationCostCash uint32 + MaxPassengers sql.NullInt32 + TravelTimeInseconds uint32 + BuyingCostCash uint32 + CompletedFlightExperience uint32 + CompletedFlightCashReward sql.NullInt32 + CompletedFlightCargoReward sql.NullInt32 +} + +// planes & fleet management +func (q *Queries) addPlane(ctx context.Context, arg addPlaneParams) (sql.Result, error) { + return q.db.ExecContext(ctx, addPlane, + arg.Name, + arg.AircraftSize, + arg.OperationType, + arg.AircraftType, + arg.MinLevel, + arg.OperationCostFuel, + arg.OperationCostCash, + arg.MaxPassengers, + arg.TravelTimeInseconds, + arg.BuyingCostCash, + arg.CompletedFlightExperience, + arg.CompletedFlightCashReward, + arg.CompletedFlightCargoReward, + ) +} + +const addPlaneToAirportByUsername = `-- name: addPlaneToAirportByUsername :execresult +INSERT INTO player_planes (airport_id, plane_id, assigned_hangar_id, current_building_id, status) +VALUES ((select id from airports where user_id = (select id from users where username = ?)), ?, ?, ?, 'idle') +` + +type addPlaneToAirportByUsernameParams struct { + Username string + PlaneID uint32 + AssignedHangarID uint32 + CurrentBuildingID sql.NullInt32 +} + +func (q *Queries) addPlaneToAirportByUsername(ctx context.Context, arg addPlaneToAirportByUsernameParams) (sql.Result, error) { + return q.db.ExecContext(ctx, addPlaneToAirportByUsername, + arg.Username, + arg.PlaneID, + arg.AssignedHangarID, + arg.CurrentBuildingID, + ) +} + +const addStorageBuilding = `-- name: addStorageBuilding :execresult + + + +INSERT INTO buildings (name,min_level,construction_cost_cash,capacity,storage_type,storage_subtype) +VALUES (?, ?, ?, ?, ?, ?) +` + +type addStorageBuildingParams struct { + Name string + MinLevel uint32 + ConstructionCostCash uint32 + Capacity sql.NullInt32 + StorageType NullBuildingsStorageType + StorageSubtype NullBuildingsStorageSubtype +} + +// ============================================================================ +// 3. WAREHOUSE & INVENTORY SYSTEM +// ============================================================================ +// ============================================================================ +// 4. BUILDINGS & PRODUCTION ENGINE +// ============================================================================ +func (q *Queries) addStorageBuilding(ctx context.Context, arg addStorageBuildingParams) (sql.Result, error) { + return q.db.ExecContext(ctx, addStorageBuilding, + arg.Name, + arg.MinLevel, + arg.ConstructionCostCash, + arg.Capacity, + arg.StorageType, + arg.StorageSubtype, + ) +} + +const updatePlayerExperience = `-- name: updatePlayerExperience :exec +UPDATE airports +SET experience_points = ? +WHERE id = ? +` + +type updatePlayerExperienceParams struct { + ExperiencePoints uint64 + ID uint32 +} + +func (q *Queries) updatePlayerExperience(ctx context.Context, arg updatePlayerExperienceParams) error { + _, err := q.db.ExecContext(ctx, updatePlayerExperience, arg.ExperiencePoints, arg.ID) + return err +} + +const updatePlayerLevel = `-- name: updatePlayerLevel :exec +UPDATE airports +SET player_level = ? +WHERE id = ? +` + +type updatePlayerLevelParams struct { + PlayerLevel uint32 + ID uint32 +} + +func (q *Queries) updatePlayerLevel(ctx context.Context, arg updatePlayerLevelParams) error { + _, err := q.db.ExecContext(ctx, updatePlayerLevel, arg.PlayerLevel, arg.ID) + return err +} diff --git a/backend/server/homepage.go b/backend/server/homepage.go index 06ab7d0..fb8681b 100644 --- a/backend/server/homepage.go +++ b/backend/server/homepage.go @@ -1 +1,205 @@ package main + +import ( + "fmt" + "os" + "strings" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +// ============================================================================ +// STYLING DEFINITIONS (Lipgloss) +// ============================================================================ +var ( + // Colors + skyBlue = lipgloss.Color("117") + neonPink = lipgloss.Color("205") + moneyGreen = lipgloss.Color("85") + gray = lipgloss.Color("240") + + // Component Styles + titleStyle = lipgloss.NewStyle(). + Foreground(skyBlue). + Bold(true). + MarginTop(1). + MarginBottom(1) + + headerBoxStyle = lipgloss.NewStyle(). + Border(lipgloss.RoundedBorder()). + BorderForeground(skyBlue). + Padding(0, 2). + MarginBottom(1) + + listStyle = lipgloss.NewStyle().MarginLeft(2) + + itemStyle = lipgloss.NewStyle(). + PaddingLeft(2). + Foreground(lipgloss.Color("252")) + + selectedItemStyle = lipgloss.NewStyle(). + PaddingLeft(2). + Foreground(neonPink). + Bold(true). + Background(lipgloss.Color("236")) // Slight background highlight + + footerStyle = lipgloss.NewStyle(). + Foreground(gray). + MarginTop(2) +) + +// ============================================================================ +// 1. THE MODEL +// ============================================================================ +type homepageModel struct { + cursor int + choices []string + selected string + + // Mock Player Data (In a real app, pass this in via initialModel) + playerName string + cash int + fleetCount int +} + +func initialHomepageModel() homepageModel { + return homepageModel{ + // Our interactive menu options + choices: []string{ + "🗄️ Manage Hangar Fleet", + "🏢 View Airport Infrastructure", + "🏁 Active Runways & Service Loop", + "🚪 Logout / Quit", + }, + playerName: "CaptainGo", + cash: 14500, + fleetCount: 12, + } +} + +// ============================================================================ +// 2. THE INIT FUNCTION +// ============================================================================ +func (m homepageModel) Init() tea.Cmd { + return nil // No background tasks to start immediately +} + +// ============================================================================ +// 3. THE UPDATE FUNCTION (Handles inputs) +// ============================================================================ +func (m homepageModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + + // Handle keyboard events + case tea.KeyMsg: + switch msg.String() { + + // Quit commands + case "ctrl+c", "q", "esc": + m.selected = "quit" + return m, tea.Quit + + // Move up the menu + case "up", "k": + if m.cursor > 0 { + m.cursor-- + } else { + m.cursor = len(m.choices) - 1 // Wrap around to bottom + } + + // Move down the menu + case "down", "j": + if m.cursor < len(m.choices)-1 { + m.cursor++ + } else { + m.cursor = 0 // Wrap around to top + } + + // Select an option + case "enter", " ": + m.selected = m.choices[m.cursor] + return m, tea.Quit + } + } + + return m, nil +} + +// ============================================================================ +// 4. THE VIEW FUNCTION (Renders the UI) +// ============================================================================ +func (m homepageModel) View() string { + var b strings.Builder + + // --- 1. TITLE --- + b.WriteString(titleStyle.Render("✈️ SKYRAMA COMMAND CENTER")) + b.WriteString("\n") + + // --- 2. HEADER BAR (Player Stats) --- + statsLine := fmt.Sprintf("[ 🔑 Player: %s ] [ 💰 Cash: %s ] [ 🛩️ Fleet: %d ]", + lipgloss.NewStyle().Foreground(lipgloss.Color("252")).Bold(true).Render(m.playerName), + lipgloss.NewStyle().Foreground(moneyGreen).Render(fmt.Sprintf("%d €", m.cash)), + m.fleetCount, + ) + b.WriteString(headerBoxStyle.Render(statsLine)) + b.WriteString("\n\n") + + // --- 3. INTERACTIVE MENU --- + b.WriteString(" Main Operations Menu:\n\n") + + for i, choice := range m.choices { + // Is the cursor pointing at this choice? + cursorStr := " " // no cursor + if m.cursor == i { + cursorStr = lipgloss.NewStyle().Foreground(neonPink).Render(">") + b.WriteString(fmt.Sprintf("%s %s\n", cursorStr, selectedItemStyle.Render(choice))) + } else { + b.WriteString(fmt.Sprintf("%s %s\n", cursorStr, itemStyle.Render(choice))) + } + } + + // --- 4. FOOTER --- + b.WriteString(footerStyle.Render("\n ↑/↓: Navigate • Enter: Select • q/esc: Quit")) + + // Return the final drawn screen with a little left margin padding + return lipgloss.NewStyle().MarginLeft(2).Render(b.String()) + "\n" +} + +// ============================================================================ +// THE WRAPPER FUNCTION +// ============================================================================ +// RunHomepageScreen starts the TUI and returns the menu string the user selected. +func RunHomepageScreen() string { + p := tea.NewProgram(initialHomepageModel(), tea.WithAltScreen()) // AltScreen creates a full-screen view + + finalModel, err := p.Run() + if err != nil { + fmt.Printf("Error running dashboard: %v", err) + os.Exit(1) + } + + if m, ok := finalModel.(homepageModel); ok { + return m.selected + } + + return "quit" +} + +/* +// Optional Main function to test it directly +func main() { + selection := RunHomepageScreen() + + // Clear the screen on exit to print standard output + fmt.Print("\033[H\033[2J") + + if selection == "quit" || selection == "🚪 Logout / Quit" { + fmt.Println("Gracefully disconnected from SkyRama servers. Goodbye!") + os.Exit(0) + } + + fmt.Printf("You selected: %s\n", selection) + fmt.Println("Here is where you would load the next Bubble Tea model for that screen!") +} +*/ diff --git a/backend/server/login.go b/backend/server/login.go index 06ab7d0..1796396 100644 --- a/backend/server/login.go +++ b/backend/server/login.go @@ -1 +1,206 @@ package main + +import ( + "fmt" + "os" + "strings" + + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +// ============================================================================ +// STYLING DEFINITIONS (Lipgloss) +// ============================================================================ +var ( + focusedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("205")).Bold(true) + blurredStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("240")) + cursorStyle = focusedStyle.Copy() + noStyle = lipgloss.NewStyle() + + // A nice box around the login screen + dialogBoxStyle = lipgloss.NewStyle(). + Border(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("87")). + Padding(1, 4). + MarginTop(1). + MarginLeft(2) +) + +// ============================================================================ +// 1. THE MODEL +// ============================================================================ +type loginModel struct { + focusIndex int + inputs []textinput.Model + cursorMode textinput.CursorMode + + // Flags to return back to the main application + isSubmitted bool + isCanceled bool + errorMessage string +} + +func initialModell() loginModel { + m := loginModel{ + inputs: make([]textinput.Model, 2), + } + + var t textinput.Model + for i := range m.inputs { + t = textinput.New() + t.Cursor.Style = cursorStyle + t.CharLimit = 32 + + switch i { + case 0: + t.Placeholder = "Username" + t.Focus() + t.PromptStyle = focusedStyle + t.TextStyle = focusedStyle + case 1: + t.Placeholder = "Password" + t.EchoMode = textinput.EchoPassword // Masks the password with * + t.EchoCharacter = '•' + } + + m.inputs[i] = t + } + + return m +} + +// ============================================================================ +// 2. THE INIT FUNCTION (Runs once on startup) +// ============================================================================ +func (m loginModel) Init() tea.Cmd { + return textinput.Blink +} + +// ============================================================================ +// 3. THE UPDATE FUNCTION (Handles keypresses) +// ============================================================================ +func (m loginModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "esc": + m.isCanceled = true + return m, tea.Quit + + // Handle switching between username and password fields + case "tab", "shift+tab", "enter", "up", "down": + s := msg.String() + + // If they press Enter on the password field, submit the form + if s == "enter" && m.focusIndex == len(m.inputs)-1 { + m.isSubmitted = true + return m, tea.Quit + } + + // Cycle through inputs + if s == "up" || s == "shift+tab" { + m.focusIndex-- + } else { + m.focusIndex++ + } + + if m.focusIndex > len(m.inputs)-1 { + m.focusIndex = 0 + } else if m.focusIndex < 0 { + m.focusIndex = len(m.inputs) - 1 + } + + // Apply focus states + cmds := make([]tea.Cmd, len(m.inputs)) + for i := 0; i <= len(m.inputs)-1; i++ { + if i == m.focusIndex { + cmds[i] = m.inputs[i].Focus() + m.inputs[i].PromptStyle = focusedStyle + m.inputs[i].TextStyle = focusedStyle + continue + } + m.inputs[i].Blur() + m.inputs[i].PromptStyle = noStyle + m.inputs[i].TextStyle = noStyle + } + + return m, tea.Batch(cmds...) + } + } + + // Handle character inputs and blinking + cmd := m.updateInputs(msg) + return m, cmd +} + +func (m *loginModel) updateInputs(msg tea.Msg) tea.Cmd { + cmds := make([]tea.Cmd, len(m.inputs)) + for i := range m.inputs { + m.inputs[i], cmds[i] = m.inputs[i].Update(msg) + } + return tea.Batch(cmds...) +} + +// ============================================================================ +// 4. THE VIEW FUNCTION (Renders the UI) +// ============================================================================ +func (m loginModel) View() string { + // Build the UI string + var b strings.Builder + + b.WriteString(lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("78")).Render("✈️ SKYRAMA TERMINAL LOGIN\n\n")) + + for i := range m.inputs { + b.WriteString(m.inputs[i].View()) + if i < len(m.inputs)-1 { + b.WriteRune('\n') + } + } + + button := &lipgloss.Style{} + if m.focusIndex == len(m.inputs) { + button = &focusedStyle + } else { + button = &blurredStyle + } + + b.WriteString("\n") + if m.errorMessage != "" { + b.WriteString(lipgloss.NewStyle().Foreground(lipgloss.Color("9")).Render("⚠️ " + m.errorMessage + "\n")) + } else { + b.WriteString("\n") + } + b.WriteString(button.Render("[ Submit ]")) + b.WriteString(blurredStyle.Render("\n\n(esc to quit)")) + + // Wrap the whole thing in our dialog box + return dialogBoxStyle.Render(b.String()) + "\n" +} + +// ============================================================================ +// THE WRAPPER FUNCTION (Call this from your app) +// ============================================================================ +// RunLoginScreen starts the TUI and returns the username, password, and a boolean +// indicating if the user completed the form (true) or pressed escape (false). +func RunLoginScreen() (username string, password string, submitted bool) { + + p := tea.NewProgram(initialModell()) + + // Run the Bubble Tea program synchronously + finalModel, err := p.Run() + if err != nil { + fmt.Printf("Error running login screen: %v", err) + os.Exit(1) + } + + // Cast the returned tea.Model back into our specific loginModel + if m, ok := finalModel.(loginModel); ok { + if m.isSubmitted { + return m.inputs[0].Value(), m.inputs[1].Value(), true + } + } + + return "", "", false +} diff --git a/backend/server/main.go b/backend/server/main.go new file mode 100644 index 0000000..07ca45d --- /dev/null +++ b/backend/server/main.go @@ -0,0 +1,182 @@ +package main + +import ( + "context" + "database/sql" + "fmt" + "os" + + tea "github.com/charmbracelet/bubbletea" + _ "github.com/go-sql-driver/mysql" // MySQL Driver + "golang.org/x/crypto/bcrypt" + + // CHANGE THIS to match your go.mod name + /dba + "skyrama_clone_backend/backend/db" +) + +// ============================================================================ +// 1. STATE DEFINITIONS +// ============================================================================ +type sessionState int + +const ( + stateLogin sessionState = iota + stateHomepage +) + +// ============================================================================ +// 2. THE MASTER MODEL (The Router) +// ============================================================================ +type mainModel struct { + state sessionState + queries *db.Queries // <-- NEW: Holds our database queries + + login loginModel + homepage homepageModel +} + +func initialModel(q *db.Queries) mainModel { + return mainModel{ + state: stateLogin, + queries: q, + login: initialModell(), + homepage: initialHomepageModel(), + } +} + +func (m mainModel) Init() tea.Cmd { + return m.login.Init() +} + +// ============================================================================ +// 3. THE MASTER UPDATE (Traffic Cop & Authentication) +// ============================================================================ +func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + if keyMsg, ok := msg.(tea.KeyMsg); ok && keyMsg.String() == "ctrl+c" { + return m, tea.Quit + } + + //var cmd tea.Cmd + var cmds []tea.Cmd + ctx := context.Background() + + switch m.state { + + case stateLogin: + newLoginModel, loginCmd := m.login.Update(msg) + m.login = newLoginModel.(loginModel) + cmds = append(cmds, loginCmd) + + // Did the user press Enter on the Submit button? + if m.login.isSubmitted { + username := m.login.inputs[0].Value() + password := m.login.inputs[1].Value() + + // 1. Fetch the user from the database + user, err := m.queries.GetUserByUsername(ctx, username) + if err != nil { + m.login.errorMessage = "User not found." + m.login.isSubmitted = false // Reset so they can try again + return m, nil + } + + // 2. Verify the password hash + err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)) + if err != nil { + m.login.errorMessage = "Invalid password." + m.login.isSubmitted = false // Reset so they can try again + return m, nil + } + + // 3. Fetch their Airport Data + // Note: user.ID is int32 in sqlc (based on schema) + airport, err := m.queries.GetAirportByUserId(ctx, user.ID) + if err != nil { + m.login.errorMessage = "No airport found for this user." + m.login.isSubmitted = false + return m, nil + } + + // 4. Fetch their Fleet Count + // Note: airport.ID is uint32, GetPlayerFleet expects the correct type + fleet, _ := m.queries.GetPlayerFleet(ctx, airport.ID) + + // 5. SUCCESS! Push real data to the homepage and switch screens + m.homepage.playerName = user.Username + m.homepage.cash = int(airport.Cash) + m.homepage.fleetCount = len(fleet) + + m.state = stateHomepage + cmds = append(cmds, m.homepage.Init()) + } else if m.login.isCanceled { + return m, tea.Quit + } + + case stateHomepage: + newHomepageModel, homeCmd := m.homepage.Update(msg) + m.homepage = newHomepageModel.(homepageModel) + cmds = append(cmds, homeCmd) + + if m.homepage.selected != "" { + if m.homepage.selected == "🚪 Logout / Quit" { + return m, tea.Quit + } + // Placeholder for other menus + return m, tea.Quit + } + } + + return m, tea.Batch(cmds...) +} + +func (m mainModel) View() string { + switch m.state { + case stateLogin: + return m.login.View() + case stateHomepage: + return m.homepage.View() + default: + return "Error: Unknown state" + } +} + +// ============================================================================ +// MAIN EXECUTION WITH DATABASE POOL +// ============================================================================ +func main() { + // 1. Connect to MySQL Database + // Ensure ?parseTime=true is present! + dsn := "skyramaUser:Skyrama1234.@tcp(127.0.0.1:3306)/skyrama_clone?parseTime=true" + dbConn, err := sql.Open("mysql", dsn) + if err != nil { + fmt.Printf("Error opening database pool: %v\n", err) + os.Exit(1) + } + defer dbConn.Close() + + if err := dbConn.Ping(); err != nil { + fmt.Printf("Database unreachable: %v\n", err) + os.Exit(1) + } + + // 2. Initialize sqlc queries + queries := db.New(dbConn) + + // 3. Start the Bubble Tea UI, passing the database into the model + p := tea.NewProgram(initialModel(queries), tea.WithAltScreen()) + + finalModel, err := p.Run() + if err != nil { + fmt.Printf("Fatal error starting SkyRama: %v", err) + os.Exit(1) + } + + fmt.Print("\033[H\033[2J") // Clear terminal on exit + if m, ok := finalModel.(mainModel); ok { + if m.state == stateHomepage && m.homepage.selected != "" && m.homepage.selected != "🚪 Logout / Quit" { + fmt.Printf("You clicked '%s', which we will build next!\n", m.homepage.selected) + } else { + fmt.Println("Gracefully disconnected from SkyRama servers. Goodbye!") + } + } +} diff --git a/backend/utils/packet_utils.go b/backend/utils/packet_utils.go index d4b585b..6ccb1e4 100644 --- a/backend/utils/packet_utils.go +++ b/backend/utils/packet_utils.go @@ -1 +1,78 @@ package utils + +import "skyrama_clone_backend/backend/objects" + +type Msg = isPacket_Msg + +func NewChat(msg string) Msg { + return &Packet_Chat{ + Chat: &ChatMessage{ + Msg: msg, + }, + } +} + +func NewId(id uint64) Msg { + return &Packet_Id{ + Id: &IdMessage{ + Id: id, + }, + } +} + +func NewOkResponse() Msg { + return &Packet_OkResponse{ + OkResponse: &OkResponseMessage{}, + } +} + +func NewDenyResponse(reason string) Msg { + return &Packet_DenyResponse{ + DenyResponse: &DenyResponseMessage{ + Reason: reason, + }, + } +} + +func NewPlayer(id uint64, player *objects.Player) Msg { + return &Packet_Player{ + Player: &PlayerMessage{ + Id: id, + Name: player.Name, + X: player.X, + Y: player.Y, + Radius: player.Radius, + Direction: player.Direction, + Speed: player.Speed, + }, + } +} + +func newSporeMessage(id uint64, spore *objects.Spore) *SporeMessage { + return &SporeMessage{ + Id: id, + X: spore.X, + Y: spore.Y, + Radius: spore.Radius, + } +} +func NewSpore(id uint64, spore *objects.Spore) Msg { + return &Packet_Spore{ + newSporeMessage(id, spore), + } +} + +func NewSporeBatches(spores map[uint64]*objects.Spore) Msg { + + SporeMessages := make([]*SporeMessage, len(spores)) + for id, spore := range spores { + SporeMessages = append(SporeMessages, newSporeMessage(id, spore)) + + } + + return &Packet_SporeBatch{ + SporeBatch: &SporesBatchMessage{ + Spores: SporeMessages, + }, + } +} diff --git a/backend/utils/packets.pb.go b/backend/utils/packets.pb.go new file mode 100644 index 0000000..72da9e1 --- /dev/null +++ b/backend/utils/packets.pb.go @@ -0,0 +1,1441 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v7.35.0 +// source: packets.proto + +package utils + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ChatMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatMessage) Reset() { + *x = ChatMessage{} + mi := &file_packets_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatMessage) ProtoMessage() {} + +func (x *ChatMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChatMessage.ProtoReflect.Descriptor instead. +func (*ChatMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{0} +} + +func (x *ChatMessage) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +type IdMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IdMessage) Reset() { + *x = IdMessage{} + mi := &file_packets_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IdMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IdMessage) ProtoMessage() {} + +func (x *IdMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IdMessage.ProtoReflect.Descriptor instead. +func (*IdMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{1} +} + +func (x *IdMessage) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +type LoginRequestMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LoginRequestMessage) Reset() { + *x = LoginRequestMessage{} + mi := &file_packets_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LoginRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginRequestMessage) ProtoMessage() {} + +func (x *LoginRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginRequestMessage.ProtoReflect.Descriptor instead. +func (*LoginRequestMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{2} +} + +func (x *LoginRequestMessage) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *LoginRequestMessage) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +type RegisterRequestMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` + Color int32 `protobuf:"varint,3,opt,name=color,proto3" json:"color,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegisterRequestMessage) Reset() { + *x = RegisterRequestMessage{} + mi := &file_packets_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterRequestMessage) ProtoMessage() {} + +func (x *RegisterRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterRequestMessage.ProtoReflect.Descriptor instead. +func (*RegisterRequestMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{3} +} + +func (x *RegisterRequestMessage) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *RegisterRequestMessage) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *RegisterRequestMessage) GetColor() int32 { + if x != nil { + return x.Color + } + return 0 +} + +type OkResponseMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *OkResponseMessage) Reset() { + *x = OkResponseMessage{} + mi := &file_packets_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *OkResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OkResponseMessage) ProtoMessage() {} + +func (x *OkResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OkResponseMessage.ProtoReflect.Descriptor instead. +func (*OkResponseMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{4} +} + +type DenyResponseMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reason string `protobuf:"bytes,1,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DenyResponseMessage) Reset() { + *x = DenyResponseMessage{} + mi := &file_packets_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DenyResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DenyResponseMessage) ProtoMessage() {} + +func (x *DenyResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DenyResponseMessage.ProtoReflect.Descriptor instead. +func (*DenyResponseMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{5} +} + +func (x *DenyResponseMessage) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type PlayerMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + X float64 `protobuf:"fixed64,3,opt,name=x,proto3" json:"x,omitempty"` + Y float64 `protobuf:"fixed64,4,opt,name=y,proto3" json:"y,omitempty"` + Radius float64 `protobuf:"fixed64,5,opt,name=radius,proto3" json:"radius,omitempty"` + Direction float64 `protobuf:"fixed64,6,opt,name=direction,proto3" json:"direction,omitempty"` + Speed float64 `protobuf:"fixed64,7,opt,name=speed,proto3" json:"speed,omitempty"` + Color int32 `protobuf:"varint,8,opt,name=color,proto3" json:"color,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PlayerMessage) Reset() { + *x = PlayerMessage{} + mi := &file_packets_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PlayerMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlayerMessage) ProtoMessage() {} + +func (x *PlayerMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlayerMessage.ProtoReflect.Descriptor instead. +func (*PlayerMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{6} +} + +func (x *PlayerMessage) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *PlayerMessage) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *PlayerMessage) GetX() float64 { + if x != nil { + return x.X + } + return 0 +} + +func (x *PlayerMessage) GetY() float64 { + if x != nil { + return x.Y + } + return 0 +} + +func (x *PlayerMessage) GetRadius() float64 { + if x != nil { + return x.Radius + } + return 0 +} + +func (x *PlayerMessage) GetDirection() float64 { + if x != nil { + return x.Direction + } + return 0 +} + +func (x *PlayerMessage) GetSpeed() float64 { + if x != nil { + return x.Speed + } + return 0 +} + +func (x *PlayerMessage) GetColor() int32 { + if x != nil { + return x.Color + } + return 0 +} + +type PlayerDirectionMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Direction float64 `protobuf:"fixed64,1,opt,name=direction,proto3" json:"direction,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PlayerDirectionMessage) Reset() { + *x = PlayerDirectionMessage{} + mi := &file_packets_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PlayerDirectionMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlayerDirectionMessage) ProtoMessage() {} + +func (x *PlayerDirectionMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlayerDirectionMessage.ProtoReflect.Descriptor instead. +func (*PlayerDirectionMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{7} +} + +func (x *PlayerDirectionMessage) GetDirection() float64 { + if x != nil { + return x.Direction + } + return 0 +} + +type SporeMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + X float64 `protobuf:"fixed64,2,opt,name=x,proto3" json:"x,omitempty"` + Y float64 `protobuf:"fixed64,3,opt,name=y,proto3" json:"y,omitempty"` + Radius float64 `protobuf:"fixed64,4,opt,name=radius,proto3" json:"radius,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SporeMessage) Reset() { + *x = SporeMessage{} + mi := &file_packets_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SporeMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SporeMessage) ProtoMessage() {} + +func (x *SporeMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SporeMessage.ProtoReflect.Descriptor instead. +func (*SporeMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{8} +} + +func (x *SporeMessage) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *SporeMessage) GetX() float64 { + if x != nil { + return x.X + } + return 0 +} + +func (x *SporeMessage) GetY() float64 { + if x != nil { + return x.Y + } + return 0 +} + +func (x *SporeMessage) GetRadius() float64 { + if x != nil { + return x.Radius + } + return 0 +} + +type SporeConsumedMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + SporeId uint64 `protobuf:"varint,1,opt,name=spore_id,json=sporeId,proto3" json:"spore_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SporeConsumedMessage) Reset() { + *x = SporeConsumedMessage{} + mi := &file_packets_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SporeConsumedMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SporeConsumedMessage) ProtoMessage() {} + +func (x *SporeConsumedMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SporeConsumedMessage.ProtoReflect.Descriptor instead. +func (*SporeConsumedMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{9} +} + +func (x *SporeConsumedMessage) GetSporeId() uint64 { + if x != nil { + return x.SporeId + } + return 0 +} + +type SporesBatchMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Spores []*SporeMessage `protobuf:"bytes,1,rep,name=spores,proto3" json:"spores,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SporesBatchMessage) Reset() { + *x = SporesBatchMessage{} + mi := &file_packets_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SporesBatchMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SporesBatchMessage) ProtoMessage() {} + +func (x *SporesBatchMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SporesBatchMessage.ProtoReflect.Descriptor instead. +func (*SporesBatchMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{10} +} + +func (x *SporesBatchMessage) GetSpores() []*SporeMessage { + if x != nil { + return x.Spores + } + return nil +} + +type PlayerConsumedMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + PlayerId uint64 `protobuf:"varint,1,opt,name=player_id,json=playerId,proto3" json:"player_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PlayerConsumedMessage) Reset() { + *x = PlayerConsumedMessage{} + mi := &file_packets_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PlayerConsumedMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlayerConsumedMessage) ProtoMessage() {} + +func (x *PlayerConsumedMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlayerConsumedMessage.ProtoReflect.Descriptor instead. +func (*PlayerConsumedMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{11} +} + +func (x *PlayerConsumedMessage) GetPlayerId() uint64 { + if x != nil { + return x.PlayerId + } + return 0 +} + +type HiscoreBoardRequestMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HiscoreBoardRequestMessage) Reset() { + *x = HiscoreBoardRequestMessage{} + mi := &file_packets_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HiscoreBoardRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HiscoreBoardRequestMessage) ProtoMessage() {} + +func (x *HiscoreBoardRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HiscoreBoardRequestMessage.ProtoReflect.Descriptor instead. +func (*HiscoreBoardRequestMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{12} +} + +type HiscoreMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Rank uint64 `protobuf:"varint,1,opt,name=rank,proto3" json:"rank,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Score uint64 `protobuf:"varint,3,opt,name=score,proto3" json:"score,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HiscoreMessage) Reset() { + *x = HiscoreMessage{} + mi := &file_packets_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HiscoreMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HiscoreMessage) ProtoMessage() {} + +func (x *HiscoreMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HiscoreMessage.ProtoReflect.Descriptor instead. +func (*HiscoreMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{13} +} + +func (x *HiscoreMessage) GetRank() uint64 { + if x != nil { + return x.Rank + } + return 0 +} + +func (x *HiscoreMessage) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *HiscoreMessage) GetScore() uint64 { + if x != nil { + return x.Score + } + return 0 +} + +type HiscoreBoardMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Hiscores []*HiscoreMessage `protobuf:"bytes,1,rep,name=hiscores,proto3" json:"hiscores,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HiscoreBoardMessage) Reset() { + *x = HiscoreBoardMessage{} + mi := &file_packets_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HiscoreBoardMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HiscoreBoardMessage) ProtoMessage() {} + +func (x *HiscoreBoardMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HiscoreBoardMessage.ProtoReflect.Descriptor instead. +func (*HiscoreBoardMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{14} +} + +func (x *HiscoreBoardMessage) GetHiscores() []*HiscoreMessage { + if x != nil { + return x.Hiscores + } + return nil +} + +type FinishedBrowsingHiscoresMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FinishedBrowsingHiscoresMessage) Reset() { + *x = FinishedBrowsingHiscoresMessage{} + mi := &file_packets_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FinishedBrowsingHiscoresMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FinishedBrowsingHiscoresMessage) ProtoMessage() {} + +func (x *FinishedBrowsingHiscoresMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FinishedBrowsingHiscoresMessage.ProtoReflect.Descriptor instead. +func (*FinishedBrowsingHiscoresMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{15} +} + +type SearchHiscoreMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SearchHiscoreMessage) Reset() { + *x = SearchHiscoreMessage{} + mi := &file_packets_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SearchHiscoreMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchHiscoreMessage) ProtoMessage() {} + +func (x *SearchHiscoreMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchHiscoreMessage.ProtoReflect.Descriptor instead. +func (*SearchHiscoreMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{16} +} + +func (x *SearchHiscoreMessage) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type DisconnectMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reason string `protobuf:"bytes,1,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DisconnectMessage) Reset() { + *x = DisconnectMessage{} + mi := &file_packets_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DisconnectMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DisconnectMessage) ProtoMessage() {} + +func (x *DisconnectMessage) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DisconnectMessage.ProtoReflect.Descriptor instead. +func (*DisconnectMessage) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{17} +} + +func (x *DisconnectMessage) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type Packet struct { + state protoimpl.MessageState `protogen:"open.v1"` + SenderId uint64 `protobuf:"varint,1,opt,name=sender_id,json=senderId,proto3" json:"sender_id,omitempty"` + // Types that are valid to be assigned to Msg: + // + // *Packet_Chat + // *Packet_Id + // *Packet_LoginRequest + // *Packet_RegisterRequest + // *Packet_OkResponse + // *Packet_DenyResponse + // *Packet_Player + // *Packet_PlayerDirection + // *Packet_Spore + // *Packet_SporeConsumed + // *Packet_SporesBatch + // *Packet_PlayerConsumed + // *Packet_HiscoreBoardRequest + // *Packet_Hiscore + // *Packet_HiscoreBoard + // *Packet_FinishedBrowsingHiscores + // *Packet_SearchHiscore + // *Packet_Disconnect + Msg isPacket_Msg `protobuf_oneof:"msg"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Packet) Reset() { + *x = Packet{} + mi := &file_packets_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Packet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Packet) ProtoMessage() {} + +func (x *Packet) ProtoReflect() protoreflect.Message { + mi := &file_packets_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Packet.ProtoReflect.Descriptor instead. +func (*Packet) Descriptor() ([]byte, []int) { + return file_packets_proto_rawDescGZIP(), []int{18} +} + +func (x *Packet) GetSenderId() uint64 { + if x != nil { + return x.SenderId + } + return 0 +} + +func (x *Packet) GetMsg() isPacket_Msg { + if x != nil { + return x.Msg + } + return nil +} + +func (x *Packet) GetChat() *ChatMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_Chat); ok { + return x.Chat + } + } + return nil +} + +func (x *Packet) GetId() *IdMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_Id); ok { + return x.Id + } + } + return nil +} + +func (x *Packet) GetLoginRequest() *LoginRequestMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_LoginRequest); ok { + return x.LoginRequest + } + } + return nil +} + +func (x *Packet) GetRegisterRequest() *RegisterRequestMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_RegisterRequest); ok { + return x.RegisterRequest + } + } + return nil +} + +func (x *Packet) GetOkResponse() *OkResponseMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_OkResponse); ok { + return x.OkResponse + } + } + return nil +} + +func (x *Packet) GetDenyResponse() *DenyResponseMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_DenyResponse); ok { + return x.DenyResponse + } + } + return nil +} + +func (x *Packet) GetPlayer() *PlayerMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_Player); ok { + return x.Player + } + } + return nil +} + +func (x *Packet) GetPlayerDirection() *PlayerDirectionMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_PlayerDirection); ok { + return x.PlayerDirection + } + } + return nil +} + +func (x *Packet) GetSpore() *SporeMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_Spore); ok { + return x.Spore + } + } + return nil +} + +func (x *Packet) GetSporeConsumed() *SporeConsumedMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_SporeConsumed); ok { + return x.SporeConsumed + } + } + return nil +} + +func (x *Packet) GetSporesBatch() *SporesBatchMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_SporesBatch); ok { + return x.SporesBatch + } + } + return nil +} + +func (x *Packet) GetPlayerConsumed() *PlayerConsumedMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_PlayerConsumed); ok { + return x.PlayerConsumed + } + } + return nil +} + +func (x *Packet) GetHiscoreBoardRequest() *HiscoreBoardRequestMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_HiscoreBoardRequest); ok { + return x.HiscoreBoardRequest + } + } + return nil +} + +func (x *Packet) GetHiscore() *HiscoreMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_Hiscore); ok { + return x.Hiscore + } + } + return nil +} + +func (x *Packet) GetHiscoreBoard() *HiscoreBoardMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_HiscoreBoard); ok { + return x.HiscoreBoard + } + } + return nil +} + +func (x *Packet) GetFinishedBrowsingHiscores() *FinishedBrowsingHiscoresMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_FinishedBrowsingHiscores); ok { + return x.FinishedBrowsingHiscores + } + } + return nil +} + +func (x *Packet) GetSearchHiscore() *SearchHiscoreMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_SearchHiscore); ok { + return x.SearchHiscore + } + } + return nil +} + +func (x *Packet) GetDisconnect() *DisconnectMessage { + if x != nil { + if x, ok := x.Msg.(*Packet_Disconnect); ok { + return x.Disconnect + } + } + return nil +} + +type isPacket_Msg interface { + isPacket_Msg() +} + +type Packet_Chat struct { + Chat *ChatMessage `protobuf:"bytes,2,opt,name=chat,proto3,oneof"` +} + +type Packet_Id struct { + Id *IdMessage `protobuf:"bytes,3,opt,name=id,proto3,oneof"` +} + +type Packet_LoginRequest struct { + LoginRequest *LoginRequestMessage `protobuf:"bytes,4,opt,name=login_request,json=loginRequest,proto3,oneof"` +} + +type Packet_RegisterRequest struct { + RegisterRequest *RegisterRequestMessage `protobuf:"bytes,5,opt,name=register_request,json=registerRequest,proto3,oneof"` +} + +type Packet_OkResponse struct { + OkResponse *OkResponseMessage `protobuf:"bytes,6,opt,name=ok_response,json=okResponse,proto3,oneof"` +} + +type Packet_DenyResponse struct { + DenyResponse *DenyResponseMessage `protobuf:"bytes,7,opt,name=deny_response,json=denyResponse,proto3,oneof"` +} + +type Packet_Player struct { + Player *PlayerMessage `protobuf:"bytes,8,opt,name=player,proto3,oneof"` +} + +type Packet_PlayerDirection struct { + PlayerDirection *PlayerDirectionMessage `protobuf:"bytes,9,opt,name=player_direction,json=playerDirection,proto3,oneof"` +} + +type Packet_Spore struct { + Spore *SporeMessage `protobuf:"bytes,10,opt,name=spore,proto3,oneof"` +} + +type Packet_SporeConsumed struct { + SporeConsumed *SporeConsumedMessage `protobuf:"bytes,11,opt,name=spore_consumed,json=sporeConsumed,proto3,oneof"` +} + +type Packet_SporesBatch struct { + SporesBatch *SporesBatchMessage `protobuf:"bytes,12,opt,name=spores_batch,json=sporesBatch,proto3,oneof"` +} + +type Packet_PlayerConsumed struct { + PlayerConsumed *PlayerConsumedMessage `protobuf:"bytes,13,opt,name=player_consumed,json=playerConsumed,proto3,oneof"` +} + +type Packet_HiscoreBoardRequest struct { + HiscoreBoardRequest *HiscoreBoardRequestMessage `protobuf:"bytes,14,opt,name=hiscore_board_request,json=hiscoreBoardRequest,proto3,oneof"` +} + +type Packet_Hiscore struct { + Hiscore *HiscoreMessage `protobuf:"bytes,15,opt,name=hiscore,proto3,oneof"` +} + +type Packet_HiscoreBoard struct { + HiscoreBoard *HiscoreBoardMessage `protobuf:"bytes,16,opt,name=hiscore_board,json=hiscoreBoard,proto3,oneof"` +} + +type Packet_FinishedBrowsingHiscores struct { + FinishedBrowsingHiscores *FinishedBrowsingHiscoresMessage `protobuf:"bytes,17,opt,name=finished_browsing_hiscores,json=finishedBrowsingHiscores,proto3,oneof"` +} + +type Packet_SearchHiscore struct { + SearchHiscore *SearchHiscoreMessage `protobuf:"bytes,18,opt,name=search_hiscore,json=searchHiscore,proto3,oneof"` +} + +type Packet_Disconnect struct { + Disconnect *DisconnectMessage `protobuf:"bytes,19,opt,name=disconnect,proto3,oneof"` +} + +func (*Packet_Chat) isPacket_Msg() {} + +func (*Packet_Id) isPacket_Msg() {} + +func (*Packet_LoginRequest) isPacket_Msg() {} + +func (*Packet_RegisterRequest) isPacket_Msg() {} + +func (*Packet_OkResponse) isPacket_Msg() {} + +func (*Packet_DenyResponse) isPacket_Msg() {} + +func (*Packet_Player) isPacket_Msg() {} + +func (*Packet_PlayerDirection) isPacket_Msg() {} + +func (*Packet_Spore) isPacket_Msg() {} + +func (*Packet_SporeConsumed) isPacket_Msg() {} + +func (*Packet_SporesBatch) isPacket_Msg() {} + +func (*Packet_PlayerConsumed) isPacket_Msg() {} + +func (*Packet_HiscoreBoardRequest) isPacket_Msg() {} + +func (*Packet_Hiscore) isPacket_Msg() {} + +func (*Packet_HiscoreBoard) isPacket_Msg() {} + +func (*Packet_FinishedBrowsingHiscores) isPacket_Msg() {} + +func (*Packet_SearchHiscore) isPacket_Msg() {} + +func (*Packet_Disconnect) isPacket_Msg() {} + +var File_packets_proto protoreflect.FileDescriptor + +const file_packets_proto_rawDesc = "" + + "\n" + + "\rpackets.proto\x12\apackets\"\x1f\n" + + "\vChatMessage\x12\x10\n" + + "\x03msg\x18\x01 \x01(\tR\x03msg\"\x1b\n" + + "\tIdMessage\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\"M\n" + + "\x13LoginRequestMessage\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\"f\n" + + "\x16RegisterRequestMessage\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\x12\x14\n" + + "\x05color\x18\x03 \x01(\x05R\x05color\"\x13\n" + + "\x11OkResponseMessage\"-\n" + + "\x13DenyResponseMessage\x12\x16\n" + + "\x06reason\x18\x01 \x01(\tR\x06reason\"\xb1\x01\n" + + "\rPlayerMessage\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\f\n" + + "\x01x\x18\x03 \x01(\x01R\x01x\x12\f\n" + + "\x01y\x18\x04 \x01(\x01R\x01y\x12\x16\n" + + "\x06radius\x18\x05 \x01(\x01R\x06radius\x12\x1c\n" + + "\tdirection\x18\x06 \x01(\x01R\tdirection\x12\x14\n" + + "\x05speed\x18\a \x01(\x01R\x05speed\x12\x14\n" + + "\x05color\x18\b \x01(\x05R\x05color\"6\n" + + "\x16PlayerDirectionMessage\x12\x1c\n" + + "\tdirection\x18\x01 \x01(\x01R\tdirection\"R\n" + + "\fSporeMessage\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x12\f\n" + + "\x01x\x18\x02 \x01(\x01R\x01x\x12\f\n" + + "\x01y\x18\x03 \x01(\x01R\x01y\x12\x16\n" + + "\x06radius\x18\x04 \x01(\x01R\x06radius\"1\n" + + "\x14SporeConsumedMessage\x12\x19\n" + + "\bspore_id\x18\x01 \x01(\x04R\asporeId\"C\n" + + "\x12SporesBatchMessage\x12-\n" + + "\x06spores\x18\x01 \x03(\v2\x15.packets.SporeMessageR\x06spores\"4\n" + + "\x15PlayerConsumedMessage\x12\x1b\n" + + "\tplayer_id\x18\x01 \x01(\x04R\bplayerId\"\x1c\n" + + "\x1aHiscoreBoardRequestMessage\"N\n" + + "\x0eHiscoreMessage\x12\x12\n" + + "\x04rank\x18\x01 \x01(\x04R\x04rank\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" + + "\x05score\x18\x03 \x01(\x04R\x05score\"J\n" + + "\x13HiscoreBoardMessage\x123\n" + + "\bhiscores\x18\x01 \x03(\v2\x17.packets.HiscoreMessageR\bhiscores\"!\n" + + "\x1fFinishedBrowsingHiscoresMessage\"*\n" + + "\x14SearchHiscoreMessage\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"+\n" + + "\x11DisconnectMessage\x12\x16\n" + + "\x06reason\x18\x01 \x01(\tR\x06reason\"\xde\t\n" + + "\x06Packet\x12\x1b\n" + + "\tsender_id\x18\x01 \x01(\x04R\bsenderId\x12*\n" + + "\x04chat\x18\x02 \x01(\v2\x14.packets.ChatMessageH\x00R\x04chat\x12$\n" + + "\x02id\x18\x03 \x01(\v2\x12.packets.IdMessageH\x00R\x02id\x12C\n" + + "\rlogin_request\x18\x04 \x01(\v2\x1c.packets.LoginRequestMessageH\x00R\floginRequest\x12L\n" + + "\x10register_request\x18\x05 \x01(\v2\x1f.packets.RegisterRequestMessageH\x00R\x0fregisterRequest\x12=\n" + + "\vok_response\x18\x06 \x01(\v2\x1a.packets.OkResponseMessageH\x00R\n" + + "okResponse\x12C\n" + + "\rdeny_response\x18\a \x01(\v2\x1c.packets.DenyResponseMessageH\x00R\fdenyResponse\x120\n" + + "\x06player\x18\b \x01(\v2\x16.packets.PlayerMessageH\x00R\x06player\x12L\n" + + "\x10player_direction\x18\t \x01(\v2\x1f.packets.PlayerDirectionMessageH\x00R\x0fplayerDirection\x12-\n" + + "\x05spore\x18\n" + + " \x01(\v2\x15.packets.SporeMessageH\x00R\x05spore\x12F\n" + + "\x0espore_consumed\x18\v \x01(\v2\x1d.packets.SporeConsumedMessageH\x00R\rsporeConsumed\x12@\n" + + "\fspores_batch\x18\f \x01(\v2\x1b.packets.SporesBatchMessageH\x00R\vsporesBatch\x12I\n" + + "\x0fplayer_consumed\x18\r \x01(\v2\x1e.packets.PlayerConsumedMessageH\x00R\x0eplayerConsumed\x12Y\n" + + "\x15hiscore_board_request\x18\x0e \x01(\v2#.packets.HiscoreBoardRequestMessageH\x00R\x13hiscoreBoardRequest\x123\n" + + "\ahiscore\x18\x0f \x01(\v2\x17.packets.HiscoreMessageH\x00R\ahiscore\x12C\n" + + "\rhiscore_board\x18\x10 \x01(\v2\x1c.packets.HiscoreBoardMessageH\x00R\fhiscoreBoard\x12h\n" + + "\x1afinished_browsing_hiscores\x18\x11 \x01(\v2(.packets.FinishedBrowsingHiscoresMessageH\x00R\x18finishedBrowsingHiscores\x12F\n" + + "\x0esearch_hiscore\x18\x12 \x01(\v2\x1d.packets.SearchHiscoreMessageH\x00R\rsearchHiscore\x12<\n" + + "\n" + + "disconnect\x18\x13 \x01(\v2\x1a.packets.DisconnectMessageH\x00R\n" + + "disconnectB\x05\n" + + "\x03msgB\bZ\x06utils/b\x06proto3" + +var ( + file_packets_proto_rawDescOnce sync.Once + file_packets_proto_rawDescData []byte +) + +func file_packets_proto_rawDescGZIP() []byte { + file_packets_proto_rawDescOnce.Do(func() { + file_packets_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_packets_proto_rawDesc), len(file_packets_proto_rawDesc))) + }) + return file_packets_proto_rawDescData +} + +var file_packets_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_packets_proto_goTypes = []any{ + (*ChatMessage)(nil), // 0: packets.ChatMessage + (*IdMessage)(nil), // 1: packets.IdMessage + (*LoginRequestMessage)(nil), // 2: packets.LoginRequestMessage + (*RegisterRequestMessage)(nil), // 3: packets.RegisterRequestMessage + (*OkResponseMessage)(nil), // 4: packets.OkResponseMessage + (*DenyResponseMessage)(nil), // 5: packets.DenyResponseMessage + (*PlayerMessage)(nil), // 6: packets.PlayerMessage + (*PlayerDirectionMessage)(nil), // 7: packets.PlayerDirectionMessage + (*SporeMessage)(nil), // 8: packets.SporeMessage + (*SporeConsumedMessage)(nil), // 9: packets.SporeConsumedMessage + (*SporesBatchMessage)(nil), // 10: packets.SporesBatchMessage + (*PlayerConsumedMessage)(nil), // 11: packets.PlayerConsumedMessage + (*HiscoreBoardRequestMessage)(nil), // 12: packets.HiscoreBoardRequestMessage + (*HiscoreMessage)(nil), // 13: packets.HiscoreMessage + (*HiscoreBoardMessage)(nil), // 14: packets.HiscoreBoardMessage + (*FinishedBrowsingHiscoresMessage)(nil), // 15: packets.FinishedBrowsingHiscoresMessage + (*SearchHiscoreMessage)(nil), // 16: packets.SearchHiscoreMessage + (*DisconnectMessage)(nil), // 17: packets.DisconnectMessage + (*Packet)(nil), // 18: packets.Packet +} +var file_packets_proto_depIdxs = []int32{ + 8, // 0: packets.SporesBatchMessage.spores:type_name -> packets.SporeMessage + 13, // 1: packets.HiscoreBoardMessage.hiscores:type_name -> packets.HiscoreMessage + 0, // 2: packets.Packet.chat:type_name -> packets.ChatMessage + 1, // 3: packets.Packet.id:type_name -> packets.IdMessage + 2, // 4: packets.Packet.login_request:type_name -> packets.LoginRequestMessage + 3, // 5: packets.Packet.register_request:type_name -> packets.RegisterRequestMessage + 4, // 6: packets.Packet.ok_response:type_name -> packets.OkResponseMessage + 5, // 7: packets.Packet.deny_response:type_name -> packets.DenyResponseMessage + 6, // 8: packets.Packet.player:type_name -> packets.PlayerMessage + 7, // 9: packets.Packet.player_direction:type_name -> packets.PlayerDirectionMessage + 8, // 10: packets.Packet.spore:type_name -> packets.SporeMessage + 9, // 11: packets.Packet.spore_consumed:type_name -> packets.SporeConsumedMessage + 10, // 12: packets.Packet.spores_batch:type_name -> packets.SporesBatchMessage + 11, // 13: packets.Packet.player_consumed:type_name -> packets.PlayerConsumedMessage + 12, // 14: packets.Packet.hiscore_board_request:type_name -> packets.HiscoreBoardRequestMessage + 13, // 15: packets.Packet.hiscore:type_name -> packets.HiscoreMessage + 14, // 16: packets.Packet.hiscore_board:type_name -> packets.HiscoreBoardMessage + 15, // 17: packets.Packet.finished_browsing_hiscores:type_name -> packets.FinishedBrowsingHiscoresMessage + 16, // 18: packets.Packet.search_hiscore:type_name -> packets.SearchHiscoreMessage + 17, // 19: packets.Packet.disconnect:type_name -> packets.DisconnectMessage + 20, // [20:20] is the sub-list for method output_type + 20, // [20:20] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name +} + +func init() { file_packets_proto_init() } +func file_packets_proto_init() { + if File_packets_proto != nil { + return + } + file_packets_proto_msgTypes[18].OneofWrappers = []any{ + (*Packet_Chat)(nil), + (*Packet_Id)(nil), + (*Packet_LoginRequest)(nil), + (*Packet_RegisterRequest)(nil), + (*Packet_OkResponse)(nil), + (*Packet_DenyResponse)(nil), + (*Packet_Player)(nil), + (*Packet_PlayerDirection)(nil), + (*Packet_Spore)(nil), + (*Packet_SporeConsumed)(nil), + (*Packet_SporesBatch)(nil), + (*Packet_PlayerConsumed)(nil), + (*Packet_HiscoreBoardRequest)(nil), + (*Packet_Hiscore)(nil), + (*Packet_HiscoreBoard)(nil), + (*Packet_FinishedBrowsingHiscores)(nil), + (*Packet_SearchHiscore)(nil), + (*Packet_Disconnect)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_packets_proto_rawDesc), len(file_packets_proto_rawDesc)), + NumEnums: 0, + NumMessages: 19, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_packets_proto_goTypes, + DependencyIndexes: file_packets_proto_depIdxs, + MessageInfos: file_packets_proto_msgTypes, + }.Build() + File_packets_proto = out.File + file_packets_proto_goTypes = nil + file_packets_proto_depIdxs = nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9a19e27 --- /dev/null +++ b/go.mod @@ -0,0 +1,33 @@ +module skyrama_clone_backend + +go 1.26.3 + +require ( + filippo.io/edwards25519 v1.2.0 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/charmbracelet/bubbles v1.0.0 // indirect + github.com/charmbracelet/bubbletea v1.3.10 // indirect + github.com/charmbracelet/colorprofile v0.4.1 // indirect + github.com/charmbracelet/lipgloss v1.1.0 // indirect + github.com/charmbracelet/x/ansi v0.11.6 // indirect + github.com/charmbracelet/x/cellbuf v0.0.15 // indirect + github.com/charmbracelet/x/term v0.2.2 // indirect + github.com/clipperhouse/displaywidth v0.9.0 // indirect + github.com/clipperhouse/stringish v0.1.1 // indirect + github.com/clipperhouse/uax29/v2 v2.5.0 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/go-sql-driver/mysql v1.10.0 // indirect + github.com/lucasb-eyer/go-colorful v1.3.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.19 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/text v0.37.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..0dcbcfa --- /dev/null +++ b/go.sum @@ -0,0 +1,75 @@ +filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= +filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc= +github.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E= +github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= +github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= +github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk= +github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk= +github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= +github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= +github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= +github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= +github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI= +github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= +github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= +github.com/clipperhouse/displaywidth v0.9.0 h1:Qb4KOhYwRiN3viMv1v/3cTBlz3AcAZX3+y9OLhMtAtA= +github.com/clipperhouse/displaywidth v0.9.0/go.mod h1:aCAAqTlh4GIVkhQnJpbL0T/WfcrJXHcj8C0yjYcjOZA= +github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= +github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= +github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U= +github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw= +github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= +github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= +github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= diff --git a/shared/packets.proto b/shared/packets.proto new file mode 100644 index 0000000..42637ac --- /dev/null +++ b/shared/packets.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; +// protoc -I=shared --go_out=backend .\shared\packets.proto +package packets; +option go_package = "utils/"; + +message ChatMessage { string msg = 1; } +message IdMessage { uint64 id = 1; } +message LoginRequestMessage { string username = 1; string password = 2; } +message RegisterRequestMessage { string username = 1; string password = 2; int32 color = 3; } +message OkResponseMessage { } +message DenyResponseMessage { string reason = 1; } +message PlayerMessage { uint64 id = 1; string name = 2; double x = 3; double y = 4; double radius = 5; double direction = 6; double speed = 7; int32 color = 8; } +message PlayerDirectionMessage { double direction = 1; } +message SporeMessage { uint64 id = 1; double x = 2; double y = 3; double radius = 4; } +message SporeConsumedMessage { uint64 spore_id = 1; } +message SporesBatchMessage { repeated SporeMessage spores = 1; } +message PlayerConsumedMessage { uint64 player_id = 1; } +message HiscoreBoardRequestMessage { } +message HiscoreMessage { uint64 rank = 1; string name = 2; uint64 score = 3; } +message HiscoreBoardMessage { repeated HiscoreMessage hiscores = 1; } +message FinishedBrowsingHiscoresMessage { } +message SearchHiscoreMessage { string name = 1; } +message DisconnectMessage { string reason = 1; } + +message Packet { + uint64 sender_id = 1; + oneof msg { + ChatMessage chat = 2; + IdMessage id = 3; + LoginRequestMessage login_request = 4; + RegisterRequestMessage register_request = 5; + OkResponseMessage ok_response = 6; + DenyResponseMessage deny_response = 7; + PlayerMessage player = 8; + PlayerDirectionMessage player_direction = 9; + SporeMessage spore = 10; + SporeConsumedMessage spore_consumed = 11; + SporesBatchMessage spores_batch = 12; + PlayerConsumedMessage player_consumed = 13; + HiscoreBoardRequestMessage hiscore_board_request = 14; + HiscoreMessage hiscore = 15; + HiscoreBoardMessage hiscore_board = 16; + FinishedBrowsingHiscoresMessage finished_browsing_hiscores = 17; + SearchHiscoreMessage search_hiscore = 18; + DisconnectMessage disconnect = 19; + } +} \ No newline at end of file