mirror of
https://github.com/logsol/chuck.js.git
synced 2026-05-11 10:37:34 +00:00
The old PUNKBUSTER check compared client-reported position to server position and snapped the player back when latency made them diverge, which felt like getting teleported under any real network conditions. Replaces that with proper client-side prediction + reconciliation: client tags each input with a sequence number and keeps an input buffer; server tracks the last processed sequence and reports its authoritative position via a per-user inputAck alongside each worldUpdate. The client only corrects when the actual disagreement exceeds what the unacked input time can explain — so steady-state movement runs purely on local physics, and only genuine unexpected events (collisions, being hit) trigger a smooth blend toward the server state. Includes adaptive threshold scaling so high-latency sessions don't false-positive corrections during normal running.
57 lines
No EOL
1.6 KiB
JavaScript
Executable file
57 lines
No EOL
1.6 KiB
JavaScript
Executable file
define([
|
|
"Game/Core/Control/PlayerController",
|
|
"Lib/Utilities/NotificationCenter",
|
|
"Lib/Utilities/Protocol/Parser"
|
|
],
|
|
|
|
function(Parent, nc, Parser) {
|
|
|
|
"use strict";
|
|
|
|
function PlayerController(player) {
|
|
|
|
Parent.call(this, player);
|
|
this._lastProcessedSeq = 0;
|
|
}
|
|
|
|
PlayerController.prototype = Object.create(Parent.prototype);
|
|
|
|
/*
|
|
* retrieves move (and other) commands from client and executes them at the server
|
|
*/
|
|
PlayerController.prototype.applyCommand = function(options) {
|
|
// FIXME: remove this function and use ProtocolHelper.applyCommand() instead
|
|
// Don't forget to change the function names to on...
|
|
var message;
|
|
if (typeof options == "string") {
|
|
message = Parser.decode(options);
|
|
} else {
|
|
message = options;
|
|
}
|
|
|
|
for (var command in message) {
|
|
var commandOptions = message[command];
|
|
|
|
// Track sequence number from client input commands
|
|
if (commandOptions && typeof commandOptions === 'object' && commandOptions._seq !== undefined) {
|
|
this._lastProcessedSeq = commandOptions._seq;
|
|
}
|
|
|
|
this[command].call(this, commandOptions);
|
|
}
|
|
};
|
|
|
|
PlayerController.prototype.handActionRequest = function(options) {
|
|
options.x = parseFloat(options.x) || 0.0;
|
|
options.y = parseFloat(options.y) || 0.0;
|
|
options.av = parseFloat(options.av) || 0.0;
|
|
if (options) this.player.handActionRequest(options);
|
|
};
|
|
|
|
PlayerController.prototype.suicide = function() {
|
|
this.player.suicide();
|
|
};
|
|
|
|
return PlayerController;
|
|
|
|
}); |