refactor: ecs
This commit is contained in:
parent
c53d716a37
commit
95a8e5f13e
|
@ -12,20 +12,15 @@ export default class Ecs {
|
|||
|
||||
diff = {};
|
||||
|
||||
static Systems = {};
|
||||
|
||||
Systems = {};
|
||||
|
||||
static Types = {};
|
||||
|
||||
Types = {};
|
||||
|
||||
$$entities = {};
|
||||
|
||||
$$entityFactory = new EntityFactory();
|
||||
|
||||
constructor() {
|
||||
const {Systems, Types} = this.constructor;
|
||||
constructor({Systems, Types} = {}) {
|
||||
for (const name in Types) {
|
||||
this.Types[name] = new Types[name](this);
|
||||
}
|
||||
|
@ -122,8 +117,7 @@ export default class Ecs {
|
|||
}
|
||||
}
|
||||
|
||||
static deserialize(view) {
|
||||
const ecs = new this();
|
||||
static deserialize(ecs, view) {
|
||||
const types = Object.keys(ecs.Types);
|
||||
const {entities, systems} = decoder.decode(view.buffer);
|
||||
for (const system of systems) {
|
||||
|
|
|
@ -30,8 +30,8 @@ const Position = wrapSpecification('Position', {
|
|||
test('activates and deactivates systems at runtime', () => {
|
||||
let oneCount = 0;
|
||||
let twoCount = 0;
|
||||
class SystemToggle extends Ecs {
|
||||
static Systems = {
|
||||
const ecs = new Ecs({
|
||||
Systems: {
|
||||
OneSystem: class extends System {
|
||||
tick() {
|
||||
oneCount += 1;
|
||||
|
@ -42,9 +42,8 @@ test('activates and deactivates systems at runtime', () => {
|
|||
twoCount += 1;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
const ecs = new SystemToggle();
|
||||
},
|
||||
});
|
||||
ecs.tick();
|
||||
expect(oneCount)
|
||||
.to.equal(0);
|
||||
|
@ -69,20 +68,14 @@ test('activates and deactivates systems at runtime', () => {
|
|||
});
|
||||
|
||||
test('creates entities with components', () => {
|
||||
class CreateEcs extends Ecs {
|
||||
static Types = {Empty, Position};
|
||||
}
|
||||
const ecs = new CreateEcs();
|
||||
const ecs = new Ecs({Types: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||
expect(JSON.stringify(ecs.get(entity)))
|
||||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
||||
});
|
||||
|
||||
test("removes entities' components", () => {
|
||||
class RemoveEcs extends Ecs {
|
||||
static Types = {Empty, Position};
|
||||
}
|
||||
const ecs = new RemoveEcs();
|
||||
const ecs = new Ecs({Types: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||
ecs.remove(entity, ['Position']);
|
||||
expect(JSON.stringify(ecs.get(entity)))
|
||||
|
@ -90,20 +83,14 @@ test("removes entities' components", () => {
|
|||
});
|
||||
|
||||
test('gets entities', () => {
|
||||
class GetEcs extends Ecs {
|
||||
static Types = {Empty, Position};
|
||||
}
|
||||
const ecs = new GetEcs();
|
||||
const ecs = new Ecs({Types: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||
expect(JSON.stringify(ecs.get(entity)))
|
||||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
||||
});
|
||||
|
||||
test('destroys entities', () => {
|
||||
class DestroyEcs extends Ecs {
|
||||
static Types = {Empty, Position};
|
||||
}
|
||||
const ecs = new DestroyEcs();
|
||||
const ecs = new Ecs({Types: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||
expect(JSON.stringify(ecs.get(entity)))
|
||||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
||||
|
@ -119,10 +106,7 @@ test('destroys entities', () => {
|
|||
});
|
||||
|
||||
test('inserts components into entities', () => {
|
||||
class InsertEcs extends Ecs {
|
||||
static Types = {Empty, Position};
|
||||
}
|
||||
const ecs = new InsertEcs();
|
||||
const ecs = new Ecs({Types: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}});
|
||||
ecs.insert(entity, {Position: {y: 128}});
|
||||
expect(JSON.stringify(ecs.get(entity)))
|
||||
|
@ -138,8 +122,8 @@ test('ticks systems', () => {
|
|||
y: {type: 'int32'},
|
||||
z: {type: 'int32'},
|
||||
});
|
||||
class TickEcs extends Ecs {
|
||||
static Systems = {
|
||||
const ecs = new Ecs({
|
||||
Systems: {
|
||||
Physics: class Physics extends System {
|
||||
|
||||
static queries() {
|
||||
|
@ -157,10 +141,9 @@ test('ticks systems', () => {
|
|||
}
|
||||
|
||||
},
|
||||
}
|
||||
static Types = {Momentum, Position};
|
||||
}
|
||||
const ecs = new TickEcs();
|
||||
},
|
||||
Types: {Momentum, Position},
|
||||
});
|
||||
ecs.system('Physics').active = true;
|
||||
const entity = ecs.create({Momentum: {}, Position: {y: 128}});
|
||||
const position = JSON.stringify(ecs.get(entity).Position);
|
||||
|
@ -174,16 +157,15 @@ test('ticks systems', () => {
|
|||
});
|
||||
|
||||
test('creates many entities when ticking systems', () => {
|
||||
class TickingSystemEcs extends Ecs {
|
||||
static Systems = {
|
||||
const ecs = new Ecs({
|
||||
Systems: {
|
||||
Spawn: class extends System {
|
||||
tick() {
|
||||
this.createManyEntities(Array.from({length: 5}).map(() => []));
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
const ecs = new TickingSystemEcs();
|
||||
},
|
||||
});
|
||||
ecs.system('Spawn').active = true;
|
||||
ecs.create();
|
||||
expect(ecs.get(5))
|
||||
|
@ -194,16 +176,15 @@ test('creates many entities when ticking systems', () => {
|
|||
});
|
||||
|
||||
test('creates entities when ticking systems', () => {
|
||||
class TickingSystemEcs extends Ecs {
|
||||
static Systems = {
|
||||
const ecs = new Ecs({
|
||||
Systems: {
|
||||
Spawn: class extends System {
|
||||
tick() {
|
||||
this.createEntity();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
const ecs = new TickingSystemEcs();
|
||||
},
|
||||
});
|
||||
ecs.system('Spawn').active = true;
|
||||
ecs.create();
|
||||
expect(ecs.get(2))
|
||||
|
@ -215,8 +196,8 @@ test('creates entities when ticking systems', () => {
|
|||
|
||||
test('schedules entities to be deleted when ticking systems', () => {
|
||||
let entity;
|
||||
class TickingSystemEcs extends Ecs {
|
||||
static Systems = {
|
||||
const ecs = new Ecs({
|
||||
Systems: {
|
||||
Despawn: class extends System {
|
||||
finalize() {
|
||||
entity = ecs.get(1);
|
||||
|
@ -225,9 +206,8 @@ test('schedules entities to be deleted when ticking systems', () => {
|
|||
this.destroyEntity(1);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
const ecs = new TickingSystemEcs();
|
||||
},
|
||||
});
|
||||
ecs.system('Despawn').active = true;
|
||||
ecs.create();
|
||||
ecs.tick(1);
|
||||
|
@ -239,8 +219,8 @@ test('schedules entities to be deleted when ticking systems', () => {
|
|||
|
||||
test('adds components to and remove components from entities when ticking systems', () => {
|
||||
let addLength, removeLength;
|
||||
class TickingSystemEcs extends Ecs {
|
||||
static Systems = {
|
||||
const ecs = new Ecs({
|
||||
Systems: {
|
||||
AddComponent: class extends System {
|
||||
static queries() {
|
||||
return {
|
||||
|
@ -267,10 +247,9 @@ test('adds components to and remove components from entities when ticking system
|
|||
removeLength = Array.from(this.select('default')).length;
|
||||
}
|
||||
},
|
||||
};
|
||||
static Types = {Foo: wrapSpecification('Foo', {bar: {type: 'uint8'}})};
|
||||
}
|
||||
const ecs = new TickingSystemEcs();
|
||||
},
|
||||
Types: {Foo: wrapSpecification('Foo', {bar: {type: 'uint8'}})},
|
||||
});
|
||||
ecs.system('AddComponent').active = true;
|
||||
ecs.create();
|
||||
ecs.tick(1);
|
||||
|
@ -296,10 +275,7 @@ test('generates coalesced diffs for entity creation', () => {
|
|||
});
|
||||
|
||||
test('generates diffs for adding and removing components', () => {
|
||||
class DiffedEcs extends Ecs {
|
||||
static Types = {Position};
|
||||
}
|
||||
const ecs = new DiffedEcs();
|
||||
const ecs = new Ecs({Types: {Position}});
|
||||
let entity;
|
||||
entity = ecs.create();
|
||||
ecs.setClean();
|
||||
|
@ -315,10 +291,7 @@ test('generates diffs for adding and removing components', () => {
|
|||
});
|
||||
|
||||
test('generates diffs for empty components', () => {
|
||||
class DiffedEcs extends Ecs {
|
||||
static Types = {Empty};
|
||||
}
|
||||
const ecs = new DiffedEcs();
|
||||
const ecs = new Ecs({Types: {Empty}});
|
||||
let entity;
|
||||
entity = ecs.create({Empty});
|
||||
expect(ecs.diff)
|
||||
|
@ -330,10 +303,7 @@ test('generates diffs for empty components', () => {
|
|||
});
|
||||
|
||||
test('generates diffs for entity mutations', () => {
|
||||
class DiffedEcs extends Ecs {
|
||||
static Types = {Position};
|
||||
}
|
||||
const ecs = new DiffedEcs();
|
||||
const ecs = new Ecs({Types: {Position}});
|
||||
let entity;
|
||||
entity = ecs.create({Position: {}});
|
||||
ecs.setClean();
|
||||
|
@ -346,10 +316,7 @@ test('generates diffs for entity mutations', () => {
|
|||
});
|
||||
|
||||
test('generates coalesced diffs for components', () => {
|
||||
class DiffedEcs extends Ecs {
|
||||
static Types = {Position};
|
||||
}
|
||||
const ecs = new DiffedEcs();
|
||||
const ecs = new Ecs({Types: {Position}});
|
||||
let entity;
|
||||
entity = ecs.create({Position});
|
||||
ecs.remove(entity, ['Position']);
|
||||
|
@ -361,10 +328,7 @@ test('generates coalesced diffs for components', () => {
|
|||
});
|
||||
|
||||
test('generates coalesced diffs for mutations', () => {
|
||||
class DiffedEcs extends Ecs {
|
||||
static Types = {Position};
|
||||
}
|
||||
const ecs = new DiffedEcs();
|
||||
const ecs = new Ecs({Types: {Position}});
|
||||
let entity;
|
||||
entity = ecs.create({Position});
|
||||
ecs.setClean();
|
||||
|
@ -386,10 +350,7 @@ test('generates diffs for deletions', () => {
|
|||
});
|
||||
|
||||
test('applies creation patches', () => {
|
||||
class PatchedEcs extends Ecs {
|
||||
static Types = {Position};
|
||||
}
|
||||
const ecs = new PatchedEcs();
|
||||
const ecs = new Ecs({Types: {Position}});
|
||||
ecs.apply({16: {Position: {x: 64}}});
|
||||
expect(Array.from(ecs.entities).length)
|
||||
.to.equal(1);
|
||||
|
@ -398,10 +359,7 @@ test('applies creation patches', () => {
|
|||
});
|
||||
|
||||
test('applies update patches', () => {
|
||||
class PatchedEcs extends Ecs {
|
||||
static Types = {Position};
|
||||
}
|
||||
const ecs = new PatchedEcs();
|
||||
const ecs = new Ecs({Types: {Position}});
|
||||
ecs.createSpecific(16, {Position: {x: 64}});
|
||||
ecs.apply({16: {Position: {x: 128}}});
|
||||
expect(Array.from(ecs.entities).length)
|
||||
|
@ -411,10 +369,7 @@ test('applies update patches', () => {
|
|||
});
|
||||
|
||||
test('applies entity deletion patches', () => {
|
||||
class PatchedEcs extends Ecs {
|
||||
static Types = {Position};
|
||||
}
|
||||
const ecs = new PatchedEcs();
|
||||
const ecs = new Ecs({Types: {Position}});
|
||||
ecs.createSpecific(16, {Position: {x: 64}});
|
||||
ecs.apply({16: false});
|
||||
expect(Array.from(ecs.entities).length)
|
||||
|
@ -422,10 +377,7 @@ test('applies entity deletion patches', () => {
|
|||
});
|
||||
|
||||
test('applies component deletion patches', () => {
|
||||
class PatchedEcs extends Ecs {
|
||||
static Types = {Empty, Position};
|
||||
}
|
||||
const ecs = new PatchedEcs();
|
||||
const ecs = new Ecs({Types: {Empty, Position}});
|
||||
ecs.createSpecific(16, {Empty: {}, Position: {x: 64}});
|
||||
expect(ecs.get(16).constructor.types)
|
||||
.to.deep.equal(['Empty', 'Position']);
|
||||
|
@ -435,10 +387,7 @@ test('applies component deletion patches', () => {
|
|||
});
|
||||
|
||||
test('calculates entity size', () => {
|
||||
class SizingEcs extends Ecs {
|
||||
static Types = {Empty, Position};
|
||||
}
|
||||
const ecs = new SizingEcs();
|
||||
const ecs = new Ecs({Types: {Empty, Position}});
|
||||
ecs.createSpecific(1, {Empty: {}, Position: {}});
|
||||
// ID + # of components + Empty + Position + x + y + z
|
||||
// 4 + 2 + 2 + 4 + 2 + 4 + 4 + 4 + 4 = 30
|
||||
|
@ -447,10 +396,7 @@ test('calculates entity size', () => {
|
|||
});
|
||||
|
||||
test('serializes and deserializes', () => {
|
||||
class SerializingEcs extends Ecs {
|
||||
static Types = {Empty, Name, Position};
|
||||
}
|
||||
const ecs = new SerializingEcs();
|
||||
const ecs = new Ecs({Types: {Empty, Name, Position}});
|
||||
ecs.createSpecific(1, {Empty: {}, Position: {x: 64}});
|
||||
ecs.createSpecific(16, {Name: {name: 'foobar'}, Position: {x: 128}});
|
||||
expect(ecs.toJSON())
|
||||
|
@ -461,8 +407,11 @@ test('serializes and deserializes', () => {
|
|||
},
|
||||
systems: [],
|
||||
});
|
||||
const view = SerializingEcs.serialize(ecs);
|
||||
const deserialized = SerializingEcs.deserialize(view);
|
||||
const view = Ecs.serialize(ecs);
|
||||
const deserialized = Ecs.deserialize(
|
||||
new Ecs({Types: {Empty, Name, Position}}),
|
||||
view,
|
||||
);
|
||||
expect(Array.from(deserialized.entities).length)
|
||||
.to.equal(2);
|
||||
expect(deserialized.get(1).constructor.types)
|
||||
|
@ -480,17 +429,14 @@ test('serializes and deserializes', () => {
|
|||
});
|
||||
|
||||
test('deserializes from compatible ECS', () => {
|
||||
class DeserializingEcs extends Ecs {
|
||||
static Types = {Empty, Name};
|
||||
}
|
||||
class SerializingEcs extends Ecs {
|
||||
static Types = {Empty, Name, Position};
|
||||
}
|
||||
const ecs = new SerializingEcs();
|
||||
const ecs = new Ecs({Types: {Empty, Name, Position}});
|
||||
ecs.createSpecific(1, {Empty: {}, Position: {x: 64}});
|
||||
ecs.createSpecific(16, {Name: {name: 'foobar'}, Position: {x: 128}});
|
||||
const view = SerializingEcs.serialize(ecs);
|
||||
const deserialized = DeserializingEcs.deserialize(view);
|
||||
const view = Ecs.serialize(ecs);
|
||||
const deserialized = Ecs.deserialize(
|
||||
new Ecs({Types: {Empty, Name}}),
|
||||
view,
|
||||
);
|
||||
expect(deserialized.get(1).toJSON())
|
||||
.to.deep.equal({Empty: {}});
|
||||
expect(deserialized.get(16).toJSON())
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import Ecs from '@/ecs/ecs.js';
|
||||
import Systems from '@/ecs-systems/index.js';
|
||||
import Types from '@/ecs-components/index.js';
|
||||
|
||||
class EngineEcs extends Ecs {
|
||||
static Systems = Systems;
|
||||
static Types = Types;
|
||||
}
|
||||
|
||||
export default EngineEcs;
|
|
@ -4,7 +4,9 @@ import {
|
|||
MOVE_MAP,
|
||||
TPS,
|
||||
} from '@/constants.js';
|
||||
import Ecs from '@/engine/ecs.js';
|
||||
import Ecs from '@/ecs/ecs.js';
|
||||
import Systems from '@/ecs-systems/index.js';
|
||||
import Types from '@/ecs-components/index.js';
|
||||
import {decode, encode} from '@/packets/index.js';
|
||||
|
||||
export default class Engine {
|
||||
|
@ -58,7 +60,11 @@ export default class Engine {
|
|||
}
|
||||
|
||||
createEcs() {
|
||||
const ecs = new Ecs();
|
||||
return new Ecs({Systems, Types});
|
||||
}
|
||||
|
||||
async createHomestead(id) {
|
||||
const ecs = this.createEcs();
|
||||
const area = {x: 100, y: 60};
|
||||
ecs.create({
|
||||
AreaSize: {x: area.x * 16, y: area.y * 16},
|
||||
|
@ -87,11 +93,6 @@ export default class Engine {
|
|||
defaultSystems.forEach((defaultSystem) => {
|
||||
ecs.system(defaultSystem).active = true;
|
||||
});
|
||||
return ecs;
|
||||
}
|
||||
|
||||
async createHomestead(id) {
|
||||
const ecs = this.createEcs();
|
||||
const view = Ecs.serialize(ecs);
|
||||
await this.server.writeData(
|
||||
join('homesteads', `${id}`),
|
||||
|
@ -137,7 +138,10 @@ export default class Engine {
|
|||
}
|
||||
|
||||
async loadEcs(path) {
|
||||
this.ecses[path] = Ecs.deserialize(await this.server.readData(path));
|
||||
this.ecses[path] = Ecs.deserialize(
|
||||
this.createEcs(),
|
||||
await this.server.readData(path),
|
||||
);
|
||||
}
|
||||
|
||||
async loadPlayer(id) {
|
||||
|
|
|
@ -2,14 +2,16 @@ import {Container} from '@pixi/react';
|
|||
import {useState} from 'react';
|
||||
|
||||
import {RESOLUTION} from '@/constants.js';
|
||||
import Ecs from '@/engine/ecs.js';
|
||||
import Ecs from '@/ecs/ecs.js';
|
||||
import Systems from '@/ecs-systems/index.js';
|
||||
import Types from '@/ecs-components/index.js';
|
||||
import usePacket from '@/hooks/use-packet.js';
|
||||
|
||||
import Entities from './entities.jsx';
|
||||
import TileLayer from './tile-layer.jsx';
|
||||
|
||||
export default function EcsComponent() {
|
||||
const [ecs] = useState(new Ecs());
|
||||
const [ecs] = useState(new Ecs({Systems, Types}));
|
||||
const [entities, setEntities] = useState({});
|
||||
const [mainEntity, setMainEntity] = useState();
|
||||
usePacket('Tick', (payload) => {
|
||||
|
|
Loading…
Reference in New Issue
Block a user