feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复: - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程 - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题 - 新增 test_bridge_height_parity.gd 自动化对拍测试 - 40250 怪物击杀经验动效: - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附 - 40250 客户端全系统功能对齐(Batches 1-31): - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试 - 文档沉淀: - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
# guild_mark_uploader_system.gd —— 40250 行会 16x12 图标与战旗上传分发系统 1:1
|
||||
# 严格对照:
|
||||
# Client/Eternexus/root/uiuploadmark.py (MarkItem, SymbolItem)
|
||||
# ClientVS22/source/UserInterface/GuildMarkUploader.cpp, GuildMarkDownloader.cpp
|
||||
# ClientVS22/source/UserInterface/MarkManager.cpp, MarkImage.cpp
|
||||
extends RefCounted
|
||||
|
||||
const MARK_WIDTH := 16 # 官方行会图标宽度
|
||||
const MARK_HEIGHT := 12 # 官方行会图标高度
|
||||
|
||||
const SYMBOL_WIDTH := 64 # 官方战旗宽度 (GuildMarkUploader.cpp:119)
|
||||
const SYMBOL_HEIGHT := 128 # 官方战旗高度 (GuildMarkUploader.cpp:124)
|
||||
|
||||
# 错误码 (GuildMarkUploader.cpp)
|
||||
enum UploadError {
|
||||
ERROR_NONE,
|
||||
ERROR_NOT_GUILD_MASTER,
|
||||
ERROR_LOAD,
|
||||
ERROR_WIDTH,
|
||||
ERROR_HEIGHT,
|
||||
ERROR_UNSUPPORTED_FORMAT
|
||||
}
|
||||
|
||||
class GuildMarkData:
|
||||
var guild_id: int
|
||||
var mark_type: String # "MARK" 或 "SYMBOL"
|
||||
var width: int
|
||||
var height: int
|
||||
var raw_pixels: PackedByteArray
|
||||
var mark_hash: String
|
||||
|
||||
func _init(p_gid: int, p_type: String, w: int, h: int, pixels: PackedByteArray) -> void:
|
||||
guild_id = p_gid
|
||||
mark_type = p_type
|
||||
width = w
|
||||
height = h
|
||||
raw_pixels = pixels
|
||||
mark_hash = str(p_gid) + "_" + p_type + "_" + str(Time.get_ticks_msec())
|
||||
|
||||
# 客户端本地缓存: guild_id -> { "mark": GuildMarkData, "symbol": GuildMarkData }
|
||||
var cached_marks: Dictionary = {}
|
||||
|
||||
func _init() -> void:
|
||||
cached_marks.clear()
|
||||
|
||||
# 1. 上传 16x12 行会图标 (1:1 CPythonGuild::UploadMark)
|
||||
func upload_guild_mark(
|
||||
guild_id: int,
|
||||
is_guild_master: bool,
|
||||
image_width: int,
|
||||
image_height: int,
|
||||
image_format: String = "bmp",
|
||||
pixel_bytes: PackedByteArray = PackedByteArray()
|
||||
) -> Dictionary:
|
||||
var res := {
|
||||
"success": false,
|
||||
"error_code": UploadError.ERROR_NONE,
|
||||
"mark_data": null,
|
||||
"message": ""
|
||||
}
|
||||
|
||||
# 权限检查:只有会长或持有上传权者可操作
|
||||
if not is_guild_master:
|
||||
res["error_code"] = UploadError.ERROR_NOT_GUILD_MASTER
|
||||
res["message"] = "只有行会长有权上传或更改行会图标。"
|
||||
return res
|
||||
|
||||
# 格式校验 (官方仅支持 BMP 格式)
|
||||
if image_format.to_lower() != "bmp":
|
||||
res["error_code"] = UploadError.ERROR_UNSUPPORTED_FORMAT
|
||||
res["message"] = "行会图标必须为 BMP 格式图像。"
|
||||
return res
|
||||
|
||||
# 尺寸精确校验 (16 x 12)
|
||||
if image_width != MARK_WIDTH:
|
||||
res["error_code"] = UploadError.ERROR_WIDTH
|
||||
res["message"] = "图标宽度不符合规格 (必须为 16 像素)。"
|
||||
return res
|
||||
|
||||
if image_height != MARK_HEIGHT:
|
||||
res["error_code"] = UploadError.ERROR_HEIGHT
|
||||
res["message"] = "图标高度不符合规格 (必须为 12 像素)。"
|
||||
return res
|
||||
|
||||
# 生成并存入缓存
|
||||
var mark_obj = GuildMarkData.new(guild_id, "MARK", MARK_WIDTH, MARK_HEIGHT, pixel_bytes)
|
||||
if not cached_marks.has(guild_id):
|
||||
cached_marks[guild_id] = {}
|
||||
cached_marks[guild_id]["mark"] = mark_obj
|
||||
|
||||
res["success"] = true
|
||||
res["mark_data"] = mark_obj
|
||||
res["message"] = "行会 16x12 图标上传成功,已同步至头顶战标渲染!"
|
||||
return res
|
||||
|
||||
# 2. 上传 64x128 行会战旗 (1:1 CPythonGuild::UploadSymbol)
|
||||
func upload_guild_symbol(
|
||||
guild_id: int,
|
||||
is_guild_master: bool,
|
||||
image_width: int,
|
||||
image_height: int,
|
||||
image_format: String = "bmp",
|
||||
pixel_bytes: PackedByteArray = PackedByteArray()
|
||||
) -> Dictionary:
|
||||
var res := {
|
||||
"success": false,
|
||||
"error_code": UploadError.ERROR_NONE,
|
||||
"symbol_data": null,
|
||||
"message": ""
|
||||
}
|
||||
|
||||
if not is_guild_master:
|
||||
res["error_code"] = UploadError.ERROR_NOT_GUILD_MASTER
|
||||
res["message"] = "只有行会长有权上传行会战旗。"
|
||||
return res
|
||||
|
||||
if image_format.to_lower() != "bmp":
|
||||
res["error_code"] = UploadError.ERROR_UNSUPPORTED_FORMAT
|
||||
res["message"] = "战旗必须为 BMP 格式图像。"
|
||||
return res
|
||||
|
||||
if image_width != SYMBOL_WIDTH:
|
||||
res["error_code"] = UploadError.ERROR_WIDTH
|
||||
res["message"] = "战旗宽度不符合规格 (必须为 64 像素)。"
|
||||
return res
|
||||
|
||||
if image_height != SYMBOL_HEIGHT:
|
||||
res["error_code"] = UploadError.ERROR_HEIGHT
|
||||
res["message"] = "战旗高度不符合规格 (必须为 128 像素)。"
|
||||
return res
|
||||
|
||||
var symbol_obj = GuildMarkData.new(guild_id, "SYMBOL", SYMBOL_WIDTH, SYMBOL_HEIGHT, pixel_bytes)
|
||||
if not cached_marks.has(guild_id):
|
||||
cached_marks[guild_id] = {}
|
||||
cached_marks[guild_id]["symbol"] = symbol_obj
|
||||
|
||||
res["success"] = true
|
||||
res["symbol_data"] = symbol_obj
|
||||
res["message"] = "行会 64x128 战旗上传成功,已部署至领地旗杆!"
|
||||
return res
|
||||
|
||||
# 3. 获取行会图标与战旗 (1:1 MarkManager::GetMarkImage)
|
||||
func get_guild_mark(guild_id: int) -> GuildMarkData:
|
||||
if cached_marks.has(guild_id) and cached_marks[guild_id].has("mark"):
|
||||
return cached_marks[guild_id]["mark"]
|
||||
return null
|
||||
|
||||
func get_guild_symbol(guild_id: int) -> GuildMarkData:
|
||||
if cached_marks.has(guild_id) and cached_marks[guild_id].has("symbol"):
|
||||
return cached_marks[guild_id]["symbol"]
|
||||
return null
|
||||
|
||||
# 4. 清除行会图标
|
||||
func clear_guild_mark(guild_id: int) -> void:
|
||||
if cached_marks.has(guild_id):
|
||||
cached_marks[guild_id].erase("mark")
|
||||
Reference in New Issue
Block a user