network the MPs finally, this removes traplaunches though

This commit is contained in:
RandomityGuy 2024-06-24 13:47:55 +05:30
parent 37e0b74347
commit b4d7d5633b
7 changed files with 213 additions and 28 deletions

View file

@ -7,6 +7,7 @@ import mis.MisParser;
import src.Settings;
import src.Debug;
import src.MarbleGame;
import src.ProfilerUI;
@:publicFields
class ConsoleEntry {
@ -122,6 +123,7 @@ class Console {
log("rewindTimeScale <scale>");
log("drawBounds <true/false>");
log("wireframe <true/false>");
log("fps <true/false>");
} else if (cmdType == "timeScale") {
if (cmdSplit.length == 2) {
var scale = Std.parseFloat(cmdSplit[1]);
@ -163,6 +165,14 @@ class Console {
} else {
error("Expected one argument, got " + (cmdSplit.length - 1));
}
} else if (cmdType == "fps") {
if (cmdSplit.length == 2) {
var scale = MisParser.parseBoolean(cmdSplit[1]);
ProfilerUI.setEnabled(scale);
log("FPS Display set to " + scale);
} else {
error("Expected one argument, got " + (cmdSplit.length - 1));
}
} else if (cmdType == 'rollback') {
var t = Std.parseFloat(cmdSplit[1]);
MarbleGame.instance.world.rollback(t);

View file

@ -1637,12 +1637,13 @@ class Marble extends GameObject {
oldPos = this.collider.transform.getPosition();
prevRot = this.getRotationQuat().clone();
if (this.controllable) {
for (interior in pathedInteriors) {
// interior.pushTickState();
interior.computeNextPathStep(timeRemaining);
}
// if (this.controllable) {
for (interior in pathedInteriors) {
if (Net.isMP)
interior.pushTickState();
interior.computeNextPathStep(timeRemaining);
}
// }
// Blast
if (m != null && m.blast) {
@ -1795,11 +1796,11 @@ class Marble extends GameObject {
timeRemaining -= timeStep;
if (this.controllable) {
for (interior in pathedInteriors) {
interior.advance(timeStep);
}
// if (this.controllable) {
for (interior in pathedInteriors) {
interior.advance(timeStep);
}
// }
piTime += timeStep;
@ -1808,11 +1809,11 @@ class Marble extends GameObject {
} while (true);
if (timeRemaining > 0) {
// Advance pls
if (this.controllable) {
for (interior in pathedInteriors) {
interior.advance(timeRemaining);
}
// if (this.controllable) {
for (interior in pathedInteriors) {
interior.advance(timeRemaining);
}
// }
}
this.queuedContacts = [];
@ -1856,6 +1857,10 @@ class Marble extends GameObject {
this.level.cancel(this.oobSchedule);
this.level.restart(cast this);
}
for (interior in pathedInteriors) {
interior.popTickState();
}
}
}
@ -1899,6 +1904,7 @@ class Marble extends GameObject {
// return false;
// }
// }
// trace('Tick RTT: ', this.serverTicks - p.serverTicks);
this.serverTicks = p.serverTicks;
this.recvServerTick = p.serverTicks;
// this.oldPos = this.newPos;
@ -2034,13 +2040,13 @@ class Marble extends GameObject {
var smooth = 1.0 / (newDt * (newDt * 0.235 * newDt) + newDt + 1.0 + 0.48 * newDt * newDt);
this.netSmoothOffset.scale(smooth);
var smoothScale = this.netSmoothOffset.lengthSq();
if (smoothScale < 0.1 || smoothScale > 10.0)
if (smoothScale < 0.01 || smoothScale > 10.0)
this.netSmoothOffset.set(0, 0, 0);
if (oldPos != null && newPos != null) {
var deltaT = physicsAccumulator / 0.032;
if (Net.isClient && !this.controllable)
deltaT *= 0.75; // Don't overshoot
// if (Net.isClient && !this.controllable)
// deltaT *= 0.75; // Don't overshoot
var renderPos = Util.lerpThreeVectors(this.oldPos, this.newPos, deltaT);
if (Net.isClient) {
renderPos.load(renderPos.add(this.netSmoothOffset));

View file

@ -1547,6 +1547,12 @@ class MarbleWorld extends Scheduler {
@:privateAccess this.marble.posStore.load(this.marble.newPos);
@:privateAccess this.marble.netCorrected = true;
// if ((marbleNeedsPrediction & (1 << Net.clientId) > 0)) {
for (pi in this.pathedInteriors) {
pi.rollbackToTick(currentTick);
}
// }
for (move in ourQueuedMoves) {
var m = move.move;
Debug.drawSphere(@:privateAccess this.marble.newPos, this.marble._radius);
@ -1574,6 +1580,13 @@ class MarbleWorld extends Scheduler {
advanceTimeState.currentAttemptTime += 0.032;
advanceTimeState.ticks++;
currentTick++;
// if ((marbleNeedsPrediction & (1 << Net.clientId) > 0)) {
for (pi in this.pathedInteriors) {
pi.computeNextPathStep(0.032);
pi.advance(0.032);
}
// }
}
lastMoves.ourMoveApplied = true;
@ -1858,6 +1871,10 @@ class MarbleWorld extends Scheduler {
this.marble.clearNetFlags();
}
}
for (pi in this.pathedInteriors) {
pi.computeNextPathStep(0.032);
pi.advance(0.032);
}
timeState.ticks++;
}
timeState.subframe = tickAccumulator / 0.032;

View file

@ -40,6 +40,9 @@ class PathedInterior extends InteriorObject {
public var currentTime:Float;
public var targetTime:Float;
var initialPosition:Float;
var initialTargetPosition:Float;
var basePosition:Vector;
var baseOrientation:Quat;
var baseScale:Vector;
@ -52,6 +55,12 @@ class PathedInterior extends InteriorObject {
var stopped:Bool = false;
var stoppedPosition:Vector;
var savedPosition:Vector;
var savedVelocity:Vector;
var savedStopped:Bool;
var savedStoppedPosition:Vector;
var savedTime:Float;
var soundChannel:Channel;
public static function createFromSimGroup(simGroup:MissionElementSimGroup, level:MarbleWorld, onFinish:PathedInterior->Void) {
@ -173,6 +182,33 @@ class PathedInterior extends InteriorObject {
}
}
public function getInternalTime(externalTime:Float) {
if (this.targetTime < 0) {
var direction = (this.targetTime == -1) ? 1 : (this.targetTime == -2) ? -1 : 0;
return Util.adjustedMod(this.currentTime + externalTime * direction, this.duration);
} else {
var dur = Math.abs(this.currentTime - this.targetTime);
var compvarion = Util.clamp(dur != 0 ? externalTime / dur : 1, 0, 1);
return Util.clamp(Util.lerp(this.currentTime, this.targetTime, compvarion), 0, this.duration);
}
}
public function rollbackToTick(tick:Int) {
// this.reset();
// Reset
this.currentTime = initialPosition;
this.targetTime = initialTargetPosition;
if (this.targetTime < 0) {
var direction = (this.targetTime == -1) ? 1 : (this.targetTime == -2) ? -1 : 0;
this.currentTime = Util.adjustedMod(this.currentTime + (tick * 0.032) * direction, duration);
} else {
this.currentTime = Util.clamp(this.currentTime + (tick * 0.032), 0, duration);
}
this.computeNextPathStep(0.032);
this.advance(0.032);
}
public function advance(timeDelta:Float) {
if (stopped)
return;
@ -213,6 +249,25 @@ class PathedInterior extends InteriorObject {
this.stoppedPosition = this.position.clone();
}
public function pushTickState() {
savedPosition = this.position.clone();
savedVelocity = this.velocity.clone();
savedStopped = this.stopped;
savedStoppedPosition = this.stoppedPosition != null ? this.stoppedPosition.clone() : null;
savedTime = this.currentTime;
}
public function popTickState() {
this.position.load(savedPosition);
this.velocity.load(savedVelocity);
this.stopped = savedStopped;
this.stoppedPosition = savedStoppedPosition;
this.collider.transform.setPosition(savedPosition);
collisionWorld.updateTransform(this.collider);
this.currentTime = savedTime;
}
function computeDuration() {
var total = 0.0;
for (i in 0...(markerData.length - 1)) {
@ -311,9 +366,12 @@ class PathedInterior extends InteriorObject {
override function reset() {
this.currentTime = 0;
this.targetTime = 0;
this.initialPosition = 0;
this.initialTargetPosition = 0;
if (this.element.initialposition != "") {
this.currentTime = MisParser.parseNumber(this.element.initialposition) / 1000;
initialPosition = this.currentTime;
}
if (this.element.initialtargetposition != "") {
@ -323,6 +381,8 @@ class PathedInterior extends InteriorObject {
// Alright this is strange. In Torque, there are some FPS-dependent client/server desync issues that cause the interior to start at the end position whenever the initialTargetPosition is somewhere greater than 1 and, like, approximately below 50.
if (this.targetTime > 0 && this.targetTime < 0.05)
this.currentTime = this.duration;
initialTargetPosition = this.targetTime;
}
this.stopped = false;

View file

@ -1,44 +1,136 @@
package src;
import net.Net;
import src.MarbleGame;
import h3d.Vector;
import hxd.res.DefaultFont;
import h2d.Text;
class ProfilerUI {
var fpsCounter:Text;
var networkStats:Text;
var debugProfiler:h3d.impl.Benchmark;
var s2d:h2d.Scene;
public var fps:Float;
public static var instance:ProfilerUI;
static var enabled:Bool = false;
static var mode:Int = 0;
public function new(s2d:h2d.Scene) {
if (instance != null)
return;
instance = this;
// debugProfiler = new h3d.impl.Benchmark(s2d);
// debugProfiler.y = 40;
// fpsCounter = new Text(DefaultFont.get(), s2d);
// fpsCounter.y = 80;
// fpsCounter.color = new Vector(1, 1, 1, 1);
this.s2d = s2d;
}
public static function begin() {
// instance.debugProfiler.begin();
if (!enabled)
return;
// if (type == mode)
instance.debugProfiler.begin();
}
public static function measure(name:String) {
// instance.debugProfiler.measure(name);
if (!enabled)
return;
// if (type == mode)
instance.debugProfiler.measure(name);
}
public static function end() {
// instance.debugProfiler.end();
if (!enabled)
return;
// if (type == mode)
instance.debugProfiler.end();
}
public static function update(fps:Float) {
instance.fps = fps;
// instance.fpsCounter.text = "FPS: " + fps;
if (!enabled)
return;
instance.fpsCounter.text = "FPS: " + fps;
updateNetworkStats();
}
public static function setEnabled(val:Bool) {
enabled = val;
if (enabled) {
if (instance.debugProfiler != null) {
instance.debugProfiler.remove();
instance.debugProfiler = null;
}
if (instance.fpsCounter != null) {
instance.fpsCounter.remove();
instance.fpsCounter = null;
}
if (instance.networkStats != null) {
instance.networkStats.remove();
instance.networkStats = null;
}
instance.debugProfiler = new h3d.impl.Benchmark(instance.s2d);
instance.debugProfiler.y = 40;
instance.fpsCounter = new Text(DefaultFont.get(), instance.s2d);
instance.fpsCounter.y = 80;
instance.fpsCounter.color = new Vector(1, 1, 1, 1);
instance.networkStats = new Text(DefaultFont.get(), instance.s2d);
instance.networkStats.y = 150;
instance.networkStats.color = new Vector(1, 1, 1, 1);
instance.debugProfiler.end(); // End current frame
} else {
instance.debugProfiler.remove();
instance.fpsCounter.remove();
instance.networkStats.remove();
instance.debugProfiler = null;
instance.fpsCounter = null;
instance.networkStats = null;
}
}
public static function setDisplayMode(m:Int) {
mode = m;
if (instance.debugProfiler != null) {
instance.debugProfiler.end(); // End
}
}
static function updateNetworkStats() {
if (MarbleGame.instance.world != null && MarbleGame.instance.world.isMultiplayer) {
static var lastSentMove = 0;
if (Net.isClient && Net.clientConnection.getQueuedMovesLength() > 0) {
lastSentMove = @:privateAccess Net.clientConnection.moveManager.queuedMoves[Net.clientConnection.moveManager.queuedMoves.length - 1].id;
}
if (Net.isClient
&& lastSentMove != 0
&& @:privateAccess MarbleGame.instance.world.lastMoves != null
&& @:privateAccess MarbleGame.instance.world.lastMoves.myMarbleUpdate != null) {
instance.networkStats.text = 'Client World Ticks: ${MarbleGame.instance.world.timeState.ticks}\n'
+ 'Client Marble Ticks: ${@:privateAccess MarbleGame.instance.world.marble.serverTicks}\n'
+ 'Server Ticks: ${@:privateAccess MarbleGame.instance.world.lastMoves.myMarbleUpdate.serverTicks}\n'
+ 'Client Move Queue Size: ${Net.isClient ? Net.clientConnection.getQueuedMovesLength() : 0}\n'
+ 'Server Move Queue Size: ${Net.isClient ? @:privateAccess MarbleGame.instance.world.lastMoves.myMarbleUpdate.moveQueueSize : 0}\n'
+ 'Last Sent Move: ${Net.isClient ? lastSentMove : 0}\n'
+ 'Last Ack Move: ${Net.isClient ? @:privateAccess Net.clientConnection.moveManager.lastAckMoveId : 0}\n'
+ 'Move Ack RTT: ${Net.isClient ? @:privateAccess Net.clientConnection.moveManager.ackRTT : 0}';
}
if (Net.isHost) {
var strs = [];
strs.push('World Ticks: ${MarbleGame.instance.world.timeState.ticks}');
for (dc => cc in Net.clients) {
strs.push('${cc.id} move: sz ${@:privateAccess cc.moveManager.getQueueSize()} avg ${@:privateAccess cc.moveManager.serverAvgMoveListSize}');
}
instance.networkStats.text = strs.join('\n');
}
} else {
instance.networkStats.text = "";
}
}
}

View file

@ -156,7 +156,7 @@ class MPPlayMissionGui extends GuiImage {
searchBtn.position = new Vector(255, 514);
searchBtn.extent = new Vector(44, 44);
searchBtn.pressedAction = (e) -> {
MarbleGame.canvas.pushDialog(new MPSearchGui(false));
MarbleGame.canvas.pushDialog(new MPSearchGui(currentCategory == "custom"));
}
if (Net.isHost)
window.addChild(searchBtn);

View file

@ -33,7 +33,7 @@ class MPSearchGui extends GuiImage {
}
}
} else {
var customsList = MissionList.customMissions;
var customsList = Marbleland.multiplayerMissions;
for (mis in customsList) {
missionList.push({
mis: mis,