Files
mtgodot-poc/project/inventory_sort_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

164 lines
4.8 KiB
GDScript

# inventory_sort_system.gd —— Metin2 40250 多页背包智能自动整理与堆叠合并 1:1
# 对照 40250 服务端 char_item.cpp, uiinventory.py, item.cpp
class_name InventorySortSystem
extends RefCounted
signal inventory_sorted(total_items: int, merged_stacks: int)
signal page_switched(new_page: int)
const PAGE_SIZE := 45
const TOTAL_PAGES := 2
const TOTAL_SLOTS := 90 # 45 x 2
const MAX_STACK_LIMIT := 200
# 排序优先级分类
enum ItemCategory {
WEAPON = 1, # 武器
ARMOR = 2, # 铠甲防具
JEWELRY = 3, # 饰品首饰
CONSUMABLE = 4, # 药水与消耗品
MATERIAL = 5, # 强化升阶材料
CHEST_KEY = 6, # 宝箱与钥匙
OTHER = 7 # 其他
}
var current_page: int = 0
# 切换当前显示背包页 (0 或 1)
func switch_page(page_idx: int) -> Dictionary:
if page_idx < 0 or page_idx >= TOTAL_PAGES:
return {"ok": false, "reason": "INVALID_PAGE", "msg": "无效的背包页码!"}
current_page = page_idx
page_switched.emit(page_idx)
return {
"ok": true,
"page": page_idx,
"slot_start": page_idx * PAGE_SIZE,
"slot_end": (page_idx + 1) * PAGE_SIZE - 1
}
# 获取物品所属排序大类
static func get_item_category(item: Dictionary) -> int:
var it_type: String = item.get("item_type", "")
match it_type:
"weapon":
return ItemCategory.WEAPON
"armor", "shield", "helmet":
return ItemCategory.ARMOR
"jewelry", "necklace", "earrings", "bracelet", "shoes", "belt":
return ItemCategory.JEWELRY
"potion", "consumable", "dew", "elixir":
return ItemCategory.CONSUMABLE
"material", "fragment", "scroll":
return ItemCategory.MATERIAL
"chest", "key":
return ItemCategory.CHEST_KEY
_:
# 根据 vnum 范围与特征推断
var vnum: int = int(item.get("vnum", 0))
if vnum < 3000 and vnum >= 10:
return ItemCategory.WEAPON
elif vnum >= 11000 and vnum < 13200:
return ItemCategory.ARMOR
elif (vnum >= 27000 and vnum < 28000) or (vnum >= 50800 and vnum < 50900) or (vnum >= 72700 and vnum < 72800):
return ItemCategory.CONSUMABLE
elif (vnum >= 50000 and vnum < 50200) or (vnum >= 30000 and vnum < 30400):
return ItemCategory.CHEST_KEY
elif vnum >= 71000 and vnum < 72000:
return ItemCategory.MATERIAL
return ItemCategory.OTHER
# 判定物品是否可堆叠
static func is_item_stackable(item: Dictionary) -> bool:
if item.get("is_stackable", false):
return true
var it_type: String = item.get("item_type", "")
if ["potion", "consumable", "dew", "elixir", "material", "fragment", "scroll", "arrow"].has(it_type):
return true
var cnt: int = int(item.get("count", 1))
return cnt > 1
# 自动合并碎片堆叠 (Auto-Stack Merge)
func merge_stacks(inventory: Array) -> int:
var merged_count := 0
for i in range(inventory.size()):
var base = inventory[i]
if base == null or not is_item_stackable(base):
continue
var b_vnum: int = int(base.get("vnum", 0))
var b_count: int = int(base.get("count", 1))
if b_count >= MAX_STACK_LIMIT:
continue
for j in range(i + 1, inventory.size()):
var other = inventory[j]
if other == null or int(other.get("vnum", 0)) != b_vnum:
continue
var o_count: int = int(other.get("count", 1))
var space := MAX_STACK_LIMIT - b_count
if o_count <= space:
b_count += o_count
base["count"] = b_count
inventory[j] = null
merged_count += 1
else:
b_count = MAX_STACK_LIMIT
base["count"] = MAX_STACK_LIMIT
other["count"] = o_count - space
merged_count += 1
break
return merged_count
# 一键智能整理背包 (堆叠合并 + 分类前置紧凑排序)
func sort_inventory(inventory: Array) -> Dictionary:
# 1. 先进行碎片堆叠合并
var merged := merge_stacks(inventory)
# 2. 收集所有有效物品并打上排序权重标签
var items_to_sort: Array = []
for i in range(inventory.size()):
var it = inventory[i]
if it != null:
var cat := get_item_category(it)
var vnum: int = int(it.get("vnum", 0))
var level: int = int(it.get("level", 0))
items_to_sort.append({
"item": it,
"category": cat,
"vnum": vnum,
"level": level
})
# 3. 排序比较器:类别升序 (1~7),同类内 vnum 升序/降序排列
items_to_sort.sort_custom(func(a: Dictionary, b: Dictionary) -> bool:
if a["category"] != b["category"]:
return a["category"] < b["category"]
if a["vnum"] != b["vnum"]:
return a["vnum"] < b["vnum"]
return int(a["item"].get("count", 1)) > int(b["item"].get("count", 1))
)
# 4. 紧凑回填背包并清空末尾
var total_items := items_to_sort.size()
for i in range(inventory.size()):
if i < total_items:
inventory[i] = items_to_sort[i]["item"]
else:
inventory[i] = null
inventory_sorted.emit(total_items, merged)
return {
"ok": true,
"total_items": total_items,
"merged_stacks": merged,
"msg": "背包整理完成!共归纳 %d 件物品,合并 %d 处堆叠。" % [total_items, merged]
}