191 lines
6.5 KiB
JavaScript
191 lines
6.5 KiB
JavaScript
const GAME_TICKRATE = 1000 / 30;
|
|
const INACTIVITY_THRESHOLD_MS = 5 * 60000;
|
|
|
|
let looseAccumulator = 0;
|
|
let accumulator = 0;
|
|
let difference = 0;
|
|
let n = performance.now();
|
|
let nn = Date.now();
|
|
let batch = {};
|
|
let isLooseIteration = false;
|
|
|
|
const packet = require("./Packets/packet");
|
|
|
|
const Game = require("./Game/Game");
|
|
|
|
const getFixedDate = require("./Utility/getFixedDate");
|
|
|
|
const packetRelevancies = require("./Data/packetRelevancies");
|
|
const constants = require("./Data/constants");
|
|
const { TIMING_EVENTS_BY_ID } = constants;
|
|
|
|
function gameLoop() {
|
|
difference = performance.now() - n;
|
|
accumulator += difference;
|
|
n = performance.now();
|
|
nn = Date.now();
|
|
|
|
if (accumulator > GAME_TICKRATE) {
|
|
Game.maps.forEach(map => {
|
|
map.eventAuthors.forEach(id => {
|
|
const currentFlush = map.eventBuffer[id];
|
|
const entity = map.getEntityFromSubgroup(currentFlush.target);
|
|
if (entity) entity.emit("attacking", currentFlush.data, currentFlush.author);
|
|
});
|
|
|
|
if (looseAccumulator === 15) {
|
|
looseAccumulator = 0;
|
|
isLooseIteration = true;
|
|
};
|
|
|
|
map.players.forEach(player => {
|
|
if (isLooseIteration) {
|
|
player.isInactive = player.lastInteractionTimestamp + INACTIVITY_THRESHOLD_MS < n;
|
|
|
|
player.refreshVisibilities(false);
|
|
|
|
if (player.isInactive) player.setIndependentEvent(4, 0);
|
|
};
|
|
|
|
if (player.hasUnexpectedlyLeft) return;
|
|
|
|
player.flush(1);
|
|
|
|
batch.packet = null;
|
|
batch.offset = 0;
|
|
|
|
const localPacketsLength = map.networkPacketsLocal.length;
|
|
const individual = map.networkPacketsInvidiual[player.id];
|
|
|
|
if (!localPacketsLength && individual)
|
|
for (let i = 0, length = individual.length; i < length; i++) batch = packet(individual[i].packet, batch, player.id, individual[i].metadata);
|
|
|
|
if (localPacketsLength)
|
|
for (let i = 0, j = 0; i < localPacketsLength; i++) {
|
|
const p = map.networkPacketsLocal[i];
|
|
const relevancyRequirement = packetRelevancies[p.header];
|
|
if (relevancyRequirement(player, p)) batch = packet(p.packet, batch, player.id, p.metadata);
|
|
|
|
if (individual)
|
|
while (j < individual.length && (i === individual[j].index || i === localPacketsLength - 1)) {
|
|
batch = packet(individual[j].packet, batch, player.id, individual[j].metadata);
|
|
j++;
|
|
};
|
|
};
|
|
|
|
for (let i = 0, length = map.testPackets.length; i < length; i++) {
|
|
const p = map.testPackets[i];
|
|
const relevancyRequirement = packetRelevancies[p.header];
|
|
if (relevancyRequirement(player, p)) batch = packet(p.packet, batch, player.id, p.metadata);
|
|
};
|
|
|
|
for (let i = 0, length = map.networkPacketsGlobal.length; i < length; i++) {
|
|
const p = map.networkPacketsGlobal[i];
|
|
batch = packet(p.packet, batch, player.id, p.metadata);
|
|
};
|
|
|
|
if (player.topics) {
|
|
player.topics.each((key, value) => {
|
|
for (let i = 0, length = value.length; i < length; i++) {
|
|
const p = value[i];
|
|
batch = packet(p, batch, player.id);
|
|
};
|
|
});
|
|
};
|
|
|
|
if (batch.offset) {
|
|
const packet = batch.packet.slice(0, batch.offset);
|
|
const session = socket.sockets[player.sessionID];
|
|
session.send(packet, true, true);
|
|
};
|
|
|
|
if (individual) individual.length = 0;
|
|
});
|
|
|
|
map.testPackets.length = 0;
|
|
map.networkPacketsGlobal.length = 0;
|
|
|
|
map.eventAuthors.length = 0;
|
|
map.eventBuffer = {};
|
|
|
|
map.packetCount = map.networkPacketsLocal.length;
|
|
map.networkPacketsLocal.length = 0;
|
|
|
|
if (isLooseIteration) {
|
|
map.towers.forEach(tower => {
|
|
if (!tower.searchedTarget) return;
|
|
|
|
tower.initializeAttackWithCannon(tower.searchedTarget);
|
|
tower.searchedTarget = null;
|
|
});
|
|
|
|
map.lookingForTarget.forEach(e => e.initializeAttackWithCannon(e.searchedTarget));
|
|
map.lookingForTarget.length = 0;
|
|
|
|
map.dirtyChunks.forEach(c => {
|
|
c.map.clear();
|
|
c.head = null;
|
|
c.tail = null;
|
|
});
|
|
};
|
|
});
|
|
|
|
Game.packets.each((_, value) => {
|
|
if (value.length > 0) console.info("Topic length", value.length, "All topics length", Game.packets.map.size)
|
|
value.length = 0
|
|
});
|
|
|
|
const closest = Game.events.peek();
|
|
if (closest && n >= closest.value)
|
|
Game.events.forEach(entry => {
|
|
if (n < entry.value) return false;
|
|
|
|
const event = Game.events.poll();
|
|
const { id, entity, index, getLocalization, data, isSingle } = event.obj;
|
|
const mapID = getLocalization();
|
|
const map = Game.maps[mapID - 1];
|
|
const entityInstance = map.getEntityFromSubgroup(entity.id);
|
|
|
|
const eventExists = entityInstance && entityInstance.events[id] && entityInstance.events[id][index];
|
|
const isCancelled = eventExists && entityInstance.events[id][index].isCancelled;
|
|
|
|
if (isSingle && eventExists) entityInstance.events[id][index].isOver = true;
|
|
|
|
if (!isCancelled && eventExists) {
|
|
const methodName = TIMING_EVENTS_BY_ID[id];
|
|
entityInstance[methodName](data);
|
|
};
|
|
|
|
return true;
|
|
});
|
|
|
|
const closestFixed = Game.eventsFixed.peek();
|
|
if (closestFixed && nn >= closestFixed.value)
|
|
Game.eventsFixed.forEach(entry => {
|
|
if (nn < entry.value) return false;
|
|
|
|
const event = Game.eventsFixed.poll();
|
|
|
|
const { fn, arguments, next } = event.obj;
|
|
|
|
fn(...arguments);
|
|
|
|
if (next) {
|
|
const nextRunDate = getFixedDate(30);
|
|
next(nextRunDate, event.obj);
|
|
};
|
|
|
|
return true;
|
|
});
|
|
|
|
isLooseIteration = false;
|
|
looseAccumulator++;
|
|
|
|
accumulator -= GAME_TICKRATE;
|
|
};
|
|
|
|
if (difference < GAME_TICKRATE - 32) setTimeout(() => gameLoop());
|
|
else setImmediate(() => gameLoop());
|
|
};
|
|
|
|
module.exports = gameLoop; |