Comparing version 0.3.1 to 0.3.2-a
@@ -73,4 +73,4 @@ declare module 'bitecs' { | ||
export function Not (c: (IComponent | IComponentProp)[]): (world: IWorld) => IComponent | IComponentProp | ||
export function enterQuery (world: IWorld, query: Query, fn: (eid: number) => void): void | ||
export function exitQuery (world: IWorld, query: Query, fn: (eid: number) => void): void | ||
export function enterQuery (query: Query): Query | ||
export function exitQuery (query: Query): Query | ||
export function commitRemovals (world: IWorld): void | ||
@@ -77,0 +77,0 @@ export function defineSystem (update: (world: IWorld) => void): System |
@@ -40,4 +40,2 @@ const TYPES_ENUM = { | ||
const roundToMultiple4 = x => Math.ceil(x / 4) * 4; | ||
const $storeRef = Symbol('storeRef'); | ||
@@ -48,2 +46,3 @@ const $storeSize = Symbol('storeSize'); | ||
const $storeBase = Symbol('storeBase'); | ||
const $storeType = Symbol('storeType'); | ||
const $storeArrayCounts = Symbol('storeArrayCount'); | ||
@@ -79,22 +78,30 @@ const $storeSubarrays = Symbol('storeSubarrays'); | ||
const resizeSubarrays = (store, size) => { | ||
const cursors = store[$subarrayCursors] = {}; | ||
Object.keys(store[$storeSubarrays]).forEach(type => { | ||
const arrayCount = store[$storeArrayCounts]; | ||
const resizeSubarrays = (metadata, size) => { | ||
Object.keys(metadata[$subarrayCursors]).forEach(k => { | ||
metadata[$subarrayCursors][k] = 0; | ||
}); | ||
const cursors = metadata[$subarrayCursors]; | ||
metadata[$storeFlattened].filter(store => !ArrayBuffer.isView(store)).forEach(store => { | ||
const type = store[$storeType]; | ||
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); | ||
const arrayCount = metadata[$storeArrayCounts][type]; | ||
const summedLength = Array(arrayCount).fill(0).reduce((a, p) => a + length, 0); // for threaded impl | ||
// const summedBytesPerElement = Array(arrayCount).fill(0).reduce((a, p) => a + TYPES[type].BYTES_PER_ELEMENT, 0) | ||
// const totalBytes = roundToMultiple4(summedBytesPerElement * summedLength * size) | ||
// const buffer = new ArrayBuffer(totalBytes) | ||
const array = new TYPES[type](summedLength * size); | ||
array.set(metadata[$storeSubarrays][type]); | ||
metadata[$storeSubarrays][type] = array; | ||
metadata[$storeSubarrays][type][$queryShadow] = array.slice(0); | ||
metadata[$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] = metadata[$storeSubarrays][type].subarray(from, to); | ||
store[eid].from = from; | ||
store[eid].to = to; | ||
store[eid][$queryShadow] = metadata[$storeSubarrays][type][$queryShadow].subarray(from, to); | ||
store[eid][$serializeShadow] = metadata[$storeSubarrays][type][$serializeShadow].subarray(from, to); | ||
store[eid][$subarray] = true; | ||
@@ -127,2 +134,3 @@ store[eid][$indexType] = array[$indexType]; | ||
const store = Array(size).fill(0); | ||
store[$storeType] = type; | ||
const cursors = metadata[$subarrayCursors]; | ||
@@ -176,3 +184,3 @@ const indexType = length < UNSIGNED_MAX.uint8 ? 'ui8' : length < UNSIGNED_MAX.uint16 ? 'ui16' : 'ui32'; | ||
const createStore = (schema, size = 1000000) => { | ||
const createStore = (schema, size = 10000) => { | ||
const $store = Symbol('store'); | ||
@@ -278,3 +286,6 @@ if (!schema) return {}; | ||
const addEntity = world => { | ||
const enabled = world[$entityEnabled]; // if data stores are 80% full | ||
const enabled = world[$entityEnabled]; | ||
const eid = removed.length > 0 ? removed.shift() : globalEntityCursor++; | ||
enabled[eid] = 1; | ||
world[$entityIndices][eid] = world[$entityArray].push(eid) - 1; // if data stores are 80% full | ||
@@ -287,8 +298,5 @@ if (globalEntityCursor >= world[$warningSize]) { | ||
world[$warningSize] = world[$size] - world[$size] / 5; | ||
console.info(`๐พ bitECS - resizing world from ${size} to ${size + amount}`); | ||
} | ||
const eid = removed.length > 0 ? removed.pop() : globalEntityCursor; | ||
enabled[eid] = 1; | ||
globalEntityCursor++; | ||
world[$entityIndices][eid] = world[$entityArray].push(eid) - 1; | ||
return eid; | ||
@@ -628,5 +636,6 @@ }; | ||
const $bitflag = Symbol('bitflag'); | ||
const createWorld = (size = 1000000) => { | ||
const createWorld = (size = 10000) => { | ||
const world = {}; | ||
world[$size] = size; | ||
world[$warningSize] = size - size / 5; | ||
world[$entityEnabled] = new Uint8Array(size); | ||
@@ -641,8 +650,15 @@ world[$entityMasks] = [new Uint32Array(size)]; | ||
world[$dirtyQueries] = new Set(); | ||
world[$warningSize] = size - size / 5; | ||
return world; | ||
}; | ||
const defineSystem = update => { | ||
const defineSystem = (fn1, fn2) => { | ||
const update = fn2 !== undefined ? fn2 : fn1; | ||
let init = false; | ||
const system = world => { | ||
if (!init && fn2 !== undefined) { | ||
fn1(world); | ||
init = true; | ||
} | ||
update(world); | ||
@@ -686,3 +702,3 @@ commitRemovals(world); | ||
const defineSerializer = (target, maxBytes = 20_000_000) => { | ||
const defineSerializer = (target, maxBytes = 20000000) => { | ||
const isWorld = Object.getOwnPropertySymbols(target).includes($componentMap); | ||
@@ -689,0 +705,0 @@ let [componentProps, changedProps] = canonicalize(target); // TODO: calculate max bytes based on target |
@@ -44,4 +44,2 @@ 'use strict'; | ||
const roundToMultiple4 = x => Math.ceil(x / 4) * 4; | ||
const $storeRef = Symbol('storeRef'); | ||
@@ -52,2 +50,3 @@ const $storeSize = Symbol('storeSize'); | ||
const $storeBase = Symbol('storeBase'); | ||
const $storeType = Symbol('storeType'); | ||
const $storeArrayCounts = Symbol('storeArrayCount'); | ||
@@ -83,22 +82,30 @@ const $storeSubarrays = Symbol('storeSubarrays'); | ||
const resizeSubarrays = (store, size) => { | ||
const cursors = store[$subarrayCursors] = {}; | ||
Object.keys(store[$storeSubarrays]).forEach(type => { | ||
const arrayCount = store[$storeArrayCounts]; | ||
const resizeSubarrays = (metadata, size) => { | ||
Object.keys(metadata[$subarrayCursors]).forEach(k => { | ||
metadata[$subarrayCursors][k] = 0; | ||
}); | ||
const cursors = metadata[$subarrayCursors]; | ||
metadata[$storeFlattened].filter(store => !ArrayBuffer.isView(store)).forEach(store => { | ||
const type = store[$storeType]; | ||
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); | ||
const arrayCount = metadata[$storeArrayCounts][type]; | ||
const summedLength = Array(arrayCount).fill(0).reduce((a, p) => a + length, 0); // for threaded impl | ||
// const summedBytesPerElement = Array(arrayCount).fill(0).reduce((a, p) => a + TYPES[type].BYTES_PER_ELEMENT, 0) | ||
// const totalBytes = roundToMultiple4(summedBytesPerElement * summedLength * size) | ||
// const buffer = new ArrayBuffer(totalBytes) | ||
const array = new TYPES[type](summedLength * size); | ||
array.set(metadata[$storeSubarrays][type]); | ||
metadata[$storeSubarrays][type] = array; | ||
metadata[$storeSubarrays][type][$queryShadow] = array.slice(0); | ||
metadata[$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] = metadata[$storeSubarrays][type].subarray(from, to); | ||
store[eid].from = from; | ||
store[eid].to = to; | ||
store[eid][$queryShadow] = metadata[$storeSubarrays][type][$queryShadow].subarray(from, to); | ||
store[eid][$serializeShadow] = metadata[$storeSubarrays][type][$serializeShadow].subarray(from, to); | ||
store[eid][$subarray] = true; | ||
@@ -131,2 +138,3 @@ store[eid][$indexType] = array[$indexType]; | ||
const store = Array(size).fill(0); | ||
store[$storeType] = type; | ||
const cursors = metadata[$subarrayCursors]; | ||
@@ -180,3 +188,3 @@ const indexType = length < UNSIGNED_MAX.uint8 ? 'ui8' : length < UNSIGNED_MAX.uint16 ? 'ui16' : 'ui32'; | ||
const createStore = (schema, size = 1000000) => { | ||
const createStore = (schema, size = 10000) => { | ||
const $store = Symbol('store'); | ||
@@ -282,3 +290,6 @@ if (!schema) return {}; | ||
const addEntity = world => { | ||
const enabled = world[$entityEnabled]; // if data stores are 80% full | ||
const enabled = world[$entityEnabled]; | ||
const eid = removed.length > 0 ? removed.shift() : globalEntityCursor++; | ||
enabled[eid] = 1; | ||
world[$entityIndices][eid] = world[$entityArray].push(eid) - 1; // if data stores are 80% full | ||
@@ -291,8 +302,5 @@ if (globalEntityCursor >= world[$warningSize]) { | ||
world[$warningSize] = world[$size] - world[$size] / 5; | ||
console.info(`๐พ bitECS - resizing world from ${size} to ${size + amount}`); | ||
} | ||
const eid = removed.length > 0 ? removed.pop() : globalEntityCursor; | ||
enabled[eid] = 1; | ||
globalEntityCursor++; | ||
world[$entityIndices][eid] = world[$entityArray].push(eid) - 1; | ||
return eid; | ||
@@ -632,5 +640,6 @@ }; | ||
const $bitflag = Symbol('bitflag'); | ||
const createWorld = (size = 1000000) => { | ||
const createWorld = (size = 10000) => { | ||
const world = {}; | ||
world[$size] = size; | ||
world[$warningSize] = size - size / 5; | ||
world[$entityEnabled] = new Uint8Array(size); | ||
@@ -645,8 +654,15 @@ world[$entityMasks] = [new Uint32Array(size)]; | ||
world[$dirtyQueries] = new Set(); | ||
world[$warningSize] = size - size / 5; | ||
return world; | ||
}; | ||
const defineSystem = update => { | ||
const defineSystem = (fn1, fn2) => { | ||
const update = fn2 !== undefined ? fn2 : fn1; | ||
let init = false; | ||
const system = world => { | ||
if (!init && fn2 !== undefined) { | ||
fn1(world); | ||
init = true; | ||
} | ||
update(world); | ||
@@ -690,3 +706,3 @@ commitRemovals(world); | ||
const defineSerializer = (target, maxBytes = 20_000_000) => { | ||
const defineSerializer = (target, maxBytes = 20000000) => { | ||
const isWorld = Object.getOwnPropertySymbols(target).includes($componentMap); | ||
@@ -693,0 +709,0 @@ let [componentProps, changedProps] = canonicalize(target); // TODO: calculate max bytes based on target |
@@ -73,4 +73,4 @@ declare module 'bitecs' { | ||
export function Not (c: (IComponent | IComponentProp)[]): (world: IWorld) => IComponent | IComponentProp | ||
export function enterQuery (world: IWorld, query: Query, fn: (eid: number) => void): void | ||
export function exitQuery (world: IWorld, query: Query, fn: (eid: number) => void): void | ||
export function enterQuery (query: Query): Query | ||
export function exitQuery (query: Query): Query | ||
export function commitRemovals (world: IWorld): void | ||
@@ -77,0 +77,0 @@ export function defineSystem (update: (world: IWorld) => void): System |
{ | ||
"name": "bitecs", | ||
"version": "0.3.1", | ||
"version": "0.3.2a", | ||
"description": "Functional, minimal, data-driven, ultra-high performance ECS library written in Javascript", | ||
@@ -5,0 +5,0 @@ "license": "MPL-2.0", |
@@ -6,12 +6,13 @@ # ๐พ bitECS ๐พ | ||
## Features | ||
## โจ Features | ||
| | | | ||
| --------------------------------- | ---------------------------------------- | | ||
| ๐ฎ Simple, declarative API | ๐ฅ Blazing fast iteration | | ||
| ๐ Powerful & performant queries | ๐พ Serialization included | | ||
| ๐ Zero dependencies | ๐ Node or browser | | ||
| ๐ค `~5kb` gzipped | ๐ท TypeScript support | | ||
| ๐ฎ Simple, declarative API | ๐ฅ Blazing fast iteration | | ||
| ๐ Powerful & performant queries | ๐พ Serialization included | | ||
| ๐ Zero dependencies | ๐ Node or browser | | ||
| ๐ค `~5kb` gzipped | ๐ท TypeScript support | | ||
| โค Made with love | ๐บ [glMatrix](https://github.com/toji/gl-matrix) support | | ||
#### Benchmarks | ||
### ๐ Benchmarks | ||
@@ -25,3 +26,3 @@ ๐ Unparalleled performance benchmarks | ||
#### In Development | ||
### ๐ฉโ๐ป In Development | ||
| | | ||
@@ -32,3 +33,3 @@ | ---------------- | | ||
## Install | ||
## ๐ฟ Install | ||
``` | ||
@@ -38,3 +39,3 @@ npm i bitecs | ||
## Overview | ||
## ๐บ Overview | ||
@@ -71,3 +72,3 @@ This is the entire API: | ||
## World | ||
## ๐ World | ||
@@ -85,3 +86,3 @@ A world represents a set of entities and the components that they each possess. | ||
``` | ||
## Entity | ||
## ๐พ Entity | ||
@@ -102,3 +103,3 @@ An entity is an integer, technically a pointer, which components can be associated with. | ||
## Component | ||
## ๐ฆ Component | ||
@@ -135,3 +136,3 @@ Components are pure data and added to entities to give them state. | ||
## Query | ||
## ๐ Query | ||
@@ -182,3 +183,3 @@ A query is defined with components and is used to obtain a specific set of entities from a world. | ||
## System | ||
## โ System | ||
@@ -249,3 +250,3 @@ Systems are functions and are run against a world to update componenet state of entities, or anything else. | ||
## Serialization | ||
## ๐พ Serialization | ||
@@ -252,0 +253,0 @@ Performant and highly customizable serialization is built-in. Any subset of data can be targeted and serialized/deserialized with great efficiency and ease. |
@@ -50,4 +50,4 @@ import { strictEqual } from 'assert' | ||
strictEqual(eid2, 0) | ||
strictEqual(getEntityCursor(), 2) | ||
strictEqual(getEntityCursor(), 1) | ||
}) | ||
}) |
@@ -10,3 +10,3 @@ import assert, { strictEqual } from 'assert' | ||
const store = createStore({ value: Types.i8 }) | ||
strictEqual(store.value.length, 1_000_000) | ||
strictEqual(store.value.length, 10000) | ||
}) | ||
@@ -21,3 +21,3 @@ it('should allow custom size', () => { | ||
assert(store.value instanceof TYPES[type]) | ||
strictEqual(store.value.length, 1_000_000) | ||
strictEqual(store.value.length, 10000) | ||
}) | ||
@@ -24,0 +24,0 @@ }) |
@@ -7,3 +7,4 @@ import assert, { strictEqual } from 'assert' | ||
const defaultSize = 1_000_000 | ||
const defaultSize = 10000 | ||
const growAmount = defaultSize + defaultSize / 2 | ||
@@ -16,9 +17,9 @@ describe('World Integration Tests', () => { | ||
const world = createWorld() | ||
resizeWorld(world, 1_500_000) | ||
strictEqual(world[$entityMasks][0].length, 1_500_000) | ||
strictEqual(world[$entityEnabled].length, 1_500_000) | ||
resizeWorld(world, growAmount) | ||
strictEqual(world[$entityMasks][0].length, growAmount) | ||
strictEqual(world[$entityEnabled].length, growAmount) | ||
}) | ||
it('should resize automatically at 80% of 1MM', () => { | ||
const world = createWorld() | ||
const n = 800_001 | ||
const n = defaultSize * 0.8 | ||
for (let i = 0; i < n; i++) { | ||
@@ -28,5 +29,5 @@ addEntity(world) | ||
strictEqual(world[$entityMasks][0].length, 1_500_000) | ||
strictEqual(world[$entityEnabled].length, 1_500_000) | ||
strictEqual(world[$entityMasks][0].length, growAmount) | ||
strictEqual(world[$entityEnabled].length, growAmount) | ||
}) | ||
}) |
@@ -7,3 +7,3 @@ import assert, { strictEqual } from 'assert' | ||
const defaultSize = 1_000_000 | ||
const defaultSize = 10000 | ||
@@ -10,0 +10,0 @@ describe('World Integration Tests', () => { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
238689
1959
299
1