Comparing version
@@ -744,3 +744,3 @@ const TYPES_ENUM = { | ||
const archetypes = []; | ||
const changed = []; | ||
const changed = SparseSet(); | ||
const toRemove = []; | ||
@@ -805,2 +805,5 @@ const entered = []; | ||
}); | ||
changedComponents.map(mapComponents).forEach(c => { | ||
c.changedQueries.add(q); | ||
}); | ||
if (notComponents.length) world[$notQueries].add(q); | ||
@@ -817,36 +820,15 @@ | ||
const diff = (q, clearDiff) => { | ||
if (clearDiff) q.changed.length = 0; | ||
const queryEntityChanged = (q, eid) => { | ||
if (q.changed.has(eid)) return; | ||
q.changed.add(eid); | ||
}; | ||
const entityChanged = (world, component, eid) => { | ||
const { | ||
flatProps, | ||
shadows | ||
} = q; | ||
for (let i = 0; i < q.dense.length; i++) { | ||
const eid = q.dense[i]; | ||
let dirty = false; | ||
for (let pid = 0; pid < flatProps.length; pid++) { | ||
const prop = flatProps[pid]; | ||
const shadow = shadows[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] !== shadow[eid]) { | ||
dirty = true; | ||
shadow[eid] = prop[eid]; | ||
} | ||
} | ||
} | ||
if (dirty) q.changed.push(eid); | ||
} | ||
return q.changed; | ||
changedQueries | ||
} = world[$componentMap].get(component); | ||
changedQueries.forEach(q => { | ||
const match = queryCheckEntity(world, q, eid); | ||
if (match) queryEntityChanged(q, eid); | ||
}); | ||
}; | ||
@@ -860,3 +842,2 @@ /** | ||
const defineQuery = components => { | ||
@@ -870,4 +851,5 @@ if (components === undefined || components[$componentMap] !== undefined) { | ||
const q = world[$queryMap].get(query); | ||
queryCommitRemovals(q); | ||
if (q.changedComponents.length) return diff(q, clearDiff); | ||
queryCommitRemovals(q); // if (q.changedComponents.length) return diff(q, clearDiff) | ||
if (q.changedComponents.length) return q.changed.dense; | ||
return q.dense; | ||
@@ -938,3 +920,3 @@ }; | ||
const q = world[$queryMap].get(query); | ||
q.changed.length = 0; | ||
q.changed = SparseSet(); | ||
}; | ||
@@ -990,6 +972,9 @@ /** | ||
const notQueries = new Set(); | ||
const changedQueries = new Set(); | ||
world[$queries].forEach(q => { | ||
if (q.components.includes(component)) { | ||
if (q.notComponents.includes(component)) { | ||
queries.add(q); | ||
} else if (q.notComponents.includes(component)) { | ||
} else if (q.changedComponents.includes(component)) { | ||
changedQueries.add(q); | ||
} else if (q.components.includes(component)) { | ||
notQueries.add(q); | ||
@@ -1003,3 +988,4 @@ } | ||
queries, | ||
notQueries | ||
notQueries, | ||
changedQueries | ||
}); | ||
@@ -1223,2 +1209,69 @@ | ||
const proxify = (proto, store) => { | ||
// for (const key in store) { | ||
const keys = Object.keys(store); | ||
for (let i = 0; i < keys.length; i++) { | ||
const key = keys[i]; | ||
if (!ArrayBuffer.isView(store[key])) { | ||
proxify(proto[key], store[key]); | ||
} else { | ||
const prop = store[key]; // const get = function() {return prop[this._eid]} | ||
// const set = function(val) {prop[this._eid] = val} | ||
Object.defineProperty(proto, key, //{get,set}) | ||
{ | ||
get() { | ||
return prop[this._eid]; | ||
}, | ||
set(val) { | ||
prop[this._eid] = val; | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
const defineProxy = store => { | ||
function P(eid) { | ||
this._eid = eid; | ||
this._store = store; | ||
} // Object.keys(store).forEach((key,i) => { | ||
// Object.defineProperty(P.prototype, key, { | ||
// get() { | ||
// const k = this._keys[i] | ||
// return this._store[k][this._eid] | ||
// }, | ||
// set(val) { | ||
// const k = this._keys[i] | ||
// this._store[k][this._eid] = val | ||
// } | ||
// }) | ||
// }) | ||
// P._store = store | ||
// P.prototype.proxify = function () { | ||
// for (const key in P._store) { | ||
// const prop = P._store[key] | ||
// Object.defineProperty(proto, key, { | ||
// get() { | ||
// return prop[this._eid] | ||
// }, | ||
// set(val) { | ||
// prop[this._eid] = val | ||
// } | ||
// }); | ||
// } | ||
// } | ||
// P.prototype.proxify() | ||
proxify(P.prototype, store); // WARNING: cursed code ahead | ||
return Object.seal(P); | ||
}; | ||
const pipe = (...fns) => (...args) => { | ||
@@ -1245,3 +1298,3 @@ const input = Array.isArray(args[0]) ? args[0] : args; | ||
export { Changed, DESERIALIZE_MODE, Not, Types, addComponent, addEntity, commitRemovals, createWorld, defineComponent, defineDeserializer, defineQuery, defineSerializer, defineSystem, deleteWorld, enterQuery, exitQuery, getEntityComponents, hasComponent, parentArray, pipe, registerComponent, registerComponents, removeComponent, removeEntity, removeQuery, resetChangedQuery, resetWorld, setDefaultSize }; | ||
export { Changed, DESERIALIZE_MODE, Not, Types, addComponent, addEntity, commitRemovals, createWorld, defineComponent, defineDeserializer, defineProxy, defineQuery, defineSerializer, defineSystem, deleteWorld, enterQuery, entityChanged, exitQuery, getEntityComponents, hasComponent, parentArray, pipe, registerComponent, registerComponents, removeComponent, removeEntity, removeQuery, resetChangedQuery, resetWorld, setDefaultSize }; | ||
//# sourceMappingURL=index.es.js.map |
@@ -748,3 +748,3 @@ 'use strict'; | ||
const archetypes = []; | ||
const changed = []; | ||
const changed = SparseSet(); | ||
const toRemove = []; | ||
@@ -809,2 +809,5 @@ const entered = []; | ||
}); | ||
changedComponents.map(mapComponents).forEach(c => { | ||
c.changedQueries.add(q); | ||
}); | ||
if (notComponents.length) world[$notQueries].add(q); | ||
@@ -821,36 +824,15 @@ | ||
const diff = (q, clearDiff) => { | ||
if (clearDiff) q.changed.length = 0; | ||
const queryEntityChanged = (q, eid) => { | ||
if (q.changed.has(eid)) return; | ||
q.changed.add(eid); | ||
}; | ||
const entityChanged = (world, component, eid) => { | ||
const { | ||
flatProps, | ||
shadows | ||
} = q; | ||
for (let i = 0; i < q.dense.length; i++) { | ||
const eid = q.dense[i]; | ||
let dirty = false; | ||
for (let pid = 0; pid < flatProps.length; pid++) { | ||
const prop = flatProps[pid]; | ||
const shadow = shadows[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] !== shadow[eid]) { | ||
dirty = true; | ||
shadow[eid] = prop[eid]; | ||
} | ||
} | ||
} | ||
if (dirty) q.changed.push(eid); | ||
} | ||
return q.changed; | ||
changedQueries | ||
} = world[$componentMap].get(component); | ||
changedQueries.forEach(q => { | ||
const match = queryCheckEntity(world, q, eid); | ||
if (match) queryEntityChanged(q, eid); | ||
}); | ||
}; | ||
@@ -864,3 +846,2 @@ /** | ||
const defineQuery = components => { | ||
@@ -874,4 +855,5 @@ if (components === undefined || components[$componentMap] !== undefined) { | ||
const q = world[$queryMap].get(query); | ||
queryCommitRemovals(q); | ||
if (q.changedComponents.length) return diff(q, clearDiff); | ||
queryCommitRemovals(q); // if (q.changedComponents.length) return diff(q, clearDiff) | ||
if (q.changedComponents.length) return q.changed.dense; | ||
return q.dense; | ||
@@ -942,3 +924,3 @@ }; | ||
const q = world[$queryMap].get(query); | ||
q.changed.length = 0; | ||
q.changed = SparseSet(); | ||
}; | ||
@@ -994,6 +976,9 @@ /** | ||
const notQueries = new Set(); | ||
const changedQueries = new Set(); | ||
world[$queries].forEach(q => { | ||
if (q.components.includes(component)) { | ||
if (q.notComponents.includes(component)) { | ||
queries.add(q); | ||
} else if (q.notComponents.includes(component)) { | ||
} else if (q.changedComponents.includes(component)) { | ||
changedQueries.add(q); | ||
} else if (q.components.includes(component)) { | ||
notQueries.add(q); | ||
@@ -1007,3 +992,4 @@ } | ||
queries, | ||
notQueries | ||
notQueries, | ||
changedQueries | ||
}); | ||
@@ -1227,2 +1213,69 @@ | ||
const proxify = (proto, store) => { | ||
// for (const key in store) { | ||
const keys = Object.keys(store); | ||
for (let i = 0; i < keys.length; i++) { | ||
const key = keys[i]; | ||
if (!ArrayBuffer.isView(store[key])) { | ||
proxify(proto[key], store[key]); | ||
} else { | ||
const prop = store[key]; // const get = function() {return prop[this._eid]} | ||
// const set = function(val) {prop[this._eid] = val} | ||
Object.defineProperty(proto, key, //{get,set}) | ||
{ | ||
get() { | ||
return prop[this._eid]; | ||
}, | ||
set(val) { | ||
prop[this._eid] = val; | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
const defineProxy = store => { | ||
function P(eid) { | ||
this._eid = eid; | ||
this._store = store; | ||
} // Object.keys(store).forEach((key,i) => { | ||
// Object.defineProperty(P.prototype, key, { | ||
// get() { | ||
// const k = this._keys[i] | ||
// return this._store[k][this._eid] | ||
// }, | ||
// set(val) { | ||
// const k = this._keys[i] | ||
// this._store[k][this._eid] = val | ||
// } | ||
// }) | ||
// }) | ||
// P._store = store | ||
// P.prototype.proxify = function () { | ||
// for (const key in P._store) { | ||
// const prop = P._store[key] | ||
// Object.defineProperty(proto, key, { | ||
// get() { | ||
// return prop[this._eid] | ||
// }, | ||
// set(val) { | ||
// prop[this._eid] = val | ||
// } | ||
// }); | ||
// } | ||
// } | ||
// P.prototype.proxify() | ||
proxify(P.prototype, store); // WARNING: cursed code ahead | ||
return Object.seal(P); | ||
}; | ||
const pipe = (...fns) => (...args) => { | ||
@@ -1259,2 +1312,3 @@ const input = Array.isArray(args[0]) ? args[0] : args; | ||
exports.defineDeserializer = defineDeserializer; | ||
exports.defineProxy = defineProxy; | ||
exports.defineQuery = defineQuery; | ||
@@ -1265,2 +1319,3 @@ exports.defineSerializer = defineSerializer; | ||
exports.enterQuery = enterQuery; | ||
exports.entityChanged = entityChanged; | ||
exports.exitQuery = exitQuery; | ||
@@ -1267,0 +1322,0 @@ exports.getEntityComponents = getEntityComponents; |
@@ -246,10 +246,18 @@ | ||
## ๐ญ Component Proxy | ||
## โ Component Proxy | ||
Component proxies are a way to interact with component data using regular objects (not to be confused with JavaScript's `Proxy`, but the behavior is basically identical). | ||
Component proxies are a way to interact with component data using regular objects (not to be confused with ES6 `Proxy`, but the behavior is basically identical). | ||
This enables cleaner syntax and easier interop with other libraries, but comes at the cost of performance. | ||
This allows cleaner syntax, references, and enhanced interoperability with other libraries. | ||
โ Comes at the cost of performance and extra boilerplate. Try not to use these for hot paths. | ||
```js | ||
const PositionProxy = defineProxy(Position) | ||
class PositionProxy { | ||
constructor(eid) { this.eid = eid } | ||
get x () { return Position.x[this.eid] } | ||
set x (val) { Position.x[this.eid] = val } | ||
get y () { return Position.y[this.eid] } | ||
set y (val) { Position.y[this.eid] = val } | ||
} | ||
@@ -271,6 +279,6 @@ const position = new PositionProxy(eid) | ||
// load data for this eid into reused proxy instances | ||
loadProxy(position, eid) | ||
loadProxy(velocity, eid) | ||
// set eid on proxies | ||
position.eid = velocity.eid = eid | ||
// proxies persist data for the respective eid | ||
position.x += velocity.x | ||
@@ -348,5 +356,5 @@ position.y += velocity.y | ||
- `REPLACE` - (default) overwrites entity data, or creates new entities if the serialized EIDs don't exist in the target world. | ||
- `APPEND` - only creates new entities, does not overwrite any existing entity data. | ||
- `APPEND` - only creates new entities, never overwrites existing entity data. | ||
- `MAP` - acts like `REPLACE` but every serialized EID is assigned a local EID which is memorized for all subsequent deserializations onto the target world. | ||
- useful when deserializing server ECS state on a client-side ECS to avoid EID collisions | ||
- useful when deserializing server ECS state onto a client ECS world to avoid EID collisions but still maintain the server-side EID relationship | ||
@@ -353,0 +361,0 @@ ```js |
{ | ||
"name": "bitecs", | ||
"version": "0.3.16-3", | ||
"version": "0.3.16-3-alpha", | ||
"description": "Functional, minimal, data-driven, ultra-high performance ECS library written in Javascript", | ||
@@ -5,0 +5,0 @@ "license": "MPL-2.0", |
@@ -28,5 +28,14 @@ # ๐พ bitECS ๐พ [](https://www.npmjs.com/package/bitecs) [](https://www.npmjs.com/package/bitecs) [](https://www.npmjs.com/package/bitecs) [](https://www.npmjs.com/package/bitecs) | ||
| ---------------- | | ||
| ๐งฌArchetypes | | ||
| ๐งฌ Archetypes | | ||
|๐งต Multithreading | | ||
## ๐ Powering | ||
| | | ||
| ---------------- | | ||
| Bokeh Network Engine (coming soon) | | ||
| [Phaser 4](https://github.com/phaserjs/phaser) | | ||
| [XREngine](https://github.com/XRFoundation/XREngine) | | ||
## ๐ฟ Install | ||
@@ -33,0 +42,0 @@ ``` |
@@ -6,3 +6,3 @@ import { strictEqual } from 'assert' | ||
import { addEntity, removeEntity, resetGlobals } from '../../src/Entity.js' | ||
import { Changed, defineQuery, enterQuery, Not } from '../../src/Query.js' | ||
import { Changed, defineQuery, enterQuery, entityChanged, Not } from '../../src/Query.js' | ||
@@ -134,3 +134,2 @@ describe('Query Integration Tests', () => { | ||
ents = fooBarQuery(world) | ||
console.log(ents) | ||
strictEqual(ents.length, 1) | ||
@@ -177,2 +176,4 @@ strictEqual(ents[0], 2) | ||
entityChanged(world, TestComponent, eid1) | ||
ents = query(world) | ||
@@ -179,0 +180,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
333169
3.85%2931
3.31%89
11.25%