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

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