feat: polish personal space editor

This commit is contained in:
ANG-Server
2026-07-22 13:41:28 +08:00
parent e3accf6b71
commit d60444d2eb
10 changed files with 858 additions and 42 deletions

View File

@@ -1153,7 +1153,8 @@ func _handle_friend_list(data: Dictionary) -> void:
_friends.append({
"user_id": str(friend.get("userId", friend.get("user_id", ""))).strip_edges(),
"username": str(friend.get("username", "")),
"online": bool(friend.get("online", false))
"online": bool(friend.get("online", false)),
"room_visitable": bool(friend.get("room_visitable", false))
})
_emit_event(EventNames.CHAT_FRIENDS_UPDATED, {
@@ -1172,7 +1173,8 @@ func _handle_friend_added(data: Dictionary) -> void:
_upsert_friend({
"user_id": friend_user_id,
"username": str(friend.get("username", "")),
"online": bool(friend.get("online", false))
"online": bool(friend.get("online", false)),
"room_visitable": bool(friend.get("room_visitable", false))
})
request_friend_list()

View File

@@ -69,6 +69,7 @@ func _process_next_save() -> void:
"position_x": float(item.get("position_x", 0.0)),
"position_y": float(item.get("position_y", 0.0)),
"scale": float(item.get("scale", item.get("default_scale", 1.0))),
"rotation_degrees": int(item.get("rotation_degrees", item.get("default_rotation_degrees", 0))),
"z_index": int(item.get("z_index", item.get("default_z_index", 0))),
}
var decorId := str(item.get("decor_id", "")).uri_encode()

View File

@@ -39,6 +39,7 @@ var is_changing_scene: bool = false # 是否正在切换场景
var _next_scene_position: Variant = null # 下一个场景的初始位置 (Vector2 or null)
var _next_spawn_name: String = "" # 下一个场景的出生点名称 (String)
var _next_destination_id: String = "" # 快速传送目标,用于发现登记
var _room_visit_context: Dictionary = {} # 访客房间的房主与返回位置
# 场景路径映射表
# 将场景名称映射到实际的文件路径
@@ -203,6 +204,39 @@ func get_next_destination_id() -> String:
_next_destination_id = ""
return destination_id
# ============ 访客房间上下文 ============
func begin_room_visit(owner_user_id: String, owner_nickname: String, return_scene: String, return_position: Vector2) -> void:
_room_visit_context = {
"owner_user_id": owner_user_id.strip_edges(),
"owner_nickname": owner_nickname.strip_edges(),
"return_scene": return_scene.strip_edges(),
"return_position": return_position,
}
func get_room_visit_context() -> Dictionary:
return _room_visit_context.duplicate(true)
func has_room_visit_context() -> bool:
return not str(_room_visit_context.get("owner_user_id", "")).strip_edges().is_empty()
func clear_room_visit_context() -> void:
_room_visit_context.clear()
func return_from_room_visit() -> bool:
if not has_room_visit_context():
return false
var context: Dictionary = _room_visit_context.duplicate(true)
clear_room_visit_context()
var return_scene: String = str(context.get("return_scene", "square")).strip_edges()
if not scene_paths.has(return_scene):
return_scene = "square"
var return_position: Variant = context.get("return_position", null)
if return_position is Vector2:
set_next_scene_position(return_position as Vector2)
change_scene(return_scene)
return true
# ============ 场景注册方法 ============
# 注册新场景

View File

@@ -25,6 +25,7 @@ const DEFAULT_SETTINGS: Dictionary = {
"allow_nearby_private": true,
"allow_nearby_friend_requests": true,
"allow_nearby_profile": true,
"room_visit_policy": "friends",
"mute_ui_sfx": false,
}

View File

@@ -82,6 +82,38 @@ func open_private_chat(user_id: String, username: String) -> void:
event_system.call("emit_event", EventNames.CHAT_PRIVATE_TARGET_SELECTED, {"userId": user_id, "username": username})
_close_profile()
func visit_room(user_id: String, nickname: String = "") -> void:
var owner_id: String = user_id.strip_edges()
if owner_id.is_empty():
return
_request_get("/social/profiles/%s" % owner_id.uri_encode(), func(success: bool, response: Dictionary, error: Dictionary) -> void:
if not success:
_show_status("无法访问房间:%s" % str(error.get("message", "请求失败")))
return
var profile_variant: Variant = response.get("data", {})
if not (profile_variant is Dictionary) or not bool((profile_variant as Dictionary).get("room_visitable", false)):
_show_status("该玩家当前不开放个人空间访问")
return
var profile: Dictionary = profile_variant as Dictionary
_begin_room_visit(owner_id, str(profile.get("nickname", nickname)))
)
func _begin_room_visit(owner_id: String, nickname: String) -> void:
var current_scene: Node = get_tree().current_scene
var return_scene: String = SceneManager.get_current_scene_name().strip_edges()
if return_scene.is_empty() and current_scene != null:
return_scene = _scene_name_to_id(current_scene.name)
if return_scene.is_empty() or return_scene == "personal_space":
return_scene = "square"
var return_position := Vector2.ZERO
if current_scene != null:
var player_node := current_scene.get_node_or_null("YSortWorld/Characters/Players/Player") as Node2D
if player_node != null:
return_position = player_node.global_position
SceneManager.begin_room_visit(owner_id, nickname, return_scene, return_position)
_close_profile()
SceneManager.change_scene("personal_space")
func request_travel(destination_id: String, completion: Callable = Callable()) -> void:
_request_post("/world/travel-destinations/%s/travel" % destination_id.uri_encode(), {}, func(success: bool, response: Dictionary, error: Dictionary) -> void:
if not success:
@@ -218,6 +250,8 @@ func _render_profile() -> void:
actions.add_theme_constant_override("separation", 8)
actions.add_child(_button("私聊", func() -> void: open_private_chat(user_id, nickname)))
actions.add_child(_button("加好友", func() -> void: request_friend(user_id, nickname)))
if bool(_current_profile.get("room_visitable", false)):
actions.add_child(_button("访问房间", func() -> void: visit_room(user_id, nickname)))
_profile_content.add_child(actions)
var safety := HBoxContainer.new()
safety.add_theme_constant_override("separation", 8)
@@ -427,6 +461,14 @@ func _current_user_id() -> String:
func _area_label(map_id: String) -> String:
return {"whale_port": "中心广场", "work_zone": "打工区", "whale_cafe": "鲸鱼咖啡馆", "personal_space": "个人空间"}.get(map_id, map_id)
func _scene_name_to_id(scene_name: String) -> String:
return {
"Square": "square",
"WorkZone": "work_zone",
"CafeInterior": "cafe_interior",
"PersonalSpace": "personal_space",
}.get(scene_name, "")
func _interest_catalog() -> Array[Dictionary]:
return [
{"id": "ai", "label": "AI/大模型"}, {"id": "programming", "label": "编程开发"},