From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Tue, 3 Jun 2025 15:20:59 +0900 Subject: [PATCH] optimise NaturalSpawner#spawnForChunk diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java index c0d941af10ffe8c158dab9db40c7c5767b6cfd6e..450f17badaa3f6c8f1cdb9e6dc76828b70afe6fc 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java @@ -238,10 +238,13 @@ public final class NaturalSpawner { // Paper end - throttle failed spawn attempts ) { // Paper end - Optional per player mob spawns - BlockPos randomPosWithin = getRandomPosWithin(level, chunk); - if (randomPosWithin.getY() >= level.getMinY() + 1) { - return spawnCategoryForPosition(category, level, chunk, randomPosWithin, filter, callback, maxSpawns, trackEntity, false); // Paper - Optional per player mob spawns // Paper - throttle failed spawn attempts + // Leaf start + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + mutableRandomPosWithin(pos, level, chunk); + if (pos.getY() >= level.getMinY() + 1) { + return spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false); // Paper - Optional per player mob spawns // Paper - throttle failed spawn attempts } + // Leaf end return 0; // Paper - throttle failed spawn attempts } @@ -275,31 +278,60 @@ public final class NaturalSpawner { StructureManager structureManager = level.structureManager(); ChunkGenerator generator = level.getChunkSource().getGenerator(); int y = pos.getY(); + int posX = pos.getX(); // Leaf + int posZ = pos.getZ(); // Leaf int i = 0; // Paper - throttle failed spawn attempts - BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn + // Leaf start + if (!level.getWorldBorder().isWithinBounds(pos) || level.isOutsideBuildHeight(pos)) { + return i; + } + BlockState blockState = chunk.getPos().longKey == ChunkPos.asLong(pos) ? chunk.getBlockState(posX, y, posZ) : level.getBlockStateIfLoaded(pos); + // Leaf end if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + BlockPos.MutableBlockPos mutableBlockPos = pos instanceof BlockPos.MutableBlockPos pos2 ? pos2 : new BlockPos.MutableBlockPos(); // Leaf //int i = 0; // Paper - throttle failed spawn attempts - move up + // Leaf start + long rand = level.random.nextLong(); + int bits = 0; for (int i1 = 0; i1 < 3; i1++) { - int x = pos.getX(); - int z = pos.getZ(); - int i2 = 6; + int x = posX; + int z = posZ; MobSpawnSettings.SpawnerData spawnerData = null; SpawnGroupData spawnGroupData = null; - int ceil = Mth.ceil(level.random.nextFloat() * 4.0F); + int ceil = (int) ((rand & 0x3L) + 1L); + bits += 2; int i3 = 0; for (int i4 = 0; i4 < ceil; i4++) { - x += level.random.nextInt(6) - level.random.nextInt(6); - z += level.random.nextInt(6) - level.random.nextInt(6); + int rand1=0,rand2=0,rand3=0,rand4=0,valuesNeeded=4; + while (valuesNeeded > 0) { + if (bits > 61) { + rand = level.random.nextLong(); + bits = 0; + } + int threeBits = (int) ((rand >>> bits) & 0x7L); + bits += 3; + if (threeBits != 7 && threeBits != 6) { + switch (valuesNeeded) { + case 1 -> rand4 = threeBits; + case 2 -> rand3 = threeBits; + case 3 -> rand2 = threeBits; + case 4 -> rand1 = threeBits; + } + valuesNeeded--; + } + } + x += rand1 - rand2; + z += rand3 - rand4; + // Leaf end mutableBlockPos.set(x, y, z); double d = x + 0.5; double d1 = z + 0.5; Player nearestPlayer = level.getNearestPlayer(d, y, d1, -1.0, level.purpurConfig.mobSpawningIgnoreCreativePlayers); // Purpur - mob spawning option to ignore creative players if (nearestPlayer != null) { double d2 = nearestPlayer.distanceToSqr(d, y, d1); - if (level.isLoadedAndInBounds(mutableBlockPos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn + if (level.getWorldBorder().isWithinBounds(mutableBlockPos) && (chunk.getPos().longKey == ChunkPos.asLong(mutableBlockPos) || level.getChunkIfLoadedImmediately(mutableBlockPos.getX() >> 4, mutableBlockPos.getZ() >> 4) != null) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn // Leaf if (spawnerData == null) { Optional randomSpawnMobAt = getRandomSpawnMobAt( level, structureManager, generator, category, level.random, mutableBlockPos @@ -368,8 +400,8 @@ public final class NaturalSpawner { private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel level, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double distance) { return !(distance <= 576.0) - && !level.getSharedSpawnPos().closerToCenterThan(new Vec3(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5), 24.0) - && (Objects.equals(new ChunkPos(pos), chunk.getPos()) || level.isNaturalSpawningAllowed(pos)); + && !(level.getSharedSpawnPos().distToCenterSqr(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5) < 576.0) // Leaf + && (ChunkPos.asLong(pos) == chunk.getPos().longKey || level.isNaturalSpawningAllowed(pos)); // Leaf } // Paper start - PreCreatureSpawnEvent @@ -474,6 +506,17 @@ public final class NaturalSpawner { } } + // Leaf start + private static void mutableRandomPosWithin(BlockPos.MutableBlockPos pos1, Level level, LevelChunk chunk) { + ChunkPos pos = chunk.getPos(); + int i = pos.getMinBlockX() + level.random.nextInt(16); + int i1 = pos.getMinBlockZ() + level.random.nextInt(16); + int i2 = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i, i1) + 1; + int i3 = Mth.randomBetweenInclusive(level.random, level.getMinY(), i2); + pos1.set(i, i3, i1); + } + // Leaf end + private static BlockPos getRandomPosWithin(Level level, LevelChunk chunk) { ChunkPos pos = chunk.getPos(); int i = pos.getMinBlockX() + level.random.nextInt(16);