Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

bitecs

Package Overview
Dependencies
Maintainers
1
Versions
133
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bitecs - npm Package Compare versions

Comparing version 0.2.15 to 0.2.16

773

dist/index.es.js

@@ -1,2 +0,773 @@

const e={bool:"Uint8",i8:"Int8",ui8:"Uint8",ui8c:"Uint8Clamped",i16:"Int16",ui16:"Uint16",i32:"Int32",ui32:"Uint32",f32:"Float32",f64:"Float64"},t={bool:"bool",i8:Int8Array,ui8:Uint8Array,ui8c:Uint8ClampedArray,i16:Int16Array,ui16:Uint16Array,i32:Int32Array,ui32:Uint32Array,f32:Float32Array,f64:Float64Array},n=256,r=65536,o=e=>4*Math.ceil(e/4),s=Symbol("storeRef"),i=Symbol("storeSize"),a=Symbol("storeMaps"),c=Symbol("storeFlattened"),l=Symbol("storeArrayCount"),u=Symbol("storeSubarrays"),f=Symbol("storeCursor"),y=Symbol("subarrayCursors"),d=Symbol("subarray"),g=Symbol("queryShadow"),b=Symbol("serializeShadow"),h=Symbol("indexType"),p=Symbol("indexBytes"),m={},E=(e,t)=>{const n=new ArrayBuffer(t*e.BYTES_PER_ELEMENT),r=new e.constructor(n);return r.set(e,0),r},S=(e,t)=>{Object.keys(e).forEach((n=>{const r=e[n];r[d]||(ArrayBuffer.isView(r)?(e[n]=E(r,t),e[n][g]=E(r[g],t),e[n][b]=E(r[b],t)):"object"==typeof r&&S(e[n],t))}))},A=(e,n)=>{e[i]=n,S(e,n),(e=>{const n=e[i],r=e[y]={};Object.keys(e[u]).forEach((s=>{const i=e[l],a=e[0].length,c=Array(i).fill(0).reduce(((e,n)=>e+t[s].BYTES_PER_ELEMENT),0),f=Array(i).fill(0).reduce(((e,t)=>e+a),0),y=new ArrayBuffer(o(c*f*n)),g=new t[s](y);g.set(e[u][s].buffer,0),e[u][s]=g;for(let t=0;t<n;t++){const n=r[s]+t*a,o=n+a;e[t]=e[u][s].subarray(n,o),e[t][d]=!0}}))})(e)},w=(e,n)=>{const r=n*t[e].BYTES_PER_ELEMENT,o=new ArrayBuffer(r);return new t[e](o)},_=(s,a,c)=>{const f=s[i],m=s[y],E=c<n?"ui8":c<r?"ui16":"ui32";if(!c)throw new Error("❌ Must define a length for component array.");if(!t[a])throw new Error(`❌ Invalid component array property type ${a}.`);if(!s[u][a]){const n=s[l],r=Array(n).fill(0).reduce(((e,n)=>e+t[a].BYTES_PER_ELEMENT),0),i=Array(n).fill(0).reduce(((e,t)=>e+c),0),y=o(r*i*f),d=new ArrayBuffer(y),m=new t[a](d);s[u][a]=m,s[u][a][g]=m.slice(0),s[u][a][b]=m.slice(0),m[h]=e[E],m[p]=t[E].BYTES_PER_ELEMENT}let S=0;for(let e=0;e<f;e++){const t=m[a]+e*c,n=t+c;s[e]=s[u][a].subarray(t,n),s[e][d]=!0,S=n}return m[a]=S,s},B=e=>{e[g]=e.slice(0),e[b]=e.slice(0)},M=e=>Array.isArray(e)&&"object"==typeof e[0]&&e[0].hasOwnProperty("type")&&e[0].hasOwnProperty("length"),T=Symbol("entityMasks"),U=Symbol("entityEnabled"),I=Symbol("deferredEntityRemovals"),j=Symbol("removedEntities");let O=0;const R=e=>{const t=e[j],n=e[ae],r=e[U];if(O>=n-n/5){const t=4*Math.ceil(n/2/4);e[ae]+=t,e[Z].forEach((t=>{A(t.store,e[ae])})),e[Y].forEach((t=>{t.indices=E(t.indices,e[ae]),t.enabled=E(t.enabled,e[ae])}))}const o=t.length>0?t.pop():O;return r[o]=1,O++,o},k=(e,t)=>{const n=e[L],r=e[j],o=e[U];if(0!==o[t]){n.forEach((n=>{X(e,n,t)})),r.push(t),o[t]=0;for(let n=0;n<e[T].length;n++)e[T][n][t]=0}},P=e=>{let t,n=new Set;return Array.isArray(e)?t=e.map((e=>{if(e._flatten)return e._flatten();if("function"==typeof e&&"QueryChanged"===e.name){if((e=e())._flatten){let t=e._flatten();return t.forEach((e=>n.add(e))),t}return n.add(e),[e]}})).reduce(((e,t)=>e.concat(t)),[]):e[Z].forEach((e=>{t=t.concat(e._flatten())})),[t,n]},C=(e,t=5e6)=>{const n=new ArrayBuffer(t),r=new DataView(n),[o,s]=P(e);return e=>{if(!e.length)return;let t=0;for(let n=0;n<o.length;n++){const i=o[n],a=s.has(i);r.setUint8(t,n),t+=1;const c=t;t+=4;let l=0;for(let n=0;n<e.length;n++){const o=e[n];if(!a||i[o]!==i[b][o])if(l++,r.setUint32(t,o),t+=4,ArrayBuffer.isView(i[o])){const e=i[o].constructor.name.replace("Array",""),n=i[o]._indexType,s=i[o]._indexBytes,a=t;t+=1;let c=0;for(let a=0;a<i[o].length;a++){const l=i[o][a];r["set"+n](t,a),t+=s,r["set"+e](t,l),t+=i[o].BYTES_PER_ELEMENT,c++}r["set"+n](a,c)}else{const e=i.constructor.name.replace("Array","");r["set"+e](t,i[o]),t+=i.BYTES_PER_ELEMENT,i[b]||console.log(i),i[b][o]=i[o]}}r.setUint32(c,l)}return n.slice(0,t)}},v=e=>{const[t]=P(e);return e=>{const n=new DataView(e);let r=0;const o=n.getUint8(r);r+=1;const s=n.getUint32(r);r+=4;const i=t[o];for(let e=0;e<s;e++){const e=n.getUint32(r);if(r+=4,ArrayBuffer.isView(i[e])){const t=i[e],o=n["get"+t._indexType];r+=t._indexBytes;for(let s=0;s<o;s++){const o=n["get"+t.constructor.name.replace("Array","")](r);r+=t.BYTES_PER_ELEMENT,i[e][s]=o}}else{let t=n["get"+i.constructor.name.replace("Array","")](r);r+=i.BYTES_PER_ELEMENT,i[e]=t}}}};function x(e){return function(){return e}}function N(e){return function(){return e}}const L=Symbol("queries"),Y=Symbol("queryMap"),V=Symbol("$dirtyQueries"),F=Symbol("queryComponents"),q=2**32,Q=(e,t,n)=>{e[Y].has(t)||$(e,t),e[Y].get(t).enter=n},z=(e,t,n)=>{e[Y].has(t)||$(e,t),e[Y].get(t).exit=n},$=(e,t)=>{e[Y].has(t)||e[Y].set(t,{});let n=[],r=[],o=[];t[F].forEach((e=>{"function"==typeof e?("QueryNot"===e.name&&r.push(e()),"QueryChanged"===e.name&&(o.push(e()),n.push(e()))):n.push(e)}));const s=t=>e[Z].get(t),a=n.reduce(((e,t)=>t[i]>e?t[i]:e),0),c=new Uint32Array(a).fill(q),l=new Uint8Array(a),u=n.concat(r).map((t=>(e[Z].has(t)||ne(e,t),t))).map(s).map((e=>e.generationId)).reduce(((e,t)=>(e.includes(t)||e.push(t),e)),[]),f=n.map(s).reduce(((e,t)=>(e[t.generationId]||(e[t.generationId]=0),e[t.generationId]|=t.bitflag,e)),{}),y=r.map(s).reduce(((e,t)=>(e[t.generationId]||(e[t.generationId]=0,e[t.generationId]|=t.bitflag),e)),{}),d=n.map((e=>e._flatten?e._flatten():[e])).reduce(((e,t)=>e.concat(t)),[]);Object.assign(e[Y].get(t),{entities:[],changed:[],enabled:l,components:n,notComponents:r,changedComponents:o,masks:f,notMasks:y,generations:u,indices:c,flatProps:d,toRemove:[]}),e[L].add(t);for(let n=0;n<O;n++)e[U][n]&&G(e,t,n)&&J(e,t,n)},D=e=>{const t=function(e){e[Y].has(t)||$(e,t),K(e,t);const n=e[Y].get(t);return n.changedComponents.length?((e,t)=>{const n=e[Y].get(t);n.changed.length=0;const r=n.flatProps;for(let e=0;e<n.entities.length;e++){const t=n.entities[e];let o=!1;for(let e=0;e<r.length;e++){const n=r[e];if(ArrayBuffer.isView(n[t]))for(let e=0;e<n[t].length;e++)n[t][e]!==n[t][g][e]&&(o=!0,n[t][g][e]=n[t][e]);else n[t]!==n[g][t]&&(o=!0,n[g][t]=n[t])}o&&n.changed.push(t)}return n.changed})(e,t):n.entities};return t[F]=e,t},G=(e,t,n)=>{const{masks:r,notMasks:o,generations:s}=e[Y].get(t);for(let t=0;t<s.length;t++){const i=s[t],a=r[i],c=o[i],l=e[T][i][n];if(c&&0!=(l&c))return!1;if(a&&(l&a)!==a)return!1}return!0},H=(e,t,n)=>n.every((n=>((e,t,n)=>{const{generationId:r,bitflag:o}=e[Z].get(n),{masks:s}=e[Y].get(t);return(s[r]&o)===o})(e,t,n))),J=(e,t,n)=>{const r=e[Y].get(t);r.enabled[n]||(r.enabled[n]=!0,r.entities.push(n),r.indices[n]=r.entities.length-1,r.enter&&r.enter(n))},K=(e,t)=>{const n=e[Y].get(t);for(;n.toRemove.length;){const e=n.toRemove.pop(),t=n.indices[e];if(t===q)continue;const r=n.entities.pop();r!==e&&(n.entities[t]=r,n.indices[r]=t),n.indices[e]=q}e[V].delete(n)},W=e=>{e[V].forEach((e=>{K(e)}))},X=(e,t,n)=>{const r=e[Y].get(t);r.enabled[n]&&(r.enabled[n]=!1,r.exit&&r.exit(n),r.toRemove.push(n),e[V].add(r))},Z=Symbol("componentMap"),ee=Symbol("de$deferredComponentRemovals"),te=e=>((e,n=1e6)=>{const r=Symbol("store");if("Map"===e.constructor.name)return e[i]=n,e;const o=(t,n)=>(M(e[n])?t++:e[n]instanceof Object&&(t+=Object.keys(e[n]).reduce(o,0)),t),d=M(e)?1:Object.keys(e).reduce(o,0),g={[i]:n,[a]:{},[u]:{},[s]:r,[f]:0,[y]:Object.keys(t).reduce(((e,t)=>({...e,[t]:0})),{}),[l]:d,[c]:[]};if("string"==typeof e)return m[r]=Object.assign(w(e,n),g),g[c].push(m[r]),B(m[r]),m[r];if(M(e)){const{type:t,length:n}=e[0];return m[r]=Object.assign(_(g,t,n),g),g[c].push(m[r]),m[r]}if(e instanceof Object&&Object.keys(e).length){const t=(e,r)=>{if("string"==typeof e[r])e[r]=w(e[r],n),g[c].push(e[r]),B(e[r]);else if(M(e[r])){const{type:t,length:n}=e[r][0];e[r]=_(g,t,n)}else e[r]instanceof Object&&(e[r]=Object.keys(e[r]).reduce(t,e[r]));return e};return m[r]=Object.assign(Object.keys(e).reduce(t,e),g),m[r]}return{}})(e),ne=(e,t)=>{e[Z].set(t,{generationId:e[T].length-1,bitflag:e[ce],store:t}),(e=>{e[ce]*=2,e[ce]>=2**32&&(e[ce]=1,e[T].push(new Uint32Array(e[ae])))})(e)},re=(e,t)=>{t.forEach((t=>ne(e,t)))},oe=(e,t,n)=>{const{generationId:r,bitflag:o}=e[Z].get(t);return(e[T][r][n]&o)===o},se=(e,t,n)=>{if(e[Z].has(t)||ne(e,t),oe(e,t,n))return;const{generationId:r,bitflag:o}=e[Z].get(t);e[T][r][n]|=o;e[L].forEach((t=>{const r=t[F];if(!H(e,t,r))return;G(e,t,n)&&J(e,t,n)}))},ie=(e,t,n)=>{const{generationId:r,bitflag:o}=e[Z].get(t);if(!(e[T][r][n]&o))return;e[L].forEach((t=>{const r=t[F];if(!H(e,t,r))return;G(e,t,n)&&X(e,t,n)})),e[T][r][n]&=~o},ae=Symbol("size"),ce=Symbol("bitflag"),le=(e=1e6)=>{const t={};return t[ae]=e,t[U]=new Uint8Array(e),t[T]=[new Uint32Array(e)],t[j]=[],t[ce]=1,t[Z]=new Map,t[Y]=new Map,t[L]=new Set,t[V]=new Set,t[ee]=[],t[I]=[],t},ue=e=>{const t=t=>{e(t),W(t)};return Object.defineProperty(t,"name",{value:(e.name||"AnonymousSystem")+"_internal",configurable:!0}),t},fe=(...e)=>t=>{e=Array.isArray(e[0])?e[0]:e;for(let n=0;n<e.length;n++){(0,e[n])(t)}},ye={bool:"bool",i8:"i8",ui8:"ui8",ui8c:"ui8c",i16:"i16",ui16:"ui16",i32:"i32",ui32:"ui32",f32:"f32",f64:"f64"};export{N as Changed,x as Not,ye as Types,se as addComponent,R as addEntity,W as commitRemovals,le as createWorld,te as defineComponent,v as defineDeserializer,D as defineQuery,C as defineSerializer,ue as defineSystem,Q as enterQuery,z as exitQuery,oe as hasComponent,fe as pipe,ne as registerComponent,re as registerComponents,ie as removeComponent,k as removeEntity};
const TYPES_ENUM = {
bool: 'bool',
i8: 'i8',
ui8: 'ui8',
ui8c: 'ui8c',
i16: 'i16',
ui16: 'ui16',
i32: 'i32',
ui32: 'ui32',
f32: 'f32',
f64: 'f64'
};
const TYPES_NAMES = {
bool: 'Uint8',
i8: 'Int8',
ui8: 'Uint8',
ui8c: 'Uint8Clamped',
i16: 'Int16',
ui16: 'Uint16',
i32: 'Int32',
ui32: 'Uint32',
f32: 'Float32',
f64: 'Float64'
};
const TYPES = {
bool: 'bool',
i8: Int8Array,
ui8: Uint8Array,
ui8c: Uint8ClampedArray,
i16: Int16Array,
ui16: Uint16Array,
i32: Int32Array,
ui32: Uint32Array,
f32: Float32Array,
f64: Float64Array
};
const UNSIGNED_MAX = {
uint8: 2 ** 8,
uint16: 2 ** 16,
uint32: 2 ** 32
};
const roundToMultiple4 = x => Math.ceil(x / 4) * 4;
const $storeRef = Symbol('storeRef');
const $storeSize = Symbol('storeSize');
const $storeMaps = Symbol('storeMaps');
const $storeFlattened = Symbol('storeFlattened');
const $storeArrayCount = Symbol('storeArrayCount');
const $storeSubarrays = Symbol('storeSubarrays');
const $storeCursor = Symbol('storeCursor');
const $subarrayCursors = Symbol('subarrayCursors');
const $subarray = Symbol('subarray');
const $queryShadow = Symbol('queryShadow');
const $serializeShadow = Symbol('serializeShadow');
const $indexType = Symbol('indexType');
const $indexBytes = Symbol('indexBytes');
const stores = {};
const resize = (ta, size) => {
const newBuffer = new ArrayBuffer(size * ta.BYTES_PER_ELEMENT);
const newTa = new ta.constructor(newBuffer);
newTa.set(ta, 0);
return newTa;
};
const resizeRecursive = (store, size) => {
Object.keys(store).forEach(key => {
const ta = store[key];
if (ta[$subarray]) return;else if (ArrayBuffer.isView(ta)) {
store[key] = resize(ta, size);
store[key][$queryShadow] = resize(ta[$queryShadow], size);
store[key][$serializeShadow] = resize(ta[$serializeShadow], size);
} else if (typeof ta === 'object') {
resizeRecursive(store[key], size);
}
});
};
const resizeSubarrays = (store, size) => {
const cursors = store[$subarrayCursors] = {};
Object.keys(store[$storeSubarrays]).forEach(type => {
const arrayCount = store[$storeArrayCount];
const length = store[0].length;
const summedBytesPerElement = Array(arrayCount).fill(0).reduce((a, p) => a + TYPES[type].BYTES_PER_ELEMENT, 0);
const summedLength = Array(arrayCount).fill(0).reduce((a, p) => a + length, 0);
const buffer = new ArrayBuffer(roundToMultiple4(summedBytesPerElement * summedLength * size));
const array = new TYPES[type](buffer);
array.set(store[$storeSubarrays][type].buffer, 0);
store[$storeSubarrays][type] = array;
store[$storeSubarrays][type][$queryShadow] = array.slice(0);
store[$storeSubarrays][type][$serializeShadow] = array.slice(0);
for (let eid = 0; eid < size; eid++) {
const from = cursors[type] + eid * length;
const to = from + length;
store[eid] = store[$storeSubarrays][type].subarray(from, to);
store[eid][$queryShadow] = store[$storeSubarrays][type][$queryShadow].subarray(from, to);
store[eid][$serializeShadow] = store[$storeSubarrays][type][$serializeShadow].subarray(from, to);
store[eid][$subarray] = true;
store[eid][$indexType] = array[$indexType];
store[eid][$indexBytes] = array[$indexBytes];
}
});
};
const resizeStore = (store, size) => {
store[$storeSize] = size;
resizeRecursive(store, size);
resizeSubarrays(store, size);
};
const createTypeStore = (type, length) => {
const totalBytes = length * TYPES[type].BYTES_PER_ELEMENT;
const buffer = new ArrayBuffer(totalBytes);
return new TYPES[type](buffer);
};
const createArrayStore = (store, type, length) => {
const size = store[$storeSize];
const cursors = store[$subarrayCursors];
const indexType = length < UNSIGNED_MAX.uint8 ? 'ui8' : length < UNSIGNED_MAX.uint16 ? 'ui16' : 'ui32';
if (!length) throw new Error('❌ Must define a length for component array.');
if (!TYPES[type]) throw new Error(`❌ Invalid component array property type ${type}.`); // create buffer for type if it does not already exist
if (!store[$storeSubarrays][type]) {
const arrayCount = store[$storeArrayCount];
const summedBytesPerElement = Array(arrayCount).fill(0).reduce((a, p) => a + TYPES[type].BYTES_PER_ELEMENT, 0);
const summedLength = Array(arrayCount).fill(0).reduce((a, p) => a + length, 0);
const totalBytes = roundToMultiple4(summedBytesPerElement * summedLength * size);
const buffer = new ArrayBuffer(totalBytes);
const array = new TYPES[type](buffer);
store[$storeSubarrays][type] = array;
store[$storeSubarrays][type][$queryShadow] = array.slice(0);
store[$storeSubarrays][type][$serializeShadow] = array.slice(0);
array[$indexType] = TYPES_NAMES[indexType];
array[$indexBytes] = TYPES[indexType].BYTES_PER_ELEMENT;
} // pre-generate subarrays for each eid
let end = 0;
for (let eid = 0; eid < size; eid++) {
const from = cursors[type] + eid * length;
const to = from + length;
store[eid] = store[$storeSubarrays][type].subarray(from, to);
store[eid][$queryShadow] = store[$storeSubarrays][type][$queryShadow].subarray(from, to);
store[eid][$serializeShadow] = store[$storeSubarrays][type][$serializeShadow].subarray(from, to);
store[eid][$subarray] = true;
store[eid][$indexType] = TYPES_NAMES[indexType];
store[eid][$indexBytes] = TYPES[indexType].BYTES_PER_ELEMENT;
end = to;
}
cursors[type] = end;
return store;
};
const createShadows = store => {
store[$queryShadow] = store.slice(0);
store[$serializeShadow] = store.slice(0);
};
const isArrayType = x => Array.isArray(x) && typeof x[0] === 'object' && x[0].hasOwnProperty('type') && x[0].hasOwnProperty('length');
const createStore = (schema, size = 1000000) => {
const $store = Symbol('store');
schema = JSON.parse(JSON.stringify(schema));
if (schema.constructor.name === 'Map') {
schema[$storeSize] = size;
return schema;
}
const collectArrayCount = (count, key) => {
if (isArrayType(schema[key])) {
count++;
} else if (schema[key] instanceof Object) {
count += Object.keys(schema[key]).reduce(collectArrayCount, 0);
}
return count;
};
const arrayCount = isArrayType(schema) ? 1 : Object.keys(schema).reduce(collectArrayCount, 0);
const metadata = {
[$storeSize]: size,
[$storeMaps]: {},
[$storeSubarrays]: {},
[$storeRef]: $store,
[$storeCursor]: 0,
[$subarrayCursors]: Object.keys(TYPES).reduce((a, type) => ({ ...a,
[type]: 0
}), {}),
[$storeArrayCount]: arrayCount,
[$storeFlattened]: []
};
if (typeof schema === 'string') {
stores[$store] = Object.assign(createTypeStore(schema, size), metadata);
metadata[$storeFlattened].push(stores[$store]);
createShadows(stores[$store]);
return stores[$store];
} else if (isArrayType(schema)) {
const {
type,
length
} = schema[0];
stores[$store] = Object.assign(createArrayStore(metadata, type, length), metadata);
metadata[$storeFlattened].push(stores[$store]);
return stores[$store];
} else if (schema instanceof Object && Object.keys(schema).length) {
const recursiveTransform = (a, k) => {
if (typeof a[k] === 'string') {
a[k] = createTypeStore(a[k], size);
metadata[$storeFlattened].push(a[k]);
createShadows(a[k]);
} else if (isArrayType(a[k])) {
const {
type,
length
} = a[k][0];
a[k] = createArrayStore(metadata, type, length);
metadata[$storeFlattened].push(a[k]);
} else if (a[k] instanceof Object) {
a[k] = Object.keys(a[k]).reduce(recursiveTransform, a[k]);
}
return a;
};
stores[$store] = Object.assign(Object.keys(schema).reduce(recursiveTransform, schema), metadata);
return stores[$store];
}
return {};
};
const $entityMasks = Symbol('entityMasks');
const $entityEnabled = Symbol('entityEnabled');
const $deferredEntityRemovals = Symbol('deferredEntityRemovals');
const $removedEntities = Symbol('removedEntities'); // need a global EID cursor which all worlds and all components know about
// so that world entities can posess entire rows spanning all component tables
let globalEntityCursor = 0;
const getEntityCursor = () => globalEntityCursor;
const resizeWorld = (world, size) => {
world[$size] = size;
world[$componentMap].forEach(c => {
resizeStore(c.store, size);
});
world[$queryMap].forEach(q => {
q.indices = resize(q.indices, size);
q.enabled = resize(q.enabled, size);
});
world[$entityEnabled] = resize(world[$entityEnabled], size);
for (let i = 0; i < world[$entityMasks].length; i++) {
const masks = world[$entityMasks][i];
world[$entityMasks][i] = resize(masks, size);
}
};
const addEntity = world => {
const removed = world[$removedEntities];
const size = world[$size];
const enabled = world[$entityEnabled]; // if data stores are 80% full
if (globalEntityCursor >= size - size / 5) {
// grow by half the original size rounded up to a multiple of 4
const amount = Math.ceil(size / 2 / 4) * 4;
resizeWorld(world, size + amount);
}
const eid = removed.length > 0 ? removed.pop() : globalEntityCursor;
enabled[eid] = 1;
globalEntityCursor++;
return eid;
};
const removeEntity = (world, eid) => {
const queries = world[$queries];
const removed = world[$removedEntities];
const enabled = world[$entityEnabled]; // Check if entity is already removed
if (enabled[eid] === 0) return; // Remove entity from all queries
// TODO: archetype graph
queries.forEach(query => {
queryRemoveEntity(world, query, eid);
}); // Free the entity
removed.push(eid);
enabled[eid] = 0; // Clear entity bitmasks
for (let i = 0; i < world[$entityMasks].length; i++) world[$entityMasks][i][eid] = 0;
};
const diff = (world, query) => {
const q = world[$queryMap].get(query);
q.changed.length = 0;
const flat = q.flatProps;
for (let i = 0; i < q.entities.length; i++) {
const eid = q.entities[i];
let dirty = false;
for (let pid = 0; pid < flat.length; pid++) {
const prop = flat[pid];
if (ArrayBuffer.isView(prop[eid])) {
for (let i = 0; i < prop[eid].length; i++) {
if (prop[eid][i] !== prop[eid][$queryShadow][i]) {
dirty = true;
prop[eid][$queryShadow][i] = prop[eid][i];
}
}
} else {
if (prop[eid] !== prop[$queryShadow][eid]) {
dirty = true;
prop[$queryShadow][eid] = prop[eid];
}
}
}
if (dirty) q.changed.push(eid);
}
return q.changed;
};
const canonicalize = target => {
let componentProps;
let changedProps = new Set();
if (Array.isArray(target)) {
componentProps = target.map(p => {
if (typeof p === 'function' && p.name === 'QueryChanged') {
p()[$storeFlattened].forEach(prop => {
changedProps.add(prop);
});
return p()[$storeFlattened];
}
return p[$storeFlattened];
}).reduce((a, v) => a.concat(v), []);
} else {
target[$componentMap].forEach(c => {
componentProps = componentProps.concat(c[$storeFlattened]);
});
}
return [componentProps, changedProps];
};
const defineSerializer = (target, maxBytes = 20_000_000) => {
const [componentProps, changedProps] = canonicalize(target); // TODO: calculate max bytes based on target
const buffer = new ArrayBuffer(maxBytes);
const view = new DataView(buffer);
return ents => {
if (!ents.length) return;
let where = 0; // iterate over component props
for (let pid = 0; pid < componentProps.length; pid++) {
const prop = componentProps[pid];
const diff = changedProps.has(prop); // write pid
view.setUint8(where, pid);
where += 1; // save space for entity count
const countWhere = where;
where += 4;
let count = 0; // write eid,val
for (let i = 0; i < ents.length; i++) {
const eid = ents[i]; // skip if diffing and no change
if (diff && prop[eid] === prop[$serializeShadow][eid]) {
continue;
}
count++; // write eid
view.setUint32(where, eid);
where += 4; // if property is an array
if (ArrayBuffer.isView(prop[eid])) {
const type = prop[eid].constructor.name.replace('Array', '');
const indexType = prop[eid][$indexType];
const indexBytes = prop[eid][$indexBytes]; // add space for count of dirty array elements
const countWhere2 = where;
where += 1;
let count2 = 0; // write array values
for (let i = 0; i < prop[eid].length; i++) {
const value = prop[eid][i];
if (diff && prop[eid][i] === prop[eid][$serializeShadow][i]) {
continue;
} // write array index
view[`set${indexType}`](where, i);
where += indexBytes; // write value at that index
view[`set${type}`](where, value);
where += prop[eid].BYTES_PER_ELEMENT;
count2++;
}
view[`set${indexType}`](countWhere2, count2);
} else {
// regular property values
const type = prop.constructor.name.replace('Array', ''); // set value next [type] bytes
view[`set${type}`](where, prop[eid]);
where += prop.BYTES_PER_ELEMENT; // sync shadow state
prop[$serializeShadow][eid] = prop[eid];
}
}
view.setUint32(countWhere, count);
}
return buffer.slice(0, where);
};
};
const defineDeserializer = target => {
const [componentProps] = canonicalize(target);
return packet => {
const view = new DataView(packet);
let where = 0;
while (where < packet.byteLength) {
// pid
const pid = view.getUint8(where);
where += 1; // entity count
const entityCount = view.getUint32(where);
where += 4; // typed array
const ta = componentProps[pid]; // Get the properties and set the new state
for (let i = 0; i < entityCount; i++) {
const eid = view.getUint32(where);
where += 4;
if (ArrayBuffer.isView(ta[eid])) {
const array = ta[eid];
const count = view[`get${array[$indexType]}`](where);
where += array[$indexBytes]; // iterate over count
for (let i = 0; i < count; i++) {
const index = view[`get${array[$indexType]}`](where);
where += array[$indexBytes];
const value = view[`get${array.constructor.name.replace('Array', '')}`](where);
where += array.BYTES_PER_ELEMENT;
ta[eid][index] = value;
}
} else {
let value = view[`get${ta.constructor.name.replace('Array', '')}`](where);
where += ta.BYTES_PER_ELEMENT;
ta[eid] = value;
}
}
}
};
};
function Not(c) {
return function QueryNot() {
return c;
};
}
function Changed(c) {
return function QueryChanged() {
return c;
};
}
const $queries = Symbol('queries');
const $queryMap = Symbol('queryMap');
const $dirtyQueries = Symbol('$dirtyQueries');
const $queryComponents = Symbol('queryComponents');
const NONE = 2 ** 32;
const enterQuery = (world, query, fn) => {
if (!world[$queryMap].has(query)) registerQuery(world, query);
world[$queryMap].get(query).enter = fn;
};
const exitQuery = (world, query, fn) => {
if (!world[$queryMap].has(query)) registerQuery(world, query);
world[$queryMap].get(query).exit = fn;
};
const registerQuery = (world, query) => {
if (!world[$queryMap].has(query)) world[$queryMap].set(query, {});
let components = [];
let notComponents = [];
let changedComponents = [];
query[$queryComponents].forEach(c => {
if (typeof c === 'function') {
if (c.name === 'QueryNot') {
notComponents.push(c());
}
if (c.name === 'QueryChanged') {
changedComponents.push(c());
components.push(c());
}
} else {
components.push(c);
}
});
const mapComponents = c => world[$componentMap].get(c);
const size = components.reduce((a, c) => c[$storeSize] > a ? c[$storeSize] : a, 0);
const entities = [];
const changed = [];
const indices = new Uint32Array(size).fill(NONE);
const enabled = new Uint8Array(size);
const generations = components.concat(notComponents).map(c => {
if (!world[$componentMap].has(c)) registerComponent(world, c);
return c;
}).map(mapComponents).map(c => c.generationId).reduce((a, v) => {
if (a.includes(v)) return a;
a.push(v);
return a;
}, []);
const reduceBitmasks = (a, c) => {
if (!a[c.generationId]) a[c.generationId] = 0;
a[c.generationId] |= c.bitflag;
return a;
};
const masks = components.map(mapComponents).reduce(reduceBitmasks, {});
const notMasks = notComponents.map(mapComponents).reduce((a, c) => {
if (!a[c.generationId]) {
a[c.generationId] = 0;
a[c.generationId] |= c.bitflag;
}
return a;
}, {});
const flatProps = components.map(c => c._flatten ? c._flatten() : [c]).reduce((a, v) => a.concat(v), []);
const toRemove = [];
Object.assign(world[$queryMap].get(query), {
entities,
changed,
enabled,
components,
notComponents,
changedComponents,
masks,
notMasks,
generations,
indices,
flatProps,
toRemove
});
world[$queries].add(query);
for (let eid = 0; eid < getEntityCursor(); eid++) {
if (!world[$entityEnabled][eid]) continue;
if (queryCheckEntity(world, query, eid)) {
queryAddEntity(world, query, eid);
}
}
};
const defineQuery = components => {
const query = function (world) {
if (!world[$queryMap].has(query)) registerQuery(world, query);
queryCommitRemovals(world, query);
const q = world[$queryMap].get(query);
if (q.changedComponents.length) return diff(world, query);
return q.entities;
};
query[$queryComponents] = components;
return query;
}; // TODO: archetype graph
const queryCheckEntity = (world, query, eid) => {
const {
masks,
notMasks,
generations
} = world[$queryMap].get(query);
for (let i = 0; i < generations.length; i++) {
const generationId = generations[i];
const qMask = masks[generationId];
const qNotMask = notMasks[generationId];
const eMask = world[$entityMasks][generationId][eid];
if (qNotMask && (eMask & qNotMask) !== 0) {
return false;
}
if (qMask && (eMask & qMask) !== qMask) {
return false;
}
}
return true;
};
const queryCheckComponent = (world, query, component) => {
const {
generationId,
bitflag
} = world[$componentMap].get(component);
const {
masks
} = world[$queryMap].get(query);
const mask = masks[generationId];
return (mask & bitflag) === bitflag;
};
const queryCheckComponents = (world, query, components) => {
return components.every(c => queryCheckComponent(world, query, c));
};
const queryAddEntity = (world, query, eid) => {
const q = world[$queryMap].get(query);
if (q.enabled[eid]) return;
q.enabled[eid] = true;
q.entities.push(eid);
q.indices[eid] = q.entities.length - 1;
if (q.enter) q.enter(eid);
};
const queryCommitRemovals = (world, query) => {
const q = world[$queryMap].get(query);
while (q.toRemove.length) {
const eid = q.toRemove.pop();
const index = q.indices[eid];
if (index === NONE) continue;
const swapped = q.entities.pop();
if (swapped !== eid) {
q.entities[index] = swapped;
q.indices[swapped] = index;
}
q.indices[eid] = NONE;
}
world[$dirtyQueries].delete(q);
};
const commitRemovals = world => {
world[$dirtyQueries].forEach(q => {
queryCommitRemovals(q);
});
};
const queryRemoveEntity = (world, query, eid) => {
const q = world[$queryMap].get(query);
if (!q.enabled[eid]) return;
q.enabled[eid] = false;
if (q.exit) q.exit(eid);
q.toRemove.push(eid);
world[$dirtyQueries].add(q);
};
const $componentMap = Symbol('componentMap');
const $deferredComponentRemovals = Symbol('de$deferredComponentRemovals');
const defineComponent = schema => createStore(schema);
const incrementBitflag = world => {
world[$bitflag] *= 2;
if (world[$bitflag] >= 2 ** 32) {
world[$bitflag] = 1;
world[$entityMasks].push(new Uint32Array(world[$size]));
}
};
const registerComponent = (world, component) => {
world[$componentMap].set(component, {
generationId: world[$entityMasks].length - 1,
bitflag: world[$bitflag],
store: component
});
incrementBitflag(world);
};
const registerComponents = (world, components) => {
components.forEach(c => registerComponent(world, c));
};
const hasComponent = (world, component, eid) => {
const {
generationId,
bitflag
} = world[$componentMap].get(component);
const mask = world[$entityMasks][generationId][eid];
return (mask & bitflag) === bitflag;
};
const addComponent = (world, component, eid) => {
if (!world[$componentMap].has(component)) registerComponent(world, component);
if (hasComponent(world, component, eid)) return; // Add bitflag to entity bitmask
const {
generationId,
bitflag
} = world[$componentMap].get(component);
world[$entityMasks][generationId][eid] |= bitflag; // Zero out each property value
// component._reset(eid)
// todo: archetype graph
const queries = world[$queries];
queries.forEach(query => {
const components = query[$queryComponents];
if (!queryCheckComponents(world, query, components)) return;
const match = queryCheckEntity(world, query, eid);
if (match) queryAddEntity(world, query, eid);
});
};
const removeComponent = (world, component, eid) => {
const {
generationId,
bitflag
} = world[$componentMap].get(component);
if (!(world[$entityMasks][generationId][eid] & bitflag)) return; // todo: archetype graph
const queries = world[$queries];
queries.forEach(query => {
const components = query[$queryComponents];
if (!queryCheckComponents(world, query, components)) return;
const match = queryCheckEntity(world, query, eid);
if (match) queryRemoveEntity(world, query, eid);
}); // Remove flag from entity bitmask
world[$entityMasks][generationId][eid] &= ~bitflag;
};
const $size = Symbol('size');
const $bitflag = Symbol('bitflag');
const createWorld = (size = 1000000) => {
const world = {};
world[$size] = size;
world[$entityEnabled] = new Uint8Array(size);
world[$entityMasks] = [new Uint32Array(size)];
world[$removedEntities] = [];
world[$bitflag] = 1;
world[$componentMap] = new Map();
world[$queryMap] = new Map();
world[$queries] = new Set();
world[$dirtyQueries] = new Set();
world[$deferredComponentRemovals] = [];
world[$deferredEntityRemovals] = [];
return world;
};
const defineSystem = update => {
const system = world => {
update(world);
commitRemovals(world);
};
Object.defineProperty(system, 'name', {
value: (update.name || "AnonymousSystem") + "_internal",
configurable: true
});
return system;
};
const pipe = (...fns) => world => {
fns = Array.isArray(fns[0]) ? fns[0] : fns;
for (let i = 0; i < fns.length; i++) {
const fn = fns[i];
fn(world);
}
};
const Types = TYPES_ENUM;
export { Changed, Not, Types, addComponent, addEntity, commitRemovals, createWorld, defineComponent, defineDeserializer, defineQuery, defineSerializer, defineSystem, enterQuery, exitQuery, hasComponent, pipe, registerComponent, registerComponents, removeComponent, removeEntity };
//# sourceMappingURL=index.es.js.map

