- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
157 lines
4.8 KiB
GDScript
157 lines
4.8 KiB
GDScript
# 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")
|