UNPKG

wolf-ecs

Version:

An entity component system framework for JavaScript and TypeScript

2 lines (1 loc) 5.63 kB
const t={custom:function(t){return t?[t]:[]},any:Array,int8:Int8Array,i8:Int8Array,char:Int8Array,uint8:Uint8Array,u8:Uint8Array,uchar:Uint8Array,int16:Int16Array,i16:Int16Array,short:Int16Array,uint16:Uint16Array,u16:Uint16Array,ushort:Uint16Array,int32:Int32Array,i32:Int32Array,int:Int32Array,uint32:Uint32Array,u32:Uint32Array,uint:Uint32Array,float32:Float32Array,f32:Float32Array,float:Float32Array,float64:Float64Array,f64:Float64Array,double:Float64Array,int64:BigInt64Array,bigint64:BigInt64Array,i64:BigInt64Array,long:BigInt64Array,uint64:BigUint64Array,biguint64:BigUint64Array,u64:BigUint64Array,ulong:BigUint64Array},r=Symbol("componentData");function e(t,r){if("function"==typeof t)return new t(r);if(t instanceof Array)return t.length?[...new Array(r)].map(t[0]):new Array(r);const s={};for(let n in t)s[n]=e(t[n],r);return s}function s(...t){if(!t.length)throw new Error("no arguments passed");return{op:s,dt:t}}function n(t){return{op:n,dt:"function"==typeof t.op?t:s(t)}}function i(...t){if(!t.length)throw new Error("no arguments passed");return{op:i,dt:t}}class h{mask;archetypes=[];ecs;constructor(t,e){const i=e=>{if(e.op===n)return{op:e.op,dt:i(e.dt)};const s=[],h=[{op:e.op,dt:new Uint32Array}];for(let n of e.dt)if(r in n){if(n[r].ecs!==t)throw new Error("component does not belong to this ECS");s.push(n[r].id)}else h.push(i(n));h[0].dt=new Uint32Array(Math.ceil((Math.max(-1,...s)+1)/32));for(let t of s)h[0].dt[Math.floor(t/32)]|=1<<t%32;return{op:e.op,dt:h}};this.mask=e?i(e):{op:s,dt:new Uint32Array},this.ecs=t}forEach(t){for(let r=0,e=this.archetypes.length;r<e;r++){const e=this.archetypes[r].entities;for(let r=e.length;r>0;r--)t(e[r-1],this.ecs)}}_forEach(t){this.forEach(t)}static match(t,r){if("BYTES_PER_ELEMENT"in r.dt)return h.partial(t,r);if(r.op===n)return!h.match(t,r.dt);if(r.op===s){for(let e of r.dt)if(!h.match(t,e))return!1;return!0}for(let e of r.dt)if(h.match(t,e))return!0;return!1}static partial(t,r){if(r.op===s){for(let e=0;e<r.dt.length;e++)if((t[e]&r.dt[e])<r.dt[e])return!1;return!0}for(let e=0;e<r.dt.length;e++)if((t[e]&r.dt[e])>0)return!0;return!1}}class a{packed=[];sparse=[];has(t){return this.sparse[t]<this.packed.length&&this.packed[this.sparse[t]]===t}add(t){this.has(t)||(this.sparse[t]=this.packed.length,this.packed.push(t))}remove(t){if(this.has(t)){const r=this.packed.pop();t!==r&&(this.sparse[r]=this.sparse[t],this.packed[this.sparse[t]]=r)}}}class o{sset=new a;entities=this.sset.packed;mask;change=[];constructor(t){this.mask=t}has(t){return this.sset.has(t)}}class c{_arch=new Map;_ent=[];_queries=[];_destroy;_mcmp={addrm:[],ent:[],cmp:[]};_rm;_empty;cmpID=0;entID=0;MAX_ENTITIES;DEFAULT_DEFER;constructor(t=1e4,r=!1){this.MAX_ENTITIES=t,this.DEFAULT_DEFER=r,this._destroy=new a,this._rm=new a,this._empty=new o(new Uint32Array)}bind(){const t=c.prototype,r={};for(let e of Object.getOwnPropertyNames(t))"function"==typeof t[e]&&"bind"!==e&&(r[e]=t[e].bind(this));return r}defineComponent(t={}){if(this.entID)throw new Error("cannot define component after entity creation");return this.registerComponent(e(t,this.MAX_ENTITIES))}registerComponent(t){return Object.assign(t,{[r]:{ecs:this,id:this.cmpID++}})}_initEmpty(){this._empty.mask=new Uint32Array(Math.ceil(this.cmpID/32)),this._arch.set(this._empty.mask.toString(),this._empty)}createQuery(...t){const r=new h(this,s(...t));return this._arch.forEach((t=>{h.match(t.mask,r.mask)&&r.archetypes.push(t)})),this._queries.push(r),r}_validID(t){return"number"==typeof t&&!(this._rm.has(t)||this.entID<=t)}_getArch(t){if(!this._arch.has(t.toString())){const r=new o(t.slice());this._arch.set(t.toString(),r);for(let e of this._queries)h.match(t,e.mask)&&e.archetypes.push(r)}return this._arch.get(t.toString())}_hasComponent(t,r){return t[Math.floor(r/32)]&1<<r%32}_archChange(t,r){const e=this._ent[t];e.sset.remove(t),e.change[r]||(this._hasComponent(e.mask,r)?(e.mask[Math.floor(r/32)]&=~(1<<r%32),e.change[r]=this._getArch(e.mask),e.mask[Math.floor(r/32)]|=1<<r%32):(e.mask[Math.floor(r/32)]|=1<<r%32,e.change[r]=this._getArch(e.mask),e.mask[Math.floor(r/32)]&=~(1<<r%32))),this._ent[t]=e.change[r],this._ent[t].sset.add(t)}_crEnt(t){this._ent[t]=this._empty,this._empty.sset.add(t)}createEntity(){if(this._rm.packed.length){const t=this._rm.packed.pop();return this._crEnt(t),t}if(this.entID||this._initEmpty(),this.entID===this.MAX_ENTITIES)throw new Error("maximum entity limit reached");return this._crEnt(this.entID),this.entID++}destroyEntity(t,r=this.DEFAULT_DEFER){r?this._destroy.add(t):(this._ent[t].sset.remove(t),this._destroy.remove(t),this._rm.add(t))}destroyPending(){for(;this._destroy.packed.length>0;)this.destroyEntity(this._destroy.packed[0]);this._destroy.packed.length=0}_addcmp(t,r){this._hasComponent(this._ent[t].mask,r)||this._archChange(t,r)}addComponent(t,e,s=this.DEFAULT_DEFER){if(!this._validID(t))throw new Error("invalid entity id");const n=e[r].id;return s?(this._mcmp.addrm.push(!0),this._mcmp.ent.push(t),this._mcmp.cmp.push(n)):this._addcmp(t,n),this}_rmcmp(t,r){this._hasComponent(this._ent[t].mask,r)&&this._archChange(t,r)}removeComponent(t,e,s=this.DEFAULT_DEFER){if(!this._validID(t))throw new Error("invalid entity id");const n=e[r].id;return s?(this._mcmp.addrm.push(!1),this._mcmp.ent.push(t),this._mcmp.cmp.push(n)):this._rmcmp(t,n),this}updatePending(){for(let t=this._mcmp.addrm.length-1;t>=0;t--)this._validID(this._mcmp.ent[t])&&(this._mcmp.addrm[t]?this._addcmp(this._mcmp.ent[t],this._mcmp.cmp[t]):this._rmcmp(this._mcmp.ent[t],this._mcmp.cmp[t]));this._mcmp={addrm:[],ent:[],cmp:[]}}}export{c as ECS,s as all,i as any,n as not,t as types};