Files
CosmicClash/Game/project.godot
T
Josh Creek 39a41c016c feat(multiplayer): Phase 2 server-authoritative simulation, dumb client
Implements tasks 2.1-2.7: NetworkedMatch spawns a deterministic slot
layout from the lobby roster, the server drives each connected peer's
ship via RLShipController fed by decoded client input and broadcasts
60Hz snapshots, and the client renders everything (including its own
ship) from a per-body NetInterpolator with no local prediction yet.
Dual-time remote entities split collider updates (present-time, for
correct contacts) from $Visual updates (interp-delayed, for smoothness).
Camera/HUD wiring and remote engine-flame VFX fell out of the existing
Ship API for free once snapshots were flowing.

Three real bugs found and fixed while getting a two-process test
green: an RPC method named _input collided with Node's built-in
_input virtual and broke the whole MatchSim autoload from loading;
networked_match.gd never called NetworkManager.poll(), so nothing
sent via RPC in this scene reached the wire despite Phase 1's manual
polling being wired up everywhere else; and a match_config
request/response fallback (added to close a startup race) could
double-deliver once polling was fixed, requiring an idempotency guard.

Verified with tests/networked_match_smoke: a real headless two-process
host+client run shows the client rendering 31m of server-authoritative
movement from a held forward-thrust input, with thrust_z=1.0 confirmed
on the interpolated snapshot mid-drive and camera/HUD both wired.
Full Phase 1 regression suite re-run clean alongside it.

Task 2.8 (net_sim.gd latency/jitter/loss decorator) is not yet done;
Phase 2's own gate needs it before it's fully met.
2026-08-20 08:42:13 +01:00

191 lines
9.3 KiB
Plaintext

; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[animation]
compatibility/default_parent_skeleton_in_mesh_instance_3d=true
[application]
config/name="Cosmic Clash"
config/description="A fast-paced, physics-based sports game set in space. From Raymond Studios."
config/version="0.0.1"
run/main_scene="uid://bcq14356s3e2i"
config/features=PackedStringArray("4.7", "Forward Plus")
config/icon="res://icon.svg"
run/main_scene.training="res://scenes/training.tscn"
[autoload]
GameSettings="*res://scripts/game_settings.gd"
VideoSettings="*res://scripts/video_settings.gd"
BackgroundFPS="*res://scripts/background_fps.gd"
PerfOverlay="*res://scripts/perf_overlay.gd"
NetworkManager="*res://scripts/network_manager.gd"
MatchNet="*res://scripts/match_net.gd"
MatchSim="*res://scripts/match_sim.gd"
NetDebugOverlay="*res://scripts/net_debug_overlay.gd"
[display]
window/size/viewport_width=1920
window/size/viewport_height=1080
window/size/mode=2
; Task 0.17c: kept fixed at "viewport" + 1080p rather than moved to
; "disabled", deliberately. A player on a 1440p/4K display cannot render
; native this way, and a 1080p player cannot render lower than 1080p through
; window scaling alone — but task 0.17b's Viewport.scaling_3d_scale already
; covers "render lower than the window" independently of stretch mode (it
; scales the 3D viewport's own internal resolution before this blit, not the
; window itself), and task 0.15b found an unexplained ~6% non-uniform width
; scaling on this project's one tested (Mac/Retina) machine — see
; multiplayer-todo.md §5.5.1 — that needs understanding before stretch mode
; is touched, not blindly carried into a resolution-dependent change.
window/stretch/mode="viewport"
window/stretch/aspect="expand"
; Task 0.17: default matches VideoSettings.gd's VsyncMode.ADAPTIVE default —
; VideoSettings.apply_vsync() overwrites this at runtime via DisplayServer as
; soon as the autoload initializes, so this is only what's in effect for the
; brief pre-autoload window and if VideoSettings ever fails to load.
window/vsync/vsync_mode=2
[editor_plugins]
enabled=PackedStringArray("res://addons/godot_rl_agents/plugin.cfg")
[input]
reset_ball={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_forward={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
]
}
move_back={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
]
}
move_left={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
]
}
move_right={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
]
}
move_up={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null)
]
}
move_down={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":81,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null)
]
}
turbo={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
]
}
turn_left={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":74,"key_label":0,"unicode":106,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
]
}
turn_right={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":76,"key_label":0,"unicode":108,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
]
}
pitch_up={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":73,"key_label":0,"unicode":105,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
]
}
pitch_down={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":75,"key_label":0,"unicode":107,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
]
}
roll_left={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":85,"key_label":0,"unicode":117,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":false,"script":null)
]
}
roll_right={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":79,"key_label":0,"unicode":111,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":10,"pressure":0.0,"pressed":false,"script":null)
]
}
toggle_perf_overlay={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194334,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
toggle_net_overlay={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194335,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
[layer_names]
3d_physics/layer_1/name="Ships"
3d_physics/layer_2/name="Ball"
3d_physics/layer_3/name="Arena"
3d_physics/layer_4/name="GoalSensor"
[physics]
3d/physics_engine="Jolt Physics"
common/physics_interpolation=true
common/physics_jitter_fix=0.0
[rendering]
anti_aliasing/quality/msaa_3d=2
anti_aliasing/quality/screen_space_aa=1
anti_aliasing/quality/use_debanding=true
lights_and_shadows/positional_shadow/atlas_size=2048
lights_and_shadows/directional_shadow/size=2048
lights_and_shadows/soft_shadow_filter_quality=2