From 2ab46851492008eb57e166fd292619192f3f7b39 Mon Sep 17 00:00:00 2001 From: Sara Freimer Date: Tue, 22 Feb 2022 18:12:06 -0500 Subject: [PATCH] Add VanillaGameEvent to allow for globally listening to vanilla's GameEvents (#8472) --- .../server/level/ServerLevel.java.patch | 8 ++ .../net/minecraftforge/common/ForgeHooks.java | 7 ++ .../event/VanillaGameEvent.java | 89 +++++++++++++++++++ .../debug/VanillaGameEventTest.java | 68 ++++++++++++++ src/test/resources/META-INF/mods.toml | 2 + 5 files changed, 174 insertions(+) create mode 100644 src/main/java/net/minecraftforge/event/VanillaGameEvent.java create mode 100644 src/test/java/net/minecraftforge/debug/VanillaGameEventTest.java diff --git a/patches/minecraft/net/minecraft/server/level/ServerLevel.java.patch b/patches/minecraft/net/minecraft/server/level/ServerLevel.java.patch index f66a7934dc..1ce8a5561f 100644 --- a/patches/minecraft/net/minecraft/server/level/ServerLevel.java.patch +++ b/patches/minecraft/net/minecraft/server/level/ServerLevel.java.patch @@ -198,6 +198,14 @@ this.f_8548_.m_6846_().m_11241_(p_8689_, p_8690_.m_20185_(), p_8690_.m_20186_(), p_8690_.m_20189_(), p_8693_ > 1.0F ? (double)(16.0F * p_8693_) : 16.0D, this.m_46472_(), new ClientboundSoundEntityPacket(p_8691_, p_8692_, p_8690_, p_8693_, p_8694_)); } +@@ -837,6 +_,7 @@ + } + + public void m_142346_(@Nullable Entity p_143268_, GameEvent p_143269_, BlockPos p_143270_) { ++ if (net.minecraftforge.common.ForgeHooks.onVanillaGameEvent(this, p_143268_, p_143269_, p_143270_)) + this.m_151513_(p_143268_, p_143269_, p_143270_, p_143269_.m_157827_()); + } + @@ -882,6 +_,7 @@ public Explosion m_7703_(@Nullable Entity p_8653_, @Nullable DamageSource p_8654_, @Nullable ExplosionDamageCalculator p_8655_, double p_8656_, double p_8657_, double p_8658_, float p_8659_, boolean p_8660_, Explosion.BlockInteraction p_8661_) { diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index b0859492bc..032dfd63ab 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -69,6 +69,7 @@ import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.item.*; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.storage.WorldData; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.LootTable; @@ -136,6 +137,7 @@ import net.minecraftforge.event.DifficultyChangeEvent; import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.ItemAttributeModifierEvent; import net.minecraftforge.event.ServerChatEvent; +import net.minecraftforge.event.VanillaGameEvent; import net.minecraftforge.event.entity.EntityAttributeCreationEvent; import net.minecraftforge.event.entity.EntityAttributeModificationEvent; import net.minecraftforge.event.entity.EntityEvent; @@ -427,6 +429,11 @@ public class ForgeHooks return event.getEntityItem(); } + public static boolean onVanillaGameEvent(Level level, @Nullable Entity cause, GameEvent vanillaEvent, BlockPos position) + { + return !MinecraftForge.EVENT_BUS.post(new VanillaGameEvent(level, cause, vanillaEvent, position)); + } + @Nullable public static Component onServerChatEvent(ServerGamePacketListenerImpl net, String raw, Component comp) { diff --git a/src/main/java/net/minecraftforge/event/VanillaGameEvent.java b/src/main/java/net/minecraftforge/event/VanillaGameEvent.java new file mode 100644 index 0000000000..1f2a5cc0d9 --- /dev/null +++ b/src/main/java/net/minecraftforge/event/VanillaGameEvent.java @@ -0,0 +1,89 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2022. + * + * 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 javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; + +/** + * VanillaGameEvent is fired on the server whenever one of Vanilla's {@link GameEvent GameEvents} fire.
+ *
+ * This allows for listening to Vanilla's events in a more structured and global way that is not tied to needing a block entity listener.
+ *
+ * This event is fired on the {@link MinecraftForge#EVENT_BUS}.
+ *
+ * Cancel this event to prevent Vanilla from posting the {@link GameEvent} to all nearby {@link net.minecraft.world.level.gameevent.GameEventListener GameEventListeners}. + **/ +@Cancelable +public class VanillaGameEvent extends Event +{ + private final Level level; + @Nullable + private final Entity cause; + private final GameEvent vanillaEvent; + private final BlockPos position; + + public VanillaGameEvent(Level level, @Nullable Entity cause, GameEvent vanillaEvent, BlockPos position) + { + this.level = level; + this.cause = cause; + this.vanillaEvent = vanillaEvent; + this.position = position; + } + + /** + * @return The level the Vanilla {@link GameEvent} occurred. + */ + public Level getLevel() + { + return level; + } + + /** + * @return The entity that was the source or "cause" of the {@link GameEvent}. + */ + @Nullable + public Entity getCause() + { + return cause; + } + + /** + * @return The Vanilla event. + */ + public GameEvent getVanillaEvent() + { + return vanillaEvent; + } + + /** + * @return The position the event took place at. This may be a block or the block position of the entity targeted. + */ + public BlockPos getEventPosition() + { + return position; + } +} diff --git a/src/test/java/net/minecraftforge/debug/VanillaGameEventTest.java b/src/test/java/net/minecraftforge/debug/VanillaGameEventTest.java new file mode 100644 index 0000000000..f8cd1946cc --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/VanillaGameEventTest.java @@ -0,0 +1,68 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2022. + * + * 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.debug; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.VanillaGameEvent; +import net.minecraftforge.fml.common.Mod; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Tests {@link VanillaGameEvent} by listening for and printing out any uses of shears in the overworld. + */ +@Mod(VanillaGameEventTest.MODID) +public class VanillaGameEventTest +{ + + static final String MODID = "vanilla_game_event_test"; + + private static final boolean ENABLED = true; + + private static final Logger LOGGER = LogManager.getLogger(); + + public VanillaGameEventTest() + { + if (!ENABLED) return; + + MinecraftForge.EVENT_BUS.addListener(this::vanillaEvent); + } + + public void vanillaEvent(VanillaGameEvent event) + { + if (event.getVanillaEvent() == GameEvent.SHEAR && event.getLevel().dimension() == Level.OVERWORLD) + { + Entity cause = event.getCause(); + if (cause == null) + { + //One case this will be fired is when a dispenser shears an entity like a sheep + LOGGER.info("Target at {} in the overworld was sheared.", event.getEventPosition()); + } + else + { + //This will be fired if a player shears an entity like a sheep or carves a block like a pumpkin + LOGGER.info("{} sheared a target at {} in the overworld.", cause, event.getEventPosition()); + } + } + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index fec19f8103..940683172d 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -16,6 +16,8 @@ license="LGPL v2.1" modId="block_place_event_test" [[mods]] modId="slipperiness_test" +[[mods]] + modId="vanilla_game_event_test" [[mods]] modId="custom_slime_block_test" [[mods]]