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,9 +3,7 @@ extends Logger
## Captures GDScript runtime errors emitted while a test is running.
##
## Deliberately no class_name: this script is compiled dynamically by
## script_error_capture_loader.gd only when Logger exists. It lives in a
## `.gdignore`d folder so older Godot editor scans never parse `extends Logger`.
## Deliberately no class_name: this is an internal test helper.
##
## Only ERROR_TYPE_SCRIPT is captured. push_error(), push_warning(), and
## engine-internal ERR_FAIL_* checks are often valid negative-path assertions and
@@ -0,0 +1 @@
uid://crk8w2nei087v
@@ -1,26 +0,0 @@
@tool
extends RefCounted
## Builds the Logger-based test script-error capture lazily.
##
## Logger exists only on newer Godot versions. The capture implementation lives
## under a `.gdignore`d folder and is compiled from source only after the runner
## verifies the Logger API is present, so older editor scans do not parse an
## `extends Logger` file and emit red startup errors.
const SCRIPT_ERROR_CAPTURE_PATH := "res://addons/godot_ai/testing/loggers/script_error_capture.gd"
static func build() -> Object:
if not ClassDB.class_exists("Logger") or not OS.has_method("add_logger"):
return null
if not FileAccess.file_exists(SCRIPT_ERROR_CAPTURE_PATH):
return null
var source := FileAccess.get_file_as_string(SCRIPT_ERROR_CAPTURE_PATH)
if source.is_empty():
return null
var script := GDScript.new()
script.source_code = source
if script.reload() != OK:
return null
return script.new()
@@ -1 +0,0 @@
uid://pmtc07go8ty4
+8 -8
View File
@@ -5,17 +5,17 @@ extends RefCounted
## Lightweight test runner for MCP plugin tests. Discovers test_* methods
## on McpTestSuite instances, runs them, and collects structured results.
const ScriptErrorCaptureLoader := preload("res://addons/godot_ai/testing/script_error_capture_loader.gd")
const ScriptErrorCapture := preload("res://addons/godot_ai/testing/script_error_capture.gd")
var _results: Array[Dictionary] = []
var _last_run_ms: int = 0
var _script_error_capture: Object = null
var _script_error_capture: ScriptErrorCapture = null
var _capture_registered := false
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE and _capture_registered and _script_error_capture != null:
OS.call("remove_logger", _script_error_capture)
OS.remove_logger(_script_error_capture)
_capture_registered = false
@@ -173,10 +173,10 @@ func _register_capture() -> void:
if _capture_registered:
return
if _script_error_capture == null:
_script_error_capture = ScriptErrorCaptureLoader.build()
_script_error_capture = ScriptErrorCapture.new()
if _script_error_capture == null:
return
OS.call("add_logger", _script_error_capture)
OS.add_logger(_script_error_capture)
_capture_registered = true
@@ -186,19 +186,19 @@ func _unregister_capture() -> void:
if _script_error_capture == null:
_capture_registered = false
return
OS.call("remove_logger", _script_error_capture)
OS.remove_logger(_script_error_capture)
_capture_registered = false
func _begin_script_error_capture() -> void:
if _script_error_capture != null and _capture_registered:
_script_error_capture.call("begin_capture")
_script_error_capture.begin_capture()
func _end_script_error_capture() -> PackedStringArray:
if _script_error_capture == null or not _capture_registered:
return PackedStringArray()
return _script_error_capture.call("end_capture") as PackedStringArray
return _script_error_capture.end_capture()
static func _edited_scene_root() -> Node:
+3 -3
View File
@@ -124,14 +124,14 @@ func skip_suite(reason: String) -> void:
## Mark the current test as skipped when the running Godot is older than
## `min_version` (a "major.minor" string like "4.4"). Use for tests that
## `min_version` (a "major.minor" string like "4.6"). Use for tests that
## exercise an engine API or behavior that only exists on newer Godot.
## Returns true when the test was skipped, so callers can `return` from
## the test body.
##
## Example:
## func test_uses_44_only_api() -> void:
## if skip_on_godot_lt("4.4", "Engine.capture_script_backtraces is 4.4+"):
## func test_uses_46_only_api() -> void:
## if skip_on_godot_lt("4.6", "example API requires Godot 4.6+"):
## return
## ...
func skip_on_godot_lt(min_version: String, reason: String = "") -> bool: