
properly removed from the chunk. This could lead to dead entities accumulating in memory over time if the chunk never gets fully unloaded (as it is the case for chunks around the spawn region). The issue is that Minecraft processes the removal of these entities during the next tick, when the chunk has already switched to state INACCESSIBLE and can no longer be retrieved as usual. For the purpose of removing dead entities from their still loaded but no longer accessible chunk, this adds and uses a new method with which a chunk can be accessed without checking its current state first.
668 lines
32 KiB
Diff
668 lines
32 KiB
Diff
--- a/net/minecraft/server/WorldServer.java
|
|
+++ b/net/minecraft/server/WorldServer.java
|
|
@@ -39,6 +39,18 @@
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
+// CraftBukkit start
|
|
+import java.util.logging.Level;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.WeatherType;
|
|
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
|
+import org.bukkit.craftbukkit.util.WorldUUID;
|
|
+import org.bukkit.event.entity.CreatureSpawnEvent;
|
|
+import org.bukkit.event.server.MapInitializeEvent;
|
|
+import org.bukkit.event.weather.LightningStrikeEvent;
|
|
+import org.bukkit.event.world.TimeSkipEvent;
|
|
+// CraftBukkit end
|
|
+
|
|
public class WorldServer extends World implements GeneratorAccessSeed {
|
|
|
|
public static final BlockPosition a = new BlockPosition(100, 50, 0);
|
|
@@ -50,7 +62,7 @@
|
|
private final ChunkProviderServer chunkProvider;
|
|
boolean tickingEntities;
|
|
private final MinecraftServer server;
|
|
- public final IWorldDataServer worldDataServer;
|
|
+ public final WorldDataServer worldDataServer; // CraftBukkit - type
|
|
public boolean savingDisabled;
|
|
private boolean everyoneSleeping;
|
|
private int emptyTime;
|
|
@@ -67,8 +79,23 @@
|
|
private final StructureManager structureManager;
|
|
private final boolean Q;
|
|
|
|
- public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey<World> resourcekey, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List<MobSpawner> list, boolean flag1) {
|
|
- super(iworlddataserver, resourcekey, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i);
|
|
+
|
|
+ // CraftBukkit start
|
|
+ private int tickPosition;
|
|
+ public final Convertable.ConversionSession convertable;
|
|
+ public final UUID uuid;
|
|
+
|
|
+ public Chunk getChunkIfLoaded(int x, int z) {
|
|
+ return this.chunkProvider.getChunkAt(x, z, false);
|
|
+ }
|
|
+
|
|
+ // Add env and gen to constructor, WorldData -> WorldDataServer
|
|
+ public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey<World> resourcekey, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List<MobSpawner> list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
|
|
+ super(iworlddataserver, resourcekey, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env);
|
|
+ this.pvpMode = minecraftserver.getPVP();
|
|
+ convertable = convertable_conversionsession;
|
|
+ uuid = WorldUUID.getUUID(convertable_conversionsession.folder.toFile());
|
|
+ // CraftBukkit end
|
|
this.nextTickListBlock = new TickListServer<>(this, (block) -> {
|
|
return block == null || block.getBlockData().isAir();
|
|
}, IRegistry.BLOCK::getKey, this::b);
|
|
@@ -80,10 +107,17 @@
|
|
this.Q = flag1;
|
|
this.server = minecraftserver;
|
|
this.mobSpawners = list;
|
|
- this.worldDataServer = iworlddataserver;
|
|
+ // CraftBukkit start
|
|
+ this.worldDataServer = (WorldDataServer) iworlddataserver;
|
|
+ worldDataServer.world = this;
|
|
+ if (gen != null) {
|
|
+ chunkgenerator = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, chunkgenerator, gen);
|
|
+ }
|
|
+
|
|
this.chunkProvider = new ChunkProviderServer(this, convertable_conversionsession, minecraftserver.getDataFixer(), minecraftserver.getDefinedStructureManager(), executor, chunkgenerator, minecraftserver.getPlayerList().getViewDistance(), minecraftserver.isSyncChunkWrites(), worldloadlistener, () -> {
|
|
return minecraftserver.E().getWorldPersistentData();
|
|
});
|
|
+ // CraftBukkit end
|
|
this.portalTravelAgent = new PortalTravelAgent(this);
|
|
this.Q();
|
|
this.R();
|
|
@@ -95,14 +129,48 @@
|
|
iworlddataserver.setGameType(minecraftserver.getGamemode());
|
|
}
|
|
|
|
- this.structureManager = new StructureManager(this, minecraftserver.getSaveData().getGeneratorSettings());
|
|
+ this.structureManager = new StructureManager(this, this.worldDataServer.getGeneratorSettings()); // CraftBukkit
|
|
if (this.getDimensionManager().isCreateDragonBattle()) {
|
|
- this.dragonBattle = new EnderDragonBattle(this, minecraftserver.getSaveData().getGeneratorSettings().getSeed(), minecraftserver.getSaveData().C());
|
|
+ this.dragonBattle = new EnderDragonBattle(this, this.worldDataServer.getGeneratorSettings().getSeed(), this.worldDataServer.C()); // CraftBukkit
|
|
} else {
|
|
this.dragonBattle = null;
|
|
}
|
|
+ this.getServer().addWorld(this.getWorld()); // CraftBukkit
|
|
+ }
|
|
+
|
|
+ // CraftBukkit start
|
|
+ @Override
|
|
+ protected TileEntity getTileEntity(BlockPosition pos, boolean validate) {
|
|
+ TileEntity result = super.getTileEntity(pos, validate);
|
|
+ if (!validate || Thread.currentThread() != this.serverThread) {
|
|
+ // SPIGOT-5378: avoid deadlock, this can be called in loading logic (i.e lighting) but getType() will block on chunk load
|
|
+ return result;
|
|
+ }
|
|
+ Block type = getType(pos).getBlock();
|
|
|
|
+ if (result != null && type != Blocks.AIR) {
|
|
+ if (!result.getTileType().isValidBlock(type)) {
|
|
+ result = fixTileEntity(pos, type, result);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ private TileEntity fixTileEntity(BlockPosition pos, Block type, TileEntity found) {
|
|
+ this.getServer().getLogger().log(Level.SEVERE, "Block at {0}, {1}, {2} is {3} but has {4}" + ". "
|
|
+ + "Bukkit will attempt to fix this, but there may be additional damage that we cannot recover.", new Object[]{pos.getX(), pos.getY(), pos.getZ(), type, found});
|
|
+
|
|
+ if (type instanceof ITileEntity) {
|
|
+ TileEntity replacement = ((ITileEntity) type).createTile(this);
|
|
+ replacement.world = this;
|
|
+ this.setTileEntity(pos, replacement);
|
|
+ return replacement;
|
|
+ } else {
|
|
+ return found;
|
|
+ }
|
|
}
|
|
+ // CraftBukkit end
|
|
|
|
public void a(int i, int j, boolean flag, boolean flag1) {
|
|
this.worldDataServer.setClearWeatherTime(i);
|
|
@@ -193,6 +261,7 @@
|
|
this.rainLevel = MathHelper.a(this.rainLevel, 0.0F, 1.0F);
|
|
}
|
|
|
|
+ /* CraftBukkit start
|
|
if (this.lastRainLevel != this.rainLevel) {
|
|
this.server.getPlayerList().a((Packet) (new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.h, this.rainLevel)), this.getDimensionKey());
|
|
}
|
|
@@ -211,18 +280,47 @@
|
|
this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.h, this.rainLevel));
|
|
this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.i, this.thunderLevel));
|
|
}
|
|
+ // */
|
|
+ for (int idx = 0; idx < this.players.size(); ++idx) {
|
|
+ if (((EntityPlayer) this.players.get(idx)).world == this) {
|
|
+ ((EntityPlayer) this.players.get(idx)).tickWeather();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (flag != this.isRaining()) {
|
|
+ // Only send weather packets to those affected
|
|
+ for (int idx = 0; idx < this.players.size(); ++idx) {
|
|
+ if (((EntityPlayer) this.players.get(idx)).world == this) {
|
|
+ ((EntityPlayer) this.players.get(idx)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ for (int idx = 0; idx < this.players.size(); ++idx) {
|
|
+ if (((EntityPlayer) this.players.get(idx)).world == this) {
|
|
+ ((EntityPlayer) this.players.get(idx)).updateWeather(this.lastRainLevel, this.rainLevel, this.lastThunderLevel, this.thunderLevel);
|
|
+ }
|
|
+ }
|
|
+ // CraftBukkit end
|
|
|
|
if (this.everyoneSleeping && this.players.stream().noneMatch((entityplayer) -> {
|
|
- return !entityplayer.isSpectator() && !entityplayer.isDeeplySleeping();
|
|
+ return !entityplayer.isSpectator() && !entityplayer.isDeeplySleeping() && !entityplayer.fauxSleeping; // CraftBukkit
|
|
})) {
|
|
- this.everyoneSleeping = false;
|
|
+ // CraftBukkit start
|
|
+ long l = this.worldData.getDayTime() + 24000L;
|
|
+ TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (l - l % 24000L) - this.getDayTime());
|
|
if (this.getGameRules().getBoolean(GameRules.DO_DAYLIGHT_CYCLE)) {
|
|
- long l = this.worldData.getDayTime() + 24000L;
|
|
+ getServer().getPluginManager().callEvent(event);
|
|
+ if (!event.isCancelled()) {
|
|
+ this.setDayTime(this.getDayTime() + event.getSkipAmount());
|
|
+ }
|
|
|
|
- this.setDayTime(l - l % 24000L);
|
|
}
|
|
|
|
- this.wakeupPlayers();
|
|
+ if (!event.isCancelled()) {
|
|
+ this.everyoneSleeping = false;
|
|
+ this.wakeupPlayers();
|
|
+ }
|
|
+ // CraftBukkit end
|
|
if (this.getGameRules().getBoolean(GameRules.DO_WEATHER_CYCLE)) {
|
|
this.clearWeather();
|
|
}
|
|
@@ -244,7 +342,7 @@
|
|
this.ak();
|
|
this.ticking = false;
|
|
gameprofilerfiller.exitEnter("entities");
|
|
- boolean flag3 = !this.players.isEmpty() || !this.getForceLoadedChunks().isEmpty();
|
|
+ boolean flag3 = true || !this.players.isEmpty() || !this.getForceLoadedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
|
|
|
|
if (flag3) {
|
|
this.resetEmptyTime();
|
|
@@ -263,6 +361,7 @@
|
|
Entity entity = (Entity) entry.getValue();
|
|
Entity entity1 = entity.getVehicle();
|
|
|
|
+ /* CraftBukkit start - We prevent spawning in general, so this butchering is not needed
|
|
if (!this.server.getSpawnAnimals() && (entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal)) {
|
|
entity.die();
|
|
}
|
|
@@ -270,6 +369,7 @@
|
|
if (!this.server.getSpawnNPCs() && entity instanceof NPC) {
|
|
entity.die();
|
|
}
|
|
+ // CraftBukkit end */
|
|
|
|
gameprofilerfiller.enter("checkDespawn");
|
|
if (!entity.dead) {
|
|
@@ -344,7 +444,7 @@
|
|
}
|
|
|
|
private void wakeupPlayers() {
|
|
- ((List) this.players.stream().filter(EntityLiving::isSleeping).collect(Collectors.toList())).forEach((entityplayer) -> {
|
|
+ (this.players.stream().filter(EntityLiving::isSleeping).collect(Collectors.toList())).forEach((entityplayer) -> { // CraftBukkit - decompile error
|
|
entityplayer.wakeup(false, false);
|
|
});
|
|
}
|
|
@@ -371,14 +471,14 @@
|
|
entityhorseskeleton.t(true);
|
|
entityhorseskeleton.setAgeRaw(0);
|
|
entityhorseskeleton.setPosition((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
|
|
- this.addEntity(entityhorseskeleton);
|
|
+ this.addEntity(entityhorseskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit
|
|
}
|
|
|
|
EntityLightning entitylightning = (EntityLightning) EntityTypes.LIGHTNING_BOLT.a((World) this);
|
|
|
|
entitylightning.d(Vec3D.c((BaseBlockPosition) blockposition));
|
|
entitylightning.setEffect(flag1);
|
|
- this.addEntity(entitylightning);
|
|
+ this.strikeLightning(entitylightning, org.bukkit.event.weather.LightningStrikeEvent.Cause.WEATHER); // CraftBukkit
|
|
}
|
|
}
|
|
|
|
@@ -389,11 +489,11 @@
|
|
BiomeBase biomebase = this.getBiome(blockposition);
|
|
|
|
if (biomebase.a(this, blockposition1)) {
|
|
- this.setTypeUpdate(blockposition1, Blocks.ICE.getBlockData());
|
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, Blocks.ICE.getBlockData(), null); // CraftBukkit
|
|
}
|
|
|
|
if (flag && biomebase.b(this, blockposition)) {
|
|
- this.setTypeUpdate(blockposition, Blocks.SNOW.getBlockData());
|
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.SNOW.getBlockData(), null); // CraftBukkit
|
|
}
|
|
|
|
if (flag && this.getBiome(blockposition1).c() == BiomeBase.Precipitation.RAIN) {
|
|
@@ -440,7 +540,7 @@
|
|
protected BlockPosition a(BlockPosition blockposition) {
|
|
BlockPosition blockposition1 = this.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING, blockposition);
|
|
AxisAlignedBB axisalignedbb = (new AxisAlignedBB(blockposition1, new BlockPosition(blockposition1.getX(), this.getBuildHeight(), blockposition1.getZ()))).g(3.0D);
|
|
- List<EntityLiving> list = this.a(EntityLiving.class, axisalignedbb, (entityliving) -> {
|
|
+ List<EntityLiving> list = this.a(EntityLiving.class, axisalignedbb, (java.util.function.Predicate<EntityLiving>) (entityliving) -> { // CraftBukkit - decompile error
|
|
return entityliving != null && entityliving.isAlive() && this.e(entityliving.getChunkCoordinates());
|
|
});
|
|
|
|
@@ -469,7 +569,7 @@
|
|
while (iterator.hasNext()) {
|
|
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
|
|
|
|
- if (entityplayer.isSpectator()) {
|
|
+ if (entityplayer.isSpectator() || (entityplayer.fauxSleeping && !entityplayer.isSleeping())) { // CraftBukkit
|
|
++i;
|
|
} else if (entityplayer.isSleeping()) {
|
|
++j;
|
|
@@ -487,10 +587,22 @@
|
|
}
|
|
|
|
private void clearWeather() {
|
|
- this.worldDataServer.setWeatherDuration(0);
|
|
+ // CraftBukkit start
|
|
this.worldDataServer.setStorm(false);
|
|
- this.worldDataServer.setThunderDuration(0);
|
|
+ // If we stop due to everyone sleeping we should reset the weather duration to some other random value.
|
|
+ // Not that everyone ever manages to get the whole server to sleep at the same time....
|
|
+ if (!this.worldDataServer.hasStorm()) {
|
|
+ this.worldDataServer.setWeatherDuration(0);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
this.worldDataServer.setThundering(false);
|
|
+ // CraftBukkit start
|
|
+ // If we stop due to everyone sleeping we should reset the weather duration to some other random value.
|
|
+ // Not that everyone ever manages to get the whole server to sleep at the same time....
|
|
+ if (!this.worldDataServer.isThundering()) {
|
|
+ this.worldDataServer.setThunderDuration(0);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
public void resetEmptyTime() {
|
|
@@ -531,6 +643,7 @@
|
|
});
|
|
gameprofilerfiller.c("tickNonPassenger");
|
|
entity.tick();
|
|
+ entity.postTick(); // CraftBukkit
|
|
gameprofilerfiller.exit();
|
|
}
|
|
|
|
@@ -563,6 +676,7 @@
|
|
});
|
|
gameprofilerfiller.c("tickPassenger");
|
|
entity1.passengerTick();
|
|
+ entity1.postTick(); // CraftBukkit
|
|
gameprofilerfiller.exit();
|
|
}
|
|
|
|
@@ -619,6 +733,7 @@
|
|
ChunkProviderServer chunkproviderserver = this.getChunkProvider();
|
|
|
|
if (!flag1) {
|
|
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit
|
|
if (iprogressupdate != null) {
|
|
iprogressupdate.a(new ChatMessage("menu.savingLevel"));
|
|
}
|
|
@@ -630,11 +745,19 @@
|
|
|
|
chunkproviderserver.save(flag);
|
|
}
|
|
+
|
|
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
|
|
+ WorldServer worldserver1 = this;
|
|
+
|
|
+ worldDataServer.a(worldserver1.getWorldBorder().t());
|
|
+ worldDataServer.setCustomBossEvents(this.server.getBossBattleCustomData().save());
|
|
+ convertable.a(this.server.customRegistry, this.worldDataServer, this.server.getPlayerList().save());
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
private void aj() {
|
|
if (this.dragonBattle != null) {
|
|
- this.server.getSaveData().a(this.dragonBattle.a());
|
|
+ this.worldDataServer.a(this.dragonBattle.a()); // CraftBukkit
|
|
}
|
|
|
|
this.getChunkProvider().getWorldPersistentData().a();
|
|
@@ -695,11 +818,24 @@
|
|
|
|
@Override
|
|
public boolean addEntity(Entity entity) {
|
|
- return this.addEntity0(entity);
|
|
+ // CraftBukkit start
|
|
+ return this.addEntity0(entity, CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
|
|
+ return this.addEntity0(entity, reason);
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
public boolean addEntitySerialized(Entity entity) {
|
|
- return this.addEntity0(entity);
|
|
+ // CraftBukkit start
|
|
+ return this.addEntitySerialized(entity, CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
+ }
|
|
+
|
|
+ public boolean addEntitySerialized(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
|
|
+ return this.addEntity0(entity, reason);
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
public void addEntityTeleport(Entity entity) {
|
|
@@ -749,13 +885,18 @@
|
|
this.registerEntity(entityplayer);
|
|
}
|
|
|
|
- private boolean addEntity0(Entity entity) {
|
|
+ // CraftBukkit start
|
|
+ private boolean addEntity0(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {
|
|
if (entity.dead) {
|
|
- WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getName(entity.getEntityType()));
|
|
+ // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getName(entity.getEntityType())); // CraftBukkit
|
|
return false;
|
|
} else if (this.isUUIDTaken(entity)) {
|
|
return false;
|
|
} else {
|
|
+ if (!CraftEventFactory.doEntityAddEventCalling(this, entity, spawnReason)) {
|
|
+ return false;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
IChunkAccess ichunkaccess = this.getChunkAt(MathHelper.floor(entity.locX() / 16.0D), MathHelper.floor(entity.locZ() / 16.0D), ChunkStatus.FULL, entity.attachedToPlayer);
|
|
|
|
if (!(ichunkaccess instanceof Chunk)) {
|
|
@@ -784,7 +925,7 @@
|
|
if (entity1 == null) {
|
|
return false;
|
|
} else {
|
|
- WorldServer.LOGGER.warn("Trying to add entity with duplicated UUID {}. Existing {}#{}, new: {}#{}", uuid, EntityTypes.getName(entity1.getEntityType()), entity1.getId(), EntityTypes.getName(entity.getEntityType()), entity.getId());
|
|
+ // WorldServer.LOGGER.warn("Trying to add entity with duplicated UUID {}. Existing {}#{}, new: {}#{}", uuid, EntityTypes.getName(entity1.getEntityType()), entity1.getId(), EntityTypes.getName(entity.getEntityType()), entity.getId()); // CraftBukkit
|
|
return true;
|
|
}
|
|
}
|
|
@@ -813,10 +954,16 @@
|
|
}
|
|
|
|
public boolean addAllEntitiesSafely(Entity entity) {
|
|
+ // CraftBukkit start
|
|
+ return this.addAllEntitiesSafely(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
+ }
|
|
+
|
|
+ public boolean addAllEntitiesSafely(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
|
|
+ // CraftBukkit end
|
|
if (entity.recursiveStream().anyMatch(this::isUUIDTaken)) {
|
|
return false;
|
|
} else {
|
|
- this.addAllEntities(entity);
|
|
+ this.addAllEntities(entity, reason); // CraftBukkit
|
|
return true;
|
|
}
|
|
}
|
|
@@ -867,10 +1014,17 @@
|
|
}
|
|
|
|
this.getScoreboard().a(entity);
|
|
+ // CraftBukkit start - SPIGOT-5278
|
|
+ if (entity instanceof EntityDrowned) {
|
|
+ this.navigators.remove(((EntityDrowned) entity).navigationWater);
|
|
+ this.navigators.remove(((EntityDrowned) entity).navigationLand);
|
|
+ } else
|
|
+ // CraftBukkit end
|
|
if (entity instanceof EntityInsentient) {
|
|
this.navigators.remove(((EntityInsentient) entity).getNavigation());
|
|
}
|
|
|
|
+ entity.valid = false; // CraftBukkit
|
|
}
|
|
|
|
private void registerEntity(Entity entity) {
|
|
@@ -891,9 +1045,16 @@
|
|
|
|
this.entitiesByUUID.put(entity.getUniqueID(), entity);
|
|
this.getChunkProvider().addEntity(entity);
|
|
+ // CraftBukkit start - SPIGOT-5278
|
|
+ if (entity instanceof EntityDrowned) {
|
|
+ this.navigators.add(((EntityDrowned) entity).navigationWater);
|
|
+ this.navigators.add(((EntityDrowned) entity).navigationLand);
|
|
+ } else
|
|
+ // CraftBukkit end
|
|
if (entity instanceof EntityInsentient) {
|
|
this.navigators.add(((EntityInsentient) entity).getNavigation());
|
|
}
|
|
+ entity.valid = true; // CraftBukkit
|
|
}
|
|
|
|
}
|
|
@@ -909,7 +1070,7 @@
|
|
}
|
|
|
|
private void removeEntityFromChunk(Entity entity) {
|
|
- IChunkAccess ichunkaccess = this.getChunkAt(entity.chunkX, entity.chunkZ, ChunkStatus.FULL, false);
|
|
+ IChunkAccess ichunkaccess = chunkProvider.getChunkUnchecked(entity.chunkX, entity.chunkZ); // CraftBukkit - SPIGOT-5228: getChunkAt won't find the entity's chunk if it has already been unloaded (i.e. if it switched to state INACCESSIBLE).
|
|
|
|
if (ichunkaccess instanceof Chunk) {
|
|
((Chunk) ichunkaccess).b(entity);
|
|
@@ -923,10 +1084,33 @@
|
|
this.everyoneSleeping();
|
|
}
|
|
|
|
+ // CraftBukkit start
|
|
+ public boolean strikeLightning(Entity entitylightning) {
|
|
+ return this.strikeLightning(entitylightning, LightningStrikeEvent.Cause.UNKNOWN);
|
|
+ }
|
|
+
|
|
+ public boolean strikeLightning(Entity entitylightning, LightningStrikeEvent.Cause cause) {
|
|
+ LightningStrikeEvent lightning = new LightningStrikeEvent(this.getWorld(), (org.bukkit.entity.LightningStrike) entitylightning.getBukkitEntity(), cause);
|
|
+ this.getServer().getPluginManager().callEvent(lightning);
|
|
+
|
|
+ if (lightning.isCancelled()) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return this.addEntity(entitylightning);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
@Override
|
|
public void a(int i, BlockPosition blockposition, int j) {
|
|
Iterator iterator = this.server.getPlayerList().getPlayers().iterator();
|
|
|
|
+ // CraftBukkit start
|
|
+ EntityHuman entityhuman = null;
|
|
+ Entity entity = this.getEntity(i);
|
|
+ if (entity instanceof EntityHuman) entityhuman = (EntityHuman) entity;
|
|
+ // CraftBukkit end
|
|
+
|
|
while (iterator.hasNext()) {
|
|
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
|
|
|
|
@@ -935,6 +1119,12 @@
|
|
double d1 = (double) blockposition.getY() - entityplayer.locY();
|
|
double d2 = (double) blockposition.getZ() - entityplayer.locZ();
|
|
|
|
+ // CraftBukkit start
|
|
+ if (entityhuman != null && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) {
|
|
+ continue;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
|
|
entityplayer.playerConnection.sendPacket(new PacketPlayOutBlockBreakAnimation(i, blockposition, j));
|
|
}
|
|
@@ -995,10 +1185,20 @@
|
|
|
|
@Override
|
|
public Explosion createExplosion(@Nullable Entity entity, @Nullable DamageSource damagesource, @Nullable ExplosionDamageCalculator explosiondamagecalculator, double d0, double d1, double d2, float f, boolean flag, Explosion.Effect explosion_effect) {
|
|
+ // CraftBukkit start
|
|
+ Explosion explosion = super.createExplosion(entity, damagesource, explosiondamagecalculator, d0, d1, d2, f, flag, explosion_effect);
|
|
+
|
|
+ if (explosion.wasCanceled) {
|
|
+ return explosion;
|
|
+ }
|
|
+
|
|
+ /* Remove
|
|
Explosion explosion = new Explosion(this, entity, damagesource, explosiondamagecalculator, d0, d1, d2, f, flag, explosion_effect);
|
|
|
|
explosion.a();
|
|
explosion.a(false);
|
|
+ */
|
|
+ // CraftBukkit end - TODO: Check if explosions are still properly implemented
|
|
if (explosion_effect == Explosion.Effect.NONE) {
|
|
explosion.clearBlocks();
|
|
}
|
|
@@ -1063,13 +1263,20 @@
|
|
}
|
|
|
|
public <T extends ParticleParam> int a(T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6) {
|
|
- PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(t0, false, d0, d1, d2, (float) d3, (float) d4, (float) d5, (float) d6, i);
|
|
+ // CraftBukkit - visibility api support
|
|
+ return sendParticles(null, t0, d0, d1, d2, i, d3, d4, d5, d6, false);
|
|
+ }
|
|
+
|
|
+ public <T extends ParticleParam> int sendParticles(EntityPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) {
|
|
+ PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(t0, force, d0, d1, d2, (float) d3, (float) d4, (float) d5, (float) d6, i);
|
|
+ // CraftBukkit end
|
|
int j = 0;
|
|
|
|
for (int k = 0; k < this.players.size(); ++k) {
|
|
EntityPlayer entityplayer = (EntityPlayer) this.players.get(k);
|
|
+ if (sender != null && !entityplayer.getBukkitEntity().canSee(sender.getBukkitEntity())) continue; // CraftBukkit
|
|
|
|
- if (this.a(entityplayer, false, d0, d1, d2, packetplayoutworldparticles)) {
|
|
+ if (this.a(entityplayer, force, d0, d1, d2, packetplayoutworldparticles)) { // CraftBukkit
|
|
++j;
|
|
}
|
|
}
|
|
@@ -1111,7 +1318,7 @@
|
|
|
|
@Nullable
|
|
public BlockPosition a(StructureGenerator<?> structuregenerator, BlockPosition blockposition, int i, boolean flag) {
|
|
- return !this.server.getSaveData().getGeneratorSettings().shouldGenerateMapFeatures() ? null : this.getChunkProvider().getChunkGenerator().findNearestMapFeature(this, structuregenerator, blockposition, i, flag);
|
|
+ return !this.worldDataServer.getGeneratorSettings().shouldGenerateMapFeatures() ? null : this.getChunkProvider().getChunkGenerator().findNearestMapFeature(this, structuregenerator, blockposition, i, flag); // CraftBukkit
|
|
}
|
|
|
|
@Nullable
|
|
@@ -1149,7 +1356,13 @@
|
|
@Override
|
|
public WorldMap a(String s) {
|
|
return (WorldMap) this.getMinecraftServer().E().getWorldPersistentData().b(() -> {
|
|
- return new WorldMap(s);
|
|
+ // CraftBukkit start
|
|
+ // We only get here when the data file exists, but is not a valid map
|
|
+ WorldMap newMap = new WorldMap(s);
|
|
+ MapInitializeEvent event = new MapInitializeEvent(newMap.mapView);
|
|
+ Bukkit.getServer().getPluginManager().callEvent(event);
|
|
+ return newMap;
|
|
+ // CraftBukkit end
|
|
}, s);
|
|
}
|
|
|
|
@@ -1460,6 +1673,11 @@
|
|
@Override
|
|
public void update(BlockPosition blockposition, Block block) {
|
|
if (!this.isDebugWorld()) {
|
|
+ // CraftBukkit start
|
|
+ if (populating) {
|
|
+ return;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
this.applyPhysics(blockposition, block);
|
|
}
|
|
|
|
@@ -1474,12 +1692,12 @@
|
|
}
|
|
|
|
public boolean isFlatWorld() {
|
|
- return this.server.getSaveData().getGeneratorSettings().isFlatWorld();
|
|
+ return this.worldDataServer.getGeneratorSettings().isFlatWorld(); // CraftBukkit
|
|
}
|
|
|
|
@Override
|
|
public long getSeed() {
|
|
- return this.server.getSaveData().getGeneratorSettings().getSeed();
|
|
+ return this.worldDataServer.getGeneratorSettings().getSeed(); // CraftBukkit
|
|
}
|
|
|
|
@Nullable
|
|
@@ -1499,9 +1717,9 @@
|
|
|
|
@VisibleForTesting
|
|
public String F() {
|
|
- return String.format("players: %s, entities: %d [%s], block_entities: %d [%s], block_ticks: %d, fluid_ticks: %d, chunk_source: %s", this.players.size(), this.entitiesById.size(), a((Collection) this.entitiesById.values(), (entity) -> {
|
|
+ return String.format("players: %s, entities: %d [%s], block_entities: %d [%s], block_ticks: %d, fluid_ticks: %d, chunk_source: %s", this.players.size(), this.entitiesById.size(), a(this.entitiesById.values(), (entity) -> { // CraftBukkit - decompile error
|
|
return IRegistry.ENTITY_TYPE.getKey(entity.getEntityType());
|
|
- }), this.tileEntityListTick.size(), a((Collection) this.tileEntityListTick, (tileentity) -> {
|
|
+ }), this.tileEntityListTick.size(), a(this.tileEntityListTick, (tileentity) -> { // CraftBukkit - decompile error
|
|
return IRegistry.BLOCK_ENTITY_TYPE.getKey(tileentity.getTileType());
|
|
}), this.getBlockTickList().a(), this.getFluidTickList().a(), this.P());
|
|
}
|
|
@@ -1509,7 +1727,7 @@
|
|
private static <T> String a(Collection<T> collection, Function<T, MinecraftKey> function) {
|
|
try {
|
|
Object2IntOpenHashMap<MinecraftKey> object2intopenhashmap = new Object2IntOpenHashMap();
|
|
- Iterator iterator = collection.iterator();
|
|
+ Iterator<T> iterator = collection.iterator(); // CraftBukkit - decompile error
|
|
|
|
while (iterator.hasNext()) {
|
|
T t0 = iterator.next();
|
|
@@ -1518,7 +1736,8 @@
|
|
object2intopenhashmap.addTo(minecraftkey, 1);
|
|
}
|
|
|
|
- return (String) object2intopenhashmap.object2IntEntrySet().stream().sorted(Comparator.comparing(it.unimi.dsi.fastutil.objects.Object2IntMap.Entry::getIntValue).reversed()).limit(5L).map((it_unimi_dsi_fastutil_objects_object2intmap_entry) -> {
|
|
+ // CraftBukkit - decompile error
|
|
+ return (String) object2intopenhashmap.object2IntEntrySet().stream().sorted(Comparator.comparing(it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<MinecraftKey>::getIntValue).reversed()).limit(5L).map((it_unimi_dsi_fastutil_objects_object2intmap_entry) -> {
|
|
return it_unimi_dsi_fastutil_objects_object2intmap_entry.getKey() + ":" + it_unimi_dsi_fastutil_objects_object2intmap_entry.getIntValue();
|
|
}).collect(Collectors.joining(","));
|
|
} catch (Exception exception) {
|
|
@@ -1527,16 +1746,32 @@
|
|
}
|
|
|
|
public static void a(WorldServer worldserver) {
|
|
+ // CraftBukkit start
|
|
+ WorldServer.a(worldserver, null);
|
|
+ }
|
|
+
|
|
+ public static void a(WorldServer worldserver, Entity entity) {
|
|
+ // CraftBukkit end
|
|
BlockPosition blockposition = WorldServer.a;
|
|
int i = blockposition.getX();
|
|
int j = blockposition.getY() - 2;
|
|
int k = blockposition.getZ();
|
|
|
|
+ // CraftBukkit start
|
|
+ org.bukkit.craftbukkit.util.BlockStateListPopulator blockList = new org.bukkit.craftbukkit.util.BlockStateListPopulator(worldserver);
|
|
BlockPosition.b(i - 2, j + 1, k - 2, i + 2, j + 3, k + 2).forEach((blockposition1) -> {
|
|
- worldserver.setTypeUpdate(blockposition1, Blocks.AIR.getBlockData());
|
|
+ blockList.setTypeAndData(blockposition1, Blocks.AIR.getBlockData(), 3);
|
|
});
|
|
BlockPosition.b(i - 2, j, k - 2, i + 2, j, k + 2).forEach((blockposition1) -> {
|
|
- worldserver.setTypeUpdate(blockposition1, Blocks.OBSIDIAN.getBlockData());
|
|
+ blockList.setTypeAndData(blockposition1, Blocks.OBSIDIAN.getBlockData(), 3);
|
|
});
|
|
+ org.bukkit.World bworld = worldserver.getWorld();
|
|
+ org.bukkit.event.world.PortalCreateEvent portalEvent = new org.bukkit.event.world.PortalCreateEvent((List<org.bukkit.block.BlockState>) (List) blockList.getList(), bworld, (entity == null) ? null : entity.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.END_PLATFORM);
|
|
+
|
|
+ worldserver.getServer().getPluginManager().callEvent(portalEvent);
|
|
+ if (!portalEvent.isCancelled()) {
|
|
+ blockList.updateList();
|
|
+ }
|
|
+ // CraftBukkit end
|
|
}
|
|
}
|