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.
This commit is contained in:
Spottedleaf
2025-06-24 04:55:58 -07:00
parent 46b4b0b8d5
commit 38c1ddb52a
8 changed files with 68 additions and 14 deletions

View File

@@ -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<Biome> biomeRegistry, final Level level, final ChunkPos chunkPos, final int chunkSection) {

View File

@@ -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<Entity> getAllEntities(final net.minecraft.server.level.ServerLevel world) {
- return ((net.minecraft.world.level.entity.LevelEntityGetterAdapter<Entity>)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<Biome> 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<Long> 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;

View File

@@ -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<Entity> getAllEntities(final net.minecraft.server.level.ServerLevel world) {
+ return ((net.minecraft.world.level.entity.LevelEntityGetterAdapter<Entity>)world.getEntities()).sectionStorage.getAllEntities();
+ }
+
+ public static void setPlayerChunkUnloadDelay(final long ticks) {
+ }
+

View File

@@ -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;
+ }

View File

@@ -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<T> 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);
}

View File

@@ -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<T> getAllEntities() {
+ java.util.List<T> ret = new java.util.ArrayList<>();
+ for (EntitySection<T> 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<EntitySection<T>> consumer) {
int sectionPosCoord = SectionPos.posToSectionCoord(boundingBox.minX - 2.0);
int sectionPosCoord1 = SectionPos.posToSectionCoord(boundingBox.minY - 4.0);

View File

@@ -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<T extends EntityAccess> implements LevelEntityGetter<T> {
private final EntityLookup<T> visibleEntities;
- private final EntitySectionStorage<T> sectionStorage;
+ public final EntitySectionStorage<T> sectionStorage; // Paper - public
public LevelEntityGetterAdapter(EntityLookup<T> visibleEntities, EntitySectionStorage<T> sectionStorage) {
this.visibleEntities = visibleEntities;

View File

@@ -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<ResourceLocation, Integer> nonEntityTicking = Maps.newHashMap();
ServerChunkCache chunkProviderServer = world.getChunkSource();
world.getAllEntities().forEach(e -> {
FeatureHooks.getAllEntities(world).forEach(e -> {
ResourceLocation key = EntityType.getKey(e.getType());
MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));