From 38c1ddb52abf11c8a72fb91a104e520962d2b53a Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Tue, 24 Jun 2025 04:55:58 -0700 Subject: [PATCH] Add and use FeatureHooks.getAllEntities The ServerLevel#getAllEntities function only returns entities which are accessible. FeatureHooks#getAllEntities will return all entities, whether or not they are accessible. Use the new hook in the EntityCommand, which allows server admins to inspect entities in unloaded chunks. Use the hook as well for ticking the EntityScheduler. This fixes an issue whether unloaded entities did not have their scheduler ticked. --- .../patches/features/0004-Anti-Xray.patch | 4 ++-- .../0016-Moonrise-optimisation-patches.patch | 20 +++++++++++-------- .../io/papermc/paper/FeatureHooks.java.patch | 7 ++++++- .../server/MinecraftServer.java.patch | 2 +- .../level/entity/EntitySection.java.patch | 15 ++++++++++++++ .../entity/EntitySectionStorage.java.patch | 19 ++++++++++++++++++ .../LevelEntityGetterAdapter.java.patch | 11 ++++++++++ .../command/subcommands/EntityCommand.java | 4 ++-- 8 files changed, 68 insertions(+), 14 deletions(-) create mode 100644 paper-server/patches/sources/net/minecraft/world/level/entity/EntitySection.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/level/entity/EntitySectionStorage.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java.patch diff --git a/paper-server/patches/features/0004-Anti-Xray.patch b/paper-server/patches/features/0004-Anti-Xray.patch index 3a664e4b92..2dbce57f7d 100644 --- a/paper-server/patches/features/0004-Anti-Xray.patch +++ b/paper-server/patches/features/0004-Anti-Xray.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Anti-Xray diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java -index 55cc0dec4a88baea17f160e95d5d8316e0bb7a50..338dc0fb07cdba5f7350cca332fa3e942c622bfb 100644 +index 811a8e5141f2061a185b53b63d951646141c0c7d..33d3eb510c5844e72bbc382bd24641aae080962d 100644 --- a/io/papermc/paper/FeatureHooks.java +++ b/io/papermc/paper/FeatureHooks.java -@@ -40,20 +40,25 @@ public final class FeatureHooks { +@@ -45,20 +45,25 @@ public final class FeatureHooks { } public static LevelChunkSection createSection(final Registry biomeRegistry, final Level level, final ChunkPos chunkPos, final int chunkSection) { diff --git a/paper-server/patches/features/0016-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0016-Moonrise-optimisation-patches.patch index f3695fc529..7dc38ba475 100644 --- a/paper-server/patches/features/0016-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0016-Moonrise-optimisation-patches.patch @@ -23061,7 +23061,7 @@ index 0000000000000000000000000000000000000000..f1f72a051083b61273202cb4e67ecb11 + private SaveUtil() {} +} diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java -index 68e1e2da7a3291c6260898c90373bf21630f3351..b2b67a3b1b4620dc97a32df953d4ad47bbe5e481 100644 +index 33d3eb510c5844e72bbc382bd24641aae080962d..ccf9bd756e4841e8c0413f078842b987324aeb35 100644 --- a/io/papermc/paper/FeatureHooks.java +++ b/io/papermc/paper/FeatureHooks.java @@ -1,6 +1,9 @@ @@ -23074,8 +23074,13 @@ index 68e1e2da7a3291c6260898c90373bf21630f3351..b2b67a3b1b4620dc97a32df953d4ad47 import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.longs.LongSets; -@@ -31,12 +34,16 @@ import org.bukkit.World; - public final class FeatureHooks { +@@ -32,16 +35,20 @@ public final class FeatureHooks { + + // this includes non-accessible entities + public static Iterable getAllEntities(final net.minecraft.server.level.ServerLevel world) { +- return ((net.minecraft.world.level.entity.LevelEntityGetterAdapter)world.getEntities()).sectionStorage.getAllEntities(); ++ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup)world.getEntities()).getAllMapped(); // Paper - rewrite chunk system + } public static void setPlayerChunkUnloadDelay(final long ticks) { + ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.setUnloadDelay(ticks); // Paper - rewrite chunk system @@ -23091,7 +23096,7 @@ index 68e1e2da7a3291c6260898c90373bf21630f3351..b2b67a3b1b4620dc97a32df953d4ad47 } public static LevelChunkSection createSection(final Registry biomeRegistry, final Level level, final ChunkPos chunkPos, final int chunkSection) { -@@ -62,111 +69,58 @@ public final class FeatureHooks { +@@ -67,111 +74,58 @@ public final class FeatureHooks { } public static Set getSentChunkKeys(final ServerPlayer player) { @@ -23224,7 +23229,7 @@ index 68e1e2da7a3291c6260898c90373bf21630f3351..b2b67a3b1b4620dc97a32df953d4ad47 org.bukkit.Chunk chunk = null; for (net.minecraft.server.level.Ticket ticket : tickets) { -@@ -186,15 +140,15 @@ public final class FeatureHooks { +@@ -191,15 +145,15 @@ public final class FeatureHooks { } public static int getViewDistance(net.minecraft.server.level.ServerLevel world) { @@ -23243,7 +23248,7 @@ index 68e1e2da7a3291c6260898c90373bf21630f3351..b2b67a3b1b4620dc97a32df953d4ad47 } public static void setViewDistance(net.minecraft.server.level.ServerLevel world, int distance) { -@@ -212,35 +166,31 @@ public final class FeatureHooks { +@@ -217,35 +171,31 @@ public final class FeatureHooks { } public static void setSendViewDistance(net.minecraft.server.level.ServerLevel world, int distance) { @@ -23286,7 +23291,6 @@ index 68e1e2da7a3291c6260898c90373bf21630f3351..b2b67a3b1b4620dc97a32df953d4ad47 } } -\ No newline at end of file diff --git a/io/papermc/paper/command/subcommands/ChunkDebugCommand.java b/io/papermc/paper/command/subcommands/ChunkDebugCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..2dca7afbd93cfbb8686f336fcd3b45dd01fba0fc @@ -23862,7 +23866,7 @@ index 46de98a6bbbae48c4837e1e588ba198a363d2dde..fd3553bdc1c3cdbf6aa3dc00e0a4987f thread1 -> { DedicatedServer dedicatedServer1 = new DedicatedServer( diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index f7362a979126c5c0a581c05c0b623cf40b8f0ebd..338ef549efe82c250c74365c1c1071986920c8c9 100644 +index aea96ab1c5f2dae9f2a19126e8be314d06b99bc3..388bf752fd09745e8c470b5bca4d004708a2d82f 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -173,7 +173,7 @@ import net.minecraft.world.phys.Vec2; diff --git a/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch b/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch index 97959e16bf..6d467d774a 100644 --- a/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch +++ b/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/io/papermc/paper/FeatureHooks.java -@@ -1,0 +_,241 @@ +@@ -1,0 +_,246 @@ +package io.papermc.paper; + +import io.papermc.paper.command.PaperSubcommand; @@ -33,6 +33,11 @@ + +public final class FeatureHooks { + ++ // this includes non-accessible entities ++ public static Iterable getAllEntities(final net.minecraft.server.level.ServerLevel world) { ++ return ((net.minecraft.world.level.entity.LevelEntityGetterAdapter)world.getEntities()).sectionStorage.getAllEntities(); ++ } ++ + public static void setPlayerChunkUnloadDelay(final long ticks) { + } + diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch index c555510571..ae7e78ecfe 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -992,7 +992,7 @@ + // Paper start - Folia scheduler API + ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) org.bukkit.Bukkit.getGlobalRegionScheduler()).tick(); + getAllLevels().forEach(level -> { -+ for (final net.minecraft.world.entity.Entity entity : level.getEntities().getAll()) { ++ for (final net.minecraft.world.entity.Entity entity : io.papermc.paper.FeatureHooks.getAllEntities(level)) { + if (entity.isRemoved()) { + continue; + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySection.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySection.java.patch new file mode 100644 index 0000000000..ba9179927b --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySection.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/world/level/entity/EntitySection.java ++++ b/net/minecraft/world/level/entity/EntitySection.java +@@ -19,6 +_,12 @@ + this.storage = new ClassInstanceMultiMap<>(entityClazz); + } + ++ // Paper start - support retrieving all entities, regardless of whether they are accessible ++ public void getEntities(java.util.List into) { ++ into.addAll(this.storage); ++ } ++ // Paper end - support retrieving all entities, regardless of whether they are accessible ++ + public void add(T entity) { + this.storage.add(entity); + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySectionStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySectionStorage.java.patch new file mode 100644 index 0000000000..a6c808035b --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/EntitySectionStorage.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/level/entity/EntitySectionStorage.java ++++ b/net/minecraft/world/level/entity/EntitySectionStorage.java +@@ -34,6 +_,16 @@ + this.intialSectionVisibility = initialSectionVisibility; + } + ++ // Paper start - support retrieving all entities, regardless of whether they are accessible ++ public Iterable getAllEntities() { ++ java.util.List ret = new java.util.ArrayList<>(); ++ for (EntitySection section : this.sections.values()) { ++ section.getEntities(ret); ++ } ++ return ret; ++ } ++ // Paper end - support retrieving all entities, regardless of whether they are accessible ++ + public void forEachAccessibleNonEmptySection(AABB boundingBox, AbortableIterationConsumer> consumer) { + int sectionPosCoord = SectionPos.posToSectionCoord(boundingBox.minX - 2.0); + int sectionPosCoord1 = SectionPos.posToSectionCoord(boundingBox.minY - 4.0); diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java.patch new file mode 100644 index 0000000000..a9e2d66b72 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java ++++ b/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java +@@ -8,7 +_,7 @@ + + public class LevelEntityGetterAdapter implements LevelEntityGetter { + private final EntityLookup visibleEntities; +- private final EntitySectionStorage sectionStorage; ++ public final EntitySectionStorage sectionStorage; // Paper - public + + public LevelEntityGetterAdapter(EntityLookup visibleEntities, EntitySectionStorage sectionStorage) { + this.visibleEntities = visibleEntities; diff --git a/paper-server/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java b/paper-server/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java index bbd29bcca9..e3ddc201b3 100644 --- a/paper-server/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java +++ b/paper-server/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java @@ -1,6 +1,7 @@ package io.papermc.paper.command.subcommands; import com.google.common.collect.Maps; +import io.papermc.paper.FeatureHooks; import io.papermc.paper.command.CommandUtil; import io.papermc.paper.command.PaperSubcommand; import java.util.Collections; @@ -9,7 +10,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; - import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEvent; @@ -102,7 +102,7 @@ public final class EntityCommand implements PaperSubcommand { ServerLevel world = ((CraftWorld) bukkitWorld).getHandle(); Map nonEntityTicking = Maps.newHashMap(); ServerChunkCache chunkProviderServer = world.getChunkSource(); - world.getAllEntities().forEach(e -> { + FeatureHooks.getAllEntities(world).forEach(e -> { ResourceLocation key = EntityType.getKey(e.getType()); MutablePair> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));