mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
feat(server): task 6.1/6.3 — dedicated server export preset and a real CLI surface
6.1: "Linux Dedicated Server" preset (dedicated_server=true, custom_features="dedicated_server") mirroring the existing training preset, plus run/main_scene.dedicated_server so the server binary reaches its own entry point with no flag. Builds: an 85MB Linux x86_64 binary, gitignored like the training one. 6.3: scripts/server_config.gd declares every server flag once - name, type, default, section, help - and one parser turns that into parsing, type checking, range validation, config-file backing and --help. The flags had grown to ~30 across server_boot.gd and networked_match.gd, each parsed inline with begins_with, none documented, and an unrecognised flag was SILENTLY IGNORED: --max-clientss=8 ran a server on the default cap and said nothing. Unknown flags, missing values, wrong types, duplicates and out-of-range values are now hard errors, reported all at once. Precedence is command line > config file > default. server_boot.gd parses strictly because it owns the whole command line; networked_match.gd reads the same declaration leniently because it is one consumer of an argv the smoke harnesses also fill with --role= and --drive-seconds=. Nothing is lost - every server flag is declared, so the strict pass already caught any typo before the match scene re-reads its own. 13 unit tests covering the precedence order, the typo rejection that motivated this, --no-<bool> not double-listing in --help, and --help documenting every flag asserted against the declaration rather than a hand-kept list. Verified end to end: --help prints, a typo'd flag refuses to start, and the plain/replay-log/late-joiner smoke scenarios still pass.
This commit is contained in:
+23
-15
@@ -17,6 +17,7 @@ const LOG_LEVELS := {"debug": 0, "info": 1, "warn": 2, "error": 3}
|
||||
var _boot_ms := 0
|
||||
var _last_physics_frame := 0
|
||||
var _log_level := 1 # info
|
||||
var config: ServerConfig = null
|
||||
var _watchdog_armed := false # skip the first _process(): engine startup scheduling can batch several physics frames before the first idle frame runs, which isn't a real overrun
|
||||
|
||||
|
||||
@@ -24,21 +25,28 @@ func _ready() -> void:
|
||||
_boot_ms = Time.get_ticks_msec()
|
||||
Engine.max_fps = 60 # a server never renders; this just caps the idle-frame poll rate so it doesn't spin
|
||||
|
||||
var port := NetworkManager.DEFAULT_PORT
|
||||
var max_clients := NetworkManager.MAX_CLIENTS
|
||||
for arg in OS.get_cmdline_user_args():
|
||||
if arg.begins_with("--port="):
|
||||
port = int(arg.substr("--port=".length()))
|
||||
elif arg.begins_with("--max-clients="):
|
||||
max_clients = int(arg.substr("--max-clients=".length()))
|
||||
elif arg.begins_with("--log-level="):
|
||||
var level_name := arg.substr("--log-level=".length())
|
||||
if LOG_LEVELS.has(level_name):
|
||||
_log_level = LOG_LEVELS[level_name]
|
||||
else:
|
||||
_log("error", "bad_log_level", {"given": level_name, "valid": LOG_LEVELS.keys()})
|
||||
get_tree().quit(1)
|
||||
return
|
||||
# Task 6.3. This process owns the whole command line, so it parses STRICTLY:
|
||||
# an unknown flag or an out-of-range value stops the server with a message
|
||||
# rather than starting one that silently ignores half of what it was told.
|
||||
config = ServerConfig.parse(OS.get_cmdline_user_args())
|
||||
if config.help_requested:
|
||||
print(ServerConfig.help_text())
|
||||
get_tree().quit(0)
|
||||
return
|
||||
if not config.is_valid():
|
||||
# Straight to stderr-ish plain print rather than through _log: the log
|
||||
# level itself may be one of the things that failed to parse, and an
|
||||
# operator running this by hand needs to see every problem at once, not
|
||||
# the first one.
|
||||
printerr("cosmic-clash-server: refusing to start")
|
||||
for problem in config.errors:
|
||||
printerr(" %s" % problem)
|
||||
printerr("try --help")
|
||||
get_tree().quit(1)
|
||||
return
|
||||
var port := int(config.get_value("port"))
|
||||
var max_clients := int(config.get_value("max-clients"))
|
||||
_log_level = LOG_LEVELS[String(config.get_value("log-level"))]
|
||||
|
||||
NetworkManager.client_connected.connect(_on_client_connected)
|
||||
NetworkManager.client_disconnected.connect(_on_client_disconnected)
|
||||
|
||||
Reference in New Issue
Block a user