Pull some improvements from #2949, style fixes, name changes to remove template plugin names.

This commit is contained in:
Davide Tantillo 2025-11-03 12:16:02 +01:00
parent 9af308b2df
commit 19396f435c
13 changed files with 218 additions and 165 deletions

View File

@ -17,7 +17,7 @@
"build:core:iife": "npx esbuild --bundle spine-core/src/index.ts --tsconfig=spine-core/tsconfig.json --sourcemap --outfile=spine-core/dist/iife/spine-core.js --format=iife --global-name=spine",
"build:core:esm": "npx esbuild --bundle spine-core/src/index.ts --tsconfig=spine-core/tsconfig.json --sourcemap --outfile=spine-core/dist/esm/spine-core.mjs --format=esm --global-name=spine",
"build:construct3": "npx tsc --project spine-construct3/tsconfig.json && npm run build:construct3:copy-assets",
"build:construct3:copy-assets": "npx copyfiles -u 2 \"spine-construct3/src/**/*.json\" \"spine-construct3/src/**/*.svg\" spine-construct3/dist/ && cp spine-construct3-lib/dist/iife/spine-construct3-lib.js spine-construct3/dist/c3runtime",
"build:construct3:copy-assets": "npx copyfiles -u 2 \"spine-construct3/src/**/*.json\" \"spine-construct3/src/**/*.svg\" spine-construct3/dist/ && npx copyfiles -u 3 spine-construct3-lib/dist/iife/spine-construct3-lib.js spine-construct3/dist/c3runtime",
"build:construct3-lib": "node spine-construct3-lib/esbuild.config.js",
"build:canvas:iife": "npx esbuild --bundle spine-canvas/src/index.ts --tsconfig=spine-canvas/tsconfig.json --sourcemap --outfile=spine-canvas/dist/iife/spine-canvas.js --format=iife --global-name=spine",
"build:canvas:esm": "npx esbuild --bundle spine-canvas/src/index.ts --tsconfig=spine-canvas/tsconfig.json --sourcemap --outfile=spine-canvas/dist/esm/spine-canvas.mjs --format=esm --global-name=spine",

View File

