From f9e766ad2bd4304d50defaa47d567d46e6cd35d7 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 219488dd..bef7b370 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; @@ -168,4 +170,14 @@ public abstract class AbstractPacketHandler public void handle(Commands commands) 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 1161dc5d..39affec6 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 @@ -18,6 +18,8 @@ import net.md_5.bungee.protocol.packet.Commands; import net.md_5.bungee.protocol.packet.EncryptionRequest; import net.md_5.bungee.protocol.packet.EncryptionResponse; import net.md_5.bungee.protocol.packet.EntityStatus; +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; @@ -96,6 +98,26 @@ public enum Protocol map( ProtocolConstants.MINECRAFT_1_12, 0x0C ), map( ProtocolConstants.MINECRAFT_1_13, 0x0C ) ); + // 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, 0x4E), + map(ProtocolConstants.MINECRAFT_1_12_1, 0x4F), + map(ProtocolConstants.MINECRAFT_1_13, 0x53) + ); + TO_CLIENT.registerPacket( + EntityRemoveEffect.class, + map(ProtocolConstants.MINECRAFT_1_8, 0x1E), + map(ProtocolConstants.MINECRAFT_1_9, 0x31), + map(ProtocolConstants.MINECRAFT_1_12, 0x32), + map(ProtocolConstants.MINECRAFT_1_12_1, 0x33), + map(ProtocolConstants.MINECRAFT_1_13, 0x36) + ); + // 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 6dae9a88..9c872a1c 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -1,7 +1,9 @@ package net.md_5.bungee; 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; @@ -125,6 +127,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 d0c2ac42..56c81262 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 @@ -42,6 +42,8 @@ import net.md_5.bungee.protocol.PacketWrapper; import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.packet.BossBar; import net.md_5.bungee.protocol.packet.Commands; +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; @@ -549,6 +551,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 0d683856..c1272da3 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.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; /** @@ -92,9 +94,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.20.1