Files
millimeters-of-aluminum/scripts/singletons/game_manager.gd

157 lines
5.4 KiB
GDScript

# GameManager.gd
extends Node
var config: GameConfig
# --- Dictionaries to track players and their objects ---
var player_controllers: Dictionary = {} # Key: player_id, Value: PlayerController node
var player_pawns: Dictionary = {} # Key: player_id, Value: CharacterPawn3D node
# This variable will hold the reference to the currently active star system.
var current_star_system: StarSystem = null
var registered_spawners: Array[Spawner] = []
var waiting_players: Array[int] = [] # A queue for players waiting to spawn
# --- Scene References for 3D ---
var player_controller_3d_scene: PackedScene = preload("res://scenes/tests/3d/player_controller_3d.tscn")
var character_pawn_3d_scene: PackedScene = preload("res://scenes/tests/3d/character_pawn_3d.tscn")
func _ready():
# Load the configuration resource from its fixed path.
config = load("res://scripts/singletons/default_game_config.tres")
if not config:
# This is now expected since we are using 3D scenes directly.
print("GameManager: game_config.tres not found or used. Using direct 3D scene references.")
return
# Check command-line arguments to determine if this instance should be a server or client.
# Godot's "Run Multiple Instances" feature adds "--server" to the main instance.
if "--server" in OS.get_cmdline_args():
NetworkHandler.create_server()
elif "--host" in OS.get_cmdline_args():
NetworkHandler.create_server()
# Host also acts as a player, so we need to handle its own connection.
NetworkHandler.on_peer_connected.call_deferred(1)
else:
print("GameManager: Starting as CLIENT.")
NetworkHandler.create_client()
func _process(_delta):
if find_available_spawner():
_try_spawn_waiting_player()
# Called when the game starts (e.g., from _ready() in StarSystemGenerator)
func start_game():
pass
func queue_spawn_player(player_id: int):
waiting_players.append(player_id)
print("GameManager: Player %d queued for spawn." % player_id)
# function to process the waiting queue.
func _try_spawn_waiting_player():
if not waiting_players.is_empty() and not registered_spawners.is_empty():
var player_id = waiting_players.pop_back()
print("GameManager: Spawner is now available. Spawning waiting player %d." % player_id)
var spawn_point = find_available_spawner()
if spawn_point:
_spawn_player_pawn(player_id)
var pawn = player_pawns[player_id]
pawn.set_multiplayer_authority(player_id)
spawn_point.add_child(pawn)
# Traverse up to find the physics body (Ship/Module) we just spawned inside
var parent_body = _get_orbital_body_ancestor(spawn_point)
if parent_body:
# Match the ship's speed so we don't slam into the wall
pawn.linear_velocity = parent_body.linear_velocity
print("GameManager: Pawn inherited velocity ", pawn.linear_velocity, " from ", parent_body.name)
print("GameManager peer %s: Player %d spawned successfully." % [multiplayer.get_unique_id(), player_id])
else:
waiting_players.append(player_id)
print("GameManager peer %s: Failed to spawn player %d." % [multiplayer.get_unique_id(), player_id])
func find_available_spawner() -> Spawner:
var idx = registered_spawners.find_custom(func(spawner: Spawner) -> bool:
return spawner.can_spawn()
)
return registered_spawners[idx] if idx != -1 else null
# @rpc("call_local")
func _spawn_player_pawn(player_id: int):
var pawn = character_pawn_3d_scene.instantiate()
pawn.name = str(player_id)
player_pawns[player_id] = pawn
pawn.set_multiplayer_authority(player_id)
print("GameManager: Spawned 3D Pawn for player %d" % player_id)
# Any scene that generates a star system will call this function to register itself.
func register_star_system(system_node):
current_star_system = system_node
print("GameManager: Star system registered.")
func register_ship(ship: OrbitalBody3D):
if not is_instance_valid(current_star_system):
return
current_star_system.system_data.ships.append(ship)
# Spawners call this function to announce their presence.
func register_spawner(spawner_node: Spawner):
if not spawner_node in registered_spawners:
registered_spawners.append(spawner_node)
print("GameManager: Spawner '%s' registered." % spawner_node.name)
# NEW: If a player is waiting, try to spawn them now.
# _try_spawn_waiting_player()
# A helper function for easily accessing the system's data.
func get_system_data() -> SystemData:
if current_star_system:
return current_star_system.get_system_data()
return null
func get_all_trackable_bodies() -> Array[OrbitalBody3D]:
var all_bodies: Array[OrbitalBody3D] = []
if current_star_system:
# First, get all the celestial bodies (planets, moons, etc.)
var system_data = current_star_system.get_system_data()
if system_data:
all_bodies.append_array(system_data.all_bodies())
# Next, add all registered ships to the list.
return all_bodies
# --- CLIENT-SIDE RPC PROXY ---
# A client-side script can call this function to send a request to the server.
# Example: GameManager.request_server_action("some_action", [arg1, arg2])
@rpc("call_remote")
func request_server_action(action_name: String, args: Array = []):
# This function's body only runs on the SERVER.
print("Server received request: ", action_name, " with args: ", args)
# Helper to find the physics root (Module/Ship) from a child node (Spawner)
func _get_orbital_body_ancestor(node: Node) -> OrbitalBody3D:
var current = node
while current:
if current is OrbitalBody3D:
return current
current = current.get_parent()
return null