From acd18455c28d888afa95602b9ff1f6d1cca7ef6e Mon Sep 17 00:00:00 2001 From: diesieben07 Date: Sun, 27 Sep 2020 19:09:31 +0200 Subject: [PATCH] Workaround for modded attributes on vanilla entities logging warnings on vanilla clients Switch to a handler-based approach per packet class, simplify patch, add some docs Add license header and docs Switch to a network handler based approach Switch to a network handler based approach revert build gradle change Simplify Packet patch Add license header to IForgePacket Revert ForgeHooks changes Less hacky and more generic way to filter packets for vanilla connections _Actually_ Order SAS. It's early Order SAS simplify vanilla connection check Remove unneeded import change --- .../fml/network/ConnectionType.java | 12 ++- .../fml/network/NetworkHooks.java | 14 ++- .../fml/server/ServerLifecycleHooks.java | 2 + .../VanillaConnectionNetworkFilter.java | 98 +++++++++++++++++++ src/main/resources/forge.sas | 1 + 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 src/main/java/net/minecraftforge/network/VanillaConnectionNetworkFilter.java diff --git a/src/main/java/net/minecraftforge/fml/network/ConnectionType.java b/src/main/java/net/minecraftforge/fml/network/ConnectionType.java index ad1a1d52f3..2af87980b5 100644 --- a/src/main/java/net/minecraftforge/fml/network/ConnectionType.java +++ b/src/main/java/net/minecraftforge/fml/network/ConnectionType.java @@ -27,7 +27,8 @@ public enum ConnectionType private final Function versionExtractor; - ConnectionType(Function versionExtractor) { + ConnectionType(Function versionExtractor) + { this.versionExtractor = versionExtractor; } @@ -36,7 +37,14 @@ public enum ConnectionType return vers.startsWith(FMLNetworkConstants.FMLNETMARKER) ? MODDED : VANILLA; } - public int getFMLVersionNumber(final String fmlVersion) { + public int getFMLVersionNumber(final String fmlVersion) + { return versionExtractor.apply(fmlVersion); } + + public boolean isVanilla() + { + return this == VANILLA; + } + } diff --git a/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java b/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java index e34321410d..5c23babbe8 100644 --- a/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java +++ b/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java @@ -27,6 +27,8 @@ import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; import net.minecraft.tags.ITagCollection; import net.minecraft.tags.ITagCollectionSupplier; import net.minecraft.util.text.StringTextComponent; @@ -62,7 +64,17 @@ public class NetworkHooks public static ConnectionType getConnectionType(final Supplier connection) { - return ConnectionType.forVersionFlag(connection.get().channel().attr(FMLNetworkConstants.FML_NETVERSION).get()); + return getConnectionType(connection.get().channel()); + } + + public static ConnectionType getConnectionType(ChannelHandlerContext context) + { + return getConnectionType(context.channel()); + } + + private static ConnectionType getConnectionType(Channel channel) + { + return ConnectionType.forVersionFlag(channel.attr(FMLNetworkConstants.FML_NETVERSION).get()); } public static IPacket getEntitySpawningPacket(Entity entity) diff --git a/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java b/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java index 93ab48e045..d3c3e85794 100644 --- a/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java +++ b/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java @@ -68,6 +68,7 @@ import net.minecraftforge.fml.loading.moddiscovery.ModFile; import net.minecraftforge.fml.packs.ModFileResourcePack; import net.minecraftforge.fml.packs.ResourcePackLoader; import net.minecraftforge.forgespi.language.IModInfo; +import net.minecraftforge.network.VanillaConnectionNetworkFilter; import net.minecraftforge.registries.GameData; public class ServerLifecycleHooks @@ -168,6 +169,7 @@ public class ServerLifecycleHooks if (packet.getRequestedState() == ProtocolType.STATUS) return true; NetworkHooks.registerServerLoginChannel(manager, packet); + VanillaConnectionNetworkFilter.injectIfNecessary(manager); return true; } diff --git a/src/main/java/net/minecraftforge/network/VanillaConnectionNetworkFilter.java b/src/main/java/net/minecraftforge/network/VanillaConnectionNetworkFilter.java new file mode 100644 index 0000000000..a6c6a3720c --- /dev/null +++ b/src/main/java/net/minecraftforge/network/VanillaConnectionNetworkFilter.java @@ -0,0 +1,98 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2020. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.network; + +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import javax.annotation.Nonnull; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageEncoder; +import net.minecraft.network.IPacket; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.play.server.SEntityPropertiesPacket; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.NetworkHooks; +import net.minecraftforge.registries.ForgeRegistries; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.common.collect.ImmutableMap; + +/** + * A filter for network packets, used to filter/modify parts of vanilla network messages that + * will cause errors or warnings on vanilla clients, for example entity attributes that are added by Forge or mods. + */ +public class VanillaConnectionNetworkFilter extends MessageToMessageEncoder> +{ + + private static final Logger LOGGER = LogManager.getLogger(); + + private static final Map>, Function, ? extends IPacket>> handlers = ImmutableMap.>, Function, ? extends IPacket>>builder() + .put(handler(SEntityPropertiesPacket.class, VanillaConnectionNetworkFilter::filterEntityProperties)) + .build(); + + + public static void injectIfNecessary(NetworkManager manager) + { + if (NetworkHooks.isVanillaConnection(manager)) + { + manager.channel().pipeline().addBefore("packet_handler", "forge:vanilla_filter", new VanillaConnectionNetworkFilter()); + LOGGER.debug("Injected into {}", manager); + } + } + + /** + * Helper function for building the handler map. + */ + @Nonnull + private static > Map.Entry>, Function, ? extends IPacket>> handler(Class cls, Function> function) + { + return new AbstractMap.SimpleEntry<>(cls, function.compose(cls::cast)); + } + + /** + * Filter for SEntityPropertiesPacket. Filters out any entity attributes that are not in the "minecraft" namespace. + * A vanilla client would ignore these with an error log. + */ + @Nonnull + private static SEntityPropertiesPacket filterEntityProperties(SEntityPropertiesPacket msg) + { + SEntityPropertiesPacket newPacket = new SEntityPropertiesPacket(); + msg.getSnapshots().stream() + .filter(snapshot -> { + ResourceLocation key = ForgeRegistries.ATTRIBUTES.getKey(snapshot.func_240834_a_()); + return key != null && key.getNamespace().equals("minecraft"); + }) + .forEach(snapshot -> newPacket.getSnapshots().add(snapshot)); + return newPacket; + } + + @Override + protected void encode(ChannelHandlerContext ctx, IPacket msg, List out) + { + Function, ? extends IPacket> function = handlers.getOrDefault(msg.getClass(), Function.identity()); + out.add(function.apply(msg)); + } +} diff --git a/src/main/resources/forge.sas b/src/main/resources/forge.sas index 0c824c9cfd..c7af72d219 100644 --- a/src/main/resources/forge.sas +++ b/src/main/resources/forge.sas @@ -74,6 +74,7 @@ net/minecraft/item/crafting/IRecipe func_193358_e()Ljava/lang/String; # getGroup net/minecraft/item/crafting/SingleItemRecipe func_193358_e()Ljava/lang/String; net/minecraft/nbt/CompressedStreamTools func_74797_a(Ljava/io/File;)Lnet/minecraft/nbt/CompoundNBT; # read net/minecraft/nbt/CompressedStreamTools func_74795_b(Lnet/minecraft/nbt/CompoundNBT;Ljava/io/File;)V # write +net/minecraft/network/play/server/SEntityPropertiesPacket func_149441_d()Ljava/util/List; # getSnapshots net/minecraft/potion/Effect func_220303_e()Lnet/minecraft/potion/EffectType; # getEffectType net/minecraft/potion/Effect func_111186_k()Ljava/util/Map; # getAttributeModifierMap net/minecraft/potion/Effect func_188408_i()Z # isBeneficial