network the MPs finally, this removes traplaunches though

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

View file

@ -7,6 +7,7 @@ import mis.MisParser;
import src.Settings; import src.Settings;
import src.Debug; import src.Debug;
import src.MarbleGame; import src.MarbleGame;
import src.ProfilerUI;
@:publicFields @:publicFields
class ConsoleEntry { class ConsoleEntry {
@ -122,6 +123,7 @@ class Console {
log("rewindTimeScale <scale>"); log("rewindTimeScale <scale>");
log("drawBounds <true/false>"); log("drawBounds <true/false>");
log("wireframe <true/false>"); log("wireframe <true/false>");
log("fps <true/false>");
} else if (cmdType == "timeScale") { } else if (cmdType == "timeScale") {
if (cmdSplit.length == 2) { if (cmdSplit.length == 2) {
var scale = Std.parseFloat(cmdSplit[1]); var scale = Std.parseFloat(cmdSplit[1]);
@ -167,6 +169,14 @@ class Console {
#if sys #if sys
hl.Gc.dumpMemory(); hl.Gc.dumpMemory();
#end #end
} 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') { } else if (cmdType == 'rollback') {
var t = Std.parseFloat(cmdSplit[1]); var t = Std.parseFloat(cmdSplit[1]);
MarbleGame.instance.world.rollback(t); MarbleGame.instance.world.rollback(t);

View file

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

View file

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

View file

@ -40,6 +40,9 @@ class PathedInterior extends InteriorObject {
public var currentTime:Float; public var currentTime:Float;
public var targetTime:Float; public var targetTime:Float;
var initialPosition:Float;
var initialTargetPosition:Float;
var basePosition:Vector; var basePosition:Vector;
var baseOrientation:Quat; var baseOrientation:Quat;
var baseScale:Vector; var baseScale:Vector;
@ -52,6 +55,12 @@ class PathedInterior extends InteriorObject {
var stopped:Bool = false; var stopped:Bool = false;
var stoppedPosition:Vector; var stoppedPosition:Vector;
var savedPosition:Vector;
var savedVelocity:Vector;
var savedStopped:Bool;
var savedStoppedPosition:Vector;
var savedTime:Float;
var soundChannel:Channel; var soundChannel:Channel;
public static function createFromSimGroup(simGroup:MissionElementSimGroup, level:MarbleWorld, onFinish:PathedInterior->Void) { 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) { public function advance(timeDelta:Float) {
if (stopped) if (stopped)
return; return;
@ -213,6 +249,25 @@ class PathedInterior extends InteriorObject {
this.stoppedPosition = this.position.clone(); 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() { function computeDuration() {
var total = 0.0; var total = 0.0;
for (i in 0...(markerData.length - 1)) { for (i in 0...(markerData.length - 1)) {
@ -311,9 +366,12 @@ class PathedInterior extends InteriorObject {
override function reset() { override function reset() {
this.currentTime = 0; this.currentTime = 0;
this.targetTime = 0; this.targetTime = 0;
this.initialPosition = 0;
this.initialTargetPosition = 0;
if (this.element.initialposition != "") { if (this.element.initialposition != "") {
this.currentTime = MisParser.parseNumber(this.element.initialposition) / 1000; this.currentTime = MisParser.parseNumber(this.element.initialposition) / 1000;
initialPosition = this.currentTime;
} }
if (this.element.initialtargetposition != "") { 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. // 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) if (this.targetTime > 0 && this.targetTime < 0.05)
this.currentTime = this.duration; this.currentTime = this.duration;
initialTargetPosition = this.targetTime;
} }
this.stopped = false; this.stopped = false;

View file

@ -1,44 +1,136 @@
package src; package src;
import net.Net;
import src.MarbleGame;
import h3d.Vector; import h3d.Vector;
import hxd.res.DefaultFont; import hxd.res.DefaultFont;
import h2d.Text; import h2d.Text;
class ProfilerUI { class ProfilerUI {
var fpsCounter:Text; var fpsCounter:Text;
var networkStats:Text;
var debugProfiler:h3d.impl.Benchmark; var debugProfiler:h3d.impl.Benchmark;
var s2d:h2d.Scene;
public var fps:Float; public var fps:Float;
public static var instance:ProfilerUI; public static var instance:ProfilerUI;
static var enabled:Bool = false;
static var mode:Int = 0;
public function new(s2d:h2d.Scene) { public function new(s2d:h2d.Scene) {
if (instance != null) if (instance != null)
return; return;
instance = this; instance = this;
// debugProfiler = new h3d.impl.Benchmark(s2d); this.s2d = s2d;
// debugProfiler.y = 40;
// fpsCounter = new Text(DefaultFont.get(), s2d);
// fpsCounter.y = 80;
// fpsCounter.color = new Vector(1, 1, 1, 1);
} }
public static function begin() { public static function begin() {
// instance.debugProfiler.begin(); if (!enabled)
return;
// if (type == mode)
instance.debugProfiler.begin();
} }
public static function measure(name:String) { public static function measure(name:String) {
// instance.debugProfiler.measure(name); if (!enabled)
return;
// if (type == mode)
instance.debugProfiler.measure(name);
} }
public static function end() { public static function end() {
// instance.debugProfiler.end(); if (!enabled)
return;
// if (type == mode)
instance.debugProfiler.end();
} }
public static function update(fps:Float) { public static function update(fps:Float) {
instance.fps = fps; 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.position = new Vector(255, 514);
searchBtn.extent = new Vector(44, 44); searchBtn.extent = new Vector(44, 44);
searchBtn.pressedAction = (e) -> { searchBtn.pressedAction = (e) -> {
MarbleGame.canvas.pushDialog(new MPSearchGui(false)); MarbleGame.canvas.pushDialog(new MPSearchGui(currentCategory == "custom"));
} }
if (Net.isHost) if (Net.isHost)
window.addChild(searchBtn); window.addChild(searchBtn);

View file

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