New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.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.3.2-a1 to 0.3.2-a2

21

dist/index.d.ts

@@ -38,2 +38,19 @@ declare module 'bitecs' {

type ArrayByType = {
['bool']: boolean[];
[Types.i8]: Int8Array;
[Types.ui8]: Uint8Array;
[Types.ui8c]: Uint8ClampedArray;
[Types.i16]: Int16Array;
[Types.ui16]: Uint16Array;
[Types.i32]: Int32Array;
[Types.ui32]: Uint32Array;
[Types.f32]: Float32Array;
[Types.f64]: Float64Array;
}
type ComponentType<T extends ISchema> = {
[key in keyof T]: T[key] extends Type ? ArrayByType[T[key]] : T[key] extends ISchema ? ComponentType<T[key]> : unknown;
}
interface IWorld {

@@ -61,3 +78,3 @@ [key: string]: any

export function createWorld (size?: number): IWorld

@@ -68,3 +85,3 @@ export function addEntity (world: IWorld): number

export function registerComponents (world: IWorld, components: IComponent[]): void
export function defineComponent (schema: ISchema): IComponent
export function defineComponent <T extends ISchema>(schema: T): ComponentType<T>
export function addComponent (world: IWorld, component: IComponent, eid: number): void

@@ -71,0 +88,0 @@ export function removeComponent (world: IWorld, component: IComponent, eid: number): void

425

dist/index.es.js

@@ -51,2 +51,3 @@ const TYPES_ENUM = {

const $subarray = Symbol('subarray');
const $tagStore = Symbol('tagStore');
const $queryShadow = Symbol('queryShadow');

@@ -68,2 +69,3 @@ const $serializeShadow = Symbol('serializeShadow');

const length = store[0].length;
const indexType = length < UNSIGNED_MAX.uint8 ? 'ui8' : length < UNSIGNED_MAX.uint16 ? 'ui16' : 'ui32';
const arrayCount = metadata[$storeArrayCounts][type];

@@ -80,2 +82,4 @@ const summedLength = Array(arrayCount).fill(0).reduce((a, p) => a + length, 0); // for threaded impl

metadata[$storeSubarrays][type][$serializeShadow] = array.slice(0);
array[$indexType] = TYPES_NAMES[indexType];
array[$indexBytes] = TYPES[indexType].BYTES_PER_ELEMENT;
let end = 0;

@@ -119,4 +123,5 @@

const resizeStore = (store, size) => {
if (store[$tagStore]) return;
store[$storeSize] = size;
store[$storeFlattened] = [];
store[$storeFlattened].length = 0;
Object.keys(store[$subarrayCursors]).forEach(k => {

@@ -191,5 +196,15 @@ store[$subarrayCursors][k] = 0;

const createStore = (schema, size = 10000) => {
const createStore = (schema, size) => {
const $store = Symbol('store');
if (!schema) return {};
if (!schema || !Object.keys(schema).length) {
// tag component
stores[$store] = {
[$storeSize]: size,
[$tagStore]: true,
[$storeBase]: () => stores[$store]
};
return stores[$store];
}
schema = JSON.parse(JSON.stringify(schema));

@@ -221,4 +236,4 @@ const arrayCounts = {};

}), {}),
[$storeArrayCounts]: arrayCounts,
[$storeFlattened]: []
[$storeFlattened]: [],
[$storeArrayCounts]: arrayCounts
};

@@ -230,2 +245,3 @@

a[k] = createTypeStore(a[k], size);
createShadows(a[k]);

@@ -235,3 +251,2 @@ a[k][$storeBase] = () => stores[$store];

metadata[$storeFlattened].push(a[k]);
createShadows(a[k]);
} else if (isArrayType(a[k])) {

@@ -257,12 +272,204 @@ const [type, length] = a[k];

return stores[$store];
} // tag component
}
};
let resized = false;
const setSerializationResized = v => {
resized = v;
};
stores[$store] = metadata;
const canonicalize = target => {
let componentProps = [];
let changedProps = new Set();
stores[$store][$storeBase] = () => stores[$store];
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 stores[$store];
if (Object.getOwnPropertySymbols(p).includes($storeFlattened)) {
return p[$storeFlattened];
}
if (Object.getOwnPropertySymbols(p).includes($storeBase)) {
return p;
}
}).reduce((a, v) => a.concat(v), []);
}
return [componentProps, changedProps];
};
const defineSerializer = (target, maxBytes = 20000000) => {
const isWorld = Object.getOwnPropertySymbols(target).includes($componentMap);
let [componentProps, changedProps] = canonicalize(target); // TODO: calculate max bytes based on target
const buffer = new ArrayBuffer(maxBytes);
const view = new DataView(buffer);
return ents => {
if (resized) {
[componentProps, changedProps] = canonicalize(target);
resized = false;
}
if (isWorld) {
componentProps = [];
target[$componentMap].forEach((c, component) => {
componentProps.push(...component[$storeFlattened]);
});
}
if (Object.getOwnPropertySymbols(ents).includes($componentMap)) {
ents = ents[$entityArray];
}
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 (prop[$tagStore]) {
continue;
} // 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 index,value
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++;
} // write total element count
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 isWorld = Object.getOwnPropertySymbols(target).includes($componentMap);
let [componentProps] = canonicalize(target);
return (world, packet) => {
if (resized) {
[componentProps] = canonicalize(target);
resized = false;
}
if (isWorld) {
componentProps = [];
target[$componentMap].forEach((c, component) => {
componentProps.push(...component[$storeFlattened]);
});
}
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++) {
let eid = view.getUint32(where);
where += 4; // if this world hasn't seen this eid yet
if (!world[$entityEnabled][eid]) {
// make a new entity for the data
eid = addEntity(world);
}
const component = ta[$storeBase]();
if (!hasComponent(world, component, eid)) {
addComponent(world, component, eid);
}
if (component[$tagStore]) {
continue;
}
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 {
const value = view[`get${ta.constructor.name.replace('Array', '')}`](where);
where += ta.BYTES_PER_ELEMENT;
ta[eid] = value;
}
}
}
};
};
const $entityMasks = Symbol('entityMasks');

