From 3b16113d0265021671079f27223782679b91b91d Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:33:56 +0530 Subject: [PATCH] network helicopter and mega marble properly --- src/Marble.hx | 144 +++++++++++++------------------ src/MarbleWorld.hx | 6 +- src/net/BitStream.hx | 132 ++++++++++++++++++++++++++++ src/net/MarblePredictionStore.hx | 7 +- src/net/Net.hx | 4 +- src/net/NetPacket.hx | 6 ++ src/shapes/Helicopter.hx | 2 +- src/shapes/MegaMarble.hx | 4 +- 8 files changed, 211 insertions(+), 94 deletions(-) create mode 100644 src/net/BitStream.hx diff --git a/src/Marble.hx b/src/Marble.hx index 182278a7..ff1916f9 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -255,14 +255,15 @@ class Marble extends GameObject { var megaMarbleEnableTime:Float = -1e8; var blastUseTime:Float = -1e8; + public var helicopterUseTick:Int = 0; + public var megaMarbleUseTick:Int = 0; + public var blastAmount:Float = 0; public var blastTicks:Int = 0; public var blastUseTick:Int = 0; // blast is 12 ticks long var blastPerc:Float = 0.0; - var teleportEnableTime:Null = null; - var teleportDisableTime:Null = null; var bounceEmitDelay:Float = 0; var bounceEmitterData:ParticleData; @@ -286,8 +287,6 @@ class Marble extends GameObject { public var prevPos:Vector; - var cloak:Bool = false; - var teleporting:Bool = false; var isUltra:Bool = false; var _firstTick = true; @@ -564,7 +563,7 @@ class Marble extends GameObject { var gWorkGravityDir = this.currentUp.multiply(-1); var A = new Vector(); A = gWorkGravityDir.multiply(this._gravity); - if (currentTime - this.helicopterEnableTime < 5) { + if (currentTime - this.helicopterEnableTime < 5 || (helicopterUseTick > 0 && (tick - helicopterUseTick) <= 156)) { A = A.multiply(0.25); } if (this.level != null) { @@ -620,7 +619,7 @@ class Marble extends GameObject { var motionDir = axes[1]; var upDir = axes[2]; var airAccel = this._airAccel; - if (currentTime - this.helicopterEnableTime < 5) { + if (currentTime - this.helicopterEnableTime < 5 || (helicopterUseTick > 0 && (tick - helicopterUseTick) <= 156)) { airAccel *= 2; } A.load(A.add(sideDir.multiply(m.d.x).add(motionDir.multiply(m.d.y)).multiply(airAccel))); @@ -954,17 +953,18 @@ class Marble extends GameObject { if (minVelocityBounceSoft <= contactVel) { var hardBounceSpeed = minVelocityBounceHard; var bounceSoundNum = Math.floor(Math.random() * 4); - var sndList = (time - this.megaMarbleEnableTime < 10) ? [ - "data/sound/mega_bouncehard1.wav", - "data/sound/mega_bouncehard2.wav", - "data/sound/mega_bouncehard3.wav", - "data/sound/mega_bouncehard4.wav" - ] : [ - "data/sound/bouncehard1.wav", - "data/sound/bouncehard2.wav", - "data/sound/bouncehard3.wav", - "data/sound/bouncehard4.wav" - ]; + var sndList = ((time - this.megaMarbleEnableTime < 10) + || (this.megaMarbleUseTick > 0 && (this.level.timeState.ticks - this.megaMarbleUseTick) < 312)) ? [ + "data/sound/mega_bouncehard1.wav", + "data/sound/mega_bouncehard2.wav", + "data/sound/mega_bouncehard3.wav", + "data/sound/mega_bouncehard4.wav" + ] : [ + "data/sound/bouncehard1.wav", + "data/sound/bouncehard2.wav", + "data/sound/bouncehard3.wav", + "data/sound/bouncehard4.wav" + ]; var snd = ResourceLoader.getResource(sndList[bounceSoundNum], ResourceLoader.getAudio, this.soundResources); var gain = bounceMinGain; @@ -1016,7 +1016,8 @@ class Marble extends GameObject { if (slipVolume < 0) slipVolume = 0; - if (time.currentAttemptTime - this.megaMarbleEnableTime < 10) { + if (time.currentAttemptTime - this.megaMarbleEnableTime < 10 + || (this.megaMarbleUseTick > 0 && (this.level.timeState.ticks - this.megaMarbleUseTick) < 312)) { if (this.rollMegaSound != null) { rollMegaSound.volume = rollVolume; rollSound.volume = 0; @@ -1661,6 +1662,8 @@ class Marble extends GameObject { marbleUpdate.moveQueueSize = this.connection != null ? this.connection.moveManager.getQueueSize() : 255; marbleUpdate.blastAmount = this.blastTicks; marbleUpdate.blastTick = this.blastUseTick; + marbleUpdate.heliTick = this.helicopterUseTick; + marbleUpdate.megaTick = this.megaMarbleUseTick; marbleUpdate.serialize(b); return b.getBytes(); } @@ -1681,6 +1684,8 @@ class Marble extends GameObject { this.omega = p.omega; this.blastTicks = p.blastAmount; this.blastUseTick = p.blastTick; + this.helicopterUseTick = p.heliTick; + this.megaMarbleUseTick = p.megaTick; if (this.controllable && Net.isClient) { // We are client, need to do something about the queue var mm = Net.clientConnection.moveManager; @@ -1737,6 +1742,19 @@ class Marble extends GameObject { 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; + } + } + return move; // if (Net.isHost) { // packets.push({b: packUpdate(move, timeState), c: this.connection != null ? this.connection.id : 0}); @@ -1771,6 +1789,12 @@ class Marble extends GameObject { updatePowerupStates(timeState.currentAttemptTime, timeState.dt); + if ((this.megaMarbleUseTick > 0 && (this.level.timeState.ticks - this.megaMarbleUseTick) < 312)) { + this._marbleScale = this._defaultScale * 2.25; + } else { + this._marbleScale = this._defaultScale; + } + var s = this._renderScale * this._renderScale; if (s <= this._marbleScale * this._marbleScale) s = 0.1; @@ -1778,29 +1802,13 @@ class Marble extends GameObject { s = 0.4; s = timeState.dt / s * 2.302585124969482; - s = 1.0 / (s * (s * 0.2349999994039536 * s) + s + 1.0 + 0.4799999892711639 * s * s); + s = 1.0 / (s * (s * 0.235 * s) + s + 1.0 + 0.48 * s * s); this._renderScale *= s; s = 1 - s; this._renderScale += s * this._marbleScale; var marbledts = cast(this.getChildAt(0), DtsObject); marbledts.setScale(this._renderScale); - if (this._radius != 0.675 && timeState.currentAttemptTime - this.megaMarbleEnableTime < 10) { - this._prevRadius = this._radius; - this._radius = 0.675; - this.collider.radius = 0.675; - this._marbleScale *= 2.25; - var boost = this.currentUp.multiply(5); - this.velocity = this.velocity.add(boost); - } else if (timeState.currentAttemptTime - this.megaMarbleEnableTime > 10) { - if (this._radius != this._prevRadius) { - this._radius = this._prevRadius; - this.collider.radius = this._radius; - this._marbleScale = this._defaultScale; - AudioManager.playSound(ResourceLoader.getResource("data/sound/MegaShrink.wav", ResourceLoader.getAudio, this.soundResources), null, false); - } - } - this.updateFinishAnimation(timeState.dt); if (this.mode == Finish) { this.setPosition(this.finishAnimPosition.x, this.finishAnimPosition.y, this.finishAnimPosition.z); @@ -1968,8 +1976,6 @@ class Marble extends GameObject { } } - this.updateTeleporterState(timeState); - this.updateFinishAnimation(timeState.dt); if (this.mode == Finish) { this.setPosition(this.finishAnimPosition.x, this.finishAnimPosition.y, this.finishAnimPosition.z); @@ -2063,7 +2069,8 @@ class Marble extends GameObject { public function updatePowerupStates(currentTime:Float, dt:Float) { if (!this.controllable && this.connection == null) return; - if (currentTime - this.helicopterEnableTime < 5) { + if (currentTime - this.helicopterEnableTime < 5 + || (helicopterUseTick > 0 && (this.level.timeState.ticks - helicopterUseTick) <= 156)) { this.helicopter.setPosition(x, y, z); this.helicopter.setRotationQuat(this.level.getOrientationQuat(currentTime)); this.helicopterSound.pause = false; @@ -2089,7 +2096,8 @@ class Marble extends GameObject { public function getMass() { if (this.level == null) return 1; - if (this.level.timeState.currentAttemptTime - this.megaMarbleEnableTime < 10) { + if (this.level.timeState.currentAttemptTime - this.megaMarbleEnableTime < 10 + || (this.megaMarbleUseTick > 0 && (this.level.timeState.ticks - this.megaMarbleUseTick) < 312)) { return 5; } else { return 1; @@ -2156,46 +2164,18 @@ class Marble extends GameObject { this.appliedImpulses.push({impulse: impulse, contactImpulse: contactImpulse}); } - public function enableHelicopter(time:Float) { - this.helicopterEnableTime = time; + public function enableHelicopter(timeState:TimeState) { + if (this.level.isMultiplayer) + this.helicopterUseTick = timeState.ticks; + else + this.helicopterEnableTime = timeState.currentAttemptTime; } - public function enableMegaMarble(time:Float) { - this.megaMarbleEnableTime = time; - } - - function updateTeleporterState(time:TimeState) { - var teleportFadeCompletion:Float = 0; - - if (this.teleportEnableTime != null) - teleportFadeCompletion = Util.clamp((time.currentAttemptTime - this.teleportEnableTime) / 0.5, 0, 1); - if (this.teleportDisableTime != null) - teleportFadeCompletion = Util.clamp(1 - (time.currentAttemptTime - this.teleportDisableTime) / 0.5, 0, 1); - - if (teleportFadeCompletion > 0) { - var ourDts:DtsObject = cast this.children[0]; - ourDts.setOpacity(Util.lerp(1, 0.25, teleportFadeCompletion)); - this.teleporting = true; - } else { - if (this.teleporting) { - var ourDts:DtsObject = cast this.children[0]; - ourDts.setOpacity(1); - this.teleporting = false; - } - } - } - - public function setCloaking(active:Bool, time:TimeState) { - this.cloak = active; - if (this.cloak) { - var completion = (this.teleportDisableTime != null) ? Util.clamp((time.currentAttemptTime - this.teleportDisableTime) / 0.5, 0, 1) : 1; - this.teleportEnableTime = time.currentAttemptTime - 0.5 * (1 - completion); - this.teleportDisableTime = null; - } else { - var completion = Util.clamp((time.currentAttemptTime - this.teleportEnableTime) / 0.5, 0, 1); - this.teleportDisableTime = time.currentAttemptTime - 0.5 * (1 - completion); - this.teleportEnableTime = null; - } + public function enableMegaMarble(timeState:TimeState) { + if (this.level.isMultiplayer) + this.megaMarbleUseTick = timeState.ticks; + else + this.megaMarbleEnableTime = timeState.currentAttemptTime; } public function setMode(mode:Mode) { @@ -2221,17 +2201,11 @@ class Marble extends GameObject { this.blastUseTime = Math.NEGATIVE_INFINITY; this.blastUseTick = 0; this.blastTicks = 0; + this.helicopterUseTick = 0; + this.megaMarbleUseTick = 0; this.lastContactNormal = new Vector(0, 0, 1); this.contactEntities = []; - this.cloak = false; this._firstTick = true; - if (this.teleporting) { - var ourDts:DtsObject = cast this.children[0]; - ourDts.setOpacity(1); - } - this.teleporting = false; - this.teleportDisableTime = null; - this.teleportEnableTime = null; this.finishAnimTime = 0; this.physicsAccumulator = 0; this.prevRot = this.getRotationQuat().clone(); diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 443a9f8a..86590646 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -1166,10 +1166,12 @@ class MarbleWorld extends Scheduler { // if (m.serverTicks == ourLastMoveTime) { var marbleToUpdate = clientMarbles[Net.clientIdMap[client]]; Debug.drawSphere(@:privateAccess marbleToUpdate.newPos, marbleToUpdate._radius); - if (marbleNeedsPrediction & (1 << Net.clientId) > 0) + + var distFromUs = @:privateAccess marbleToUpdate.newPos.distance(this.marble.newPos); + if (distFromUs < 5) m.calculationTicks = ourQueuedMoves.length; // ourQueuedMoves.length; else - m.calculationTicks = ourQueuedMoves.length; + m.calculationTicks = Std.int(Math.max(1, ourQueuedMoves.length - (distFromUs - 5) / 5)); // - Std.int((@:privateAccess Net.clientConnection.moveManager.ackRTT - ourLastMove.moveQueueSize) / 2); marblesToTick.set(client, m); diff --git a/src/net/BitStream.hx b/src/net/BitStream.hx new file mode 100644 index 00000000..81d170e4 --- /dev/null +++ b/src/net/BitStream.hx @@ -0,0 +1,132 @@ +package net; + +import haxe.io.BytesOutput; +import haxe.io.BytesInput; +import haxe.io.Bytes; + +class InputBitStream { + var data:Bytes; + var position:Int; + var shift:Int; + + public function new(data:Bytes) { + this.data = data; + this.position = 0; + this.shift = 0; + } + + function readBits(bits:Int = 8) { + if (this.shift + bits >= 8) { + var extra = (this.shift + bits) % 8; + var remain = bits - extra; + var first = data.get(position) >> shift; + var result = first; + this.position++; + if (extra > 0) { + var second = (data.get(position) & (0xFF >> (8 - extra))) << remain; + result |= second; + } + this.shift = extra; + return result; + } else { + var result = (data.get(position) >> shift) & (0xFF >> (8 - bits)); + shift += bits; + + return result; + } + } + + public function readInt(bits:Int = 32) { + var value = 0; + var shift = 0; + while (bits > 0) { + value |= readBits(bits < 8 ? bits : 8) << shift; + shift += 8; + bits -= 8; + } + return value; + } + + public function readFlag() { + return readInt(1); + } + + public function readByte() { + return readInt(8); + } + + public function readUInt16() { + return readInt(16); + } + + public function readInt32() { + return readInt(32); + } + + public function readFloat() { + return readInt32(); + } +} + +class OutputBitStream { + var data:BytesOutput; + var position:Int; + var shift:Int; + var lastByte:Int; + + public function new(data:BytesOutput = null) { + this.data = data; + if (this.data == null) + this.data = new BytesOutput(); + this.position = 0; + this.shift = 0; + this.lastByte = 0; + } + + function writeBits(value:Int, bits:Int) { + value = value & (0xFF >> (8 - bits)); + if (this.shift + bits >= 8) { + var extra = (shift + bits) % 8; + var remain = bits - extra; + + var first = value & (0xFF >> (8 - remain)); + lastByte |= first << shift; + + var second = (value >> remain) & (0xFF >> (8 - extra)); + this.data.writeByte(this.lastByte); + this.lastByte = second; + this.shift = extra; + } else { + lastByte |= (value << this.shift) & (0xFF >> (8 - bits - this.shift)); + } + } + + public function writeInt(value:Int, bits:Int = 32) { + while (bits > 0) { + this.writeBits(value & 0xFF, bits < 8 ? bits : 8); + value >>= 8; + bits -= 8; + } + } + + public function writeFlag(value:Int) { + writeInt(value, 1); + } + + public function writeByte(value:Int) { + writeInt(value, 8); + } + + public function writeUInt16(value:Int) { + writeInt(value, 16); + } + + public function writeInt32(value:Int) { + writeInt(value, 32); + } + + public function getBytes() { + this.data.writeByte(this.lastByte); + return this.data.getBytes(); + } +} diff --git a/src/net/MarblePredictionStore.hx b/src/net/MarblePredictionStore.hx index 601e507b..f5df5587 100644 --- a/src/net/MarblePredictionStore.hx +++ b/src/net/MarblePredictionStore.hx @@ -25,9 +25,10 @@ class MarblePrediction { } public inline function getError(p:MarbleUpdatePacket) { - var subs = position.sub(p.position).lengthSq() + velocity.sub(p.velocity).lengthSq() + omega.sub(p.omega).lengthSq(); - if (isControl) - subs += Math.abs(blastAmount - p.blastAmount); + // 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 (isControl) + // subs += Math.abs(blastAmount - p.blastAmount); return subs; } } diff --git a/src/net/Net.hx b/src/net/Net.hx index a88c8d90..e688b200 100644 --- a/src/net/Net.hx +++ b/src/net/Net.hx @@ -50,7 +50,7 @@ class Net { isHost = true; isClient = false; clientId = 0; - masterWs = new WebSocket("ws://192.168.1.2:8080"); + masterWs = new WebSocket("ws://localhost:8080"); masterWs.onmessage = (m) -> { switch (m) { @@ -97,7 +97,7 @@ class Net { } public static function joinServer(connectedCb:() -> Void) { - masterWs = new WebSocket("ws://192.168.1.2:8080"); + masterWs = new WebSocket("ws://localhost:8080"); masterWs.onopen = () -> { client = new RTCPeerConnection(["stun:stun.l.google.com:19302"], "0.0.0.0"); var candidates = []; diff --git a/src/net/NetPacket.hx b/src/net/NetPacket.hx index f33e989a..82220138 100644 --- a/src/net/NetPacket.hx +++ b/src/net/NetPacket.hx @@ -40,6 +40,8 @@ class MarbleUpdatePacket implements NetPacket { var omega:Vector; var blastAmount:Int; var blastTick:Int; + var megaTick:Int; + var heliTick:Int; var moveQueueSize:Int; public function new() {} @@ -60,6 +62,8 @@ class MarbleUpdatePacket implements NetPacket { b.writeFloat(omega.z); b.writeUInt16(blastAmount); b.writeUInt16(blastTick); + b.writeUInt16(heliTick); + b.writeUInt16(megaTick); } public inline function deserialize(b:haxe.io.BytesInput) { @@ -72,5 +76,7 @@ class MarbleUpdatePacket implements NetPacket { omega = new Vector(b.readFloat(), b.readFloat(), b.readFloat()); blastAmount = b.readUInt16(); blastTick = b.readUInt16(); + heliTick = b.readUInt16(); + megaTick = b.readUInt16(); } } diff --git a/src/shapes/Helicopter.hx b/src/shapes/Helicopter.hx index bbd7c19f..6069047b 100644 --- a/src/shapes/Helicopter.hx +++ b/src/shapes/Helicopter.hx @@ -34,7 +34,7 @@ class Helicopter extends PowerUp { } public function use(marble:Marble, timeState:TimeState) { - marble.enableHelicopter(timeState.currentAttemptTime); + marble.enableHelicopter(timeState); this.level.deselectPowerUp(marble); } diff --git a/src/shapes/MegaMarble.hx b/src/shapes/MegaMarble.hx index 79098831..ba329160 100644 --- a/src/shapes/MegaMarble.hx +++ b/src/shapes/MegaMarble.hx @@ -41,7 +41,9 @@ class MegaMarble extends PowerUp { } public function use(marble:Marble, timeState:TimeState) { - marble.enableMegaMarble(timeState.currentAttemptTime); + marble.enableMegaMarble(timeState); + var boost = marble.currentUp.multiply(5); + marble.velocity.load(marble.velocity.add(boost)); this.level.deselectPowerUp(marble); if (this.level.marble == marble && @:privateAccess !marble.isNetUpdate) AudioManager.playSound(ResourceLoader.getResource('data/sound/use_mega.wav', ResourceLoader.getAudio, this.soundResources));