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
+34 -8
View File
@@ -34,6 +34,7 @@ extends RefCounted
const DEFAULT_TIMEOUT_MS := 8000
const _POLL_INTERVAL_MS := 50
const _KILL_GRACE_MS := 500
static func run(
@@ -44,6 +45,15 @@ static func run(
) -> Dictionary:
if exe.is_empty():
return _spawn_failed_result()
return _run_piped(exe, args, timeout_ms, capture_stderr)
static func _run_piped(
exe: String,
args: Array,
timeout_ms: int,
capture_stderr: bool,
) -> Dictionary:
var spawn_exe := exe
var spawn_args := args
@@ -76,12 +86,18 @@ static func run(
var deadline := Time.get_ticks_msec() + maxi(timeout_ms, _POLL_INTERVAL_MS)
while OS.is_process_running(pid):
if Time.get_ticks_msec() >= deadline:
## Read whatever made it to the pipes before we kill the
## process — partial output beats blank "timed out" when the
## CLI was emitting useful diagnostics on its way to hanging.
var partial_stdout := _drain_pipe(stdio)
var partial_stderr := _drain_pipe(stderr_pipe) if capture_stderr else ""
## Kill before draining: a pipe read can block while the child is
## still alive. Once it exits, drain any buffered partial output.
OS.kill(pid)
var kill_deadline := Time.get_ticks_msec() + _KILL_GRACE_MS
while OS.is_process_running(pid) and Time.get_ticks_msec() < kill_deadline:
OS.delay_msec(_POLL_INTERVAL_MS)
var partial_stdout := ""
var partial_stderr := ""
if not OS.is_process_running(pid):
partial_stdout = _drain_pipe(stdio)
partial_stderr = _drain_pipe(stderr_pipe) if capture_stderr else ""
_close_pipes(stdio, stderr_pipe)
return {
"exit_code": -1,
@@ -119,9 +135,19 @@ static func _spawn_failed_result() -> Dictionary:
static func _drain_pipe(pipe: Variant) -> String:
if pipe is FileAccess:
return (pipe as FileAccess).get_as_text()
return ""
if not (pipe is FileAccess):
return ""
var f := pipe as FileAccess
var bytes := PackedByteArray()
var max_bytes := 1 << 20 # 1 MiB, far above expected client CLI output.
while bytes.size() < max_bytes:
var chunk := f.get_buffer(mini(4096, max_bytes - bytes.size()))
if chunk.is_empty():
break
bytes.append_array(chunk)
if f.eof_reached():
break
return bytes.get_string_from_utf8()
static func _join_streams(stdout: String, stderr_text: String) -> String: