Files
mtgodot-poc/project/weapon_attach_test.gd
T
shenleiandClaude Opus 5 1933a5ceda fix(combat): 战斗逐项对齐 40250,修复移动 / 技能释放与武器挂点
- 连击类型由 combo_changed 驱动(SetComboSkillFlag,技能 122 等级)
- 命中判定改为 .msa 刀尖 Z 圆柱 vs .msm 防御球(hit_collision.gd 逐行移植)
- _register_hit 改为 map::insert 语义,修正命中上限
- 攻速同时缩放 GetAttackingElapsedTime 与攻击动作速率;按武器动作模式目录绑定攻击段
- 去掉本地连击超时,motion_bound 清命中表 / 连击段号
- __ProcessDataAttackSuccess:InsertDelay 硬直、physics_push.gd 击退 + GetBlendingPosition 同步、
  命中特效、__HitGood / __HitGreate / __HitStone 受击动作链与抖动(ui/hit_reaction.gd)
- ClassicSession::send_use_skill 不再夹带 CG_FLY_TARGETING
- mac 前进 / 后退方向与技能释放修复;武器按职业骨骼挂到手上
- 新增 hit_collision / physics_push / hit_view / net_world_push / weapon_attach 测试;
  gpu_pose_bounds / race_motion_assembly 适配 damage 随机变体
- 文档:CLIENT-GAP.md、CLIENT-GAP-FIX.md §3.5 / §3.7 与 C.5 增量 130

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ft3kXpNdLbKEfg5uDLfqVF
2026-09-12 13:15:28 +09:00

82 lines
3.1 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# weapon_attach_test —— 武器挂点按种族 + 左右手(真 PlayerView + 真 gr2)。
# godot --headless --path project --script weapon_attach_test.gd
#
# 参考端 playersettingmodule.py RegisterAttachingBoneName
# warrior PART_WEAPON=equip_right_hand (661)
# assassin PART_WEAPON=equip_right PART_WEAPON_LEFT=equip_left (873-874)
# sura PART_WEAPON=equip_right (999)
# shaman PART_WEAPON=equip_right PART_WEAPON_LEFT=equip_left (1190-1191)
# ActorInstanceAttach.cpp AttachWeaponGetAttachingBoneName 失败(该职业没登记左手)就不挂。
# PlayerView 的 shield_gr2 槽 = PART_WEAPON_LEFT(参考端没有盾牌挂件)。
extends SceneTree
const PlayerView = preload("res://ui/player_view.gd")
const RIGHT_BONE := ["equip_right_hand", "equip_right", "equip_right", "equip_right"]
const LEFT_BONE := ["", "equip_left", "", "equip_left"]
const MAX_GRIP_M := 0.10
var _fail := 0
func _ck(c: bool, m: String) -> void:
if not c:
_fail += 1
printerr("FAIL: " + m)
func _init() -> void:
await _run()
if _fail == 0:
print("PASS: weapon_attach_test (race attaching bones + left/right hand)")
quit(0)
else:
printerr("%d check(s) failed" % _fail)
quit(1)
func _run() -> void:
if not ClassDB.class_exists("Metin2Model"):
print(" (skip: no Metin2Model extension)")
return
var assets := AssetRoot.path()
var weapon_dir := assets.path_join("item/ymir work/item/weapon")
var sword := weapon_dir.path_join("00010.gr2")
var dagger := weapon_dir.path_join("04000.gr2")
if not FileAccess.file_exists(sword) or not FileAccess.file_exists(dagger):
print(" (skip: weapon gr2 assets missing)")
return
await process_frame
for race in 8:
var job := race & 3
var pv = PlayerView.new()
get_root().add_child(pv)
if not pv.build(assets, race):
print(" (skip race %d: body assets missing)" % race)
pv.free()
continue
pv.set("weapon_gr2", sword)
pv.set("shield_gr2", dagger)
for i in 3:
await process_frame
var right := pv.model.get_node_or_null("Weapon") as Node3D
_ck(right != null, "race %d: right-hand weapon attached (%s)" % [race, RIGHT_BONE[job]])
if right:
_ck(_near(pv, right, RIGHT_BONE[job]), "race %d: weapon sits on %s" % [race, RIGHT_BONE[job]])
var left := pv.model.get_node_or_null("Shield") as Node3D
if LEFT_BONE[job] == "":
_ck(left == null, "race %d: no PART_WEAPON_LEFT bone registered -> nothing on left hand" % race)
else:
_ck(left != null, "race %d: left-hand weapon attached (%s)" % [race, LEFT_BONE[job]])
if left:
_ck(_near(pv, left, LEFT_BONE[job]), "race %d: left weapon sits on %s" % [race, LEFT_BONE[job]])
pv.queue_free()
await process_frame
func _near(pv: Node, node: Node3D, bone: String) -> bool:
var pose: Dictionary = pv.anim.call("get_effect_bone_pose", bone)
if pose.is_empty():
printerr(" bone %s has no pose" % bone)
return false
var hand: Vector3 = (pv.model as Node3D).global_transform * (pose["transform"] as Transform3D).origin
var d := node.global_position.distance_to(hand)
if d > MAX_GRIP_M:
printerr(" %s is %.3f m from %s" % [node.name, d, bone])
return d <= MAX_GRIP_M