@@ -1,2 +0,796 @@

"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={bool:"Uint8",i8:"Int8",ui8:"Uint8",ui8c:"Uint8Clamped",i16:"Int16",ui16:"Uint16",i32:"Int32",ui32:"Uint32",f32:"Float32",f64:"Float64"},t={bool:"bool",i8:Int8Array,ui8:Uint8Array,ui8c:Uint8ClampedArray,i16:Int16Array,ui16:Uint16Array,i32:Int32Array,ui32:Uint32Array,f32:Float32Array,f64:Float64Array},n=256,r=65536,o=e=>4*Math.ceil(e/4),s=Symbol("storeRef"),i=Symbol("storeSize"),a=Symbol("storeMaps"),c=Symbol("storeFlattened"),l=Symbol("storeArrayCount"),u=Symbol("storeSubarrays"),f=Symbol("storeCursor"),y=Symbol("subarrayCursors"),p=Symbol("subarray"),d=Symbol("queryShadow"),g=Symbol("serializeShadow"),m=Symbol("indexType"),b=Symbol("indexBytes"),h={},E=(e,t)=>{const n=new ArrayBuffer(t*e.BYTES_PER_ELEMENT),r=new e.constructor(n);return r.set(e,0),r},S=(e,t)=>{Object.keys(e).forEach((n=>{const r=e[n];r[p]||(ArrayBuffer.isView(r)?(e[n]=E(r,t),e[n][d]=E(r[d],t),e[n][g]=E(r[g],t)):"object"==typeof r&&S(e[n],t))}))},A=(e,n)=>{e[i]=n,S(e,n),(e=>{const n=e[i],r=e[y]={};Object.keys(e[u]).forEach((s=>{const i=e[l],a=e[0].length,c=Array(i).fill(0).reduce(((e,n)=>e+t[s].BYTES_PER_ELEMENT),0),f=Array(i).fill(0).reduce(((e,t)=>e+a),0),y=new ArrayBuffer(o(c*f*n)),d=new t[s](y);d.set(e[u][s].buffer,0),e[u][s]=d;for(let t=0;t<n;t++){const n=r[s]+t*a,o=n+a;e[t]=e[u][s].subarray(n,o),e[t][p]=!0}}))})(e)},w=(e,n)=>{const r=n*t[e].BYTES_PER_ELEMENT,o=new ArrayBuffer(r);return new t[e](o)},_=(s,a,c)=>{const f=s[i],h=s[y],E=c<n?"ui8":c<r?"ui16":"ui32";if(!c)throw new Error("❌ Must define a length for component array.");if(!t[a])throw new Error(`❌ Invalid component array property type ${a}.`);if(!s[u][a]){const n=s[l],r=Array(n).fill(0).reduce(((e,n)=>e+t[a].BYTES_PER_ELEMENT),0),i=Array(n).fill(0).reduce(((e,t)=>e+c),0),y=o(r*i*f),p=new ArrayBuffer(y),h=new t[a](p);s[u][a]=h,s[u][a][d]=h.slice(0),s[u][a][g]=h.slice(0),h[m]=e[E],h[b]=t[E].BYTES_PER_ELEMENT}let S=0;for(let e=0;e<f;e++){const t=h[a]+e*c,n=t+c;s[e]=s[u][a].subarray(t,n),s[e][p]=!0,S=n}return h[a]=S,s},x=e=>{e[d]=e.slice(0),e[g]=e.slice(0)},M=e=>Array.isArray(e)&&"object"==typeof e[0]&&e[0].hasOwnProperty("type")&&e[0].hasOwnProperty("length"),T=Symbol("entityMasks"),B=Symbol("entityEnabled"),U=Symbol("deferredEntityRemovals"),j=Symbol("removedEntities");let C=0;const I=e=>{let t,n=new Set;return Array.isArray(e)?t=e.map((e=>{if(e._flatten)return e._flatten();if("function"==typeof e&&"QueryChanged"===e.name){if((e=e())._flatten){let t=e._flatten();return t.forEach((e=>n.add(e))),t}return n.add(e),[e]}})).reduce(((e,t)=>e.concat(t)),[]):e[q].forEach((e=>{t=t.concat(e._flatten())})),[t,n]};const O=Symbol("queries"),R=Symbol("queryMap"),P=Symbol("$dirtyQueries"),k=Symbol("queryComponents"),v=2**32,N=(e,t)=>{e[R].has(t)||e[R].set(t,{});let n=[],r=[],o=[];t[k].forEach((e=>{"function"==typeof e?("QueryNot"===e.name&&r.push(e()),"QueryChanged"===e.name&&(o.push(e()),n.push(e()))):n.push(e)}));const s=t=>e[q].get(t),a=n.reduce(((e,t)=>t[i]>e?t[i]:e),0),c=new Uint32Array(a).fill(v),l=new Uint8Array(a),u=n.concat(r).map((t=>(e[q].has(t)||$(e,t),t))).map(s).map((e=>e.generationId)).reduce(((e,t)=>(e.includes(t)||e.push(t),e)),[]),f=n.map(s).reduce(((e,t)=>(e[t.generationId]||(e[t.generationId]=0),e[t.generationId]|=t.bitflag,e)),{}),y=r.map(s).reduce(((e,t)=>(e[t.generationId]||(e[t.generationId]=0,e[t.generationId]|=t.bitflag),e)),{}),p=n.map((e=>e._flatten?e._flatten():[e])).reduce(((e,t)=>e.concat(t)),[]);Object.assign(e[R].get(t),{entities:[],changed:[],enabled:l,components:n,notComponents:r,changedComponents:o,masks:f,notMasks:y,generations:u,indices:c,flatProps:p,toRemove:[]}),e[O].add(t);for(let n=0;n<C;n++)e[B][n]&&L(e,t,n)&&Q(e,t,n)},L=(e,t,n)=>{const{masks:r,notMasks:o,generations:s}=e[R].get(t);for(let t=0;t<s.length;t++){const i=s[t],a=r[i],c=o[i],l=e[T][i][n];if(c&&0!=(l&c))return!1;if(a&&(l&a)!==a)return!1}return!0},Y=(e,t,n)=>n.every((n=>((e,t,n)=>{const{generationId:r,bitflag:o}=e[q].get(n),{masks:s}=e[R].get(t);return(s[r]&o)===o})(e,t,n))),Q=(e,t,n)=>{const r=e[R].get(t);r.enabled[n]||(r.enabled[n]=!0,r.entities.push(n),r.indices[n]=r.entities.length-1,r.enter&&r.enter(n))},V=(e,t)=>{const n=e[R].get(t);for(;n.toRemove.length;){const e=n.toRemove.pop(),t=n.indices[e];if(t===v)continue;const r=n.entities.pop();r!==e&&(n.entities[t]=r,n.indices[r]=t),n.indices[e]=v}e[P].delete(n)},z=e=>{e[P].forEach((e=>{V(e)}))},F=(e,t,n)=>{const r=e[R].get(t);r.enabled[n]&&(r.enabled[n]=!1,r.exit&&r.exit(n),r.toRemove.push(n),e[P].add(r))},q=Symbol("componentMap"),D=Symbol("de$deferredComponentRemovals"),$=(e,t)=>{e[q].set(t,{generationId:e[T].length-1,bitflag:e[H],store:t}),(e=>{e[H]*=2,e[H]>=2**32&&(e[H]=1,e[T].push(new Uint32Array(e[G])))})(e)},W=(e,t,n)=>{const{generationId:r,bitflag:o}=e[q].get(t);return(e[T][r][n]&o)===o},G=Symbol("size"),H=Symbol("bitflag"),J={bool:"bool",i8:"i8",ui8:"ui8",ui8c:"ui8c",i16:"i16",ui16:"ui16",i32:"i32",ui32:"ui32",f32:"f32",f64:"f64"};exports.Changed=function(e){return function(){return e}},exports.Not=function(e){return function(){return e}},exports.Types=J,exports.addComponent=(e,t,n)=>{if(e[q].has(t)||$(e,t),W(e,t,n))return;const{generationId:r,bitflag:o}=e[q].get(t);e[T][r][n]|=o;e[O].forEach((t=>{const r=t[k];if(!Y(e,t,r))return;L(e,t,n)&&Q(e,t,n)}))},exports.addEntity=e=>{const t=e[j],n=e[G],r=e[B];if(C>=n-n/5){const t=4*Math.ceil(n/2/4);e[G]+=t,e[q].forEach((t=>{A(t.store,e[G])})),e[R].forEach((t=>{t.indices=E(t.indices,e[G]),t.enabled=E(t.enabled,e[G])}))}const o=t.length>0?t.pop():C;return r[o]=1,C++,o},exports.commitRemovals=z,exports.createWorld=(e=1e6)=>{const t={};return t[G]=e,t[B]=new Uint8Array(e),t[T]=[new Uint32Array(e)],t[j]=[],t[H]=1,t[q]=new Map,t[R]=new Map,t[O]=new Set,t[P]=new Set,t[D]=[],t[U]=[],t},exports.defineComponent=e=>((e,n=1e6)=>{const r=Symbol("store");if("Map"===e.constructor.name)return e[i]=n,e;const o=(t,n)=>(M(e[n])?t++:e[n]instanceof Object&&(t+=Object.keys(e[n]).reduce(o,0)),t),p=M(e)?1:Object.keys(e).reduce(o,0),d={[i]:n,[a]:{},[u]:{},[s]:r,[f]:0,[y]:Object.keys(t).reduce(((e,t)=>({...e,[t]:0})),{}),[l]:p,[c]:[]};if("string"==typeof e)return h[r]=Object.assign(w(e,n),d),d[c].push(h[r]),x(h[r]),h[r];if(M(e)){const{type:t,length:n}=e[0];return h[r]=Object.assign(_(d,t,n),d),d[c].push(h[r]),h[r]}if(e instanceof Object&&Object.keys(e).length){const t=(e,r)=>{if("string"==typeof e[r])e[r]=w(e[r],n),d[c].push(e[r]),x(e[r]);else if(M(e[r])){const{type:t,length:n}=e[r][0];e[r]=_(d,t,n)}else e[r]instanceof Object&&(e[r]=Object.keys(e[r]).reduce(t,e[r]));return e};return h[r]=Object.assign(Object.keys(e).reduce(t,e),d),h[r]}return{}})(e),exports.defineDeserializer=e=>{const[t]=I(e);return e=>{const n=new DataView(e);let r=0;const o=n.getUint8(r);r+=1;const s=n.getUint32(r);r+=4;const i=t[o];for(let e=0;e<s;e++){const e=n.getUint32(r);if(r+=4,ArrayBuffer.isView(i[e])){const t=i[e],o=n["get"+t._indexType];r+=t._indexBytes;for(let s=0;s<o;s++){const o=n["get"+t.constructor.name.replace("Array","")](r);r+=t.BYTES_PER_ELEMENT,i[e][s]=o}}else{let t=n["get"+i.constructor.name.replace("Array","")](r);r+=i.BYTES_PER_ELEMENT,i[e]=t}}}},exports.defineQuery=e=>{const t=function(e){e[R].has(t)||N(e,t),V(e,t);const n=e[R].get(t);return n.changedComponents.length?((e,t)=>{const n=e[R].get(t);n.changed.length=0;const r=n.flatProps;for(let e=0;e<n.entities.length;e++){const t=n.entities[e];let o=!1;for(let e=0;e<r.length;e++){const n=r[e];if(ArrayBuffer.isView(n[t]))for(let e=0;e<n[t].length;e++)n[t][e]!==n[t][d][e]&&(o=!0,n[t][d][e]=n[t][e]);else n[t]!==n[d][t]&&(o=!0,n[d][t]=n[t])}o&&n.changed.push(t)}return n.changed})(e,t):n.entities};return t[k]=e,t},exports.defineSerializer=(e,t=5e6)=>{const n=new ArrayBuffer(t),r=new DataView(n),[o,s]=I(e);return e=>{if(!e.length)return;let t=0;for(let n=0;n<o.length;n++){const i=o[n],a=s.has(i);r.setUint8(t,n),t+=1;const c=t;t+=4;let l=0;for(let n=0;n<e.length;n++){const o=e[n];if(!a||i[o]!==i[g][o])if(l++,r.setUint32(t,o),t+=4,ArrayBuffer.isView(i[o])){const e=i[o].constructor.name.replace("Array",""),n=i[o]._indexType,s=i[o]._indexBytes,a=t;t+=1;let c=0;for(let a=0;a<i[o].length;a++){const l=i[o][a];r["set"+n](t,a),t+=s,r["set"+e](t,l),t+=i[o].BYTES_PER_ELEMENT,c++}r["set"+n](a,c)}else{const e=i.constructor.name.replace("Array","");r["set"+e](t,i[o]),t+=i.BYTES_PER_ELEMENT,i[g]||console.log(i),i[g][o]=i[o]}}r.setUint32(c,l)}return n.slice(0,t)}},exports.defineSystem=e=>{const t=t=>{e(t),z(t)};return Object.defineProperty(t,"name",{value:(e.name||"AnonymousSystem")+"_internal",configurable:!0}),t},exports.enterQuery=(e,t,n)=>{e[R].has(t)||N(e,t),e[R].get(t).enter=n},exports.exitQuery=(e,t,n)=>{e[R].has(t)||N(e,t),e[R].get(t).exit=n},exports.hasComponent=W,exports.pipe=(...e)=>t=>{e=Array.isArray(e[0])?e[0]:e;for(let n=0;n<e.length;n++){(0,e[n])(t)}},exports.registerComponent=$,exports.registerComponents=(e,t)=>{t.forEach((t=>$(e,t)))},exports.removeComponent=(e,t,n)=>{const{generationId:r,bitflag:o}=e[q].get(t);if(!(e[T][r][n]&o))return;e[O].forEach((t=>{const r=t[k];if(!Y(e,t,r))return;L(e,t,n)&&F(e,t,n)})),e[T][r][n]&=~o},exports.removeEntity=(e,t)=>{const n=e[O],r=e[j],o=e[B];if(0!==o[t]){n.forEach((n=>{F(e,n,t)})),r.push(t),o[t]=0;for(let n=0;n<e[T].length;n++)e[T][n][t]=0}};
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const TYPES_ENUM = {
bool: 'bool',
i8: 'i8',
ui8: 'ui8',
ui8c: 'ui8c',
i16: 'i16',
ui16: 'ui16',
i32: 'i32',
ui32: 'ui32',
f32: 'f32',
f64: 'f64'
};
const TYPES_NAMES = {
bool: 'Uint8',
i8: 'Int8',
ui8: 'Uint8',
ui8c: 'Uint8Clamped',
i16: 'Int16',
ui16: 'Uint16',
i32: 'Int32',
ui32: 'Uint32',
f32: 'Float32',
f64: 'Float64'
};
const TYPES = {
bool: 'bool',
i8: Int8Array,
ui8: Uint8Array,
ui8c: Uint8ClampedArray,
i16: Int16Array,
ui16: Uint16Array,
i32: Int32Array,
ui32: Uint32Array,
f32: Float32Array,
f64: Float64Array
};
const UNSIGNED_MAX = {
uint8: 2 ** 8,
uint16: 2 ** 16,
uint32: 2 ** 32
};
const roundToMultiple4 = x => Math.ceil(x / 4) * 4;
const $storeRef = Symbol('storeRef');
const $storeSize = Symbol('storeSize');
const $storeMaps = Symbol('storeMaps');
const $storeFlattened = Symbol('storeFlattened');
const $storeArrayCount = Symbol('storeArrayCount');
const $storeSubarrays = Symbol('storeSubarrays');
const $storeCursor = Symbol('storeCursor');
const $subarrayCursors = Symbol('subarrayCursors');
const $subarray = Symbol('subarray');
const $queryShadow = Symbol('queryShadow');
const $serializeShadow = Symbol('serializeShadow');
const $indexType = Symbol('indexType');
const $indexBytes = Symbol('indexBytes');
const stores = {};
const resize = (ta, size) => {
const newBuffer = new ArrayBuffer(size * ta.BYTES_PER_ELEMENT);
const newTa = new ta.constructor(newBuffer);
newTa.set(ta, 0);
return newTa;
};
const resizeRecursive = (store, size) => {
Object.keys(store).forEach(key => {
const ta = store[key];
if (ta[$subarray]) return;else if (ArrayBuffer.isView(ta)) {
store[key] = resize(ta, size);
store[key][$queryShadow] = resize(ta[$queryShadow], size);
store[key][$serializeShadow] = resize(ta[$serializeShadow], size);
} else if (typeof ta === 'object') {
resizeRecursive(store[key], size);
}
});
};
const resizeSubarrays = (store, size) => {
const cursors = store[$subarrayCursors] = {};
Object.keys(store[$storeSubarrays]).forEach(type => {
const arrayCount = store[$storeArrayCount];
const length = store[0].length;
const summedBytesPerElement = Array(arrayCount).fill(0).reduce((a, p) => a + TYPES[type].BYTES_PER_ELEMENT, 0);
const summedLength = Array(arrayCount).fill(0).reduce((a, p) => a + length, 0);
const buffer = new ArrayBuffer(roundToMultiple4(summedBytesPerElement * summedLength * size));
const array = new TYPES[type](buffer);
array.set(store[$storeSubarrays][type].buffer, 0);
store[$storeSubarrays][type] = array;
store[$storeSubarrays][type][$queryShadow] = array.slice(0);
store[$storeSubarrays][type][$serializeShadow] = array.slice(0);
for (let eid = 0; eid < size; eid++) {
const from = cursors[type] + eid * length;
const to = from + length;
store[eid] = store[$storeSubarrays][type].subarray(from, to);
store[eid][$queryShadow] = store[$storeSubarrays][type][$queryShadow].subarray(from, to);
store[eid][$serializeShadow] = store[$storeSubarrays][type][$serializeShadow].subarray(from, to);
store[eid][$subarray] = true;
store[eid][$indexType] = array[$indexType];
store[eid][$indexBytes] = array[$indexBytes];
}
});
};
const resizeStore = (store, size) => {
store[$storeSize] = size;
resizeRecursive(store, size);
resizeSubarrays(store, size);
};
const createTypeStore = (type, length) => {
const totalBytes = length * TYPES[type].BYTES_PER_ELEMENT;
const buffer = new ArrayBuffer(totalBytes);
return new TYPES[type](buffer);
};
const createArrayStore = (store, type, length) => {
const size = store[$storeSize];
const cursors = store[$subarrayCursors];
const indexType = length < UNSIGNED_MAX.uint8 ? 'ui8' : length < UNSIGNED_MAX.uint16 ? 'ui16' : 'ui32';
if (!length) throw new Error('❌ Must define a length for component array.');
if (!TYPES[type]) throw new Error(`❌ Invalid component array property type ${type}.`); // create buffer for type if it does not already exist
if (!store[$storeSubarrays][type]) {
const arrayCount = store[$storeArrayCount];
const summedBytesPerElement = Array(arrayCount).fill(0).reduce((a, p) => a + TYPES[type].BYTES_PER_ELEMENT, 0);
const summedLength = Array(arrayCount).fill(0).reduce((a, p) => a + length, 0);
const totalBytes = roundToMultiple4(summedBytesPerElement * summedLength * size);
const buffer = new ArrayBuffer(totalBytes);
const array = new TYPES[type](buffer);
store[$storeSubarrays][type] = array;
store[$storeSubarrays][type][$queryShadow] = array.slice(0);
store[$storeSubarrays][type][$serializeShadow] = array.slice(0);
array[$indexType] = TYPES_NAMES[indexType];
array[$indexBytes] = TYPES[indexType].BYTES_PER_ELEMENT;
} // pre-generate subarrays for each eid
let end = 0;
for (let eid = 0; eid < size; eid++) {
const from = cursors[type] + eid * length;
const to = from + length;
store[eid] = store[$storeSubarrays][type].subarray(from, to);
store[eid][$queryShadow] = store[$storeSubarrays][type][$queryShadow].subarray(from, to);
store[eid][$serializeShadow] = store[$storeSubarrays][type][$serializeShadow].subarray(from, to);
store[eid][$subarray] = true;
store[eid][$indexType] = TYPES_NAMES[indexType];
store[eid][$indexBytes] = TYPES[indexType].BYTES_PER_ELEMENT;
end = to;
}
cursors[type] = end;
return store;
};
const createShadows = store => {
store[$queryShadow] = store.slice(0);
store[$serializeShadow] = store.slice(0);
};
const isArrayType = x => Array.isArray(x) && typeof x[0] === 'object' && x[0].hasOwnProperty('type') && x[0].hasOwnProperty('length');
const createStore = (schema, size = 1000000) => {
const $store = Symbol('store');
schema = JSON.parse(JSON.stringify(schema));
if (schema.constructor.name === 'Map') {
schema[$storeSize] = size;
return schema;
}
const collectArrayCount = (count, key) => {
if (isArrayType(schema[key])) {
count++;
} else if (schema[key] instanceof Object) {
count += Object.keys(schema[key]).reduce(collectArrayCount, 0);
}
return count;
};
const arrayCount = isArrayType(schema) ? 1 : Object.keys(schema).reduce(collectArrayCount, 0);
const metadata = {
[$storeSize]: size,
[$storeMaps]: {},
[$storeSubarrays]: {},
[$storeRef]: $store,
[$storeCursor]: 0,
[$subarrayCursors]: Object.keys(TYPES).reduce((a, type) => ({ ...a,
[type]: 0
}), {}),
[$storeArrayCount]: arrayCount,
[$storeFlattened]: []
};
if (typeof schema === 'string') {
stores[$store] = Object.assign(createTypeStore(schema, size), metadata);
metadata[$storeFlattened].push(stores[$store]);
createShadows(stores[$store]);
return stores[$store];
} else if (isArrayType(schema)) {
const {
type,
length
} = schema[0];
stores[$store] = Object.assign(createArrayStore(metadata, type, length), metadata);
metadata[$storeFlattened].push(stores[$store]);
return stores[$store];
} else if (schema instanceof Object && Object.keys(schema).length) {
const recursiveTransform = (a, k) => {
if (typeof a[k] === 'string') {
a[k] = createTypeStore(a[k], size);
metadata[$storeFlattened].push(a[k]);
createShadows(a[k]);
} else if (isArrayType(a[k])) {
const {
type,
length
} = a[k][0];
a[k] = createArrayStore(metadata, type, length);
metadata[$storeFlattened].push(a[k]);
} else if (a[k] instanceof Object) {
a[k] = Object.keys(a[k]).reduce(recursiveTransform, a[k]);
}
return a;
};
stores[$store] = Object.assign(Object.keys(schema).reduce(recursiveTransform, schema), metadata);
return stores[$store];
}
return {};
};
const $entityMasks = Symbol('entityMasks');
const $entityEnabled = Symbol('entityEnabled');
const $deferredEntityRemovals = Symbol('deferredEntityRemovals');
const $removedEntities = Symbol('removedEntities'); // need a global EID cursor which all worlds and all components know about
// so that world entities can posess entire rows spanning all component tables
let globalEntityCursor = 0;
const getEntityCursor = () => globalEntityCursor;
const resizeWorld = (world, size) => {
world[$size] = size;
world[$componentMap].forEach(c => {
resizeStore(c.store, size);
});
world[$queryMap].forEach(q => {
q.indices = resize(q.indices, size);
q.enabled = resize(q.enabled, size);
});
world[$entityEnabled] = resize(world[$entityEnabled], size);
for (let i = 0; i < world[$entityMasks].length; i++) {
const masks = world[$entityMasks][i];
world[$entityMasks][i] = resize(masks, size);
}
};
const addEntity = world => {
const removed = world[$removedEntities];
const size = world[$size];
const enabled = world[$entityEnabled]; // if data stores are 80% full
if (globalEntityCursor >= size - size / 5) {
// grow by half the original size rounded up to a multiple of 4
const amount = Math.ceil(size / 2 / 4) * 4;
resizeWorld(world, size + amount);
}
const eid = removed.length > 0 ? removed.pop() : globalEntityCursor;
enabled[eid] = 1;
globalEntityCursor++;
return eid;
};
const removeEntity = (world, eid) => {
const queries = world[$queries];
const removed = world[$removedEntities];
const enabled = world[$entityEnabled]; // Check if entity is already removed
if (enabled[eid] === 0) return; // Remove entity from all queries
// TODO: archetype graph
queries.forEach(query => {
queryRemoveEntity(world, query, eid);
}); // Free the entity
removed.push(eid);
enabled[eid] = 0; // Clear entity bitmasks
for (let i = 0; i < world[$entityMasks].length; i++) world[$entityMasks][i][eid] = 0;
};
const diff = (world, query) => {
const q = world[$queryMap].get(query);
q.changed.length = 0;
const flat = q.flatProps;
for (let i = 0; i < q.entities.length; i++) {
const eid = q.entities[i];
let dirty = false;
for (let pid = 0; pid < flat.length; pid++) {
const prop = flat[pid];
if (ArrayBuffer.isView(prop[eid])) {
for (let i = 0; i < prop[eid].length; i++) {
if (prop[eid][i] !== prop[eid][$queryShadow][i]) {
dirty = true;
prop[eid][$queryShadow][i] = prop[eid][i];
}
}
} else {
if (prop[eid] !== prop[$queryShadow][eid]) {
dirty = true;
prop[$queryShadow][eid] = prop[eid];
}
}
}
if (dirty) q.changed.push(eid);
}
return q.changed;
};
const canonicalize = target => {
let componentProps;
let changedProps = new Set();
if (Array.isArray(target)) {
componentProps = target.map(p => {
if (typeof p === 'function' && p.name === 'QueryChanged') {
p()[$storeFlattened].forEach(prop => {
changedProps.add(prop);
});
return p()[$storeFlattened];
}
return p[$storeFlattened];
}).reduce((a, v) => a.concat(v), []);
} else {
target[$componentMap].forEach(c => {
componentProps = componentProps.concat(c[$storeFlattened]);
});
}
return [componentProps, changedProps];
};
const defineSerializer = (target, maxBytes = 20_000_000) => {
const [componentProps, changedProps] = canonicalize(target); // TODO: calculate max bytes based on target
const buffer = new ArrayBuffer(maxBytes);
const view = new DataView(buffer);
return ents => {
if (!ents.length) return;
let where = 0; // iterate over component props
for (let pid = 0; pid < componentProps.length; pid++) {
const prop = componentProps[pid];
const diff = changedProps.has(prop); // write pid
view.setUint8(where, pid);
where += 1; // save space for entity count
const countWhere = where;
where += 4;
let count = 0; // write eid,val
for (let i = 0; i < ents.length; i++) {
const eid = ents[i]; // skip if diffing and no change
if (diff && prop[eid] === prop[$serializeShadow][eid]) {
continue;
}
count++; // write eid
view.setUint32(where, eid);
where += 4; // if property is an array
if (ArrayBuffer.isView(prop[eid])) {
const type = prop[eid].constructor.name.replace('Array', '');
const indexType = prop[eid][$indexType];
const indexBytes = prop[eid][$indexBytes]; // add space for count of dirty array elements
const countWhere2 = where;
where += 1;
let count2 = 0; // write array values
for (let i = 0; i < prop[eid].length; i++) {
const value = prop[eid][i];
if (diff && prop[eid][i] === prop[eid][$serializeShadow][i]) {
continue;
} // write array index
view[`set${indexType}`](where, i);
where += indexBytes; // write value at that index
view[`set${type}`](where, value);
where += prop[eid].BYTES_PER_ELEMENT;
count2++;
}
view[`set${indexType}`](countWhere2, count2);
} else {
// regular property values
const type = prop.constructor.name.replace('Array', ''); // set value next [type] bytes
view[`set${type}`](where, prop[eid]);
where += prop.BYTES_PER_ELEMENT; // sync shadow state
prop[$serializeShadow][eid] = prop[eid];
}
}
view.setUint32(countWhere, count);
}
return buffer.slice(0, where);
};
};
const defineDeserializer = target => {
const [componentProps] = canonicalize(target);
return packet => {
const view = new DataView(packet);
let where = 0;
while (where < packet.byteLength) {
// pid
const pid = view.getUint8(where);
where += 1; // entity count
const entityCount = view.getUint32(where);
where += 4; // typed array
const ta = componentProps[pid]; // Get the properties and set the new state
for (let i = 0; i < entityCount; i++) {
const eid = view.getUint32(where);
where += 4;
if (ArrayBuffer.isView(ta[eid])) {
const array = ta[eid];
const count = view[`get${array[$indexType]}`](where);
where += array[$indexBytes]; // iterate over count
for (let i = 0; i < count; i++) {
const index = view[`get${array[$indexType]}`](where);
where += array[$indexBytes];
const value = view[`get${array.constructor.name.replace('Array', '')}`](where);
where += array.BYTES_PER_ELEMENT;
ta[eid][index] = value;
}
} else {
let value = view[`get${ta.constructor.name.replace('Array', '')}`](where);
where += ta.BYTES_PER_ELEMENT;
ta[eid] = value;
}
}
}
};
};
function Not(c) {
return function QueryNot() {
return c;
};
}
function Changed(c) {
return function QueryChanged() {
return c;
};
}
const $queries = Symbol('queries');
const $queryMap = Symbol('queryMap');
const $dirtyQueries = Symbol('$dirtyQueries');
const $queryComponents = Symbol('queryComponents');
const NONE = 2 ** 32;
const enterQuery = (world, query, fn) => {
if (!world[$queryMap].has(query)) registerQuery(world, query);
world[$queryMap].get(query).enter = fn;
};
const exitQuery = (world, query, fn) => {
if (!world[$queryMap].has(query)) registerQuery(world, query);
world[$queryMap].get(query).exit = fn;
};
const registerQuery = (world, query) => {
if (!world[$queryMap].has(query)) world[$queryMap].set(query, {});
let components = [];
let notComponents = [];
let changedComponents = [];
query[$queryComponents].forEach(c => {
if (typeof c === 'function') {
if (c.name === 'QueryNot') {
notComponents.push(c());
}
if (c.name === 'QueryChanged') {
changedComponents.push(c());
components.push(c());
}
} else {
components.push(c);
}
});
const mapComponents = c => world[$componentMap].get(c);
const size = components.reduce((a, c) => c[$storeSize] > a ? c[$storeSize] : a, 0);
const entities = [];
const changed = [];
const indices = new Uint32Array(size).fill(NONE);
const enabled = new Uint8Array(size);
const generations = components.concat(notComponents).map(c => {
if (!world[$componentMap].has(c)) registerComponent(world, c);
return c;
}).map(mapComponents).map(c => c.generationId).reduce((a, v) => {
if (a.includes(v)) return a;
a.push(v);
return a;
}, []);
const reduceBitmasks = (a, c) => {
if (!a[c.generationId]) a[c.generationId] = 0;
a[c.generationId] |= c.bitflag;
return a;
};
const masks = components.map(mapComponents).reduce(reduceBitmasks, {});
const notMasks = notComponents.map(mapComponents).reduce((a, c) => {
if (!a[c.generationId]) {
a[c.generationId] = 0;
a[c.generationId] |= c.bitflag;
}
return a;
}, {});
const flatProps = components.map(c => c._flatten ? c._flatten() : [c]).reduce((a, v) => a.concat(v), []);
const toRemove = [];
Object.assign(world[$queryMap].get(query), {
entities,
changed,
enabled,
components,
notComponents,
changedComponents,
masks,
notMasks,
generations,
indices,
flatProps,
toRemove
});
world[$queries].add(query);
for (let eid = 0; eid < getEntityCursor(); eid++) {
if (!world[$entityEnabled][eid]) continue;
if (queryCheckEntity(world, query, eid)) {
queryAddEntity(world, query, eid);
}
}
};
const defineQuery = components => {
const query = function (world) {
if (!world[$queryMap].has(query)) registerQuery(world, query);
queryCommitRemovals(world, query);
const q = world[$queryMap].get(query);
if (q.changedComponents.length) return diff(world, query);
return q.entities;
};
query[$queryComponents] = components;
return query;
}; // TODO: archetype graph
const queryCheckEntity = (world, query, eid) => {
const {
masks,
notMasks,
generations
} = world[$queryMap].get(query);
for (let i = 0; i < generations.length; i++) {
const generationId = generations[i];
const qMask = masks[generationId];
const qNotMask = notMasks[generationId];
const eMask = world[$entityMasks][generationId][eid];
if (qNotMask && (eMask & qNotMask) !== 0) {
return false;
}
if (qMask && (eMask & qMask) !== qMask) {
return false;
}
}
return true;
};
const queryCheckComponent = (world, query, component) => {
const {
generationId,
bitflag
} = world[$componentMap].get(component);
const {
masks
} = world[$queryMap].get(query);
const mask = masks[generationId];
return (mask & bitflag) === bitflag;
};
const queryCheckComponents = (world, query, components) => {
return components.every(c => queryCheckComponent(world, query, c));
};
const queryAddEntity = (world, query, eid) => {
const q = world[$queryMap].get(query);
if (q.enabled[eid]) return;
q.enabled[eid] = true;
q.entities.push(eid);
q.indices[eid] = q.entities.length - 1;
if (q.enter) q.enter(eid);
};
const queryCommitRemovals = (world, query) => {
const q = world[$queryMap].get(query);
while (q.toRemove.length) {
const eid = q.toRemove.pop();
const index = q.indices[eid];
if (index === NONE) continue;
const swapped = q.entities.pop();
if (swapped !== eid) {
q.entities[index] = swapped;
q.indices[swapped] = index;
}
q.indices[eid] = NONE;
}
world[$dirtyQueries].delete(q);
};
const commitRemovals = world => {
world[$dirtyQueries].forEach(q => {
queryCommitRemovals(q);
});
};
const queryRemoveEntity = (world, query, eid) => {
const q = world[$queryMap].get(query);
if (!q.enabled[eid]) return;
q.enabled[eid] = false;
if (q.exit) q.exit(eid);
q.toRemove.push(eid);
world[$dirtyQueries].add(q);
};
const $componentMap = Symbol('componentMap');
const $deferredComponentRemovals = Symbol('de$deferredComponentRemovals');
const defineComponent = schema => createStore(schema);
const incrementBitflag = world => {
world[$bitflag] *= 2;
if (world[$bitflag] >= 2 ** 32) {
world[$bitflag] = 1;
world[$entityMasks].push(new Uint32Array(world[$size]));
}
};
const registerComponent = (world, component) => {
world[$componentMap].set(component, {
generationId: world[$entityMasks].length - 1,
bitflag: world[$bitflag],
store: component
});
incrementBitflag(world);
};
const registerComponents = (world, components) => {
components.forEach(c => registerComponent(world, c));
};
const hasComponent = (world, component, eid) => {
const {
generationId,
bitflag
} = world[$componentMap].get(component);
const mask = world[$entityMasks][generationId][eid];
return (mask & bitflag) === bitflag;
};
const addComponent = (world, component, eid) => {
if (!world[$componentMap].has(component)) registerComponent(world, component);
if (hasComponent(world, component, eid)) return; // Add bitflag to entity bitmask
const {
generationId,
bitflag
} = world[$componentMap].get(component);
world[$entityMasks][generationId][eid] |= bitflag; // Zero out each property value
// component._reset(eid)
// todo: archetype graph
const queries = world[$queries];
queries.forEach(query => {
const components = query[$queryComponents];
if (!queryCheckComponents(world, query, components)) return;
const match = queryCheckEntity(world, query, eid);
if (match) queryAddEntity(world, query, eid);
});
};
const removeComponent = (world, component, eid) => {
const {
generationId,
bitflag
} = world[$componentMap].get(component);
if (!(world[$entityMasks][generationId][eid] & bitflag)) return; // todo: archetype graph
const queries = world[$queries];
queries.forEach(query => {
const components = query[$queryComponents];
if (!queryCheckComponents(world, query, components)) return;
const match = queryCheckEntity(world, query, eid);
if (match) queryRemoveEntity(world, query, eid);
}); // Remove flag from entity bitmask
world[$entityMasks][generationId][eid] &= ~bitflag;
};
const $size = Symbol('size');
const $bitflag = Symbol('bitflag');
const createWorld = (size = 1000000) => {
const world = {};
world[$size] = size;
world[$entityEnabled] = new Uint8Array(size);
world[$entityMasks] = [new Uint32Array(size)];
world[$removedEntities] = [];
world[$bitflag] = 1;
world[$componentMap] = new Map();
world[$queryMap] = new Map();
world[$queries] = new Set();
world[$dirtyQueries] = new Set();
world[$deferredComponentRemovals] = [];
world[$deferredEntityRemovals] = [];
return world;
};
const defineSystem = update => {
const system = world => {
update(world);
commitRemovals(world);
};
Object.defineProperty(system, 'name', {
value: (update.name || "AnonymousSystem") + "_internal",
configurable: true
});
return system;
};
const pipe = (...fns) => world => {
fns = Array.isArray(fns[0]) ? fns[0] : fns;
for (let i = 0; i < fns.length; i++) {
const fn = fns[i];
fn(world);
}
};
const Types = TYPES_ENUM;
exports.Changed = Changed;
exports.Not = Not;
exports.Types = Types;
exports.addComponent = addComponent;
exports.addEntity = addEntity;
exports.commitRemovals = commitRemovals;
exports.createWorld = createWorld;
exports.defineComponent = defineComponent;
exports.defineDeserializer = defineDeserializer;
exports.defineQuery = defineQuery;
exports.defineSerializer = defineSerializer;
exports.defineSystem = defineSystem;
exports.enterQuery = enterQuery;
exports.exitQuery = exitQuery;
exports.hasComponent = hasComponent;
exports.pipe = pipe;
exports.registerComponent = registerComponent;
exports.registerComponents = registerComponents;
exports.removeComponent = removeComponent;
exports.removeEntity = removeEntity;
//# sourceMappingURL=index.min.js.map

