Comparing version 0.3.1 to 0.3.2
@@ -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,3 +636,3 @@ }; | ||
const $bitflag = Symbol('bitflag'); | ||
const createWorld = (size = 1000000) => { | ||
const createWorld = (size = 10000) => { | ||
const world = {}; | ||
@@ -631,0 +639,0 @@ world[$size] = size; |
@@ -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,3 +640,3 @@ }; | ||
const $bitflag = Symbol('bitflag'); | ||
const createWorld = (size = 1000000) => { | ||
const createWorld = (size = 10000) => { | ||
const world = {}; | ||
@@ -635,0 +643,0 @@ world[$size] = size; |
@@ -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.2", | ||
"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
237548
1947
299