Fix: players fall through the floor in multiplayer
checkpoint / checkpoint (push) Failing after 1m34s
checkpoint / checkpoint (push) Failing after 1m34s
scenes/server_player.tscn was a bare CharacterBody3D with NO CollisionShape3D, so on the server move_and_slide() never hit the ground and is_on_floor() was always false -> the server player fell forever, and the client (which snaps to the server's authoritative position past a drift threshold) fell with it. Give the server player the same CapsuleShape3D (r=0.35, h=1.6) as the client. The 2-player test now also asserts the server keeps the player on the ground (on_floor / min_y), which is how this slipped through -- the tests only checked "position changes" and "sees the other player". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jtxAiu5dAW4WxCNdGkrkJ
This commit is contained in:
@@ -1,6 +1,13 @@
|
|||||||
[gd_scene load_steps=2 format=3]
|
[gd_scene load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/player_spawner.gd" id="1"]
|
[ext_resource type="Script" path="res://scripts/player_spawner.gd" id="1"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape_server_player"]
|
||||||
|
radius = 0.35
|
||||||
|
height = 1.6
|
||||||
|
|
||||||
[node name="Player" type="CharacterBody3D"]
|
[node name="Player" type="CharacterBody3D"]
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("CapsuleShape_server_player")
|
||||||
|
|||||||
@@ -45,14 +45,20 @@ func _run() -> void:
|
|||||||
quit(0)
|
quit(0)
|
||||||
return
|
return
|
||||||
|
|
||||||
# role a: move forward, watch for a remote and our own displacement.
|
# role a: move forward, watch for a remote and our own displacement, and
|
||||||
|
# confirm the server keeps us on the ground (not falling through it).
|
||||||
var start: Vector3 = net.position
|
var start: Vector3 = net.position
|
||||||
var max_remotes := 0
|
var max_remotes := 0
|
||||||
|
var min_server_y := 1000.0
|
||||||
for i in 90:
|
for i in 90:
|
||||||
net.predict_and_send(1.0 / 30.0, 0.0, -1.0, false, 0.0)
|
net.predict_and_send(1.0 / 30.0, 0.0, -1.0, false, 0.0)
|
||||||
await process_frame
|
await process_frame
|
||||||
max_remotes = maxi(max_remotes, net.get_remote_states().size())
|
max_remotes = maxi(max_remotes, net.get_remote_states().size())
|
||||||
|
var st: Dictionary = net.get_own_server_state()
|
||||||
|
if st.has("position"):
|
||||||
|
min_server_y = minf(min_server_y, st["position"].y)
|
||||||
var moved: bool = net.position.distance_to(start) > 1.0
|
var moved: bool = net.position.distance_to(start) > 1.0
|
||||||
print("RESULT a remotes=%d moved=%s" % [max_remotes, str(moved)])
|
var on_floor: bool = min_server_y > -2.0
|
||||||
|
print("RESULT a remotes=%d moved=%s on_floor=%s (min_y=%.2f)" % [max_remotes, str(moved), str(on_floor), min_server_y])
|
||||||
net.disconnect_from_server()
|
net.disconnect_from_server()
|
||||||
quit(0 if (moved and max_remotes >= 1) else 1)
|
quit(0 if (moved and max_remotes >= 1 and on_floor) else 1)
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ echo "server: $(grep -c 'joined' /tmp/mp2p_server.log) joins seen"
|
|||||||
echo "A: ${A_LINE:-<none>}"
|
echo "A: ${A_LINE:-<none>}"
|
||||||
echo "B: ${B_LINE:-<none>}"
|
echo "B: ${B_LINE:-<none>}"
|
||||||
|
|
||||||
if echo "$A_LINE" | grep -q 'moved=true' && echo "$A_LINE" | grep -qE 'remotes=[1-9]'; then
|
if echo "$A_LINE" | grep -q 'moved=true' \
|
||||||
|
&& echo "$A_LINE" | grep -qE 'remotes=[1-9]' \
|
||||||
|
&& echo "$A_LINE" | grep -q 'on_floor=true'; then
|
||||||
echo "=== SMOKE RESULT: PASS ==="
|
echo "=== SMOKE RESULT: PASS ==="
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user