feat: add in-game social test lab

This commit is contained in:
ANG-Server
2026-07-22 12:16:31 +08:00
parent 9a3248abd6
commit e3accf6b71
9 changed files with 876 additions and 1 deletions

View File

@@ -0,0 +1,135 @@
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