2

package.json
{
"name": "bitecs",
"version": "0.2.15",
"version": "0.2.16",
"description": "Tiny, data-driven, high performance ECS library written in Javascript",

@@ -5,0 +5,0 @@ "license": "MPL-2.0",

@@ -30,7 +30,7 @@ import { performance} from'perf_hooks'

const Position = defineComponent(Vector2)
const Velocity = defineComponent({x: [{type:f32,length:2}]})
const Velocity = defineComponent(Vector2)
// registerComponents(world, [Position, Velocity])
const query = defineQuery([Position,Velocity])
const serialize = defineSerializer([Changed(Position), Velocity])
const serialize = defineSerializer([Position, Velocity])
const deserialize = defineDeserializer([Position,Velocity])

@@ -47,4 +47,4 @@

Position.y[eid]++
Velocity.x[eid].fill(1)
// Velocity.y[eid].fill(1)
Velocity.x[eid]++
Velocity.y[eid]++
}

@@ -74,13 +74,2 @@

for (let i = 0; i < n; i++) {
Position.x[i]++
Position.y[i]++
Velocity.x[i].fill(2)
// Velocity.y[eid].fill(2)
}
// console.log('before',Velocity.x[0])
then = now()

@@ -90,3 +79,1 @@ deserialize(packet)

// console.log('after',Velocity.x[0])
console.log(Velocity.x[0][0])

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc