From 42e0fbbb0278e904c36c17e522704aefd148ad8b Mon Sep 17 00:00:00 2001 From: Max Becker Date: Sat, 5 Nov 2016 21:12:05 +0100 Subject: [PATCH] Add support for custom entity selectors in commands (#3356) --- .../command/EntitySelector.java.patch | 12 +- .../event/EntitySelectorEvent.java | 121 ++++++++++++++++++ .../event/ForgeEventFactory.java | 10 ++ 3 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/minecraftforge/event/EntitySelectorEvent.java diff --git a/patches/minecraft/net/minecraft/command/EntitySelector.java.patch b/patches/minecraft/net/minecraft/command/EntitySelector.java.patch index 7780106b2..c95b86bda 100644 --- a/patches/minecraft/net/minecraft/command/EntitySelector.java.patch +++ b/patches/minecraft/net/minecraft/command/EntitySelector.java.patch @@ -5,10 +5,18 @@ public class EntitySelector { - private static final Pattern field_82389_a = Pattern.compile("^@([pare])(?:\\[([\\w=,!-]*)\\])?$"); -+ private static final Pattern field_82389_a = Pattern.compile("^@([pare])(?:\\[([\\w\\.=,!-]*)\\])?$"); // FORGE: allow . in entity selectors ++ private static final Pattern field_82389_a = Pattern.compile("^@([pare])(?:\\[([\\w\\.:=,!-]*)\\])?$"); // FORGE: allow '.' and ':' in entity selectors private static final Pattern field_82387_b = Pattern.compile("\\G([-!]?[\\w-]*)(?:$|,)"); - private static final Pattern field_82388_c = Pattern.compile("\\G(\\w+)=([-!]?[\\w-]*)(?:$|,)"); -+ private static final Pattern field_82388_c = Pattern.compile("\\G(\\w+)=([-!]?[\\w\\.-]*)(?:$|,)"); // FORGE: allow . in entity selectors ++ private static final Pattern field_82388_c = Pattern.compile("\\G([\\w:]+)=([-!]?[\\w\\.-]*)(?:$|,)"); // FORGE: allow ':' in arguments and '.' in value of entity selectors private static final Set field_179666_d = Sets.newHashSet(new String[] {"x", "y", "z", "dx", "dy", "dz", "rm", "r"}); @Nullable +@@ -111,6 +111,7 @@ + list2.addAll(func_184951_f(map)); + list2.addAll(func_180698_a(map, vec3d)); + list2.addAll(func_179662_g(map)); ++ list2.addAll(net.minecraftforge.event.ForgeEventFactory.gatherEntitySelectors(map, s, p_179656_0_, vec3d)); + list1.addAll(func_179660_a(map, p_179656_2_, list2, s, world, blockpos)); + } + } diff --git a/src/main/java/net/minecraftforge/event/EntitySelectorEvent.java b/src/main/java/net/minecraftforge/event/EntitySelectorEvent.java new file mode 100644 index 000000000..c2aefdd7d --- /dev/null +++ b/src/main/java/net/minecraftforge/event/EntitySelectorEvent.java @@ -0,0 +1,121 @@ +/* + * 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.event; + +import com.google.common.base.Predicate; +import com.google.common.collect.Lists; +import net.minecraft.command.EntitySelector; +import net.minecraft.command.ICommandSender; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.Event; + +import java.util.List; +import java.util.Map; + +/** + * EntitySelectorEvent is fired whenever Minecraft collects entity selectors. + * This happens (one or multiple times) when you use something like @a[gamemode=1] in a command.
+ * This event is fired via {@link ForgeEventFactory#gatherEntitySelectors(Map, String, ICommandSender, Vec3d)}, + * which is executed in {@link net.minecraft.command.EntitySelector#matchEntities(ICommandSender, String, Class)}
+ *
+ * This event is not cancelable and does not have a result.
+ *
+ * This event is fired on the {@link MinecraftForge#EVENT_BUS} + */ +public class EntitySelectorEvent extends Event +{ + + private final Map map; + private final String mainSelector; + private final ICommandSender sender; + private final Vec3d position; + private final List> selectors; + + public EntitySelectorEvent(Map map, String mainSelector, ICommandSender sender, Vec3d position) + { + this.map = map; + this.mainSelector = mainSelector; + this.sender = sender; + this.position = position; + selectors = Lists.newArrayList(); + } + + /** + * Add your custom selector. + * It is recommend to use "modid:name", if checking for own arguments, to avoid inter-mod interference (e.g. "@a[Forge:timeplayed=100]"). + * + * @param selector Your custom predicate + */ + public void addPredicate(Predicate selector) + { + if (selector == null) + { + throw new NullPointerException("Attempted to add null predicate as entity selector"); + } + selectors.add(selector); + } + + /** + * @return The main selector used (e.g. 'a' for all players or 'e' for all entities) + */ + public String getMainSelector() + { + return mainSelector; + } + + /** + * Example: "@a[test=true]" would result in a map with "test"=>"true" + * + * @return The argument map. Maps all given argument names with its value. + */ + public Map getArgumentMap() + { + return map; + } + + /** + * See {@link EntitySelector#getPosFromArguments(Map, Vec3d)} + * + * @return A position either specified in the selector arguments or by the players position. + */ + public Vec3d getPosition() + { + return position; + } + + /** + * @return The sender of the command. + */ + public ICommandSender getSender() + { + return sender; + } + + /** + * @return The list of added custom selectors + */ + List> getSelectors() + { + return selectors; + } + +} diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index 5aa9ee0f0..73d341930 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -22,9 +22,12 @@ package net.minecraftforge.event; import java.io.File; import java.util.EnumSet; import java.util.List; +import java.util.Map; import java.util.Random; +import com.google.common.base.Predicate; import net.minecraft.block.state.IBlockState; +import net.minecraft.command.ICommandSender; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -242,6 +245,13 @@ public class ForgeEventFactory return event.getDisplayname(); } + public static List> gatherEntitySelectors(Map map, String mainSelector, ICommandSender sender, Vec3d position) + { + EntitySelectorEvent event=new EntitySelectorEvent(map, mainSelector, sender, position); + MinecraftForge.EVENT_BUS.post(event); + return event.getSelectors(); + } + public static float fireBlockHarvesting(List drops, World world, BlockPos pos, IBlockState state, int fortune, float dropChance, boolean silkTouch, EntityPlayer player) { BlockEvent.HarvestDropsEvent event = new BlockEvent.HarvestDropsEvent(world, pos, state, fortune, dropChance, drops, player, silkTouch);