From 17e77c709669dcc84049133e26d8c88721ab415c Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Tue, 27 Feb 2024 22:47:08 +0530 Subject: [PATCH] get the powerup states network a bit better with compression --- src/Marble.hx | 115 +++++++++++++++++++++---------- src/MarbleWorld.hx | 18 ++--- src/net/MarblePredictionStore.hx | 6 +- src/net/MarbleUpdateQueue.hx | 60 +++++++++++----- src/net/NetPacket.hx | 15 ++-- 5 files changed, 144 insertions(+), 70 deletions(-) diff --git a/src/Marble.hx b/src/Marble.hx index b23635c7..de22fce9 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -303,6 +303,7 @@ class Marble extends GameObject { var lastMove:Move; var isNetUpdate:Bool = false; var netFlags:Int = 0; + var serverTicks:Int; public function new() { super(); @@ -564,13 +565,14 @@ class Marble extends GameObject { } } - function getExternalForces(currentTime:Float, m:Move, dt:Float, tick:Int) { + function getExternalForces(timeState:TimeState, m:Move) { if (this.mode == Finish) return this.velocity.multiply(-16); var gWorkGravityDir = this.currentUp.multiply(-1); var A = new Vector(); A = gWorkGravityDir.multiply(this._gravity); - if (currentTime - this.helicopterEnableTime < 5 || (helicopterUseTick > 0 && (tick - helicopterUseTick) <= 156)) { + var helicopter = isHelicopterEnabled(timeState); + if (helicopter) { A = A.multiply(0.25); } if (this.level != null) { @@ -581,7 +583,7 @@ class Marble extends GameObject { } for (marble in level.marbles) { if (marble != cast this) { - var force = marble.getForce(this.collider.transform.getPosition(), tick); + var force = marble.getForce(this.collider.transform.getPosition(), timeState.ticks); A = A.add(force.multiply(1 / mass)); } } @@ -617,7 +619,7 @@ class Marble extends GameObject { if (dot > 0) a -= dot; - A.load(A.add(contactNormal.multiply(a / dt))); + A.load(A.add(contactNormal.multiply(a / timeState.dt))); } } } @@ -627,7 +629,7 @@ class Marble extends GameObject { var motionDir = axes[1]; var upDir = axes[2]; var airAccel = this._airAccel; - if (currentTime - this.helicopterEnableTime < 5 || (helicopterUseTick > 0 && (tick - helicopterUseTick) <= 156)) { + if (helicopter) { airAccel *= 2; } A.load(A.add(sideDir.multiply(m.d.x).add(motionDir.multiply(m.d.y)).multiply(airAccel))); @@ -1479,6 +1481,12 @@ class Marble extends GameObject { lastMove = m; } + if (this.blastTicks < (30000 >> 5)) + this.blastTicks += 1; + + if (Net.isClient) + this.serverTicks++; + _bounceYet = false; var contactTime = 0.0; @@ -1533,7 +1541,7 @@ class Marble extends GameObject { var isCentered = this.computeMoveForces(m, aControl, desiredOmega); stoppedPaths = this.velocityCancel(timeState.currentAttemptTime, timeStep, isCentered, false, stoppedPaths, pathedInteriors); - var A = this.getExternalForces(timeState.currentAttemptTime, m, timeStep, timeState.ticks); + var A = this.getExternalForces(tempState, m); var a = this.applyContactForces(timeStep, m, isCentered, aControl, desiredOmega, A); this.velocity.set(this.velocity.x + A.x * timeStep, this.velocity.y + A.y * timeStep, this.velocity.z + A.z * timeStep); this.omega.set(this.omega.x + a.x * timeStep, this.omega.y + a.y * timeStep, this.omega.z + a.z * timeStep); @@ -1655,6 +1663,34 @@ class Marble extends GameObject { } this.updateRollSound(timeState, contactTime / timeState.dt, this._slipAmount); + + if (this.megaMarbleUseTick > 0) { + if (Net.isHost) { + if ((timeState.ticks - this.megaMarbleUseTick) < 312) { + this._radius = 0.675; + this.collider.radius = 0.675; + } else if ((timeState.ticks - this.megaMarbleUseTick) > 312) { + this.collider.radius = this._radius = 0.3; + if (!this.isNetUpdate && this.controllable) + AudioManager.playSound(ResourceLoader.getResource("data/sound/MegaShrink.wav", ResourceLoader.getAudio, this.soundResources), null, + false); + this.megaMarbleUseTick = 0; + this.netFlags |= MarbleNetFlags.DoMega; + } + } + if (Net.isClient) { + if (this.serverTicks - this.megaMarbleUseTick < 312) { + this._radius = 0.675; + this.collider.radius = 0.675; + } else { + this.collider.radius = this._radius = 0.3; + if (!this.isNetUpdate && this.controllable) + AudioManager.playSound(ResourceLoader.getResource("data/sound/MegaShrink.wav", ResourceLoader.getAudio, this.soundResources), null, + false); + this.megaMarbleUseTick = 0; + } + } + } } // MP Only Functions @@ -1675,7 +1711,7 @@ class Marble extends GameObject { marbleUpdate.heliTick = this.helicopterUseTick; marbleUpdate.megaTick = this.megaMarbleUseTick; marbleUpdate.oob = this.outOfBounds; - marbleUpdate.powerUpId = this.heldPowerup != null ? this.heldPowerup.netIndex : 0xFFFF; + marbleUpdate.powerUpId = this.heldPowerup != null ? this.heldPowerup.netIndex : 0x1FF; marbleUpdate.netFlags = this.netFlags; this.netFlags = 0; marbleUpdate.serialize(b); @@ -1691,6 +1727,7 @@ class Marble extends GameObject { // return false; // } // } + this.serverTicks = p.serverTicks; this.oldPos = this.newPos; this.newPos = p.position; this.collider.transform.setPosition(p.position); @@ -1702,7 +1739,7 @@ class Marble extends GameObject { this.megaMarbleUseTick = p.megaTick; this.outOfBounds = p.oob; this.camera.oob = p.oob; - if (p.powerUpId == 0xFFFF) { + if (p.powerUpId == 0x1FF) { this.level.deselectPowerUp(cast this); } else { this.level.pickUpPowerUp(cast this, this.level.powerUps[p.powerUpId]); @@ -1758,25 +1795,10 @@ class Marble extends GameObject { move = new NetMove(innerMove, axis, timeState, 65535); } - if (this.blastTicks < (30000 >> 5)) - this.blastTicks += 1; - playedSounds = []; advancePhysics(timeState, move.move, collisionWorld, pathedInteriors); physicsAccumulator = 0; - if (this.megaMarbleUseTick > 0) { - if ((this.level.timeState.ticks - this.megaMarbleUseTick) < 312) { - this._radius = 0.675; - this.collider.radius = 0.675; - } else if ((this.level.timeState.ticks - this.megaMarbleUseTick) > 312) { - this.collider.radius = this._radius = 0.3; - if (!this.isNetUpdate && this.controllable) - AudioManager.playSound(ResourceLoader.getResource("data/sound/MegaShrink.wav", ResourceLoader.getAudio, this.soundResources), null, false); - this.megaMarbleUseTick = 0; - } - } - if (move.move.jump && this.outOfBounds) { this.level.cancel(this.oobSchedule); this.level.restart(cast this); @@ -1814,9 +1836,9 @@ class Marble extends GameObject { this.camera.update(timeState.currentAttemptTime, timeState.dt); } - updatePowerupStates(timeState.currentAttemptTime, timeState.dt); + updatePowerupStates(timeState); - if ((this.megaMarbleUseTick > 0 && (this.level.timeState.ticks - this.megaMarbleUseTick) < 312)) { + if (isMegaMarbleEnabled(timeState)) { this._marbleScale = this._defaultScale * 2.25; } else { this._marbleScale = this._defaultScale; @@ -1839,7 +1861,7 @@ class Marble extends GameObject { this.updateFinishAnimation(timeState.dt); if (this.mode == Finish) { this.setPosition(this.finishAnimPosition.x, this.finishAnimPosition.y, this.finishAnimPosition.z); - updatePowerupStates(timeState.currentAttemptTime, timeState.dt); + updatePowerupStates(timeState); } this.trailEmitter(); @@ -1971,7 +1993,7 @@ class Marble extends GameObject { this.camera.update(timeState.currentAttemptTime, timeState.dt); } - updatePowerupStates(timeState.currentAttemptTime, timeState.dt); + updatePowerupStates(timeState); var s = this._renderScale * this._renderScale; if (s <= this._marbleScale * this._marbleScale) @@ -2006,7 +2028,7 @@ class Marble extends GameObject { this.updateFinishAnimation(timeState.dt); if (this.mode == Finish) { this.setPosition(this.finishAnimPosition.x, this.finishAnimPosition.y, this.finishAnimPosition.z); - updatePowerupStates(timeState.currentAttemptTime, timeState.dt); + updatePowerupStates(timeState); } this.trailEmitter(); @@ -2093,13 +2115,12 @@ class Marble extends GameObject { } } - public function updatePowerupStates(currentTime:Float, dt:Float) { + public function updatePowerupStates(timeState:TimeState) { if (!this.controllable && this.connection == null) return; - if (currentTime - this.helicopterEnableTime < 5 - || (helicopterUseTick > 0 && (this.level.timeState.ticks - helicopterUseTick) <= 156)) { + if (isHelicopterEnabled(timeState)) { this.helicopter.setPosition(x, y, z); - this.helicopter.setRotationQuat(this.level.getOrientationQuat(currentTime)); + this.helicopter.setRotationQuat(this.level.getOrientationQuat(timeState.currentAttemptTime)); this.helicopterSound.pause = false; this.helicopter.setScale(this._renderScale); } else { @@ -2107,13 +2128,13 @@ class Marble extends GameObject { this.helicopterSound.pause = true; } - if (this.blastUseTime > currentTime) { + if (this.blastUseTime > timeState.currentAttemptTime) { this.blastUseTime = Math.POSITIVE_INFINITY; this.blastWave.doSequenceOnceBeginTime = 0; } - if (currentTime - this.blastUseTime < this.blastWave.dts.sequences[0].duration) { + if (timeState.currentAttemptTime - this.blastUseTime < this.blastWave.dts.sequences[0].duration) { this.blastWave.setPosition(x, y, z); - this.blastWave.setRotationQuat(this.level.getOrientationQuat(this.level.timeState.currentAttemptTime)); + this.blastWave.setRotationQuat(this.level.getOrientationQuat(timeState.currentAttemptTime)); this.blastWave.setScale(this._renderScale); } else { this.blastWave.setPosition(1e8, 1e8, 1e8); @@ -2204,6 +2225,30 @@ class Marble extends GameObject { this.helicopterEnableTime = timeState.currentAttemptTime; } + inline function isHelicopterEnabled(timeState:TimeState) { + if (!this.level.isMultiplayer) { + return timeState.currentAttemptTime - this.helicopterEnableTime < 5; + } else { + if (Net.isHost) { + return (helicopterUseTick > 0 && (this.level.timeState.ticks - helicopterUseTick) <= 156); + } else { + return (helicopterUseTick > 0 && (serverTicks - helicopterUseTick) <= 156); + } + } + } + + inline function isMegaMarbleEnabled(timeState:TimeState) { + if (!this.level.isMultiplayer) { + return timeState.currentAttemptTime - this.megaMarbleEnableTime < 10; + } else { + if (Net.isHost) { + return (megaMarbleUseTick > 0 && (this.level.timeState.ticks - megaMarbleUseTick) <= 312); + } else { + return (megaMarbleUseTick > 0 && (serverTicks - megaMarbleUseTick) <= 312); + } + } + } + public function enableMegaMarble(timeState:TimeState) { if (this.level.isMultiplayer) { this.megaMarbleUseTick = timeState.ticks; diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 97d9e584..b7c0be73 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -1063,10 +1063,10 @@ class MarbleWorld extends Scheduler { lastMoves.ourMoveApplied = true; for (client => arr in lastMoves.otherMarbleUpdates) { var lastMove = null; - while (arr.length > 0) { - var p = arr[0]; + while (arr.packets.length > 0) { + var p = arr.packets[0]; if (p.serverTicks <= ourMove.serverTicks) { - lastMove = arr.shift(); + lastMove = arr.packets.shift(); } else { break; } @@ -1085,7 +1085,7 @@ class MarbleWorld extends Scheduler { trace('Desync for tick ${ourMoveStruct.timeState.ticks}'); clientMarbles[Net.clientIdMap[client]].unpackUpdate(lastMove); needsPrediction |= 1 << client; - arr.insert(0, lastMove); + arr.packets.insert(0, lastMove); predictions.clearStatesAfterTick(clientMarbles[Net.clientIdMap[client]], ourMoveStruct.timeState.ticks); } } else { @@ -1093,7 +1093,7 @@ class MarbleWorld extends Scheduler { trace('Desync for tick ${ourMoveStruct.timeState.ticks}'); clientMarbles[Net.clientIdMap[client]].unpackUpdate(lastMove); needsPrediction |= 1 << client; - arr.insert(0, lastMove); + arr.packets.insert(0, lastMove); predictions.clearStatesAfterTick(clientMarbles[Net.clientIdMap[client]], ourMoveStruct.timeState.ticks); } } else { @@ -1101,7 +1101,7 @@ class MarbleWorld extends Scheduler { trace('Desync in General'); clientMarbles[Net.clientIdMap[client]].unpackUpdate(lastMove); needsPrediction |= 1 << client; - arr.insert(0, lastMove); + arr.packets.insert(0, lastMove); // predictions.clearStatesAfterTick(clientMarbles[Net.clientIdMap[client]], ourMoveStruct.timeState.ticks); } } @@ -1175,8 +1175,8 @@ class MarbleWorld extends Scheduler { var marblesToTick = new Map(); for (client => arr in lastMoves.otherMarbleUpdates) { - if (marbleNeedsPrediction & (1 << client) > 0 && arr.length > 0) { - var m = arr[0]; + if (marbleNeedsPrediction & (1 << client) > 0 && arr.packets.length > 0) { + var m = arr.packets[0]; // if (m.serverTicks == ourLastMoveTime) { var marbleToUpdate = clientMarbles[Net.clientIdMap[client]]; Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius); @@ -1189,7 +1189,7 @@ class MarbleWorld extends Scheduler { // - Std.int((@:privateAccess Net.clientConnection.moveManager.ackRTT - ourLastMove.moveQueueSize) / 2); marblesToTick.set(client, m); - arr.shift(); + arr.packets.shift(); // } } } diff --git a/src/net/MarblePredictionStore.hx b/src/net/MarblePredictionStore.hx index f958319c..3add76c2 100644 --- a/src/net/MarblePredictionStore.hx +++ b/src/net/MarblePredictionStore.hx @@ -14,7 +14,6 @@ class MarblePrediction { var omega:Vector; var isControl:Bool; var blastAmount:Int; - var powerupItemId:Int; public function new(marble:Marble, tick:Int) { this.tick = tick; @@ -23,14 +22,15 @@ class MarblePrediction { omega = @:privateAccess marble.omega.clone(); blastAmount = @:privateAccess marble.blastTicks; isControl = @:privateAccess marble.controllable; - powerupItemId = marble.heldPowerup != null ? marble.heldPowerup.netIndex : 0xFFFF; } public inline function getError(p:MarbleUpdatePacket) { // Just doing position errors is enough to make it work var subs = position.sub(p.position).lengthSq(); // + velocity.sub(p.velocity).lengthSq() + omega.sub(p.omega).lengthSq(); - if (p.powerUpId != powerupItemId) + if (p.netFlags != 0) subs += 1; + // if (p.powerUpId != powerupItemId) + // subs += 1; // if (isControl) // subs += Math.abs(blastAmount - p.blastAmount); return subs; diff --git a/src/net/MarbleUpdateQueue.hx b/src/net/MarbleUpdateQueue.hx index d876f862..9139f7df 100644 --- a/src/net/MarbleUpdateQueue.hx +++ b/src/net/MarbleUpdateQueue.hx @@ -1,12 +1,24 @@ package net; +import hl.I64; import net.NetPacket.MarbleNetFlags; import net.NetPacket.MarbleUpdatePacket; import net.Net; +@:publicFields +class OtherMarbleUpdate { + var packets:Array = []; + var lastBlastTick:Int; + var lastHeliTick:Int; + var lastMegaTick:Int; + var lastPowerUpId:Int; + + public function new() {} +} + @:publicFields class MarbleUpdateQueue { - var otherMarbleUpdates:Map> = []; + var otherMarbleUpdates:Map = []; var myMarbleUpdate:MarbleUpdatePacket; var ourMoveApplied:Bool = false; @@ -18,23 +30,39 @@ class MarbleUpdateQueue { if (myMarbleUpdate != null && update.serverTicks > myMarbleUpdate.serverTicks) ourMoveApplied = true; if (otherMarbleUpdates.exists(cc)) { - var ourList = otherMarbleUpdates[cc]; - if (ourList.length != 0) { - var lastOne = ourList[ourList.length - 1]; - - // Copy the netflagg'd fields - if (update.netFlags & MarbleNetFlags.DoBlast == 0) - update.blastTick = lastOne.blastTick; - if (update.netFlags & MarbleNetFlags.DoHelicopter == 0) - update.heliTick = lastOne.heliTick; - if (update.netFlags & MarbleNetFlags.DoMega == 0) - update.megaTick = lastOne.megaTick; - if (update.netFlags & MarbleNetFlags.PickupPowerup == 0) - update.powerUpId = lastOne.powerUpId; - } + var otherUpdate = otherMarbleUpdates[cc]; + var ourList = otherUpdate.packets; + // Copy the netflagg'd fields + if (update.netFlags & MarbleNetFlags.DoBlast == 0) + update.blastTick = otherUpdate.lastBlastTick; + else + otherUpdate.lastBlastTick = update.blastTick; + if (update.netFlags & MarbleNetFlags.DoHelicopter == 0) + update.heliTick = otherUpdate.lastHeliTick; + else + otherUpdate.lastHeliTick = update.heliTick; + if (update.netFlags & MarbleNetFlags.DoMega == 0) + update.megaTick = otherUpdate.lastMegaTick; + else + otherUpdate.lastMegaTick = update.megaTick; + if (update.netFlags & MarbleNetFlags.PickupPowerup == 0) + update.powerUpId = otherUpdate.lastPowerUpId; + else + otherUpdate.lastPowerUpId = update.powerUpId; ourList.push(update); } else { - otherMarbleUpdates[cc] = [update]; + var otherUpdate = new OtherMarbleUpdate(); + otherUpdate.packets.push(update); + // Copy the netflagg'd fields + if (update.netFlags & MarbleNetFlags.DoBlast != 0) + otherUpdate.lastBlastTick = update.blastTick; + if (update.netFlags & MarbleNetFlags.DoHelicopter != 0) + otherUpdate.lastHeliTick = update.heliTick; + if (update.netFlags & MarbleNetFlags.DoMega != 0) + otherUpdate.lastMegaTick = update.megaTick; + if (update.netFlags & MarbleNetFlags.PickupPowerup != 0) + otherUpdate.lastPowerUpId = update.powerUpId; + otherMarbleUpdates[cc] = otherUpdate; } } else { if (myMarbleUpdate == null || update.serverTicks > myMarbleUpdate.serverTicks) { diff --git a/src/net/NetPacket.hx b/src/net/NetPacket.hx index f5dd2941..7cfff9e7 100644 --- a/src/net/NetPacket.hx +++ b/src/net/NetPacket.hx @@ -32,11 +32,11 @@ class MarbleMovePacket implements NetPacket { } enum abstract MarbleNetFlags(Int) from Int to Int { - var NullFlag; - var DoBlast; - var DoHelicopter; - var DoMega; - var PickupPowerup; + var NullFlag = 0; + var DoBlast = 1 << 0; + var DoHelicopter = 1 << 1; + var DoMega = 1 << 2; + var PickupPowerup = 1 << 3; } @:publicFields @@ -63,7 +63,7 @@ class MarbleUpdatePacket implements NetPacket { b.writeByte(clientId); MoveManager.packMove(move, b); b.writeUInt16(serverTicks); - b.writeInt(moveQueueSize, 6); + b.writeByte(moveQueueSize); b.writeFloat(position.x); b.writeFloat(position.y); b.writeFloat(position.z); @@ -105,7 +105,7 @@ class MarbleUpdatePacket implements NetPacket { clientId = b.readByte(); move = MoveManager.unpackMove(b); serverTicks = b.readUInt16(); - moveQueueSize = b.readInt(6); + moveQueueSize = b.readByte(); position = new Vector(b.readFloat(), b.readFloat(), b.readFloat()); velocity = new Vector(b.readFloat(), b.readFloat(), b.readFloat()); omega = new Vector(b.readFloat(), b.readFloat(), b.readFloat()); @@ -126,6 +126,7 @@ class MarbleUpdatePacket implements NetPacket { oob = b.readFlag(); if (b.readFlag()) { powerUpId = b.readInt(9); + trace('pickup: ${powerUpId}'); this.netFlags |= MarbleNetFlags.PickupPowerup; } }