Skip to content

Commit

Permalink
Add mob spawn overrides
Browse files Browse the repository at this point in the history
  • Loading branch information
Malfrador committed Jan 15, 2024
1 parent 159fd9e commit bc5bcdb
Show file tree
Hide file tree
Showing 2 changed files with 273 additions and 5 deletions.
256 changes: 253 additions & 3 deletions patches/server/0005-Hephaestus.patch
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
+ }
Expand Down Expand Up @@ -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<Biome> biomeHolder;
+ public WeightedRandomList<MobSpawnSettings.SpawnerData> 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<Biome> 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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<MobSpawnSettings.SpawnerData> getRandomSpawnMobAt(ServerLevel world, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobCategory spawnGroup, RandomSource random, BlockPos pos) {
Holder<Biome> 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<MobSpawnSettings.SpawnerData> 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<MobSpawnSettings.SpawnerData> mobsAt(ServerLevel world, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobCategory spawnGroup, BlockPos pos, @Nullable Holder<Biome> 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
Expand All @@ -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
Expand Down
22 changes: 20 additions & 2 deletions test-plugin/src/main/java/de/erethon/PapyrusTestPlugin.java
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -28,6 +35,7 @@ public void onEnable() {
Main.itemLibrary.readyBehaviours();
getCommand("test").setExecutor(this);
Main.itemLibrary.enableHandler(this);
getServer().getPluginManager().registerEvents(this, this);
}

@Override
Expand All @@ -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));
}
}

0 comments on commit bc5bcdb

Please sign in to comment.