From 406c4652df1c052e7b0219f8a4e400a34aee01ef 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 35236382..558d0dbb 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 @@ -10,6 +10,8 @@ import net.md_5.bungee.protocol.packet.ClientStatus; 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.EntityEffect; // Waterfall +import net.md_5.bungee.protocol.packet.EntityRemoveEffect; // Waterfall import net.md_5.bungee.protocol.packet.EntityStatus; import net.md_5.bungee.protocol.packet.GameState; import net.md_5.bungee.protocol.packet.Handshake; @@ -213,4 +215,14 @@ public abstract class AbstractPacketHandler public void handle(GameState gameState) 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 ad0c66a5..014383b3 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 @@ -20,6 +20,8 @@ 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.GameState; +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; @@ -133,6 +135,20 @@ public enum Protocol PlayerChat::new, map( ProtocolConstants.MINECRAFT_1_19, 0x30 ) ); + // Waterfall start + TO_CLIENT.registerPacket( + EntityEffect.class, + EntityEffect::new, + map(ProtocolConstants.MINECRAFT_1_8, 0x1D), + map(ProtocolConstants.MINECRAFT_1_9, Integer.MIN_VALUE) + ); + TO_CLIENT.registerPacket( + EntityRemoveEffect.class, + EntityRemoveEffect::new, + map(ProtocolConstants.MINECRAFT_1_8, 0x1E), + map(ProtocolConstants.MINECRAFT_1_9, Integer.MIN_VALUE) + ); + // Waterfall end TO_CLIENT.registerPacket( PlayerListItem.class, // PlayerInfo PlayerListItem::new, @@ -620,9 +636,11 @@ public enum Protocol break; } + if (mapping.packetID != Integer.MIN_VALUE) { // Waterfall ProtocolData data = protocols.get( protocol ); data.packetMap.put( packetClass, mapping.packetID ); data.packetConstructors[mapping.packetID] = constructor; + } // Waterfall } } 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 ccb9efdc..c96117c6 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 98bebb94..b5f8c473 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 @@ -51,6 +51,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.Kick; import net.md_5.bungee.protocol.packet.PlayerListItem; @@ -665,6 +667,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 d15044f4..bea2bbff 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; /** @@ -94,9 +96,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.36.1.windows.1