@@ -272,7 +479,8 @@ const $entityEnabled = Symbol('entityEnabled');

const $entityIndices = Symbol('entityIndices');
const NONE$1 = 2 ** 32; // need a global EID cursor which all worlds and all components know about
const NONE$1 = 2 ** 32;
const defaultSize = 100000; // 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;
let globalSize = 10000;
let globalSize = defaultSize;

@@ -287,3 +495,3 @@ let resizeThreshold = () => globalSize - globalSize / 5;

const enabled = world[$entityEnabled];
const eid = removed.length > 0 ? removed.shift() : globalEntityCursor++;
const eid = removed.length > 0 ? removed.pop() : globalEntityCursor++;
enabled[eid] = 1;

@@ -300,2 +508,3 @@ world[$entityIndices][eid] = world[$entityArray].push(eid) - 1; // if data stores are 80% full

resizeComponents(newSize);
setSerializationResized(true);
console.info(`๐Ÿ‘พ bitECS - resizing all worlds from ${size} to ${size + amount}`);

@@ -332,9 +541,2 @@ }

enabled[eid] = 0; // pop swap
// const index = world[$entityIndices][eid]
// const swapped = world[$entityArray].pop()
// if (swapped !== eid) {
// world[$entityArray][index] = swapped
// world[$entityIndices][swapped] = index
// }
// world[$entityIndices][eid] = NONE

@@ -538,3 +740,4 @@ popSwap(world, eid); // Clear entity bitmasks

q.entities.push(eid);
q.indices[eid] = q.entities.length - 1;
q.indices[eid] = q.entities.length - 1; // TODO: pop swap so dupes don't enter
q.entered.push(eid);

@@ -571,3 +774,4 @@ };

q.toRemove.push(eid);
world[$dirtyQueries].add(q);
world[$dirtyQueries].add(q); // TODO: pop swap so dupes don't enter
q.exited.push(eid);

