157 lines
5.4 KiB
GDScript
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
|