refactor: test and clean
This commit is contained in:
parent
a70b8c2d76
commit
da6d15e910
|
@ -1,375 +1,17 @@
|
|||
/* eslint-disable guard-for-in, max-classes-per-file, no-restricted-syntax */
|
||||
import ArbitraryComponent from './component/arbitrary';
|
||||
import FlatComponent from './component/flat';
|
||||
import Schema from './schema';
|
||||
import Serializer from './serializer';
|
||||
|
||||
class BaseComponent {
|
||||
|
||||
$$dirty = true;
|
||||
|
||||
map = [];
|
||||
|
||||
pool = [];
|
||||
|
||||
schema;
|
||||
|
||||
serializer;
|
||||
|
||||
constructor(schema) {
|
||||
this.schema = schema;
|
||||
this.serializer = new Serializer(schema);
|
||||
}
|
||||
|
||||
allocate() {
|
||||
const [index] = this.allocateMany(1);
|
||||
return index;
|
||||
}
|
||||
|
||||
allocateMany(count) {
|
||||
const results = [];
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
while (count-- > 0 && this.pool.length > 0) {
|
||||
results.push(this.pool.pop());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
create(entity, values) {
|
||||
const [result] = this.createMany([entity, values]);
|
||||
return result;
|
||||
}
|
||||
|
||||
destroy(entity) {
|
||||
this.destroyMany([entity]);
|
||||
}
|
||||
|
||||
destroyMany(entities) {
|
||||
this.freeMany(entities.map((entity) => this.map[entity]).filter((index) => !!index));
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
this.map[entities[i]] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
get dirty() {
|
||||
return this.$$dirty;
|
||||
}
|
||||
|
||||
setDirty(dirty) {
|
||||
this.$$dirty = dirty;
|
||||
}
|
||||
|
||||
free(index) {
|
||||
this.freeMany([index]);
|
||||
}
|
||||
|
||||
freeMany(indices) {
|
||||
for (let i = 0; i < indices.length; ++i) {
|
||||
this.pool.push(indices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
set(entity, values) {
|
||||
const instance = this.getUnsafe(entity);
|
||||
for (const i in values) {
|
||||
instance[i] = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FlatComponent extends BaseComponent {
|
||||
|
||||
chunkSize = 64;
|
||||
|
||||
caret = 0;
|
||||
|
||||
data = new ArrayBuffer(0);
|
||||
|
||||
Window;
|
||||
|
||||
window;
|
||||
|
||||
allocateMany(count) {
|
||||
const results = super.allocateMany(count);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
count -= results.length;
|
||||
if (count > 0) {
|
||||
const required = (this.caret + count) * this.constructor.width;
|
||||
if (required > this.data.byteLength) {
|
||||
const chunkWidth = this.chunkSize * this.constructor.width;
|
||||
const remainder = required % chunkWidth;
|
||||
const extra = 0 === remainder ? 0 : chunkWidth - remainder;
|
||||
const size = required + extra;
|
||||
const data = new ArrayBuffer(size);
|
||||
(new Uint8Array(data)).set(this.data);
|
||||
this.data = data;
|
||||
}
|
||||
for (let i = 0; i < count; ++i) {
|
||||
results.push(this.caret++);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
clean() {
|
||||
if (!this.dirty) {
|
||||
return;
|
||||
}
|
||||
if (!this.Window) {
|
||||
this.Window = this.makeWindowClass();
|
||||
}
|
||||
const window = new this.Window(this.data, this);
|
||||
for (let i = 0; i < this.caret; ++i) {
|
||||
window.dirty = false;
|
||||
window.cursor += this.constructor.width;
|
||||
}
|
||||
this.setDirty(0, 0);
|
||||
}
|
||||
|
||||
createMany(entries) {
|
||||
if (entries.length > 0) {
|
||||
const allocated = this.allocateMany(entries.length);
|
||||
if (!this.Window) {
|
||||
this.Window = this.makeWindowClass();
|
||||
}
|
||||
const window = new this.Window(this.data, this);
|
||||
const {defaultValues} = this.schema;
|
||||
for (let i = 0; i < entries.length; ++i) {
|
||||
let entity;
|
||||
let values = {};
|
||||
if (Array.isArray(entries[i])) {
|
||||
[entity, values] = entries[i];
|
||||
}
|
||||
else {
|
||||
entity = entries[i];
|
||||
}
|
||||
this.map[entity] = allocated[i];
|
||||
window.cursor = allocated[i] * this.constructor.width;
|
||||
window.entity = entity;
|
||||
for (const [i] of this.schema) {
|
||||
if (i in values) {
|
||||
window[i] = values[i];
|
||||
}
|
||||
else if (i in defaultValues) {
|
||||
window[i] = defaultValues[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get(entity) {
|
||||
if ('undefined' === typeof this.map[entity]) {
|
||||
return undefined;
|
||||
}
|
||||
if (!this.Window) {
|
||||
this.Window = this.makeWindowClass();
|
||||
}
|
||||
const window = new this.Window(this.data, this);
|
||||
window.cursor = this.map[entity] * this.constructor.width;
|
||||
return window;
|
||||
}
|
||||
|
||||
getUnsafe(entity) {
|
||||
if ('undefined' === typeof this.map[entity]) {
|
||||
return undefined;
|
||||
}
|
||||
if (!this.Window) {
|
||||
this.Window = this.makeWindowClass();
|
||||
}
|
||||
if (!this.window) {
|
||||
this.window = new this.Window(this.data, this);
|
||||
}
|
||||
this.window.cursor = this.map[entity] * this.constructor.width;
|
||||
return this.window;
|
||||
}
|
||||
|
||||
makeWindowClass() {
|
||||
const Component = this;
|
||||
class Window {
|
||||
|
||||
cursor = 0;
|
||||
|
||||
parent;
|
||||
|
||||
view;
|
||||
|
||||
constructor(data, parent) {
|
||||
if (data) {
|
||||
this.view = new DataView(data);
|
||||
}
|
||||
if (parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
const json = {};
|
||||
for (const [i] of Component.schema) {
|
||||
json[i] = this[i];
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
||||
let offset = 0;
|
||||
const properties = {};
|
||||
const {width} = this.constructor;
|
||||
const get = (type) => (
|
||||
`return this.view.get${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, true);`
|
||||
);
|
||||
const set = (type) => [
|
||||
`this.parent.setDirty(1, Number(this.view.getBigUint64(this.cursor + ${width - 9}, true)));`,
|
||||
`this.view.set${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, v, true);`,
|
||||
`this.view.setUint8(this.cursor + ${width - 1}, 1, true);`,
|
||||
].join('');
|
||||
/* eslint-disable no-new-func */
|
||||
properties.dirty = {
|
||||
get: new Function('', `return !!this.view.getUint8(this.cursor + ${width - 1}, true);`),
|
||||
set: new Function('v', `this.view.setUint8(this.cursor + ${width - 1}, v ? 1 : 0, true);`),
|
||||
};
|
||||
properties.entity = {
|
||||
get: new Function('', `return Number(this.view.getBigUint64(this.cursor + ${width - 9}, true));`),
|
||||
set: new Function('v', `this.view.setBigUint64(this.cursor + ${width - 9}, BigInt(v), true);`),
|
||||
};
|
||||
for (const [i, spec] of this.schema) {
|
||||
const {type} = spec;
|
||||
properties[i] = {};
|
||||
properties[i].get = new Function('', get(type));
|
||||
properties[i].set = new Function('v', set(type));
|
||||
offset += Schema.sizeOfType(type);
|
||||
}
|
||||
/* eslint-enable no-new-func */
|
||||
Object.defineProperties(Window.prototype, properties);
|
||||
return Window;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ArbitraryComponent extends BaseComponent {
|
||||
|
||||
data = [];
|
||||
|
||||
Instance;
|
||||
|
||||
allocateMany(count) {
|
||||
if (!this.Instance) {
|
||||
this.Instance = this.instanceFromSchema();
|
||||
}
|
||||
const results = super.allocateMany(count);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
count -= results.length;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
while (count--) {
|
||||
results.push(this.data.push(new this.Instance()) - 1);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
clean() {
|
||||
if (!this.dirty) {
|
||||
return;
|
||||
}
|
||||
for (const i in this.map) {
|
||||
this.data[this.map[i]].dirty = false;
|
||||
}
|
||||
this.setDirty(false, 0);
|
||||
}
|
||||
|
||||
createMany(entries) {
|
||||
if (entries.length > 0) {
|
||||
const allocated = this.allocateMany(entries.length);
|
||||
for (let i = 0; i < entries.length; ++i) {
|
||||
let entity;
|
||||
let values = {};
|
||||
if (Array.isArray(entries[i])) {
|
||||
[entity, values] = entries[i];
|
||||
}
|
||||
else {
|
||||
entity = entries[i];
|
||||
}
|
||||
this.map[entity] = allocated[i];
|
||||
this.data[allocated[i]].entity = entity;
|
||||
for (const j in values) {
|
||||
if (this.schema.has(j)) {
|
||||
this.data[allocated[i]][j] = values[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get(entity) {
|
||||
return this.data[this.map[entity]];
|
||||
}
|
||||
|
||||
getUnsafe(entity) {
|
||||
return this.get(entity);
|
||||
}
|
||||
|
||||
instanceFromSchema() {
|
||||
const Component = this;
|
||||
const Instance = class {
|
||||
|
||||
$$dirty = 1;
|
||||
|
||||
$$entity = 0;
|
||||
|
||||
constructor() {
|
||||
for (const [i, {defaultValue}] of Component.schema) {
|
||||
this[i] = defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
const json = {};
|
||||
for (const [i] of Component.schema) {
|
||||
json[i] = this[i];
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
};
|
||||
const properties = {};
|
||||
properties.dirty = {
|
||||
get: function get() {
|
||||
return !!this.$$dirty;
|
||||
},
|
||||
set: function set(v) {
|
||||
this.$$dirty = v;
|
||||
},
|
||||
};
|
||||
properties.entity = {
|
||||
get: function get() {
|
||||
return this.$$entity;
|
||||
},
|
||||
set: function set(v) {
|
||||
this.$$entity = v;
|
||||
},
|
||||
};
|
||||
for (const [i] of Component.schema) {
|
||||
properties[i] = {
|
||||
get: function get() {
|
||||
return this[`$$${i}`];
|
||||
},
|
||||
set: function set(v) {
|
||||
this[`$$${i}`] = v;
|
||||
this.$$dirty = 1;
|
||||
Component.setDirty(1, this.entity);
|
||||
},
|
||||
};
|
||||
}
|
||||
Object.defineProperties(Instance.prototype, properties);
|
||||
return Instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default function ComponentRouter() {
|
||||
const schema = new Schema(this.constructor.schema);
|
||||
let RealClass;
|
||||
if (schema.width > 0) {
|
||||
RealClass = class extends FlatComponent {};
|
||||
RealClass.width = schema.width + 9; // 1 for dirty, 8 for entity
|
||||
RealClass = class extends FlatComponent {
|
||||
|
||||
static width = schema.width + 9; // 1 for dirty, 8 for entity
|
||||
|
||||
};
|
||||
}
|
||||
else {
|
||||
RealClass = class extends ArbitraryComponent {};
|
||||
|
|
121
packages/ecs/src/component/arbitrary.js
Normal file
121
packages/ecs/src/component/arbitrary.js
Normal file
|
@ -0,0 +1,121 @@
|
|||
/* eslint-disable guard-for-in, max-classes-per-file, no-restricted-syntax */
|
||||
import BaseComponent from './base';
|
||||
|
||||
export default class ArbitraryComponent extends BaseComponent {
|
||||
|
||||
data = [];
|
||||
|
||||
Instance;
|
||||
|
||||
allocateMany(count) {
|
||||
if (!this.Instance) {
|
||||
this.Instance = this.instanceFromSchema();
|
||||
}
|
||||
const results = super.allocateMany(count);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
count -= results.length;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
while (count--) {
|
||||
results.push(this.data.push(new this.Instance()) - 1);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
createMany(entries) {
|
||||
if (entries.length > 0) {
|
||||
const allocated = this.allocateMany(entries.length);
|
||||
for (let i = 0; i < entries.length; ++i) {
|
||||
let entity;
|
||||
let values = {};
|
||||
if (Array.isArray(entries[i])) {
|
||||
[entity, values] = entries[i];
|
||||
}
|
||||
else {
|
||||
entity = entries[i];
|
||||
}
|
||||
this.map[entity] = allocated[i];
|
||||
this.data[allocated[i]].entity = entity;
|
||||
for (const j in values) {
|
||||
if (this.schema.has(j)) {
|
||||
this.data[allocated[i]][j] = values[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get(entity) {
|
||||
return this.data[this.map[entity]];
|
||||
}
|
||||
|
||||
getUnsafe(entity) {
|
||||
return this.get(entity);
|
||||
}
|
||||
|
||||
instanceFromSchema() {
|
||||
const Component = this;
|
||||
const Instance = class {
|
||||
|
||||
$$dirty = 1;
|
||||
|
||||
$$entity = 0;
|
||||
|
||||
constructor() {
|
||||
for (const [i, {defaultValue}] of Component.schema) {
|
||||
this[i] = defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
const json = {};
|
||||
for (const [i] of Component.schema) {
|
||||
json[i] = this[i];
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
};
|
||||
const properties = {};
|
||||
properties.dirty = {
|
||||
get: function get() {
|
||||
return !!this.$$dirty;
|
||||
},
|
||||
set: function set(v) {
|
||||
this.$$dirty = v;
|
||||
},
|
||||
};
|
||||
properties.entity = {
|
||||
get: function get() {
|
||||
return this.$$entity;
|
||||
},
|
||||
set: function set(v) {
|
||||
this.$$entity = v;
|
||||
},
|
||||
};
|
||||
for (const [i] of Component.schema) {
|
||||
properties[i] = {
|
||||
get: function get() {
|
||||
return this[`$$${i}`];
|
||||
},
|
||||
set: function set(v) {
|
||||
this[`$$${i}`] = v;
|
||||
this.$$dirty = 1;
|
||||
Component.setDirty(this.entity);
|
||||
},
|
||||
};
|
||||
}
|
||||
Object.defineProperties(Instance.prototype, properties);
|
||||
return Instance;
|
||||
}
|
||||
|
||||
setClean() {
|
||||
super.setClean();
|
||||
if (!this.dirty) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < this.data.length; i++) {
|
||||
this.data[i].dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
79
packages/ecs/src/component/base.js
Normal file
79
packages/ecs/src/component/base.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* eslint-disable no-restricted-syntax, guard-for-in */
|
||||
import Serializer from '../serializer';
|
||||
|
||||
export default class BaseComponent {
|
||||
|
||||
$$dirty = true;
|
||||
|
||||
map = [];
|
||||
|
||||
pool = [];
|
||||
|
||||
schema;
|
||||
|
||||
serializer;
|
||||
|
||||
constructor(schema) {
|
||||
this.schema = schema;
|
||||
this.serializer = new Serializer(schema);
|
||||
}
|
||||
|
||||
allocate() {
|
||||
const [index] = this.allocateMany(1);
|
||||
return index;
|
||||
}
|
||||
|
||||
allocateMany(count) {
|
||||
const results = [];
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
while (count-- > 0 && this.pool.length > 0) {
|
||||
results.push(this.pool.pop());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
create(entity, values) {
|
||||
this.createMany([entity, values]);
|
||||
}
|
||||
|
||||
destroy(entity) {
|
||||
this.destroyMany([entity]);
|
||||
}
|
||||
|
||||
destroyMany(entities) {
|
||||
this.freeMany(entities.map((entity) => this.map[entity]).filter((index) => !!index));
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
this.map[entities[i]] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
get dirty() {
|
||||
return this.$$dirty;
|
||||
}
|
||||
|
||||
free(index) {
|
||||
this.freeMany([index]);
|
||||
}
|
||||
|
||||
freeMany(indices) {
|
||||
for (let i = 0; i < indices.length; ++i) {
|
||||
this.pool.push(indices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
set(entity, values) {
|
||||
const instance = this.getUnsafe(entity);
|
||||
for (const i in values) {
|
||||
instance[i] = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
setClean() {
|
||||
this.$$dirty = false;
|
||||
}
|
||||
|
||||
setDirty() {
|
||||
this.$$dirty = true;
|
||||
}
|
||||
|
||||
}
|
172
packages/ecs/src/component/flat.js
Normal file
172
packages/ecs/src/component/flat.js
Normal file
|
@ -0,0 +1,172 @@
|
|||
/* eslint-disable guard-for-in, max-classes-per-file, no-restricted-syntax */
|
||||
import BaseComponent from './base';
|
||||
import Schema from '../schema';
|
||||
|
||||
export default class FlatComponent extends BaseComponent {
|
||||
|
||||
chunkSize = 64;
|
||||
|
||||
caret = 0;
|
||||
|
||||
data = new ArrayBuffer(0);
|
||||
|
||||
Window;
|
||||
|
||||
window;
|
||||
|
||||
allocateMany(count) {
|
||||
const results = super.allocateMany(count);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
count -= results.length;
|
||||
if (count > 0) {
|
||||
const required = (this.caret + count) * this.constructor.width;
|
||||
if (required > this.data.byteLength) {
|
||||
const chunkWidth = this.chunkSize * this.constructor.width;
|
||||
const remainder = required % chunkWidth;
|
||||
const extra = 0 === remainder ? 0 : chunkWidth - remainder;
|
||||
const size = required + extra;
|
||||
const data = new ArrayBuffer(size);
|
||||
(new Uint8Array(data)).set(this.data);
|
||||
this.data = data;
|
||||
}
|
||||
for (let i = 0; i < count; ++i) {
|
||||
results.push(this.caret++);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
createMany(entries) {
|
||||
if (entries.length > 0) {
|
||||
const allocated = this.allocateMany(entries.length);
|
||||
if (!this.Window) {
|
||||
this.Window = this.makeWindowClass();
|
||||
}
|
||||
const window = new this.Window(this.data, this);
|
||||
const {defaultValues} = this.schema;
|
||||
for (let i = 0; i < entries.length; ++i) {
|
||||
let entity;
|
||||
let values = {};
|
||||
if (Array.isArray(entries[i])) {
|
||||
[entity, values] = entries[i];
|
||||
}
|
||||
else {
|
||||
entity = entries[i];
|
||||
}
|
||||
this.map[entity] = allocated[i];
|
||||
window.cursor = allocated[i] * this.constructor.width;
|
||||
window.entity = entity;
|
||||
for (const [i] of this.schema) {
|
||||
if (i in values) {
|
||||
window[i] = values[i];
|
||||
}
|
||||
else if ('undefined' !== typeof defaultValues[i]) {
|
||||
window[i] = defaultValues[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get(entity) {
|
||||
if ('undefined' === typeof this.map[entity]) {
|
||||
return undefined;
|
||||
}
|
||||
if (!this.Window) {
|
||||
this.Window = this.makeWindowClass();
|
||||
}
|
||||
const window = new this.Window(this.data, this);
|
||||
window.cursor = this.map[entity] * this.constructor.width;
|
||||
return window;
|
||||
}
|
||||
|
||||
getUnsafe(entity) {
|
||||
if ('undefined' === typeof this.map[entity]) {
|
||||
return undefined;
|
||||
}
|
||||
if (!this.Window) {
|
||||
this.Window = this.makeWindowClass();
|
||||
}
|
||||
if (!this.window) {
|
||||
this.window = new this.Window(this.data, this);
|
||||
}
|
||||
this.window.cursor = this.map[entity] * this.constructor.width;
|
||||
return this.window;
|
||||
}
|
||||
|
||||
makeWindowClass() {
|
||||
const Component = this;
|
||||
class Window {
|
||||
|
||||
cursor = 0;
|
||||
|
||||
parent;
|
||||
|
||||
view;
|
||||
|
||||
constructor(data, parent) {
|
||||
if (data) {
|
||||
this.view = new DataView(data);
|
||||
}
|
||||
if (parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
const json = {};
|
||||
for (const [i] of Component.schema) {
|
||||
json[i] = this[i];
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
||||
let offset = 0;
|
||||
const properties = {};
|
||||
const {width} = this.constructor;
|
||||
const get = (type) => (
|
||||
`return this.view.get${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, true);`
|
||||
);
|
||||
const set = (type) => [
|
||||
`this.parent.setDirty(Number(this.view.getBigUint64(this.cursor + ${width - 9}, true)));`,
|
||||
`this.view.set${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, v, true);`,
|
||||
`this.view.setUint8(this.cursor + ${width - 1}, 1, true);`,
|
||||
].join('');
|
||||
/* eslint-disable no-new-func */
|
||||
properties.dirty = {
|
||||
get: new Function('', `return !!this.view.getUint8(this.cursor + ${width - 1}, true);`),
|
||||
set: new Function('v', `this.view.setUint8(this.cursor + ${width - 1}, v ? 1 : 0, true);`),
|
||||
};
|
||||
properties.entity = {
|
||||
get: new Function('', `return Number(this.view.getBigUint64(this.cursor + ${width - 9}, true));`),
|
||||
set: new Function('v', `this.view.setBigUint64(this.cursor + ${width - 9}, BigInt(v), true);`),
|
||||
};
|
||||
for (const [i, spec] of this.schema) {
|
||||
const {type} = spec;
|
||||
properties[i] = {};
|
||||
properties[i].get = new Function('', get(type));
|
||||
properties[i].set = new Function('v', set(type));
|
||||
offset += Schema.sizeOfType(type);
|
||||
}
|
||||
/* eslint-enable no-new-func */
|
||||
Object.defineProperties(Window.prototype, properties);
|
||||
return Window;
|
||||
}
|
||||
|
||||
setClean() {
|
||||
super.setClean();
|
||||
if (!this.dirty) {
|
||||
return;
|
||||
}
|
||||
if (!this.Window) {
|
||||
this.Window = this.makeWindowClass();
|
||||
}
|
||||
const window = new this.Window(this.data, this);
|
||||
for (let i = 0; i < this.caret; ++i) {
|
||||
window.dirty = false;
|
||||
window.cursor += this.constructor.width;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -19,12 +19,9 @@ export default class Ecs {
|
|||
constructor(Components) {
|
||||
for (const i in Components) {
|
||||
const comp = new Components[i]();
|
||||
const {setDirty} = comp;
|
||||
comp.setDirty = (dirty, entity) => {
|
||||
setDirty.call(comp, dirty);
|
||||
if (entity) {
|
||||
comp.setDirty = (entity) => {
|
||||
comp.$$dirty = true;
|
||||
this.dirty.add(entity);
|
||||
}
|
||||
};
|
||||
this.Components[i] = comp;
|
||||
}
|
||||
|
@ -299,7 +296,7 @@ export default class Ecs {
|
|||
|
||||
tickClean() {
|
||||
for (const i in this.Components) {
|
||||
this.Components[i].clean();
|
||||
this.Components[i].setClean();
|
||||
}
|
||||
this.dirty.clear();
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import Schema from './schema';
|
|||
export default class Serializer {
|
||||
|
||||
constructor(schema) {
|
||||
this.schema = schema;
|
||||
this.schema = schema instanceof Schema ? schema : new Schema(schema);
|
||||
}
|
||||
|
||||
decode(view, destination, offset = 0) {
|
||||
|
|
15
packages/ecs/test/schema.js
Normal file
15
packages/ecs/test/schema.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import {expect} from 'chai';
|
||||
|
||||
import Schema from '../src/schema';
|
||||
|
||||
it('can validate a schema', () => {
|
||||
expect(() => new Schema({test: 'unknown'}))
|
||||
.to.throw();
|
||||
});
|
||||
|
||||
it('can calculate the size of an instance', () => {
|
||||
expect((new Schema({foo: 'uint8', bar: 'uint32'})).sizeOf({foo: 69, bar: 420}))
|
||||
.to.equal(5);
|
||||
expect((new Schema({foo: 'string'})).sizeOf({foo: 'hi'}))
|
||||
.to.equal(4 + 2);
|
||||
});
|
32
packages/ecs/test/serializer.js
Normal file
32
packages/ecs/test/serializer.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
import {expect} from 'chai';
|
||||
|
||||
import Serializer from '../src/serializer';
|
||||
|
||||
it('can encode and decode', () => {
|
||||
const entries = [
|
||||
['uint8', 255],
|
||||
['int8', -128],
|
||||
['int8', 127],
|
||||
['uint16', 65535],
|
||||
['int16', -32768],
|
||||
['int16', 32767],
|
||||
['uint32', 4294967295],
|
||||
['int32', -2147483648],
|
||||
['int32', 2147483647],
|
||||
['uint64', 18446744073709551615n],
|
||||
['int64', -9223372036854775808n],
|
||||
['int64', 9223372036854775807n],
|
||||
['float32', 0.5],
|
||||
['float64', 1.234],
|
||||
['string', 'hello world'],
|
||||
];
|
||||
const schema = entries.reduce((r, [type]) => ({...r, [Object.keys(r).length]: type}), {});
|
||||
const data = entries.reduce((r, [, value]) => ({...r, [Object.keys(r).length]: value}), {});
|
||||
const serializer = new Serializer(schema);
|
||||
const view = new DataView(new ArrayBuffer(serializer.schema.sizeOf(data)));
|
||||
serializer.encode(data, view);
|
||||
const result = {};
|
||||
serializer.decode(view, result);
|
||||
expect(data)
|
||||
.to.deep.equal(result);
|
||||
});
|
Loading…
Reference in New Issue
Block a user