flow: dirtiness

This commit is contained in:
cha0s 2022-09-14 05:03:08 -05:00
parent 94addfb22a
commit 788e94db41
4 changed files with 53 additions and 40 deletions

View File

@ -51,7 +51,7 @@ class BaseComponent {
return this.$$dirty; return this.$$dirty;
} }
set dirty(dirty) { setDirty(dirty) {
this.$$dirty = dirty; this.$$dirty = dirty;
} }
@ -84,9 +84,9 @@ class FlatComponent extends BaseComponent {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
count -= results.length; count -= results.length;
if (count > 0) { if (count > 0) {
const required = (this.caret + count) * this.schema.width; const required = (this.caret + count) * this.constructor.width;
if (required > this.data.byteLength) { if (required > this.data.byteLength) {
const chunkWidth = this.chunkSize * this.schema.width; const chunkWidth = this.chunkSize * this.constructor.width;
const remainder = required % chunkWidth; const remainder = required % chunkWidth;
const extra = 0 === remainder ? 0 : chunkWidth - remainder; const extra = 0 === remainder ? 0 : chunkWidth - remainder;
const size = required + extra; const size = required + extra;
@ -111,7 +111,7 @@ class FlatComponent extends BaseComponent {
const window = new this.Window(this.data, this); const window = new this.Window(this.data, this);
for (let i = 0; i < this.caret; ++i) { for (let i = 0; i < this.caret; ++i) {
window.dirty = false; window.dirty = false;
window.cursor += this.schema.width; window.cursor += this.constructor.width;
} }
this.dirty = false; this.dirty = false;
} }
@ -134,7 +134,8 @@ class FlatComponent extends BaseComponent {
entity = entries[i]; entity = entries[i];
} }
this.map[entity] = allocated[i]; this.map[entity] = allocated[i];
window.cursor = allocated[i] * this.schema.width; window.cursor = allocated[i] * this.constructor.width;
window.entity = entity;
for (const [i] of this.schema) { for (const [i] of this.schema) {
if (i in values) { if (i in values) {
window[i] = values[i]; window[i] = values[i];
@ -155,7 +156,7 @@ class FlatComponent extends BaseComponent {
this.Window = this.makeWindowClass(); this.Window = this.makeWindowClass();
} }
const window = new this.Window(this.data, this); const window = new this.Window(this.data, this);
window.cursor = this.map[entity] * this.schema.width; window.cursor = this.map[entity] * this.constructor.width;
return window; return window;
} }
@ -169,7 +170,7 @@ class FlatComponent extends BaseComponent {
if (!this.window) { if (!this.window) {
this.window = new this.Window(this.data, this); this.window = new this.Window(this.data, this);
} }
this.window.cursor = this.map[entity] * this.schema.width; this.window.cursor = this.map[entity] * this.constructor.width;
return this.window; return this.window;
} }
@ -194,18 +195,23 @@ class FlatComponent extends BaseComponent {
} }
let offset = 0; let offset = 0;
const properties = {}; const properties = {};
const {width} = this.constructor;
const get = (type) => ( const get = (type) => (
`return this.view.get${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, true);` `return this.view.get${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, true);`
); );
const set = (type) => [ const set = (type) => [
'this.parent.dirty = true;', `this.parent.setDirty(1, this.view.getBigUint64(this.cursor + ${width - 9}, true));`,
`this.view.set${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, v, true);`, `this.view.set${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, v, true);`,
`this.view.setUint8(this.cursor + ${this.schema.width - 1}, 1, true);`, `this.view.setUint8(this.cursor + ${width - 1}, 1, true);`,
].join(''); ].join('');
/* eslint-disable no-new-func */ /* eslint-disable no-new-func */
properties.dirty = { properties.dirty = {
get: new Function('', `return !!this.view.getUint8(this.cursor + ${this.schema.width - 1}, true);`), get: new Function('', `return !!this.view.getUint8(this.cursor + ${width - 1}, true);`),
set: new Function('v', `this.view.setUint8(this.cursor + ${this.schema.width - 1}, v ? 1 : 0, true);`), set: new Function('v', `this.view.setUint8(this.cursor + ${width - 1}, v ? 1 : 0, true);`),
};
properties.entity = {
get: new Function('', `return this.view.getBigUint64(this.cursor + ${width - 9}, true);`),
set: new Function('v', `this.view.setBigUint64(this.cursor + ${width - 9}, v ? 1 : 0, true);`),
}; };
for (const [i, spec] of this.schema) { for (const [i, spec] of this.schema) {
const {type} = spec; const {type} = spec;
@ -229,7 +235,7 @@ class ArbitraryComponent extends BaseComponent {
allocateMany(count) { allocateMany(count) {
if (!this.Instance) { if (!this.Instance) {
this.Instance = this.constructor.instanceFromSchema(this.schema); this.Instance = this.instanceFromSchema();
} }
const results = super.allocateMany(count); const results = super.allocateMany(count);
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
@ -248,7 +254,7 @@ class ArbitraryComponent extends BaseComponent {
for (const i in this.map) { for (const i in this.map) {
this.data[this.map[i]].dirty = false; this.data[this.map[i]].dirty = false;
} }
this.dirty = false; this.setDirty(false, 0);
} }
createMany(entries) { createMany(entries) {
@ -264,6 +270,7 @@ class ArbitraryComponent extends BaseComponent {
entity = entries[i]; entity = entries[i];
} }
this.map[entity] = allocated[i]; this.map[entity] = allocated[i];
this.data[allocated[i]].entity = entity;
for (const j in values) { for (const j in values) {
if (this.schema.has(j)) { if (this.schema.has(j)) {
this.data[allocated[i]][j] = values[j]; this.data[allocated[i]][j] = values[j];
@ -281,12 +288,16 @@ class ArbitraryComponent extends BaseComponent {
return this.get(entity); return this.get(entity);
} }
static instanceFromSchema(schema) { instanceFromSchema() {
const Component = this;
const Instance = class { const Instance = class {
$$dirty = 1;
$$entity = 0;
constructor() { constructor() {
this.$$dirty = 1; for (const [i, {defaultValue}] of Component.schema) {
for (const [i, {defaultValue}] of schema) {
this[i] = defaultValue; this[i] = defaultValue;
} }
} }
@ -301,7 +312,15 @@ class ArbitraryComponent extends BaseComponent {
this.$$dirty = v; this.$$dirty = v;
}, },
}; };
for (const [i] of schema) { properties.entity = {
get: function get() {
return this.$$entity;
},
set: function set(v) {
this.$$entity = v;
},
};
for (const [i] of Component.schema) {
properties[i] = { properties[i] = {
get: function get() { get: function get() {
return this[`$$${i}`]; return this[`$$${i}`];
@ -309,6 +328,7 @@ class ArbitraryComponent extends BaseComponent {
set: function set(v) { set: function set(v) {
this[`$$${i}`] = v; this[`$$${i}`] = v;
this.$$dirty = 1; this.$$dirty = 1;
Component.setDirty(1, this.entity);
}, },
}; };
} }
@ -322,10 +342,11 @@ export default function ComponentRouter() {
const schema = new Schema(this.constructor.schema); const schema = new Schema(this.constructor.schema);
let RealClass; let RealClass;
if (schema.width > 0) { if (schema.width > 0) {
RealClass = FlatComponent; RealClass = class extends FlatComponent {};
RealClass.width = schema.width + 9; // 1 for dirty, 8 for entity
} }
else { else {
RealClass = ArbitraryComponent; RealClass = class extends ArbitraryComponent {};
} }
return new RealClass(schema); return new RealClass(schema);
} }

View File

@ -6,8 +6,6 @@ export default class Ecs {
$$caret = 1; $$caret = 1;
$$cleanEntities = new Set();
Components = {}; Components = {};
dirty = new Set(); dirty = new Set();
@ -20,24 +18,15 @@ export default class Ecs {
constructor(Components) { constructor(Components) {
for (const i in Components) { for (const i in Components) {
class Component extends Components[i] { const comp = new Components[i]();
const {setDirty} = comp;
set dirty(dirty) { comp.setDirty = (dirty, entity) => {
super.dirty = dirty; setDirty.call(comp, dirty);
const it = this.$$cleanEntities.values(); if (entity) {
let result = it.next(); this.dirty.add(entity);
while (!result.done) {
result = it.next();
} }
for (let i = 0; i < this.$$entities.length; i++) { };
if (this.get(this.$$entities[i])) { this.Components[i] = comp;
this.dirty.add(this.$$entities[i]);
}
}
}
}
this.Components[i] = new Component();
} }
} }
@ -143,7 +132,7 @@ export default class Ecs {
for (const i in this.Components) { for (const i in this.Components) {
this.Components[i].clean(); this.Components[i].clean();
} }
this.dirty = []; this.dirty.clear();
} }
tickFinalize() { tickFinalize() {

View File

@ -65,7 +65,9 @@ for (let i = 0; i < warm; ++i) {
} }
performance.mark('tick0'); performance.mark('tick0');
ecs.tick(0.01); ecs.tick(0.01);
console.log(ecs.dirty.size);
ecs.tickFinalize(); ecs.tickFinalize();
console.log(ecs.dirty.size);
performance.mark('tick1'); performance.mark('tick1');
console.log(ecs.$$systems[0].queries.default.count); console.log(ecs.$$systems[0].queries.default.count);
@ -78,6 +80,7 @@ console.log({
y: p.y, y: p.y,
z: p.z, z: p.z,
dirty: p.dirty, dirty: p.dirty,
entity: p.entity,
}); });
console.log(performance.getEntriesByType('measure').map(({duration, name}) => ({duration, name}))); console.log(performance.getEntriesByType('measure').map(({duration, name}) => ({duration, name})));

View File

@ -4,7 +4,7 @@ export default class Schema {
defaultValues = {}; defaultValues = {};
width = 1; width = 0;
spec; spec;