extends Node # 游戏内管理员测试实验室的唯一 API 入口。 # 客户端只把 role=9 用于显示入口;实际授权仍由后端 TestLabGuard 完成。 signal status_changed(status: Dictionary) signal status_failed(message: String) signal operation_completed(message: String) var _status: Dictionary = {} var _loading_status: bool = false var _account_generation: int = -1 func _ready() -> void: var auth_manager := get_node_or_null("/root/AuthManager") if auth_manager != null and auth_manager.has_signal("auth_state_changed"): var callback := Callable(self, "_on_auth_state_changed") if not auth_manager.is_connected("auth_state_changed", callback): auth_manager.connect("auth_state_changed", callback) call_deferred("_refresh_after_ready") func get_status() -> Dictionary: return _status.duplicate(true) func is_loaded() -> bool: return not _status.is_empty() func is_admin() -> bool: var auth_manager := get_node_or_null("/root/AuthManager") if auth_manager == null or not auth_manager.has_method("is_authenticated") or not bool(auth_manager.call("is_authenticated")): return false if not auth_manager.has_method("get_current_user"): return false var user_variant: Variant = auth_manager.call("get_current_user") if not (user_variant is Dictionary): return false var user: Dictionary = user_variant as Dictionary return int(user.get("role", 0)) == 9 func refresh_status() -> void: if not is_admin() or _loading_status: return var api := _api_client() if api == null: status_failed.emit("测试实验室服务不可用") return _loading_status = true _account_generation = _current_account_generation() api.call("get_json", "/admin/test-lab/status", Callable(self, "_on_status_response").bind(_account_generation), true) func create_actor(nickname: String, map_id: String, x: int, y: int, skin_id: String) -> void: _mutate("post_json", "/admin/test-lab/actors", { "nickname": nickname.strip_edges(), "mapId": map_id, "x": x, "y": y, "skinId": skin_id }, "测试假人已上线") func update_actor(user_id: String, online: bool, map_id: String, x: int, y: int, skin_id: String) -> void: _mutate("patch_json", "/admin/test-lab/actors/%s" % user_id.uri_encode(), { "online": online, "mapId": map_id, "x": x, "y": y, "skinId": skin_id }, "假人状态已同步") func set_room_policy(user_id: String, policy: String) -> void: _mutate("patch_json", "/admin/test-lab/actors/%s/room-policy" % user_id.uri_encode(), { "roomVisitPolicy": policy }, "房间访问策略已更新") func send_message(user_id: String, scope: String, content: String, target_user_id: String = "") -> void: var payload := {"scope": scope, "content": content.strip_edges()} if scope == "private": payload["targetUserId"] = target_user_id _mutate("post_json", "/admin/test-lab/actors/%s/messages" % user_id.uri_encode(), payload, "测试消息已发送") func social_action(user_id: String, action: String, target_user_id: String) -> void: _mutate("post_json", "/admin/test-lab/actors/%s/social" % user_id.uri_encode(), { "action": action, "targetUserId": target_user_id }, "社交操作已执行") func delete_actor(user_id: String) -> void: _mutate("delete_json", "/admin/test-lab/actors/%s" % user_id.uri_encode(), {}, "测试假人已删除") func clear_all() -> void: _mutate("delete_json", "/admin/test-lab/actors", {}, "测试实验室已清空") func _mutate(method_name: String, endpoint: String, payload: Dictionary, success_message: String) -> void: if not is_admin(): status_failed.emit("仅管理员可使用测试实验室") return var api := _api_client() if api == null: status_failed.emit("测试实验室服务不可用") return var request_generation := _current_account_generation() api.call(method_name, endpoint, payload, Callable(self, "_on_mutation_response").bind(success_message, request_generation), true) func _refresh_after_ready() -> void: if is_admin(): refresh_status() func _on_auth_state_changed(is_authenticated: bool, _user: Dictionary) -> void: if not is_authenticated or not is_admin(): _status.clear() _loading_status = false _account_generation = -1 status_changed.emit({}) return refresh_status() func _on_status_response(success: bool, response: Dictionary, error_info: Dictionary, request_generation: int) -> void: if request_generation != _current_account_generation(): return _loading_status = false if not success: status_failed.emit(str(error_info.get("message", "测试实验室读取失败"))) return var data_variant: Variant = response.get("data", {}) if not (data_variant is Dictionary): status_failed.emit("测试实验室响应格式错误") return _status = (data_variant as Dictionary).duplicate(true) status_changed.emit(get_status()) func _on_mutation_response(success: bool, _response: Dictionary, error_info: Dictionary, success_message: String, request_generation: int) -> void: if request_generation != _current_account_generation(): return if not success: status_failed.emit(str(error_info.get("message", "测试实验室操作失败"))) return operation_completed.emit(success_message) refresh_status() func _api_client() -> Node: return get_node_or_null("/root/ApiClient") func _current_account_generation() -> int: var auth_manager := get_node_or_null("/root/AuthManager") return int(auth_manager.call("get_account_generation")) if auth_manager != null and auth_manager.has_method("get_account_generation") else 0