From bc5bcdb060b515086df67b4bbcc147d0dd42ef24 Mon Sep 17 00:00:00 2001 From: Malfrador Date: Mon, 15 Jan 2024 14:16:26 +0100 Subject: [PATCH] Add mob spawn overrides --- patches/server/0005-Hephaestus.patch | 256 +++++++++++++++++- .../java/de/erethon/PapyrusTestPlugin.java | 22 +- 2 files changed, 273 insertions(+), 5 deletions(-) diff --git a/patches/server/0005-Hephaestus.patch b/patches/server/0005-Hephaestus.patch index 1474ebe..9f25be2 100644 --- a/patches/server/0005-Hephaestus.patch +++ b/patches/server/0005-Hephaestus.patch @@ -582,10 +582,10 @@ index 0000000000000000000000000000000000000000..f5c220a6142d60db52a9035c9c665641 +} diff --git a/src/main/java/de/erethon/hephaestus/HItemStack.java b/src/main/java/de/erethon/hephaestus/HItemStack.java new file mode 100644 -index 0000000000000000000000000000000000000000..2efd7dce31b9a1f6d37043dd34cd7c5ac0e2646e +index 0000000000000000000000000000000000000000..8dc87af8a6d65b73c1b0ca794793e4892fe93bdd --- /dev/null +++ b/src/main/java/de/erethon/hephaestus/HItemStack.java -@@ -0,0 +1,61 @@ +@@ -0,0 +1,60 @@ +package de.erethon.hephaestus; + +import net.minecraft.resources.ResourceLocation; @@ -599,7 +599,6 @@ index 0000000000000000000000000000000000000000..2efd7dce31b9a1f6d37043dd34cd7c5a + private ItemStack stack; + + public HItemStack(ItemStack stack, HItem config) { -+ LOGGER.info("Init new item stack for " + config.getId()); + this.stack = stack; + this.item = config; + } @@ -824,6 +823,116 @@ index 0000000000000000000000000000000000000000..8ef09800709175c8844fb6979708e56b + return craftItemStack.handle.hItemStack; + } +} +diff --git a/src/main/java/de/erethon/hephaestus/events/MobSpawnEntityCreateEvent.java b/src/main/java/de/erethon/hephaestus/events/MobSpawnEntityCreateEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..53d1624375afb11f487bad0b52166ebe899f97a2 +--- /dev/null ++++ b/src/main/java/de/erethon/hephaestus/events/MobSpawnEntityCreateEvent.java +@@ -0,0 +1,46 @@ ++package de.erethon.hephaestus.events; ++ ++import net.minecraft.core.BlockPos; ++import net.minecraft.core.Holder; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.world.entity.EntityType; ++import net.minecraft.world.entity.Mob; ++import net.minecraft.world.entity.SpawnGroupData; ++import net.minecraft.world.entity.player.Player; ++import net.minecraft.world.level.biome.Biome; ++import net.minecraft.world.level.biome.MobSpawnSettings; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class MobSpawnEntityCreateEvent extends Event { ++ private static final HandlerList handlers = new HandlerList(); ++ ++ public ServerLevel world; ++ public MobSpawnSettings.SpawnerData spawnerData; ++ public Mob mob; ++ public BlockPos.MutableBlockPos pos; ++ public Player nearestPlayer; ++ public SpawnGroupData data; ++ ++ public MobSpawnEntityCreateEvent(Mob mob, ServerLevel world, MobSpawnSettings.SpawnerData spawnerData, BlockPos.MutableBlockPos pos, Player player, @Nullable SpawnGroupData data) { ++ this.mob = mob; ++ this.world = world; ++ this.spawnerData = spawnerData; ++ this.pos = pos; ++ this.nearestPlayer = player; ++ this.data = data; ++ } ++ ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/de/erethon/hephaestus/events/MobSpawnSettingsEvent.java b/src/main/java/de/erethon/hephaestus/events/MobSpawnSettingsEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3827cd2200bfa3434555e973b9a6b7ea9d1ff12c +--- /dev/null ++++ b/src/main/java/de/erethon/hephaestus/events/MobSpawnSettingsEvent.java +@@ -0,0 +1,52 @@ ++package de.erethon.hephaestus.events; ++ ++import net.minecraft.core.BlockPos; ++import net.minecraft.core.Holder; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.util.RandomSource; ++import net.minecraft.util.random.WeightedRandomList; ++import net.minecraft.world.entity.MobCategory; ++import net.minecraft.world.level.StructureManager; ++import net.minecraft.world.level.biome.Biome; ++import net.minecraft.world.level.biome.MobSpawnSettings; ++import net.minecraft.world.level.chunk.ChunkGenerator; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.NotNull; ++ ++import javax.annotation.Nullable; ++import java.util.Optional; ++ ++public class MobSpawnSettingsEvent extends Event { ++ ++ private static final HandlerList handlers = new HandlerList(); ++ ++ public Holder biomeHolder; ++ public WeightedRandomList spawnerData; ++ public ServerLevel world; ++ public StructureManager structureAccessor; ++ public ChunkGenerator chunkGenerator; ++ public MobCategory spawnGroup; ++ public RandomSource random; ++ public BlockPos pos; ++ ++ public MobSpawnSettingsEvent(ServerLevel world, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobCategory spawnGroup, BlockPos pos, @Nullable Holder biomeEntry) { ++ this.biomeHolder = biomeEntry; ++ this.world = world; ++ this.structureAccessor = structureAccessor; ++ this.chunkGenerator = chunkGenerator; ++ this.spawnGroup = spawnGroup; ++ this.pos = pos; ++ this.spawnerData = null; ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} diff --git a/src/main/java/de/erethon/papyrus/ContainerLoadEvent.java b/src/main/java/de/erethon/papyrus/ContainerLoadEvent.java index e672340310a8863a627c083cbea2c08a8d6049b9..b6e1158585a4a8971a2fcc5fcea55e9d467b03e6 100644 --- a/src/main/java/de/erethon/papyrus/ContainerLoadEvent.java @@ -927,6 +1036,32 @@ index 01063c3bc672eecdf8fe1c5b5a89fbf576c940f3..949207f366aa0659c563fa123047112d } +diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java +index 7999b85b7df949e4dfcad2ca23489324ebd8a2c7..117809c39c7bf76581e122d92dce965af48e4358 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -174,7 +174,7 @@ public abstract class Mob extends LivingEntity implements Targeting { + protected void registerGoals() {} + + public static AttributeSupplier.Builder createMobAttributes() { +- return LivingEntity.createLivingAttributes().add(Attributes.FOLLOW_RANGE, 16.0D).add(Attributes.ATTACK_KNOCKBACK).add(Attributes.ATTACK_SPEED, 80.0); ++ return LivingEntity.createLivingAttributes().add(Attributes.FOLLOW_RANGE, 16.0D).add(Attributes.ATTACK_KNOCKBACK).add(Attributes.ATTACK_SPEED, 80.0).add(Attributes.ATTACK_DAMAGE, 128); + } + + protected PathNavigation createNavigation(Level world) { +@@ -1272,6 +1272,12 @@ public abstract class Mob extends LivingEntity implements Targeting { + RandomSource randomsource = world.getRandom(); + + this.getAttribute(Attributes.FOLLOW_RANGE).addPermanentModifier(new AttributeModifier("Random spawn bonus", randomsource.triangle(0.0D, 0.11485000000000001D), AttributeModifier.Operation.MULTIPLY_BASE)); ++ // Papyrus ++ this.getAttribute(Attributes.MAX_HEALTH).addPermanentModifier(new AttributeModifier("Papyrus Random spawn bonus", randomsource.triangle(0.0D, 0.33D), AttributeModifier.Operation.MULTIPLY_BASE)); ++ this.getAttribute(Attributes.ATTACK_DAMAGE).addPermanentModifier(new AttributeModifier("Papyrus Random spawn bonus", randomsource.triangle(0.0D, 0.2D), AttributeModifier.Operation.MULTIPLY_BASE)); ++ this.getAttribute(Attributes.ADV_PHYSICAL).addPermanentModifier(new AttributeModifier("Papyrus Random spawn bonus", randomsource.triangle(0.0D, 0.33D), AttributeModifier.Operation.MULTIPLY_BASE)); ++ this.getAttribute(Attributes.RES_PHYSICAL).addPermanentModifier(new AttributeModifier("Papyrus Random spawn bonus", randomsource.triangle(0.0D, 0.33D), AttributeModifier.Operation.MULTIPLY_BASE)); ++ + if (randomsource.nextFloat() < 0.05F) { + this.setLeftHanded(true); + } else { diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java index 4ab0452af6eeae9316311d473be23de9a74d9e4b..4637149278b3ab316c589a41335a595dd2e68ee9 100644 --- a/src/main/java/net/minecraft/world/item/ItemStack.java @@ -1159,6 +1294,108 @@ index 4ab0452af6eeae9316311d473be23de9a74d9e4b..4637149278b3ab316c589a41335a595d } } +diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +index 9c2d62feff1816f5729060c6192269a5b2d34153..2c3d440bb59707f1708eba1261d0b8f8c554b77f 100644 +--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java ++++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java +@@ -1,6 +1,8 @@ + package net.minecraft.world.level; + + import com.mojang.logging.LogUtils; ++import de.erethon.hephaestus.events.MobSpawnEntityCreateEvent; ++import de.erethon.hephaestus.events.MobSpawnSettingsEvent; + import it.unimi.dsi.fastutil.objects.Object2IntMap; + import it.unimi.dsi.fastutil.objects.Object2IntMaps; + import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +@@ -25,13 +27,7 @@ import net.minecraft.util.Mth; + import net.minecraft.util.RandomSource; + import net.minecraft.util.VisibleForDebug; + import net.minecraft.util.random.WeightedRandomList; +-import net.minecraft.world.entity.Entity; +-import net.minecraft.world.entity.EntityType; +-import net.minecraft.world.entity.Mob; +-import net.minecraft.world.entity.MobCategory; +-import net.minecraft.world.entity.MobSpawnType; +-import net.minecraft.world.entity.SpawnGroupData; +-import net.minecraft.world.entity.SpawnPlacements; ++import net.minecraft.world.entity.*; + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.level.biome.Biome; + import net.minecraft.world.level.biome.MobSpawnSettings; +@@ -287,8 +283,13 @@ public final class NaturalSpawner { + } + if (doSpawning == PreSpawnStatus.SUCCESS && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) { + // Paper end +- Mob entityinsentient = NaturalSpawner.getMobForSpawn(world, biomesettingsmobs_c.type); +- ++ // Papyrus start - use our spawn method ++ MobSpawnEntityCreateEvent event = getPapyrusMobForSpawn(world, biomesettingsmobs_c, blockposition_mutableblockposition, entityhuman, groupdataentity); ++ Mob entityinsentient = event.mob; ++ biomesettingsmobs_c = event.spawnerData; ++ groupdataentity = event.data; ++ blockposition_mutableblockposition = event.pos; ++ // Papyrus end + if (entityinsentient == null) { + return j; // Paper + } +@@ -401,14 +402,30 @@ public final class NaturalSpawner { + return null; + } + ++ private static MobSpawnEntityCreateEvent getPapyrusMobForSpawn(ServerLevel level, MobSpawnSettings.SpawnerData spawnerData, BlockPos.MutableBlockPos pos, Player player, @Nullable SpawnGroupData groupData) { ++ try { ++ Entity entity = spawnerData.type.create(level); ++ if (entity instanceof Mob mob) { ++ MobSpawnEntityCreateEvent event = new MobSpawnEntityCreateEvent(mob, level, spawnerData, pos, player, groupData); ++ event.callEvent(); ++ return event; ++ } ++ NaturalSpawner.LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(spawnerData.type)); ++ } catch (Exception exception) { ++ NaturalSpawner.LOGGER.warn("Failed to create mob", exception); ++ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper ++ } ++ return null; ++ } ++ + private static boolean isValidPositionForMob(ServerLevel world, Mob entity, double squaredDistance) { + return squaredDistance > (double) (entity.getType().getCategory().getDespawnDistance() * entity.getType().getCategory().getDespawnDistance()) && entity.removeWhenFarAway(squaredDistance) ? false : entity.checkSpawnRules(world, MobSpawnType.NATURAL) && entity.checkSpawnObstruction(world); + } + + private static Optional getRandomSpawnMobAt(ServerLevel world, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobCategory spawnGroup, RandomSource random, BlockPos pos) { + Holder holder = world.getBiome(pos); +- +- return spawnGroup == MobCategory.WATER_AMBIENT && holder.is(BiomeTags.REDUCED_WATER_AMBIENT_SPAWNS) && random.nextFloat() < 0.98F ? Optional.empty() : NaturalSpawner.mobsAt(world, structureAccessor, chunkGenerator, spawnGroup, pos, holder).getRandom(random); ++ Optional data = spawnGroup == MobCategory.WATER_AMBIENT && holder.is(BiomeTags.REDUCED_WATER_AMBIENT_SPAWNS) && random.nextFloat() < 0.98F ? Optional.empty() : NaturalSpawner.mobsAt(world, structureAccessor, chunkGenerator, spawnGroup, pos, holder).getRandom(random); ++ return data; + } + + private static boolean canSpawnMobAt(ServerLevel world, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobCategory spawnGroup, MobSpawnSettings.SpawnerData spawnEntry, BlockPos pos) { +@@ -416,6 +433,12 @@ public final class NaturalSpawner { + } + + private static WeightedRandomList mobsAt(ServerLevel world, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobCategory spawnGroup, BlockPos pos, @Nullable Holder biomeEntry) { ++ // Papyrus start ++ MobSpawnSettingsEvent event = new MobSpawnSettingsEvent(world, structureAccessor, chunkGenerator, spawnGroup, pos, biomeEntry); ++ event.callEvent(); ++ if (event.spawnerData != null) { ++ return event.spawnerData; ++ } + return NaturalSpawner.isInNetherFortressBounds(pos, world, spawnGroup, structureAccessor) ? NetherFortressStructure.FORTRESS_ENEMIES : chunkGenerator.getMobsAt(biomeEntry != null ? biomeEntry : world.getBiome(pos), structureAccessor, spawnGroup, pos); + } + +diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java +index efca73d4de33028cf9df944f36e51b7b50f7a4c5..e28347cf823578ac9e002332c3ac9ffd59a4bf6f 100644 +--- a/src/main/java/net/minecraft/world/level/biome/Biome.java ++++ b/src/main/java/net/minecraft/world/level/biome/Biome.java +@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList; + import com.mojang.serialization.Codec; + import com.mojang.serialization.MapCodec; + import com.mojang.serialization.codecs.RecordCodecBuilder; ++import de.erethon.hephaestus.events.MobSpawnSettingsEvent; + import it.unimi.dsi.fastutil.longs.Long2FloatLinkedOpenHashMap; + import java.util.Optional; + import javax.annotation.Nullable; diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java index e21867d3956078bb0db4ceed45e5811e9acd7377..9e1ae79ad84045933e435cc5cb08e7137dfa0790 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java @@ -1172,6 +1409,19 @@ index e21867d3956078bb0db4ceed45e5811e9acd7377..9e1ae79ad84045933e435cc5cb08e713 } public static void dropResources(BlockState state, Level world, BlockPos pos) { +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java +index a907b79fd8291a0e92db138f37239d17424188a1..aeaf6a32a06d375c3e5fd0f88c23d9503d78758a 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java +@@ -139,7 +139,7 @@ public class ChunkStatus { + }); + public static final ChunkStatus SPAWN = ChunkStatus.registerSimple("spawn", ChunkStatus.LIGHT, 0, ChunkStatus.POST_FEATURES, ChunkStatus.ChunkType.PROTOCHUNK, (chunkstatus, worldserver, chunkgenerator, list, ichunkaccess) -> { + if (!ichunkaccess.isUpgrading()) { +- chunkgenerator.spawnOriginalMobs(new WorldGenRegion(worldserver, list, chunkstatus, -1)); ++ // chunkgenerator.spawnOriginalMobs(new WorldGenRegion(worldserver, list, chunkstatus, -1)); Papyrus - disable mob spawn during chunk gen + } + + }); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index c0cb4358e013372aa880aac9e40639f865246e6b..07a373f7ccbe298e579e7db268b1662a0df5d393 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java diff --git a/test-plugin/src/main/java/de/erethon/PapyrusTestPlugin.java b/test-plugin/src/main/java/de/erethon/PapyrusTestPlugin.java index 192d9a7..bc47437 100644 --- a/test-plugin/src/main/java/de/erethon/PapyrusTestPlugin.java +++ b/test-plugin/src/main/java/de/erethon/PapyrusTestPlugin.java @@ -1,18 +1,25 @@ package de.erethon; import de.erethon.hephaestus.HItem; +import de.erethon.hephaestus.events.MobSpawnEntityCreateEvent; +import de.erethon.hephaestus.events.MobSpawnSettingsEvent; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.Main; -import org.bukkit.Bukkit; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.level.biome.MobSpawnSettings; import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; -public class PapyrusTestPlugin extends JavaPlugin implements CommandExecutor { +public class PapyrusTestPlugin extends JavaPlugin implements CommandExecutor, Listener { ResourceLocation loc = new ResourceLocation("test", "test"); HItem registered; @@ -28,6 +35,7 @@ public void onEnable() { Main.itemLibrary.readyBehaviours(); getCommand("test").setExecutor(this); Main.itemLibrary.enableHandler(this); + getServer().getPluginManager().registerEvents(this, this); } @Override @@ -36,4 +44,14 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command player.getWorld().dropItem(player.getLocation(), registered.getItem().getBukkitStack()); return true; } + + @EventHandler + public void onTest(MobSpawnEntityCreateEvent event) { + //event.mob = EntityType.PIG.create(event.world); + } + + @EventHandler + public void onTest2(MobSpawnSettingsEvent event) { + event.spawnerData = java.util.Optional.of(new MobSpawnSettings.SpawnerData(EntityType.PIG, 1, 20, 25)); + } }