Skip to content

replicator

The Replication class drives client-side entity interpolation and extrapolation. It maintains a queue of server ticks, advances a local clock (shiftedGameTime) each renderer frame, and fires callbacks when the client time crosses a tick boundary. It also tracks diagnostics such as FPS, frame stutters, extrapolation incidents, and client-server time desync.

Replication private

Bound to game.world as game.world.replicator.

Properties

NameTypeDescription
currentTickobject \| nullThe most recently consumed tick from the queue.
ticksobject[]Queue of incoming server ticks awaiting consumption.
shiftedGameTimenumberThe authoritative client-side game clock (ms), offset by a 90 ms interpolation buffer.
lastShiftedGameTimenumberPrevious frame's shiftedGameTime, used for renderer-pause detection.
receivedFirstTickbooleanWhether the first server tick has been received and the clock initialized.
serverTimenumberEstimated server time (ms), derived from each tick's index and ping.
msPerTicknumberDuration of one server tick in milliseconds.
msInThisTicknumberMilliseconds elapsed within the current tick window.
msElapsednumberAccumulator for fixed-timestep stutter detection.
lastMsElapsednumberDelta time of the most recent renderer frame.
pingnumberNetwork ping at the time of entering the world.
lastPingnumberPrevious ping value.
startTimeDate \| nullWall-clock timestamp when the first tick was received.
startShiftedGameTimenumberValue of shiftedGameTime at the moment the first tick was received.
frameStuttersnumberNumber of frames where more than one fixed timestep elapsed (frame drops).
frameTimesnumber[]Rolling window (last 10) of frame delta times for FPS calculation.
interpolatingbooleantrue when the client clock is within the bounds of the current tick window; false during extrapolation.
ticksDesyncednumberCounter for consecutive ticks where serverTime - shiftedGameTime < ping.
ticksDesynced2numberCounter for consecutive ticks where the client-server time difference exceeds 40 ms. Triggers a client time reset at 10.
clientTimeResetsnumberNumber of times the client clock was forcibly corrected due to desync.
maxExtrapolationTimenumberLargest observed extrapolation overshoot (ms).
totalExtrapolationTimenumberCumulative time spent extrapolating (ms).
extrapolationIncidentsnumberNumber of times the client transitioned from interpolation to extrapolation.
differenceInClientTimenumberMost recent difference between expected and actual client time (ms).
equalTimesnumberConsecutive frames where shiftedGameTime did not change, used for pause detection.
wasRendererJustUnpausedbooleanFlag set when the renderer resumes from a detected pause.
tickUpdatedCallbackFunctionCallback invoked when the client clock crosses a tick boundary (set by World).
latestTickUpdatedCallbackFunction \| undefinedOptional callback invoked immediately when a new tick arrives from the server.

Methods

init()

ts
function init(): void

Registers network handlers for EnterWorld and EntityUpdate, and adds a renderer tick callback.

setTargetTickUpdatedCallback()

ts
function setTargetTickUpdatedCallback(tickUpdatedCallback: function): void

Sets the callback that is invoked each time the client clock advances past a tick boundary. Used by World to receive entity updates.

setLatestTickUpdatedCallback()

ts
function setLatestTickUpdatedCallback(callback: function): void

Sets an optional callback invoked immediately upon receiving each entity update from the server, before tick scheduling.

resetClientLag()

ts
function resetClientLag(): void

Resets shiftedGameTime to the real client time, correcting any accumulated drift.

Getters & Setters

getClientTimeResets()

ts
function getClientTimeResets(): number

Returns the number of client clock resets that have occurred.

getMsInThisTick()

ts
function getMsInThisTick(): number

Returns the floored milliseconds elapsed within the current tick.

getMsPerTick()

ts
function getMsPerTick(): number

Returns the tick duration in milliseconds.

getMsSinceTick()

ts
function getMsSinceTick(tick: number, useInterpolationOffset?: boolean): number