@@ -582,3 +786,3 @@ };

const defineComponent = schema => {
const component = createStore(schema);
const component = createStore(schema, defaultSize);
if (schema && Object.keys(schema).length) components.push(component);

@@ -719,177 +923,2 @@ return component;

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];
}
if (Object.getOwnPropertySymbols(p).includes($storeFlattened)) {
return p[$storeFlattened];
}
if (Object.getOwnPropertySymbols(p).includes($storeBase)) {
return p;
}
}).reduce((a, v) => a.concat(v), []);
}
return [componentProps, changedProps];
};
const defineSerializer = (target, maxBytes = 20000000) => {
const isWorld = Object.getOwnPropertySymbols(target).includes($componentMap);
let [componentProps, changedProps] = canonicalize(target); // TODO: calculate max bytes based on target
const buffer = new ArrayBuffer(maxBytes);
const view = new DataView(buffer);
return ents => {
if (isWorld) {
componentProps = [];
target[$componentMap].forEach((c, component) => {
componentProps.push(...component[$storeFlattened]);
});
}
if (Object.getOwnPropertySymbols(ents).includes($componentMap)) {
ents = ents[$entityArray];
}
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 index,value
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++;
} // write total element count
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 isWorld = Object.getOwnPropertySymbols(target).includes($componentMap);
let [componentProps] = canonicalize(target);
return (world, packet) => {
if (isWorld) {
componentProps = [];
target[$componentMap].forEach((c, component) => {
componentProps.push(...component[$storeFlattened]);
});
}
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++) {
let eid = view.getUint32(where);
where += 4; // if this world hasn't seen this eid yet
if (!world[$entityEnabled][eid]) {
// make a new entity for the data
eid = addEntity(world);
}
const component = ta[$storeBase]();
if (!hasComponent(world, component, eid)) {
addComponent(world, component, eid);
}
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;
}
}
}
};
};
const pipe = (...fns) => input => {

@@ -896,0 +925,0 @@ if (!input || Array.isArray(input) && input.length === 0) return;

@@ -55,2 +55,3 @@ 'use strict';

const $subarray = Symbol('subarray');
const $tagStore = Symbol('tagStore');
const $queryShadow = Symbol('queryShadow');

@@ -72,2 +73,3 @@ const $serializeShadow = Symbol('serializeShadow');

const length = store[0].length;
const indexType = length < UNSIGNED_MAX.uint8 ? 'ui8' : length < UNSIGNED_MAX.uint16 ? 'ui16' : 'ui32';
const arrayCount = metadata[$storeArrayCounts][type];

@@ -84,2 +86,4 @@ const summedLength = Array(arrayCount).fill(0).reduce((a, p) => a + length, 0); // for threaded impl

metadata[$storeSubarrays][type][$serializeShadow] = array.slice(0);
array[$indexType] = TYPES_NAMES[indexType];
array[$indexBytes] = TYPES[indexType].BYTES_PER_ELEMENT;
let end = 0;

@@ -123,4 +127,5 @@

const resizeStore = (store, size) => {
if (store[$tagStore]) return;
store[$storeSize] = size;
store[$storeFlattened] = [];
store[$storeFlattened].length = 0;
Object.keys(store[$subarrayCursors]).forEach(k => {

@@ -195,5 +200,15 @@ store[$subarrayCursors][k] = 0;

const createStore = (schema, size = 10000) => {
const createStore = (schema, size) => {
const $store = Symbol('store');
if (!schema) return {};
if (!schema || !Object.keys(schema).length) {
// tag component
stores[$store] = {
[$storeSize]: size,
[$tagStore]: true,
[$storeBase]: () => stores[$store]
};
return stores[$store];
}
schema = JSON.parse(JSON.stringify(schema));

@@ -225,4 +240,4 @@ const arrayCounts = {};

}), {}),
[$storeArrayCounts]: arrayCounts,
[$storeFlattened]: []
[$storeFlattened]: [],
[$storeArrayCounts]: arrayCounts
};

@@ -234,2 +249,3 @@

a[k] = createTypeStore(a[k], size);
createShadows(a[k]);

@@ -239,3 +255,2 @@ a[k][$storeBase] = () => stores[$store];

metadata[$storeFlattened].push(a[k]);
createShadows(a[k]);
} else if (isArrayType(a[k])) {

@@ -261,12 +276,204 @@ const [type, length] = a[k];

return stores[$store];
} // tag component
}
};
let resized = false;
const setSerializationResized = v => {
resized = v;
};
stores[$store] = metadata;
const canonicalize = target => {
let componentProps = [];
let changedProps = new Set();
stores[$store][$storeBase] = () => stores[$store];
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 stores[$store];
if (Object.getOwnPropertySymbols(p).includes($storeFlattened)) {
return p[$storeFlattened];
}
if (Object.getOwnPropertySymbols(p).includes($storeBase)) {
return p;
}
}).reduce((a, v) => a.concat(v), []);
}
return [componentProps, changedProps];
};
const defineSerializer = (target, maxBytes = 20000000) => {
const isWorld = Object.getOwnPropertySymbols(target).includes($componentMap);
let [componentProps, changedProps] = canonicalize(target); // TODO: calculate max bytes based on target
const buffer = new ArrayBuffer(maxBytes);
const view = new DataView(buffer);
return ents => {
if (resized) {
[componentProps, changedProps] = canonicalize(target);
resized = false;
}
if (isWorld) {
componentProps = [];
target[$componentMap].forEach((c, component) => {
componentProps.push(...component[$storeFlattened]);
});
}
if (Object.getOwnPropertySymbols(ents).includes($componentMap)) {
ents = ents[$entityArray];
}
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 (prop[$tagStore]) {
continue;
} // 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 index,value
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++;
} // write total element count
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 isWorld = Object.getOwnPropertySymbols(target).includes($componentMap);
let [componentProps] = canonicalize(target);
return (world, packet) => {
if (resized) {
[componentProps] = canonicalize(target);
resized = false;
}
if (isWorld) {
componentProps = [];
target[$componentMap].forEach((c, component) => {
componentProps.push(...component[$storeFlattened]);
});
}
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++) {
let eid = view.getUint32(where);
where += 4; // if this world hasn't seen this eid yet
if (!world[$entityEnabled][eid]) {
// make a new entity for the data
eid = addEntity(world);
}
const component = ta[$storeBase]();
if (!hasComponent(world, component, eid)) {
addComponent(world, component, eid);
}
if (component[$tagStore]) {
continue;
}
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 {
const value = view[`get${ta.constructor.name.replace('Array', '')}`](where);
where += ta.BYTES_PER_ELEMENT;
ta[eid] = value;
}
}
}
};
};
const $entityMasks = Symbol('entityMasks');

