mudb
Version:
Real-time database for multiplayer games
183 lines • 5.62 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var uint32_1 = require("../schema/uint32");
var stream_1 = require("../stream");
exports.MuDefaultStateSchema = {
client: {
ackState: new uint32_1.MuUint32(),
forgetState: new uint32_1.MuUint32(),
},
server: {
ackState: new uint32_1.MuUint32(),
forgetState: new uint32_1.MuUint32(),
},
};
var MuStateSet = (function () {
function MuStateSet(initialState) {
this.ticks = [];
this.states = [];
this.ticks.push(0);
this.states.push(initialState);
}
MuStateSet.prototype.at = function (tick) {
for (var i = this.ticks.length - 1; i >= 0; --i) {
if (this.ticks[i] <= tick) {
return i;
}
}
return -1;
};
return MuStateSet;
}());
exports.MuStateSet = MuStateSet;
function pushState(stateSet, tick, state) {
var ticks = stateSet.ticks, states = stateSet.states;
ticks.push(tick);
states.push(state);
for (var i = ticks.length - 1; i >= 1; --i) {
if (ticks[i - 1] > tick) {
ticks[i] = ticks[i - 1];
states[i] = states[i - 1];
}
else {
ticks[i] = tick;
states[i] = state;
return;
}
}
}
function garbageCollectStates(schema, stateSet, horizon) {
var ticks = stateSet.ticks, states = stateSet.states;
var ptr = 1;
for (var i = 1; i < ticks.length; ++i) {
if (ticks[i] < horizon) {
schema.free(states[i]);
}
else {
ticks[ptr] = ticks[i];
states[ptr] = states[i];
ptr++;
}
}
ticks.length = ptr;
states.length = ptr;
var modified = ptr !== ticks.length;
return modified;
}
exports.garbageCollectStates = garbageCollectStates;
var _pointers = [];
var _heads = [];
function mostRecentCommonState(tickSets) {
_pointers.length = tickSets.length;
_heads.length = tickSets.length;
for (var i = 0; i < tickSets.length; ++i) {
_pointers[i] = tickSets[i].length - 1;
_heads[i] = tickSets[i][tickSets[i].length - 1];
}
while (true) {
var largestIndex = 0;
var largestValue = _heads[0];
var allEqual = true;
for (var i = 1; i < tickSets.length; ++i) {
var v = _heads[i];
allEqual = allEqual && (v === largestValue);
if (v > largestValue) {
largestIndex = i;
largestValue = v;
}
}
if (allEqual) {
return largestValue;
}
_heads[largestIndex] = tickSets[largestIndex][--_pointers[largestIndex]];
}
}
function addObservation(ticks, newTick) {
ticks.push(newTick);
for (var i = ticks.length - 2; i >= 0; --i) {
if (ticks[i] < newTick) {
ticks[i + 1] = newTick;
break;
}
else if (ticks[i] > newTick) {
ticks[i + 1] = ticks[i];
}
else {
ticks.splice(i + 1, 1);
break;
}
}
}
exports.addObservation = addObservation;
function forgetObservation(ticks, horizon) {
var pointer = 1;
for (var i = 1; i < ticks.length; ++i) {
if (ticks[i] >= horizon) {
ticks[pointer] = ticks[i];
pointer++;
}
}
ticks.length = pointer;
}
exports.forgetObservation = forgetObservation;
function parseState(packet, schema, replica, ack, forget) {
var history = replica.history, windowSize = replica.windowSize, state = replica.state;
var stream = new stream_1.MuReadStream(packet);
var nextTick = stream.readUint32();
for (var i = 0; i < history.ticks.length; ++i) {
if (history.ticks[i] === nextTick) {
return false;
}
}
var baseTick = stream.readUint32();
var baseIndex = history.at(baseTick);
if (history.ticks[baseIndex] !== baseTick) {
return false;
}
var baseState = history.states[baseIndex];
var nextState;
if (stream.offset < stream.length) {
nextState = schema.patch(baseState, stream);
}
else {
nextState = schema.clone(baseState);
}
pushState(history, nextTick, nextState);
ack(nextTick, true);
var horizon = baseTick - windowSize - 1;
if (garbageCollectStates(schema, history, horizon)) {
forget(horizon, true);
}
if (nextTick > replica.tick) {
replica.state = nextState;
replica.tick = nextTick;
return true;
}
return false;
}
exports.parseState = parseState;
function publishState(schema, observations, replica, raw, reliable) {
var history = replica.history, windowSize = replica.windowSize, state = replica.state;
observations.push(history.ticks);
var baseTick = mostRecentCommonState(observations);
observations.pop();
var baseIndex = history.at(baseTick);
var baseState = history.states[baseIndex];
var nextTick = ++replica.tick;
pushState(history, nextTick, schema.clone(state));
var stream = new stream_1.MuWriteStream(4096);
stream.writeUint32(nextTick);
stream.writeUint32(baseTick);
schema.diff(baseState, state, stream);
var contentBytes = stream.bytes();
raw(contentBytes, !reliable);
stream.destroy();
if (reliable) {
observations[observations.length - 1].push(nextTick);
}
var horizon = baseTick - windowSize - 1;
garbageCollectStates(schema, history, horizon);
return baseTick;
}
exports.publishState = publishState;
//# sourceMappingURL=state.js.map