Allow for custom argument types by filtering them on vanilla connections (#7463)
This commit is contained in:
parent
f3b53001c9
commit
bca20ace4e
7 changed files with 151 additions and 27 deletions
|
@ -0,0 +1,11 @@
|
|||
--- a/net/minecraft/command/arguments/ArgumentTypes.java
|
||||
+++ b/net/minecraft/command/arguments/ArgumentTypes.java
|
||||
@@ -220,4 +220,8 @@
|
||||
this.field_197481_c = p_i48088_3_;
|
||||
}
|
||||
}
|
||||
+ @javax.annotation.Nullable public static ResourceLocation getId(ArgumentType<?> type) {
|
||||
+ Entry<?> entry = func_201040_a(type);
|
||||
+ return entry == null ? null : entry.field_197481_c;
|
||||
+ }
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
--- a/net/minecraft/network/play/server/SCommandListPacket.java
|
||||
+++ b/net/minecraft/network/play/server/SCommandListPacket.java
|
||||
@@ -119,6 +119,9 @@
|
||||
String s = p_197695_0_.func_150789_c(32767);
|
||||
ArgumentType<?> argumenttype = ArgumentTypes.func_197486_a(p_197695_0_);
|
||||
if (argumenttype == null) {
|
||||
+ if ((i & 16) != 0) { // FORGE: Flush unused suggestion data
|
||||
+ p_197695_0_.func_192575_l();
|
||||
+ }
|
||||
return null;
|
||||
} else {
|
||||
RequiredArgumentBuilder<ISuggestionProvider, ?> requiredargumentbuilder = RequiredArgumentBuilder.argument(s, argumenttype);
|
|
@ -19,6 +19,9 @@
|
|||
|
||||
package net.minecraftforge.common;
|
||||
|
||||
import net.minecraft.command.arguments.ArgumentSerializer;
|
||||
import net.minecraft.command.arguments.ArgumentTypes;
|
||||
import net.minecraft.command.arguments.IArgumentSerializer;
|
||||
import net.minecraft.entity.ai.attributes.Attribute;
|
||||
import net.minecraft.entity.ai.attributes.RangedAttribute;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
|
@ -34,6 +37,8 @@ import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
|
|||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.server.command.EnumArgument;
|
||||
import net.minecraftforge.server.command.ModIdArgument;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.versions.mcp.MCPVersion;
|
||||
|
||||
|
@ -139,13 +144,14 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
|
|||
|
||||
VersionChecker.startVersionCheck();
|
||||
|
||||
/*
|
||||
* We can't actually add any of these, because vanilla clients will choke on unknown argument types
|
||||
* So our custom arguments will not validate client-side, but they do still work
|
||||
ArgumentTypes.register("forge:enum", EnumArgument.class, new EnumArgument.Serializer());
|
||||
registerArgumentTypes();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private void registerArgumentTypes()
|
||||
{
|
||||
ArgumentTypes.register("forge:enum", EnumArgument.class, (IArgumentSerializer) new EnumArgument.Serializer());
|
||||
ArgumentTypes.register("forge:modid", ModIdArgument.class, new ArgumentSerializer<>(ModIdArgument::modIdArgument));
|
||||
ArgumentTypes.register("forge:structure_type", StructureArgument.class, new ArgumentSerializer<>(StructureArgument::structure));
|
||||
*/
|
||||
}
|
||||
|
||||
public void serverStopping(FMLServerStoppingEvent evt)
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
import com.mojang.brigadier.tree.ArgumentCommandNode;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
import com.mojang.brigadier.tree.RootCommandNode;
|
||||
|
||||
class CommandTreeCleaner
|
||||
{
|
||||
|
||||
/**
|
||||
* Cleans the command tree starting at the given root node from any argument types that do not match the given predicate.
|
||||
* Any {@code ArgumentCommandNode}s that have an unmatched argument type will be stripped from the tree.
|
||||
* @return A new command tree, stripped of any unmatched argument types
|
||||
*/
|
||||
public static <S> RootCommandNode<S> cleanArgumentTypes(RootCommandNode<S> root, Predicate<ArgumentType<?>> argumentTypeFilter)
|
||||
{
|
||||
Predicate<CommandNode<?>> nodeFilter = node -> !(node instanceof ArgumentCommandNode<?, ?>) || argumentTypeFilter.test(((ArgumentCommandNode<?, ?>)node).getType());
|
||||
return (RootCommandNode<S>)processCommandNode(root, nodeFilter, new HashMap<>());
|
||||
}
|
||||
|
||||
private static <S> CommandNode<S> processCommandNode(CommandNode<S> node, Predicate<CommandNode<?>> nodeFilter, Map<CommandNode<S>, CommandNode<S>> newNodes)
|
||||
{
|
||||
CommandNode<S> existingNode = newNodes.get(node);
|
||||
if (existingNode == null)
|
||||
{
|
||||
CommandNode<S> newNode = cloneNode(node, nodeFilter, newNodes);
|
||||
newNodes.put(node, newNode);
|
||||
node.getChildren().stream()
|
||||
.filter(nodeFilter)
|
||||
.map(child -> processCommandNode(child, nodeFilter, newNodes))
|
||||
.forEach(newNode::addChild);
|
||||
return newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
return existingNode;
|
||||
}
|
||||
}
|
||||
|
||||
private static <S> CommandNode<S> cloneNode(CommandNode<S> node, Predicate<CommandNode<?>> nodeFilter, Map<CommandNode<S>, CommandNode<S>> newNodes)
|
||||
{
|
||||
if (node instanceof RootCommandNode<?>)
|
||||
{
|
||||
return new RootCommandNode<>();
|
||||
}
|
||||
else
|
||||
{
|
||||
ArgumentBuilder<S, ?> builder = node.createBuilder();
|
||||
if (node.getRedirect() != null)
|
||||
{
|
||||
if (nodeFilter.test(node.getRedirect()))
|
||||
{
|
||||
builder.forward(processCommandNode(node.getRedirect(), nodeFilter, newNodes), node.getRedirectModifier(), node.isFork());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.redirect(null);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -28,8 +28,11 @@ import javax.annotation.Nonnull;
|
|||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import net.minecraft.command.ISuggestionProvider;
|
||||
import net.minecraft.command.arguments.ArgumentTypes;
|
||||
import net.minecraft.network.IPacket;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.play.server.SCommandListPacket;
|
||||
import net.minecraft.network.play.server.SEntityPropertiesPacket;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.network.NetworkHooks;
|
||||
|
@ -39,6 +42,7 @@ import org.apache.logging.log4j.LogManager;
|
|||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.brigadier.tree.RootCommandNode;
|
||||
|
||||
/**
|
||||
* A filter for network packets, used to filter/modify parts of vanilla network messages that
|
||||
|
@ -51,6 +55,7 @@ public class VanillaConnectionNetworkFilter extends MessageToMessageEncoder<IPac
|
|||
|
||||
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))
|
||||
.put(handler(SCommandListPacket.class, VanillaConnectionNetworkFilter::filterCommandList))
|
||||
.build();
|
||||
|
||||
|
||||
|
@ -89,6 +94,21 @@ public class VanillaConnectionNetworkFilter extends MessageToMessageEncoder<IPac
|
|||
return newPacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter for SCommandListPacket. Uses {@link CommandTreeCleaner} to filter out any ArgumentTypes that are not in the "minecraft" or "brigadier" namespace.
|
||||
* A vanilla client would fail to deserialize the packet and disconnect with an error message if these were sent.
|
||||
*/
|
||||
@Nonnull
|
||||
private static SCommandListPacket filterCommandList(SCommandListPacket packet)
|
||||
{
|
||||
RootCommandNode<ISuggestionProvider> root = packet.getRoot();
|
||||
RootCommandNode<ISuggestionProvider> newRoot = CommandTreeCleaner.cleanArgumentTypes(root, argType -> {
|
||||
ResourceLocation id = ArgumentTypes.getId(argType);
|
||||
return id != null && (id.getNamespace().equals("minecraft") || id.getNamespace().equals("brigadier"));
|
||||
});
|
||||
return new SCommandListPacket(newRoot);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, IPacket<?> msg, List<Object> out)
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package net.minecraftforge.server.command;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
|
@ -26,6 +27,9 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import net.minecraft.command.ISuggestionProvider;
|
||||
import net.minecraft.command.arguments.IArgumentSerializer;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -56,28 +60,33 @@ public class EnumArgument<T extends Enum<T>> implements ArgumentType<T> {
|
|||
return Stream.of(enumClass.getEnumConstants()).map(Object::toString).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/* JAVAC HATES RAW TYPES!
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public static class Serialzier implements IArgumentSerializer<EnumArgument> {
|
||||
public static class Serializer implements IArgumentSerializer<EnumArgument<?>>
|
||||
{
|
||||
@Override
|
||||
public void write(EnumArgument argument, PacketBuffer buffer) {
|
||||
public void write(EnumArgument<?> argument, PacketBuffer buffer)
|
||||
{
|
||||
buffer.writeString(argument.enumClass.getName());
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public EnumArgument<?> read(PacketBuffer buffer) {
|
||||
try {
|
||||
public EnumArgument<?> read(PacketBuffer buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
String name = buffer.readString();
|
||||
return new EnumArgument(Class.forName(name));
|
||||
} catch (ClassNotFoundException e) {
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(EnumArgument argument, JsonObject json) {
|
||||
public void write(EnumArgument<?> argument, JsonObject json)
|
||||
{
|
||||
json.addProperty("enum", argument.enumClass.getName());
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -75,6 +75,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/SCommandListPacket func_197693_a()Lcom/mojang/brigadier/tree/RootCommandNode; # getRoot
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue