@combos-fun/engine 0.0.38 → 0.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- "use strict";var e=require("eventemitter3"),t=require("lodash-es"),s=require("tslib"),r=require("@combos-fun/inspector-decorator"),o=require("resource-loader");function n(e){return e&&e.__esModule?e:{default:e}}var a,i=n(e);class c extends i.default{get game(){return this.gameObject?.scene?.game}constructor(e){super(),this.started=!1;const t=this.constructor;this.name=t.componentName,this.__componentDefaultParams=e}}exports.OBSERVER_TYPE=void 0,(a=exports.OBSERVER_TYPE||(exports.OBSERVER_TYPE={})).ADD="ADD",a.REMOVE="REMOVE",a.CHANGE="CHANGE";const p={},h={},m={},d={};function l(e,t){p[e.gameObject.id]||(p[e.gameObject.id]={});const s=p[e.gameObject.id],r=e.name+"_"+t.join(",");if(s[r])return s[r];const o=t.length-1;let n=e;for(let e=0;e<o;e++){if(void 0===n[t[e]]||null===n[t[e]])return{property:void 0,key:void 0};n=n[t[e]]}return s[r]={property:n,key:t[o]},s[r]}function u({systemName:e,componentName:t,component:s,prop:r,type:o}){h[e]?.componentObserver?.add({component:s,prop:r,type:o,componentName:t})}function y({obj:e,key:s,prop:r,component:o,componentName:n}){if(void 0!==e)if(s in e){if(Object.defineProperty(e,`_${s}`,{enumerable:!1,writable:!0,value:e[s]}),r.deep&&t.isObject(e[s]))for(const t of Object.keys(e[s]))y({obj:e[s],key:t,prop:r,component:o,componentName:n});Object.defineProperty(e,s,{enumerable:!0,set(a){e[`_${s}`]!==a&&(e[`_${s}`]=a,function({prop:e,component:s,componentName:r}){for(const o in m){const n=(m[o]||{})[r];n&&(n.findIndex(s=>t.isEqual(s,e))>-1&&u({systemName:o,componentName:r,component:s,prop:e,type:exports.OBSERVER_TYPE.CHANGE}))}}({prop:r,component:o,componentName:n}))},get:()=>e[`_${s}`]})}else console.error(`prop ${s} not in component: ${n}, Can not observer`)}function f(e,t=e.name){for(const s in m){(m[s]||{})[t]&&h[s]?.componentObserver?.add({component:e,type:exports.OBSERVER_TYPE.REMOVE,componentName:t})}!function(e){e.gameObject&&delete p[e.gameObject.id]}(e)}class g extends c{constructor(){super(...arguments),this.name="Transform",this._parent=null,this.inScene=!1,this.children=[],this.position={x:0,y:0},this.size={width:0,height:0},this.origin={x:0,y:0},this.anchor={x:0,y:0},this.scale={x:1,y:1},this.skew={x:0,y:0},this.rotation=0}static{this.componentName="Transform"}init(e={}){const t=["position","size","origin","anchor","scale","skew"];for(const s of t)Object.assign(this[s],e[s]);this.rotation=e.rotation??this.rotation}set parent(e){e?e.addChild(this):this.parent&&this.parent.removeChild(this)}get parent(){return this._parent}addChild(e){if(e.parent===this){const t=this.children.findIndex(t=>t===e);this.children.splice(t,1)}else e.parent&&e.parent.removeChild(e);e._parent=this,this.children.push(e)}removeChild(e){const t=this.children.findIndex(t=>t===e);t>-1&&(this.children.splice(t,1),e._parent=null)}clearChildren(){this.children.length=0}}s.__decorate([r.Field({type:"vector2",step:1,group:"Transform",label:"Position",description:"Position on the design canvas (x right, y down)."})],g.prototype,"position",void 0),s.__decorate([r.Field({type:"size",step:1,min:0,group:"Transform",label:"Size",description:"Width and height of the object in design pixels."})],g.prototype,"size",void 0),s.__decorate([r.Field({type:"vector2",step:.1,group:"Transform",label:"Origin",description:"Local origin used for layout math."})],g.prototype,"origin",void 0),s.__decorate([r.Field({type:"vector2",step:.1,group:"Transform",label:"Anchor",description:"Anchor point (0–1) used when positioning and scaling."})],g.prototype,"anchor",void 0),s.__decorate([r.Field({type:"vector2",step:.1,group:"Transform",label:"Scale",description:"Scale multipliers on X and Y (1 = original size)."})],g.prototype,"scale",void 0),s.__decorate([r.Field({type:"vector2",step:.1,group:"Transform",label:"Skew",description:"Skew amounts on X and Y."})],g.prototype,"skew",void 0),s.__decorate([r.Field({type:"number",step:.1,group:"Transform",label:"Rotation",description:"Rotation in radians.",editor:"number-stepper"})],g.prototype,"rotation",void 0);let E=0;class _{constructor(e,t){this._componentCache={},this.components=[],this.destroyed=!1,this._name=e,this.id=++E,this.addComponent(g,t)}get transform(){return this.getComponent(g)}get parent(){return this.transform&&this.transform.parent&&this.transform.parent.gameObject}get name(){return this._name}set scene(e){if(this._scene===e)return;const t=this._scene;if(this._scene=e,this.transform&&this.transform.children)for(const t of this.transform.children)t.gameObject.scene=e;e?e.addGameObject(this):t&&t.removeGameObject(this)}get scene(){return this._scene}addChild(e){if(e&&e.transform&&e!==this){if(!(e instanceof _))throw new Error("addChild only receive GameObject");if(!this.transform)throw new Error(`gameObject '${this.name}' has been destroy`);e.transform.parent=this.transform,e.scene=this.scene}}removeChild(e){return e instanceof _&&e.parent&&e.parent===this?(e.transform.parent=null,e.scene=null,e):e}addComponent(e,t){if(this.destroyed)return;const s=function(e){return e instanceof c?e.name:e instanceof Function?e.componentName:void 0}(e);if(this._componentCache[s])return;let r;if(e instanceof Function)r=new e(t);else{if(!(e instanceof c))throw new Error("addComponent recieve Component and Component Constructor");r=e}if(r.gameObject)throw new Error(`component has been added on gameObject ${r.gameObject.name}`);return r.gameObject=this,r.init&&r.init(r.__componentDefaultParams),function(e,t=e.name){for(const s in m)(m[s]||{})[t]&&h[s]?.componentObserver?.add({component:e,type:exports.OBSERVER_TYPE.ADD,componentName:t})}(r,r.name),function(e,t=e.name){if(t&&d[t]){if(!(e&&(s=e,s&&s.constructor&&"componentName"in s.constructor)))throw new Error("component param must be an instance of Component");var s;if(!e.gameObject||!e.gameObject.id)throw new Error("component should be add to a gameObject");for(const s of d[t]){const{property:r,key:o}=l(e,s.prop);y({obj:r,key:o,prop:s,component:e,componentName:t})}}}(r,r.name),this.components.push(r),this._componentCache[s]=r,r.awake&&r.awake(),r}removeComponent(e){let t;if("string"==typeof e?t=e:e instanceof c?t=e.name:e.componentName&&(t=e.componentName),"Transform"===t)throw new Error("Transform can't be removed");return this._removeComponent(t)}_removeComponent(e){const t=this.components.findIndex(({name:t})=>t===e);if(-1===t)return;const s=this.components.splice(t,1)[0];return delete this._componentCache[e],delete s.__componentDefaultParams,s.onDestroy&&s.onDestroy(),f(s,e),s.gameObject=void 0,s}getComponent(e){let t;return"string"==typeof e?t=e:e instanceof c?t=e.name:e.componentName&&(t=e.componentName),void 0!==this._componentCache[t]?this._componentCache[t]:void 0}remove(){if(this.parent)return this.parent.removeChild(this)}destroy(){if(this.transform){Array.from(this.transform.children).forEach(({gameObject:e})=>{e.destroy()}),this.remove(),this.transform.clearChildren();for(const e in this._componentCache)this._removeComponent(e);this.components.length=0,this.destroyed=!0}else console.error("Cannot destroy gameObject that have already been destroyed.")}}class b{constructor(){this.events=[]}add({component:e,prop:s,type:r,componentName:o}){if(r===exports.OBSERVER_TYPE.REMOVE){if(this.events.find(t=>t.component===e&&t.type===exports.OBSERVER_TYPE.ADD))return void(this.events=this.events.filter(t=>t.component!==e));this.events=this.events.filter(t=>t.component!==e)}const n=this.events.findIndex(o=>o.component===e&&t.isEqual(o.prop,s)&&o.type===r);n>-1&&this.events.splice(n,1),this.events.push({gameObject:e.gameObject,component:e,prop:s,type:r,componentName:o})}getChanged(){return this.events}get changed(){return this.events}clear(){const e=this.events;return this.events=[],e}}class T{constructor(e){this.started=!1,this.componentObserver=new b,this.__systemDefaultParams=e;const t=this.constructor;this.name=t.systemName}destroy(){this.componentObserver=null,this.__systemDefaultParams=null,this.onDestroy?.()}}const S=function(){let e=null;return e=Date.now?Date.now:()=>(new Date).getTime(),e}(),O={originTime:0,playbackRate:1};class R{constructor(e,t){e instanceof R&&(t=e,e={}),e=Object.assign({},O,e),t&&(this._parent=t),this._createTime=S(),this._timeMark=[{globalTime:this.globalTime,localTime:-e.originTime,entropy:-e.originTime,playbackRate:e.playbackRate,globalEntropy:0}],this._parent&&(this._timeMark[0].globalEntropy=this._parent.entropy),this._playbackRate=e.playbackRate}get globalTime(){return this.parent?this.parent.currentTime:S()-this._createTime}get parent(){return this._parent}get lastTimeMark(){return this._timeMark[this._timeMark.length-1]}markTime({time:e=this.currentTime,entropy:t=this.entropy,playbackRate:s=this.playbackRate}={}){const r={globalTime:this.globalTime,localTime:e,entropy:t,playbackRate:s,globalEntropy:this.globalEntropy};this._timeMark.push(r)}get currentTime(){const{localTime:e,globalTime:t}=this.lastTimeMark;return e+(this.globalTime-t)*this.playbackRate}set currentTime(e){this.markTime({time:e})}get globalEntropy(){return this._parent?this._parent.entropy:this.globalTime}get entropy(){const{entropy:e,globalEntropy:t}=this.lastTimeMark;return e+Math.abs((this.globalEntropy-t)*this.playbackRate)}set entropy(e){if(this.entropy>e){const t=this.seekTimeMark(e);this._timeMark.length=t+1}this.markTime({entropy:e})}fork(e){return new R(e,this)}seekGlobalTime(e){const t=this.seekTimeMark(e),s=this._timeMark[t],{entropy:r,playbackRate:o,globalTime:n}=s;return n+(e-r)/Math.abs(o)}seekLocalTime(e){const t=this.seekTimeMark(e),s=this._timeMark[t],{localTime:r,entropy:o,playbackRate:n}=s;return n>0?r+(e-o):r-(e-o)}seekTimeMark(e){const t=this._timeMark;let s=0,r=t.length-1;if(e<=t[s].entropy)return s;if(e>=t[r].entropy)return r;let o=Math.floor((s+r)/2);for(;o>s&&o<r;){if(e===t[o].entropy)return o;e<t[o].entropy?r=o:e>t[o].entropy&&(s=o),o=Math.floor((s+r)/2)}return s}get playbackRate(){return this._playbackRate}set playbackRate(e){e!==this.playbackRate&&(this.markTime({playbackRate:e}),this._playbackRate=e)}get paused(){if(0===this.playbackRate)return!0;let e=this.parent;for(;e;){if(0===e.playbackRate)return!0;e=e.parent}return!1}}const k={autoStart:!0,frameRate:60};class v{constructor(e){e=Object.assign({},k,e),this._frameCount=0,this._frameDuration=1e3/e.frameRate,this.autoStart=e.autoStart,this.frameRate=e.frameRate,this.timeline=new R({originTime:0,playbackRate:1}),this._lastFrameTime=this.timeline.currentTime,this._tickers=new Set,this._requestId=null,this._ticker=()=>{this._started&&(this._requestId=requestAnimationFrame(this._ticker),this.update())},this.autoStart&&this.start()}update(){const e=this.timeline.currentTime,t=e-this._lastFrameTime;if(t>=this._frameDuration){const s=e-t%this._frameDuration,r=s-this._lastFrameTime;this._lastFrameTime=s;const o={deltaTime:r,delta:r,time:s,currentTime:s,frameCount:++this._frameCount,fps:Math.round(1e3/r)};for(const e of this._tickers)"function"==typeof e&&e(o)}}add(e){this._tickers.add(e)}remove(e){this._tickers.delete(e)}start(){this._started||(this._started=!0,this.timeline.playbackRate=1,this._requestId=requestAnimationFrame(this._ticker))}pause(){this._started=!1,this.timeline.playbackRate=0}setPlaybackRate(e){this.timeline.playbackRate=e}}class w extends _{constructor(e,t){super(e,t),this.gameObjects=[],this.scene=this}addGameObject(e){this.gameObjects.push(e),e.transform&&(e.transform.inScene=!0)}removeGameObject(e){const t=this.gameObjects.indexOf(e);-1!==t&&(e.transform&&(e.transform.inScene=!1),this.gameObjects.splice(t,1))}destroy(){this.scene=null,super.destroy(),this.gameObjects=null,this.canvas=null}}const L="0.0.38",M="combos-game:plugin-init-success",x="combos-game:ready",C="combos-game:set-playing",N="combos-game:state-changed";function A(e,t){if("undefined"!=typeof window&&window.parent&&window.parent!==window)try{window.parent.postMessage(e,t)}catch{}}function P(e,t="*"){A({type:M,systemName:e.systemName,engineVersion:L,...e.packageName?{packageName:e.packageName}:{},...e.packageVersion?{packageVersion:e.packageVersion}:{}},t)}function I(e,t="*"){A({type:x,engineVersion:L,...void 0===e?{}:{error:e instanceof Error?e.message:String(e)}},t)}function D(e,t="*"){A({type:N,playing:e.playing,started:e.started},t)}function j(e){if(!e||"object"!=typeof e)return null;const t=e;return t.type!==C||"boolean"!=typeof t.playing?null:t.playing}const X=["knoffice.tech","converge.ai"];function V(e,t){if(t.includes("*"))return!0;if(0===t.length)return!1;let s;try{s=new URL(e)}catch{return!1}const r=e.toLowerCase(),o=s.hostname.toLowerCase();for(const e of t){const t=e.trim();if(!t)continue;if(t.includes("://")){if(r===t.toLowerCase())return!0;continue}const s=t.toLowerCase().replace(/^\./,"");if(o===s||o.endsWith(`.${s}`))return!0}return!1}function G(e){if(!e?.length)return[...X];if(e.includes("*"))return["*"];const t=new Set,s=[];for(const r of[...X,...e]){const e=r.trim();e&&!t.has(e)&&(t.add(e),s.push(e))}return s}function $(e){if("systemName"in e){const t=e.systemName;if("string"==typeof t)return t}return"UnknownSystem"}function F(e){const t=e;return{packageName:"string"==typeof t.packageName?t.packageName:void 0,packageVersion:"string"==typeof t.packageVersion?t.packageVersion:void 0}}var U;exports.LOAD_SCENE_MODE=void 0,(U=exports.LOAD_SCENE_MODE||(exports.LOAD_SCENE_MODE={})).SINGLE="SINGLE",U.MULTI_CANVAS="MULTI_CANVAS";const B=e=>{if((e instanceof T||e instanceof c)&&!e.started){e.started=!0;try{e.start&&e.start()}catch(t){e instanceof c?console.error(`${function(e){if("componentName"in e){const t=e.componentName;if("string"==typeof t)return t}return"UnknownComponent"}(e.constructor)} start error`,t):console.error(`${$(e.constructor)} start error`,t)}}};class Y extends i.default{constructor({systems:e,frameRate:t=60,autoStart:s=!0,needScene:r=!0,onSystemsBootstrapComplete:o,pluginInitNotifyTargetOrigin:n="*",allowedMessageOrigins:a}={}){if(super(),this.playing=!1,this.started=!1,this.multiScenes=[],this.systems=[],this.pluginInitNotifyTargetOrigin="*",this.allowedMessageOrigins=G(),this.onHostMessage=e=>{if(!V(e.origin,this.allowedMessageOrigins))return;const t=j(e.data);null!==t&&this.setPlaying(t)},this.pluginInitNotifyTargetOrigin=n,this.allowedMessageOrigins=G(a),this.ticker=new v({autoStart:!1,frameRate:t}),this.initTicker(),"undefined"!=typeof window&&window.addEventListener("message",this.onHostMessage),e&&e.length){const t=[...e];this.bootstrapSystemsAndMaybeStart(t,r,s,o)}else o?.(this),this.notifyReady()}setPlaying(e){e?this.started?this.resume():this.start():this.pause()}notifyReady(e){I(e,this.pluginInitNotifyTargetOrigin)}notifyStateChanged(){D({playing:this.playing,started:this.started},this.pluginInitNotifyTargetOrigin)}async bootstrapSystemsAndMaybeStart(e,t,s,r){let o;try{for(const t of e)await this.addSystem(t);t&&this.loadScene({scene:new w("scene")}),s&&this.start()}catch(e){o=e,console.error("Game bootstrap failed",e)}finally{r?.(this,o),this.notifyReady(o)}}get scene(){return this._scene}set scene(e){this._scene=e}get gameObjects(){return(e=>{const t=e?.scene?.gameObjects||[],s=e?.multiScenes.map(({gameObjects:e})=>e);let r=[];for(const e of s)r=[...r,...e];return[...t,...r]})(this)}async addSystem(e,s){let r;if(e instanceof Function)r=new e(s);else{if(!(e instanceof T))return void console.warn("can only add System");r=e}if(!this.systems.find(e=>e.constructor===r.constructor)){r.game=this,r.init&&await Promise.resolve(r.init(r.__systemDefaultParams)),P({systemName:$(r.constructor),...F(r.constructor)},this.pluginInitNotifyTargetOrigin),function(e,t){m[t.systemName]=t.observerInfo,h[t.systemName]=e}(r,r.constructor),function(e){const s=[];e instanceof Array?s.push(...e):s.push(e);for(const e of s)for(const s in e.observerInfo){d[s]=d[s]||[];const r=d[s];for(const o of e.observerInfo[s])-1===r.findIndex(e=>t.isEqual(e,o))&&d[s].push(o)}}(r.constructor);try{r.awake&&r.awake()}catch(e){console.error(`${$(r.constructor)} awake error`,e)}return this.systems.push(r),r}console.warn(`${$(r.constructor)} System has been added`)}removeSystem(e){if(!e)return;let t=-1;"string"==typeof e?t=this.systems.findIndex(t=>t.name===e):e instanceof Function?t=this.systems.findIndex(t=>t.constructor===e):e instanceof T&&(t=this.systems.findIndex(t=>t===e)),t>-1&&(this.systems[t].destroy&&this.systems[t].destroy(),this.systems.splice(t,1))}getSystem(e){return this.systems.find(t=>"string"==typeof e?t.name===e:t instanceof e)}pause(){this.playing&&(this.playing=!1,this.ticker.pause(),this.triggerPause(),this.notifyStateChanged())}start(){this.playing||(this.playing=!0,this.started=!0,this.ticker.start(),this.notifyStateChanged())}resume(){this.playing||(this.playing=!0,this.ticker.start(),this.triggerResume(),this.notifyStateChanged())}initTicker(){this.ticker.add(e=>{this.scene&&((e,t=[])=>{for(const s of t)for(const t of s.components)try{B(t),t.update&&t.update(e)}catch(e){console.error(`gameObject: ${s.name} ${t.name} update error`,e)}for(const s of t)for(const t of s.components)try{t.lateUpdate&&t.lateUpdate(e)}catch(e){console.error(`gameObject: ${s.name} ${t.name} lateUpdate error`,e)}})(e,this.gameObjects);for(const t of this.systems)try{B(t),t.update&&t.update(e)}catch(e){console.error(`${$(t.constructor)} update error`,e)}for(const t of this.systems)try{t.lateUpdate&&t.lateUpdate(e)}catch(e){console.error(`${$(t.constructor)} lateUpdate error`,e)}})}triggerResume(){(e=>{for(const t of e)for(const e of t.components)try{e.onResume&&e.onResume()}catch(s){console.error(`gameObject: ${t.name}, ${e.name}, onResume error`,s)}})(this.gameObjects);for(const e of this.systems)try{e.onResume&&e.onResume()}catch(t){console.error(`${$(e.constructor)}, onResume error`,t)}}triggerPause(){(e=>{for(const t of e)for(const e of t.components)try{e.onPause&&e.onPause()}catch(s){console.error(`gameObject: ${t.name}, ${e.name}, onPause error`,s)}})(this.gameObjects);for(const e of this.systems)try{e.onPause&&e.onPause()}catch(t){console.error(`${$(e.constructor)}, onPause error`,t)}}destroySystems(){for(const e of[...this.systems])this.removeSystem(e);this.systems.length=0}destroy(){"undefined"!=typeof window&&window.removeEventListener("message",this.onHostMessage),this.removeAllListeners(),this.pause(),this.scene.destroy(),this.destroySystems(),this.ticker=null,this.scene=null,this.canvas=null,this.multiScenes=null}loadScene({scene:e,mode:t=exports.LOAD_SCENE_MODE.SINGLE,params:s={}}){if(e){switch(e.game=this,t){case exports.LOAD_SCENE_MODE.SINGLE:this.scene=e;break;case exports.LOAD_SCENE_MODE.MULTI_CANVAS:this.multiScenes.push(e)}this.emit("sceneChanged",{scene:e,mode:t,params:s})}}}function H(e,t){e.constructor.IDEProps||(e.constructor.IDEProps=[]),e.constructor.IDEProps.push(t)}function q(e={}){return function(t){if(!t.observerInfo){for(const t in e)for(const s in e[t]){let r;"string"==typeof e[t][s]&&(e[t][s]=[e[t][s]]),Array.isArray(e[t][s])&&(r={prop:e[t][s],deep:!1},e[t][s]=r),r=e[t][s],"string"==typeof r.prop&&(r.prop=[r.prop])}t.observerInfo=e}}}var z;exports.LOAD_EVENT=void 0,(z=exports.LOAD_EVENT||(exports.LOAD_EVENT={})).START="start",z.PROGRESS="progress",z.LOADED="loaded",z.COMPLETE="complete",z.ERROR="error";class J extends i.default{constructor({resource:e,resourceTotal:t}){super(),this.progress=0,this.resourceTotal=0,this.resourceLoadedCount=0,this.resource=e,this.resourceTotal=t,0===t&&this.resource.emit(exports.LOAD_EVENT.COMPLETE,this)}onStart(){this.resource.emit(exports.LOAD_EVENT.START,this)}onProgress(e){this.resourceLoadedCount++,this.progress=Math.floor(this.resourceLoadedCount/this.resourceTotal*100)/100,e.success?this.resource.emit(exports.LOAD_EVENT.LOADED,this,e):this.resource.emit(exports.LOAD_EVENT.ERROR,this,e),this.resource.emit(exports.LOAD_EVENT.PROGRESS,this,e),this.resourceLoadedCount===this.resourceTotal&&this.resource.emit(exports.LOAD_EVENT.COMPLETE,this)}}const W={AbstractLoadStrategy:o.AbstractLoadStrategy,AudioLoadStrategy:o.AudioLoadStrategy,ImageLoadStrategy:o.ImageLoadStrategy,XhrResponseType:o.XhrResponseType,MediaElementLoadStrategy:o.MediaElementLoadStrategy,VideoLoadStrategy:o.VideoLoadStrategy,XhrLoadStrategy:o.XhrLoadStrategy,Loader:o.Loader,Resource:o.Resource,ResourceType:o.ResourceType,ResourceState:o.ResourceState};var K;exports.RESOURCE_TYPE=void 0,(K=exports.RESOURCE_TYPE||(exports.RESOURCE_TYPE={})).IMAGE="IMAGE",K.SPRITE="SPRITE",K.SPRITE_ANIMATION="SPRITE_ANIMATION",K.AUDIO="AUDIO",K.VIDEO="VIDEO",K.GLB="GLB",o.XhrLoadStrategy.setExtensionXhrType("json",o.XhrResponseType.Json),o.XhrLoadStrategy.setExtensionXhrType("tex",o.XhrResponseType.Json),o.XhrLoadStrategy.setExtensionXhrType("ske",o.XhrResponseType.Json),o.XhrLoadStrategy.setExtensionXhrType("mp3",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("wav",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("aac",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("ogg",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("glb",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("gltf",o.XhrResponseType.Json);const Q={png:o.ImageLoadStrategy,jpg:o.ImageLoadStrategy,jpeg:o.ImageLoadStrategy,webp:o.ImageLoadStrategy,json:o.XhrLoadStrategy,tex:o.XhrLoadStrategy,ske:o.XhrLoadStrategy,audio:o.XhrLoadStrategy,video:o.VideoLoadStrategy,glb:o.XhrLoadStrategy,gltf:o.XhrLoadStrategy};class Z extends i.default{constructor(e){super(),this.timeout=6e3,this.preProcessResourceHandlers=[],this.resourcesMap={},this.makeInstanceFunctions={},this.destroyInstanceFunctions={},this.promiseMap={},this.loaders=[],e&&"number"==typeof e.timeout&&(this.timeout=e.timeout)}loadConfig(e){this.addResource(e),this.preload()}loadSingle(e){return this.addResource([e]),this.getResource(e.name)}addResource(e){if(!e||e.length<1)console.warn("no resources");else for(const t of e)this.resourcesMap[t.name]?console.warn(t.name+" was already added"):(this.resourcesMap[t.name]=t,this.resourcesMap[t.name].data={})}addPreProcessResourceHandler(e){this.preProcessResourceHandlers.push(e)}removePreProcessResourceHandler(e){this.preProcessResourceHandlers.splice(this.preProcessResourceHandlers.indexOf(e),1)}preload(){const e=[];for(const t in this.resourcesMap){const s=this.resourcesMap[t];!s.preload||s.complete||this.promiseMap[t]||e.push(s.name)}this.progress=new J({resource:this,resourceTotal:e.length}),this.loadResource({names:e,preload:!0})}async getResource(e){return this.loadResource({names:[e]}),this.promiseMap[e]||Promise.resolve({})}async instance(e){const t=this.resourcesMap[e];return this.makeInstanceFunctions[t.type]&&await this.makeInstanceFunctions[t.type](t)}async destroy(e){await this._destroy(e)}async _destroy(e,t=!1){const s=this.resourcesMap[e];if(s){if(!t)try{this.destroyInstanceFunctions[s.type]&&await this.destroyInstanceFunctions[s.type](s)}catch(e){console.warn(`destroy resource ${s.name} error with '${e.message}'`)}delete this.promiseMap[e],s.data={},s.complete=!1,s.instance=void 0}}registerResourceType(e,t=e){if(exports.RESOURCE_TYPE[e])throw new Error(`The type ${e} already exists in RESOURCE_TYPE`);exports.RESOURCE_TYPE[e]=t}registerInstance(e,t){this.makeInstanceFunctions[e]=t}registerDestroy(e,t){this.destroyInstanceFunctions[e]=t}loadResource({names:e=[],preload:t=!1}){const s=e.filter(e=>!this.promiseMap[e]&&this.resourcesMap[e]);if(!s.length)return;const r={},o=this.getLoader(t);s.forEach(e=>{this.promiseMap[e]=new Promise(t=>r[e]=t);const s=this.resourcesMap[e];for(const e of this.preProcessResourceHandlers)e(s);for(const n in s.src){const a=s.src[n].type;"data"===a?(s.data[n]=s.src[n].data,this.doComplete(e,r[e],t)):o.add({url:s.src[n].url,name:`${s.name}_${n}`,strategy:Q[a],metadata:{key:n,name:s.name,resolves:r}})}}),o.load()}async doComplete(e,t,s=!1){const r=this.resourcesMap[e],o={name:e,resource:this.resourcesMap[e],success:!0};if(this.checkAllLoaded(e))try{r.instance=await this.instance(e),r.complete=!0,s&&this.progress.onProgress(o),t(r)}catch(e){console.error(e),r.complete=!1,s&&(o.errMsg=e.message,o.success=!1,this.progress.onProgress(o)),t({})}}checkAllLoaded(e){const t=this.resourcesMap[e];return Array.from(Object.keys(t.src)).every(e=>t.data[e])}getLoader(e=!1){let t=this.loaders.find(({loading:e})=>!e);return t||(t=new o.Loader,this.loaders.push(t)),e&&t.onStart.once(()=>{this.progress.onStart()}),t.onLoad.add((t,s)=>{this.onLoad({preload:e,resource:s})}),t.onError.add((t,s,r)=>{this.onError({errMsg:t,resource:r,preload:e})}),t.onComplete.once(()=>{t.onLoad.detachAll(),t.onError.detachAll(),t.reset()}),t}async onLoad({preload:e=!1,resource:t}){const{metadata:{key:s,name:r,resolves:o},data:n}=t;this.resourcesMap[r].data[s]=n,this.doComplete(r,o[r],e)}async onError({errMsg:e,preload:t=!1,resource:s}){const{metadata:{name:r,resolves:o}}=s;if(this._destroy(r,!0),o[r]({}),t){const t={name:r,resource:this.resourcesMap[r],success:!1,errMsg:e};this.progress.onProgress(t)}}}const ee=new Z,te={IDEProp:H,componentObserver:q};console.log(`@combos-fun/engine version: ${L}`),exports.COMBOS_GAME_PLUGIN_INIT_SUCCESS=M,exports.COMBOS_GAME_READY=x,exports.COMBOS_GAME_SET_PLAYING=C,exports.COMBOS_GAME_STATE_CHANGED=N,exports.Component=c,exports.DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES=X,exports.Game=Y,exports.GameObject=_,exports.IDEProp=H,exports.RESOURCE_TYPE_STRATEGY=Q,exports.Scene=w,exports.System=T,exports.Transform=g,exports.componentObserver=q,exports.decorators=te,exports.isAllowedMessageOrigin=V,exports.mergeAllowedMessageOrigins=G,exports.parseSetPlayingMessage=j,exports.postParentGameReady=I,exports.postParentGameState=D,exports.postParentPluginInitSuccess=P,exports.resource=ee,exports.resourceLoader=W,exports.version=L;
1
+ "use strict";var e=require("eventemitter3"),t=require("lodash-es"),s=require("tslib"),r=require("@combos-fun/inspector-decorator"),o=require("resource-loader");function n(e){return e&&e.__esModule?e:{default:e}}var a,i=n(e);class c extends i.default{get game(){return this.gameObject?.scene?.game}constructor(e){super(),this.started=!1;const t=this.constructor;this.name=t.componentName,this.__componentDefaultParams=e}}exports.OBSERVER_TYPE=void 0,(a=exports.OBSERVER_TYPE||(exports.OBSERVER_TYPE={})).ADD="ADD",a.REMOVE="REMOVE",a.CHANGE="CHANGE";const p={},m={},h={},l={};function d(e,t){p[e.gameObject.id]||(p[e.gameObject.id]={});const s=p[e.gameObject.id],r=e.name+"_"+t.join(",");if(s[r])return s[r];const o=t.length-1;let n=e;for(let e=0;e<o;e++){if(void 0===n[t[e]]||null===n[t[e]])return{property:void 0,key:void 0};n=n[t[e]]}return s[r]={property:n,key:t[o]},s[r]}function u({systemName:e,componentName:t,component:s,prop:r,type:o}){m[e]?.componentObserver?.add({component:s,prop:r,type:o,componentName:t})}function f({obj:e,key:s,prop:r,component:o,componentName:n}){if(void 0!==e)if(s in e){if(Object.defineProperty(e,`_${s}`,{enumerable:!1,writable:!0,value:e[s]}),r.deep&&t.isObject(e[s]))for(const t of Object.keys(e[s]))f({obj:e[s],key:t,prop:r,component:o,componentName:n});Object.defineProperty(e,s,{enumerable:!0,set(a){e[`_${s}`]!==a&&(e[`_${s}`]=a,function({prop:e,component:s,componentName:r}){for(const o in h){const n=(h[o]||{})[r];n&&(n.findIndex(s=>t.isEqual(s,e))>-1&&u({systemName:o,componentName:r,component:s,prop:e,type:exports.OBSERVER_TYPE.CHANGE}))}}({prop:r,component:o,componentName:n}))},get:()=>e[`_${s}`]})}else console.error(`prop ${s} not in component: ${n}, Can not observer`)}function y(e,t=e.name){for(const s in h){(h[s]||{})[t]&&m[s]?.componentObserver?.add({component:e,type:exports.OBSERVER_TYPE.REMOVE,componentName:t})}!function(e){e.gameObject&&delete p[e.gameObject.id]}(e)}class g extends c{constructor(){super(...arguments),this.name="Transform",this._parent=null,this.inScene=!1,this.children=[],this.position={x:0,y:0},this.size={width:0,height:0},this.origin={x:0,y:0},this.anchor={x:0,y:0},this.scale={x:1,y:1},this.skew={x:0,y:0},this.rotation=0}static{this.componentName="Transform"}init(e={}){const t=["position","size","origin","anchor","scale","skew"];for(const s of t)Object.assign(this[s],e[s]);this.rotation=e.rotation??this.rotation}set parent(e){e?e.addChild(this):this.parent&&this.parent.removeChild(this)}get parent(){return this._parent}addChild(e){if(e.parent===this){const t=this.children.findIndex(t=>t===e);this.children.splice(t,1)}else e.parent&&e.parent.removeChild(e);e._parent=this,this.children.push(e)}removeChild(e){const t=this.children.findIndex(t=>t===e);t>-1&&(this.children.splice(t,1),e._parent=null)}clearChildren(){this.children.length=0}}s.__decorate([r.Field({type:"vector2",step:1,group:"Transform",label:"Position",description:"Position on the design canvas (x right, y down)."})],g.prototype,"position",void 0),s.__decorate([r.Field({type:"size",step:1,min:0,group:"Transform",label:"Size",description:"Width and height of the object in design pixels."})],g.prototype,"size",void 0),s.__decorate([r.Field({type:"vector2",step:.1,group:"Transform",label:"Origin",description:"Local origin used for layout math."})],g.prototype,"origin",void 0),s.__decorate([r.Field({type:"vector2",step:.1,group:"Transform",label:"Anchor",description:"Anchor point (0–1) used when positioning and scaling."})],g.prototype,"anchor",void 0),s.__decorate([r.Field({type:"vector2",step:.1,group:"Transform",label:"Scale",description:"Scale multipliers on X and Y (1 = original size)."})],g.prototype,"scale",void 0),s.__decorate([r.Field({type:"vector2",step:.1,group:"Transform",label:"Skew",description:"Skew amounts on X and Y."})],g.prototype,"skew",void 0),s.__decorate([r.Field({type:"number",step:.1,group:"Transform",label:"Rotation",description:"Rotation in radians.",editor:"number-stepper"})],g.prototype,"rotation",void 0);let E=0;class b{constructor(e,t){this._componentCache={},this.components=[],this.destroyed=!1,this._name=e,this.id=++E,this.addComponent(g,t)}get transform(){return this.getComponent(g)}get parent(){return this.transform&&this.transform.parent&&this.transform.parent.gameObject}get name(){return this._name}set scene(e){if(this._scene===e)return;const t=this._scene;if(this._scene=e,this.transform&&this.transform.children)for(const t of this.transform.children)t.gameObject.scene=e;e?e.addGameObject(this):t&&t.removeGameObject(this)}get scene(){return this._scene}addChild(e){if(e&&e.transform&&e!==this){if(!(e instanceof b))throw new Error("addChild only receive GameObject");if(!this.transform)throw new Error(`gameObject '${this.name}' has been destroy`);e.transform.parent=this.transform,e.scene=this.scene}}removeChild(e){return e instanceof b&&e.parent&&e.parent===this?(e.transform.parent=null,e.scene=null,e):e}addComponent(e,t){if(this.destroyed)return;const s=function(e){return e instanceof c?e.name:e instanceof Function?e.componentName:void 0}(e);if(this._componentCache[s])return;let r;if(e instanceof Function)r=new e(t);else{if(!(e instanceof c))throw new Error("addComponent recieve Component and Component Constructor");r=e}if(r.gameObject)throw new Error(`component has been added on gameObject ${r.gameObject.name}`);return r.gameObject=this,r.init&&r.init(r.__componentDefaultParams),function(e,t=e.name){for(const s in h)(h[s]||{})[t]&&m[s]?.componentObserver?.add({component:e,type:exports.OBSERVER_TYPE.ADD,componentName:t})}(r,r.name),function(e,t=e.name){if(t&&l[t]){if(!(e&&(s=e,s&&s.constructor&&"componentName"in s.constructor)))throw new Error("component param must be an instance of Component");var s;if(!e.gameObject||!e.gameObject.id)throw new Error("component should be add to a gameObject");for(const s of l[t]){const{property:r,key:o}=d(e,s.prop);f({obj:r,key:o,prop:s,component:e,componentName:t})}}}(r,r.name),this.components.push(r),this._componentCache[s]=r,r.awake&&r.awake(),r}removeComponent(e){let t;if("string"==typeof e?t=e:e instanceof c?t=e.name:e.componentName&&(t=e.componentName),"Transform"===t)throw new Error("Transform can't be removed");return this._removeComponent(t)}_removeComponent(e){const t=this.components.findIndex(({name:t})=>t===e);if(-1===t)return;const s=this.components.splice(t,1)[0];return delete this._componentCache[e],delete s.__componentDefaultParams,s.onDestroy&&s.onDestroy(),y(s,e),s.gameObject=void 0,s}getComponent(e){let t;return"string"==typeof e?t=e:e instanceof c?t=e.name:e.componentName&&(t=e.componentName),void 0!==this._componentCache[t]?this._componentCache[t]:void 0}remove(){if(this.parent)return this.parent.removeChild(this)}destroy(){if(this.transform){Array.from(this.transform.children).forEach(({gameObject:e})=>{e.destroy()}),this.remove(),this.transform.clearChildren();for(const e in this._componentCache)this._removeComponent(e);this.components.length=0,this.destroyed=!0}else console.error("Cannot destroy gameObject that have already been destroyed.")}}class S{constructor(){this.events=[]}add({component:e,prop:s,type:r,componentName:o}){if(r===exports.OBSERVER_TYPE.REMOVE){if(this.events.find(t=>t.component===e&&t.type===exports.OBSERVER_TYPE.ADD))return void(this.events=this.events.filter(t=>t.component!==e));this.events=this.events.filter(t=>t.component!==e)}const n=this.events.findIndex(o=>o.component===e&&t.isEqual(o.prop,s)&&o.type===r);n>-1&&this.events.splice(n,1),this.events.push({gameObject:e.gameObject,component:e,prop:s,type:r,componentName:o})}getChanged(){return this.events}get changed(){return this.events}clear(){const e=this.events;return this.events=[],e}}class T{constructor(e){this.started=!1,this.componentObserver=new S,this.__systemDefaultParams=e;const t=this.constructor;this.name=t.systemName}destroy(){this.componentObserver=null,this.__systemDefaultParams=null,this.onDestroy?.()}}const _=function(){let e=null;return e=Date.now?Date.now:()=>(new Date).getTime(),e}(),O={originTime:0,playbackRate:1};class R{constructor(e,t){e instanceof R&&(t=e,e={}),e=Object.assign({},O,e),t&&(this._parent=t),this._createTime=_(),this._timeMark=[{globalTime:this.globalTime,localTime:-e.originTime,entropy:-e.originTime,playbackRate:e.playbackRate,globalEntropy:0}],this._parent&&(this._timeMark[0].globalEntropy=this._parent.entropy),this._playbackRate=e.playbackRate}get globalTime(){return this.parent?this.parent.currentTime:_()-this._createTime}get parent(){return this._parent}get lastTimeMark(){return this._timeMark[this._timeMark.length-1]}markTime({time:e=this.currentTime,entropy:t=this.entropy,playbackRate:s=this.playbackRate}={}){const r={globalTime:this.globalTime,localTime:e,entropy:t,playbackRate:s,globalEntropy:this.globalEntropy};this._timeMark.push(r)}get currentTime(){const{localTime:e,globalTime:t}=this.lastTimeMark;return e+(this.globalTime-t)*this.playbackRate}set currentTime(e){this.markTime({time:e})}get globalEntropy(){return this._parent?this._parent.entropy:this.globalTime}get entropy(){const{entropy:e,globalEntropy:t}=this.lastTimeMark;return e+Math.abs((this.globalEntropy-t)*this.playbackRate)}set entropy(e){if(this.entropy>e){const t=this.seekTimeMark(e);this._timeMark.length=t+1}this.markTime({entropy:e})}fork(e){return new R(e,this)}seekGlobalTime(e){const t=this.seekTimeMark(e),s=this._timeMark[t],{entropy:r,playbackRate:o,globalTime:n}=s;return n+(e-r)/Math.abs(o)}seekLocalTime(e){const t=this.seekTimeMark(e),s=this._timeMark[t],{localTime:r,entropy:o,playbackRate:n}=s;return n>0?r+(e-o):r-(e-o)}seekTimeMark(e){const t=this._timeMark;let s=0,r=t.length-1;if(e<=t[s].entropy)return s;if(e>=t[r].entropy)return r;let o=Math.floor((s+r)/2);for(;o>s&&o<r;){if(e===t[o].entropy)return o;e<t[o].entropy?r=o:e>t[o].entropy&&(s=o),o=Math.floor((s+r)/2)}return s}get playbackRate(){return this._playbackRate}set playbackRate(e){e!==this.playbackRate&&(this.markTime({playbackRate:e}),this._playbackRate=e)}get paused(){if(0===this.playbackRate)return!0;let e=this.parent;for(;e;){if(0===e.playbackRate)return!0;e=e.parent}return!1}}const k={autoStart:!0,frameRate:60};class x{constructor(e){e=Object.assign({},k,e),this._frameCount=0,this._frameDuration=1e3/e.frameRate,this.autoStart=e.autoStart,this.frameRate=e.frameRate,this.timeline=new R({originTime:0,playbackRate:1}),this._lastFrameTime=this.timeline.currentTime,this._tickers=new Set,this._requestId=null,this._ticker=()=>{this._started&&(this._requestId=requestAnimationFrame(this._ticker),this.update())},this.autoStart&&this.start()}update(){const e=this.timeline.currentTime,t=e-this._lastFrameTime;if(t>=this._frameDuration){const s=e-t%this._frameDuration,r=s-this._lastFrameTime;this._lastFrameTime=s;const o={deltaTime:r,delta:r,time:s,currentTime:s,frameCount:++this._frameCount,fps:Math.round(1e3/r)};for(const e of this._tickers)"function"==typeof e&&e(o)}}add(e){this._tickers.add(e)}remove(e){this._tickers.delete(e)}start(){this._started||(this._started=!0,this.timeline.playbackRate=1,this._requestId=requestAnimationFrame(this._ticker))}pause(){this._started=!1,this.timeline.playbackRate=0}setPlaybackRate(e){this.timeline.playbackRate=e}}class w extends b{constructor(e,t){super(e,t),this.gameObjects=[],this.scene=this}addGameObject(e){this.gameObjects.push(e),e.transform&&(e.transform.inScene=!0)}removeGameObject(e){const t=this.gameObjects.indexOf(e);-1!==t&&(e.transform&&(e.transform.inScene=!1),this.gameObjects.splice(t,1))}destroy(){this.scene=null,super.destroy(),this.gameObjects=null,this.canvas=null}}const L="0.0.40",v="combos-game:plugin-init-success",M="combos-game:ready",A="combos-game:set-playing",C="combos-game:state-changed";function j(e,t){if("undefined"!=typeof window&&window.parent&&window.parent!==window)try{window.parent.postMessage(e,t)}catch{}}function N(e,t="*"){j({type:v,systemName:e.systemName,engineVersion:L,...e.packageName?{packageName:e.packageName}:{},...e.packageVersion?{packageVersion:e.packageVersion}:{}},t)}function I(e,t="*"){j({type:M,engineVersion:L,...void 0===e?{}:{error:e instanceof Error?e.message:String(e)}},t)}function P(e,t="*"){j({type:C,playing:e.playing,started:e.started},t)}function D(e){if(!e||"object"!=typeof e)return null;const t=e;return t.type!==A||"boolean"!=typeof t.playing?null:t.playing}const X=["knoffice.tech","converge.ai"];function V(e,t){if(t.includes("*"))return!0;if(0===t.length)return!1;let s;try{s=new URL(e)}catch{return!1}const r=e.toLowerCase(),o=s.hostname.toLowerCase();for(const e of t){const t=e.trim();if(!t)continue;if(t.includes("://")){if(r===t.toLowerCase())return!0;continue}const s=t.toLowerCase().replace(/^\./,"");if(o===s||o.endsWith(`.${s}`))return!0}return!1}function $(e){if(!e?.length)return[...X];if(e.includes("*"))return["*"];const t=new Set,s=[];for(const r of[...X,...e]){const e=r.trim();e&&!t.has(e)&&(t.add(e),s.push(e))}return s}function G(e){if("systemName"in e){const t=e.systemName;if("string"==typeof t)return t}return"UnknownSystem"}function F(e){const t=e;return{packageName:"string"==typeof t.packageName?t.packageName:void 0,packageVersion:"string"==typeof t.packageVersion?t.packageVersion:void 0}}var B;exports.LOAD_SCENE_MODE=void 0,(B=exports.LOAD_SCENE_MODE||(exports.LOAD_SCENE_MODE={})).SINGLE="SINGLE",B.MULTI_CANVAS="MULTI_CANVAS";const U=e=>{if((e instanceof T||e instanceof c)&&!e.started){e.started=!0;try{e.start&&e.start()}catch(t){e instanceof c?console.error(`${function(e){if("componentName"in e){const t=e.componentName;if("string"==typeof t)return t}return"UnknownComponent"}(e.constructor)} start error`,t):console.error(`${G(e.constructor)} start error`,t)}}};class Y extends i.default{constructor({systems:e,frameRate:t=60,autoStart:s=!0,needScene:r=!0,onSystemsBootstrapComplete:o,pluginInitNotifyTargetOrigin:n="*",allowedMessageOrigins:a}={}){if(super(),this.playing=!1,this.started=!1,this.multiScenes=[],this.systems=[],this.pluginInitNotifyTargetOrigin="*",this.allowedMessageOrigins=$(),this.onHostMessage=e=>{if(!V(e.origin,this.allowedMessageOrigins))return;const t=D(e.data);null!==t&&this.setPlaying(t)},this.pluginInitNotifyTargetOrigin=n,this.allowedMessageOrigins=$(a),this.ticker=new x({autoStart:!1,frameRate:t}),this.initTicker(),"undefined"!=typeof window&&window.addEventListener("message",this.onHostMessage),e&&e.length){const t=[...e];this.bootstrapSystemsAndMaybeStart(t,r,s,o)}else o?.(this),this.notifyReady()}setPlaying(e){e?this.started?this.resume():this.start():this.pause()}notifyReady(e){I(e,this.pluginInitNotifyTargetOrigin)}notifyStateChanged(){P({playing:this.playing,started:this.started},this.pluginInitNotifyTargetOrigin)}async bootstrapSystemsAndMaybeStart(e,t,s,r){let o;try{for(const t of e)await this.addSystem(t);t&&this.loadScene({scene:new w("scene")}),s&&this.start()}catch(e){o=e,console.error("Game bootstrap failed",e)}finally{r?.(this,o),this.notifyReady(o)}}get scene(){return this._scene}set scene(e){this._scene=e}get gameObjects(){return(e=>{const t=e?.scene?.gameObjects||[],s=e?.multiScenes.map(({gameObjects:e})=>e);let r=[];for(const e of s)r=[...r,...e];return[...t,...r]})(this)}async addSystem(e,s){let r;if(e instanceof Function)r=new e(s);else{if(!(e instanceof T))return void console.warn("can only add System");r=e}if(!this.systems.find(e=>e.constructor===r.constructor)){r.game=this,r.init&&await Promise.resolve(r.init(r.__systemDefaultParams)),N({systemName:G(r.constructor),...F(r.constructor)},this.pluginInitNotifyTargetOrigin),function(e,t){h[t.systemName]=t.observerInfo,m[t.systemName]=e}(r,r.constructor),function(e){const s=[];e instanceof Array?s.push(...e):s.push(e);for(const e of s)for(const s in e.observerInfo){l[s]=l[s]||[];const r=l[s];for(const o of e.observerInfo[s])-1===r.findIndex(e=>t.isEqual(e,o))&&l[s].push(o)}}(r.constructor);try{r.awake&&r.awake()}catch(e){console.error(`${G(r.constructor)} awake error`,e)}return this.systems.push(r),r}console.warn(`${G(r.constructor)} System has been added`)}removeSystem(e){if(!e)return;let t=-1;"string"==typeof e?t=this.systems.findIndex(t=>t.name===e):e instanceof Function?t=this.systems.findIndex(t=>t.constructor===e):e instanceof T&&(t=this.systems.findIndex(t=>t===e)),t>-1&&(this.systems[t].destroy&&this.systems[t].destroy(),this.systems.splice(t,1))}getSystem(e){return this.systems.find(t=>"string"==typeof e?t.name===e:t instanceof e)}pause(){this.playing&&(this.playing=!1,this.ticker.pause(),this.triggerPause(),this.notifyStateChanged())}start(){this.playing||(this.playing=!0,this.started=!0,this.ticker.start(),this.notifyStateChanged())}resume(){this.playing||(this.playing=!0,this.ticker.start(),this.triggerResume(),this.notifyStateChanged())}initTicker(){this.ticker.add(e=>{this.scene&&((e,t=[])=>{for(const s of t)for(const t of s.components)try{U(t),t.update&&t.update(e)}catch(e){console.error(`gameObject: ${s.name} ${t.name} update error`,e)}for(const s of t)for(const t of s.components)try{t.lateUpdate&&t.lateUpdate(e)}catch(e){console.error(`gameObject: ${s.name} ${t.name} lateUpdate error`,e)}})(e,this.gameObjects);for(const t of this.systems)try{U(t),t.update&&t.update(e)}catch(e){console.error(`${G(t.constructor)} update error`,e)}for(const t of this.systems)try{t.lateUpdate&&t.lateUpdate(e)}catch(e){console.error(`${G(t.constructor)} lateUpdate error`,e)}})}triggerResume(){(e=>{for(const t of e)for(const e of t.components)try{e.onResume&&e.onResume()}catch(s){console.error(`gameObject: ${t.name}, ${e.name}, onResume error`,s)}})(this.gameObjects);for(const e of this.systems)try{e.onResume&&e.onResume()}catch(t){console.error(`${G(e.constructor)}, onResume error`,t)}}triggerPause(){(e=>{for(const t of e)for(const e of t.components)try{e.onPause&&e.onPause()}catch(s){console.error(`gameObject: ${t.name}, ${e.name}, onPause error`,s)}})(this.gameObjects);for(const e of this.systems)try{e.onPause&&e.onPause()}catch(t){console.error(`${G(e.constructor)}, onPause error`,t)}}destroySystems(){for(const e of[...this.systems])this.removeSystem(e);this.systems.length=0}destroy(){"undefined"!=typeof window&&window.removeEventListener("message",this.onHostMessage),this.removeAllListeners(),this.pause(),this.scene.destroy(),this.destroySystems(),this.ticker=null,this.scene=null,this.canvas=null,this.multiScenes=null}loadScene({scene:e,mode:t=exports.LOAD_SCENE_MODE.SINGLE,params:s={}}){if(e){switch(e.game=this,t){case exports.LOAD_SCENE_MODE.SINGLE:this.scene=e;break;case exports.LOAD_SCENE_MODE.MULTI_CANVAS:this.multiScenes.push(e)}this.emit("sceneChanged",{scene:e,mode:t,params:s})}}}function q(e,t){e.constructor.IDEProps||(e.constructor.IDEProps=[]),e.constructor.IDEProps.push(t)}function z(e={}){return function(t){if(!t.observerInfo){for(const t in e)for(const s in e[t]){let r;"string"==typeof e[t][s]&&(e[t][s]=[e[t][s]]),Array.isArray(e[t][s])&&(r={prop:e[t][s],deep:!1},e[t][s]=r),r=e[t][s],"string"==typeof r.prop&&(r.prop=[r.prop])}t.observerInfo=e}}}var H;exports.LOAD_EVENT=void 0,(H=exports.LOAD_EVENT||(exports.LOAD_EVENT={})).START="start",H.PROGRESS="progress",H.LOADED="loaded",H.COMPLETE="complete",H.ERROR="error";class J extends i.default{constructor({resource:e,resourceTotal:t}){super(),this.progress=0,this.resourceTotal=0,this.resourceLoadedCount=0,this.resource=e,this.resourceTotal=t,0===t&&this.resource.emit(exports.LOAD_EVENT.COMPLETE,this)}onStart(){this.resource.emit(exports.LOAD_EVENT.START,this)}onProgress(e){this.resourceLoadedCount++,this.progress=Math.floor(this.resourceLoadedCount/this.resourceTotal*100)/100,e.success?this.resource.emit(exports.LOAD_EVENT.LOADED,this,e):this.resource.emit(exports.LOAD_EVENT.ERROR,this,e),this.resource.emit(exports.LOAD_EVENT.PROGRESS,this,e),this.resourceLoadedCount===this.resourceTotal&&this.resource.emit(exports.LOAD_EVENT.COMPLETE,this)}}const W={image:"png",json:"json",tex:"tex",ske:"ske",audio:"audio",video:"video",model:"glb",mtl:"mtl",bin:"bin"},K={png:"png",jpg:"jpg",jpeg:"jpeg",webp:"webp",json:"json",tex:"tex",ske:"ske",mp3:"audio",wav:"audio",aac:"audio",ogg:"audio",mp4:"video",webm:"video",glb:"glb",gltf:"gltf",fbx:"fbx",obj:"obj",mtl:"mtl",stl:"stl",dae:"dae",ply:"ply",bin:"bin"};function Q(e,t){return K[function(e){const t=e.split("?")[0].split("#")[0],s=t.lastIndexOf(".");return s<0?"":t.slice(s+1).toLowerCase()}(e)]||W[t]||"png"}function Z(e,t,s){if("string"==typeof t){const r=t.trim();if(!r)throw ee(s,e);return{type:Q(r,e),url:r}}if(!t||"object"!=typeof t||Array.isArray(t))throw new Error(`Resource "${s}" src.${e} must be a url string or { type, url }.`);const r=t;if("data"===r.type)return r;const o="string"==typeof r.url?r.url.trim():"";if(!o)throw ee(s,e);return{...r,type:r.type||Q(o,e),url:o}}function ee(e,t){return new Error(`Resource "${e}" src.${t}.url is required. Use { type, url } (e.g. { type: "webp", url: "https://..." }). A flat path string is also accepted and will be normalized.`)}function te(e,t,s="(unnamed)"){if(null==e)throw new Error(`Resource "${s}" src is required.`);if("string"==typeof e){const r=function(e){return"AUDIO"===e?"audio":"VIDEO"===e?"video":"MODEL"===e||"GLB"===e?"model":"image"}(t);return{[r]:Z(r,e,s)}}if("object"!=typeof e||Array.isArray(e))throw new Error(`Resource "${s}" src must be a url string or a slot object.`);const r={};for(const[t,o]of Object.entries(e))null!=o&&(r[t]=Z(t,o,s));if(0===Object.keys(r).length)throw new Error(`Resource "${s}" src has no loadable slots.`);return r}const se={AbstractLoadStrategy:o.AbstractLoadStrategy,AudioLoadStrategy:o.AudioLoadStrategy,ImageLoadStrategy:o.ImageLoadStrategy,XhrResponseType:o.XhrResponseType,MediaElementLoadStrategy:o.MediaElementLoadStrategy,VideoLoadStrategy:o.VideoLoadStrategy,XhrLoadStrategy:o.XhrLoadStrategy,Loader:o.Loader,Resource:o.Resource,ResourceType:o.ResourceType,ResourceState:o.ResourceState};function re(e){const t=e.frame;return t&&"object"==typeof t?{...e,frame:t,rotated:Boolean(e.rotated),trimmed:Boolean(e.trimmed),spriteSourceSize:e.spriteSourceSize,sourceSize:e.sourceSize}:null}function oe(e,t,s){for(const r of e){if(!r||"object"!=typeof r)continue;const e=r,o=String(e.filename||e.name||"");if(!o)continue;const n=re(e);if(!n)continue;t[o]=n;const a=o.lastIndexOf("/");if(a>0){const e=o.slice(0,a);s[e]||(s[e]=[]),s[e].includes(o)||s[e].push(o)}}}var ne;exports.RESOURCE_TYPE=void 0,(ne=exports.RESOURCE_TYPE||(exports.RESOURCE_TYPE={})).IMAGE="IMAGE",ne.SPRITE="SPRITE",ne.SPRITE_ANIMATION="SPRITE_ANIMATION",ne.AUDIO="AUDIO",ne.VIDEO="VIDEO",ne.GLB="GLB",ne.MODEL="MODEL",o.XhrLoadStrategy.setExtensionXhrType("json",o.XhrResponseType.Json),o.XhrLoadStrategy.setExtensionXhrType("tex",o.XhrResponseType.Json),o.XhrLoadStrategy.setExtensionXhrType("ske",o.XhrResponseType.Json),o.XhrLoadStrategy.setExtensionXhrType("mp3",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("wav",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("aac",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("ogg",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("glb",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("gltf",o.XhrResponseType.Json),o.XhrLoadStrategy.setExtensionXhrType("fbx",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("stl",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("ply",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("bin",o.XhrResponseType.Buffer),o.XhrLoadStrategy.setExtensionXhrType("obj",o.XhrResponseType.Text),o.XhrLoadStrategy.setExtensionXhrType("mtl",o.XhrResponseType.Text),o.XhrLoadStrategy.setExtensionXhrType("dae",o.XhrResponseType.Text);const ae={png:o.ImageLoadStrategy,jpg:o.ImageLoadStrategy,jpeg:o.ImageLoadStrategy,webp:o.ImageLoadStrategy,json:o.XhrLoadStrategy,tex:o.XhrLoadStrategy,ske:o.XhrLoadStrategy,audio:o.XhrLoadStrategy,video:o.VideoLoadStrategy,glb:o.XhrLoadStrategy,gltf:o.XhrLoadStrategy,fbx:o.XhrLoadStrategy,obj:o.XhrLoadStrategy,mtl:o.XhrLoadStrategy,stl:o.XhrLoadStrategy,dae:o.XhrLoadStrategy,ply:o.XhrLoadStrategy,bin:o.XhrLoadStrategy};class ie extends i.default{constructor(e){super(),this.timeout=6e3,this.preProcessResourceHandlers=[],this.resourcesMap={},this.makeInstanceFunctions={},this.destroyInstanceFunctions={},this.promiseMap={},this.loaders=[],e&&"number"==typeof e.timeout&&(this.timeout=e.timeout)}loadConfig(e){this.addResource(e),this.preload()}loadSingle(e){return this.addResource([e]),this.getResource(e.name)}addResource(e){if(!e||e.length<1)console.warn("no resources");else for(const t of e)this.resourcesMap[t.name]?console.warn(t.name+" was already added"):this.resourcesMap[t.name]={...t,src:te(t.src,String(t.type),t.name),data:{}}}addPreProcessResourceHandler(e){this.preProcessResourceHandlers.push(e)}removePreProcessResourceHandler(e){this.preProcessResourceHandlers.splice(this.preProcessResourceHandlers.indexOf(e),1)}preload(){const e=[];for(const t in this.resourcesMap){const s=this.resourcesMap[t];!s.preload||s.complete||this.promiseMap[t]||e.push(s.name)}this.progress=new J({resource:this,resourceTotal:e.length}),this.loadResource({names:e,preload:!0})}async getResource(e){return this.loadResource({names:[e]}),this.promiseMap[e]||Promise.resolve({})}async instance(e){const t=this.resourcesMap[e];return this.makeInstanceFunctions[t.type]&&await this.makeInstanceFunctions[t.type](t)}async destroy(e){await this._destroy(e)}async _destroy(e,t=!1){const s=this.resourcesMap[e];if(s){if(!t)try{this.destroyInstanceFunctions[s.type]&&await this.destroyInstanceFunctions[s.type](s)}catch(e){console.warn(`destroy resource ${s.name} error with '${e.message}'`)}delete this.promiseMap[e],s.data={},s.complete=!1,s.instance=void 0}}registerResourceType(e,t=e){if(exports.RESOURCE_TYPE[e])throw new Error(`The type ${e} already exists in RESOURCE_TYPE`);exports.RESOURCE_TYPE[e]=t}registerInstance(e,t){this.makeInstanceFunctions[e]=t}registerDestroy(e,t){this.destroyInstanceFunctions[e]=t}loadResource({names:e=[],preload:t=!1}){const s=e.filter(e=>!this.promiseMap[e]&&this.resourcesMap[e]);if(!s.length)return;const r={},o=this.getLoader(t);s.forEach(e=>{this.promiseMap[e]=new Promise(t=>r[e]=t);const s=this.resourcesMap[e];for(const e of this.preProcessResourceHandlers)e(s);s.src=te(s.src,String(s.type),s.name);for(const n in s.src){const a=s.src[n].type;"data"===a?(s.data[n]=s.src[n].data,this.doComplete(e,r[e],t)):o.add({url:s.src[n].url,name:`${s.name}_${n}`,strategy:ae[a],metadata:{key:n,name:s.name,resolves:r}})}}),o.load()}async doComplete(e,t,s=!1){const r=this.resourcesMap[e],o={name:e,resource:this.resourcesMap[e],success:!0};if(this.checkAllLoaded(e))try{r.instance=await this.instance(e),r.complete=!0,s&&this.progress.onProgress(o),t(r)}catch(e){console.error(e),r.complete=!1,s&&(o.errMsg=e.message,o.success=!1,this.progress.onProgress(o)),t({})}}checkAllLoaded(e){const t=this.resourcesMap[e];return Array.from(Object.keys(t.src)).every(e=>t.data[e])}getLoader(e=!1){let t=this.loaders.find(({loading:e})=>!e);return t||(t=new o.Loader,this.loaders.push(t)),e&&t.onStart.once(()=>{this.progress.onStart()}),t.onLoad.add((t,s)=>{this.onLoad({preload:e,resource:s})}),t.onError.add((t,s,r)=>{this.onError({errMsg:t,resource:r,preload:e})}),t.onComplete.once(()=>{t.onLoad.detachAll(),t.onError.detachAll(),t.reset()}),t}async onLoad({preload:e=!1,resource:t}){const{metadata:{key:s,name:r,resolves:o},data:n}=t;this.resourcesMap[r].data[s]=n,this.doComplete(r,o[r],e)}async onError({errMsg:e,preload:t=!1,resource:s}){const{metadata:{name:r,resolves:o}}=s;if(this._destroy(r,!0),o[r]({}),t){const t={name:r,resource:this.resourcesMap[r],success:!1,errMsg:e};this.progress.onProgress(t)}}}const ce=new ie,pe={IDEProp:q,componentObserver:z};console.log(`@combos-fun/engine version: ${L}`),exports.COMBOS_GAME_PLUGIN_INIT_SUCCESS=v,exports.COMBOS_GAME_READY=M,exports.COMBOS_GAME_SET_PLAYING=A,exports.COMBOS_GAME_STATE_CHANGED=C,exports.Component=c,exports.DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES=X,exports.Game=Y,exports.GameObject=b,exports.IDEProp=q,exports.RESOURCE_TYPE_STRATEGY=ae,exports.Scene=w,exports.System=T,exports.Transform=g,exports.componentObserver=z,exports.decorators=pe,exports.isAllowedMessageOrigin=V,exports.mergeAllowedMessageOrigins=$,exports.normalizeResourceSrc=te,exports.normalizeSpritesheetData=function(e){if(!e||"object"!=typeof e)return{frames:{},animations:{},meta:{scale:1}};const t=e;if(function(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}(t.frames))return{...t,frames:t.frames,animations:{...t.animations||{}},meta:{scale:1,...t.meta||{}}};const s={},r={...t.animations||{}};if(Array.isArray(t.textures)){for(const e of t.textures)e&&"object"==typeof e&&Array.isArray(e.frames)&&oe(e.frames,s,r);const e=t.textures[0]||{},o=e.scale??t.meta?.scale??1;return{frames:s,animations:r,meta:{scale:"number"==typeof o||"string"==typeof o?o:1,image:"string"==typeof e.image?e.image:void 0,size:e.size,format:e.format,...t.meta||{}}}}return Array.isArray(t.frames)?(oe(t.frames,s,r),{frames:s,animations:r,meta:{scale:1,...t.meta||{}}}):{frames:{},animations:r,meta:{scale:1,...t.meta||{}}}},exports.parseSetPlayingMessage=D,exports.postParentGameReady=I,exports.postParentGameState=P,exports.postParentPluginInitSuccess=N,exports.resource=ce,exports.resourceLoader=se,exports.version=L;
package/dist/engine.d.ts CHANGED
@@ -738,6 +738,79 @@ declare enum LOAD_EVENT {
738
738
  'ERROR' = "error"
739
739
  }
740
740
 
741
+ /** One media slot after normalization. */
742
+ interface NormalizedSrcSlot {
743
+ type: string;
744
+ url?: string;
745
+ data?: unknown;
746
+ size?: {
747
+ width: number;
748
+ height: number;
749
+ };
750
+ texture?: {
751
+ type: string;
752
+ url: string;
753
+ size?: {
754
+ width: number;
755
+ height: number;
756
+ };
757
+ } | Array<{
758
+ type: string;
759
+ url: string;
760
+ size?: {
761
+ width: number;
762
+ height: number;
763
+ };
764
+ }>;
765
+ }
766
+ /**
767
+ * Accept the documented `{ type, url }` slots, plus the common guesses
768
+ * `src: "file.png"` and `src: { image: "a.webp", json: "a.json" }`.
769
+ */
770
+ declare function normalizeResourceSrc(src: unknown, resourceType?: string, resourceName?: string): Record<string, NormalizedSrcSlot>;
771
+
772
+ type SpritesheetFrame = {
773
+ frame: {
774
+ x: number;
775
+ y: number;
776
+ w: number;
777
+ h: number;
778
+ };
779
+ rotated?: boolean;
780
+ trimmed?: boolean;
781
+ spriteSourceSize?: {
782
+ x: number;
783
+ y: number;
784
+ w: number;
785
+ h: number;
786
+ };
787
+ sourceSize?: {
788
+ w: number;
789
+ h: number;
790
+ };
791
+ [key: string]: unknown;
792
+ };
793
+ type PixiSpritesheetData = {
794
+ frames: Record<string, SpritesheetFrame>;
795
+ animations: Record<string, string[]>;
796
+ meta: {
797
+ scale: number | string;
798
+ image?: string;
799
+ size?: {
800
+ w: number;
801
+ h: number;
802
+ };
803
+ [key: string]: unknown;
804
+ };
805
+ };
806
+ /**
807
+ * Pixi `Spritesheet` reads `data.meta.scale` and a name→frame `frames` map.
808
+ * TexturePacker multi-atlas (`textures[].frames` as an array) is accepted and
809
+ * rewritten to that hash. Always returns a `meta.scale` so construction cannot
810
+ * throw `Cannot read properties of undefined (reading 'scale')`.
811
+ */
812
+ declare function normalizeSpritesheetData(raw: unknown): PixiSpritesheetData;
813
+
741
814
  /** Resource type */
742
815
  declare enum RESOURCE_TYPE {
743
816
  'IMAGE' = "IMAGE",
@@ -745,7 +818,8 @@ declare enum RESOURCE_TYPE {
745
818
  'SPRITE_ANIMATION' = "SPRITE_ANIMATION",
746
819
  'AUDIO' = "AUDIO",
747
820
  'VIDEO' = "VIDEO",
748
- 'GLB' = "GLB"
821
+ 'GLB' = "GLB",
822
+ 'MODEL' = "MODEL"
749
823
  }
750
824
  /** Resource item */
751
825
  interface SrcBase {
@@ -943,7 +1017,7 @@ declare function isAllowedMessageOrigin(origin: string, allowed: readonly string
943
1017
  declare function mergeAllowedMessageOrigins(extra?: string[]): string[];
944
1018
 
945
1019
  /** Generated at build from package.json */
946
- declare const version = "0.0.38";
1020
+ declare const version = "0.0.40";
947
1021
 
948
1022
  /** Decorators util */
949
1023
  declare const decorators: {
@@ -951,5 +1025,5 @@ declare const decorators: {
951
1025
  componentObserver: typeof componentObserver;
952
1026
  };
953
1027
 
954
- export { COMBOS_GAME_PLUGIN_INIT_SUCCESS, COMBOS_GAME_READY, COMBOS_GAME_SET_PLAYING, COMBOS_GAME_STATE_CHANGED, Component, DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES, Game, GameObject, IDEProp, LOAD_EVENT, LOAD_SCENE_MODE, ObserverType as OBSERVER_TYPE, RESOURCE_TYPE, RESOURCE_TYPE_STRATEGY, Scene, System, Transform, componentObserver, decorators, isAllowedMessageOrigin, mergeAllowedMessageOrigins, parseSetPlayingMessage, postParentGameReady, postParentGameState, postParentPluginInitSuccess, resource, resourceLoader, version };
955
- export type { CombosGamePluginInitSuccessMessage, CombosGameReadyMessage, CombosGameSetPlayingMessage, CombosGameStateChangedMessage, ObserverEvent as ComponentChanged, ComponentParams, GameParams, ObserverInfo, PluginStruct, PureObserverInfo, ResourceBase, SystemConstructor, TransformParams, UpdateParams };
1028
+ export { COMBOS_GAME_PLUGIN_INIT_SUCCESS, COMBOS_GAME_READY, COMBOS_GAME_SET_PLAYING, COMBOS_GAME_STATE_CHANGED, Component, DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES, Game, GameObject, IDEProp, LOAD_EVENT, LOAD_SCENE_MODE, ObserverType as OBSERVER_TYPE, RESOURCE_TYPE, RESOURCE_TYPE_STRATEGY, Scene, System, Transform, componentObserver, decorators, isAllowedMessageOrigin, mergeAllowedMessageOrigins, normalizeResourceSrc, normalizeSpritesheetData, parseSetPlayingMessage, postParentGameReady, postParentGameState, postParentPluginInitSuccess, resource, resourceLoader, version };
1029
+ export type { CombosGamePluginInitSuccessMessage, CombosGameReadyMessage, CombosGameSetPlayingMessage, CombosGameStateChangedMessage, ObserverEvent as ComponentChanged, ComponentParams, GameParams, NormalizedSrcSlot, ObserverInfo, PixiSpritesheetData, PluginStruct, PureObserverInfo, ResourceBase, ResourceStruct, SystemConstructor, TransformParams, UpdateParams };
@@ -995,7 +995,7 @@ class Scene extends GameObject {
995
995
  }
996
996
 
997
997
  /** Generated at build from package.json */
998
- const version = "0.0.38";
998
+ const version = "0.0.40";
999
999
 
1000
1000
  /**
1001
1001
  * Sent to `window.parent` after each `System.init` completes during `Game.addSystem`
@@ -1636,6 +1636,117 @@ class Progress extends EventEmitter {
1636
1636
  }
1637
1637
  }
1638
1638
 
1639
+ const SLOT_DEFAULT_TYPE = {
1640
+ image: 'png',
1641
+ json: 'json',
1642
+ tex: 'tex',
1643
+ ske: 'ske',
1644
+ audio: 'audio',
1645
+ video: 'video',
1646
+ model: 'glb',
1647
+ mtl: 'mtl',
1648
+ bin: 'bin',
1649
+ };
1650
+ const EXT_TO_TYPE = {
1651
+ png: 'png',
1652
+ jpg: 'jpg',
1653
+ jpeg: 'jpeg',
1654
+ webp: 'webp',
1655
+ json: 'json',
1656
+ tex: 'tex',
1657
+ ske: 'ske',
1658
+ mp3: 'audio',
1659
+ wav: 'audio',
1660
+ aac: 'audio',
1661
+ ogg: 'audio',
1662
+ mp4: 'video',
1663
+ webm: 'video',
1664
+ glb: 'glb',
1665
+ gltf: 'gltf',
1666
+ fbx: 'fbx',
1667
+ obj: 'obj',
1668
+ mtl: 'mtl',
1669
+ stl: 'stl',
1670
+ dae: 'dae',
1671
+ ply: 'ply',
1672
+ bin: 'bin',
1673
+ };
1674
+ function extensionOf(url) {
1675
+ const path = url.split('?')[0].split('#')[0];
1676
+ const dot = path.lastIndexOf('.');
1677
+ if (dot < 0)
1678
+ return '';
1679
+ return path.slice(dot + 1).toLowerCase();
1680
+ }
1681
+ function typeFromUrl(url, slot) {
1682
+ return EXT_TO_TYPE[extensionOf(url)] || SLOT_DEFAULT_TYPE[slot] || 'png';
1683
+ }
1684
+ function defaultSlotForResourceType(resourceType) {
1685
+ if (resourceType === 'AUDIO')
1686
+ return 'audio';
1687
+ if (resourceType === 'VIDEO')
1688
+ return 'video';
1689
+ if (resourceType === 'MODEL' || resourceType === 'GLB')
1690
+ return 'model';
1691
+ return 'image';
1692
+ }
1693
+ function wrapSlot(slot, value, resourceName) {
1694
+ if (typeof value === 'string') {
1695
+ const url = value.trim();
1696
+ if (!url) {
1697
+ throw missingUrlError(resourceName, slot);
1698
+ }
1699
+ return { type: typeFromUrl(url, slot), url };
1700
+ }
1701
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
1702
+ throw new Error(`Resource "${resourceName}" src.${slot} must be a url string or { type, url }.`);
1703
+ }
1704
+ const slotValue = value;
1705
+ if (slotValue.type === 'data') {
1706
+ return slotValue;
1707
+ }
1708
+ const url = typeof slotValue.url === 'string' ? slotValue.url.trim() : '';
1709
+ if (!url) {
1710
+ throw missingUrlError(resourceName, slot);
1711
+ }
1712
+ return {
1713
+ ...slotValue,
1714
+ type: slotValue.type || typeFromUrl(url, slot),
1715
+ url,
1716
+ };
1717
+ }
1718
+ function missingUrlError(resourceName, slot) {
1719
+ return new Error(`Resource "${resourceName}" src.${slot}.url is required. ` +
1720
+ `Use { type, url } (e.g. { type: "webp", url: "https://..." }). ` +
1721
+ `A flat path string is also accepted and will be normalized.`);
1722
+ }
1723
+ /**
1724
+ * Accept the documented `{ type, url }` slots, plus the common guesses
1725
+ * `src: "file.png"` and `src: { image: "a.webp", json: "a.json" }`.
1726
+ */
1727
+ function normalizeResourceSrc(src, resourceType, resourceName = '(unnamed)') {
1728
+ if (src == null) {
1729
+ throw new Error(`Resource "${resourceName}" src is required.`);
1730
+ }
1731
+ if (typeof src === 'string') {
1732
+ const slot = defaultSlotForResourceType(resourceType);
1733
+ return { [slot]: wrapSlot(slot, src, resourceName) };
1734
+ }
1735
+ if (typeof src !== 'object' || Array.isArray(src)) {
1736
+ throw new Error(`Resource "${resourceName}" src must be a url string or a slot object.`);
1737
+ }
1738
+ const out = {};
1739
+ for (const [slot, value] of Object.entries(src)) {
1740
+ if (value == null)
1741
+ continue;
1742
+ out[slot] = wrapSlot(slot, value, resourceName);
1743
+ }
1744
+ if (Object.keys(out).length === 0) {
1745
+ throw new Error(`Resource "${resourceName}" src has no loadable slots.`);
1746
+ }
1747
+ return out;
1748
+ }
1749
+
1639
1750
  const resourceLoader = {
1640
1751
  AbstractLoadStrategy,
1641
1752
  AudioLoadStrategy,
@@ -1650,6 +1761,102 @@ const resourceLoader = {
1650
1761
  ResourceState
1651
1762
  };
1652
1763
 
1764
+ function isFrameMap(frames) {
1765
+ return !!frames && typeof frames === 'object' && !Array.isArray(frames);
1766
+ }
1767
+ function frameFromPackedItem(item) {
1768
+ const frame = item.frame;
1769
+ if (!frame || typeof frame !== 'object')
1770
+ return null;
1771
+ return {
1772
+ ...item,
1773
+ frame: frame,
1774
+ rotated: Boolean(item.rotated),
1775
+ trimmed: Boolean(item.trimmed),
1776
+ spriteSourceSize: item.spriteSourceSize,
1777
+ sourceSize: item.sourceSize,
1778
+ };
1779
+ }
1780
+ function collectArrayFrames(list, frames, animations) {
1781
+ for (const raw of list) {
1782
+ if (!raw || typeof raw !== 'object')
1783
+ continue;
1784
+ const item = raw;
1785
+ const name = String(item.filename || item.name || '');
1786
+ if (!name)
1787
+ continue;
1788
+ const packed = frameFromPackedItem(item);
1789
+ if (!packed)
1790
+ continue;
1791
+ frames[name] = packed;
1792
+ const slash = name.lastIndexOf('/');
1793
+ if (slash > 0) {
1794
+ const anim = name.slice(0, slash);
1795
+ if (!animations[anim])
1796
+ animations[anim] = [];
1797
+ if (!animations[anim].includes(name))
1798
+ animations[anim].push(name);
1799
+ }
1800
+ }
1801
+ }
1802
+ /**
1803
+ * Pixi `Spritesheet` reads `data.meta.scale` and a name→frame `frames` map.
1804
+ * TexturePacker multi-atlas (`textures[].frames` as an array) is accepted and
1805
+ * rewritten to that hash. Always returns a `meta.scale` so construction cannot
1806
+ * throw `Cannot read properties of undefined (reading 'scale')`.
1807
+ */
1808
+ function normalizeSpritesheetData(raw) {
1809
+ if (!raw || typeof raw !== 'object') {
1810
+ return { frames: {}, animations: {}, meta: { scale: 1 } };
1811
+ }
1812
+ const json = raw;
1813
+ if (isFrameMap(json.frames)) {
1814
+ return {
1815
+ ...json,
1816
+ frames: json.frames,
1817
+ animations: { ...(json.animations || {}) },
1818
+ meta: { scale: 1, ...(json.meta || {}) },
1819
+ };
1820
+ }
1821
+ const frames = {};
1822
+ const animations = { ...(json.animations || {}) };
1823
+ if (Array.isArray(json.textures)) {
1824
+ for (const sheet of json.textures) {
1825
+ if (!sheet || typeof sheet !== 'object')
1826
+ continue;
1827
+ if (Array.isArray(sheet.frames)) {
1828
+ collectArrayFrames(sheet.frames, frames, animations);
1829
+ }
1830
+ }
1831
+ const first = json.textures[0] || {};
1832
+ const scale = first.scale ?? json.meta?.scale ?? 1;
1833
+ return {
1834
+ frames,
1835
+ animations,
1836
+ meta: {
1837
+ scale: typeof scale === 'number' || typeof scale === 'string' ? scale : 1,
1838
+ image: typeof first.image === 'string' ? first.image : undefined,
1839
+ size: first.size,
1840
+ format: first.format,
1841
+ ...(json.meta || {}),
1842
+ },
1843
+ };
1844
+ }
1845
+ if (Array.isArray(json.frames)) {
1846
+ collectArrayFrames(json.frames, frames, animations);
1847
+ return {
1848
+ frames,
1849
+ animations,
1850
+ meta: { scale: 1, ...(json.meta || {}) },
1851
+ };
1852
+ }
1853
+ return {
1854
+ frames: {},
1855
+ animations,
1856
+ meta: { scale: 1, ...(json.meta || {}) },
1857
+ };
1858
+ }
1859
+
1653
1860
  /** Resource type */
1654
1861
  var RESOURCE_TYPE;
1655
1862
  (function (RESOURCE_TYPE) {
@@ -1659,6 +1866,7 @@ var RESOURCE_TYPE;
1659
1866
  RESOURCE_TYPE["AUDIO"] = "AUDIO";
1660
1867
  RESOURCE_TYPE["VIDEO"] = "VIDEO";
1661
1868
  RESOURCE_TYPE["GLB"] = "GLB";
1869
+ RESOURCE_TYPE["MODEL"] = "MODEL";
1662
1870
  })(RESOURCE_TYPE || (RESOURCE_TYPE = {}));
1663
1871
  XhrLoadStrategy.setExtensionXhrType('json', XhrResponseType.Json);
1664
1872
  XhrLoadStrategy.setExtensionXhrType('tex', XhrResponseType.Json);
@@ -1669,6 +1877,13 @@ XhrLoadStrategy.setExtensionXhrType('aac', XhrResponseType.Buffer);
1669
1877
  XhrLoadStrategy.setExtensionXhrType('ogg', XhrResponseType.Buffer);
1670
1878
  XhrLoadStrategy.setExtensionXhrType('glb', XhrResponseType.Buffer);
1671
1879
  XhrLoadStrategy.setExtensionXhrType('gltf', XhrResponseType.Json);
1880
+ XhrLoadStrategy.setExtensionXhrType('fbx', XhrResponseType.Buffer);
1881
+ XhrLoadStrategy.setExtensionXhrType('stl', XhrResponseType.Buffer);
1882
+ XhrLoadStrategy.setExtensionXhrType('ply', XhrResponseType.Buffer);
1883
+ XhrLoadStrategy.setExtensionXhrType('bin', XhrResponseType.Buffer);
1884
+ XhrLoadStrategy.setExtensionXhrType('obj', XhrResponseType.Text);
1885
+ XhrLoadStrategy.setExtensionXhrType('mtl', XhrResponseType.Text);
1886
+ XhrLoadStrategy.setExtensionXhrType('dae', XhrResponseType.Text);
1672
1887
  const RESOURCE_TYPE_STRATEGY = {
1673
1888
  png: ImageLoadStrategy,
1674
1889
  jpg: ImageLoadStrategy,
@@ -1681,6 +1896,13 @@ const RESOURCE_TYPE_STRATEGY = {
1681
1896
  video: VideoLoadStrategy,
1682
1897
  glb: XhrLoadStrategy,
1683
1898
  gltf: XhrLoadStrategy,
1899
+ fbx: XhrLoadStrategy,
1900
+ obj: XhrLoadStrategy,
1901
+ mtl: XhrLoadStrategy,
1902
+ stl: XhrLoadStrategy,
1903
+ dae: XhrLoadStrategy,
1904
+ ply: XhrLoadStrategy,
1905
+ bin: XhrLoadStrategy,
1684
1906
  };
1685
1907
  /**
1686
1908
  * Resource manager
@@ -1727,8 +1949,11 @@ class Resource extends EventEmitter {
1727
1949
  console.warn(res.name + ' was already added');
1728
1950
  continue;
1729
1951
  }
1730
- this.resourcesMap[res.name] = res;
1731
- this.resourcesMap[res.name].data = {};
1952
+ this.resourcesMap[res.name] = {
1953
+ ...res,
1954
+ src: normalizeResourceSrc(res.src, String(res.type), res.name),
1955
+ data: {},
1956
+ };
1732
1957
  }
1733
1958
  }
1734
1959
  /** dd resource preprocesser*/
@@ -1817,6 +2042,7 @@ class Resource extends EventEmitter {
1817
2042
  for (const handler of this.preProcessResourceHandlers) {
1818
2043
  handler(res);
1819
2044
  }
2045
+ res.src = normalizeResourceSrc(res.src, String(res.type), res.name);
1820
2046
  for (const key in res.src) {
1821
2047
  const resourceType = res.src[key].type;
1822
2048
  if (resourceType === 'data') {
@@ -1926,5 +2152,5 @@ const decorators = {
1926
2152
  };
1927
2153
  console.log(`@combos-fun/engine version: ${version}`);
1928
2154
 
1929
- export { COMBOS_GAME_PLUGIN_INIT_SUCCESS, COMBOS_GAME_READY, COMBOS_GAME_SET_PLAYING, COMBOS_GAME_STATE_CHANGED, Component, DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES, Game, GameObject, IDEProp, LOAD_EVENT, LOAD_SCENE_MODE, ObserverType as OBSERVER_TYPE, RESOURCE_TYPE, RESOURCE_TYPE_STRATEGY, Scene, System, Transform, componentObserver, decorators, isAllowedMessageOrigin, mergeAllowedMessageOrigins, parseSetPlayingMessage, postParentGameReady, postParentGameState, postParentPluginInitSuccess, resource, resourceLoader, version };
2155
+ export { COMBOS_GAME_PLUGIN_INIT_SUCCESS, COMBOS_GAME_READY, COMBOS_GAME_SET_PLAYING, COMBOS_GAME_STATE_CHANGED, Component, DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES, Game, GameObject, IDEProp, LOAD_EVENT, LOAD_SCENE_MODE, ObserverType as OBSERVER_TYPE, RESOURCE_TYPE, RESOURCE_TYPE_STRATEGY, Scene, System, Transform, componentObserver, decorators, isAllowedMessageOrigin, mergeAllowedMessageOrigins, normalizeResourceSrc, normalizeSpritesheetData, parseSetPlayingMessage, postParentGameReady, postParentGameState, postParentPluginInitSuccess, resource, resourceLoader, version };
1930
2156
  //# sourceMappingURL=engine.esm.js.map