diff --git a/src/Marble.hx b/src/Marble.hx index 13734670..b23635c7 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -1,5 +1,6 @@ package src; +import net.NetPacket.MarbleNetFlags; import net.BitStream.OutputBitStream; import net.ClientConnection; import net.ClientConnection.GameConnection; @@ -301,6 +302,7 @@ class Marble extends GameObject { var moveMotionDir:Vector; var lastMove:Move; var isNetUpdate:Bool = false; + var netFlags:Int = 0; public function new() { super(); @@ -1611,6 +1613,8 @@ class Marble extends GameObject { pTime.currentAttemptTime = passedTime; this.heldPowerup.use(cast this, pTime); this.heldPowerup = null; + if (!this.isNetUpdate) + this.netFlags |= MarbleNetFlags.PickupPowerup; if (this.level.isRecording) { this.level.replay.recordPowerupPickup(null); } @@ -1672,6 +1676,8 @@ class Marble extends GameObject { marbleUpdate.megaTick = this.megaMarbleUseTick; marbleUpdate.oob = this.outOfBounds; marbleUpdate.powerUpId = this.heldPowerup != null ? this.heldPowerup.netIndex : 0xFFFF; + marbleUpdate.netFlags = this.netFlags; + this.netFlags = 0; marbleUpdate.serialize(b); return b.getBytes(); } @@ -1701,6 +1707,7 @@ class Marble extends GameObject { } else { this.level.pickUpPowerUp(cast this, this.level.powerUps[p.powerUpId]); } + if (this.controllable && Net.isClient) { // We are client, need to do something about the queue var mm = Net.clientConnection.moveManager; @@ -2129,14 +2136,18 @@ class Marble extends GameObject { if (this.blastTicks < (7500 >> 5)) return false; this.blastUseTick = timeState.ticks; + if (!this.isNetUpdate) + this.netFlags |= MarbleNetFlags.DoBlast; var amount = this.blastTicks / (30000 >> 5); this.blastPerc = amount; var impulse = this.currentUp.multiply(amount * 8); this.applyImpulse(impulse); if (this.controllable) AudioManager.playSound(ResourceLoader.getResource('data/sound/use_blast.wav', ResourceLoader.getAudio, this.soundResources)); - this.blastWave.doSequenceOnceBeginTime = this.level.timeState.timeSinceLoad; - this.blastUseTime = this.level.timeState.currentAttemptTime; + if (!this.isNetUpdate) { + this.blastWave.doSequenceOnceBeginTime = this.level.timeState.timeSinceLoad; + this.blastUseTime = this.level.timeState.currentAttemptTime; + } this.blastTicks = 0; return true; } else { @@ -2185,16 +2196,20 @@ class Marble extends GameObject { } public function enableHelicopter(timeState:TimeState) { - if (this.level.isMultiplayer) + if (this.level.isMultiplayer) { this.helicopterUseTick = timeState.ticks; - else + if (!this.isNetUpdate) + this.netFlags |= MarbleNetFlags.DoHelicopter; + } else this.helicopterEnableTime = timeState.currentAttemptTime; } public function enableMegaMarble(timeState:TimeState) { - if (this.level.isMultiplayer) + if (this.level.isMultiplayer) { this.megaMarbleUseTick = timeState.ticks; - else + if (!this.isNetUpdate) + this.netFlags |= MarbleNetFlags.DoMega; + } else this.megaMarbleEnableTime = timeState.currentAttemptTime; } @@ -2223,6 +2238,7 @@ class Marble extends GameObject { this.blastTicks = 0; this.helicopterUseTick = 0; this.megaMarbleUseTick = 0; + this.netFlags = MarbleNetFlags.DoBlast | MarbleNetFlags.DoMega | MarbleNetFlags.DoHelicopter | MarbleNetFlags.PickupPowerup; this.lastContactNormal = new Vector(0, 0, 1); this.contactEntities = []; this._firstTick = true; diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index bf4ceca3..97d9e584 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -1,5 +1,6 @@ package src; +import net.NetPacket.MarbleNetFlags; import net.PowerupPredictionStore; import net.MarblePredictionStore; import net.MarblePredictionStore.MarblePrediction; @@ -1973,6 +1974,8 @@ class MarbleWorld extends Scheduler { return false; Console.log("PowerUp pickup: " + powerUp.identifier); marble.heldPowerup = powerUp; + if (@:privateAccess !marble.isNetUpdate) + @:privateAccess marble.netFlags |= MarbleNetFlags.PickupPowerup; if (this.marble == marble) { this.playGui.setPowerupImage(powerUp.identifier); MarbleGame.instance.touchInput.powerupButton.setEnabled(true); @@ -1985,6 +1988,7 @@ class MarbleWorld extends Scheduler { public function deselectPowerUp(marble:Marble) { marble.heldPowerup = null; + @:privateAccess marble.netFlags |= MarbleNetFlags.PickupPowerup; if (this.marble == marble) { this.playGui.setPowerupImage(""); MarbleGame.instance.touchInput.powerupButton.setEnabled(false); diff --git a/src/net/BitStream.hx b/src/net/BitStream.hx index ddace257..15da901e 100644 --- a/src/net/BitStream.hx +++ b/src/net/BitStream.hx @@ -49,7 +49,7 @@ class InputBitStream { } public function readFlag() { - return readInt(1); + return readInt(1) != 0; } public function readByte() { @@ -99,6 +99,7 @@ class OutputBitStream { this.shift = extra; } else { lastByte |= (value << this.shift) & (0xFF >> (8 - bits - this.shift)); + this.shift += bits; } } @@ -110,8 +111,8 @@ class OutputBitStream { } } - public function writeFlag(value:Int) { - writeInt(value, 1); + public function writeFlag(value:Bool) { + writeInt(value ? 1 : 0, 1); } public function writeByte(value:Int) { diff --git a/src/net/MarbleUpdateQueue.hx b/src/net/MarbleUpdateQueue.hx index ed8a1131..d876f862 100644 --- a/src/net/MarbleUpdateQueue.hx +++ b/src/net/MarbleUpdateQueue.hx @@ -1,5 +1,6 @@ package net; +import net.NetPacket.MarbleNetFlags; import net.NetPacket.MarbleUpdatePacket; import net.Net; @@ -17,12 +18,37 @@ class MarbleUpdateQueue { if (myMarbleUpdate != null && update.serverTicks > myMarbleUpdate.serverTicks) ourMoveApplied = true; if (otherMarbleUpdates.exists(cc)) { - otherMarbleUpdates[cc].push(update); + 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; + } + ourList.push(update); } else { otherMarbleUpdates[cc] = [update]; } } else { if (myMarbleUpdate == null || update.serverTicks > myMarbleUpdate.serverTicks) { + if (myMarbleUpdate != null) { + // Copy the netflagg'd fields + if (update.netFlags & MarbleNetFlags.DoBlast == 0) + update.blastTick = myMarbleUpdate.blastTick; + if (update.netFlags & MarbleNetFlags.DoHelicopter == 0) + update.heliTick = myMarbleUpdate.heliTick; + if (update.netFlags & MarbleNetFlags.DoMega == 0) + update.megaTick = myMarbleUpdate.megaTick; + if (update.netFlags & MarbleNetFlags.PickupPowerup == 0) + update.powerUpId = myMarbleUpdate.powerUpId; + } myMarbleUpdate = update; ourMoveApplied = false; } diff --git a/src/net/MoveManager.hx b/src/net/MoveManager.hx index c4ca7212..3c390f51 100644 --- a/src/net/MoveManager.hx +++ b/src/net/MoveManager.hx @@ -117,14 +117,9 @@ class MoveManager { b.writeUInt16(m.id); b.writeByte(Std.int((m.move.d.x * 16) + 16)); b.writeByte(Std.int((m.move.d.y * 16) + 16)); - var flags = 0; - if (m.move.jump) - flags |= 1; - if (m.move.powerup) - flags |= 2; - if (m.move.blast) - flags |= 4; - b.writeByte(flags); + b.writeFlag(m.move.jump); + b.writeFlag(m.move.powerup); + b.writeFlag(m.move.blast); b.writeFloat(m.motionDir.x); b.writeFloat(m.motionDir.y); b.writeFloat(m.motionDir.z); @@ -137,10 +132,9 @@ class MoveManager { move.d = new Vector(); move.d.x = (b.readByte() - 16) / 16.0; move.d.y = (b.readByte() - 16) / 16.0; - var flags = b.readByte(); - move.jump = (flags & 1) != 0; - move.powerup = (flags & 2) != 0; - move.blast = (flags & 4) != 0; + move.jump = b.readFlag(); + move.powerup = b.readFlag(); + move.blast = b.readFlag(); var motionDir = new Vector(); motionDir.x = b.readFloat(); motionDir.y = b.readFloat(); diff --git a/src/net/Net.hx b/src/net/Net.hx index 7a7e9a94..0379a37f 100644 --- a/src/net/Net.hx +++ b/src/net/Net.hx @@ -161,9 +161,9 @@ class Net { dc.onMessage = (msgBytes) -> { onPacketReceived(c, dc, new InputBitStream(msgBytes)); } - var b = haxe.io.Bytes.alloc(3); + var b = haxe.io.Bytes.alloc(2); b.set(0, ClientIdAssign); - b.setUInt16(1, clientId); + b.set(1, clientId); dc.sendBytes(b); Console.log("Client has connected!"); // Send the ping packet to calculcate the RTT @@ -205,7 +205,7 @@ class Net { NetCommands.readPacket(input); case ClientIdAssign: - clientId = input.readUInt16(); + clientId = input.readByte(); // 8 bit client id, hopefully we don't exceed this Console.log('Client ID set to ${clientId}'); case Ping: diff --git a/src/net/NetPacket.hx b/src/net/NetPacket.hx index 17d84b05..f5dd2941 100644 --- a/src/net/NetPacket.hx +++ b/src/net/NetPacket.hx @@ -19,18 +19,26 @@ class MarbleMovePacket implements NetPacket { public function new() {} public inline function deserialize(b:InputBitStream) { - clientId = b.readUInt16(); + clientId = b.readByte(); clientTicks = b.readUInt16(); move = MoveManager.unpackMove(b); } public inline function serialize(b:OutputBitStream) { - b.writeUInt16(clientId); + b.writeByte(clientId); b.writeUInt16(clientTicks); MoveManager.packMove(move, b); } } +enum abstract MarbleNetFlags(Int) from Int to Int { + var NullFlag; + var DoBlast; + var DoHelicopter; + var DoMega; + var PickupPowerup; +} + @:publicFields class MarbleUpdatePacket implements NetPacket { var clientId:Int; @@ -47,14 +55,15 @@ class MarbleUpdatePacket implements NetPacket { var oob:Bool; var powerUpId:Int; var moveQueueSize:Int; + var netFlags:Int; public function new() {} public inline function serialize(b:OutputBitStream) { - b.writeUInt16(clientId); + b.writeByte(clientId); MoveManager.packMove(move, b); b.writeUInt16(serverTicks); - b.writeByte(moveQueueSize); + b.writeInt(moveQueueSize, 6); b.writeFloat(position.x); b.writeFloat(position.y); b.writeFloat(position.z); @@ -64,28 +73,61 @@ class MarbleUpdatePacket implements NetPacket { b.writeFloat(omega.x); b.writeFloat(omega.y); b.writeFloat(omega.z); - b.writeUInt16(blastAmount); - b.writeUInt16(blastTick); - b.writeUInt16(heliTick); - b.writeUInt16(megaTick); - b.writeByte(oob ? 1 : 0); - b.writeUInt16(powerUpId); + b.writeInt(blastAmount, 11); + if (netFlags & MarbleNetFlags.DoBlast > 0) { + b.writeFlag(true); + b.writeUInt16(blastTick); + } else { + b.writeFlag(false); + } + if (netFlags & MarbleNetFlags.DoHelicopter > 0) { + b.writeFlag(true); + b.writeUInt16(heliTick); + } else { + b.writeFlag(false); + } + if (netFlags & MarbleNetFlags.DoMega > 0) { + b.writeFlag(true); + b.writeUInt16(megaTick); + } else { + b.writeFlag(false); + } + b.writeFlag(oob); + if (netFlags & MarbleNetFlags.PickupPowerup > 0) { + b.writeFlag(true); + b.writeInt(powerUpId, 9); + } else { + b.writeFlag(false); + } } public inline function deserialize(b:InputBitStream) { - clientId = b.readUInt16(); + clientId = b.readByte(); move = MoveManager.unpackMove(b); serverTicks = b.readUInt16(); - moveQueueSize = b.readByte(); + moveQueueSize = b.readInt(6); 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()); - blastAmount = b.readUInt16(); - blastTick = b.readUInt16(); - heliTick = b.readUInt16(); - megaTick = b.readUInt16(); - oob = b.readByte() != 0; - powerUpId = b.readUInt16(); + blastAmount = b.readInt(11); + this.netFlags = 0; + if (b.readFlag()) { + blastTick = b.readUInt16(); + this.netFlags |= MarbleNetFlags.DoBlast; + } + if (b.readFlag()) { + heliTick = b.readUInt16(); + this.netFlags |= MarbleNetFlags.DoHelicopter; + } + if (b.readFlag()) { + megaTick = b.readUInt16(); + this.netFlags |= MarbleNetFlags.DoMega; + } + oob = b.readFlag(); + if (b.readFlag()) { + powerUpId = b.readInt(9); + this.netFlags |= MarbleNetFlags.PickupPowerup; + } } } @@ -98,14 +140,14 @@ class PowerupPickupPacket implements NetPacket { public function new() {} public inline function deserialize(b:InputBitStream) { - clientId = b.readUInt16(); + clientId = b.readByte(); serverTicks = b.readUInt16(); - powerupItemId = b.readUInt16(); + powerupItemId = b.readInt(9); } public inline function serialize(b:OutputBitStream) { - b.writeUInt16(clientId); + b.writeByte(clientId); b.writeUInt16(serverTicks); - b.writeUInt16(powerupItemId); + b.writeInt(powerupItemId, 9); } }