diff --git a/spine-ts/spine-construct3/src/aces.json b/spine-ts/spine-construct3/src/aces.json index 12457536a..52be3e76c 100644 --- a/spine-ts/spine-construct3/src/aces.json +++ b/spine-ts/spine-construct3/src/aces.json @@ -715,6 +715,18 @@ } ] }, + { + "id": "slot-attachment-placeholder", + "expressionName": "SlotAttachmentPlaceholder", + "highlight": false, + "returnType": "string", + "params": [ + { + "id": "slot-name", + "type": "string" + } + ] + }, { "id": "bone-x", "expressionName": "BoneX", diff --git a/spine-ts/spine-construct3/src/c3runtime/expressions.ts b/spine-ts/spine-construct3/src/c3runtime/expressions.ts index da010cd4e..5e08c87d5 100644 --- a/spine-ts/spine-construct3/src/c3runtime/expressions.ts +++ b/spine-ts/spine-construct3/src/c3runtime/expressions.ts @@ -27,6 +27,7 @@ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +import type { Attachment, Skin } from "@esotericsoftware/spine-construct3-lib"; import type { SDKInstanceClass as SpineC3Instance } from "./instance"; const C3 = globalThis.C3; @@ -34,13 +35,35 @@ const C3 = globalThis.C3; C3.Plugins.EsotericSoftware_SpineConstruct3.Exps = { SlotAttachment (this: SpineC3Instance, slotName: string) { - if (!this.skeleton) return ""; - const slot = this.skeleton.findSlot(slotName); + const { skeleton } = this; + if (!skeleton) return ""; + const slot = skeleton.findSlot(slotName); if (!slot) return ""; const attachment = slot.pose.getAttachment(); return attachment ? attachment.name : ""; }, + SlotAttachmentPlaceholder (this: SpineC3Instance, slotName: string) { + const { skeleton } = this; + if (!skeleton) return ""; + const slot = skeleton.findSlot(slotName); + if (!slot) return ""; + const attachment = slot.pose.getAttachment(); + if (!attachment) return ""; + const slotIndex = slot.data.index; + const skin = skeleton.skin; + if (skin) { + const name = findPlaceholderName(skin, slotIndex, attachment); + if (name) return name; + } + const defaultSkin = skeleton.data.defaultSkin; + if (defaultSkin) { + const name = findPlaceholderName(defaultSkin, slotIndex, attachment); + if (name) return name; + } + return attachment.name; + }, + BoneX (this: SpineC3Instance, boneName: string) { return this.getBoneX(boneName); }, @@ -116,3 +139,12 @@ C3.Plugins.EsotericSoftware_SpineConstruct3.Exps = return this.getBounds().height; } }; + +function findPlaceholderName (skin: Skin, slotIndex: number, attachment: Attachment): string | null { + const dictionary = skin.attachments[slotIndex]; + if (!dictionary) return null; + for (const name in dictionary) { + if (dictionary[name] === attachment) return name; + } + return null; +} diff --git a/spine-ts/spine-construct3/src/lang/en-US.json b/spine-ts/spine-construct3/src/lang/en-US.json index 9c62bbc09..435c0132d 100644 --- a/spine-ts/spine-construct3/src/lang/en-US.json +++ b/spine-ts/spine-construct3/src/lang/en-US.json @@ -811,6 +811,16 @@ } } }, + "slot-attachment-placeholder": { + "description": "Get the skin placeholder name of the attachment on a slot, or the attachment name if using the default skin. Returns empty string if no attachment.", + "translated-name": "SlotAttachmentPlaceholder", + "params": { + "slot-name": { + "name": "Slot name", + "desc": "Name of the slot" + } + } + }, "bone-x": { "description": "Get the world X position of a bone.", "translated-name": "BoneX", diff --git a/spine-ts/spine-construct3/src/lang/zh-CN.json b/spine-ts/spine-construct3/src/lang/zh-CN.json index e7d78ae30..69ce34b01 100644 --- a/spine-ts/spine-construct3/src/lang/zh-CN.json +++ b/spine-ts/spine-construct3/src/lang/zh-CN.json @@ -811,6 +811,16 @@ } } }, + "slot-attachment-placeholder": { + "description": "获取插槽上附件的皮肤占位符名称,如果使用默认皮肤则返回附件名称。如果没有附件则返回空字符串。", + "translated-name": "SlotAttachmentPlaceholder", + "params": { + "slot-name": { + "name": "插槽名称", + "desc": "插槽的名称" + } + } + }, "bone-x": { "description": "获取骨骼的世界X位置。", "translated-name": "BoneX",