refactor: Synchronization

This commit is contained in:
cha0s 2021-03-14 03:07:13 -05:00
parent fb1f2909a4
commit bcd5b36e77
9 changed files with 99 additions and 47 deletions

View File

@ -82,6 +82,7 @@ export default (latus) => class Vulnerable extends Trait {
}
destroy() {
super.destroy();
this.#locks.clear();
}
@ -389,7 +390,7 @@ export default (latus) => class Vulnerable extends Trait {
};
}
packets() {
packetsFor() {
return this.#harms.length > 0
? [['Harm', this.#harms.map((harm) => ({
...harm,

View File

@ -15,7 +15,7 @@ export default () => {
return undefined;
}
const onDisconnect = () => {
synchronizer.deleteSynchronized(room.constructor.resourceId, room.s13nId());
synchronizer.destroySynchronized(room.constructor.resourceId, room.s13nId);
setRoom(undefined);
};
socket.on('disconnect', onDisconnect);
@ -27,9 +27,9 @@ export default () => {
if (!synchronizer) {
return undefined;
}
const onCreated = (type, created) => {
const onCreated = (created) => {
const {Room} = latus.get('%resources');
switch (type) {
switch (created.constructor.resourceId) {
// Track room.
case Room.resourceId: {
setRoom(created);

View File

@ -1,52 +1,68 @@
/* eslint-disable max-classes-per-file */
import {Rectangle, Vector} from '@avocado/math';
import {Resource} from '@avocado/resource';
import {Synchronized} from '@avocado/s13n';
import {Trait} from '@avocado/traits';
import {SenderSynchronizer} from '@avocado/s13n';
import {compose} from '@latus/core';
export default (latus) => class Informed extends Trait {
export default (latus) => {
const decorate = compose(
Synchronized(latus),
);
class Synchronizer extends decorate(Resource) {}
return class Informed extends Trait {
#synchronizer = new SenderSynchronizer(latus);
#synchronizer = new Synchronizer();
static dependencies() {
return [
'Followed',
];
}
static dependencies() {
return [
'Followed',
];
}
destroy() {
this.#synchronizer.destroy();
}
destroy() {
super.destroy();
this.#synchronizer.destroy();
}
get areaToInform() {
// Reduce entity list to visible.
const {camera} = this.entity;
// Blow up camera rectangle to compensate for camera desync.
const size = Rectangle.size(camera.rectangle);
return Rectangle.expand(
camera.rectangle,
Vector.scale(size, 0.5),
);
}
get areaToInform() {
// Reduce entity list to visible.
const {camera} = this.entity;
// Blow up camera rectangle to compensate for camera desync.
const size = Rectangle.size(camera.rectangle);
return Rectangle.expand(
camera.rectangle,
Vector.scale(size, 0.5),
);
}
methods() {
return {
methods() {
return {
inform: async (socket) => {
this.#synchronizer.send(socket, this.entity);
},
cleanInformingPackets: () => {
this.#synchronizer.cleanPackets();
},
addSynchronized: (synchronized) => {
this.#synchronizer.addSynchronized(synchronized);
},
inform: async (socket) => {
if (socket) {
const packets = this.#synchronizer.packetsFor(this.entity);
if (packets.length > 0) {
await socket.send(['Bundle', packets]);
}
}
},
queuePacket: (packet) => {
this.#synchronizer.queuePacket(packet);
},
startInforming: (synchronized) => {
this.#synchronizer.startSynchronizing(synchronized);
},
removeSynchronized: (synchronized) => {
this.#synchronizer.removeSynchronized(synchronized);
},
stopInforming: (synchronized) => {
this.#synchronizer.stopSynchronizing(synchronized);
},
};
}
};
}
};
};

View File

@ -111,7 +111,7 @@ export default (latus) => class Plant extends decorate(Trait) {
};
}
packets() {
packetsFor() {
const {growthStage} = this.stateDifferences();
return growthStage
? [[

View File

@ -147,6 +147,7 @@ export default (latus) => class Receptacle extends decorate(Trait) {
}
destroy() {
super.destroy();
for (let i = 0; i < this.entity.slotCount; ++i) {
const item = this.entity.removeItemFromSlot(i);
if (item) {
@ -292,7 +293,7 @@ export default (latus) => class Receptacle extends decorate(Trait) {
};
}
packets(informed) {
packetsFor(informed) {
return informed === this.entity ? this.packetUpdates : [];
}

View File

@ -1,11 +1,13 @@
import {ReceiverSynchronizer} from '@avocado/s13n';
import {gatherWithLatus} from '@latus/core';
import Receiver from './receiver';
export default {
hooks: {
'@latus/http/client/up': (latus) => {
window.latus = latus;
const synchronizer = new ReceiverSynchronizer(latus);
const Synchronizer = Receiver(latus);
const synchronizer = new Synchronizer();
latus.set('%synchronizer', synchronizer);
latus.get('%socket').on('packet', synchronizer.acceptPacket, synchronizer);
},

View File

@ -0,0 +1,23 @@
import {Resource} from '@avocado/resource';
import {Synchronized} from '@avocado/s13n';
import {compose, EventEmitter} from '@latus/core';
export default (latus) => {
const decorate = compose(
EventEmitter,
Synchronized(latus),
);
return class Receiver extends decorate(Resource) {
async acceptPacket(packet) {
await super.acceptPacket(packet);
const {s13nType} = packet;
if ('create' === s13nType) {
const {Room} = latus.get('%resources');
const {id} = packet.data.synchronized;
this.emit('created', this.synchronized(Room.resourceId, id));
}
}
};
};

View File

@ -6,6 +6,10 @@ export default class Player {
this.user = user;
}
cleanInformingPackets() {
this.entity.cleanInformingPackets();
}
inform() {
this.entity.inform(this.socket);
}

View File

@ -26,7 +26,7 @@ export default (latus) => class Universe extends JsonResource {
addPlayer({entity, socket, user}) {
const room = this.room(entity.currentRoom);
room.addEntityToLayer(entity, 0);
entity.addSynchronized(room);
entity.startInforming(room);
const player = new Player({entity, socket, user});
this.#players.push(player);
return player;
@ -41,6 +41,7 @@ export default (latus) => class Universe extends JsonResource {
super.load(json);
const {tps = 60, uri} = json;
const {Room} = latus.get('%resources');
// console.log(Object.getPrototypeOf(Object.getPrototypeOf(Room)).toString());
if (uri) {
const universePath = dirname(uri);
await Promise.all(
@ -72,10 +73,14 @@ export default (latus) => class Universe extends JsonResource {
for (let i = 0; i < this.#players.length; ++i) {
promises.push(this.#players[i].inform());
}
// TODO: rogue client?
await Promise.all(promises);
for (let i = 0; i < this.#roomsFlat.length; i++) {
this.#roomsFlat[i].cleanPackets();
}
for (let i = 0; i < this.#players.length; ++i) {
this.#players[i].cleanInformingPackets();
}
}
static async load(json = {}) {
@ -88,7 +93,7 @@ export default (latus) => class Universe extends JsonResource {
removePlayer(player) {
const {entity} = player;
const room = this.room(entity.currentRoom);
entity.removeSynchronized(room);
entity.stopInforming(room);
room.removeEntityFromLayer(entity, 0);
const index = this.#players.indexOf(player);
if (-1 !== index) {