Returns the milliseconds elapsed since the given tick. When useInterpolationOffset is true (default), adds a 2-tick offset before computing the delta.

getMsUntilTick()

ts
function getMsUntilTick(tick: number): number

Returns the milliseconds remaining until the given tick.

getServerTime()

ts
function getServerTime(): number

Returns the floored estimated server time.

getClientTime()

ts
function getClientTime(): number

Returns the floored shiftedGameTime.

getRealClientTime()

ts
function getRealClientTime(): number

Returns the actual wall-clock-based client time, computed from startShiftedGameTime plus the elapsed wall time since startTime. Returns 0 before the first tick is received.

getFrameStutters()

ts
function getFrameStutters(): number

Returns the total number of frame stutters detected.

getDifferenceInClientTime()

ts
function getDifferenceInClientTime(): number

Returns the most recent client time difference value.

isFpsReady()

ts
function isFpsReady(): boolean

Returns true once at least 10 frame times have been collected.

getFps()

ts
function getFps(): number

Computes and returns the average FPS from the last 10 frame deltas.

getInterpolating()

ts
function getInterpolating(): boolean

Returns whether the replicator is currently interpolating (as opposed to extrapolating).

getTickByteSize()

ts
function getTickByteSize(): number

Returns the byte size of the current tick. Returns 0 if no tick has been consumed yet.

getTickEntities()

ts
function getTickEntities(): number

Returns the number of entities in the current tick. Returns 0 if no tick has been consumed yet.

getTickIndex()

ts
function getTickIndex(): number

Returns the tick index of the current tick. Returns 0 if no tick has been consumed yet.

getLastMsElapsed()

ts
function getLastMsElapsed(): number

Returns the delta time of the most recent renderer frame.

getMaxExtrapolationTime()

ts
function getMaxExtrapolationTime(): number

Returns the maximum extrapolation overshoot observed (ms).

getExtrapolationIncidents()

ts
function getExtrapolationIncidents(): number

Returns the total number of extrapolation incidents.

getTotalExtrapolationTime()

ts
function getTotalExtrapolationTime(): number

Returns the cumulative time spent extrapolating (ms).

Event Handlers

onEnterWorld()

ts
function onEnterWorld(data: ENTER_WORLD_DATA): void

Handles the EnterWorld network event. If allowed is false, returns early. Otherwise resets all timing state — msPerTick, shiftedGameTime, serverTime, ping, and flags — preparing the replicator for a new world session.

onEntityUpdate()

ts
function onEntityUpdate(data: ENTITY_UPDATE_DATA): void

Handles incoming entity update packets. Fires the latestTickUpdatedCallback if set, updates serverTime, and pushes the tick onto the queue. On the first tick, initializes startTime, shiftedGameTime (with a 90 ms interpolation buffer), and startShiftedGameTime. On subsequent ticks, checks for renderer pauses, computes client lag difference, and resets the client clock if the desync exceeds 40 ms for 10 consecutive ticks or the renderer was just unpaused.

onTick()

ts
function onTick(msElapsed: number): void

Renderer tick handler. Accumulates frame times for FPS and stutter tracking, detects renderer pauses (zeroing msElapsed on resume to avoid time jumps), advances serverTime, shiftedGameTime, and msInThisTick, then calls updateTick().

updateTick() internal

ts
function updateTick(): void

Iterates the tick queue and fires tickUpdatedCallback for each tick whose start time the client clock has passed. After draining eligible ticks, checks whether the client clock exceeds the next expected tick boundary to detect extrapolation, and tracks desync counters.

checkRendererPaused() internal

ts
function checkRendererPaused(): void

Increments equalTimes if shiftedGameTime has not changed since the last check, or resets it to 0. Used by isRendererPaused().

isRendererPaused() internal

ts
function isRendererPaused(): boolean

Returns true when equalTimes >= 8, indicating the renderer has been stalled for at least 8 consecutive frames.