diff --git a/BungeeCord-Patches/0041-Fix-potion-race-condition-on-Forge-1.8.9.patch b/BungeeCord-Patches/0041-Fix-potion-race-condition-on-Forge-1.8.9.patch new file mode 100644 index 0000000..0785410 --- /dev/null +++ b/BungeeCord-Patches/0041-Fix-potion-race-condition-on-Forge-1.8.9.patch @@ -0,0 +1,269 @@ +From 8d698e6607b6687705a9cb38ab541b658a462034 Mon Sep 17 00:00:00 2001 +From: Aaron Hill +Date: Thu, 15 Sep 2016 16:38:37 -0400 +Subject: [PATCH] Fix potion race condition on Forge 1.8.9 + + +diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java b/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java +index 6f782c8..2d5fc48 100644 +--- a/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java ++++ b/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java +@@ -1,6 +1,8 @@ + package net.md_5.bungee.protocol; + + import net.md_5.bungee.protocol.packet.BossBar; ++import net.md_5.bungee.protocol.packet.EntityEffect; ++import net.md_5.bungee.protocol.packet.EntityRemoveEffect; + import net.md_5.bungee.protocol.packet.KeepAlive; + import net.md_5.bungee.protocol.packet.ClientSettings; + import net.md_5.bungee.protocol.packet.ClientStatus; +@@ -148,4 +150,13 @@ public abstract class AbstractPacketHandler + public void handle(BossBar bossBar) throws Exception + { + } ++ // Waterfall start ++ public void handle(EntityEffect entityEffect) throws Exception ++ { ++ } ++ ++ public void handle(EntityRemoveEffect removeEffect) throws Exception ++ { ++ } ++ // Waterfall end + } +diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java +index 4decbb2..796daa3 100644 +--- a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java ++++ b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java +@@ -16,6 +16,8 @@ import net.md_5.bungee.protocol.packet.Chat; + import net.md_5.bungee.protocol.packet.ClientSettings; + import net.md_5.bungee.protocol.packet.EncryptionRequest; + import net.md_5.bungee.protocol.packet.EncryptionResponse; ++import net.md_5.bungee.protocol.packet.EntityEffect; ++import net.md_5.bungee.protocol.packet.EntityRemoveEffect; + import net.md_5.bungee.protocol.packet.Handshake; + import net.md_5.bungee.protocol.packet.KeepAlive; + import net.md_5.bungee.protocol.packet.Kick; +@@ -81,6 +83,18 @@ public enum Protocol + BossBar.class, + map( ProtocolConstants.MINECRAFT_1_9, 0x0C ) + ); ++ // Waterfall start ++ TO_CLIENT.registerPacket( ++ EntityEffect.class, ++ map(ProtocolConstants.MINECRAFT_1_8, 0x1D), ++ map(ProtocolConstants.MINECRAFT_1_9, 0x4B) ++ ); ++ TO_CLIENT.registerPacket( ++ EntityRemoveEffect.class, ++ map(ProtocolConstants.MINECRAFT_1_8, 0x1E), ++ map(ProtocolConstants.MINECRAFT_1_9, 0x31) ++ ); ++ // Waterfall end + TO_CLIENT.registerPacket( + PlayerListItem.class, // PlayerInfo + map( ProtocolConstants.MINECRAFT_1_8, 0x38 ), +diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/EntityEffect.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/EntityEffect.java +new file mode 100644 +index 0000000..d11a9ea +--- /dev/null ++++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/EntityEffect.java +@@ -0,0 +1,45 @@ ++package net.md_5.bungee.protocol.packet; ++ ++import io.netty.buffer.ByteBuf; ++import lombok.AllArgsConstructor; ++import lombok.Data; ++import lombok.EqualsAndHashCode; ++import lombok.NoArgsConstructor; ++import net.md_5.bungee.protocol.AbstractPacketHandler; ++import net.md_5.bungee.protocol.DefinedPacket; ++ ++@Data ++@NoArgsConstructor ++@AllArgsConstructor ++@EqualsAndHashCode(callSuper = false) ++public class EntityEffect extends DefinedPacket { ++ ++ private int entityId; ++ private int effectId; ++ private int amplifier; ++ private int duration; ++ private boolean hideParticles; ++ ++ @Override ++ public void read(ByteBuf buf) { ++ this.entityId = readVarInt(buf); ++ this.effectId = buf.readUnsignedByte(); ++ this.amplifier = buf.readUnsignedByte(); ++ this.duration = readVarInt(buf); ++ this.hideParticles = buf.readBoolean(); ++ } ++ ++ @Override ++ public void write(ByteBuf buf) { ++ writeVarInt(this.entityId, buf); ++ buf.writeByte(this.effectId); ++ buf.writeByte(this.amplifier); ++ writeVarInt(this.duration, buf); ++ buf.writeBoolean(this.hideParticles); ++ } ++ ++ @Override ++ public void handle(AbstractPacketHandler handler) throws Exception { ++ handler.handle(this); ++ } ++} +diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/EntityRemoveEffect.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/EntityRemoveEffect.java +new file mode 100644 +index 0000000..7ed2dc3 +--- /dev/null ++++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/EntityRemoveEffect.java +@@ -0,0 +1,36 @@ ++package net.md_5.bungee.protocol.packet; ++ ++import io.netty.buffer.ByteBuf; ++import lombok.AllArgsConstructor; ++import lombok.Data; ++import lombok.EqualsAndHashCode; ++import lombok.NoArgsConstructor; ++import net.md_5.bungee.protocol.AbstractPacketHandler; ++import net.md_5.bungee.protocol.DefinedPacket; ++ ++@Data ++@NoArgsConstructor ++@AllArgsConstructor ++@EqualsAndHashCode(callSuper = false) ++public class EntityRemoveEffect extends DefinedPacket { ++ ++ private int entityId; ++ private int effectId; ++ ++ @Override ++ public void read(ByteBuf buf) { ++ this.entityId = readVarInt(buf); ++ this.effectId = buf.readUnsignedByte(); ++ } ++ ++ @Override ++ public void write(ByteBuf buf) { ++ writeVarInt(this.entityId, buf); ++ buf.writeByte(effectId); ++ } ++ ++ @Override ++ public void handle(AbstractPacketHandler handler) throws Exception { ++ handler.handle(this); ++ } ++} +diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java +index fead216..f26d20c 100644 +--- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java ++++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java +@@ -2,7 +2,9 @@ package net.md_5.bungee; + + import com.google.common.base.Objects; + import com.google.common.base.Preconditions; ++import com.google.common.collect.HashMultimap; + import com.google.common.collect.ImmutableMap; ++import com.google.common.collect.Multimap; + import io.netty.bootstrap.Bootstrap; + import io.netty.channel.Channel; + import io.netty.channel.ChannelFuture; +@@ -131,6 +133,10 @@ public final class UserConnection implements ProxiedPlayer + private final Scoreboard serverSentScoreboard = new Scoreboard(); + @Getter + private final Collection sentBossBars = new HashSet<>(); ++ // Waterfall start ++ @Getter ++ private final Multimap potions = HashMultimap.create(); ++ // Waterfall end + /*========================================================================*/ + @Getter + private String displayName; +diff --git a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java +index 4177ef5..9618d10 100644 +--- a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java ++++ b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java +@@ -31,6 +31,8 @@ import net.md_5.bungee.netty.PacketHandler; + import net.md_5.bungee.protocol.DefinedPacket; + import net.md_5.bungee.protocol.PacketWrapper; + import net.md_5.bungee.protocol.packet.BossBar; ++import net.md_5.bungee.protocol.packet.EntityEffect; ++import net.md_5.bungee.protocol.packet.EntityRemoveEffect; + import net.md_5.bungee.protocol.packet.KeepAlive; + import net.md_5.bungee.protocol.packet.PlayerListItem; + import net.md_5.bungee.protocol.packet.ScoreboardObjective; +@@ -519,6 +521,32 @@ public class DownstreamBridge extends PacketHandler + } + } + ++ // Waterfall start ++ @Override ++ public void handle(EntityEffect entityEffect) throws Exception ++ { ++ // Don't send any potions when switching between servers (which involves a handshake), which can trigger a race ++ // condition on the client. ++ if (this.con.getForgeClientHandler().isForgeUser() && !this.con.getForgeClientHandler().isHandshakeComplete()) { ++ throw CancelSendSignal.INSTANCE; ++ } ++ con.getPotions().put(rewriteEntityId(entityEffect.getEntityId()), entityEffect.getEffectId()); ++ } ++ ++ @Override ++ public void handle(EntityRemoveEffect removeEffect) throws Exception ++ { ++ con.getPotions().remove(rewriteEntityId(removeEffect.getEntityId()), removeEffect.getEffectId()); ++ } ++ ++ private int rewriteEntityId(int entityId) { ++ if (entityId == con.getServerEntityId()) { ++ return con.getClientEntityId(); ++ } ++ return entityId; ++ } ++ // Waterfall end ++ + @Override + public String toString() + { +diff --git a/proxy/src/main/java/net/md_5/bungee/forge/ForgeClientHandler.java b/proxy/src/main/java/net/md_5/bungee/forge/ForgeClientHandler.java +index 314fd43..3367349 100644 +--- a/proxy/src/main/java/net/md_5/bungee/forge/ForgeClientHandler.java ++++ b/proxy/src/main/java/net/md_5/bungee/forge/ForgeClientHandler.java +@@ -9,6 +9,8 @@ import lombok.RequiredArgsConstructor; + import lombok.Setter; + import net.md_5.bungee.BungeeCord; + import net.md_5.bungee.UserConnection; ++import net.md_5.bungee.protocol.ProtocolConstants; ++import net.md_5.bungee.protocol.packet.EntityRemoveEffect; + import net.md_5.bungee.protocol.packet.PluginMessage; + + /** +@@ -91,9 +93,23 @@ public class ForgeClientHandler + public void resetHandshake() + { + state = ForgeClientHandshakeState.HELLO; ++ ++ // This issue only exists in Forge 1.8.9 ++ if (this.con.getPendingConnection().getVersion() == ProtocolConstants.MINECRAFT_1_8) { ++ this.resetAllThePotions(con); ++ } ++ + con.unsafe().sendPacket( ForgeConstants.FML_RESET_HANDSHAKE ); + } + ++ private void resetAllThePotions(UserConnection con) { ++ // Just to be sure ++ for (Map.Entry entry: con.getPotions().entries()) { ++ con.unsafe().sendPacket(new EntityRemoveEffect(entry.getKey(), entry.getValue())); ++ } ++ con.getPotions().clear(); ++ } ++ + /** + * Sends the server mod list to the client, or stores it for sending later. + * +-- +2.9.3 +