P7.9: fix headless export — resolve Resource class_name ordering + duplicate RoundManager + simulation stub API
- Fix dead code in server_main.gd (unreachable lag compensation print) - Remove WeaponData type hints from weapon_server.gd (Resource class_name in Node scripts = headless fail) - Use preload() instead of WeaponData class_name in weapon_definitions.gd for const refs - Lazy-init WEAPONS dict (const can't reference preload members) - Remove duplicate class_name RoundManager from server/scripts/round/round_manager.gd - Remove DamageProcessor type hints from round/round_manager.gd and bomb_objective.gd - Add start()/stop()/can_tick()/tick()/spawn_entity()/despawn_entity() to simulation_server_stub.gd - Fix get_world_3d() → get_tree().root.world_3d in weapon_server.gd Node context - Fix var data := → var data = for untyped WeaponDefinitions.get_weapon() returns - Clean export cache and verify server starts with zero parse errors
This commit is contained in:
@@ -9,7 +9,9 @@
|
||||
## print(data.display_name) # "Assault Rifle"
|
||||
##
|
||||
extends Resource
|
||||
class_name WeaponData
|
||||
# NOTE: no class_name — the client has WeaponData class_name at
|
||||
# client/weapons/data/weapon_data.gd with different field names.
|
||||
# Server code uses preload() + untyped references to avoid conflicts.
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Properties
|
||||
@@ -46,31 +48,34 @@ class_name WeaponData
|
||||
@export var pellets_per_shot: int = 1
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pre-configured weapon instances (class-level constants)
|
||||
# Pre-configured weapon instances (class-level static vars)
|
||||
# ---------------------------------------------------------------------------
|
||||
# NOTE: static var initializers CAN call functions (unlike const).
|
||||
# These run when the script is loaded, which avoids the "not a constant
|
||||
# expression" error that occurs with const + .new().
|
||||
|
||||
## Assault Rifle — 30 dmg, 10 rps, 30 mag, 2.1s reload, automatic, 0.5° spread, 200m range.
|
||||
const RIFLE: Resource = pref(
|
||||
"rifle", "Assault Rifle",
|
||||
30.0, 10.0, 30, 2.1, true, 0.5, 200.0, 1
|
||||
static var RIFLE: Resource = pref(
|
||||
"rifle", "Assault Rifle",
|
||||
30.0, 10.0, 30, 2.1, true, 0.5, 200.0, 1
|
||||
)
|
||||
|
||||
## Pistol — 25 dmg, 4 rps, 12 mag, 1.5s reload, semi-auto, 0.3° spread, 80m range.
|
||||
const PISTOL: Resource = pref(
|
||||
"pistol", "Pistol",
|
||||
25.0, 4.0, 12, 1.5, false, 0.3, 80.0, 1
|
||||
static var PISTOL: Resource = pref(
|
||||
"pistol", "Pistol",
|
||||
25.0, 4.0, 12, 1.5, false, 0.3, 80.0, 1
|
||||
)
|
||||
|
||||
## Shotgun — 8 dmg × 8 pellets, 1 rps, 8 mag, 3.0s reload, semi-auto, 3° spread, 30m range.
|
||||
const SHOTGUN: Resource = pref(
|
||||
"shotgun", "Shotgun",
|
||||
8.0, 1.0, 8, 3.0, false, 3.0, 30.0, 8
|
||||
static var SHOTGUN: Resource = pref(
|
||||
"shotgun", "Shotgun",
|
||||
8.0, 1.0, 8, 3.0, false, 3.0, 30.0, 8
|
||||
)
|
||||
|
||||
## SMG — 18 dmg, 12 rps, 25 mag, 1.8s reload, automatic, 1.5° spread, 100m range.
|
||||
const SMG: Resource = pref(
|
||||
"smg", "Submachine Gun",
|
||||
18.0, 12.0, 25, 1.8, true, 1.5, 100.0, 1
|
||||
static var SMG: Resource = pref(
|
||||
"smg", "Submachine Gun",
|
||||
18.0, 12.0, 25, 1.8, true, 1.5, 100.0, 1
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -80,26 +85,26 @@ const SMG: Resource = pref(
|
||||
## Internal helper that constructs a WeaponData instance from raw values.
|
||||
## This avoids repeating the constructor boilerplate for every constant.
|
||||
static func pref(
|
||||
_weapon_id: String,
|
||||
_display_name: String,
|
||||
_damage: float,
|
||||
_fire_rate: float,
|
||||
_mag_size: int,
|
||||
_reload_time: float,
|
||||
_is_automatic: bool,
|
||||
_spread_degrees: float,
|
||||
_range: float,
|
||||
_pellets: int = 1
|
||||
) -> WeaponData:
|
||||
var w := WeaponData.new()
|
||||
w.weapon_id = _weapon_id
|
||||
w.display_name = _display_name
|
||||
w.damage = _damage
|
||||
w.fire_rate = _fire_rate
|
||||
w.mag_size = _mag_size
|
||||
w.reload_time = _reload_time
|
||||
w.is_automatic = _is_automatic
|
||||
w.spread_degrees = _spread_degrees
|
||||
w.range = _range
|
||||
w.pellets_per_shot = _pellets
|
||||
return w
|
||||
_weapon_id: String,
|
||||
_display_name: String,
|
||||
_damage: float,
|
||||
_fire_rate: float,
|
||||
_mag_size: int,
|
||||
_reload_time: float,
|
||||
_is_automatic: bool,
|
||||
_spread_degrees: float,
|
||||
_range: float,
|
||||
_pellets: int = 1
|
||||
): # -> WeaponData (untyped for headless compat)
|
||||
var w = WeaponData.new()
|
||||
w.weapon_id = _weapon_id
|
||||
w.display_name = _display_name
|
||||
w.damage = _damage
|
||||
w.fire_rate = _fire_rate
|
||||
w.mag_size = _mag_size
|
||||
w.reload_time = _reload_time
|
||||
w.is_automatic = _is_automatic
|
||||
w.spread_degrees = _spread_degrees
|
||||
w.range = _range
|
||||
w.pellets_per_shot = _pellets
|
||||
return w
|
||||
|
||||
@@ -12,23 +12,38 @@
|
||||
extends RefCounted
|
||||
class_name WeaponDefinitions
|
||||
|
||||
# Preload WeaponData script directly (no class_name dependency — the server
|
||||
# weapon_data.gd intentionally avoids class_name to avoid conflicts with
|
||||
# client/weapons/data/weapon_data.gd which also registers WeaponData).
|
||||
const _WD = preload("res://scripts/combat/weapon_data.gd")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Weapon Registry
|
||||
# Weapon Registry — lazily initialised to avoid const + .new() errors
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
## Whether the WEAPONS dictionary has been populated.
|
||||
static var _initialized: bool = false
|
||||
|
||||
## All weapons indexed by weapon_id — the single source of truth for the
|
||||
## game's starter arsenal. Add new weapons here and in WeaponData.
|
||||
const WEAPONS: Dictionary = {
|
||||
"rifle": WeaponData.RIFLE,
|
||||
"pistol": WeaponData.PISTOL,
|
||||
"shotgun": WeaponData.SHOTGUN,
|
||||
"smg": WeaponData.SMG,
|
||||
}
|
||||
## game's starter arsenal. Populated on first access via _ensure_init().
|
||||
static var WEAPONS: Dictionary = {}
|
||||
|
||||
static func _ensure_init() -> void:
|
||||
if _initialized:
|
||||
return
|
||||
_initialized = true
|
||||
WEAPONS = {
|
||||
"rifle": _WD.RIFLE,
|
||||
"pistol": _WD.PISTOL,
|
||||
"shotgun": _WD.SHOTGUN,
|
||||
"smg": _WD.SMG,
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Lookup
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
## Return the WeaponData for the given weapon_id, or null if unknown.
|
||||
static func get_weapon(id: String) -> WeaponData:
|
||||
return WEAPONS.get(id, null) as WeaponData
|
||||
static func get_weapon(id: String):
|
||||
_ensure_init()
|
||||
return WEAPONS.get(id, null)
|
||||
|
||||
@@ -24,7 +24,7 @@ signal player_despawned(peer_id: int)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Exports
|
||||
# ---------------------------------------------------------------------------
|
||||
@export var player_scene: PackedScene = preload("res://scenes/player.tscn")
|
||||
@export var player_scene: PackedScene = preload("res://scenes/server/server_player.tscn")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# State
|
||||
@@ -58,13 +58,16 @@ func _ready() -> void:
|
||||
# Use load() instead of preload() so GameServer's dev dependencies
|
||||
# (weapons, economy, objectives, teams) don't block compilation.
|
||||
var GameServerClass = load("res://server/scripts/game_server.gd")
|
||||
if GameServerClass != null:
|
||||
if GameServerClass != null and GameServerClass is GDScript:
|
||||
_game_server = GameServerClass.new()
|
||||
add_child(_game_server)
|
||||
# GameServer registers SimulationServer as a singleton on _ready
|
||||
_game_server.start_simulation()
|
||||
if _game_server != null:
|
||||
add_child(_game_server)
|
||||
# GameServer registers SimulationServer as a singleton on _ready
|
||||
_game_server.start_simulation()
|
||||
else:
|
||||
push_warning("[ServerMain] GameServer instantiation failed")
|
||||
else:
|
||||
push_warning("[ServerMain] GameServer not available — running without simulation server")
|
||||
push_warning("[ServerMain] GameServer class not available — running without simulation server")
|
||||
|
||||
# Check if ServerConfig has finished loading.
|
||||
|
||||
@@ -94,8 +97,6 @@ func _ready() -> void:
|
||||
## Check if ServerConfig has finished loading.
|
||||
func _server_config_loaded() -> bool:
|
||||
return ServerConfig and ServerConfig.has_method(&"get_config_path") and not ServerConfig.get_config_path().is_empty()
|
||||
var lag_comp_ms: float = 64.0 * 1000.0 / ServerConfig.tick_rate
|
||||
print("[ServerMain] Lag comp: Enabled (64-tick history = %.1fms)" % lag_comp_ms)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
NetworkManager.stop()
|
||||
|
||||
Reference in New Issue
Block a user