package net.minecraft.world.level; import com.google.common.collect.Maps; import it.unimi.dsi.fastutil.longs.Long2ObjectFunction; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import java.util.List; import java.util.Map; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.MobCategory; public class LocalMobCapCalculator { private final Long2ObjectMap> playersNearChunk = new Long2ObjectOpenHashMap<>(); private final Map playerMobCounts = Maps.newHashMap(); private final ChunkMap chunkMap; public LocalMobCapCalculator(ChunkMap chunkMap) { this.chunkMap = chunkMap; } private List getPlayersNear(ChunkPos pos) { return this.playersNearChunk .computeIfAbsent(pos.toLong(), (Long2ObjectFunction>)(l -> this.chunkMap.getPlayersCloseForSpawning(pos))); } public void addMob(ChunkPos pos, MobCategory category) { for (ServerPlayer serverPlayer : this.getPlayersNear(pos)) { ((LocalMobCapCalculator.MobCounts)this.playerMobCounts.computeIfAbsent(serverPlayer, serverPlayerx -> new LocalMobCapCalculator.MobCounts())).add(category); } } public boolean canSpawn(MobCategory category, ChunkPos pos) { for (ServerPlayer serverPlayer : this.getPlayersNear(pos)) { LocalMobCapCalculator.MobCounts mobCounts = (LocalMobCapCalculator.MobCounts)this.playerMobCounts.get(serverPlayer); if (mobCounts == null || mobCounts.canSpawn(category)) { return true; } } return false; } static class MobCounts { private final Object2IntMap counts = new Object2IntOpenHashMap<>(MobCategory.values().length); public void add(MobCategory category) { this.counts.computeInt(category, (mobCategory, integer) -> integer == null ? 1 : integer + 1); } public boolean canSpawn(MobCategory category) { return this.counts.getOrDefault(category, 0) < category.getMaxInstancesPerChunk(); } } }