UNPKG

mudb

Version:

Real-time database for multiplayer games

183 lines 5.62 kB
"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