- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
120 lines
4.6 KiB
GDScript
120 lines
4.6 KiB
GDScript
# test_inventory_sort_parity.gd —— 40250 多页背包与智能自动整理 1:1 纯净回归测试套件
|
|
extends SceneTree
|
|
|
|
const InventorySortSystem = preload("res://inventory_sort_system.gd")
|
|
|
|
var _passed := 0
|
|
var _failed := 0
|
|
|
|
func _assert(cond: bool, msg: String) -> void:
|
|
if cond:
|
|
_passed += 1
|
|
print(" [PASS] %s" % msg)
|
|
else:
|
|
_failed += 1
|
|
printerr(" [FAIL] %s" % msg)
|
|
|
|
func _init() -> void:
|
|
print("\n=== Running test_inventory_sort_parity (Direction 2: Inventory Sort & Stacking 1:1) ===")
|
|
_test_page_switching()
|
|
_test_stack_merging()
|
|
_test_category_sorting_and_compaction()
|
|
_finish()
|
|
|
|
func _test_page_switching() -> void:
|
|
print("\n--- Test 1: Multi-Page Switching (Page 0 & Page 1, 90 Slots) ---")
|
|
var iss := InventorySortSystem.new()
|
|
|
|
var page_signal := {"fired": false, "page": -1}
|
|
iss.page_switched.connect(func(p: int):
|
|
page_signal["fired"] = true
|
|
page_signal["page"] = p
|
|
)
|
|
|
|
# Invalid page
|
|
var r_bad = iss.switch_page(2)
|
|
_assert(r_bad["ok"] == false and r_bad["reason"] == "INVALID_PAGE", "Page 2 rejected (> max page 1)")
|
|
|
|
# Page 0 (Slots 0..44)
|
|
var r0 = iss.switch_page(0)
|
|
_assert(r0["ok"] == true, "Page 0 switched successfully")
|
|
_assert(r0["slot_start"] == 0 and r0["slot_end"] == 44, "Page 0 covers slots 0 to 44")
|
|
_assert(page_signal["fired"] == true and page_signal["page"] == 0, "page_switched signal fired for 0")
|
|
|
|
# Page 1 (Slots 45..89)
|
|
var r1 = iss.switch_page(1)
|
|
_assert(r1["ok"] == true, "Page 1 switched successfully")
|
|
_assert(r1["slot_start"] == 45 and r1["slot_end"] == 89, "Page 1 covers slots 45 to 89")
|
|
_assert(page_signal["page"] == 1, "page_switched signal fired for 1")
|
|
|
|
func _test_stack_merging() -> void:
|
|
print("\n--- Test 2: Auto-Stack Merging (Max 200 Limit) ---")
|
|
var iss := InventorySortSystem.new()
|
|
var inv: Array = [
|
|
{"vnum": 27003, "name": "红药水(大)", "item_type": "potion", "count": 50}, # Slot 0
|
|
null, # Slot 1
|
|
{"vnum": 27003, "name": "红药水(大)", "item_type": "potion", "count": 80}, # Slot 2
|
|
{"vnum": 27003, "name": "红药水(大)", "item_type": "potion", "count": 100} # Slot 3
|
|
]
|
|
|
|
var merged = iss.merge_stacks(inv)
|
|
_assert(merged == 2, "2 stack merges performed")
|
|
|
|
# Slot 0 should have 50 + 80 + 70 = 200 (max cap)
|
|
_assert(inv[0]["count"] == 200, "Slot 0 merged to max 200")
|
|
# Slot 2 fully consumed into slot 0
|
|
_assert(inv[2] == null, "Slot 2 consumed and set to null")
|
|
# Slot 3 had 100, gave 70 to slot 0 -> 30 remaining
|
|
_assert(inv[3] != null and inv[3]["count"] == 30, "Slot 3 has 30 remaining count")
|
|
|
|
func _test_category_sorting_and_compaction() -> void:
|
|
print("\n--- Test 3: Category Sorting (Weapons -> Armors -> Consumables -> Materials -> Chests) ---")
|
|
var iss := InventorySortSystem.new()
|
|
|
|
var sort_signal := {"fired": false, "items": 0, "merged": 0}
|
|
iss.inventory_sorted.connect(func(cnt: int, m: int):
|
|
sort_signal["fired"] = true
|
|
sort_signal["items"] = cnt
|
|
sort_signal["merged"] = m
|
|
)
|
|
|
|
# Fragmented messy inventory
|
|
var inv: Array = [
|
|
{"vnum": 71084, "name": "高级附魔石", "item_type": "material", "count": 5}, # Mat
|
|
null,
|
|
{"vnum": 169, "name": "战神之剑+9", "item_type": "weapon"}, # Weapon
|
|
{"vnum": 27003, "name": "红药水(大)", "item_type": "potion", "count": 10}, # Potion
|
|
null,
|
|
{"vnum": 11299, "name": "黑钢甲+9", "item_type": "armor"}, # Armor
|
|
{"vnum": 50006, "name": "九尾宝箱", "item_type": "chest"} # Chest
|
|
]
|
|
|
|
var res = iss.sort_inventory(inv)
|
|
_assert(res["ok"] == true, "sort_inventory succeeded")
|
|
_assert(res["total_items"] == 5, "5 total non-empty items sorted")
|
|
_assert(sort_signal["fired"] == true and sort_signal["items"] == 5, "inventory_sorted signal fired")
|
|
|
|
# Check exact order:
|
|
# 1. Weapon (169)
|
|
# 2. Armor (11299)
|
|
# 3. Consumable (27003)
|
|
# 4. Material (71084)
|
|
# 5. Chest (50006)
|
|
_assert(inv[0] != null and inv[0]["vnum"] == 169, "Slot 0 is Weapon (169)")
|
|
_assert(inv[1] != null and inv[1]["vnum"] == 11299, "Slot 1 is Armor (11299)")
|
|
_assert(inv[2] != null and inv[2]["vnum"] == 27003, "Slot 2 is Potion (27003)")
|
|
_assert(inv[3] != null and inv[3]["vnum"] == 71084, "Slot 3 is Material (71084)")
|
|
_assert(inv[4] != null and inv[4]["vnum"] == 50006, "Slot 4 is Chest (50006)")
|
|
|
|
# Remaining slots compacted to null
|
|
_assert(inv[5] == null and inv[6] == null, "Trailing slots compacted to null")
|
|
|
|
func _finish() -> void:
|
|
print("\n==========================================")
|
|
print("Inventory Sort Parity Test Results: %d Passed, %d Failed" % [_passed, _failed])
|
|
print("==========================================")
|
|
if _failed > 0:
|
|
quit(1)
|
|
else:
|
|
quit(0)
|