// get current local relative time
this.getCurrTimeC = function () {
return (performance.now() - this.appStart);
}
// get the synchronized time
// Between server and client
// _coffset is the delta time between client and server
this.getCurrTime = function () {
var curr = performance.now() + this._coffset;
this.lastCurrTime = curr;
return (curr - this.appStart);
}
this.processLatency = function (cp2, clTime1, servTime1, servTime2, lastSize,px,py) {
// px py are position of player on the server
// this fn calculates the time offset between se4ver and the client
// cp2 : current time on client
//cltime: client time of the last input sent to server
// servtime1 : server time when last input recieved from client
//servtime2 : server time when the last packet sent
// all these times are delta times like cp2 is the performance.now- appstarttime
this.lastServTime = this.servTime;
this.servTime = servTime2;
this.packDt = this.servTime - this.lastServTime;
var rtt = this.roundTripTime = cp2 - clTime1;
var now = this.getCurrTime();
var spp = servTime2 - servTime1;
/// more than 100s with no input
this.latency = (rtt - spp) / 2;
this.lat_coll.push(this.latency);
this.alatency = Math.floor(this.lat_coll.reduce(function (a, b) {
return a + b;
}) / this.lat_coll.length);
if (this.packRec % 19 === 0) {
this._coffset = ((servTime2 + this.alatency - cp2) + (servTime1 - this.alatency - clTime1)) * 0.5;
}
this.packRec++;
this.ctimeArr.length > 10 && this.ctimeArr.splice(0, 1);
this.ctimeArr.push(this._coffset);
this._coffset_avg = Math.floor(this.ctimeArr.reduce(function (a, b) {
return a + b;
}) / this.ctimeArr.length);
this.lat_coll.length > Conf.LAT_SIZE && this.lat_coll.splice(0, 1);
this.lastPackFromServ = this.getCurrTime();
this.lastPackSize = lastSize;
this.player.pushSnapshots(servTime2,now,px,py);
};
Player.prototype.pushSnapshots = function (sTime, now, px, py) {
// ip is the interpolator
// stime is the time when server sent the packet and now is current sync time.
this.ip.addSample(sTime, now, px, py);
};
// currentTime is the sync time
Player.prototype.updatePlayer = function (currentTime) {
var ret = this.ip.getPosition(currentTime, this.id);
if (ret) {
this.position.x = ret[0];
this.position.y = ret[1];
}
};
// interpolator
var PI = Math.PI;
var TWO_PI = Math.PI * 2;
var DEF_UP = 100;
var MAX_STICK_TIME = 350; //
var Vec2D = function (x, y) {
this.x = x || 0;
this.y = y || 0;
}
var Interpolator = function (id) {
this.id = id;
this.SnapPosition = new Vec2D(0, 0);
this.SnapVelocity = new Vec2D(0, 0);
this.AimPos = new Vec2D(0, 0);
this.LastPackPos = new Vec2D(0, 0);
this.SnapTime = 0;
this.AimTime = 0;
this.Latency = 0;
this.UpdateTime = DEF_UP;
this.LastPacketTime = 0;
};
module.exports = Interpolator;
Interpolator.prototype.reset = function (pt, ct, pos) {
this.LastPacketTime = pt;
this.LastPackPos.x = this.SnapPosition.x = pos.x;
this.LastPackPos.y = this.SnapPosition.y = pos.y;
this.SnapTime = ct;
this.UpdateTime = DEF_UP;
this.Latency = this.UpdateTime;
this.AimTime = ct + this.UpdateTime;
this.AimPos.x = this.SnapPosition.x + this.SnapVelocity.x * this.UpdateTime;
this.AimPos.y = this.SnapPosition.y + this.SnapVelocity.y * this.UpdateTime;
}
Interpolator.prototype.addSample = function (packetTime, currTime, px,py) {
var dt = 0,
snapRead = [],
packDel = 1.0 / (packetTime - this.LastPacketTime);
var MA = Math.abs;
if (MA(packetTime - this.LastPacketTime) < 0.0001 || !this.Smooth(packetTime, currTime)) {
return null; // neglect this sample
}
var _a = MA(px - this.LastPackPos.x);
var _b = MA(py - this.LastPackPos.y);
if(_a>300 || _b>300){
this.SnapPosition.x = px;
this.SnapPosition.y = py;
}
this.LastPackPos.x = px;
this.LastPackPos.y = py;
this.LastPacketTime = packetTime;
snapRead = this.getPosition(currTime);
this.SnapPosition.x = snapRead[0];
this.SnapPosition.y = snapRead[1];
this.AimTime = currTime + this.UpdateTime;
this.SnapTime = currTime;
this.AimPos.x = px;
this.AimPos.y = py;
if ((MA(this.AimTime - this.SnapTime) >= 0.0001)) {
dt = 1 / (this.AimTime - this.SnapTime);
this.SnapVelocity.x = (this.AimPos.x - this.SnapPosition.x) * dt;
this.SnapVelocity.y = (this.AimPos.y - this.SnapPosition.y) * dt;
}else{
this.SnapVelocity.x =0;
this.SnapVelocity.y = 0;
}
};
Interpolator.prototype.Smooth = function (packtime, currtime) {
if (packtime <= this.LastPacketTime) {
return false;
}
var lat = currtime - packtime;
var tick = packtime - this.LastPacketTime;
if(tick>MAX_STICK_TIME){
this.LastPacketTime = packtime - 30;
tick = 50;
}
lat < 0 && (lat = 0);
this.Latency = (lat > this.Latency) ? ((this.Latency + lat) * 0.5) : ((this.Latency * 7 + lat) * 0.125);
this.UpdateTime = (tick > this.UpdateTime) ? ((this.UpdateTime + tick) * 0.5) : ((this.UpdateTime * 7 + tick) * 0.125);
return true;
};
Interpolator.prototype.getPosition = function (forTime,id) {
var maxRange = this.AimTime + this.UpdateTime;
forTime < this.SnapTime && (forTime = this.SnapTime);
forTime > maxRange && (forTime = maxRange);
var max = forTime - this.SnapTime;
var getPos = [this.SnapPosition.x + this.SnapVelocity.x * max, this.SnapPosition.y + this.SnapVelocity.y * max];
return getPos;
};
The code above is based on code from @hplus0603
The code above works OK but there is some jitter from time to time.
Any help will be greatly appreciated.
Thanks.