Fix headless class_name dependencies
- Replaced TeamData.Team type hints with int in all scripts - Added explicit preloads for headless mode class resolution - Created stub LagCompensation and DamageProcessor scripts - Fixed PluginManager, SpawnManager, EconomyManager, BuyZone, RoundManager, BuyMenuHandler, BombObjective class_name references - Updated server config to match ServerConfig.gd format Gray screen root cause: server scripts failed to parse in headless mode due to Godot 4 class_name loading order (Resource after Node), leaving server_main.gd non-functional — accepted connections but never spawned players.
This commit is contained in:
@@ -23,6 +23,21 @@
|
||||
##
|
||||
extends Node
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Force class_name script dependencies to load first
|
||||
# (Godot 4 headless mode doesn't resolve global classes in dependency order)
|
||||
# ---------------------------------------------------------------------------
|
||||
const _ws = preload("res://server/scripts/weapons/weapon_server.gd")
|
||||
const _lc = preload("res://server/scripts/combat/lag_compensation.gd")
|
||||
const _dp = preload("res://server/scripts/combat/damage_processor.gd")
|
||||
const _tm = preload("res://scripts/teams/team_manager.gd")
|
||||
const _rm = preload("res://server/scripts/round/round_manager.gd")
|
||||
const _em = preload("res://server/scripts/economy/economy_manager.gd")
|
||||
const _bm = preload("res://server/scripts/economy/buy_menu_handler.gd")
|
||||
const _bo = preload("res://server/scripts/objectives/bomb_objective.gd")
|
||||
const _sm = preload("res://scripts/teams/spawn_manager.gd")
|
||||
const _td = preload("res://scripts/teams/team_data.gd")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Signals
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -41,28 +56,28 @@ var simulation_server: Object = null
|
||||
var is_running: bool = false
|
||||
|
||||
## WeaponServer — handles hit-scan raycasting and lag-compensated fire.
|
||||
var weapon_server: WeaponServer = null
|
||||
var weapon_server = null
|
||||
|
||||
## LagCompensation — records player positions per tick for rewind raycasts.
|
||||
var lag_compensation: LagCompensation = null
|
||||
var lag_compensation = null
|
||||
|
||||
## DamageProcessor — applies hit results, tracks health and kills.
|
||||
var damage_processor: DamageProcessor = null
|
||||
var damage_processor = null
|
||||
|
||||
## TeamManager — manages team assignment and scoring.
|
||||
var team_manager: TeamManager = null
|
||||
var team_manager = null
|
||||
|
||||
## RoundManager — match lifecycle (warmup → prep → live → post).
|
||||
var round_manager: RoundManager = null
|
||||
var round_manager = null
|
||||
|
||||
## EconomyManager — per-player money tracking and earnings.
|
||||
var economy_manager: EconomyManager = null
|
||||
var economy_manager = null
|
||||
|
||||
## BuyMenuHandler — server-side buy request validation and processing.
|
||||
var buy_menu_handler: BuyMenuHandler = null
|
||||
var buy_menu_handler = null
|
||||
|
||||
## BombObjective — server-authoritative bomb plant/defuse logic.
|
||||
var bomb_objective: BombObjective = null
|
||||
var bomb_objective = null
|
||||
|
||||
## Current server tick counter, incremented each time tick() is called.
|
||||
var _current_tick: int = 0
|
||||
@@ -108,34 +123,34 @@ func _ready() -> void:
|
||||
# Create and wire the WeaponServer with LagCompensation and DamageProcessor.
|
||||
# These work alongside the C++ SimulationServer for the GDScript
|
||||
# weapon path.
|
||||
weapon_server = WeaponServer.new()
|
||||
weapon_server = _ws.new()
|
||||
weapon_server.physics_world = get_viewport().get_world_3d()
|
||||
add_child(weapon_server)
|
||||
|
||||
lag_compensation = LagCompensation.new()
|
||||
lag_compensation = _lc.new()
|
||||
add_child(lag_compensation)
|
||||
|
||||
damage_processor = DamageProcessor.new()
|
||||
damage_processor = _dp.new()
|
||||
add_child(damage_processor)
|
||||
|
||||
# --- Round / Match lifecycle ---
|
||||
round_manager = RoundManager.new()
|
||||
round_manager = _rm.new()
|
||||
add_child(round_manager)
|
||||
|
||||
# Wire up TeamManager reference (find it in the tree or create it)
|
||||
team_manager = get_node_or_null("/root/TeamManager")
|
||||
if not team_manager:
|
||||
team_manager = TeamManager.new()
|
||||
team_manager = _tm.new()
|
||||
add_child(team_manager)
|
||||
|
||||
round_manager.team_manager = team_manager
|
||||
round_manager.damage_processor = damage_processor
|
||||
|
||||
# --- Economy system ---
|
||||
economy_manager = EconomyManager.new()
|
||||
economy_manager = _em.new()
|
||||
add_child(economy_manager)
|
||||
|
||||
buy_menu_handler = BuyMenuHandler.new()
|
||||
buy_menu_handler = _bm.new()
|
||||
add_child(buy_menu_handler)
|
||||
buy_menu_handler.initialise(economy_manager, weapon_server, team_manager)
|
||||
|
||||
@@ -167,7 +182,7 @@ func _ready() -> void:
|
||||
Engine.register_singleton("SimulationServer", simulation_server)
|
||||
|
||||
# --- Bomb / Defuse Objective ---
|
||||
bomb_objective = BombObjective.new()
|
||||
bomb_objective = _bo.new()
|
||||
add_child(bomb_objective)
|
||||
bomb_objective.round_manager = round_manager
|
||||
bomb_objective.team_manager = team_manager
|
||||
@@ -192,11 +207,11 @@ func _ready() -> void:
|
||||
# Wire: bomb explosion/defuse → round end
|
||||
bomb_objective.bomb_exploded.connect(func(_pos):
|
||||
if round_manager:
|
||||
round_manager.end_round(TeamData.Team.TERRORIST, "bomb_exploded")
|
||||
round_manager.end_round(_td.Team.TERRORIST, "bomb_exploded")
|
||||
)
|
||||
bomb_objective.bomb_defused.connect(func(_player_id):
|
||||
if round_manager:
|
||||
round_manager.end_round(TeamData.Team.COUNTER_TERRORIST, "bomb_defused")
|
||||
round_manager.end_round(_td.Team.COUNTER_TERRORIST, "bomb_defused")
|
||||
)
|
||||
|
||||
# Wire: round end → reset bomb
|
||||
@@ -380,7 +395,7 @@ func _on_kill_for_round(victim_id: int, shooter_id: int) -> void:
|
||||
|
||||
if all_dead and team_player_ids.size() > 0:
|
||||
print("[GameServer] Team elimination detected! %s eliminated by %s" %
|
||||
[TeamData.get_team_name(victim_team), TeamData.get_team_name(shooter_team)])
|
||||
[_td.get_team_name(victim_team), _td.get_team_name(shooter_team)])
|
||||
round_manager.end_round(shooter_team, "elimination")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -398,13 +413,13 @@ func _on_rcon_command(command: String, args: PackedStringArray) -> void:
|
||||
# end_round [team_name] [reason]
|
||||
var team_name: String = args[0] if args.size() > 0 else "ct"
|
||||
var reason: String = args[1] if args.size() > 1 else "admin"
|
||||
var team: int = TeamData.from_string(team_name)
|
||||
if team == TeamData.Team.SPECTATOR:
|
||||
var team: int = _td.from_string(team_name)
|
||||
if team == _td.Team.SPECTATOR:
|
||||
# Default to CT
|
||||
team = TeamData.Team.COUNTER_TERRORIST
|
||||
team = _td.Team.COUNTER_TERRORIST
|
||||
if round_manager:
|
||||
round_manager.end_round(team, reason)
|
||||
print("[GameServer] RCON: round ended — %s wins (%s)" % [TeamData.get_team_name(team), reason])
|
||||
print("[GameServer] RCON: round ended — %s wins (%s)" % [_td.get_team_name(team), reason])
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Main loop (128 Hz)
|
||||
|
||||
Reference in New Issue
Block a user