From 0f8ea6bde880d5c28b271d69467071e45eb9e484 Mon Sep 17 00:00:00 2001 From: quentin452 <42176772+quentin452@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:35:58 +0100 Subject: [PATCH] MixinPatchSpawnerAnimals : fix a large bottleneck fix a large bottleneck on modpacks caused by Entity Counter by making a thread for it --- .../common/core/MixinPatchSpawnerAnimals.java | 39 +------ .../vanilla/CreatureCountTask.java | 107 ++++++++++++++++++ 2 files changed, 109 insertions(+), 37 deletions(-) create mode 100644 src/main/java/fr/iamacat/optimizationsandtweaks/utilsformods/vanilla/CreatureCountTask.java diff --git a/src/main/java/fr/iamacat/optimizationsandtweaks/mixins/common/core/MixinPatchSpawnerAnimals.java b/src/main/java/fr/iamacat/optimizationsandtweaks/mixins/common/core/MixinPatchSpawnerAnimals.java index f9a2b9b6..f7fbfeb2 100644 --- a/src/main/java/fr/iamacat/optimizationsandtweaks/mixins/common/core/MixinPatchSpawnerAnimals.java +++ b/src/main/java/fr/iamacat/optimizationsandtweaks/mixins/common/core/MixinPatchSpawnerAnimals.java @@ -4,7 +4,6 @@ import fr.iamacat.optimizationsandtweaks.utils.agrona.collections.Object2ObjectHashMap; import net.minecraft.block.Block; import net.minecraft.block.material.Material; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EnumCreatureType; import net.minecraft.entity.player.EntityPlayer; @@ -18,6 +17,8 @@ import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Unique; +import static fr.iamacat.optimizationsandtweaks.utilsformods.vanilla.CreatureCountTask.*; + @Mixin(value = SpawnerAnimals.class, priority = 999) public class MixinPatchSpawnerAnimals { @@ -38,10 +39,6 @@ protected static ChunkPosition func_151350_a(World world, int chunkX, int chunkZ return new ChunkPosition(x, y, z); } - - @Unique - private static Object2ObjectHashMap optimizationsAndTweaks$eligibleChunksForSpawning = new Object2ObjectHashMap(); - /** * @author * @reason @@ -70,38 +67,6 @@ public static boolean canCreatureTypeSpawnAtLocation(EnumCreatureType creatureTy return blockMaterial.isLiquid() && blockBelowMaterial.isLiquid() && !isNormalCubeAbove; } - @Unique - private static boolean optimizationsAndTweaks$canCreatureSpawnOnLand(EnumCreatureType creatureType, World world, int x, int y, int z, Block block, Block blockAbove) { - if (!World.doesBlockHaveSolidTopSurface(world, x, y - 1, z)) { - return false; - } - boolean isPeacefulCreature = creatureType.getPeacefulCreature(); - boolean isAnimal = creatureType.getAnimal(); - if ((!isPeacefulCreature || isAnimal) && optimizationsAndTweaks$shouldSpawnCreature(creatureType, world, optimizationsAndTweaks$eligibleChunksForSpawning)) { - for (int spawnAttempt = 0; spawnAttempt < creatureType.getMaxNumberOfCreature(); spawnAttempt++) { - if (block != Blocks.bedrock && !blockAbove.isNormalCube() && !blockAbove.getMaterial().isLiquid()) { - return true; - } - } - } - return false; - } - - @Unique - private static boolean optimizationsAndTweaks$shouldSpawnCreature(EnumCreatureType creatureType, World world, Object2ObjectHashMap eligibleChunks) { - int creatureCount = 0; - for (Object entity : world.loadedEntityList) { - if (creatureType.getCreatureClass().isInstance(entity)) { - ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(MathHelper.floor_double(((Entity) entity).posX) >> 4, MathHelper.floor_double(((Entity) entity).posZ) >> 4); - Boolean isChunkEligible = eligibleChunks.get(chunkCoord); - if (isChunkEligible != null && isChunkEligible) { - creatureCount++; - } - } - } - return creatureCount <= creatureType.getMaxNumberOfCreature() * eligibleChunks.size() / 256; - } - /** * @author iamacatfr * @reason optimize findChunksForSpawning diff --git a/src/main/java/fr/iamacat/optimizationsandtweaks/utilsformods/vanilla/CreatureCountTask.java b/src/main/java/fr/iamacat/optimizationsandtweaks/utilsformods/vanilla/CreatureCountTask.java new file mode 100644 index 00000000..01d3b93c --- /dev/null +++ b/src/main/java/fr/iamacat/optimizationsandtweaks/utilsformods/vanilla/CreatureCountTask.java @@ -0,0 +1,107 @@ +package fr.iamacat.optimizationsandtweaks.utilsformods.vanilla; + +import fr.iamacat.optimizationsandtweaks.utils.agrona.collections.Object2ObjectHashMap; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.init.Blocks; +import net.minecraft.util.MathHelper; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; + +import java.util.Iterator; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; + +public class CreatureCountTask implements Runnable { + public static final Object2ObjectHashMap optimizationsAndTweaks$eligibleChunksForSpawning = new Object2ObjectHashMap(); + private static final Thread countThread = new Thread(new CreatureCountTask(), "CreatureCountThread"); + private static boolean threadStarted = false; + + private final EnumCreatureType creatureType; + private final World world; + private final Object2ObjectHashMap eligibleChunks; + private final AtomicInteger result; + + private CreatureCountTask() { + this.creatureType = null; + this.world = null; + this.eligibleChunks = null; + this.result = null; + } + + public CreatureCountTask(EnumCreatureType creatureType, World world, Object2ObjectHashMap eligibleChunks, AtomicInteger result) { + this.creatureType = creatureType; + this.world = world; + this.eligibleChunks = eligibleChunks; + this.result = result; + } + + @Override + public void run() { + int totalCreatureCount = 0; + int maxCreatureCount = optimizationsAndTweaks$getMaxCreatureCount(creatureType, eligibleChunks); + Iterator entityIterator = world.loadedEntityList.iterator(); + Class creatureClass = Objects.requireNonNull(creatureType.getCreatureClass()); + + while (entityIterator.hasNext() && totalCreatureCount < maxCreatureCount) { + Object entity = entityIterator.next(); + if (creatureClass.isInstance(entity)) { + double entityPosX = ((Entity) entity).posX; + double entityPosZ = ((Entity) entity).posZ; + int chunkX = MathHelper.floor_double(entityPosX) >> 4; + int chunkZ = MathHelper.floor_double(entityPosZ) >> 4; + ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(chunkX, chunkZ); + Boolean isChunkEligible = eligibleChunks.get(chunkCoord); + if (isChunkEligible != null && isChunkEligible) { + ++totalCreatureCount; + } + } + } + + assert result != null; + result.set(totalCreatureCount); + } + + private static int optimizationsAndTweaks$getMaxCreatureCount(EnumCreatureType creatureType, Object2ObjectHashMap eligibleChunks) { + return creatureType.getMaxNumberOfCreature() * eligibleChunks.size() / 256; + } + + public int getTotalCreatureCount() { + assert result != null; + return result.get(); + } + + public static boolean optimizationsAndTweaks$shouldSpawnCreature(EnumCreatureType creatureType, World world, Object2ObjectHashMap eligibleChunks) { + if (!threadStarted) { + countThread.start(); + threadStarted = true; + } + + try { + countThread.join(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + int totalCreatureCount = new CreatureCountTask(creatureType, world, eligibleChunks, new AtomicInteger()).getTotalCreatureCount(); + int maxCreatureCount = optimizationsAndTweaks$getMaxCreatureCount(creatureType, eligibleChunks); + return totalCreatureCount <= maxCreatureCount; + } + + public static boolean optimizationsAndTweaks$canCreatureSpawnOnLand(EnumCreatureType creatureType, World world, int x, int y, int z, Block block, Block blockAbove) { + if (!World.doesBlockHaveSolidTopSurface(world, x, y - 1, z)) { + return false; + } + boolean isPeacefulCreature = creatureType.getPeacefulCreature(); + boolean isAnimal = creatureType.getAnimal(); + if ((!isPeacefulCreature || isAnimal) && optimizationsAndTweaks$shouldSpawnCreature(creatureType, world, optimizationsAndTweaks$eligibleChunksForSpawning)) { + for (int spawnAttempt = 0; spawnAttempt < creatureType.getMaxNumberOfCreature(); spawnAttempt++) { + if (block != Blocks.bedrock && !blockAbove.isNormalCube() && !blockAbove.getMaterial().isLiquid()) { + return true; + } + } + } + return false; + } +}