From 06d9d89f98d6ab2bc889af9ff13fa701da562622 Mon Sep 17 00:00:00 2001 From: TheMuso <9444357+TheMuso@users.noreply.github.com> Date: Sat, 6 Aug 2022 02:29:02 +1000 Subject: [PATCH] Re-add PotentialSpawns event (#8712) --- .../world/level/NaturalSpawner.java.patch | 7 +- .../event/ForgeEventFactory.java | 11 +++ .../event/level/LevelEvent.java | 87 +++++++++++++++++++ .../debug/world/PotentialSpawnsEventTest.java | 46 ++++++++++ src/test/resources/META-INF/mods.toml | 2 + 5 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 src/test/java/net/minecraftforge/debug/world/PotentialSpawnsEventTest.java diff --git a/patches/minecraft/net/minecraft/world/level/NaturalSpawner.java.patch b/patches/minecraft/net/minecraft/world/level/NaturalSpawner.java.patch index 4e2be8dbdf..1e2750ded4 100644 --- a/patches/minecraft/net/minecraft/world/level/NaturalSpawner.java.patch +++ b/patches/minecraft/net/minecraft/world/level/NaturalSpawner.java.patch @@ -4,7 +4,7 @@ import net.minecraft.world.phys.Vec3; import org.slf4j.Logger; -+// TODO: ForgeEventFactory.getPotentialSpawns, ForgeHooks.canEntitySpawn ++// TODO: ForgeHooks.canEntitySpawn public final class NaturalSpawner { private static final Logger f_46977_ = LogUtils.getLogger(); private static final int f_151589_ = 24; @@ -35,12 +35,13 @@ return; } -@@ -266,7 +_,7 @@ +@@ -266,7 +_,8 @@ } private static WeightedRandomList m_220443_(ServerLevel p_220444_, StructureManager p_220445_, ChunkGenerator p_220446_, MobCategory p_220447_, BlockPos p_220448_, @Nullable Holder p_220449_) { - return m_220455_(p_220448_, p_220444_, p_220447_, p_220445_) ? NetherFortressStructure.f_228517_ : p_220446_.m_223133_(p_220449_ != null ? p_220449_ : p_220444_.m_204166_(p_220448_), p_220445_, p_220447_, p_220448_); -+ return m_220455_(p_220448_, p_220444_, p_220447_, p_220445_) ? p_220445_.m_220521_().m_175515_(Registry.f_235725_).m_123013_(BuiltinStructures.f_209859_).m_226612_().get(MobCategory.MONSTER).f_210044_() : p_220446_.m_223133_(p_220449_ != null ? p_220449_ : p_220444_.m_204166_(p_220448_), p_220445_, p_220447_, p_220448_); ++ // Forge: Add in potential spawns, and replace hardcoded nether fortress mob list ++ return net.minecraftforge.event.ForgeEventFactory.getPotentialSpawns(p_220444_, p_220447_, p_220448_, m_220455_(p_220448_, p_220444_, p_220447_, p_220445_) ? p_220445_.m_220521_().m_175515_(Registry.f_235725_).m_123013_(BuiltinStructures.f_209859_).m_226612_().get(MobCategory.MONSTER).f_210044_() : p_220446_.m_223133_(p_220449_ != null ? p_220449_ : p_220444_.m_204166_(p_220448_), p_220445_, p_220447_, p_220448_)); } public static boolean m_220455_(BlockPos p_220456_, ServerLevel p_220457_, MobCategory p_220458_, StructureManager p_220459_) { diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index be69edf12c..4c5af112b0 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -18,9 +18,12 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.ReloadableServerResources; import net.minecraft.server.players.PlayerList; import net.minecraft.util.RandomSource; +import net.minecraft.util.random.WeightedRandomList; import net.minecraft.world.Container; +import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.entity.projectile.ThrownEnderpearl; +import net.minecraft.world.level.biome.MobSpawnSettings; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.portal.PortalShape; import net.minecraft.world.level.block.state.BlockState; @@ -801,4 +804,12 @@ public class ForgeEventFactory { MinecraftForge.EVENT_BUS.post(new TickEvent.ServerTickEvent(TickEvent.Phase.END, haveTime, server)); } + + public static WeightedRandomList getPotentialSpawns(LevelAccessor level, MobCategory category, BlockPos pos, WeightedRandomList oldList) + { + LevelEvent.PotentialSpawns event = new LevelEvent.PotentialSpawns(level, category, pos, oldList); + if (MinecraftForge.EVENT_BUS.post(event)) + return WeightedRandomList.create(); + return WeightedRandomList.create(event.getSpawnerDataList()); + } } diff --git a/src/main/java/net/minecraftforge/event/level/LevelEvent.java b/src/main/java/net/minecraftforge/event/level/LevelEvent.java index addc76d506..8749e36656 100644 --- a/src/main/java/net/minecraftforge/event/level/LevelEvent.java +++ b/src/main/java/net/minecraftforge/event/level/LevelEvent.java @@ -5,13 +5,21 @@ package net.minecraftforge.event.level; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.ProgressListener; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.biome.MobSpawnSettings; import net.minecraft.world.level.storage.ServerLevelData; import net.minecraftforge.common.ForgeInternalHandler; import net.minecraftforge.common.MinecraftForge; @@ -117,4 +125,83 @@ public class LevelEvent extends Event return settings; } } + + /** + * Fired when building a list of all possible entities that can spawn at the specified location. + * + *

If an entry is added to the list, it needs to be a globally unique instance.

+ * + * The event is called in {@link net.minecraft.world.level.NaturalSpawner#getRandomSpawnMobAt(ServerLevel, + * StructureManager, ChunkGenerator, MobCategory, RandomSource, BlockPos)}.

+ * + *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * Canceling the event will result in an empty list, meaning no entity will be spawned.

+ */ + @Cancelable + public static class PotentialSpawns extends LevelEvent + { + private final MobCategory mobcategory; + private final BlockPos pos; + private final List list; + private final List view; + + public PotentialSpawns(LevelAccessor level, MobCategory category, BlockPos pos, WeightedRandomList oldList) + { + super(level); + this.pos = pos; + this.mobcategory = category; + if (!oldList.isEmpty()) + this.list = new ArrayList<>(oldList.unwrap()); + else + this.list = new ArrayList<>(); + + this.view = Collections.unmodifiableList(list); + } + + /** + * {@return the category of the mobs in the spawn list.} + */ + public MobCategory getMobCategory() + { + return mobcategory; + } + + /** + * {@return the block position where the chosen mob will be spawned.} + */ + public BlockPos getPos() + { + return pos; + } + + /** + * {@return the list of mobs that can potentially be spawned.} + */ + public List getSpawnerDataList() + { + return view; + } + + /** + * Appends a SpawnerData entry to the spawn list. + * + * @param data SpawnerData entry to be appended to the spawn list. + */ + public void addSpawnerData(MobSpawnSettings.SpawnerData data) + { + list.add(data); + } + + /** + * Removes a SpawnerData entry from the spawn list. + * + * @param data SpawnerData entry to be removed from the spawn list. + * + * {@return {@code true} if the spawn list contained the specified element.} + */ + public boolean removeSpawnerData(MobSpawnSettings.SpawnerData data) + { + return list.remove(data); + } + } } diff --git a/src/test/java/net/minecraftforge/debug/world/PotentialSpawnsEventTest.java b/src/test/java/net/minecraftforge/debug/world/PotentialSpawnsEventTest.java new file mode 100644 index 0000000000..2881f509ef --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/world/PotentialSpawnsEventTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.debug.world; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.Difficulty; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.LevelAccessor; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.level.LevelEvent; +import net.minecraftforge.fml.common.Mod; + +/** + *

This tests net.minecraftforge.event.world.World.WorldEvent.PotentialSpawns. If ENABLED is set to true, + * this test mod uses the PotentialSpawns event to prevent mobs in the MONSTER mob category from spawning if the + * game difficulty is set to anything other than hard.

+ */ +@Mod("potentialspawnsevent_test") +public class PotentialSpawnsEventTest +{ + public static final boolean ENABLED = false; + + public PotentialSpawnsEventTest() + { + if (ENABLED) + { + MinecraftForge.EVENT_BUS.addListener(PotentialSpawnsEventTest::onlySpawnHostileMobs); + } + } + + public static void onlySpawnHostileMobs(LevelEvent.PotentialSpawns event) + { + LevelAccessor level = event.getLevel(); + BlockPos pos = event.getPos(); + Difficulty difficulty = level.getCurrentDifficultyAt(pos).getDifficulty(); + MobCategory category = event.getMobCategory(); + + if (category == MobCategory.MONSTER && difficulty != Difficulty.HARD) + { + event.setCanceled(true); + } + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index fb214dd703..5d93f73e4c 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -12,6 +12,8 @@ license="LGPL v2.1" modId="structure_modifiers_test" [[mods]] modId="fluid_type_test" +[[mods]] + modId="potentialspawnsevent_test" # LEGACY TEST CASES