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:
2026-07-02 10:09:28 -04:00
parent ad48f38ca5
commit 4a5264c5b0
14 changed files with 202 additions and 284 deletions
+13 -12
View File
@@ -20,6 +20,7 @@
extends Node
class_name RoundManager
const _td_rm = preload("res://scripts/teams/team_data.gd")
# ---------------------------------------------------------------------------
# Round Phase enum
@@ -177,8 +178,8 @@ func start_warmup() -> void:
_round_kills.clear()
_round_deaths.clear()
_consecutive_losses = {
TeamData.Team.COUNTER_TERRORIST: 0,
TeamData.Team.TERRORIST: 0,
_td_rm.Team.COUNTER_TERRORIST: 0,
_td_rm.Team.TERRORIST: 0,
}
print("[RoundManager] Warmup started — infinite duration")
round_phase_changed.emit(RoundPhase.WARMUP, 0)
@@ -230,7 +231,7 @@ func start_live() -> void:
round_phase_changed.emit(RoundPhase.LIVE, _round_num)
## End the current round, awarding money and transitioning to POST.
## winning_team: TeamData.Team enum of the winner.
## winning_team: int enum of the winner.
## reason: string describing the outcome (e.g. "elimination", "time_expired").
func end_round(winning_team: int, reason: String) -> void:
if _phase != RoundPhase.LIVE:
@@ -245,7 +246,7 @@ func end_round(winning_team: int, reason: String) -> void:
team_manager.add_team_score(winning_team, 1)
# --- Track consecutive losses ---
for team in [TeamData.Team.COUNTER_TERRORIST, TeamData.Team.TERRORIST]:
for team in [_td_rm.Team.COUNTER_TERRORIST, _td_rm.Team.TERRORIST]:
if team == winning_team:
_consecutive_losses[team] = 0
else:
@@ -253,7 +254,7 @@ func end_round(winning_team: int, reason: String) -> void:
# --- Compute economy data ---
var team_money_data: Dictionary = {}
for team in [TeamData.Team.COUNTER_TERRORIST, TeamData.Team.TERRORIST]:
for team in [_td_rm.Team.COUNTER_TERRORIST, _td_rm.Team.TERRORIST]:
var is_winner: bool = (team == winning_team)
var money: int = 0
if is_winner:
@@ -268,7 +269,7 @@ func end_round(winning_team: int, reason: String) -> void:
"total": money,
}
print("[RoundManager] Round %d ended — %s wins (%s)" % [_round_num, TeamData.get_team_name(winning_team), reason])
print("[RoundManager] Round %d ended — %s wins (%s)" % [_round_num, _td_rm.get_team_name(winning_team), reason])
# --- Match point / match win check ---
if team_manager:
@@ -277,7 +278,7 @@ func end_round(winning_team: int, reason: String) -> void:
# One more round wins the match
match_point.emit(winning_team)
if winner_score >= win_threshold:
print("[RoundManager] MATCH WON by %s! (Score: %d)" % [TeamData.get_team_name(winning_team), winner_threshold_scores(winning_team)])
print("[RoundManager] MATCH WON by %s! (Score: %d)" % [_td_rm.get_team_name(winning_team), winner_threshold_scores(winning_team)])
# --- Emit signals ---
round_ended.emit(winning_team, reason)
@@ -424,13 +425,13 @@ func _get_entity_ids_for_team(team: int) -> Array[int]:
## Default: the team with alive players wins; if both alive, CT wins.
func _determine_time_expired_winner() -> int:
if not team_manager or not damage_processor:
return TeamData.Team.COUNTER_TERRORIST
return _td_rm.Team.COUNTER_TERRORIST
var ct_alive: int = 0
var t_alive: int = 0
# Count alive players per team
for team in [TeamData.Team.COUNTER_TERRORIST, TeamData.Team.TERRORIST]:
for team in [_td_rm.Team.COUNTER_TERRORIST, _td_rm.Team.TERRORIST]:
var player_ids: Array[int] = team_manager.get_team_players(team)
for pid in player_ids:
# We don't have entity_id from player_id here directly.
@@ -440,7 +441,7 @@ func _determine_time_expired_winner() -> int:
# Simple default: CT wins on time expiry
# (Conceptually, CT defends the site and time runs out = attackers failed)
return TeamData.Team.COUNTER_TERRORIST
return _td_rm.Team.COUNTER_TERRORIST
## Resolve a player_id or entity_id to a team.
## For now, returns -1 if resolution fails.
@@ -455,6 +456,6 @@ func _get_entity_team(_entity_or_player_id: int) -> int:
func winner_threshold_scores(winning_team: int) -> String:
if not team_manager:
return str(win_threshold)
var ct_score: int = team_manager.get_team_score(TeamData.Team.COUNTER_TERRORIST)
var t_score: int = team_manager.get_team_score(TeamData.Team.TERRORIST)
var ct_score: int = team_manager.get_team_score(_td_rm.Team.COUNTER_TERRORIST)
var t_score: int = team_manager.get_team_score(_td_rm.Team.TERRORIST)
return "CT %d%d T" % [ct_score, t_score]