P7.8: Port FPS controller to netfox BaseNetInput pattern
- FPSCharacterController: removed SimulationServer dependency, added _rollback_tick() with acceleration-based CharacterBody3D movement, gravity, jump, crouch/sprint speed. Kept mouse look, crouch lerp, sprint/crouch toggle, _move_local() standalone fallback. - Player: extends FPSCharacterController (CharacterBody3D). Added authority-guarded _rollback_tick that delegates to super for server and local client prediction. TickInterpolator created dynamically (avoids headless class_name parse errors). PlayerNetInput child wired via existing RollbackSynchronizer input_properties. - player.tscn: CharacterBody3D root with FpsCamera, CollisionShape3D, PlayerNetInput children. TickInterpolator created in code. - client_main.gd: _spawn_local_player() creates FPS player node with first-person camera for own peer. _spawn_remote_player() removes FpsCamera for remote players. - fps_camera.gd: duck-typed _controller (Node) instead of class_name cast for headless safety. Fixed type inference warnings. Also includes parent task P7.5-P7.7 changes: - project.godot: main_scene -> server_main.tscn - network_manager.gd: Chan enum -> raw channel ints - server_main.gd: deferred ServerConfig load, GameServer load() - game_server.gd: commented out dev deps for headless compilation
This commit is contained in:
@@ -40,9 +40,11 @@ var _game_server: Node = null
|
||||
# Lifecycle
|
||||
# ---------------------------------------------------------------------------
|
||||
func _ready() -> void:
|
||||
# Wait for ServerConfig to finish (it loads via call_deferred)
|
||||
if ServerConfig and ServerConfig.has_signal(&"config_loaded"):
|
||||
await ServerConfig.config_loaded
|
||||
# Wait for ServerConfig to finish (it loads via call_deferred).
|
||||
# Check if already loaded to avoid racing the signal.
|
||||
if ServerConfig and not _server_config_loaded():
|
||||
if ServerConfig.has_signal(&"config_loaded"):
|
||||
await ServerConfig.config_loaded
|
||||
|
||||
# Config driven — ServerConfig singleton loaded at autoload time.
|
||||
# Allow port override via env var for backwards compatibility
|
||||
@@ -53,10 +55,18 @@ func _ready() -> void:
|
||||
print("[ServerMain] Port overridden by SERVER_PORT env: %d" % effective_port)
|
||||
|
||||
# Create GameServer (drives the 128Hz simulation + hit detection)
|
||||
_game_server = preload("res://server/scripts/game_server.gd").new()
|
||||
add_child(_game_server)
|
||||
# GameServer registers SimulationServer as a singleton on _ready
|
||||
_game_server.start_simulation()
|
||||
# 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:
|
||||
_game_server = GameServerClass.new()
|
||||
add_child(_game_server)
|
||||
# GameServer registers SimulationServer as a singleton on _ready
|
||||
_game_server.start_simulation()
|
||||
else:
|
||||
push_warning("[ServerMain] GameServer not available — running without simulation server")
|
||||
|
||||
# Check if ServerConfig has finished loading.
|
||||
|
||||
# Instance the map from the config's map rotation
|
||||
_load_map()
|
||||
@@ -79,6 +89,11 @@ func _ready() -> void:
|
||||
print("[ServerMain] Maps: %s" % str(ServerConfig.map_list))
|
||||
print("[ServerMain] Headless: %s" % (DisplayServer.get_name() == &"headless"))
|
||||
print("[ServerMain] Spawn pts: Team A=%d, Team B=%d" % [spawn_points_a.size(), spawn_points_b.size()])
|
||||
|
||||
|
||||
## 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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user