@combos-fun/engine 0.0.23 → 0.0.27
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.
- package/agent-skill.md +26 -4
- package/dist/engine.cjs.js +184 -7
- package/dist/engine.cjs.js.map +1 -1
- package/dist/engine.cjs.prod.js +1 -1
- package/dist/engine.d.ts +85 -7
- package/dist/engine.esm.js +176 -8
- package/dist/engine.esm.js.map +1 -1
- package/package.json +2 -2
package/dist/engine.cjs.prod.js
CHANGED
|
@@ -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 u(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 l({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&&l({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.type("vector2"),r.step(1)],g.prototype,"position",void 0),s.__decorate([r.type("size"),r.step(1)],g.prototype,"size",void 0),s.__decorate([r.type("vector2"),r.step(.1)],g.prototype,"origin",void 0),s.__decorate([r.type("vector2"),r.step(.1)],g.prototype,"anchor",void 0),s.__decorate([r.type("vector2"),r.step(.1)],g.prototype,"scale",void 0),s.__decorate([r.type("vector2"),r.step(.1)],g.prototype,"skew",void 0),s.__decorate([r.type("number"),r.step(.1)],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}=u(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 R=function(){let e=null;return e=Date.now?Date.now:()=>(new Date).getTime(),e}(),O={originTime:0,playbackRate:1};class S{constructor(e,t){e instanceof S&&(t=e,e={}),e=Object.assign({},O,e),t&&(this._parent=t),this._createTime=R(),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:R()-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 S(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 S({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 L 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 x="0.0.22",C="combos-game:plugin-init-success";function M(e,t="*"){if("undefined"==typeof window)return;if(!window.parent||window.parent===window)return;const s={type:C,systemName:e.systemName,engineVersion:x,...e.packageName?{packageName:e.packageName}:{},...e.packageVersion?{packageVersion:e.packageVersion}:{}};try{window.parent.postMessage(s,t)}catch{}}function N(e){if("systemName"in e){const t=e.systemName;if("string"==typeof t)return t}return"UnknownSystem"}function w(e){const t=e;return{packageName:"string"==typeof t.packageName?t.packageName:void 0,packageVersion:"string"==typeof t.packageVersion?t.packageVersion:void 0}}var I;exports.LOAD_SCENE_MODE=void 0,(I=exports.LOAD_SCENE_MODE||(exports.LOAD_SCENE_MODE={})).SINGLE="SINGLE",I.MULTI_CANVAS="MULTI_CANVAS";const P=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(`${N(e.constructor)} start error`,t)}}};class A extends i.default{constructor({systems:e,frameRate:t=60,autoStart:s=!0,needScene:r=!0,onSystemsBootstrapComplete:o,pluginInitNotifyTargetOrigin:n="*"}={}){if(super(),this.playing=!1,this.started=!1,this.multiScenes=[],this.systems=[],this.pluginInitNotifyTargetOrigin="*",this.pluginInitNotifyTargetOrigin=n,this.ticker=new v({autoStart:!1,frameRate:t}),this.initTicker(),e&&e.length){const t=[...e];this.bootstrapSystemsAndMaybeStart(t,r,s,o)}else o?.(this)}async bootstrapSystemsAndMaybeStart(e,t,s,r){let o;try{for(const t of e)await this.addSystem(t);t&&this.loadScene({scene:new L("scene")}),s&&this.start()}catch(e){o=e,console.error("Game bootstrap failed",e)}finally{r?.(this,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)),M({systemName:N(r.constructor),...w(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(`${N(r.constructor)} awake error`,e)}return this.systems.push(r),r}console.warn(`${N(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())}start(){this.playing||(this.playing=!0,this.started=!0,this.ticker.start())}resume(){this.playing||(this.playing=!0,this.ticker.start(),this.triggerResume())}initTicker(){this.ticker.add(e=>{this.scene&&((e,t=[])=>{for(const s of t)for(const t of s.components)try{P(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{P(t),t.update&&t.update(e)}catch(e){console.error(`${N(t.constructor)} update error`,e)}for(const t of this.systems)try{t.lateUpdate&&t.lateUpdate(e)}catch(e){console.error(`${N(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(`${N(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(`${N(e.constructor)}, onPause error`,t)}}destroySystems(){for(const e of[...this.systems])this.removeSystem(e);this.systems.length=0}destroy(){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 j(e,t){e.constructor.IDEProps||(e.constructor.IDEProps=[]),e.constructor.IDEProps.push(t)}function D(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 X;exports.LOAD_EVENT=void 0,(X=exports.LOAD_EVENT||(exports.LOAD_EVENT={})).START="start",X.PROGRESS="progress",X.LOADED="loaded",X.COMPLETE="complete",X.ERROR="error";class V 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 $={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 G;exports.RESOURCE_TYPE=void 0,(G=exports.RESOURCE_TYPE||(exports.RESOURCE_TYPE={})).IMAGE="IMAGE",G.SPRITE="SPRITE",G.SPRITE_ANIMATION="SPRITE_ANIMATION",G.AUDIO="AUDIO",G.VIDEO="VIDEO",G.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 U={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 F 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 V({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:U[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 B=new F,Y={IDEProp:j,componentObserver:D};console.log(`@combos-fun/engine version: ${x}`),exports.COMBOS_GAME_PLUGIN_INIT_SUCCESS=C,exports.Component=c,exports.Game=A,exports.GameObject=_,exports.IDEProp=j,exports.RESOURCE_TYPE_STRATEGY=U,exports.Scene=L,exports.System=T,exports.Transform=g,exports.componentObserver=D,exports.decorators=Y,exports.postParentPluginInitSuccess=M,exports.resource=B,exports.resourceLoader=$,exports.version=x;
|
|
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.type("vector2"),r.step(1)],g.prototype,"position",void 0),s.__decorate([r.type("size"),r.step(1)],g.prototype,"size",void 0),s.__decorate([r.type("vector2"),r.step(.1)],g.prototype,"origin",void 0),s.__decorate([r.type("vector2"),r.step(.1)],g.prototype,"anchor",void 0),s.__decorate([r.type("vector2"),r.step(.1)],g.prototype,"scale",void 0),s.__decorate([r.type("vector2"),r.step(.1)],g.prototype,"skew",void 0),s.__decorate([r.type("number"),r.step(.1)],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 O{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 T=function(){let e=null;return e=Date.now?Date.now:()=>(new Date).getTime(),e}(),S={originTime:0,playbackRate:1};class R{constructor(e,t){e instanceof R&&(t=e,e={}),e=Object.assign({},S,e),t&&(this._parent=t),this._createTime=T(),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:T()-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 M 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.27",w="combos-game:plugin-init-success",C="combos-game:ready",x="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:w,systemName:e.systemName,engineVersion:L,...e.packageName?{packageName:e.packageName}:{},...e.packageVersion?{packageVersion:e.packageVersion}:{}},t)}function I(e,t="*"){A({type:C,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!==x||"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 U(e){const t=e;return{packageName:"string"==typeof t.packageName?t.packageName:void 0,packageVersion:"string"==typeof t.packageVersion?t.packageVersion:void 0}}var F;exports.LOAD_SCENE_MODE=void 0,(F=exports.LOAD_SCENE_MODE||(exports.LOAD_SCENE_MODE={})).SINGLE="SINGLE",F.MULTI_CANVAS="MULTI_CANVAS";const B=e=>{if((e instanceof O||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 M("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 O))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),...U(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 O&&(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=w,exports.COMBOS_GAME_READY=C,exports.COMBOS_GAME_SET_PLAYING=x,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=M,exports.System=O,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;
|
package/dist/engine.d.ts
CHANGED
|
@@ -326,10 +326,17 @@ interface GameParams {
|
|
|
326
326
|
/** whether or not need to create scene */
|
|
327
327
|
needScene?: boolean;
|
|
328
328
|
/**
|
|
329
|
-
* `postMessage` targetOrigin when notifying parent
|
|
330
|
-
*
|
|
329
|
+
* `postMessage` targetOrigin when notifying `window.parent` of lifecycle events
|
|
330
|
+
* (`combos-game:plugin-init-success`, `combos-game:ready`, `combos-game:state-changed`).
|
|
331
|
+
* Default `'*'`. Only used when `window.parent` exists and differs from `window`.
|
|
331
332
|
*/
|
|
332
333
|
pluginInitNotifyTargetOrigin?: string;
|
|
334
|
+
/**
|
|
335
|
+
* Inbound `postMessage` origins allowed to send host commands (`combos-game:set-playing`),
|
|
336
|
+
* merged with {@link DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES}. Each entry is a host suffix
|
|
337
|
+
* (e.g. `localhost`) or a full origin. Pass `['*']` to accept any origin (dev only).
|
|
338
|
+
*/
|
|
339
|
+
allowedMessageOrigins?: string[];
|
|
333
340
|
/**
|
|
334
341
|
* Called after async system bootstrap finishes (constructor path with non-empty `systems`),
|
|
335
342
|
* i.e. after all `addSystem`/`init` work and optional `loadScene` / `start`.
|
|
@@ -382,10 +389,23 @@ declare class Game extends EventEmitter {
|
|
|
382
389
|
/** Systems alled to this game */
|
|
383
390
|
systems: System[];
|
|
384
391
|
/**
|
|
385
|
-
* Passed to `postMessage` when reporting
|
|
392
|
+
* Passed to `postMessage` when reporting lifecycle events to `window.parent`
|
|
393
|
+
* (`plugin-init-success`, `ready`, `state-changed`).
|
|
386
394
|
*/
|
|
387
395
|
pluginInitNotifyTargetOrigin: string;
|
|
388
|
-
|
|
396
|
+
/** Inbound `postMessage` origins allowed to send host commands. */
|
|
397
|
+
private allowedMessageOrigins;
|
|
398
|
+
/** Bound inbound `message` handler; retained so it can be removed on `destroy`. */
|
|
399
|
+
private readonly onHostMessage;
|
|
400
|
+
constructor({ systems, frameRate, autoStart, needScene, onSystemsBootstrapComplete, pluginInitNotifyTargetOrigin, allowedMessageOrigins, }?: GameParams);
|
|
401
|
+
/**
|
|
402
|
+
* Host command bridge: `true` cold-starts on first play (`start`), otherwise
|
|
403
|
+
* `resume`s; `false` pauses. Mirrors what a parent frame drives via
|
|
404
|
+
* `postMessage({ type: 'combos-game:set-playing', playing })`.
|
|
405
|
+
*/
|
|
406
|
+
setPlaying(playing: boolean): void;
|
|
407
|
+
private notifyReady;
|
|
408
|
+
private notifyStateChanged;
|
|
389
409
|
/** When `systems` is passed in the constructor, run async `init` for each before `loadScene` / `start`. */
|
|
390
410
|
private bootstrapSystemsAndMaybeStart;
|
|
391
411
|
/**
|
|
@@ -859,13 +879,71 @@ interface CombosGamePluginInitSuccessInput {
|
|
|
859
879
|
packageName?: string;
|
|
860
880
|
packageVersion?: string;
|
|
861
881
|
}
|
|
882
|
+
/**
|
|
883
|
+
* iframe → parent: game bootstrap finished (all systems `init`/`awake`, optional
|
|
884
|
+
* scene load and `start`). Sent once, even when `autoStart` is `false`, so the host
|
|
885
|
+
* knows assets + scene graph are ready and it may pause / hold before play.
|
|
886
|
+
*/
|
|
887
|
+
declare const COMBOS_GAME_READY: "combos-game:ready";
|
|
888
|
+
/**
|
|
889
|
+
* parent → iframe: start / pause the game loop. Payload: `{ playing: boolean }`.
|
|
890
|
+
* `true` cold-starts (`Game.start`) on first play, otherwise resumes; `false` pauses.
|
|
891
|
+
*/
|
|
892
|
+
declare const COMBOS_GAME_SET_PLAYING: "combos-game:set-playing";
|
|
893
|
+
/**
|
|
894
|
+
* iframe → parent: current run state after a `start` / `pause` / `resume`.
|
|
895
|
+
*/
|
|
896
|
+
declare const COMBOS_GAME_STATE_CHANGED: "combos-game:state-changed";
|
|
897
|
+
interface CombosGameReadyMessage {
|
|
898
|
+
type: typeof COMBOS_GAME_READY;
|
|
899
|
+
engineVersion: string;
|
|
900
|
+
/** Set when bootstrap threw (serialized error message). */
|
|
901
|
+
error?: string;
|
|
902
|
+
}
|
|
903
|
+
interface CombosGameStateChangedMessage {
|
|
904
|
+
type: typeof COMBOS_GAME_STATE_CHANGED;
|
|
905
|
+
/** Loop currently running. */
|
|
906
|
+
playing: boolean;
|
|
907
|
+
/** Whether the game has been started at least once (cold start happened). */
|
|
908
|
+
started: boolean;
|
|
909
|
+
}
|
|
910
|
+
interface CombosGameSetPlayingMessage {
|
|
911
|
+
type: typeof COMBOS_GAME_SET_PLAYING;
|
|
912
|
+
playing: boolean;
|
|
913
|
+
}
|
|
862
914
|
/**
|
|
863
915
|
* Notifies the embedding page that a system (plugin) finished async/sync `init`.
|
|
864
916
|
*/
|
|
865
917
|
declare function postParentPluginInitSuccess(input: CombosGamePluginInitSuccessInput, targetOrigin?: string): void;
|
|
918
|
+
/** Notifies the embedding page that game bootstrap finished. */
|
|
919
|
+
declare function postParentGameReady(error?: unknown, targetOrigin?: string): void;
|
|
920
|
+
/** Notifies the embedding page of the current play/pause state. */
|
|
921
|
+
declare function postParentGameState(state: {
|
|
922
|
+
playing: boolean;
|
|
923
|
+
started: boolean;
|
|
924
|
+
}, targetOrigin?: string): void;
|
|
925
|
+
/**
|
|
926
|
+
* Reads a `combos-game:set-playing` command from an inbound `postMessage` payload.
|
|
927
|
+
* Returns the requested `playing` value, or `null` when the message is unrelated / malformed.
|
|
928
|
+
*/
|
|
929
|
+
declare function parseSetPlayingMessage(data: unknown): boolean | null;
|
|
930
|
+
|
|
931
|
+
/** Default inbound postMessage host suffixes (host + all subdomains). */
|
|
932
|
+
declare const DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES: readonly ["knoffice.tech", "converge.ai"];
|
|
933
|
+
/**
|
|
934
|
+
* Returns whether `origin` is allowed by `allowed`.
|
|
935
|
+
*
|
|
936
|
+
* Each entry in `allowed` is either:
|
|
937
|
+
* - a **host suffix** (e.g. `knoffice.tech`) — matches that host and `*.knoffice.tech`;
|
|
938
|
+
* - a **full origin** (e.g. `https://creator.knoffice.tech`) — exact match;
|
|
939
|
+
* - `'*'` — accept any origin (escape hatch).
|
|
940
|
+
*/
|
|
941
|
+
declare function isAllowedMessageOrigin(origin: string, allowed: readonly string[]): boolean;
|
|
942
|
+
/** Defaults plus any extra entries (deduped). `['*']` alone accepts any origin. */
|
|
943
|
+
declare function mergeAllowedMessageOrigins(extra?: string[]): string[];
|
|
866
944
|
|
|
867
945
|
/** Generated at build from package.json */
|
|
868
|
-
declare const version = "0.0.
|
|
946
|
+
declare const version = "0.0.27";
|
|
869
947
|
|
|
870
948
|
/** Decorators util */
|
|
871
949
|
declare const decorators: {
|
|
@@ -873,5 +951,5 @@ declare const decorators: {
|
|
|
873
951
|
componentObserver: typeof componentObserver;
|
|
874
952
|
};
|
|
875
953
|
|
|
876
|
-
export { COMBOS_GAME_PLUGIN_INIT_SUCCESS, Component, Game, GameObject, IDEProp, LOAD_EVENT, LOAD_SCENE_MODE, ObserverType as OBSERVER_TYPE, RESOURCE_TYPE, RESOURCE_TYPE_STRATEGY, Scene, System, Transform, componentObserver, decorators, postParentPluginInitSuccess, resource, resourceLoader, version };
|
|
877
|
-
export type { CombosGamePluginInitSuccessMessage, ObserverEvent as ComponentChanged, ComponentParams, GameParams, ObserverInfo, PluginStruct, PureObserverInfo, ResourceBase, SystemConstructor, TransformParams, UpdateParams };
|
|
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 };
|
package/dist/engine.esm.js
CHANGED
|
@@ -958,7 +958,7 @@ class Scene extends GameObject {
|
|
|
958
958
|
}
|
|
959
959
|
|
|
960
960
|
/** Generated at build from package.json */
|
|
961
|
-
const version = "0.0.
|
|
961
|
+
const version = "0.0.27";
|
|
962
962
|
|
|
963
963
|
/**
|
|
964
964
|
* Sent to `window.parent` after each `System.init` completes during `Game.addSystem`
|
|
@@ -966,13 +966,36 @@ const version = "0.0.22";
|
|
|
966
966
|
*/
|
|
967
967
|
const COMBOS_GAME_PLUGIN_INIT_SUCCESS = "combos-game:plugin-init-success";
|
|
968
968
|
/**
|
|
969
|
-
*
|
|
969
|
+
* iframe → parent: game bootstrap finished (all systems `init`/`awake`, optional
|
|
970
|
+
* scene load and `start`). Sent once, even when `autoStart` is `false`, so the host
|
|
971
|
+
* knows assets + scene graph are ready and it may pause / hold before play.
|
|
970
972
|
*/
|
|
971
|
-
|
|
973
|
+
const COMBOS_GAME_READY = "combos-game:ready";
|
|
974
|
+
/**
|
|
975
|
+
* parent → iframe: start / pause the game loop. Payload: `{ playing: boolean }`.
|
|
976
|
+
* `true` cold-starts (`Game.start`) on first play, otherwise resumes; `false` pauses.
|
|
977
|
+
*/
|
|
978
|
+
const COMBOS_GAME_SET_PLAYING = "combos-game:set-playing";
|
|
979
|
+
/**
|
|
980
|
+
* iframe → parent: current run state after a `start` / `pause` / `resume`.
|
|
981
|
+
*/
|
|
982
|
+
const COMBOS_GAME_STATE_CHANGED = "combos-game:state-changed";
|
|
983
|
+
function postToParent(payload, targetOrigin) {
|
|
972
984
|
if (typeof window === "undefined")
|
|
973
985
|
return;
|
|
974
986
|
if (!window.parent || window.parent === window)
|
|
975
987
|
return;
|
|
988
|
+
try {
|
|
989
|
+
window.parent.postMessage(payload, targetOrigin);
|
|
990
|
+
}
|
|
991
|
+
catch {
|
|
992
|
+
/* ignore cross-origin or detached frame */
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Notifies the embedding page that a system (plugin) finished async/sync `init`.
|
|
997
|
+
*/
|
|
998
|
+
function postParentPluginInitSuccess(input, targetOrigin = "*") {
|
|
976
999
|
const payload = {
|
|
977
1000
|
type: COMBOS_GAME_PLUGIN_INIT_SUCCESS,
|
|
978
1001
|
systemName: input.systemName,
|
|
@@ -980,12 +1003,109 @@ function postParentPluginInitSuccess(input, targetOrigin = "*") {
|
|
|
980
1003
|
...(input.packageName ? { packageName: input.packageName } : {}),
|
|
981
1004
|
...(input.packageVersion ? { packageVersion: input.packageVersion } : {}),
|
|
982
1005
|
};
|
|
1006
|
+
postToParent(payload, targetOrigin);
|
|
1007
|
+
}
|
|
1008
|
+
/** Notifies the embedding page that game bootstrap finished. */
|
|
1009
|
+
function postParentGameReady(error, targetOrigin = "*") {
|
|
1010
|
+
const payload = {
|
|
1011
|
+
type: COMBOS_GAME_READY,
|
|
1012
|
+
engineVersion: version,
|
|
1013
|
+
...(error === undefined
|
|
1014
|
+
? {}
|
|
1015
|
+
: { error: error instanceof Error ? error.message : String(error) }),
|
|
1016
|
+
};
|
|
1017
|
+
postToParent(payload, targetOrigin);
|
|
1018
|
+
}
|
|
1019
|
+
/** Notifies the embedding page of the current play/pause state. */
|
|
1020
|
+
function postParentGameState(state, targetOrigin = "*") {
|
|
1021
|
+
const payload = {
|
|
1022
|
+
type: COMBOS_GAME_STATE_CHANGED,
|
|
1023
|
+
playing: state.playing,
|
|
1024
|
+
started: state.started,
|
|
1025
|
+
};
|
|
1026
|
+
postToParent(payload, targetOrigin);
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Reads a `combos-game:set-playing` command from an inbound `postMessage` payload.
|
|
1030
|
+
* Returns the requested `playing` value, or `null` when the message is unrelated / malformed.
|
|
1031
|
+
*/
|
|
1032
|
+
function parseSetPlayingMessage(data) {
|
|
1033
|
+
if (!data || typeof data !== "object")
|
|
1034
|
+
return null;
|
|
1035
|
+
const d = data;
|
|
1036
|
+
if (d.type !== COMBOS_GAME_SET_PLAYING)
|
|
1037
|
+
return null;
|
|
1038
|
+
if (typeof d.playing !== "boolean")
|
|
1039
|
+
return null;
|
|
1040
|
+
return d.playing;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
/** Default inbound postMessage host suffixes (host + all subdomains). */
|
|
1044
|
+
const DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES = [
|
|
1045
|
+
"knoffice.tech",
|
|
1046
|
+
"converge.ai",
|
|
1047
|
+
];
|
|
1048
|
+
/**
|
|
1049
|
+
* Returns whether `origin` is allowed by `allowed`.
|
|
1050
|
+
*
|
|
1051
|
+
* Each entry in `allowed` is either:
|
|
1052
|
+
* - a **host suffix** (e.g. `knoffice.tech`) — matches that host and `*.knoffice.tech`;
|
|
1053
|
+
* - a **full origin** (e.g. `https://creator.knoffice.tech`) — exact match;
|
|
1054
|
+
* - `'*'` — accept any origin (escape hatch).
|
|
1055
|
+
*/
|
|
1056
|
+
function isAllowedMessageOrigin(origin, allowed) {
|
|
1057
|
+
if (allowed.includes("*")) {
|
|
1058
|
+
return true;
|
|
1059
|
+
}
|
|
1060
|
+
if (allowed.length === 0) {
|
|
1061
|
+
return false;
|
|
1062
|
+
}
|
|
1063
|
+
let parsed;
|
|
983
1064
|
try {
|
|
984
|
-
|
|
1065
|
+
parsed = new URL(origin);
|
|
985
1066
|
}
|
|
986
1067
|
catch {
|
|
987
|
-
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1070
|
+
const originLower = origin.toLowerCase();
|
|
1071
|
+
const hostLower = parsed.hostname.toLowerCase();
|
|
1072
|
+
for (const entry of allowed) {
|
|
1073
|
+
const trimmed = entry.trim();
|
|
1074
|
+
if (!trimmed) {
|
|
1075
|
+
continue;
|
|
1076
|
+
}
|
|
1077
|
+
if (trimmed.includes("://")) {
|
|
1078
|
+
if (originLower === trimmed.toLowerCase()) {
|
|
1079
|
+
return true;
|
|
1080
|
+
}
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1083
|
+
const suffix = trimmed.toLowerCase().replace(/^\./, "");
|
|
1084
|
+
if (hostLower === suffix || hostLower.endsWith(`.${suffix}`)) {
|
|
1085
|
+
return true;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
return false;
|
|
1089
|
+
}
|
|
1090
|
+
/** Defaults plus any extra entries (deduped). `['*']` alone accepts any origin. */
|
|
1091
|
+
function mergeAllowedMessageOrigins(extra) {
|
|
1092
|
+
if (!extra?.length) {
|
|
1093
|
+
return [...DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES];
|
|
1094
|
+
}
|
|
1095
|
+
if (extra.includes("*")) {
|
|
1096
|
+
return ["*"];
|
|
1097
|
+
}
|
|
1098
|
+
const seen = new Set();
|
|
1099
|
+
const result = [];
|
|
1100
|
+
for (const entry of [...DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES, ...extra]) {
|
|
1101
|
+
const trimmed = entry.trim();
|
|
1102
|
+
if (!trimmed || seen.has(trimmed)) {
|
|
1103
|
+
continue;
|
|
1104
|
+
}
|
|
1105
|
+
seen.add(trimmed);
|
|
1106
|
+
result.push(trimmed);
|
|
988
1107
|
}
|
|
1108
|
+
return result;
|
|
989
1109
|
}
|
|
990
1110
|
|
|
991
1111
|
function systemClassName(ctor) {
|
|
@@ -1091,7 +1211,7 @@ const gameObjectPause = (gameObjects) => {
|
|
|
1091
1211
|
}
|
|
1092
1212
|
};
|
|
1093
1213
|
class Game extends EventEmitter {
|
|
1094
|
-
constructor({ systems, frameRate = 60, autoStart = true, needScene = true, onSystemsBootstrapComplete, pluginInitNotifyTargetOrigin = "*", } = {}) {
|
|
1214
|
+
constructor({ systems, frameRate = 60, autoStart = true, needScene = true, onSystemsBootstrapComplete, pluginInitNotifyTargetOrigin = "*", allowedMessageOrigins, } = {}) {
|
|
1095
1215
|
super();
|
|
1096
1216
|
/**
|
|
1097
1217
|
* State of game
|
|
@@ -1103,20 +1223,61 @@ class Game extends EventEmitter {
|
|
|
1103
1223
|
/** Systems alled to this game */
|
|
1104
1224
|
this.systems = [];
|
|
1105
1225
|
/**
|
|
1106
|
-
* Passed to `postMessage` when reporting
|
|
1226
|
+
* Passed to `postMessage` when reporting lifecycle events to `window.parent`
|
|
1227
|
+
* (`plugin-init-success`, `ready`, `state-changed`).
|
|
1107
1228
|
*/
|
|
1108
1229
|
this.pluginInitNotifyTargetOrigin = "*";
|
|
1230
|
+
/** Inbound `postMessage` origins allowed to send host commands. */
|
|
1231
|
+
this.allowedMessageOrigins = mergeAllowedMessageOrigins();
|
|
1232
|
+
/** Bound inbound `message` handler; retained so it can be removed on `destroy`. */
|
|
1233
|
+
this.onHostMessage = (e) => {
|
|
1234
|
+
if (!isAllowedMessageOrigin(e.origin, this.allowedMessageOrigins))
|
|
1235
|
+
return;
|
|
1236
|
+
const playing = parseSetPlayingMessage(e.data);
|
|
1237
|
+
if (playing === null)
|
|
1238
|
+
return;
|
|
1239
|
+
this.setPlaying(playing);
|
|
1240
|
+
};
|
|
1109
1241
|
this.pluginInitNotifyTargetOrigin = pluginInitNotifyTargetOrigin;
|
|
1242
|
+
this.allowedMessageOrigins = mergeAllowedMessageOrigins(allowedMessageOrigins);
|
|
1110
1243
|
this.ticker = new Ticker({ autoStart: false, frameRate });
|
|
1111
1244
|
this.initTicker();
|
|
1245
|
+
if (typeof window !== "undefined") {
|
|
1246
|
+
window.addEventListener("message", this.onHostMessage);
|
|
1247
|
+
}
|
|
1112
1248
|
if (systems && systems.length) {
|
|
1113
1249
|
const systemsToAdd = [...systems];
|
|
1114
1250
|
void this.bootstrapSystemsAndMaybeStart(systemsToAdd, needScene, autoStart, onSystemsBootstrapComplete);
|
|
1115
1251
|
}
|
|
1116
1252
|
else {
|
|
1117
1253
|
onSystemsBootstrapComplete?.(this);
|
|
1254
|
+
this.notifyReady();
|
|
1118
1255
|
}
|
|
1119
1256
|
}
|
|
1257
|
+
/**
|
|
1258
|
+
* Host command bridge: `true` cold-starts on first play (`start`), otherwise
|
|
1259
|
+
* `resume`s; `false` pauses. Mirrors what a parent frame drives via
|
|
1260
|
+
* `postMessage({ type: 'combos-game:set-playing', playing })`.
|
|
1261
|
+
*/
|
|
1262
|
+
setPlaying(playing) {
|
|
1263
|
+
if (playing) {
|
|
1264
|
+
if (this.started) {
|
|
1265
|
+
this.resume();
|
|
1266
|
+
}
|
|
1267
|
+
else {
|
|
1268
|
+
this.start();
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
else {
|
|
1272
|
+
this.pause();
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
notifyReady(error) {
|
|
1276
|
+
postParentGameReady(error, this.pluginInitNotifyTargetOrigin);
|
|
1277
|
+
}
|
|
1278
|
+
notifyStateChanged() {
|
|
1279
|
+
postParentGameState({ playing: this.playing, started: this.started }, this.pluginInitNotifyTargetOrigin);
|
|
1280
|
+
}
|
|
1120
1281
|
/** When `systems` is passed in the constructor, run async `init` for each before `loadScene` / `start`. */
|
|
1121
1282
|
async bootstrapSystemsAndMaybeStart(systemsToAdd, needScene, autoStart, onComplete) {
|
|
1122
1283
|
let error;
|
|
@@ -1137,6 +1298,7 @@ class Game extends EventEmitter {
|
|
|
1137
1298
|
}
|
|
1138
1299
|
finally {
|
|
1139
1300
|
onComplete?.(this, error);
|
|
1301
|
+
this.notifyReady(error);
|
|
1140
1302
|
}
|
|
1141
1303
|
}
|
|
1142
1304
|
/**
|
|
@@ -1239,6 +1401,7 @@ class Game extends EventEmitter {
|
|
|
1239
1401
|
this.playing = false;
|
|
1240
1402
|
this.ticker.pause();
|
|
1241
1403
|
this.triggerPause();
|
|
1404
|
+
this.notifyStateChanged();
|
|
1242
1405
|
}
|
|
1243
1406
|
/** Start game */
|
|
1244
1407
|
start() {
|
|
@@ -1247,6 +1410,7 @@ class Game extends EventEmitter {
|
|
|
1247
1410
|
this.playing = true;
|
|
1248
1411
|
this.started = true;
|
|
1249
1412
|
this.ticker.start();
|
|
1413
|
+
this.notifyStateChanged();
|
|
1250
1414
|
}
|
|
1251
1415
|
/** Resume game */
|
|
1252
1416
|
resume() {
|
|
@@ -1255,6 +1419,7 @@ class Game extends EventEmitter {
|
|
|
1255
1419
|
this.playing = true;
|
|
1256
1420
|
this.ticker.start();
|
|
1257
1421
|
this.triggerResume();
|
|
1422
|
+
this.notifyStateChanged();
|
|
1258
1423
|
}
|
|
1259
1424
|
/**
|
|
1260
1425
|
* add main render method to ticker
|
|
@@ -1321,6 +1486,9 @@ class Game extends EventEmitter {
|
|
|
1321
1486
|
}
|
|
1322
1487
|
/** Destroy game instance */
|
|
1323
1488
|
destroy() {
|
|
1489
|
+
if (typeof window !== "undefined") {
|
|
1490
|
+
window.removeEventListener("message", this.onHostMessage);
|
|
1491
|
+
}
|
|
1324
1492
|
this.removeAllListeners();
|
|
1325
1493
|
this.pause();
|
|
1326
1494
|
this.scene.destroy();
|
|
@@ -1721,5 +1889,5 @@ const decorators = {
|
|
|
1721
1889
|
};
|
|
1722
1890
|
console.log(`@combos-fun/engine version: ${version}`);
|
|
1723
1891
|
|
|
1724
|
-
export { COMBOS_GAME_PLUGIN_INIT_SUCCESS, Component, Game, GameObject, IDEProp, LOAD_EVENT, LOAD_SCENE_MODE, ObserverType as OBSERVER_TYPE, RESOURCE_TYPE, RESOURCE_TYPE_STRATEGY, Scene, System, Transform, componentObserver, decorators, postParentPluginInitSuccess, resource, resourceLoader, version };
|
|
1892
|
+
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 };
|
|
1725
1893
|
//# sourceMappingURL=engine.esm.js.map
|