682f1f89f7
Made the multiplayer core actually work (it had never run a real sim): - project.godot: physics pinned to 30 Hz -- the shared sim/snapshot/prediction rate. - server.gd: loads the world's level (real ground + collision), spawns a server Player per peer at the level's PlayerSpawn, broadcasts a full snapshot every physics frame with each peer's state AND last_seq (the last input seq applied for that peer). Accepts `--port/--world/--status-file` args (status file = player count for a future idle reaper); defaults keep `godot res://scenes/server.tscn` working standalone. - player_spawner.gd (server Player): rewrote -- drains its whole input queue each physics frame in seq order, integrates gravity/walk/jump with the shared constants, move_and_slide(), tracks last_applied_seq. No more no-op process_server_input(). - network_client.gd: rewrote reconciliation -- drops inputs the server has acked (last_seq), re-simulates the still-in-flight ones from the authoritative state, snaps only on real drift. Exposes get_remote_states() (peer_id -> latest snapshot state) for the game to render other players. predict_and_send() now also sends body yaw. - proxies trimmed to the RPC set the rewrite actually uses. - scripts/mp_test_client.gd + run_multiplayer_2p_test.sh: two real client processes vs one real server -- client A sees client B and its own movement round-trips. PASS. - run_checkpoint_tests.py: also run the 2p shell test. smoke_test_network_client 4/4, player 15/15, avatar_in_world 10/10, all green. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jtxAiu5dAW4WxCNdGkrkJ
46 lines
1.6 KiB
Bash
Executable File
46 lines
1.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Two real client processes against one real dedicated server: client A must
|
|
# see client B and its own movement must round-trip through the server.
|
|
#
|
|
# Usage: scripts/run_multiplayer_2p_test.sh
|
|
# Exit 0 iff A reports moved=true and remotes>=1.
|
|
set -uo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
GODOT_BIN="${GODOT_BIN:-godot}"
|
|
command -v "$GODOT_BIN" >/dev/null 2>&1 || GODOT_BIN="$HOME/godot/godot"
|
|
PORT=7787
|
|
|
|
cleanup() { kill "${SRV_PID:-}" "${B_PID:-}" 2>/dev/null; wait 2>/dev/null; }
|
|
trap cleanup EXIT
|
|
|
|
echo "=== starting dedicated server on $PORT ==="
|
|
"$GODOT_BIN" --headless --path . res://scenes/server.tscn -- --port "$PORT" >/tmp/mp2p_server.log 2>&1 &
|
|
SRV_PID=$!
|
|
sleep 3
|
|
|
|
echo "=== starting client B (idle observer) ==="
|
|
"$GODOT_BIN" --headless --path . --script res://scripts/mp_test_client.gd -- --role b --port "$PORT" >/tmp/mp2p_b.log 2>&1 &
|
|
B_PID=$!
|
|
# Wait until B is actually connected before starting A.
|
|
for _ in $(seq 1 30); do grep -q 'RESULT b connected' /tmp/mp2p_b.log && break; sleep 1; done
|
|
|
|
echo "=== running client A (mover) ==="
|
|
"$GODOT_BIN" --headless --path . --script res://scripts/mp_test_client.gd -- --role a --port "$PORT" 2>&1 | tee /tmp/mp2p_a.log
|
|
A_LINE=$(grep '^RESULT a' /tmp/mp2p_a.log || true)
|
|
|
|
wait "$B_PID" 2>/dev/null
|
|
B_LINE=$(grep '^RESULT b' /tmp/mp2p_b.log || true)
|
|
|
|
echo
|
|
echo "server: $(grep -c 'joined' /tmp/mp2p_server.log) joins seen"
|
|
echo "A: ${A_LINE:-<none>}"
|
|
echo "B: ${B_LINE:-<none>}"
|
|
|
|
if echo "$A_LINE" | grep -q 'moved=true' && echo "$A_LINE" | grep -qE 'remotes=[1-9]'; then
|
|
echo "=== SMOKE RESULT: PASS ==="
|
|
exit 0
|
|
fi
|
|
echo "=== SMOKE RESULT: FAIL ==="
|
|
exit 1
|