@@ -276,7 +483,8 @@ const $entityEnabled = Symbol('entityEnabled');

const $entityIndices = Symbol('entityIndices');
const NONE$1 = 2 ** 32; // need a global EID cursor which all worlds and all components know about
const NONE$1 = 2 ** 32;
const defaultSize = 100000; // 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;
let globalSize = 10000;
let globalSize = defaultSize;

@@ -291,3 +499,3 @@ let resizeThreshold = () => globalSize - globalSize / 5;

const enabled = world[$entityEnabled];
const eid = removed.length > 0 ? removed.shift() : globalEntityCursor++;
const eid = removed.length > 0 ? removed.pop() : globalEntityCursor++;
enabled[eid] = 1;

@@ -304,2 +512,3 @@ world[$entityIndices][eid] = world[$entityArray].push(eid) - 1; // if data stores are 80% full

resizeComponents(newSize);
setSerializationResized(true);
console.info(`๐Ÿ‘พ bitECS - resizing all worlds from ${size} to ${size + amount}`);

@@ -336,9 +545,2 @@ }

enabled[eid] = 0; // pop swap
// const index = world[$entityIndices][eid]
// const swapped = world[$entityArray].pop()
// if (swapped !== eid) {
// world[$entityArray][index] = swapped
// world[$entityIndices][swapped] = index
// }
// world[$entityIndices][eid] = NONE

