diff --git a/src/Marble.hx b/src/Marble.hx index b7829c21..dca76895 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -721,7 +721,11 @@ class Marble extends GameObject { if (contact.force != 0 && !forceObjects.contains(contact.otherObject)) { if (contact.otherObject is RoundBumper) { if (!level.isReplayingMovement && !playedSounds.contains("data/sound/bumperding1.wav") && !this.isNetUpdate) { - AudioManager.playSound(ResourceLoader.getResource("data/sound/bumperding1.wav", ResourceLoader.getAudio, this.soundResources)); + if (level.marble == cast this) + AudioManager.playSound(ResourceLoader.getResource("data/sound/bumperding1.wav", ResourceLoader.getAudio, this.soundResources)); + else + AudioManager.playSound(ResourceLoader.getResource("data/sound/bumperding1.wav", ResourceLoader.getAudio, this.soundResources), + this.getAbsPos().getPosition()); playedSounds.push("data/sound/bumperding1.wav"); } } @@ -2505,6 +2509,14 @@ class Marble extends GameObject { this.setPosition(x, y, z); } + public inline function getConnectionId() { + if (this.connection == null) { + return Net.isHost ? 0 : Net.clientId; + } else { + return this.connection.id; + } + } + public override function reset() { this.velocity = new Vector(); this.collider.velocity = new Vector(); diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 4cd5348e..9877b34e 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -518,6 +518,13 @@ class MarbleWorld extends Scheduler { NetCommands.clientIsReady(Net.clientId); if (this.isMultiplayer && Net.isHost) { NetCommands.clientIsReady(-1); + + // Sort all the marbles so that they are updated in a deterministic order + this.marbles.sort((a, b) -> @:privateAccess { + var aId = a.connection != null ? a.connection.id : 0; // Must be a host + var bId = b.connection != null ? b.connection.id : 0; // Must be a host + return (aId > bId) ? 1 : (aId < bId) ? -1 : 0; + }); } var cc = 0; for (client in Net.clients) @@ -535,6 +542,13 @@ class MarbleWorld extends Scheduler { this.restart(addedMarble); // spawn it this.playGui.addPlayer(cc.id, cc.getName(), false); this.playGui.redrawPlayerList(); + + // Sort all the marbles so that they are updated in a deterministic order + this.marbles.sort((a, b) -> @:privateAccess { + var aId = a.getConnectionId(); + var bId = b.getConnectionId(); + return (aId > bId) ? 1 : (aId < bId) ? -1 : 0; + }); onAdded(); }); } @@ -545,6 +559,13 @@ class MarbleWorld extends Scheduler { this.restart(addedMarble); // spawn it this.playGui.addPlayer(cc.id, cc.getName(), false); this.playGui.redrawPlayerList(); + + // Sort all the marbles so that they are updated in a deterministic order + this.marbles.sort((a, b) -> @:privateAccess { + var aId = a.getConnectionId(); + var bId = b.getConnectionId(); + return (aId > bId) ? 1 : (aId < bId) ? -1 : 0; + }); onAdded(); }); } @@ -1627,11 +1648,17 @@ class MarbleWorld extends Scheduler { fixedDt.dt = 0.032; tickAccumulator -= 0.032; var packets = []; - var myMove = marble.updateServer(fixedDt, collisionWorld, pathedInteriors); var otherMoves = []; - for (client => marble in clientMarbles) { - otherMoves.push(marble.updateServer(fixedDt, collisionWorld, pathedInteriors)); + var myMove = null; + + for (marble in marbles) { + var move = marble.updateServer(fixedDt, collisionWorld, pathedInteriors); + if (marble == this.marble) + myMove = move; + else + otherMoves.push(move); } + if (myMove != null && Net.isClient) { this.predictions.storeState(marble, myMove.timeState.ticks); for (client => marble in clientMarbles) { @@ -1639,11 +1666,18 @@ class MarbleWorld extends Scheduler { } } if (Net.isHost) { - for (client => othermarble in clientMarbles) { // Oh no! - var mv = otherMoves.shift(); - packets.push(marble.packUpdate(myMove, fixedDt)); - packets.push(othermarble.packUpdate(mv, fixedDt)); + packets.push(marble.packUpdate(myMove, fixedDt)); + for (othermarble in marbles) { + if (othermarble != this.marble) { + var mv = otherMoves.shift(); + packets.push(othermarble.packUpdate(mv, fixedDt)); + } } + // for (client => othermarble in clientMarbles) { // Oh no! + // var mv = otherMoves.shift(); + // packets.push(marble.packUpdate(myMove, fixedDt)); + // packets.push(othermarble.packUpdate(mv, fixedDt)); + // } var allRecv = true; for (client => marble in clientMarbles) { // Oh no! // var pktClone = packets.copy();