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
This commit is contained in:
diesieben07 authored and cpw committed 2020-11-03 18:47:04 -05:00
1 parent 5a7facc20f
commit acd18455c2
5 files changed
+124 -3

No files matched your search

@@ -27,7 +27,8 @@ public enum ConnectionType
private final Function<String, Integer> versionExtractor;
ConnectionType(Function<String, Integer> versionExtractor) {
ConnectionType(Function<String, Integer> 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;
}
}
@@ -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<NetworkManager> 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)
@@ -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;
}
@@ -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<IPacket<?>>
{
private static final Logger LOGGER = LogManager.getLogger();
private static final Map<Class<? extends IPacket<?>>, Function<IPacket<?>, ? extends IPacket<?>>> handlers = ImmutableMap.<Class<? extends IPacket<?>>, Function<IPacket<?>, ? 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 <T extends IPacket<?>> Map.Entry<Class<? extends IPacket<?>>, Function<IPacket<?>, ? extends IPacket<?>>> handler(Class<T> cls, Function<T, ? extends IPacket<?>> 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<Object> out)
{
Function<IPacket<?>, ? extends IPacket<?>> function = handlers.getOrDefault(msg.getClass(), Function.identity());
out.add(function.apply(msg));
}
}