feat: async creation
This commit is contained in:
parent
76f18e09c7
commit
74ec36dfa8
|
@ -28,22 +28,20 @@ export default class Component {
|
|||
return results;
|
||||
}
|
||||
|
||||
create(entityId, values) {
|
||||
async create(entityId, values) {
|
||||
this.createMany([[entityId, values]]);
|
||||
}
|
||||
|
||||
createMany(entries) {
|
||||
async createMany(entries) {
|
||||
if (entries.length > 0) {
|
||||
const allocated = this.allocateMany(entries.length);
|
||||
const {properties} = this.constructor.schema.specification;
|
||||
const keys = Object.keys(properties);
|
||||
const promises = [];
|
||||
for (let i = 0; i < entries.length; ++i) {
|
||||
const [entityId, values = {}] = entries[i];
|
||||
this.map[entityId] = allocated[i];
|
||||
this.data[allocated[i]].entity = entityId;
|
||||
if (false === values) {
|
||||
continue;
|
||||
}
|
||||
for (let k = 0; k < keys.length; ++k) {
|
||||
const j = keys[k];
|
||||
const {defaultValue} = properties[j];
|
||||
|
@ -54,7 +52,9 @@ export default class Component {
|
|||
this.data[allocated[i]][j] = defaultValue;
|
||||
}
|
||||
}
|
||||
promises.push(this.load(this.data[allocated[i]]));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ export default class Component {
|
|||
return this.data[this.map[entityId]];
|
||||
}
|
||||
|
||||
insertMany(entities) {
|
||||
async insertMany(entities) {
|
||||
const creating = [];
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
const [entityId, values] = entities[i];
|
||||
|
@ -122,7 +122,7 @@ export default class Component {
|
|||
}
|
||||
}
|
||||
}
|
||||
this.createMany(creating);
|
||||
await this.createMany(creating);
|
||||
}
|
||||
|
||||
instanceFromSchema() {
|
||||
|
@ -170,6 +170,10 @@ export default class Component {
|
|||
return Instance;
|
||||
}
|
||||
|
||||
async load(instance) {
|
||||
return instance;
|
||||
}
|
||||
|
||||
markChange(entityId, key, value) {
|
||||
this.ecs.markChange(entityId, {[this.constructor.componentName]: {[key]: value}})
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ export default class Ecs {
|
|||
}
|
||||
}
|
||||
|
||||
apply(patch) {
|
||||
async apply(patch) {
|
||||
const creating = [];
|
||||
const destroying = [];
|
||||
const removing = [];
|
||||
|
@ -63,7 +63,7 @@ export default class Ecs {
|
|||
this.destroyMany(destroying);
|
||||
this.insertMany(updating);
|
||||
this.removeMany(removing);
|
||||
this.createManySpecific(creating);
|
||||
await this.createManySpecific(creating);
|
||||
}
|
||||
|
||||
changed(criteria) {
|
||||
|
@ -91,12 +91,12 @@ export default class Ecs {
|
|||
};
|
||||
}
|
||||
|
||||
create(components = {}) {
|
||||
const [entityId] = this.createMany([components]);
|
||||
async create(components = {}) {
|
||||
const [entityId] = await this.createMany([components]);
|
||||
return entityId;
|
||||
}
|
||||
|
||||
createMany(componentsList) {
|
||||
async createMany(componentsList) {
|
||||
const specificsList = [];
|
||||
for (const components of componentsList) {
|
||||
specificsList.push([this.$$caret++, components]);
|
||||
|
@ -104,7 +104,7 @@ export default class Ecs {
|
|||
return this.createManySpecific(specificsList);
|
||||
}
|
||||
|
||||
createManySpecific(specificsList) {
|
||||
async createManySpecific(specificsList) {
|
||||
const entityIds = [];
|
||||
const creating = {};
|
||||
for (let i = 0; i < specificsList.length; i++) {
|
||||
|
@ -125,14 +125,16 @@ export default class Ecs {
|
|||
}
|
||||
this.markChange(entityId, components);
|
||||
}
|
||||
const promises = [];
|
||||
for (const i in creating) {
|
||||
this.Components[i].createMany(creating[i]);
|
||||
promises.push(this.Components[i].createMany(creating[i]));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
this.reindex(entityIds);
|
||||
return entityIds;
|
||||
}
|
||||
|
||||
createSpecific(entityId, components) {
|
||||
async createSpecific(entityId, components) {
|
||||
return this.createManySpecific([[entityId, components]]);
|
||||
}
|
||||
|
||||
|
@ -142,7 +144,7 @@ export default class Ecs {
|
|||
}
|
||||
}
|
||||
|
||||
static deserialize(ecs, view) {
|
||||
static async deserialize(ecs, view) {
|
||||
const componentNames = Object.keys(ecs.Components);
|
||||
const {entities, systems} = decoder.decode(view.buffer);
|
||||
for (const system of systems) {
|
||||
|
@ -164,7 +166,7 @@ export default class Ecs {
|
|||
]);
|
||||
}
|
||||
ecs.$$caret = max + 1;
|
||||
ecs.createManySpecific(specifics);
|
||||
await ecs.createManySpecific(specifics);
|
||||
return ecs;
|
||||
}
|
||||
|
||||
|
@ -220,11 +222,11 @@ export default class Ecs {
|
|||
return this.$$entities[entityId];
|
||||
}
|
||||
|
||||
insert(entityId, components) {
|
||||
this.insertMany([[entityId, components]]);
|
||||
async insert(entityId, components) {
|
||||
return this.insertMany([[entityId, components]]);
|
||||
}
|
||||
|
||||
insertMany(entities) {
|
||||
async insertMany(entities) {
|
||||
const inserting = {};
|
||||
const unique = new Set();
|
||||
for (const [entityId, components] of entities) {
|
||||
|
@ -240,9 +242,11 @@ export default class Ecs {
|
|||
unique.add(entityId);
|
||||
this.markChange(entityId, diff);
|
||||
}
|
||||
const promises = [];
|
||||
for (const componentName in inserting) {
|
||||
this.Components[componentName].insertMany(inserting[componentName]);
|
||||
promises.push(this.Components[componentName].insertMany(inserting[componentName]));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
this.reindex(unique.values());
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,24 @@ const Position = wrapProperties('Position', {
|
|||
z: {type: 'int32'},
|
||||
});
|
||||
|
||||
function asyncTimesTwo(x) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(x * 2)
|
||||
}, 5);
|
||||
});
|
||||
}
|
||||
|
||||
class Async extends Component {
|
||||
static componentName = 'Async';
|
||||
static properties = {
|
||||
foo: {type: 'uint8'},
|
||||
};
|
||||
async load(instance) {
|
||||
instance.foo = await asyncTimesTwo(instance.foo);
|
||||
}
|
||||
}
|
||||
|
||||
test('activates and deactivates systems at runtime', () => {
|
||||
let oneCount = 0;
|
||||
let twoCount = 0;
|
||||
|
@ -63,31 +81,31 @@ test('activates and deactivates systems at runtime', () => {
|
|||
.to.equal(2);
|
||||
});
|
||||
|
||||
test('creates entities with components', () => {
|
||||
test('creates entities with components', async () => {
|
||||
const ecs = new Ecs({Components: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||
const entity = await 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", () => {
|
||||
test("removes entities' components", async () => {
|
||||
const ecs = new Ecs({Components: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||
const entity = await ecs.create({Empty: {}, Position: {y: 128}});
|
||||
ecs.remove(entity, ['Position']);
|
||||
expect(JSON.stringify(ecs.get(entity)))
|
||||
.to.deep.equal(JSON.stringify({Empty: {}}));
|
||||
});
|
||||
|
||||
test('gets entities', () => {
|
||||
test('gets entities', async () => {
|
||||
const ecs = new Ecs({Components: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||
const entity = await ecs.create({Empty: {}, Position: {y: 128}});
|
||||
expect(JSON.stringify(ecs.get(entity)))
|
||||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
||||
});
|
||||
|
||||
test('destroys entities', () => {
|
||||
test('destroys entities', async () => {
|
||||
const ecs = new Ecs({Components: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}, Position: {y: 128}});
|
||||
const entity = await ecs.create({Empty: {}, Position: {y: 128}});
|
||||
expect(JSON.stringify(ecs.get(entity)))
|
||||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
||||
expect(ecs.get(entity))
|
||||
|
@ -101,9 +119,9 @@ test('destroys entities', () => {
|
|||
.to.throw();
|
||||
});
|
||||
|
||||
test('inserts components into entities', () => {
|
||||
test('inserts components into entities', async () => {
|
||||
const ecs = new Ecs({Components: {Empty, Position}});
|
||||
const entity = ecs.create({Empty: {}});
|
||||
const entity = await ecs.create({Empty: {}});
|
||||
ecs.insert(entity, {Position: {y: 128}});
|
||||
expect(JSON.stringify(ecs.get(entity)))
|
||||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 128}}));
|
||||
|
@ -112,7 +130,7 @@ test('inserts components into entities', () => {
|
|||
.to.deep.equal(JSON.stringify({Empty: {}, Position: {y: 64}}));
|
||||
});
|
||||
|
||||
test('ticks systems', () => {
|
||||
test('ticks systems', async () => {
|
||||
const Momentum = wrapProperties('Momentum', {
|
||||
x: {type: 'int32'},
|
||||
y: {type: 'int32'},
|
||||
|
@ -141,7 +159,7 @@ test('ticks systems', () => {
|
|||
},
|
||||
});
|
||||
ecs.system('Physics').active = true;
|
||||
const entity = ecs.create({Momentum: {}, Position: {y: 128}});
|
||||
const entity = await ecs.create({Momentum: {}, Position: {y: 128}});
|
||||
const position = JSON.stringify(ecs.get(entity).Position);
|
||||
ecs.tick(1);
|
||||
expect(JSON.stringify(ecs.get(entity).Position))
|
||||
|
@ -262,10 +280,10 @@ test('adds components to and remove components from entities when ticking system
|
|||
.to.be.undefined;
|
||||
});
|
||||
|
||||
test('generates coalesced diffs for entity creation', () => {
|
||||
test('generates coalesced diffs for entity creation', async () => {
|
||||
const ecs = new Ecs();
|
||||
let entity;
|
||||
entity = ecs.create();
|
||||
entity = await ecs.create();
|
||||
expect(ecs.diff)
|
||||
.to.deep.equal({[entity]: {}});
|
||||
});
|
||||
|
@ -286,10 +304,10 @@ test('generates diffs for adding and removing components', () => {
|
|||
.to.deep.equal({[entity]: {Position: false}});
|
||||
});
|
||||
|
||||
test('generates diffs for empty components', () => {
|
||||
test('generates diffs for empty components', async () => {
|
||||
const ecs = new Ecs({Components: {Empty}});
|
||||
let entity;
|
||||
entity = ecs.create({Empty: {}});
|
||||
entity = await ecs.create({Empty: {}});
|
||||
expect(ecs.diff)
|
||||
.to.deep.equal({[entity]: {Empty: {}}});
|
||||
ecs.setClean();
|
||||
|
@ -298,10 +316,10 @@ test('generates diffs for empty components', () => {
|
|||
.to.deep.equal({[entity]: {Empty: false}});
|
||||
});
|
||||
|
||||
test('generates diffs for entity mutations', () => {
|
||||
test('generates diffs for entity mutations', async () => {
|
||||
const ecs = new Ecs({Components: {Position}});
|
||||
let entity;
|
||||
entity = ecs.create({Position: {}});
|
||||
entity = await ecs.create({Position: {}});
|
||||
ecs.setClean();
|
||||
ecs.get(entity).Position.x = 128;
|
||||
expect(ecs.diff)
|
||||
|
@ -311,10 +329,10 @@ test('generates diffs for entity mutations', () => {
|
|||
.to.deep.equal({});
|
||||
});
|
||||
|
||||
test('generates coalesced diffs for components', () => {
|
||||
test('generates coalesced diffs for components', async () => {
|
||||
const ecs = new Ecs({Components: {Position}});
|
||||
let entity;
|
||||
entity = ecs.create({Position});
|
||||
entity = await ecs.create({Position});
|
||||
ecs.remove(entity, ['Position']);
|
||||
expect(ecs.diff)
|
||||
.to.deep.equal({[entity]: {Position: false}});
|
||||
|
@ -323,10 +341,10 @@ test('generates coalesced diffs for components', () => {
|
|||
.to.deep.equal({[entity]: {Position: {}}});
|
||||
});
|
||||
|
||||
test('generates coalesced diffs for mutations', () => {
|
||||
test('generates coalesced diffs for mutations', async () => {
|
||||
const ecs = new Ecs({Components: {Position}});
|
||||
let entity;
|
||||
entity = ecs.create({Position});
|
||||
entity = await ecs.create({Position});
|
||||
ecs.setClean();
|
||||
ecs.get(entity).Position.x = 128;
|
||||
ecs.get(entity).Position.x = 256;
|
||||
|
@ -335,10 +353,10 @@ test('generates coalesced diffs for mutations', () => {
|
|||
.to.deep.equal({[entity]: {Position: {x: 512}}});
|
||||
});
|
||||
|
||||
test('generates diffs for deletions', () => {
|
||||
test('generates diffs for deletions', async () => {
|
||||
const ecs = new Ecs();
|
||||
let entity;
|
||||
entity = ecs.create();
|
||||
entity = await ecs.create();
|
||||
ecs.setClean();
|
||||
ecs.destroy(entity);
|
||||
expect(ecs.diff)
|
||||
|
@ -438,3 +456,30 @@ test('deserializes from compatible ECS', () => {
|
|||
expect(deserialized.get(16).toJSON())
|
||||
.to.deep.equal({Name: {name: 'foobar'}});
|
||||
});
|
||||
|
||||
test('creates entities asynchronously', async () => {
|
||||
const ecs = new Ecs({Components: {Async}});
|
||||
const entity = await ecs.create({Async: {foo: 64}});
|
||||
expect(ecs.get(entity).toJSON())
|
||||
.to.deep.equal({Async: {foo: 128}});
|
||||
});
|
||||
|
||||
test('inserts components asynchronously', async () => {
|
||||
const ecs = new Ecs({Components: {Async}});
|
||||
const entity = await ecs.create();
|
||||
await ecs.insert(entity, {Async: {foo: 64}});
|
||||
expect(ecs.get(entity).toJSON())
|
||||
.to.deep.equal({Async: {foo: 128}});
|
||||
});
|
||||
|
||||
test('deserializes asynchronously', async () => {
|
||||
const ecs = new Ecs({Components: {Async}});
|
||||
await ecs.createSpecific(16, {Async: {foo: 16}});
|
||||
const view = Ecs.serialize(ecs);
|
||||
const deserialized = await Ecs.deserialize(
|
||||
new Ecs({Components: {Async}}),
|
||||
view,
|
||||
);
|
||||
expect(deserialized.get(16).toJSON())
|
||||
.to.deep.equal({Async: {foo: 64}});
|
||||
});
|
||||
|
|
|
@ -99,7 +99,7 @@ export default class Engine {
|
|||
await this.loadEcs(entityJson.Ecs.path);
|
||||
}
|
||||
const ecs = this.ecses[entityJson.Ecs.path];
|
||||
const entity = ecs.create(entityJson);
|
||||
const entity = await ecs.create(entityJson);
|
||||
this.connections.push(connection);
|
||||
this.connectedPlayers.set(
|
||||
connection,
|
||||
|
@ -118,7 +118,7 @@ export default class Engine {
|
|||
async createHomestead(id) {
|
||||
const ecs = this.createEcs();
|
||||
const area = {x: 100, y: 60};
|
||||
ecs.create({
|
||||
await ecs.create({
|
||||
AreaSize: {x: area.x * 16, y: area.y * 16},
|
||||
Engine: {},
|
||||
TileLayers: {
|
||||
|
|
|
@ -29,7 +29,7 @@ test('visibility-based updates', async () => {
|
|||
await engine.connectPlayer(0, 0);
|
||||
const ecs = engine.ecses['homesteads/0'];
|
||||
// Create an entity.
|
||||
const entity = ecs.get(ecs.create({
|
||||
const entity = ecs.get(await ecs.create({
|
||||
Forces: {forceX: 1},
|
||||
Position: {x: (RESOLUTION.x * 1.5) + 32 - 3, y: 20},
|
||||
VisibleAabb: {},
|
||||
|
|
Loading…
Reference in New Issue
Block a user