net.minecraft.world.level.entity

This commit is contained in:
Noah van der Aa
2024-12-14 15:02:14 +01:00
parent 7d70dbf927
commit 6fdbfef28e
4 changed files with 217 additions and 295 deletions

View File

@@ -0,0 +1,15 @@
--- a/net/minecraft/world/level/entity/EntityAccess.java
+++ b/net/minecraft/world/level/entity/EntityAccess.java
@@ -23,6 +_,12 @@
void setRemoved(Entity.RemovalReason removalReason);
+ // CraftBukkit start - add Bukkit remove cause
+ default void setRemoved(Entity.RemovalReason entity_removalreason, org.bukkit.event.entity.EntityRemoveEvent.Cause cause) {
+ this.setRemoved(entity_removalreason);
+ }
+ // CraftBukkit end
+
boolean shouldBeSaved();
boolean isAlwaysTicking();

View File

@@ -0,0 +1,17 @@
--- a/net/minecraft/world/level/entity/EntityLookup.java
+++ b/net/minecraft/world/level/entity/EntityLookup.java
@@ -33,6 +_,14 @@
UUID uuid = entity.getUUID();
if (this.byUuid.containsKey(uuid)) {
LOGGER.warn("Duplicate entity UUID {}: {}", uuid, entity);
+ // Paper start - extra debug info
+ if (entity instanceof net.minecraft.world.entity.Entity) {
+ final T old = this.byUuid.get(entity.getUUID());
+ if (old instanceof net.minecraft.world.entity.Entity oldCast && oldCast.getId() != entity.getId() && oldCast.valid) {
+ LOGGER.error("Overwrote an existing entity {} with {}", oldCast, entity);
+ }
+ }
+ // Paper end
} else {
this.byUuid.put(uuid, entity);
this.byId.put(entity.getId(), entity);

View File

@@ -0,0 +1,208 @@
--- a/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
+++ b/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
@@ -52,6 +_,16 @@
this.entityGetter = new LevelEntityGetterAdapter<>(this.visibleEntityStorage, this.sectionStorage);
}
+ // CraftBukkit start - add method to get all entities in chunk
+ public List<Entity> getEntities(ChunkPos chunkCoordIntPair) {
+ return this.sectionStorage.getExistingSectionsInChunk(chunkCoordIntPair.toLong()).flatMap(EntitySection::getEntities).map(entity -> (Entity) entity).collect(Collectors.toList());
+ }
+
+ public boolean isPending(long pair) {
+ return this.chunkLoadStatuses.get(pair) == ChunkLoadStatus.PENDING;
+ }
+ // CraftBukkit end
+
void removeSectionIfEmpty(long sectionKey, EntitySection<T> section) {
if (section.isEmpty()) {
this.sectionStorage.remove(sectionKey);
@@ -59,6 +_,7 @@
}
private boolean addEntityUuid(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper
if (!this.knownUuids.add(entity.getUUID())) {
LOGGER.warn("UUID of added entity already exists: {}", entity);
return false;
@@ -72,6 +_,17 @@
}
private boolean addEntity(T entity, boolean worldGenSpawned) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper
+ // Paper start - chunk system hooks
+ // I don't want to know why this is a generic type.
+ Entity entityCasted = (Entity)entity;
+ boolean wasRemoved = entityCasted.isRemoved();
+ boolean screened = ca.spottedleaf.moonrise.common.util.ChunkSystem.screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted, existing, true);
+ if ((!wasRemoved && entityCasted.isRemoved()) || !screened) {
+ // removed by callback
+ return false;
+ }
+ // Paper end - chunk system hooks
if (!this.addEntityUuid(entity)) {
return false;
} else {
@@ -109,19 +_,23 @@
}
void startTicking(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity start ticking"); // Paper
this.callbacks.onTickingStart(entity);
}
void stopTicking(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity stop ticking"); // Paper
this.callbacks.onTickingEnd(entity);
}
void startTracking(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity start tracking"); // Paper
this.visibleEntityStorage.add(entity);
this.callbacks.onTrackingStart(entity);
}
void stopTracking(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity stop tracking"); // Paper
this.callbacks.onTrackingEnd(entity);
this.visibleEntityStorage.remove(entity);
}
@@ -132,6 +_,7 @@
}
public void updateChunkStatus(ChunkPos pos, Visibility visibility) {
+ org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper
long packedChunkPos = pos.toLong();
if (visibility == Visibility.HIDDEN) {
this.chunkVisibility.remove(packedChunkPos);
@@ -165,6 +_,7 @@
}
public void ensureChunkQueuedForLoad(long chunkPosValue) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper
PersistentEntitySectionManager.ChunkLoadStatus chunkLoadStatus = this.chunkLoadStatuses.get(chunkPosValue);
if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) {
this.requestChunkLoad(chunkPosValue);
@@ -172,6 +_,11 @@
}
private boolean storeChunkSections(long chunkPosValue, Consumer<T> entityAction) {
+ // CraftBukkit start
+ return storeChunkSections(chunkPosValue, entityAction, false);
+ }
+ private boolean storeChunkSections(long chunkPosValue, Consumer<T> entityAction, boolean callEvent) {
+ // CraftBukkit end
PersistentEntitySectionManager.ChunkLoadStatus chunkLoadStatus = this.chunkLoadStatuses.get(chunkPosValue);
if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.PENDING) {
return false;
@@ -182,6 +_,7 @@
.collect(Collectors.toList());
if (list.isEmpty()) {
if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.LOADED) {
+ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, new ChunkPos(chunkPosValue), ImmutableList.of()); // CraftBukkit
this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(chunkPosValue), ImmutableList.of()));
}
@@ -190,6 +_,7 @@
this.requestChunkLoad(chunkPosValue);
return false;
} else {
+ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, new ChunkPos(i), list.stream().map(entity -> (Entity) entity).collect(Collectors.toList())); // CraftBukkit
this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(chunkPosValue), list));
list.forEach(entityAction);
return true;
@@ -198,6 +_,7 @@
}
private void requestChunkLoad(long chunkPosValue) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk load request"); // Paper
this.chunkLoadStatuses.put(chunkPosValue, PersistentEntitySectionManager.ChunkLoadStatus.PENDING);
ChunkPos chunkPos = new ChunkPos(chunkPosValue);
this.permanentStorage.loadEntities(chunkPos).thenAccept(this.loadingInbox::add).exceptionally(throwable -> {
@@ -207,7 +_,8 @@
}
private boolean processChunkUnload(long chunkPosValue) {
- boolean flag = this.storeChunkSections(chunkPosValue, entity -> entity.getPassengersAndSelf().forEach(this::unloadEntity));
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk unload process"); // Paper
+ boolean flag = this.storeChunkSections(chunkPosValue, entity -> entity.getPassengersAndSelf().forEach(this::unloadEntity), true); // CraftBukkit - add boolean for event call
if (!flag) {
return false;
} else {
@@ -217,7 +_,7 @@
}
private void unloadEntity(EntityAccess entity) {
- entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK);
+ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD); // CraftBukkit - add Bukkit remove cause
entity.setLevelCallback(EntityInLevelCallback.NULL);
}
@@ -227,14 +_,20 @@
}
private void processPendingLoads() {
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper
ChunkEntities<T> chunkEntities;
while ((chunkEntities = this.loadingInbox.poll()) != null) {
chunkEntities.getEntities().forEach(entity -> this.addEntity((T)entity, true));
this.chunkLoadStatuses.put(chunkEntities.getPos().toLong(), PersistentEntitySectionManager.ChunkLoadStatus.LOADED);
+ // CraftBukkit start - call entity load event
+ List<Entity> entities = this.getEntities(chunkEntities.getPos());
+ org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesLoadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, chunkentities.getPos(), entities);
+ // CraftBukkit end
}
}
public void tick() {
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper
this.processPendingLoads();
this.processUnloads();
}
@@ -252,6 +_,7 @@
}
public void autoSave() {
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager autosave"); // Paper
this.getAllChunksToSave().forEach(packedChunkPos -> {
boolean flag = this.chunkVisibility.get(packedChunkPos) == Visibility.HIDDEN;
if (flag) {
@@ -263,6 +_,7 @@
}
public void saveAll() {
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper
LongSet allChunksToSave = this.getAllChunksToSave();
while (!allChunksToSave.isEmpty()) {
@@ -279,7 +_,13 @@
@Override
public void close() throws IOException {
- this.saveAll();
+ // CraftBukkit start
+ this.close(true);
+ }
+
+ public void close(boolean save) throws IOException {
+ if (save) this.saveAll();
+ // CraftBukkit end
this.permanentStorage.close();
}
@@ -380,6 +_,7 @@
BlockPos blockPos = this.entity.blockPosition();
long packedSectionPos = SectionPos.asLong(blockPos);
if (packedSectionPos != this.currentSectionKey) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper
Visibility status = this.currentSection.getStatus();
if (!this.currentSection.remove(this.entity)) {
PersistentEntitySectionManager.LOGGER
@@ -427,6 +_,7 @@
@Override
public void onRemove(Entity.RemovalReason reason) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity remove"); // Paper
if (!this.currentSection.remove(this.entity)) {
PersistentEntitySectionManager.LOGGER
.warn("Entity {} wasn't found in section {} (destroying due to {})", this.entity, SectionPos.of(this.currentSectionKey), reason);