@ -1,17 +1,17 @@
{
"$schema": "./plugin.addon.schema.json",
"$schema": "../plugin.addon.schema.json",
"is-c3-addon": true,
"sdk-version": 2,
"min-construct-version": "r401",
"min-construct-version": "r459",
"type": "plugin",
"name": "My Spine plugin",
"name": "Spine Construct3",
"id": "EsotericSoftware_SpineConstruct3",
"version": "1.0.0.1",
"author": "Esoteric Software",
"website": "https://www.esotericsoftware.com",
"documentation": "https://www.esotericsoftware.com",
"description": "Example custom drawing Construct 3 plugin.",
"description": "The official Spine runtime for Construct3.",
"editor-scripts": [
"plugin.js",
"type.js",
@ -27,6 +27,7 @@
"c3runtime/actions.js",
"c3runtime/expressions.js",
"lang/en-US.json",
"lang/zh-CN.json",
"aces.json",
"addon.json",
"icon.svg",

View File

@ -6,7 +6,7 @@ const C3 = globalThis.C3;
C3.Plugins.EsotericSoftware_SpineConstruct3.Acts =
{
Alert (this: SDKInstanceClass) {
alert("Test property = " + this._getTestProperty());
alert(`Test property = ${this._getTestProperty()}`);
},
SetSkin (this: SDKInstanceClass, skinList: string) {

View File

@ -5,8 +5,7 @@ const C3 = globalThis.C3;
C3.Plugins.EsotericSoftware_SpineConstruct3.Exps =
{
Double(this: SDKInstanceClass, num: number)
{
Double (this: SDKInstanceClass, num: number) {
return num * 2;
}
};

View File

@ -1,11 +1,11 @@
import { AnimationEventType, type AnimationState, AnimationStateListener, type AssetLoader, BlendingModeSpineToC3, type Event, EventType, type Skeleton, type SkeletonRendererCore, type SpineBoundsProvider, type TextureAtlas, TrackEntry } from "@esotericsoftware/spine-construct3-lib";
import type { AnimationState, AssetLoader, Event, Skeleton, SkeletonRendererCore, TextureAtlas, } from "@esotericsoftware/spine-construct3-lib";
const C3 = globalThis.C3;
const spine = globalThis.spine;
spine.Skeleton.yDown = true;
class DrawingInstance extends globalThis.ISDKWorldInstanceBase {
class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
propAtlas = "";
propSkel = "";
propLoaderScale = 1;
@ -292,6 +292,6 @@ class DrawingInstance extends globalThis.ISDKWorldInstanceBase {
}
};
C3.Plugins.EsotericSoftware_SpineConstruct3.Instance = DrawingInstance;
C3.Plugins.EsotericSoftware_SpineConstruct3.Instance = SpineC3Instance;
export type { DrawingInstance as SDKInstanceClass };
export type { SpineC3Instance as SDKInstanceClass };

View File

@ -1,12 +1,7 @@
const C3 = globalThis.C3;
C3.Plugins.EsotericSoftware_SpineConstruct3 = class DrawingPlugin extends globalThis.ISDKPluginBase
{
constructor()
{
super();
}
C3.Plugins.EsotericSoftware_SpineConstruct3 = class SpineC3 extends globalThis.ISDKPluginBase {
};
// Necessary for TypeScript to treat this file as a module

View File

@ -3,47 +3,5 @@ import type { SDKInstanceClass } from "./instance.ts";
const C3 = globalThis.C3;
C3.Plugins.EsotericSoftware_SpineConstruct3.Type = class DrawingType extends globalThis.ISDKObjectTypeBase<SDKInstanceClass>
{
constructor()
{
super();
}
// async _loadTextures(renderer: IRenderer)
// {
// return renderer.loadTextureForImageInfo(this.getImageInfo(), {
// sampling: this.runtime.sampling
// });
// }
// async _loadTextures(renderer: IRenderer)
// {
// return renderer.loadTextureForImageInfo(this.getImageInfo(), {
// sampling: this.runtime.sampling
// });
// }
// getImageInfo(): IImageInfo
// {
// return {
// width: 1,
// height: 1,
// getSize(): Vec2Arr { return [1, 1]; },
// getTexture(renderer: IRenderer): ITexture | null { return null; },
// getTexRect(): DOMRect { return new DOMRect(0, 0, 1, 1); }
// };
// }
// _onCreate()
// {
// this.runtime.assets.loadImageAsset(this.getImageInfo());
// }
// _releaseTextures(renderer: IRenderer)
// {
// renderer.releaseTextureForImageInfo(this.getImageInfo());
// }
C3.Plugins.EsotericSoftware_SpineConstruct3.Type = class SpineC3Type extends globalThis.ISDKObjectTypeBase<SDKInstanceClass> {
};

View File

@ -1,6 +1,6 @@
// / <reference types="editor/sdk" />
import { AnimationState, AssetLoader, Skeleton, SkeletonRendererCore, SpineBoundsProvider, TextureAtlas } from "@esotericsoftware/spine-construct3-lib";
import type { AnimationState, AssetLoader, Skeleton, SkeletonRendererCore, SpineBoundsProvider, TextureAtlas } from "@esotericsoftware/spine-construct3-lib";
const SDK = globalThis.SDK;
@ -10,7 +10,7 @@ let spine: typeof globalThis.spine;
type SpineBoundsProviderType = "setup" | "animation-skin" | "AABB";
class MyDrawingInstance extends SDK.IWorldInstanceBase {
class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
private layoutView?: SDK.UI.ILayoutView;
private renderer?: SDK.Gfx.IWebGLRenderer;
@ -467,6 +467,6 @@ class MyDrawingInstance extends SDK.IWorldInstanceBase {
}
};
PLUGIN_CLASS.Instance = MyDrawingInstance;
PLUGIN_CLASS.Instance = SpineC3PluginInstance;
export type { MyDrawingInstance as SDKEditorInstanceClass };
export type { SpineC3PluginInstance as SDKEditorInstanceClass };

View File

@ -2,7 +2,7 @@
"$schema": "../../plugin.lang.schema.json",
"languageTag": "en-US",
"fileDescription": "Strings for MyDrawingPlugin.",
"fileDescription": "Strings for SpineC3Plugin.",
"text": {
"plugins": {
"esotericsoftware_spineconstruct3": {

View File

@ -0,0 +1,178 @@
{
"$schema": "../../plugin.lang.schema.json",
"languageTag": "zh-CN",
"fileDescription": "Spine插件的字符串资源。",
"text": {
"plugins": {
"esotericsoftware_spineconstruct3": {
"name": "Spine",
"description": "Spine运行时 for Construct3。",
"help-url": "https://www.construct.net",
"properties": {
"spine-skeleton-file": {
"name": "骨架",
"desc": "骨架文件"
},
"spine-atlas-file": {
"name": "图集",
"desc": "图集文件"
},
"spine-loader-scale": {
"name": "加载比例",
"desc": "加载比例"
},
"spine-animation": {
"name": "动画",
"desc": "动画"
},
"spine-skin": {
"name": "皮肤",
"desc": "皮肤"
},
"spine-errors": {
"name": "错误",
"desc": "错误"
},
"spine-bounds-provider-group": {
"name": "边界提供者",
"desc": "选择所需的边界提供者并填写相应的属性。"
},
"spine-bounds-provider": {
"name": "边界提供者",
"desc": "要使用的边界提供者。",
"items": {
"setup": "初始姿势边界",
"animation-skin": "动画/皮肤边界"
}
},
"spine-bounds-provider-move": {
"name": "位置边界",
"desc": "在调整边界大小和位置时保持骨架固定在一个位置。"
},
"spine-scale-x": {
"name": "X缩放",
"desc": "X缩放"
},
"spine-scale-y": {
"name": "Y缩放",
"desc": "Y缩放"
},
"spine-bounds-offset-x": {
"name": "X偏移",
"desc": "X偏移"
},
"spine-bounds-offset-y": {
"name": "Y偏移",
"desc": "Y偏移"
},
"spine-bounds-offset-angle": {
"name": "偏移角度",
"desc": "偏移角度"
}
},
"aceCategories": {
"custom": "自定义"
},
"conditions": {
"on-skeleton-loaded": {
"list-name": "骨架加载完成时",
"display-text": "骨架加载完成时",
"description": "当骨架加载完成时执行操作"
},
"on-animation-event": {
"list-name": "动画事件触发时",
"display-text": "当轨道{1}上的动画{2}触发{0}事件时",
"description": "当动画事件触发时执行操作",
"params": {
"event": {
"name": "事件名称",
"desc": "事件名称"
},
"animation": {
"name": "动画",
"desc": "动画"
},
"track": {
"name": "轨道编号",
"desc": "轨道编号"
}
}
}
},
"actions": {
"do-alert": {
"list-name": "显示警告",
"display-text": "显示警告",
"description": "显示一个示例警告。"
},
"set-skin": {
"list-name": "设置皮肤",
"display-text": "设置皮肤 {0}",
"description": "设置皮肤",
"params": {
"skin-name": {
"name": "皮肤列表",
"desc": "用逗号分隔的要设置的皮肤列表。空字符串表示取消设置所有皮肤。"
}
}
},
"add-animation": {
"list-name": "添加动画",
"display-text": "在轨道{0}上添加动画{1},循环{2},延迟{3}",
"description": "添加动画",
"params": {
"track": {
"name": "轨道",
"desc": "轨道"
},
"animation": {
"name": "动画名称",
"desc": "动画名称"
},
"loop": {
"name": "循环",
"desc": "循环"
},
"delay": {
"name": "延迟",
"desc": "延迟"
}
}
},
"set-animation": {
"list-name": "设置动画",
"display-text": "在轨道{0}上设置动画{1},循环{2}",
"description": "设置动画",
"params": {
"track": {
"name": "轨道",
"desc": "轨道"
},
"animation": {
"name": "动画名称",
"desc": "动画名称"
},
"loop": {
"name": "循环",
"desc": "循环"
}
}
}
},
"expressions": {
"double": {
"description": "将数字翻倍。",
"translated-name": "Double",
"params": {
"number": {
"name": "数字",
"desc": "要翻倍的数字。"
}
}
}
}
}
}
}
}

View File

@ -1,73 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://construct.net/sdk/schema/plugin.addon.schema.json",
"title": "Plugin addon.json",
"description": "Main JSON file that describes metadata about a plugin.",
"type": "object",
"properties": {
"is-c3-addon": {
"description": "This is used by Construct to identify valid addons.",
"const": true
},
"sdk-version": {
"description": "The version of the Addon SDK used for this addon.",
"enum": [1, 2]
},
"type": {
"description": "Indicates the addon type. For the plugin schema, this must be \"plugin\".",
"const": "plugin"
},
"name": {
"description": "The displayed name of the addon, in English. This can be changed after release.",
"type": "string"
},
"id": {
"description": "The unique ID of the addon. This must not be used by any other addon ever published for Construct, and must never change after you first publish your addon. It is recommended to use a vendor-specific prefix, e.g. MyCompany_MyAddon.",
"type": "string"
},
"version": {
"description": "A string specifying the addon version in four parts (major, minor, patch, revision).",
"type": "string"
},
"min-construct-version": {
"description": "The minimum Construct version required to use this addon, e.g. \"r400\"",
"type": "string"
},
"supports-worker-mode": {
"description": "Whether the addon supports running in worker mode, where the Construct runtime is hosted in a Web Worker. Defaults to true; if set to false the presence of the addon in a project will block the runtime from using worker mode.",
"type": "boolean"
},
"author": {
"description": "A string identifying the author of the addon.",
"type": "string"
},
"website": {
"description": "A string of a URL to the author's website. It is recommended to provide updates to the addon at this URL if any become available. The website should use HTTPS.",
"type": "string",
"format": "uri"
},
"documentation": {
"description": "A string of a URL to the online documentation for the addon. It is important to provide documentation for your addon to be useful to users.",
"type": "string",
"format": "uri"
},
"description": {
"description": "A string of a brief description of what the addon does, displayed when prompting the user to install the addon.",
"type": "string"
},
"editor-scripts": {
"description": "An array of script files in the addon package to load in the editor.",
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"uniqueItems": true
},
"file-list": {
"description": "A list of all files used by the addon. Required for Developer Mode addons to work.",
"type": "array",
"items": { "type": "string" }
}
},
"required": ["is-c3-addon", "type", "name", "id", "version", "author", "website", "documentation", "description", "editor-scripts"]
}

View File

@ -1,3 +1,4 @@
// biome-ignore lint/correctness/noUnusedImports: necessary to make C3 recognize the plugin
import type { SDKEditorInstanceClass } from "./instance.ts";
const SDK = globalThis.SDK;
@ -15,7 +16,7 @@ const PLUGIN_ID = "EsotericSoftware_SpineConstruct3";
const PLUGIN_CATEGORY = "general";
const PLUGIN_CLASS = class MyDrawingPlugin extends SDK.IPluginBase {
const PLUGIN_CLASS = class SpineC3Plugin extends SDK.IPluginBase {
static PROP_ATLAS = "spine-atlas-file";
static PROP_SKELETON = "spine-skeleton-file";
static PROP_LOADER_SCALE = "spine-loader-scale";
@ -39,7 +40,7 @@ const PLUGIN_CLASS = class MyDrawingPlugin extends SDK.IPluginBase {
constructor () {
super(PLUGIN_ID);
SDK.Lang.PushContext("plugins." + PLUGIN_ID.toLowerCase());
SDK.Lang.PushContext(`plugins.${PLUGIN_ID.toLowerCase()}`);
// @ts-ignore
this._info.SetName(globalThis.lang(".name"));
@ -65,12 +66,12 @@ const PLUGIN_CLASS = class MyDrawingPlugin extends SDK.IPluginBase {
SDK.Lang.PushContext(".properties");
this._info.SetProperties([
new SDK.PluginProperty("projectfile", MyDrawingPlugin.PROP_ATLAS, ""),
new SDK.PluginProperty("projectfile", MyDrawingPlugin.PROP_SKELETON, ""),
new SDK.PluginProperty("float", MyDrawingPlugin.PROP_LOADER_SCALE, 1),
new SDK.PluginProperty("text", MyDrawingPlugin.PROP_SKIN, ""),
new SDK.PluginProperty("text", MyDrawingPlugin.PROP_ANIMATION, ""),
new SDK.PluginProperty("info", MyDrawingPlugin.PROP_ERRORS, {
new SDK.PluginProperty("projectfile", SpineC3Plugin.PROP_ATLAS, { initialValue: "", filter: ".atlas" }),
new SDK.PluginProperty("projectfile", SpineC3Plugin.PROP_SKELETON, { initialValue: "", filter: ".json,.skel" }),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_LOADER_SCALE, 1),
new SDK.PluginProperty("text", SpineC3Plugin.PROP_SKIN, ""),
new SDK.PluginProperty("text", SpineC3Plugin.PROP_ANIMATION, ""),
new SDK.PluginProperty("info", SpineC3Plugin.PROP_ERRORS, {
infoCallback (inst) {
const errors = (inst.GetInstance() as unknown as { errors: Record<string, string> }).errors;
return Object.values(errors).reduce((acc, next) => {
@ -79,20 +80,20 @@ const PLUGIN_CLASS = class MyDrawingPlugin extends SDK.IPluginBase {
},
}),
new SDK.PluginProperty("group", MyDrawingPlugin.PROP_BOUNDS_PROVIDER_GROUP),
new SDK.PluginProperty("combo", MyDrawingPlugin.PROP_BOUNDS_PROVIDER, {
new SDK.PluginProperty("group", SpineC3Plugin.PROP_BOUNDS_PROVIDER_GROUP),
new SDK.PluginProperty("combo", SpineC3Plugin.PROP_BOUNDS_PROVIDER, {
initialValue: "setup",
items: [
MyDrawingPlugin.TYPE_BOUNDS_SETUP,
MyDrawingPlugin.TYPE_BOUNDS_ANIMATION_SKIN,
SpineC3Plugin.TYPE_BOUNDS_SETUP,
SpineC3Plugin.TYPE_BOUNDS_ANIMATION_SKIN,
],
}),
new SDK.PluginProperty("check", MyDrawingPlugin.PROP_BOUNDS_PROVIDER_MOVE, false),
new SDK.PluginProperty("float", MyDrawingPlugin.PROP_BOUNDS_OFFSET_X, 0),
new SDK.PluginProperty("float", MyDrawingPlugin.PROP_BOUNDS_OFFSET_Y, 0),
new SDK.PluginProperty("float", MyDrawingPlugin.PROP_BOUNDS_OFFSET_ANGLE, 0),
new SDK.PluginProperty("float", MyDrawingPlugin.PROP_SKELETON_SCALE_X, 1),
new SDK.PluginProperty("float", MyDrawingPlugin.PROP_SKELETON_SCALE_Y, 1),
new SDK.PluginProperty("check", SpineC3Plugin.PROP_BOUNDS_PROVIDER_MOVE, false),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_BOUNDS_OFFSET_X, 0),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_BOUNDS_OFFSET_Y, 0),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_BOUNDS_OFFSET_ANGLE, 0),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_SKELETON_SCALE_X, 1),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_SKELETON_SCALE_Y, 1),
]);

View File

@ -3,21 +3,15 @@ const SDK = globalThis.SDK;
const PLUGIN_CLASS = SDK.Plugins.EsotericSoftware_SpineConstruct3;
PLUGIN_CLASS.Type = class MyDrawingPluginType extends SDK.ITypeBase {
PLUGIN_CLASS.Type = class SpineC3PluginType extends SDK.ITypeBase {
spineLogo?: SDK.Gfx.IWebGLTexture;
private spineLogoRequested = false;
constructor (sdkPlugin: SDK.IPluginBase, iObjectType: SDK.IObjectType) {
super(sdkPlugin, iObjectType);
}
getSpineLogo (iRenderer: SDK.Gfx.IWebGLRenderer) {
if (this.spineLogo) return this.spineLogo;
if (this.spineLogoRequested) return undefined;
console.log("UNA VOLTA");
this.spineLogoRequested = true;
const blob = new Blob([Uint8Array.from(atob(spineLogoBase64), char => char.charCodeAt(0))], { type: "image/png" });