Files
mtgodot-poc/project/guild_mark_uploader_system.gd
T
shenandshen 66d217b313 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 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

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")