@@ -542,3 +744,4 @@ popSwap(world, eid); // Clear entity bitmasks

q.entities.push(eid);
q.indices[eid] = q.entities.length - 1;
q.indices[eid] = q.entities.length - 1; // TODO: pop swap so dupes don't enter
q.entered.push(eid);

@@ -575,3 +778,4 @@ };

q.toRemove.push(eid);
world[$dirtyQueries].add(q);
world[$dirtyQueries].add(q); // TODO: pop swap so dupes don't enter
q.exited.push(eid);

@@ -586,3 +790,3 @@ };

const defineComponent = schema => {
const component = createStore(schema);
const component = createStore(schema, defaultSize);
if (schema && Object.keys(schema).length) components.push(component);

@@ -723,177 +927,2 @@ return component;

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];
}
if (Object.getOwnPropertySymbols(p).includes($storeFlattened)) {
return p[$storeFlattened];
}
if (Object.getOwnPropertySymbols(p).includes($storeBase)) {
return p;
}
}).reduce((a, v) => a.concat(v), []);
}
return [componentProps, changedProps];
};
const defineSerializer = (target, maxBytes = 20000000) => {
const isWorld = Object.getOwnPropertySymbols(target).includes($componentMap);
let [componentProps, changedProps] = canonicalize(target); // TODO: calculate max bytes based on target
const buffer = new ArrayBuffer(maxBytes);
const view = new DataView(buffer);
return ents => {
if (isWorld) {
componentProps = [];
target[$componentMap].forEach((c, component) => {
componentProps.push(...component[$storeFlattened]);
});
}
if (Object.getOwnPropertySymbols(ents).includes($componentMap)) {
ents = ents[$entityArray];
}
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 index,value
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++;
} // write total element count
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 isWorld = Object.getOwnPropertySymbols(target).includes($componentMap);
let [componentProps] = canonicalize(target);
return (world, packet) => {
if (isWorld) {
componentProps = [];
target[$componentMap].forEach((c, component) => {
componentProps.push(...component[$storeFlattened]);
});
}
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++) {
let eid = view.getUint32(where);
where += 4; // if this world hasn't seen this eid yet
if (!world[$entityEnabled][eid]) {
// make a new entity for the data
eid = addEntity(world);
}
const component = ta[$storeBase]();
if (!hasComponent(world, component, eid)) {
addComponent(world, component, eid);
}
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;
}
}
}
};
};
const pipe = (...fns) => input => {

@@ -900,0 +929,0 @@ if (!input || Array.isArray(input) && input.length === 0) return;

@@ -38,2 +38,19 @@ declare module 'bitecs' {

type ArrayByType = {
['bool']: boolean[];
[Types.i8]: Int8Array;
[Types.ui8]: Uint8Array;
[Types.ui8c]: Uint8ClampedArray;
[Types.i16]: Int16Array;
[Types.ui16]: Uint16Array;
[Types.i32]: Int32Array;
[Types.ui32]: Uint32Array;
[Types.f32]: Float32Array;
[Types.f64]: Float64Array;
}
type ComponentType<T extends ISchema> = {
[key in keyof T]: T[key] extends Type ? ArrayByType[T[key]] : T[key] extends ISchema ? ComponentType<T[key]> : unknown;
}
interface IWorld {

@@ -61,3 +78,3 @@ [key: string]: any

export function createWorld (size?: number): IWorld

@@ -68,3 +85,3 @@ export function addEntity (world: IWorld): number

export function registerComponents (world: IWorld, components: IComponent[]): void
export function defineComponent (schema: ISchema): IComponent
export function defineComponent <T extends ISchema>(schema: T): ComponentType<T>
export function addComponent (world: IWorld, component: IComponent, eid: number): void

@@ -71,0 +88,0 @@ export function removeComponent (world: IWorld, component: IComponent, eid: number): void

{
"name": "bitecs",
"version": "0.3.2a1",
"version": "0.3.2-a2",
"description": "Functional, minimal, data-driven, ultra-high performance ECS library written in Javascript",

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

@@ -175,3 +175,3 @@ # ๐Ÿ‘พ bitECS ๐Ÿ‘พ

## โ˜„ System
## ๐Ÿ›ธ System

@@ -178,0 +178,0 @@ Systems are functions and are run against a world to update componenet state of entities, or anything else.

@@ -15,4 +15,4 @@ import { strictEqual } from 'assert'

const eid = addEntity(world)
// console.log(TestComponent)
addComponent(world, TestComponent, eid)
const serialize = defineSerializer(world)

@@ -19,0 +19,0 @@ const deserialize = defineDeserializer(world)

import assert, { strictEqual } from 'assert'
import { defaultSize } from '../../src/Entity.js'
import { Types } from '../../src/index.js'

@@ -8,5 +9,5 @@ import { createStore, TYPES } from '../../src/Storage.js'

describe('Storage Integration Tests', () => {
it('should default to size of 1MM', () => {
const store = createStore({ value: Types.i8 })
strictEqual(store.value.length, 10000)
it('should default to size of 100k', () => {
const store = createStore({ value: Types.i8 }, defaultSize)
strictEqual(store.value.length, defaultSize)
})

@@ -19,5 +20,5 @@ it('should allow custom size', () => {

it('should create a store with ' + type, () => {
const store = createStore({ value: type })
const store = createStore({ value: type }, defaultSize)
assert(store.value instanceof TYPES[type])
strictEqual(store.value.length, 10000)
strictEqual(store.value.length, defaultSize)
})

@@ -45,3 +46,3 @@ })

it('should create flat stores', () => {
const store = createStore({ value1: Types.i8, value2: Types.ui16, value3: Types.f32 })
const store = createStore({ value1: Types.i8, value2: Types.ui16, value3: Types.f32 }, defaultSize)
assert(store.value1 != undefined)

@@ -55,5 +56,5 @@ assert(store.value1 instanceof Int8Array)

it('should create nested stores', () => {
const store1 = createStore({ nest: { value: Types.i8 } })
const store2 = createStore({ nest: { nest: { value: Types.ui32 } } })
const store3 = createStore({ nest: { nest: { nest: { value: Types.i16 } } } })
const store1 = createStore({ nest: { value: Types.i8 } }, defaultSize)
const store2 = createStore({ nest: { nest: { value: Types.ui32 } } }, defaultSize)
const store3 = createStore({ nest: { nest: { nest: { value: Types.i16 } } } }, defaultSize)
assert(store1.nest.value instanceof Int8Array)

@@ -60,0 +61,0 @@ assert(store2.nest.nest.value instanceof Uint32Array)

import assert, { strictEqual } from 'assert'
import { $componentMap } from '../../src/Component.js'
import { $entityEnabled, $entityMasks, resetGlobals, addEntity } from '../../src/Entity.js'
import { $entityEnabled, $entityMasks, resetGlobals, addEntity, defaultSize } from '../../src/Entity.js'
import { $dirtyQueries, $queries, $queryMap } from '../../src/Query.js'
import { createWorld, $size, $bitflag } from '../../src/World.js'
const defaultSize = 10000
const growAmount = defaultSize + defaultSize / 2

@@ -9,0 +8,0 @@

import assert, { strictEqual } from 'assert'
import { $componentMap } from '../../src/Component.js'
import { $entityEnabled, $entityMasks, resetGlobals, addEntity } from '../../src/Entity.js'
import { $entityEnabled, $entityMasks, resetGlobals, addEntity, defaultSize } from '../../src/Entity.js'
import { $dirtyQueries, $queries, $queryMap } from '../../src/Query.js'
import { createWorld, $size, $bitflag } from '../../src/World.js'
const defaultSize = 10000
describe('World Integration Tests', () => {

@@ -10,0 +8,0 @@ afterEach(() => {

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