refactor: much cleaner informed
This commit is contained in:
parent
afb1002607
commit
fdf68f50ce
|
@ -42,6 +42,187 @@ export class Informed extends decorate(Trait) {
|
|||
);
|
||||
}
|
||||
|
||||
filterInvisibleEntityPackets(packets) {
|
||||
return packets.filter((packet) => {
|
||||
const entity = packet.entity;
|
||||
if (!entity) {
|
||||
return true;
|
||||
}
|
||||
// Removes could be on destroyed entities, so pass them.
|
||||
if (packet instanceof EntityRemovePacket) {
|
||||
return true;
|
||||
}
|
||||
return entity.is('visible');
|
||||
});
|
||||
}
|
||||
|
||||
filterKnownEntityCreatePackets(packets) {
|
||||
return packets.filter((packet) => {
|
||||
if (!packet.entity) {
|
||||
return true;
|
||||
}
|
||||
if (!(packet instanceof EntityCreatePacket)) {
|
||||
return true;
|
||||
}
|
||||
return !this.hasSeenEntity(packet.entity);
|
||||
});
|
||||
}
|
||||
|
||||
filterOutOfRangeEntityPackets(packets, outOfRangeEntities) {
|
||||
return packets.filter((packet) => {
|
||||
const entity = packet.entity;
|
||||
if (!entity) {
|
||||
return true;
|
||||
}
|
||||
// Send removes even if they're out of range, if client knows about
|
||||
// them.
|
||||
if (
|
||||
packet instanceof EntityRemovePacket
|
||||
&& this.hasSeenEntity(entity)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return -1 === outOfRangeEntities.indexOf(packet.entity);
|
||||
});
|
||||
}
|
||||
|
||||
hasSeenEntity(entity) {
|
||||
return -1 !== this.seenEntities.indexOf(entity);
|
||||
}
|
||||
|
||||
injectEntityCreatePackets(packets, visibleEntities) {
|
||||
// Get a list of all visible but not yet seen entities.
|
||||
const visibleButNotYetSeen = [];
|
||||
for (let i = 0; i < visibleEntities.length; i++) {
|
||||
const entity = visibleEntities[i];
|
||||
if (!this.hasSeenEntity(entity)) {
|
||||
visibleButNotYetSeen.push(entity);
|
||||
}
|
||||
}
|
||||
// Get a list of all existing created entities.
|
||||
const allExistingCreatedEntities = packets.filter((packet) => {
|
||||
return packet instanceof EntityCreatePacket;
|
||||
}).map((packet) => {
|
||||
return packet.entity;
|
||||
})
|
||||
// JIT inject creates before any unknown updates.
|
||||
for (let i = 0; i < packets.length; i++) {
|
||||
const packet = packets[i];
|
||||
// Only care about entity packets.
|
||||
if (!(packet instanceof EntityPacket)) {
|
||||
continue;
|
||||
}
|
||||
// Only unknown.
|
||||
const entity = packet.entity;
|
||||
if (this.hasSeenEntity(entity)) {
|
||||
continue;
|
||||
}
|
||||
if (-1 !== allExistingCreatedEntities.indexOf(entity)) {
|
||||
continue;
|
||||
}
|
||||
// Not creates nor removes.
|
||||
if (
|
||||
packet instanceof EntityCreatePacket
|
||||
|| packet instanceof EntityRemovePacket
|
||||
) {
|
||||
// This does count as seen.
|
||||
const index = visibleButNotYetSeen.indexOf(entity);
|
||||
if (-1 !== index) {
|
||||
visibleButNotYetSeen.splice(index, 1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Inject.
|
||||
packets.splice(
|
||||
i,
|
||||
0,
|
||||
new EntityCreatePacket(entity.toJSON(), entity)
|
||||
);
|
||||
i += 1;
|
||||
// We've seen it.
|
||||
const index = visibleButNotYetSeen.indexOf(entity);
|
||||
if (-1 !== index) {
|
||||
visibleButNotYetSeen.splice(index, 1);
|
||||
}
|
||||
allExistingCreatedEntities.push(entity);
|
||||
}
|
||||
// Append creates for any visible-but-not-yet-seen entities.
|
||||
for (let i = 0; i < visibleButNotYetSeen.length; i++) {
|
||||
const entity = visibleButNotYetSeen[i];
|
||||
// Skip any existing creates.
|
||||
if (-1 === allExistingCreatedEntities.indexOf(entity)) {
|
||||
packets.push(new EntityCreatePacket(entity.toJSON(), entity));
|
||||
}
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
|
||||
injectEntityRemovePackets(packets, visibleEntities) {
|
||||
for (let i = 0; i < this.seenEntities.length; i++) {
|
||||
const entity = this.seenEntities[i];
|
||||
if (-1 === visibleEntities.indexOf(entity)) {
|
||||
packets.push(new EntityRemovePacket({}, entity));
|
||||
}
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
|
||||
markEntitiesSeen(visibleEntities) {
|
||||
for (let i = 0; i < visibleEntities.length; i++) {
|
||||
const entity = visibleEntities[i];
|
||||
if (-1 === this.seenEntities.indexOf(entity)) {
|
||||
this.seenEntities.push(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
markEntitiesUnseen(packets) {
|
||||
const removedEntities = packets.filter((packet) => {
|
||||
return packet instanceof EntityRemovePacket;
|
||||
}).map((packet) => {
|
||||
return packet.entity;
|
||||
});
|
||||
for (let i = 0; i < removedEntities.length; i++) {
|
||||
const entity = removedEntities[i];
|
||||
const index = this.seenEntities.indexOf(entity)
|
||||
if (-1 !== index) {
|
||||
this.seenEntities.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reducePacketEntitiesByRange(packets) {
|
||||
// Unique packet entities.
|
||||
const packetEntitiesMap = new Map();
|
||||
for (let i = 0; i < packets.length; i++) {
|
||||
const entity = packets[i].entity;
|
||||
if (entity && !packetEntitiesMap.has(entity)) {
|
||||
packetEntitiesMap.set(entity, true);
|
||||
}
|
||||
}
|
||||
// Locate visible entities.
|
||||
const areaToInform = this.areaToInform;
|
||||
const visibleEntities = this.entity.room.visibleEntities(areaToInform);
|
||||
// Document out of range entities.
|
||||
const inRangeEntities = [];
|
||||
const outOfRangeEntities = [];
|
||||
let it = packetEntitiesMap.keys();
|
||||
for (let value = it.next(); !value.done; value = it.next()) {
|
||||
const entity = value.value;
|
||||
if (-1 === visibleEntities.indexOf(entity)) {
|
||||
if (-1 === outOfRangeEntities.indexOf(entity)) {
|
||||
outOfRangeEntities.push(entity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (-1 === inRangeEntities.indexOf(entity)) {
|
||||
inRangeEntities.push(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
return [inRangeEntities, outOfRangeEntities, visibleEntities];
|
||||
}
|
||||
|
||||
get socket() {
|
||||
return this._socket;
|
||||
}
|
||||
|
@ -59,155 +240,40 @@ export class Informed extends decorate(Trait) {
|
|||
return;
|
||||
}
|
||||
// Filter invisible entities.
|
||||
packets = packets.filter((packet) => {
|
||||
const entity = packet.entity;
|
||||
if (!entity) {
|
||||
return true;
|
||||
}
|
||||
// Removes could be on destroyed entities, so pass them.
|
||||
if (packet instanceof EntityRemovePacket) {
|
||||
return true;
|
||||
}
|
||||
return entity.is('visible');
|
||||
});
|
||||
// Build entity map.
|
||||
const packetEntitiesMap = new Map();
|
||||
for (let i = 0; i < packets.length; i++) {
|
||||
const entity = packets[i].entity;
|
||||
if (entity && !packetEntitiesMap.has(entity)) {
|
||||
packetEntitiesMap.set(entity, true);
|
||||
}
|
||||
}
|
||||
// Locate visible entities.
|
||||
const areaToInform = this.areaToInform;
|
||||
const visibleEntities = this.entity.room.visibleEntities(areaToInform);
|
||||
// Document out of range entities.
|
||||
const outOfRangeEntities = [];
|
||||
let it = packetEntitiesMap.keys();
|
||||
for (let value = it.next(); !value.done; value = it.next()) {
|
||||
const entity = value.value;
|
||||
if (-1 === visibleEntities.indexOf(entity)) {
|
||||
outOfRangeEntities.push(entity);
|
||||
}
|
||||
}
|
||||
packets = this.filterInvisibleEntityPackets(packets);
|
||||
// Reduce entities by range.
|
||||
const [
|
||||
inRangeEntities,
|
||||
outOfRangeEntities,
|
||||
visibleEntities,
|
||||
] = this.reducePacketEntitiesByRange(packets);
|
||||
|
||||
// TODO? Upgrade seen entity packets that are out of range to entity
|
||||
// remembers.
|
||||
|
||||
// Filter all the rest of out of range entity updates and remove them
|
||||
// from 'packet entities' map.
|
||||
packets = packets.filter((packet) => {
|
||||
const entity = packet.entity;
|
||||
if (!entity) {
|
||||
return true;
|
||||
}
|
||||
// Send removes even if they're out of range, if client knows about
|
||||
// them.
|
||||
if (
|
||||
packet instanceof EntityRemovePacket
|
||||
&& -1 !== this.seenEntities.indexOf(entity)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return -1 === outOfRangeEntities.indexOf(packet.entity);
|
||||
});
|
||||
for (let i = 0; i < outOfRangeEntities.length; i++) {
|
||||
packetEntitiesMap.delete(outOfRangeEntities[i]);
|
||||
}
|
||||
// Filter known creates. TODO: downgrade to trait updates.
|
||||
packets = packets.filter((packet) => {
|
||||
if (!packet.entity) {
|
||||
return true;
|
||||
}
|
||||
if (!(packet instanceof EntityCreatePacket)) {
|
||||
return true;
|
||||
}
|
||||
return -1 === this.seenEntities.indexOf(packet.entity);
|
||||
});
|
||||
// Inject creates for any visible-but-not-yet-seen entities.
|
||||
const currentEntities = Array.from(packetEntitiesMap.keys());
|
||||
for (let i = 0; i < visibleEntities.length; i++) {
|
||||
const entity = visibleEntities[i];
|
||||
if (
|
||||
// Haven't seen?
|
||||
-1 === this.seenEntities.indexOf(entity)
|
||||
// Isn't already addressed by some present update?
|
||||
&& -1 === currentEntities.indexOf(entity)
|
||||
) {
|
||||
packets.push(new EntityCreatePacket(entity.toJSON(), entity));
|
||||
this.seenEntities.push(entity);
|
||||
}
|
||||
}
|
||||
// Upgrade unknown entity updates to entity creates.
|
||||
// TODO would be nice to JIT inject a create right before the update.
|
||||
const unknownUpdatedEntities = [];
|
||||
// First filter out the bad updates.
|
||||
packets = packets.filter((packet) => {
|
||||
// Only care about entity packets.
|
||||
if (!(packet instanceof EntityPacket)) {
|
||||
return true;
|
||||
}
|
||||
// But not creates.
|
||||
if (packet instanceof EntityCreatePacket) {
|
||||
return true;
|
||||
}
|
||||
// Nor removes.
|
||||
if (packet instanceof EntityRemovePacket) {
|
||||
return true;
|
||||
}
|
||||
// Known? Nevermind.
|
||||
if (-1 !== this.seenEntities.indexOf(packet.entity)) {
|
||||
return true;
|
||||
}
|
||||
// Side-effect.
|
||||
if (-1 === unknownUpdatedEntities.indexOf(packet.entity)) {
|
||||
unknownUpdatedEntities.push(packet.entity);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
// Then, inject creates.
|
||||
for (let i = 0; i < unknownUpdatedEntities.length; i++) {
|
||||
const entity = unknownUpdatedEntities[i];
|
||||
packets.push(new EntityCreatePacket(entity.toJSON(), entity));
|
||||
this.seenEntities.push(entity);
|
||||
}
|
||||
// Filter the out of range entity updates.
|
||||
packets = this.filterOutOfRangeEntityPackets(
|
||||
packets,
|
||||
outOfRangeEntities
|
||||
);
|
||||
// Filter known creates.
|
||||
packets = this.filterKnownEntityCreatePackets(packets);
|
||||
// Inject create packets.
|
||||
packets = this.injectEntityCreatePackets(packets, visibleEntities);
|
||||
// Inject removes for any previously seen entity that isn't visible
|
||||
// anymore.
|
||||
for (let i = 0; i < this.seenEntities.length; i++) {
|
||||
const entity = this.seenEntities[i];
|
||||
if (-1 === visibleEntities.indexOf(entity)) {
|
||||
packets.push(new EntityRemovePacket({}, entity));
|
||||
}
|
||||
}
|
||||
// Document any new entities.
|
||||
it = packetEntitiesMap.keys();
|
||||
for (let value = it.next(); !value.done; value = it.next()) {
|
||||
const entity = value.value;
|
||||
if (-1 === this.seenEntities.indexOf(entity)) {
|
||||
this.seenEntities.push(entity);
|
||||
}
|
||||
}
|
||||
packets = this.injectEntityRemovePackets(packets, visibleEntities);
|
||||
// "See" entities.
|
||||
this.markEntitiesSeen(visibleEntities);
|
||||
// Unsee any removed entities.
|
||||
const removedEntities = packets.filter((packet) => {
|
||||
return packet instanceof EntityRemovePacket;
|
||||
}).map((packet) => {
|
||||
return packet.entity;
|
||||
});
|
||||
for (let i = 0; i < removedEntities.length; i++) {
|
||||
const entity = removedEntities[i];
|
||||
const index = this.seenEntities.indexOf(entity)
|
||||
if (-1 !== index) {
|
||||
this.seenEntities.splice(index, 1);
|
||||
}
|
||||
}
|
||||
// Ship it!
|
||||
this.markEntitiesUnseen(packets);
|
||||
// Ship it! TODO: bundle.
|
||||
for (let i = 0; i < packets.length; i++) {
|
||||
const packet = packets[i];
|
||||
// This can actually happen during a send. Yikes.
|
||||
if (!this._socket) {
|
||||
break;
|
||||
}
|
||||
this._socket.send(packet);
|
||||
this._socket.send(packets[i]);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user