fix: 装备属性面板避让逻辑 + 多项功能更新

- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
This commit is contained in:
shen
2026-09-21 16:38:59 -07:00
parent 1522a8a1a1
commit c93894313a
5498 changed files with 4558004 additions and 1442 deletions
+22 -13
View File
@@ -35,10 +35,12 @@ const JOB_BASE_STATS := {
2: {"con": 3, "int": 5, "str": 5, "dex": 3}, # sura
3: {"con": 4, "int": 6, "str": 3, "dex": 3}, # shaman
}
# §1.10 名称长度校验统一:与 wire 契约 CHARACTER_NAME_MAX_LEN(=24, name[25])
# 对齐。角色名可含多字节字符,wire 缓冲是定长 25 字节,故按 UTF-8 字节长度设限,
# 与 guild_ui.gd 的公会名校验(非空 / 超长 / 控制字符)保持同一形状
const CHAR_NAME_MAX_BYTES := 24
# §1.10:40250 的角色名上限是网络字段的 24 个 GB2312 字节,而不是
# Godot/UTF-8 输入的 24 个字节。一个常用汉字在 GB2312 中占 2 字节,所以
# 12 个汉字可以合法放入角色名字段;直接按 UTF-8 字节限制会把它错误拒绝
# 输入框只限制 Unicode 字符数量,最终的 GB2312 可表示性和 wire 字节容量由
# M2Client/ClassicSession 在真正发包前统一校验。
const CHAR_NAME_MAX_CHARS := 24
const CHAR_NAME_MIN_CHARS := 2
const EMPIRE_KEY := {1: "EMPIRE_A", 2: "EMPIRE_B", 3: "EMPIRE_C"}
@@ -128,8 +130,8 @@ func _first_occupied() -> int:
func _validate_char_name(nm: String) -> String:
if nm.length() < CHAR_NAME_MIN_CHARS:
return "名称太短"
if nm.to_utf8_buffer().size() > CHAR_NAME_MAX_BYTES:
return "名称太长(最多 %d 字节" % CHAR_NAME_MAX_BYTES
if nm.length() > CHAR_NAME_MAX_CHARS:
return "名称太长(最多 %d 个字符" % CHAR_NAME_MAX_CHARS
for ch in nm:
if ch.unicode_at(0) < 32:
return "名称包含非法字符"
@@ -695,9 +697,16 @@ func _do_start() -> void:
if dur > 0.0:
anim_dur = dur
await get_tree().create_timer(anim_dur).timeout
if not is_inside_tree():
return
# The real select window is always tree-owned, but keeping the signal
# usable when a headless/reconnect harness invokes the handler before the
# transient CanvasLayer is attached prevents the selection from being
# silently dropped. Once a tree-owned screen leaves the tree, it is being
# replaced and must not emit into the new phase.
var had_tree := is_inside_tree()
if had_tree and get_tree() != null:
await get_tree().create_timer(anim_dur).timeout
if not is_inside_tree():
return
select_requested.emit(_slot_index())
func _unhandled_input(event: InputEvent) -> void:
@@ -791,9 +800,9 @@ func _open_create_dialog() -> void:
nrow.add_child(_plain("名称", 13, Color(0.72, 0.78, 0.85)))
var name_edit := LineEdit.new()
name_edit.name = "Name"
name_edit.max_length = CHAR_NAME_MAX_BYTES
name_edit.max_length = CHAR_NAME_MAX_CHARS
name_edit.custom_minimum_size = Vector2(240, 0)
name_edit.placeholder_text = "角色名(最多 24 字节)"
name_edit.placeholder_text = "角色名(中文最多 12 字,最终按 GB2312 字节校验"
nrow.add_child(name_edit)
# 四维(起始属性,只读,随职业变)
@@ -852,9 +861,9 @@ func _open_change_name_dialog() -> void:
nrow.add_child(_plain("新名称", 13, Color(0.72, 0.78, 0.85)))
var name_edit := LineEdit.new()
name_edit.name = "Name"
name_edit.max_length = CHAR_NAME_MAX_BYTES
name_edit.max_length = CHAR_NAME_MAX_CHARS
name_edit.custom_minimum_size = Vector2(220, 0)
name_edit.placeholder_text = "角色名(最多 24 字节)"
name_edit.placeholder_text = "角色名(中文最多 12 字,最终按 GB2312 字节校验"
nrow.add_child(name_edit)
box.add_child(_sep())
var brow := HBoxContainer.new()