From 8faa93de2ad9295f92d53da48e907cfd10aa8f6f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 15 Sep 2016 22:38:37 +0200 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 6f782c8f..2d5fc487 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 a7036833..c59006d6 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; @@ -86,6 +88,22 @@ public enum Protocol map( ProtocolConstants.MINECRAFT_1_9, 0x0C ), map( ProtocolConstants.MINECRAFT_1_12, 0x0D ) ); + // Waterfall start + TO_CLIENT.registerPacket( + EntityEffect.class, + map(ProtocolConstants.MINECRAFT_1_8, 0x1D), + map(ProtocolConstants.MINECRAFT_1_9, 0x4C), + map(ProtocolConstants.MINECRAFT_1_9_4, 0x4B), + map(ProtocolConstants.MINECRAFT_1_10, 0x4B), + map(ProtocolConstants.MINECRAFT_1_12, 0x4D) + ); + TO_CLIENT.registerPacket( + EntityRemoveEffect.class, + map(ProtocolConstants.MINECRAFT_1_8, 0x1E), + map(ProtocolConstants.MINECRAFT_1_9, 0x31), + map(ProtocolConstants.MINECRAFT_1_12, 0x33) + ); + // 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 00000000..d11a9ea9 --- /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 00000000..7ed2dc3a --- /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 23e03ca2..e1aa8213 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; @@ -127,6 +129,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 1cdfb995..30ee7d16 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.Respawn; @@ -520,6 +522,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 void handle(Respawn respawn) { 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 673497e5..17e250d4 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 @@ -8,6 +8,8 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.Setter; 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; /** @@ -90,9 +92,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.13.0.windows.1