fix: Articulate pants with leg bones and fix walking animation clipping
checkpoint / checkpoint (push) Successful in 6m11s
checkpoint / checkpoint (push) Successful in 6m11s
This commit is contained in:
@@ -191,23 +191,52 @@ func load_attachment(slot_id: String, asset_id: String) -> Node3D:
|
||||
# skeleton; static props (the common case) are unaffected.
|
||||
_retarget_skin(attachment_node)
|
||||
|
||||
# Mount to the appropriate bone via a BoneAttachment3D so it follows the
|
||||
# skeleton. Falls back to a plain skeleton child if the mount bone is
|
||||
# missing (a bad catalog entry) rather than dropping the attachment.
|
||||
var mount_bone: String = asset_meta.get("mount_bone", "")
|
||||
if mount_bone.is_empty():
|
||||
mount_bone = _slot_to_mount_bone(slot_id)
|
||||
# Check if this attachment has multi-bone children (e.g. Attach_LeftUpperLeg, Attach_Hips).
|
||||
var multi_bone_children: Array[Node] = []
|
||||
for child in attachment_node.get_children():
|
||||
var cname := child.name
|
||||
if cname.begins_with("Attach_") or cname.begins_with("attach_"):
|
||||
var target_bone := cname.substr(7)
|
||||
if skeleton.find_bone(target_bone) != -1:
|
||||
multi_bone_children.append(child)
|
||||
|
||||
var mount_node: Node3D
|
||||
if not mount_bone.is_empty() and skeleton.find_bone(mount_bone) != -1:
|
||||
var ba := BoneAttachment3D.new()
|
||||
ba.name = "Mount_%s" % slot_id if slot_id != "accessory" else "Mount_accessory_%s" % asset_id
|
||||
ba.bone_name = mount_bone
|
||||
skeleton.add_child(ba)
|
||||
ba.add_child(attachment_node)
|
||||
mount_node = ba
|
||||
else:
|
||||
if not multi_bone_children.is_empty():
|
||||
var created_bas: Array[BoneAttachment3D] = []
|
||||
for child in multi_bone_children:
|
||||
var target_bone := child.name.substr(7)
|
||||
var ba := BoneAttachment3D.new()
|
||||
ba.name = "Mount_%s_%s" % [slot_id, target_bone]
|
||||
ba.bone_name = target_bone
|
||||
skeleton.add_child(ba)
|
||||
attachment_node.remove_child(child)
|
||||
ba.add_child(child)
|
||||
created_bas.append(ba)
|
||||
|
||||
skeleton.add_child(attachment_node)
|
||||
attachment_node.set_meta("bone_attachments", created_bas)
|
||||
attachment_node.tree_exiting.connect(func():
|
||||
for ba in created_bas:
|
||||
if is_instance_valid(ba) and not ba.is_queued_for_deletion():
|
||||
ba.queue_free()
|
||||
)
|
||||
mount_node = attachment_node
|
||||
else:
|
||||
# Single mount bone via a BoneAttachment3D so it follows the skeleton.
|
||||
# Falls back to a plain skeleton child if the mount bone is missing.
|
||||
var mount_bone: String = asset_meta.get("mount_bone", "")
|
||||
if mount_bone.is_empty():
|
||||
mount_bone = _slot_to_mount_bone(slot_id)
|
||||
if not mount_bone.is_empty() and skeleton.find_bone(mount_bone) != -1:
|
||||
var ba := BoneAttachment3D.new()
|
||||
ba.name = "Mount_%s" % slot_id if slot_id != "accessory" else "Mount_accessory_%s" % asset_id
|
||||
ba.bone_name = mount_bone
|
||||
skeleton.add_child(ba)
|
||||
ba.add_child(attachment_node)
|
||||
mount_node = ba
|
||||
else:
|
||||
skeleton.add_child(attachment_node)
|
||||
mount_node = attachment_node
|
||||
|
||||
# Store the top-level mount node so unload can free the whole unit.
|
||||
if slot_id == "accessory":
|
||||
@@ -228,11 +257,19 @@ func unload_attachment(slot_id: String) -> void:
|
||||
if slot_id == "accessory":
|
||||
for node in _attachments.get("accessory", []):
|
||||
if is_instance_valid(node):
|
||||
if node.has_meta("bone_attachments"):
|
||||
for ba in node.get_meta("bone_attachments"):
|
||||
if is_instance_valid(ba):
|
||||
ba.queue_free()
|
||||
node.queue_free()
|
||||
_attachments.erase("accessory")
|
||||
else:
|
||||
var node = _attachments.get(slot_id)
|
||||
if is_instance_valid(node):
|
||||
if node.has_meta("bone_attachments"):
|
||||
for ba in node.get_meta("bone_attachments"):
|
||||
if is_instance_valid(ba):
|
||||
ba.queue_free()
|
||||
node.queue_free()
|
||||
_attachments.erase(slot_id)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user