refactor: names
This commit is contained in:
parent
95a8e5f13e
commit
5b2db45e94
|
@ -8,14 +8,14 @@ const specificationsOrClasses = gather(
|
||||||
);
|
);
|
||||||
|
|
||||||
const Components = {};
|
const Components = {};
|
||||||
for (const name in specificationsOrClasses) {
|
for (const componentName in specificationsOrClasses) {
|
||||||
const specificationOrClass = specificationsOrClasses[name];
|
const specificationOrClass = specificationsOrClasses[componentName];
|
||||||
if (specificationOrClass instanceof Base) {
|
if (specificationOrClass instanceof Base) {
|
||||||
Components[name] = specificationOrClass;
|
Components[componentName] = specificationOrClass;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Components[name] = class Component extends Arbitrary {
|
Components[componentName] = class Component extends Arbitrary {
|
||||||
static name = name;
|
static name = componentName;
|
||||||
static schema = new Schema({
|
static schema = new Schema({
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: specificationOrClass,
|
properties: specificationOrClass,
|
||||||
|
|
149
app/ecs/ecs.js
149
app/ecs/ecs.js
|
@ -10,22 +10,22 @@ export default class Ecs {
|
||||||
|
|
||||||
$$caret = 1;
|
$$caret = 1;
|
||||||
|
|
||||||
|
Components = {};
|
||||||
|
|
||||||
diff = {};
|
diff = {};
|
||||||
|
|
||||||
Systems = {};
|
Systems = {};
|
||||||
|
|
||||||
Types = {};
|
|
||||||
|
|
||||||
$$entities = {};
|
$$entities = {};
|
||||||
|
|
||||||
$$entityFactory = new EntityFactory();
|
$$entityFactory = new EntityFactory();
|
||||||
|
|
||||||
constructor({Systems, Types} = {}) {
|
constructor({Systems, Components} = {}) {
|
||||||
for (const name in Types) {
|
for (const componentName in Components) {
|
||||||
this.Types[name] = new Types[name](this);
|
this.Components[componentName] = new Components[componentName](this);
|
||||||
}
|
}
|
||||||
for (const name in Systems) {
|
for (const systemName in Systems) {
|
||||||
this.Systems[name] = new Systems[name](this);
|
this.Systems[systemName] = new Systems[systemName](this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,12 +42,12 @@ export default class Ecs {
|
||||||
}
|
}
|
||||||
const componentsToRemove = [];
|
const componentsToRemove = [];
|
||||||
const componentsToUpdate = {};
|
const componentsToUpdate = {};
|
||||||
for (const i in components) {
|
for (const componentName in components) {
|
||||||
if (false === components[i]) {
|
if (false === components[componentName]) {
|
||||||
componentsToRemove.push(i);
|
componentsToRemove.push(componentName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
componentsToUpdate[i] = components[i];
|
componentsToUpdate[componentName] = components[componentName];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (componentsToRemove.length > 0) {
|
if (componentsToRemove.length > 0) {
|
||||||
|
@ -84,24 +84,24 @@ export default class Ecs {
|
||||||
const creating = {};
|
const creating = {};
|
||||||
for (let i = 0; i < specificsList.length; i++) {
|
for (let i = 0; i < specificsList.length; i++) {
|
||||||
const [entityId, components] = specificsList[i];
|
const [entityId, components] = specificsList[i];
|
||||||
const componentKeys = [];
|
const componentNames = [];
|
||||||
for (const name in components) {
|
for (const componentName in components) {
|
||||||
if (this.Types[name]) {
|
if (this.Components[componentName]) {
|
||||||
componentKeys.push(name);
|
componentNames.push(componentName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entityIds.push(entityId);
|
entityIds.push(entityId);
|
||||||
this.rebuild(entityId, () => componentKeys);
|
this.rebuild(entityId, () => componentNames);
|
||||||
for (const component of componentKeys) {
|
for (const componentName of componentNames) {
|
||||||
if (!creating[component]) {
|
if (!creating[componentName]) {
|
||||||
creating[component] = [];
|
creating[componentName] = [];
|
||||||
}
|
}
|
||||||
creating[component].push([entityId, components[component]]);
|
creating[componentName].push([entityId, components[componentName]]);
|
||||||
}
|
}
|
||||||
this.markChange(entityId, components);
|
this.markChange(entityId, components);
|
||||||
}
|
}
|
||||||
for (const i in creating) {
|
for (const i in creating) {
|
||||||
this.Types[i].createMany(creating[i]);
|
this.Components[i].createMany(creating[i]);
|
||||||
}
|
}
|
||||||
this.reindex(entityIds);
|
this.reindex(entityIds);
|
||||||
return entityIds;
|
return entityIds;
|
||||||
|
@ -112,13 +112,13 @@ export default class Ecs {
|
||||||
}
|
}
|
||||||
|
|
||||||
deindex(entityIds) {
|
deindex(entityIds) {
|
||||||
for (const name in this.Systems) {
|
for (const systemName in this.Systems) {
|
||||||
this.Systems[name].deindex(entityIds);
|
this.Systems[systemName].deindex(entityIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static deserialize(ecs, view) {
|
static deserialize(ecs, view) {
|
||||||
const types = Object.keys(ecs.Types);
|
const componentNames = Object.keys(ecs.Components);
|
||||||
const {entities, systems} = decoder.decode(view.buffer);
|
const {entities, systems} = decoder.decode(view.buffer);
|
||||||
for (const system of systems) {
|
for (const system of systems) {
|
||||||
ecs.system(system).active = true;
|
ecs.system(system).active = true;
|
||||||
|
@ -129,7 +129,10 @@ export default class Ecs {
|
||||||
max = Math.max(max, parseInt(id));
|
max = Math.max(max, parseInt(id));
|
||||||
specifics.push([
|
specifics.push([
|
||||||
parseInt(id),
|
parseInt(id),
|
||||||
Object.fromEntries(Object.entries(entities[id]).filter(([type]) => types.includes(type))),
|
Object.fromEntries(
|
||||||
|
Object.entries(entities[id])
|
||||||
|
.filter(([componentName]) => componentNames.includes(componentName)),
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
ecs.$$caret = max + 1;
|
ecs.$$caret = max + 1;
|
||||||
|
@ -152,17 +155,17 @@ export default class Ecs {
|
||||||
if (!this.$$entities[entityId]) {
|
if (!this.$$entities[entityId]) {
|
||||||
throw new Error(`can't destroy non-existent entity ${entityId}`);
|
throw new Error(`can't destroy non-existent entity ${entityId}`);
|
||||||
}
|
}
|
||||||
for (const component of this.$$entities[entityId].constructor.types) {
|
for (const componentName of this.$$entities[entityId].constructor.componentNames) {
|
||||||
if (!destroying[component]) {
|
if (!destroying[componentName]) {
|
||||||
destroying[component] = [];
|
destroying[componentName] = [];
|
||||||
}
|
}
|
||||||
destroying[component].push(entityId);
|
destroying[componentName].push(entityId);
|
||||||
}
|
}
|
||||||
this.$$entities[entityId] = undefined;
|
this.$$entities[entityId] = undefined;
|
||||||
this.diff[entityId] = false;
|
this.diff[entityId] = false;
|
||||||
}
|
}
|
||||||
for (const i in destroying) {
|
for (const i in destroying) {
|
||||||
this.Types[i].destroyMany(destroying[i]);
|
this.Components[i].destroyMany(destroying[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,20 +200,20 @@ export default class Ecs {
|
||||||
const inserting = {};
|
const inserting = {};
|
||||||
const unique = new Set();
|
const unique = new Set();
|
||||||
for (const [entityId, components] of entities) {
|
for (const [entityId, components] of entities) {
|
||||||
this.rebuild(entityId, (types) => [...new Set(types.concat(Object.keys(components)))]);
|
this.rebuild(entityId, (componentNames) => [...new Set(componentNames.concat(Object.keys(components)))]);
|
||||||
const diff = {};
|
const diff = {};
|
||||||
for (const component in components) {
|
for (const componentName in components) {
|
||||||
if (!inserting[component]) {
|
if (!inserting[componentName]) {
|
||||||
inserting[component] = [];
|
inserting[componentName] = [];
|
||||||
}
|
}
|
||||||
diff[component] = {};
|
diff[componentName] = {};
|
||||||
inserting[component].push([entityId, components[component]]);
|
inserting[componentName].push([entityId, components[componentName]]);
|
||||||
}
|
}
|
||||||
unique.add(entityId);
|
unique.add(entityId);
|
||||||
this.markChange(entityId, diff);
|
this.markChange(entityId, diff);
|
||||||
}
|
}
|
||||||
for (const component in inserting) {
|
for (const componentName in inserting) {
|
||||||
this.Types[component].insertMany(inserting[component]);
|
this.Components[componentName].insertMany(inserting[componentName]);
|
||||||
}
|
}
|
||||||
this.reindex(unique.values());
|
this.reindex(unique.values());
|
||||||
}
|
}
|
||||||
|
@ -223,38 +226,38 @@ export default class Ecs {
|
||||||
// Created?
|
// Created?
|
||||||
else if (!this.diff[entityId]) {
|
else if (!this.diff[entityId]) {
|
||||||
const filtered = {};
|
const filtered = {};
|
||||||
for (const name in components) {
|
for (const componentName in components) {
|
||||||
filtered[name] = false === components[name]
|
filtered[componentName] = false === components[componentName]
|
||||||
? false
|
? false
|
||||||
: this.Types[name].constructor.filterDefaults(components[name]);
|
: this.Components[componentName].constructor.filterDefaults(components[componentName]);
|
||||||
}
|
}
|
||||||
this.diff[entityId] = filtered;
|
this.diff[entityId] = filtered;
|
||||||
}
|
}
|
||||||
// Otherwise, merge.
|
// Otherwise, merge.
|
||||||
else {
|
else {
|
||||||
for (const name in components) {
|
for (const componentName in components) {
|
||||||
this.diff[entityId][name] = false === components[name]
|
this.diff[entityId][componentName] = false === components[componentName]
|
||||||
? false
|
? false
|
||||||
: this.Types[name].mergeDiff(
|
: this.Components[componentName].mergeDiff(
|
||||||
this.diff[entityId][name] || {},
|
this.diff[entityId][componentName] || {},
|
||||||
components[name],
|
components[componentName],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuild(entityId, types) {
|
rebuild(entityId, componentNames) {
|
||||||
let existing = [];
|
let existing = [];
|
||||||
if (this.$$entities[entityId]) {
|
if (this.$$entities[entityId]) {
|
||||||
existing.push(...this.$$entities[entityId].constructor.types);
|
existing.push(...this.$$entities[entityId].constructor.componentNames);
|
||||||
}
|
}
|
||||||
const Class = this.$$entityFactory.makeClass(types(existing), this.Types);
|
const Class = this.$$entityFactory.makeClass(componentNames(existing), this.Components);
|
||||||
this.$$entities[entityId] = new Class(entityId);
|
this.$$entities[entityId] = new Class(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
reindex(entityIds) {
|
reindex(entityIds) {
|
||||||
for (const name in this.Systems) {
|
for (const systemName in this.Systems) {
|
||||||
this.Systems[name].reindex(entityIds);
|
this.Systems[systemName].reindex(entityIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,18 +271,18 @@ export default class Ecs {
|
||||||
for (const [entityId, components] of entities) {
|
for (const [entityId, components] of entities) {
|
||||||
unique.add(entityId);
|
unique.add(entityId);
|
||||||
const diff = {};
|
const diff = {};
|
||||||
for (const component of components) {
|
for (const componentName of components) {
|
||||||
diff[component] = false;
|
diff[componentName] = false;
|
||||||
if (!removing[component]) {
|
if (!removing[componentName]) {
|
||||||
removing[component] = [];
|
removing[componentName] = [];
|
||||||
}
|
}
|
||||||
removing[component].push(entityId);
|
removing[componentName].push(entityId);
|
||||||
}
|
}
|
||||||
this.markChange(entityId, diff);
|
this.markChange(entityId, diff);
|
||||||
this.rebuild(entityId, (types) => types.filter((type) => !components.includes(type)));
|
this.rebuild(entityId, (componentNames) => componentNames.filter((type) => !components.includes(type)));
|
||||||
}
|
}
|
||||||
for (const component in removing) {
|
for (const componentName in removing) {
|
||||||
this.Types[component].destroyMany(removing[component]);
|
this.Components[componentName].destroyMany(removing[componentName]);
|
||||||
}
|
}
|
||||||
this.reindex(unique.values());
|
this.reindex(unique.values());
|
||||||
}
|
}
|
||||||
|
@ -301,7 +304,7 @@ export default class Ecs {
|
||||||
let size = 0;
|
let size = 0;
|
||||||
// # of components.
|
// # of components.
|
||||||
size += 2;
|
size += 2;
|
||||||
for (const type in this.Types) {
|
for (const type in this.Components) {
|
||||||
size += Schema.sizeOf(type, {type: 'string'});
|
size += Schema.sizeOf(type, {type: 'string'});
|
||||||
}
|
}
|
||||||
// # of entities.
|
// # of entities.
|
||||||
|
@ -312,19 +315,19 @@ export default class Ecs {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
system(name) {
|
system(systemName) {
|
||||||
return this.Systems[name];
|
return this.Systems[systemName];
|
||||||
}
|
}
|
||||||
|
|
||||||
tick(elapsed) {
|
tick(elapsed) {
|
||||||
for (const name in this.Systems) {
|
for (const systemName in this.Systems) {
|
||||||
if (this.Systems[name].active) {
|
if (this.Systems[systemName].active) {
|
||||||
this.Systems[name].tick(elapsed);
|
this.Systems[systemName].tick(elapsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const name in this.Systems) {
|
for (const systemName in this.Systems) {
|
||||||
if (this.Systems[name].active) {
|
if (this.Systems[systemName].active) {
|
||||||
this.Systems[name].finalize(elapsed);
|
this.Systems[systemName].finalize(elapsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.tickDestruction();
|
this.tickDestruction();
|
||||||
|
@ -332,8 +335,8 @@ export default class Ecs {
|
||||||
|
|
||||||
tickDestruction() {
|
tickDestruction() {
|
||||||
const unique = new Set();
|
const unique = new Set();
|
||||||
for (const name in this.Systems) {
|
for (const systemName in this.Systems) {
|
||||||
const System = this.Systems[name];
|
const System = this.Systems[systemName];
|
||||||
if (System.active) {
|
if (System.active) {
|
||||||
for (let j = 0; j < System.destroying.length; j++) {
|
for (let j = 0; j < System.destroying.length; j++) {
|
||||||
unique.add(System.destroying[j]);
|
unique.add(System.destroying[j]);
|
||||||
|
@ -352,9 +355,9 @@ export default class Ecs {
|
||||||
entities[id] = this.$$entities[id].toJSON();
|
entities[id] = this.$$entities[id].toJSON();
|
||||||
}
|
}
|
||||||
const systems = [];
|
const systems = [];
|
||||||
for (const name in this.Systems) {
|
for (const systemName in this.Systems) {
|
||||||
if (this.Systems[name].active) {
|
if (this.Systems[systemName].active) {
|
||||||
systems.push(name);
|
systems.push(systemName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -68,14 +68,14 @@ test('activates and deactivates systems at runtime', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('creates entities with components', () => {
|
test('creates entities with components', () => {
|
||||||
const ecs = new Ecs({Types: {Empty, Position}});
|
const ecs = new Ecs({Components: {Empty, Position}});
|
||||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||||
expect(JSON.stringify(ecs.get(entity)))
|
expect(JSON.stringify(ecs.get(entity)))
|
||||||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("removes entities' components", () => {
|
test("removes entities' components", () => {
|
||||||
const ecs = new Ecs({Types: {Empty, Position}});
|
const ecs = new Ecs({Components: {Empty, Position}});
|
||||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||||
ecs.remove(entity, ['Position']);
|
ecs.remove(entity, ['Position']);
|
||||||
expect(JSON.stringify(ecs.get(entity)))
|
expect(JSON.stringify(ecs.get(entity)))
|
||||||
|
@ -83,14 +83,14 @@ test("removes entities' components", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('gets entities', () => {
|
test('gets entities', () => {
|
||||||
const ecs = new Ecs({Types: {Empty, Position}});
|
const ecs = new Ecs({Components: {Empty, Position}});
|
||||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||||
expect(JSON.stringify(ecs.get(entity)))
|
expect(JSON.stringify(ecs.get(entity)))
|
||||||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('destroys entities', () => {
|
test('destroys entities', () => {
|
||||||
const ecs = new Ecs({Types: {Empty, Position}});
|
const ecs = new Ecs({Components: {Empty, Position}});
|
||||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||||
expect(JSON.stringify(ecs.get(entity)))
|
expect(JSON.stringify(ecs.get(entity)))
|
||||||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
||||||
|
@ -106,7 +106,7 @@ test('destroys entities', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('inserts components into entities', () => {
|
test('inserts components into entities', () => {
|
||||||
const ecs = new Ecs({Types: {Empty, Position}});
|
const ecs = new Ecs({Components: {Empty, Position}});
|
||||||
const entity = ecs.create({Empty: {}});
|
const entity = ecs.create({Empty: {}});
|
||||||
ecs.insert(entity, {Position: {y: 128}});
|
ecs.insert(entity, {Position: {y: 128}});
|
||||||
expect(JSON.stringify(ecs.get(entity)))
|
expect(JSON.stringify(ecs.get(entity)))
|
||||||
|
@ -123,6 +123,7 @@ test('ticks systems', () => {
|
||||||
z: {type: 'int32'},
|
z: {type: 'int32'},
|
||||||
});
|
});
|
||||||
const ecs = new Ecs({
|
const ecs = new Ecs({
|
||||||
|
Components: {Momentum, Position},
|
||||||
Systems: {
|
Systems: {
|
||||||
Physics: class Physics extends System {
|
Physics: class Physics extends System {
|
||||||
|
|
||||||
|
@ -142,7 +143,6 @@ test('ticks systems', () => {
|
||||||
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Types: {Momentum, Position},
|
|
||||||
});
|
});
|
||||||
ecs.system('Physics').active = true;
|
ecs.system('Physics').active = true;
|
||||||
const entity = ecs.create({Momentum: {}, Position: {y: 128}});
|
const entity = ecs.create({Momentum: {}, Position: {y: 128}});
|
||||||
|
@ -220,6 +220,7 @@ test('schedules entities to be deleted when ticking systems', () => {
|
||||||
test('adds components to and remove components from entities when ticking systems', () => {
|
test('adds components to and remove components from entities when ticking systems', () => {
|
||||||
let addLength, removeLength;
|
let addLength, removeLength;
|
||||||
const ecs = new Ecs({
|
const ecs = new Ecs({
|
||||||
|
Components: {Foo: wrapSpecification('Foo', {bar: {type: 'uint8'}})},
|
||||||
Systems: {
|
Systems: {
|
||||||
AddComponent: class extends System {
|
AddComponent: class extends System {
|
||||||
static queries() {
|
static queries() {
|
||||||
|
@ -248,7 +249,6 @@ test('adds components to and remove components from entities when ticking system
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Types: {Foo: wrapSpecification('Foo', {bar: {type: 'uint8'}})},
|
|
||||||
});
|
});
|
||||||
ecs.system('AddComponent').active = true;
|
ecs.system('AddComponent').active = true;
|
||||||
ecs.create();
|
ecs.create();
|
||||||
|
@ -275,7 +275,7 @@ test('generates coalesced diffs for entity creation', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('generates diffs for adding and removing components', () => {
|
test('generates diffs for adding and removing components', () => {
|
||||||
const ecs = new Ecs({Types: {Position}});
|
const ecs = new Ecs({Components: {Position}});
|
||||||
let entity;
|
let entity;
|
||||||
entity = ecs.create();
|
entity = ecs.create();
|
||||||
ecs.setClean();
|
ecs.setClean();
|
||||||
|
@ -291,7 +291,7 @@ test('generates diffs for adding and removing components', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('generates diffs for empty components', () => {
|
test('generates diffs for empty components', () => {
|
||||||
const ecs = new Ecs({Types: {Empty}});
|
const ecs = new Ecs({Components: {Empty}});
|
||||||
let entity;
|
let entity;
|
||||||
entity = ecs.create({Empty});
|
entity = ecs.create({Empty});
|
||||||
expect(ecs.diff)
|
expect(ecs.diff)
|
||||||
|
@ -303,7 +303,7 @@ test('generates diffs for empty components', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('generates diffs for entity mutations', () => {
|
test('generates diffs for entity mutations', () => {
|
||||||
const ecs = new Ecs({Types: {Position}});
|
const ecs = new Ecs({Components: {Position}});
|
||||||
let entity;
|
let entity;
|
||||||
entity = ecs.create({Position: {}});
|
entity = ecs.create({Position: {}});
|
||||||
ecs.setClean();
|
ecs.setClean();
|
||||||
|
@ -316,7 +316,7 @@ test('generates diffs for entity mutations', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('generates coalesced diffs for components', () => {
|
test('generates coalesced diffs for components', () => {
|
||||||
const ecs = new Ecs({Types: {Position}});
|
const ecs = new Ecs({Components: {Position}});
|
||||||
let entity;
|
let entity;
|
||||||
entity = ecs.create({Position});
|
entity = ecs.create({Position});
|
||||||
ecs.remove(entity, ['Position']);
|
ecs.remove(entity, ['Position']);
|
||||||
|
@ -328,7 +328,7 @@ test('generates coalesced diffs for components', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('generates coalesced diffs for mutations', () => {
|
test('generates coalesced diffs for mutations', () => {
|
||||||
const ecs = new Ecs({Types: {Position}});
|
const ecs = new Ecs({Components: {Position}});
|
||||||
let entity;
|
let entity;
|
||||||
entity = ecs.create({Position});
|
entity = ecs.create({Position});
|
||||||
ecs.setClean();
|
ecs.setClean();
|
||||||
|
@ -350,7 +350,7 @@ test('generates diffs for deletions', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('applies creation patches', () => {
|
test('applies creation patches', () => {
|
||||||
const ecs = new Ecs({Types: {Position}});
|
const ecs = new Ecs({Components: {Position}});
|
||||||
ecs.apply({16: {Position: {x: 64}}});
|
ecs.apply({16: {Position: {x: 64}}});
|
||||||
expect(Array.from(ecs.entities).length)
|
expect(Array.from(ecs.entities).length)
|
||||||
.to.equal(1);
|
.to.equal(1);
|
||||||
|
@ -359,7 +359,7 @@ test('applies creation patches', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('applies update patches', () => {
|
test('applies update patches', () => {
|
||||||
const ecs = new Ecs({Types: {Position}});
|
const ecs = new Ecs({Components: {Position}});
|
||||||
ecs.createSpecific(16, {Position: {x: 64}});
|
ecs.createSpecific(16, {Position: {x: 64}});
|
||||||
ecs.apply({16: {Position: {x: 128}}});
|
ecs.apply({16: {Position: {x: 128}}});
|
||||||
expect(Array.from(ecs.entities).length)
|
expect(Array.from(ecs.entities).length)
|
||||||
|
@ -369,7 +369,7 @@ test('applies update patches', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('applies entity deletion patches', () => {
|
test('applies entity deletion patches', () => {
|
||||||
const ecs = new Ecs({Types: {Position}});
|
const ecs = new Ecs({Components: {Position}});
|
||||||
ecs.createSpecific(16, {Position: {x: 64}});
|
ecs.createSpecific(16, {Position: {x: 64}});
|
||||||
ecs.apply({16: false});
|
ecs.apply({16: false});
|
||||||
expect(Array.from(ecs.entities).length)
|
expect(Array.from(ecs.entities).length)
|
||||||
|
@ -377,17 +377,17 @@ test('applies entity deletion patches', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('applies component deletion patches', () => {
|
test('applies component deletion patches', () => {
|
||||||
const ecs = new Ecs({Types: {Empty, Position}});
|
const ecs = new Ecs({Components: {Empty, Position}});
|
||||||
ecs.createSpecific(16, {Empty: {}, Position: {x: 64}});
|
ecs.createSpecific(16, {Empty: {}, Position: {x: 64}});
|
||||||
expect(ecs.get(16).constructor.types)
|
expect(ecs.get(16).constructor.componentNames)
|
||||||
.to.deep.equal(['Empty', 'Position']);
|
.to.deep.equal(['Empty', 'Position']);
|
||||||
ecs.apply({16: {Empty: false}});
|
ecs.apply({16: {Empty: false}});
|
||||||
expect(ecs.get(16).constructor.types)
|
expect(ecs.get(16).constructor.componentNames)
|
||||||
.to.deep.equal(['Position']);
|
.to.deep.equal(['Position']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('calculates entity size', () => {
|
test('calculates entity size', () => {
|
||||||
const ecs = new Ecs({Types: {Empty, Position}});
|
const ecs = new Ecs({Components: {Empty, Position}});
|
||||||
ecs.createSpecific(1, {Empty: {}, Position: {}});
|
ecs.createSpecific(1, {Empty: {}, Position: {}});
|
||||||
// ID + # of components + Empty + Position + x + y + z
|
// ID + # of components + Empty + Position + x + y + z
|
||||||
// 4 + 2 + 2 + 4 + 2 + 4 + 4 + 4 + 4 = 30
|
// 4 + 2 + 2 + 4 + 2 + 4 + 4 + 4 + 4 = 30
|
||||||
|
@ -396,7 +396,7 @@ test('calculates entity size', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('serializes and deserializes', () => {
|
test('serializes and deserializes', () => {
|
||||||
const ecs = new Ecs({Types: {Empty, Name, Position}});
|
const ecs = new Ecs({Components: {Empty, Name, Position}});
|
||||||
ecs.createSpecific(1, {Empty: {}, Position: {x: 64}});
|
ecs.createSpecific(1, {Empty: {}, Position: {x: 64}});
|
||||||
ecs.createSpecific(16, {Name: {name: 'foobar'}, Position: {x: 128}});
|
ecs.createSpecific(16, {Name: {name: 'foobar'}, Position: {x: 128}});
|
||||||
expect(ecs.toJSON())
|
expect(ecs.toJSON())
|
||||||
|
@ -409,14 +409,14 @@ test('serializes and deserializes', () => {
|
||||||
});
|
});
|
||||||
const view = Ecs.serialize(ecs);
|
const view = Ecs.serialize(ecs);
|
||||||
const deserialized = Ecs.deserialize(
|
const deserialized = Ecs.deserialize(
|
||||||
new Ecs({Types: {Empty, Name, Position}}),
|
new Ecs({Components: {Empty, Name, Position}}),
|
||||||
view,
|
view,
|
||||||
);
|
);
|
||||||
expect(Array.from(deserialized.entities).length)
|
expect(Array.from(deserialized.entities).length)
|
||||||
.to.equal(2);
|
.to.equal(2);
|
||||||
expect(deserialized.get(1).constructor.types)
|
expect(deserialized.get(1).constructor.componentNames)
|
||||||
.to.deep.equal(['Empty', 'Position']);
|
.to.deep.equal(['Empty', 'Position']);
|
||||||
expect(deserialized.get(16).constructor.types)
|
expect(deserialized.get(16).constructor.componentNames)
|
||||||
.to.deep.equal(['Name', 'Position']);
|
.to.deep.equal(['Name', 'Position']);
|
||||||
expect(JSON.stringify(deserialized.get(1)))
|
expect(JSON.stringify(deserialized.get(1)))
|
||||||
.to.equal(JSON.stringify({Empty: {}, Position: {x: 64}}))
|
.to.equal(JSON.stringify({Empty: {}, Position: {x: 64}}))
|
||||||
|
@ -429,12 +429,12 @@ test('serializes and deserializes', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('deserializes from compatible ECS', () => {
|
test('deserializes from compatible ECS', () => {
|
||||||
const ecs = new Ecs({Types: {Empty, Name, Position}});
|
const ecs = new Ecs({Components: {Empty, Name, Position}});
|
||||||
ecs.createSpecific(1, {Empty: {}, Position: {x: 64}});
|
ecs.createSpecific(1, {Empty: {}, Position: {x: 64}});
|
||||||
ecs.createSpecific(16, {Name: {name: 'foobar'}, Position: {x: 128}});
|
ecs.createSpecific(16, {Name: {name: 'foobar'}, Position: {x: 128}});
|
||||||
const view = Ecs.serialize(ecs);
|
const view = Ecs.serialize(ecs);
|
||||||
const deserialized = Ecs.deserialize(
|
const deserialized = Ecs.deserialize(
|
||||||
new Ecs({Types: {Empty, Name}}),
|
new Ecs({Components: {Empty, Name}}),
|
||||||
view,
|
view,
|
||||||
);
|
);
|
||||||
expect(deserialized.get(1).toJSON())
|
expect(deserialized.get(1).toJSON())
|
||||||
|
|
|
@ -7,8 +7,8 @@ export default class EntityFactory {
|
||||||
|
|
||||||
$$tries = new Node();
|
$$tries = new Node();
|
||||||
|
|
||||||
makeClass(types, Types) {
|
makeClass(componentNames, Components) {
|
||||||
const sorted = types.toSorted();
|
const sorted = componentNames.toSorted();
|
||||||
let walk = this.$$tries;
|
let walk = this.$$tries;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < sorted.length) {
|
while (i < sorted.length) {
|
||||||
|
@ -20,14 +20,14 @@ export default class EntityFactory {
|
||||||
}
|
}
|
||||||
if (!walk.class) {
|
if (!walk.class) {
|
||||||
class Entity {
|
class Entity {
|
||||||
static types = sorted;
|
static componentNames = sorted;
|
||||||
constructor(id) {
|
constructor(id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
size() {
|
size() {
|
||||||
let size = 0;
|
let size = 0;
|
||||||
for (const component of this.constructor.types) {
|
for (const componentName of this.constructor.componentNames) {
|
||||||
const instance = Types[component];
|
const instance = Components[componentName];
|
||||||
size += 2 + 4 + instance.constructor.schema.sizeOf(instance.get(this.id));
|
size += 2 + 4 + instance.constructor.schema.sizeOf(instance.get(this.id));
|
||||||
}
|
}
|
||||||
// ID + # of components.
|
// ID + # of components.
|
||||||
|
@ -37,7 +37,7 @@ export default class EntityFactory {
|
||||||
const properties = {};
|
const properties = {};
|
||||||
for (const type of sorted) {
|
for (const type of sorted) {
|
||||||
properties[type] = {};
|
properties[type] = {};
|
||||||
const get = Types[type].get.bind(Types[type]);
|
const get = Components[type].get.bind(Components[type]);
|
||||||
properties[type].get = function() {
|
properties[type].get = function() {
|
||||||
return get(this.id);
|
return get(this.id);
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,15 +4,15 @@ export default class Query {
|
||||||
|
|
||||||
$$index = new Set();
|
$$index = new Set();
|
||||||
|
|
||||||
constructor(parameters, Types) {
|
constructor(parameters, Components) {
|
||||||
for (let i = 0; i < parameters.length; ++i) {
|
for (let i = 0; i < parameters.length; ++i) {
|
||||||
const parameter = parameters[i];
|
const parameter = parameters[i];
|
||||||
switch (parameter.charCodeAt(0)) {
|
switch (parameter.charCodeAt(0)) {
|
||||||
case '!'.charCodeAt(0):
|
case '!'.charCodeAt(0):
|
||||||
this.$$criteria.without.push(Types[parameter.slice(1)]);
|
this.$$criteria.without.push(Components[parameter.slice(1)]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.$$criteria.with.push(Types[parameter]);
|
this.$$criteria.with.push(Components[parameter]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,13 @@ const A = new (wrapSpecification('A', {a: {type: 'int32', defaultValue: 420}}));
|
||||||
const B = new (wrapSpecification('B', {b: {type: 'int32', defaultValue: 69}}));
|
const B = new (wrapSpecification('B', {b: {type: 'int32', defaultValue: 69}}));
|
||||||
const C = new (wrapSpecification('C', {c: {type: 'int32'}}));
|
const C = new (wrapSpecification('C', {c: {type: 'int32'}}));
|
||||||
|
|
||||||
const Types = {A, B, C};
|
const Components = {A, B, C};
|
||||||
Types.A.createMany([[2], [3]]);
|
Components.A.createMany([[2], [3]]);
|
||||||
Types.B.createMany([[1], [2]]);
|
Components.B.createMany([[1], [2]]);
|
||||||
Types.C.createMany([[2], [4]]);
|
Components.C.createMany([[2], [4]]);
|
||||||
|
|
||||||
function testQuery(parameters, expected) {
|
function testQuery(parameters, expected) {
|
||||||
const query = new Query(parameters, Types);
|
const query = new Query(parameters, Components);
|
||||||
query.reindex([1, 2, 3]);
|
query.reindex([1, 2, 3]);
|
||||||
expect(query.count)
|
expect(query.count)
|
||||||
.to.equal(expected.length);
|
.to.equal(expected.length);
|
||||||
|
@ -51,7 +51,7 @@ test('can query excluding', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can deindex', () => {
|
test('can deindex', () => {
|
||||||
const query = new Query(['A'], Types);
|
const query = new Query(['A'], Components);
|
||||||
query.reindex([1, 2, 3]);
|
query.reindex([1, 2, 3]);
|
||||||
expect(query.count)
|
expect(query.count)
|
||||||
.to.equal(2);
|
.to.equal(2);
|
||||||
|
@ -74,7 +74,7 @@ test('can reindex', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can select', () => {
|
test('can select', () => {
|
||||||
const query = new Query(['A'], Types);
|
const query = new Query(['A'], Components);
|
||||||
query.reindex([1, 2, 3]);
|
query.reindex([1, 2, 3]);
|
||||||
const it = query.select();
|
const it = query.select();
|
||||||
const result = it.next();
|
const result = it.next();
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default class System {
|
||||||
this.ecs = ecs;
|
this.ecs = ecs;
|
||||||
const queries = this.constructor.queries();
|
const queries = this.constructor.queries();
|
||||||
for (const i in queries) {
|
for (const i in queries) {
|
||||||
this.queries[i] = new Query(queries[i], ecs.Types);
|
this.queries[i] = new Query(queries[i], ecs.Components);
|
||||||
}
|
}
|
||||||
this.reindex(ecs.entities);
|
this.reindex(ecs.entities);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import {
|
||||||
TPS,
|
TPS,
|
||||||
} from '@/constants.js';
|
} from '@/constants.js';
|
||||||
import Ecs from '@/ecs/ecs.js';
|
import Ecs from '@/ecs/ecs.js';
|
||||||
|
import Components from '@/ecs-components/index.js';
|
||||||
import Systems from '@/ecs-systems/index.js';
|
import Systems from '@/ecs-systems/index.js';
|
||||||
import Types from '@/ecs-components/index.js';
|
|
||||||
import {decode, encode} from '@/packets/index.js';
|
import {decode, encode} from '@/packets/index.js';
|
||||||
|
|
||||||
export default class Engine {
|
export default class Engine {
|
||||||
|
@ -60,7 +60,7 @@ export default class Engine {
|
||||||
}
|
}
|
||||||
|
|
||||||
createEcs() {
|
createEcs() {
|
||||||
return new Ecs({Systems, Types});
|
return new Ecs({Components, Systems});
|
||||||
}
|
}
|
||||||
|
|
||||||
async createHomestead(id) {
|
async createHomestead(id) {
|
||||||
|
|
|
@ -3,15 +3,15 @@ import {useState} from 'react';
|
||||||
|
|
||||||
import {RESOLUTION} from '@/constants.js';
|
import {RESOLUTION} from '@/constants.js';
|
||||||
import Ecs from '@/ecs/ecs.js';
|
import Ecs from '@/ecs/ecs.js';
|
||||||
|
import Components from '@/ecs-components/index.js';
|
||||||
import Systems from '@/ecs-systems/index.js';
|
import Systems from '@/ecs-systems/index.js';
|
||||||
import Types from '@/ecs-components/index.js';
|
|
||||||
import usePacket from '@/hooks/use-packet.js';
|
import usePacket from '@/hooks/use-packet.js';
|
||||||
|
|
||||||
import Entities from './entities.jsx';
|
import Entities from './entities.jsx';
|
||||||
import TileLayer from './tile-layer.jsx';
|
import TileLayer from './tile-layer.jsx';
|
||||||
|
|
||||||
export default function EcsComponent() {
|
export default function EcsComponent() {
|
||||||
const [ecs] = useState(new Ecs({Systems, Types}));
|
const [ecs] = useState(new Ecs({Components, Systems}));
|
||||||
const [entities, setEntities] = useState({});
|
const [entities, setEntities] = useState({});
|
||||||
const [mainEntity, setMainEntity] = useState();
|
const [mainEntity, setMainEntity] = useState();
|
||||||
usePacket('Tick', (payload) => {
|
usePacket('Tick', (payload) => {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user