Allow custom selector types to be defined (#4259)

This commit is contained in:
Philipp Provenzano 2017-10-31 19:28:11 +01:00 committed by LexManos
parent 2a546955a4
commit aa2480c7a1
5 changed files with 284 additions and 1 deletions

View File

@ -1,6 +1,18 @@
--- ../src-base/minecraft/net/minecraft/command/EntitySelector.java
+++ ../src-work/minecraft/net/minecraft/command/EntitySelector.java
@@ -153,6 +153,7 @@
@@ -121,6 +121,11 @@
public static <T extends Entity> List<T> func_179656_b(ICommandSender p_179656_0_, String p_179656_1_, Class <? extends T > p_179656_2_) throws CommandException
{
+ return net.minecraftforge.common.command.SelectorHandlerManager.matchEntities(p_179656_0_, p_179656_1_, p_179656_2_);
+ }
+
+ public static <T extends Entity> List<T> matchEntitiesDefault(ICommandSender p_179656_0_, String p_179656_1_, Class <? extends T > p_179656_2_) throws CommandException
+ {
Matcher matcher = field_82389_a.matcher(p_179656_1_);
if (matcher.matches() && p_179656_0_.func_70003_b(1, "@"))
@@ -153,6 +158,7 @@
list2.addAll(func_184951_f(map));
list2.addAll(func_180698_a(map, vec3d));
list2.addAll(func_179662_g(map));
@ -8,3 +20,27 @@
if ("s".equalsIgnoreCase(s))
{
@@ -786,6 +792,11 @@
public static boolean func_82377_a(String p_82377_0_) throws CommandException
{
+ return net.minecraftforge.common.command.SelectorHandlerManager.matchesMultiplePlayers(p_82377_0_);
+ }
+
+ public static boolean matchesMultiplePlayersDefault(String p_82377_0_) throws CommandException
+ {
Matcher matcher = field_82389_a.matcher(p_82377_0_);
if (!matcher.matches())
@@ -803,6 +814,11 @@
public static boolean func_82378_b(String p_82378_0_)
{
+ return net.minecraftforge.common.command.SelectorHandlerManager.isSelector(p_82378_0_);
+ }
+
+ public static boolean isSelectorDefault(String p_82378_0_)
+ {
return field_82389_a.matcher(p_82378_0_).matches();
}

View File

@ -0,0 +1,52 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* 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.common.command;
import java.util.List;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.Entity;
/**
* Handler for custom types of selectors registered with {@link SelectorHandlerManager}
*/
public interface SelectorHandler
{
/**
* Returns a {@link List} of {@link Entity Entities} of class {@code targetClass} ({@code T}) represented by {@code token}<br>
* <b>Note:</b> If {@code token} does not match the overall syntax defined by {@link #isSelector}, this method should return an empty list.
* For any other error, an exception should be thrown
*
* @param sender The {@link ICommandSender} that initiated the query
*/
public <T extends Entity> List<T> matchEntities(ICommandSender sender, String token, Class<? extends T> targetClass) throws CommandException;
/**
* Returns whether the selector string potentially matches multiple entities
*/
public boolean matchesMultiplePlayers(String selectorStr) throws CommandException;
/**
* Returns whether the string matches the overall syntax of the selector<br>
* <b>Note:</b> If this returns {@code false}, {@link #matchEntities} should return an empty list
*/
public boolean isSelector(String selectorStr);
}

View File

@ -0,0 +1,141 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* 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.common.command;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.TreeMap;
import org.apache.commons.lang3.ArrayUtils;
import net.minecraft.command.CommandException;
import net.minecraft.command.EntitySelector;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.Entity;
import net.minecraftforge.fml.common.Loader;
/**
* Allows registration of custom selector types by assigning a {@link SelectorHandler} to a prefix
* This class handles calls to the {@link EntitySelector} methods {@link EntitySelector#matchEntities matchEntities},
* {@link EntitySelector#matchesMultiplePlayers matchesMultiplePlayers} and {@link EntitySelector#isSelector isSelector}.<br>
* The calls are delegated to the handler with the longest matching prefix.<br>
* <br>
* <b>Note:</b> If you register a {@link SelectorHandler} to a broader domain (not just a single selector), you should take care of possible shadowing conflicts yourself.
* For this you can use the information provided by {@link #selectorHandlers} and {@link #registeringMods}.
*/
public class SelectorHandlerManager
{
private SelectorHandlerManager()
{
}
//the ordering is reversed such that longer prefixes appear before their shorter substrings
public static final NavigableMap<String, SelectorHandler> selectorHandlers = new TreeMap<String, SelectorHandler>(Collections.<String> reverseOrder());
public static final NavigableMap<String, String> registeringMods = new TreeMap<String, String>(Collections.<String> reverseOrder());
private static final SelectorHandler vanillaHandler = new SelectorHandler()
{
@Override
public <T extends Entity> List<T> matchEntities(final ICommandSender sender, final String token, final Class<? extends T> targetClass) throws CommandException
{
return EntitySelector.matchEntitiesDefault(sender, token, targetClass);
}
@Override
public boolean matchesMultiplePlayers(final String selectorStr) throws CommandException
{
return EntitySelector.matchesMultiplePlayersDefault(selectorStr);
}
@Override
public boolean isSelector(final String selectorStr)
{
return EntitySelector.isSelectorDefault(selectorStr);
}
};
static
{
for (final String prefix : ArrayUtils.toArray("@p", "@a", "@r", "@e", "@s"))
{
selectorHandlers.put(prefix, vanillaHandler);
registeringMods.put(prefix, "minecraft");
}
}
/**
* Registers a new {@link SelectorHandler} for {@code prefix}.<br>
*
* @param prefix The domain the specified {@code handler} is registered for.
* If you want to register just a single selector, {@code prefix} has the form '@{selectorName}'
*/
public static void register(final String prefix, final SelectorHandler handler)
{
if (prefix.isEmpty())
{
throw new IllegalArgumentException("Prefix must not be empty");
}
final String modId = Loader.instance().activeModContainer().getModId();
selectorHandlers.put(prefix, handler);
registeringMods.put(prefix, modId);
}
/**
* Returns the best matching handler for the given string. Defaults to the vanilla handler if no prefix applies
*/
public static SelectorHandler getHandler(final String selectorStr)
{
if (!selectorStr.isEmpty())
{
for (final Entry<String, SelectorHandler> handler : selectorHandlers.subMap(selectorStr, true, selectorStr.substring(0, 1), true).entrySet())
{
if (selectorStr.startsWith(handler.getKey()))
{
return handler.getValue();
}
}
}
return vanillaHandler;
}
//These methods are called by the vanilla methods
public static <T extends Entity> List<T> matchEntities(final ICommandSender sender, final String token, final Class<? extends T> targetClass) throws CommandException
{
return getHandler(token).matchEntities(sender, token, targetClass);
}
public static boolean matchesMultiplePlayers(final String selectorStr) throws CommandException
{
return getHandler(selectorStr).matchesMultiplePlayers(selectorStr);
}
public static boolean isSelector(final String selectorStr)
{
return getHandler(selectorStr).isSelector(selectorStr);
}
}

View File

@ -61,3 +61,7 @@ net/minecraft/world/storage/loot/LootEntryEmpty.<init>(II[Lnet/minecraft/world/s
net/minecraft/world/chunk/BlockStateContainer.setBits(IZ)V=|p_186012_1_,forceBits
net/minecraft/village/Village.getPlayerReputation(Ljava/util/UUID;)I=|p_82684_1_
net/minecraft/village/Village.modifyPlayerReputation(Ljava/util/UUID;I)I=|p_82688_1_,p_82688_2_
net/minecraft/command/EntitySelector.matchEntitiesDefault(Lnet/minecraft/command/ICommandSender;Ljava/lang/String;Ljava/lang/Class;)Ljava/util/List;=|p_179656_0_,p_179656_1_,p_179656_2_
net/minecraft/command/EntitySelector.matchesMultiplePlayersDefault(Ljava/lang/String;)Z=|p_82377_0_
net/minecraft/command/EntitySelector.isSelectorDefault(Ljava/lang/String;)Z=|p_82378_0_

View File

@ -0,0 +1,50 @@
package net.minecraftforge.test;
import java.util.Collections;
import java.util.List;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.Entity;
import net.minecraftforge.common.command.SelectorHandler;
import net.minecraftforge.common.command.SelectorHandlerManager;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
@Mod(modid = "selectorhandlertest", name = "Selector Handler Test", version = "0.0.0")
public class SelectorHandlerTest
{
@EventHandler
public void init(final FMLInitializationEvent event)
{
SelectorHandlerManager.register(Handler.name, new Handler());
}
private static class Handler implements SelectorHandler
{
protected static final String name = "@self";
@SuppressWarnings("unchecked")
@Override
public <T extends Entity> List<T> matchEntities(final ICommandSender sender, final String token, final Class<? extends T> targetClass) throws CommandException
{
final Entity senderEntity = sender.getCommandSenderEntity();
return senderEntity != null && targetClass.isAssignableFrom(senderEntity.getClass()) && name.equals(token)
? Collections.singletonList((T) sender.getCommandSenderEntity())
: Collections.<T> emptyList();
}
@Override
public boolean matchesMultiplePlayers(final String selectorStr) throws CommandException
{
return false;
}
@Override
public boolean isSelector(final String selectorStr)
{
return name.equals(selectorStr);
}
}
}