fix(network): prevent null multiplayer peer crashes offline/teardown and fix Nakama RPC session validation

This commit is contained in:
2026-07-10 17:36:26 +08:00
parent 2b4c9d9dcb
commit b30709de3d
84 changed files with 5291 additions and 982 deletions
+3
View File
@@ -427,6 +427,9 @@ func link_google(id_token: String) -> bool:
func logout() -> void:
print("[AuthManager] Logging out...")
if NakamaManager.client and NakamaManager.session:
await NakamaManager.client.session_logout_async(NakamaManager.session)
# FULL CLEANUP: close socket, leave bridge, clear multiplayer peer
NakamaManager.cleanup()
+3 -3
View File
@@ -22,7 +22,7 @@ func after_action_completed():
return
player._is_processing_action = true
if player.is_multiplayer_authority():
if player.can_rpc() and multiplayer.has_multiplayer_peer():
player.update_finish_availability()
# Clear the highlights after placing the tiles. (Quickfix for Clientside)
@@ -30,12 +30,12 @@ func after_action_completed():
# Only update UI if this is the LOCAL HUMAN PLAYER
# Guard against stale callbacks after peer teardown (host quitting solo match)
if not multiplayer.has_multiplayer_peer():
if not multiplayer or not multiplayer.has_multiplayer_peer():
player._is_processing_action = false
return
if multiplayer.get_unique_id() == player.get_multiplayer_authority():
# Sync playerboard (Bots DO need to sync their board logic, just not update local UI)
if player.is_multiplayer_authority() and player.has_method("can_rpc") and player.can_rpc():
if player.can_rpc() and multiplayer.has_multiplayer_peer():
var main = player.get_tree().get_root().get_node_or_null("Main")
if main:
main.rpc("sync_playerboard", player.name.to_int(), player.playerboard)
+5 -4
View File
@@ -99,10 +99,11 @@ func handle_unhandled_input(event):
var gm = player.get_node_or_null("/root/Main/CandySurvivalManager")
if gm and gm.active:
var pid = player.get("peer_id") if "peer_id" in player else player.name.to_int()
if multiplayer.is_server():
gm.try_activate_ghost(pid)
else:
gm.rpc_id(1, "try_activate_ghost", pid)
if player.can_rpc() and multiplayer.has_multiplayer_peer():
if multiplayer.is_server():
gm.try_activate_ghost(pid)
else:
gm.rpc_id(1, "try_activate_ghost", pid)
else:
player.activate_held_powerup()
get_viewport().set_input_as_handled()
+12 -10
View File
@@ -168,9 +168,10 @@ func simple_move_to(grid_position: Vector2i) -> bool:
if gm and gm.active and gm.has_method("try_deliver"):
var dist = abs(grid_position.x - 8) + abs(grid_position.y - 8)
if dist <= 1:
if multiplayer.is_server():
var pid = player.get("peer_id") if "peer_id" in player else player.name.to_int()
gm.try_deliver(pid)
if player.can_rpc() and multiplayer.has_multiplayer_peer():
if multiplayer.is_server():
var pid = player.get("peer_id") if "peer_id" in player else player.name.to_int()
gm.try_deliver(pid)
rotate_towards_target(grid_position)
@@ -249,10 +250,11 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
if gm and gm.active and gm.has_method("try_knock"):
var pid = player.get("peer_id") if "peer_id" in player else player.name.to_int()
var other_pid = other_player.get("peer_id") if "peer_id" in other_player else other_player.name.to_int()
if multiplayer.is_server():
gm.try_knock(pid, other_pid)
else:
gm.rpc_id(1, "try_knock", pid, other_pid)
if player.can_rpc() and multiplayer.has_multiplayer_peer():
if multiplayer.is_server():
gm.try_knock(pid, other_pid)
else:
gm.rpc_id(1, "try_knock", pid, other_pid)
# Consume knock mode after use (toggle off)
player.is_charged_strike = false
return false
@@ -315,7 +317,7 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
print("[Move] Ghost mode bypassed push-into-sticky at %s" % pushed_to_pos)
else:
print("[Move] Player pushed into sticky cell at %s — slowed" % pushed_to_pos)
if multiplayer.is_server() or other_player.is_multiplayer_authority():
if other_player.can_rpc() and multiplayer.has_multiplayer_peer() and (multiplayer.is_server() or other_player.is_multiplayer_authority()):
gm_sticky.apply_sticky_slow(other_player)
# 2. Apply freeze/stun effect
@@ -342,10 +344,10 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
if main_score:
var gcm = main_score.get_node_or_null("GoalsCycleManager")
if gcm:
if multiplayer.is_server():
if multiplayer.has_multiplayer_peer() and multiplayer.is_server():
# Server/Bot: Directly add score to specific player ID
gcm.add_score(player.name.to_int(), 200)
else:
elif player.can_rpc() and multiplayer.has_multiplayer_peer():
# Client: Request score add (sender ID used)
gcm.rpc("request_add_score", 200)
NotificationManager.send_message(player, "Successful Attack! +200 Pts", NotificationManager.MessageType.GOAL)