SPIGOT-6547: Chunk#getEntities() doesn't return all entities immediately after chunk load
By: DerFrZocker <derrieple@gmail.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import com.google.common.base.Predicates;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.core.BlockPosition;
|
||||
import net.minecraft.core.IRegistry;
|
||||
@@ -23,12 +24,12 @@ import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.DataPaletteBlock;
|
||||
import net.minecraft.world.level.chunk.IChunkAccess;
|
||||
import net.minecraft.world.level.chunk.NibbleArray;
|
||||
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
||||
import net.minecraft.world.level.levelgen.HeightMap;
|
||||
import net.minecraft.world.level.levelgen.SeededRandom;
|
||||
import net.minecraft.world.level.lighting.LightEngine;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
@@ -56,6 +57,13 @@ public class CraftChunk implements Chunk {
|
||||
z = getHandle().getPos().z;
|
||||
}
|
||||
|
||||
public CraftChunk(WorldServer worldServer, int x, int z) {
|
||||
this.weakChunk = new WeakReference<>(null);
|
||||
this.worldServer = worldServer;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return worldServer.getWorld();
|
||||
@@ -109,11 +117,35 @@ public class CraftChunk implements Chunk {
|
||||
getWorld().getChunkAt(x, z); // Transient load for this tick
|
||||
}
|
||||
|
||||
Location location = new Location(null, 0, 0, 0);
|
||||
return getWorld().getEntities().stream().filter((entity) -> {
|
||||
entity.getLocation(location);
|
||||
return location.getBlockX() >> 4 == this.x && location.getBlockZ() >> 4 == this.z;
|
||||
}).toArray(Entity[]::new);
|
||||
PersistentEntitySectionManager<net.minecraft.world.entity.Entity> entityManager = getCraftWorld().getHandle().entityManager;
|
||||
long pair = ChunkCoordIntPair.pair(x, z);
|
||||
|
||||
if (entityManager.a(pair)) { // PAIL rename isEntitiesLoaded
|
||||
return entityManager.getEntities(new ChunkCoordIntPair(x, z)).stream()
|
||||
.map(net.minecraft.world.entity.Entity::getBukkitEntity)
|
||||
.filter(Objects::nonNull).toArray(Entity[]::new);
|
||||
}
|
||||
|
||||
entityManager.b(pair); // Start entity loading
|
||||
|
||||
// now we wait until the entities are loaded,
|
||||
// the converting from NBT to entity object is done on the main Thread which is why we wait
|
||||
getCraftWorld().getHandle().getMinecraftServer().awaitTasks(() -> {
|
||||
boolean status = entityManager.a(pair);
|
||||
// only execute inbox if our entities are not present
|
||||
if (status) {
|
||||
return true;
|
||||
}
|
||||
// tick loading inbox, which loads the created entities to the world
|
||||
// (if present)
|
||||
entityManager.tick();
|
||||
// check if our entities are loaded
|
||||
return entityManager.a(pair);
|
||||
});
|
||||
|
||||
return entityManager.getEntities(new ChunkCoordIntPair(x, z)).stream()
|
||||
.map(net.minecraft.world.entity.Entity::getBukkitEntity)
|
||||
.filter(Objects::nonNull).toArray(Entity[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,6 +56,7 @@ import net.minecraft.world.inventory.ContainerMerchant;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.context.ItemActionContext;
|
||||
import net.minecraft.world.level.ChunkCoordIntPair;
|
||||
import net.minecraft.world.level.Explosion;
|
||||
import net.minecraft.world.level.GeneratorAccess;
|
||||
import net.minecraft.world.level.World;
|
||||
@@ -75,6 +76,7 @@ import org.bukkit.Statistic.Type;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.craftbukkit.CraftChunk;
|
||||
import org.bukkit.craftbukkit.CraftLootTable;
|
||||
import org.bukkit.craftbukkit.CraftRaid;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
@@ -219,6 +221,8 @@ import org.bukkit.event.raid.RaidTriggerEvent;
|
||||
import org.bukkit.event.server.ServerListPingEvent;
|
||||
import org.bukkit.event.vehicle.VehicleCreateEvent;
|
||||
import org.bukkit.event.weather.LightningStrikeEvent;
|
||||
import org.bukkit.event.world.EntitiesLoadEvent;
|
||||
import org.bukkit.event.world.EntitiesUnloadEvent;
|
||||
import org.bukkit.event.world.LootGenerateEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
@@ -1643,4 +1647,15 @@ public class CraftEventFactory {
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
public static void callEntitiesLoadEvent(World world, ChunkCoordIntPair coords, List<Entity> entities) {
|
||||
List<org.bukkit.entity.Entity> bukkitEntities = Collections.unmodifiableList(entities.stream().map(Entity::getBukkitEntity).collect(Collectors.toList()));
|
||||
EntitiesLoadEvent event = new EntitiesLoadEvent(new CraftChunk((WorldServer) world, coords.x, coords.z), bukkitEntities);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
}
|
||||
public static void callEntitiesUnloadEvent(World world, ChunkCoordIntPair coords, List<Entity> entities) {
|
||||
List<org.bukkit.entity.Entity> bukkitEntities = Collections.unmodifiableList(entities.stream().map(Entity::getBukkitEntity).collect(Collectors.toList()));
|
||||
EntitiesUnloadEvent event = new EntitiesUnloadEvent(new CraftChunk((WorldServer) world, coords.x, coords.z), bukkitEntities);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user