package net.minecraft.server; import co.aikar.timings.Timings; import io.akarin.server.core.AkarinAsyncExecutor; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFutureTask; import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import java.util.function.BooleanSupplier; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; // CraftBukkit start import java.util.logging.Level; import org.bukkit.WeatherType; import org.bukkit.block.BlockState; import org.bukkit.craftbukkit.util.HashTreeSet; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.weather.LightningStrikeEvent; // CraftBukkit end public class WorldServer extends World implements IAsyncTaskHandler { private static final Logger a = LogManager.getLogger(); boolean hasPhysicsEvent = true; // Paper private final MinecraftServer server; public EntityTracker tracker; private final PlayerChunkMap manager; public final Map entitiesByUUID = Maps.newHashMap(); // Paper public boolean savingDisabled; private boolean J; private int emptyTime; private final PortalTravelAgent portalTravelAgent; private final SpawnerCreature spawnerCreature = new SpawnerCreature(); private final TickListServer nextTickListBlock; private final TickListServer nextTickListFluid; protected final VillageSiege siegeManager; ObjectLinkedOpenHashSet d; private boolean P; // CraftBukkit start public final DimensionManager dimension; private static Throwable getAddToWorldStackTrace(Entity entity) { return new Throwable(entity + " Added to world at " + new java.util.Date()); } // Add env and gen to constructor public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, PersistentCollection persistentcollection, WorldData worlddata, DimensionManager dimensionmanager, MethodProfiler methodprofiler, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) { super(idatamanager, persistentcollection, worlddata, DimensionManager.a(env.getId()).e(), methodprofiler, false, gen, env); this.dimension = dimensionmanager; this.pvpMode = minecraftserver.getPVP(); worlddata.world = this; // CraftBukkit end this.nextTickListBlock = new TickListServer<>(this, (block) -> { return block == null || block.getBlockData().isAir(); }, IRegistry.BLOCK::getKey, IRegistry.BLOCK::getOrDefault, this::b, "Blocks"); // Paper - timings this.nextTickListFluid = new TickListServer<>(this, (fluidtype) -> { return fluidtype == null || fluidtype == FluidTypes.EMPTY; }, IRegistry.FLUID::getKey, IRegistry.FLUID::getOrDefault, this::a, "Fluids"); // Paper - timings this.siegeManager = new VillageSiege(this); this.d = new ObjectLinkedOpenHashSet(); this.server = minecraftserver; this.tracker = new EntityTracker(this); this.manager = new PlayerChunkMap(this); this.worldProvider.a((World) this); this.chunkProvider = this.r(); this.portalTravelAgent = new org.bukkit.craftbukkit.CraftTravelAgent(this); // CraftBukkit this.P(); this.Q(); this.getWorldBorder().a(minecraftserver.au()); MCUtil.scheduleAsyncTask(() -> this.getChunkProvider().chunkLoader.getPersistentStructureLegacy(worldProvider.getDimensionManager(), worldMaps)); // Paper } public WorldServer i_() { String s = PersistentVillage.a(this.worldProvider); PersistentVillage persistentvillage = (PersistentVillage) this.a(DimensionManager.OVERWORLD, PersistentVillage::new, s); if (persistentvillage == null) { this.villages = new PersistentVillage(this); this.a(DimensionManager.OVERWORLD, s, (PersistentBase) this.villages); } else { this.villages = persistentvillage; this.villages.a((World) this); } if (getServer().getScoreboardManager() == null) { // CraftBukkit PersistentScoreboard persistentscoreboard = (PersistentScoreboard) this.a(DimensionManager.OVERWORLD, PersistentScoreboard::new, "scoreboard"); if (persistentscoreboard == null) { persistentscoreboard = new PersistentScoreboard(); this.a(DimensionManager.OVERWORLD, "scoreboard", (PersistentBase) persistentscoreboard); } persistentscoreboard.a((Scoreboard) this.server.getScoreboard()); this.server.getScoreboard().a((Runnable) (new RunnableSaveScoreboard(persistentscoreboard))); } // CraftBukkit this.getWorldBorder().setCenter(this.worldData.B(), this.worldData.C()); this.getWorldBorder().setDamageAmount(this.worldData.H()); this.getWorldBorder().setDamageBuffer(this.worldData.G()); this.getWorldBorder().setWarningDistance(this.worldData.I()); this.getWorldBorder().setWarningTime(this.worldData.J()); if (this.worldData.E() > 0L) { this.getWorldBorder().transitionSizeBetween(this.worldData.D(), this.worldData.F(), this.worldData.E()); } else { this.getWorldBorder().setSize(this.worldData.D()); } // CraftBukkit start if (generator != null) { getWorld().getPopulators().addAll(generator.getDefaultPopulators(getWorld())); } // CraftBukkit end return this; } // CraftBukkit start @Override public TileEntity getTileEntity(BlockPosition pos) { TileEntity result = super.getTileEntity(pos); Block type = getType(pos).getBlock(); if (type == Blocks.CHEST || type == Blocks.TRAPPED_CHEST) { // Spigot if (!(result instanceof TileEntityChest)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.FURNACE) { if (!(result instanceof TileEntityFurnace)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.DROPPER) { if (!(result instanceof TileEntityDropper)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.DISPENSER) { if (!(result instanceof TileEntityDispenser)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.JUKEBOX) { if (!(result instanceof TileEntityJukeBox)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.SPAWNER) { if (!(result instanceof TileEntityMobSpawner)) { result = fixTileEntity(pos, type, result); } } else if ((type == Blocks.SIGN) || (type == Blocks.WALL_SIGN)) { if (!(result instanceof TileEntitySign)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.ENDER_CHEST) { if (!(result instanceof TileEntityEnderChest)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.BREWING_STAND) { if (!(result instanceof TileEntityBrewingStand)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.BEACON) { if (!(result instanceof TileEntityBeacon)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.HOPPER) { if (!(result instanceof TileEntityHopper)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.ENCHANTING_TABLE) { if (!(result instanceof TileEntityEnchantTable)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.END_PORTAL) { if (!(result instanceof TileEntityEnderPortal)) { result = fixTileEntity(pos, type, result); } } else if (type instanceof BlockSkullAbstract) { if (!(result instanceof TileEntitySkull)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.DAYLIGHT_DETECTOR) { if (!(result instanceof TileEntityLightDetector)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.COMPARATOR) { if (!(result instanceof TileEntityComparator)) { result = fixTileEntity(pos, type, result); } }else if (type instanceof BlockBannerAbstract) { if (!(result instanceof TileEntityBanner)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.STRUCTURE_BLOCK) { if (!(result instanceof TileEntityStructure)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.END_GATEWAY) { if (!(result instanceof TileEntityEndGateway)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.COMMAND_BLOCK) { if (!(result instanceof TileEntityCommand)) { result = fixTileEntity(pos, type, result); } } else if (type == Blocks.STRUCTURE_BLOCK) { if (!(result instanceof TileEntityStructure)) { result = fixTileEntity(pos, type, result); } } else if (type instanceof BlockBed) { if (!(result instanceof TileEntityBed)) { result = fixTileEntity(pos, type, result); } } // Paper Start - add TE fix checks for shulkers, see nms.BlockShulkerBox else if (type instanceof BlockShulkerBox) { if (!(result instanceof TileEntityShulkerBox)) { result = fixTileEntity(pos, type, result); } } // Paper end 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).a(this); replacement.world = this; this.setTileEntity(pos, replacement); return replacement; } else { this.getServer().getLogger().severe("Don't know how to fix for this type... Can't do anything! :("); return found; } } // CraftBukkit end public void doTick(BooleanSupplier booleansupplier) { this.P = true; super.doTick(booleansupplier); // Akarin start /* if (this.getWorldData().isHardcore() && this.getDifficulty() != EnumDifficulty.HARD) { this.getWorldData().setDifficulty(EnumDifficulty.HARD); } */ // Akarin end this.chunkProvider.getChunkGenerator().getWorldChunkManager().tick(); if (this.everyoneDeeplySleeping()) { // Akarin start /* if (this.getGameRules().getBoolean("doDaylightCycle")) { long i = this.worldData.getDayTime() + 24000L; this.worldData.setDayTime(i - i % 24000L); } */ // Akarin end this.i(); } //this.methodProfiler.enter(* // Akarin - remove caller // CraftBukkit start - Only call spawner if we have players online and the world allows for mobs or animals long time = this.worldData.getTime(); if (this.getGameRules().getBoolean("doMobSpawning") && this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES && (this.allowMonsters || this.allowAnimals) && (this instanceof WorldServer && this.players.size() > 0)) { timings.mobSpawn.startTimingUnsafe(); // Spigot this.spawnerCreature.a(this, this.allowMonsters && (this.ticksPerMonsterSpawns != 0 && time % this.ticksPerMonsterSpawns == 0L), this.allowAnimals && (this.ticksPerAnimalSpawns != 0 && time % this.ticksPerAnimalSpawns == 0L), this.worldData.getTime() % 400L == 0L); this.getChunkProvider().a(this, this.allowMonsters && (this.ticksPerMonsterSpawns != 0 && time % this.ticksPerMonsterSpawns == 0L), this.allowAnimals && (this.ticksPerAnimalSpawns != 0 && time % this.ticksPerAnimalSpawns == 0L)); timings.mobSpawn.stopTimingUnsafe(); // Spigot // CraftBukkit end } timings.doChunkUnload.startTimingUnsafe(); // Spigot // Akarin //this.methodProfiler.exitEnter("chunkSource"); // Akarin - remove caller this.chunkProvider.unloadChunks(booleansupplier); int j = this.a(1.0F); if (j != this.c()) { this.c(j); } this.worldData.setTime(this.worldData.getTime() + 1L); if (this.getGameRules().getBoolean("doDaylightCycle")) { this.worldData.setDayTime(this.worldData.getDayTime() + 1L); } timings.doChunkUnload.stopTimingUnsafe(); // Spigot // Akarin //this.methodProfiler.exitEnter("tickPending"); // Akarin - remove caller timings.scheduledBlocks.startTimingUnsafe(); // Paper // Akarin this.q(); timings.scheduledBlocks.stopTimingUnsafe(); // Paper // Akarin //this.methodProfiler.exitEnter("tickBlocks"); // Akarin - remove caller timings.chunkTicks.startTimingUnsafe(); // Paper // Akarin this.n_(); timings.chunkTicks.stopTimingUnsafe(); // Paper // Akarin //this.methodProfiler.exitEnter("chunkMap"); // Akarin - remove caller timings.doChunkMap.startTimingUnsafe(); // Spigot // Akarin this.manager.flush(); timings.doChunkMap.stopTimingUnsafe(); // Spigot // Akarin //this.methodProfiler.exitEnter("village"); // Akarin - remove caller timings.doVillages.startTimingUnsafe(); // Spigot // Akarin this.villages.tick(); this.siegeManager.a(); timings.doVillages.stopTimingUnsafe(); // Spigot // Akarin //this.methodProfiler.exitEnter("portalForcer"); // Akarin - remove caller timings.doPortalForcer.startTimingUnsafe(); // Spigot // Akarin this.portalTravelAgent.a(this.getTime()); timings.doPortalForcer.stopTimingUnsafe(); // Spigot // Akarin //this.methodProfiler.exit(); // Akarin - remove caller timings.doSounds.startTimingUnsafe(); // Spigot // Akarin this.an(); timings.doSounds.stopTimingUnsafe(); // Spigot // Akarin this.P = false; timings.doChunkGC.startTimingUnsafe();// Spigot // Akarin this.getWorld().processChunkGC(); // CraftBukkit timings.doChunkGC.stopTimingUnsafe(); // Spigot // Akarin } public boolean j_() { return this.P; } @Nullable public BiomeBase.BiomeMeta getBiomeMetaAt(EnumCreatureType enumcreaturetype, BlockPosition blockposition) { return a(enumcreaturetype, blockposition); } // Akarin @Nullable public BiomeBase.BiomeMeta a(EnumCreatureType enumcreaturetype, BlockPosition blockposition) { List list = this.getChunkProvider().a(enumcreaturetype, blockposition); return list.isEmpty() ? null : (BiomeBase.BiomeMeta) WeightedRandom.a(this.random, list); } public boolean isBiomeMetaValidAt(EnumCreatureType enumcreaturetype, BiomeBase.BiomeMeta biomebase_biomemeta, BlockPosition blockposition) { return this.a(enumcreaturetype, biomebase_biomemeta, blockposition); } // Akarin public boolean a(EnumCreatureType enumcreaturetype, BiomeBase.BiomeMeta biomebase_biomemeta, BlockPosition blockposition) { List list = this.getChunkProvider().a(enumcreaturetype, blockposition); return list != null && !list.isEmpty() ? list.contains(biomebase_biomemeta) : false; } public void everyoneSleeping() { this.J = false; if (!this.players.isEmpty()) { int i = 0; int j = 0; Iterator iterator = this.players.iterator(); while (iterator.hasNext()) { EntityHuman entityhuman = (EntityHuman) iterator.next(); if (entityhuman.isSpectator()) { ++i; } else if (entityhuman.isSleeping() || entityhuman.fauxSleeping) { ++j; } } this.J = j > 0 && j >= this.players.size() - i; } } public ScoreboardServer getScoreboard() { return this.server.getScoreboard(); } protected void i() { this.J = false; List list = (List) this.players.stream().filter(EntityHuman::isSleeping).collect(Collectors.toList()); Iterator iterator = list.iterator(); while (iterator.hasNext()) { EntityHuman entityhuman = (EntityHuman) iterator.next(); entityhuman.a(false, false, true); } // Akarin start /* if (this.getGameRules().getBoolean("doWeatherCycle")) { this.b(); } */ // Akarin end } public void clearWeather() { this.b(); } // Akarin - OBFHLPER private void b() { // CraftBukkit start this.worldData.setStorm(false); // 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.worldData.hasStorm()) { this.worldData.setWeatherDuration(0); } // CraftBukkit end this.worldData.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.worldData.isThundering()) { this.worldData.setThunderDuration(0); } // CraftBukkit end } public boolean everyoneDeeplySleeping() { if (this.J && !this.isClientSide) { Iterator iterator = this.players.iterator(); // CraftBukkit - This allows us to assume that some people are in bed but not really, allowing time to pass in spite of AFKers boolean foundActualSleepers = false; EntityHuman entityhuman; do { if (!iterator.hasNext()) { return foundActualSleepers; } entityhuman = (EntityHuman) iterator.next(); // CraftBukkit start if (entityhuman.isDeeplySleeping()) { foundActualSleepers = true; } } while (!entityhuman.isSpectator() || entityhuman.isDeeplySleeping() || entityhuman.fauxSleeping); // CraftBukkit end return false; } else { return false; } } public boolean isChunkLoaded(int i, int j, boolean flag) { return this.a(i, j); } public boolean a(int i, int j) { return this.getChunkProvider().isLoaded(i, j); } public void randomLightUpdates() { this.l(); } // Akarin - OBFHELPER protected void l() { //this.methodProfiler.enter(* // Akarin - remove caller if (spigotConfig.randomLightUpdates && !this.players.isEmpty()) { // Spigot int i = ThreadLocalRandom.current().nextInt(this.players.size()); // Akarin - ThreadLocalRandom EntityHuman entityhuman = (EntityHuman) this.players.get(i); if (entityhuman == null) return; int j = MathHelper.floor(entityhuman.locX) + this.random.nextInt(11) - 5; int k = MathHelper.floor(entityhuman.locY) + this.random.nextInt(11) - 5; int l = MathHelper.floor(entityhuman.locZ) + this.random.nextInt(11) - 5; this.r(new BlockPosition(j, k, l)); } //this.methodProfiler.exit(); // Akarin - remove caller } protected void n_() { //this.l(); // Akarin if (this.worldData.getType() == WorldType.DEBUG_ALL_BLOCK_STATES) { Iterator iterator = this.manager.b(); while (iterator.hasNext()) { ((Chunk) iterator.next()).d(false); } } else { int i = this.getGameRules().c("randomTickSpeed"); boolean flag = this.isRaining(); boolean flag1 = this.Y(); //this.methodProfiler.enter(* // Akarin - remove caller for (Iterator iterator1 = this.manager.b(); iterator1.hasNext(); /*this.methodProfiler.exit()*/) { // Akarin - remove caller //this.methodProfiler.enter(* // Akarin - remove caller Chunk chunk = (Chunk) iterator1.next(); int j = chunk.locX * 16; int k = chunk.locZ * 16; //this.methodProfiler.exitEnter("checkNextLight"); // Akarin - remove caller AkarinAsyncExecutor.scheduleAsyncTask(chunk::x); // Akarin //this.methodProfiler.exitEnter("tickChunk"); // Akarin - remove caller chunk.d(false); if ( !chunk.areNeighborsLoaded( 1 ) ) continue; // Spigot //this.methodProfiler.exitEnter("thunder"); // Akarin - remove caller int l; BlockPosition blockposition; if (!this.paperConfig.disableThunder && flag && flag1 && this.random.nextInt(100000) == 0) { // Paper - Disable thunder this.m = this.m * 3 + 1013904223; l = this.m >> 2; blockposition = this.a(new BlockPosition(j + (l & 15), 0, k + (l >> 8 & 15))); if (this.isRainingAt(blockposition)) { DifficultyDamageScaler difficultydamagescaler = this.getDamageScaler(blockposition); boolean flag2 = this.getGameRules().getBoolean("doMobSpawning") && this.random.nextDouble() < (double) difficultydamagescaler.b() * paperConfig.skeleHorseSpawnChance; // Paper if (flag2) { EntityHorseSkeleton entityhorseskeleton = EntityTypes.SKELETON_HORSE.create(this); // Paper entityhorseskeleton.s(true); entityhorseskeleton.setAgeRaw(0); entityhorseskeleton.setPosition((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()); this.addEntity(entityhorseskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit } this.strikeLightning(new EntityLightning(this, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, flag2), org.bukkit.event.weather.LightningStrikeEvent.Cause.WEATHER); // CraftBukkit } } //this.methodProfiler.exitEnter("iceandsnow"); // Akarin - remove caller if (!this.paperConfig.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow this.m = this.m * 3 + 1013904223; l = this.m >> 2; blockposition = this.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING, new BlockPosition(j + (l & 15), 0, k + (l >> 8 & 15))); BlockPosition blockposition1 = blockposition.down(); BiomeBase biomebase = this.getBiome(blockposition); if (biomebase.a((IWorldReader) this, blockposition1)) { org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, Blocks.ICE.getBlockData(), null); // CraftBukkit } if (flag && biomebase.b(this, blockposition)) { org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.SNOW.getBlockData(), null); // CraftBukkit } if (flag && this.getBiome(blockposition1).c() == BiomeBase.Precipitation.RAIN) { this.getType(blockposition1).getBlock().c(this, blockposition1); } } //this.methodProfiler.exitEnter("tickBlocks"); // Akarin - remove caller timings.chunkTicksBlocks.startTimingUnsafe(); // Paper if (i > 0) { ChunkSection[] achunksection = chunk.getSections(); int i1 = achunksection.length; for (int j1 = 0; j1 < i1; ++j1) { ChunkSection chunksection = achunksection[j1]; if (chunksection != Chunk.a && chunksection.b()) { for (int k1 = 0; k1 < i; ++k1) { this.m = this.m * 3 + 1013904223; int l1 = this.m >> 2; int i2 = l1 & 15; int j2 = l1 >> 8 & 15; int k2 = l1 >> 16 & 15; IBlockData iblockdata = chunksection.getType(i2, k2, j2); Fluid fluid = chunksection.b(i2, k2, j2); //this.methodProfiler.enter(* // Akarin - remove caller if (iblockdata.t()) { iblockdata.b((World) this, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), this.random); } if (fluid.h()) { fluid.b(this, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), this.random); } //this.methodProfiler.exit(); // Akarin - remove caller } } } } timings.chunkTicksBlocks.stopTimingUnsafe(); // Paper } //this.methodProfiler.exit(); // Akarin - remove caller } } protected BlockPosition a(BlockPosition blockposition) { BlockPosition blockposition1 = this.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING, blockposition); AxisAlignedBB axisalignedbb = (new AxisAlignedBB(blockposition1, new BlockPosition(blockposition1.getX(), this.getHeight(), blockposition1.getZ()))).g(3.0D); List list = this.a(EntityLiving.class, axisalignedbb, (java.util.function.Predicate) (entityliving) -> { // CraftBukkit - decompile error return entityliving != null && entityliving.isAlive() && this.e(entityliving.getChunkCoordinates()); }); if (!list.isEmpty()) { return ((EntityLiving) list.get(this.random.nextInt(list.size()))).getChunkCoordinates(); } else { if (blockposition1.getY() == -1) { blockposition1 = blockposition1.up(2); } return blockposition1; } } public void tickEntities() { if (false && this.players.isEmpty()) { // CraftBukkit - this prevents entity cleanup, other issues on servers with no players if (this.emptyTime++ >= 300) { return; } } else { this.p(); } this.worldProvider.l(); super.tickEntities(); spigotConfig.currentPrimedTnt = 0; // Spigot } protected void p_() { super.p_(); //this.methodProfiler.exitEnter("players"); // Akarin - remove caller for (int i = 0; i < this.players.size(); ++i) { Entity entity = (Entity) this.players.get(i); Entity entity1 = entity.getVehicle(); if (entity1 != null) { if (!entity1.dead && entity1.w(entity)) { continue; } entity.stopRiding(); } //this.methodProfiler.enter(* // Akarin - remove caller if (!entity.dead) { try { this.g(entity); } catch (Throwable throwable) { CrashReport crashreport = CrashReport.a(throwable, "Ticking player"); CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Player being ticked"); entity.appendEntityCrashDetails(crashreportsystemdetails); throw new ReportedException(crashreport); } } //this.methodProfiler.exit(); // Akarin - remove caller //this.methodProfiler.enter(* // Akarin - remove caller if (entity.dead) { int j = entity.chunkX; int k = entity.chunkZ; if (entity.inChunk && this.isChunkLoaded(j, k, true)) { this.getChunkAt(j, k).b(entity); } this.entityList.remove(entity); this.c(entity); } //this.methodProfiler.exit(); // Akarin - remove caller } } public void p() { this.emptyTime = 0; } public void q() { if (this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES) { this.nextTickListBlock.a(); this.nextTickListFluid.a(); } } private void a(NextTickListEntry nextticklistentry) { Fluid fluid = this.getFluid(nextticklistentry.a); if (fluid.c() == nextticklistentry.a()) { fluid.a((World) this, nextticklistentry.a); } } private void b(NextTickListEntry nextticklistentry) { IBlockData iblockdata = this.getType(nextticklistentry.a); if (iblockdata.getBlock() == nextticklistentry.a()) { iblockdata.a((World) this, nextticklistentry.a, this.random); } } /* CraftBukkit start - We prevent spawning in general, so this butchering is not needed public void entityJoinedWorld(Entity entity, boolean flag) { if (!this.getSpawnAnimals() && (entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal)) { entity.die(); } if (!this.getSpawnNPCs() && entity instanceof NPC) { entity.die(); } super.entityJoinedWorld(entity, flag); } // CraftBukkit end */ private boolean getSpawnNPCs() { return this.server.getSpawnNPCs(); } private boolean getSpawnAnimals() { return this.server.getSpawnAnimals(); } protected IChunkProvider r() { IChunkLoader ichunkloader = this.dataManager.createChunkLoader(this.worldProvider); // CraftBukkit start org.bukkit.craftbukkit.generator.InternalChunkGenerator gen; if (this.generator != null) { gen = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, this.getSeed(), this.generator); } else if (this.worldProvider instanceof WorldProviderHell) { gen = new org.bukkit.craftbukkit.generator.NetherChunkGenerator(this, this.getSeed()); } else if (this.worldProvider instanceof WorldProviderTheEnd) { gen = new org.bukkit.craftbukkit.generator.SkyLandsChunkGenerator(this, this.getSeed()); } else { gen = new org.bukkit.craftbukkit.generator.NormalChunkGenerator(this, this.getSeed()); } return com.destroystokyo.paper.PaperConfig.asyncChunks ? new PaperAsyncChunkProvider(this, ichunkloader, gen, this.server) : new ChunkProviderServer(this, ichunkloader, gen, this.server); // Paper - async chunks // CraftBukkit end } public boolean a(EntityHuman entityhuman, BlockPosition blockposition) { return !this.server.a(this, blockposition, entityhuman) && this.getWorldBorder().a(blockposition); } public void a(WorldSettings worldsettings) { if (!this.worldData.v()) { try { this.b(worldsettings); if (this.worldData.getType() == WorldType.DEBUG_ALL_BLOCK_STATES) { this.am(); } super.a(worldsettings); } catch (Throwable throwable) { CrashReport crashreport = CrashReport.a(throwable, "Exception initializing level"); try { this.a(crashreport); } catch (Throwable throwable1) { ; } throw new ReportedException(crashreport); } this.worldData.d(true); } } private void am() { this.worldData.f(false); this.worldData.c(true); this.worldData.setStorm(false); this.worldData.setThundering(false); this.worldData.g(1000000000); this.worldData.setDayTime(6000L); this.worldData.setGameType(EnumGamemode.SPECTATOR); this.worldData.g(false); this.worldData.setDifficulty(EnumDifficulty.PEACEFUL); this.worldData.e(true); this.getGameRules().set("doDaylightCycle", "false", this.server); } private void b(WorldSettings worldsettings) { if (!this.worldProvider.canRespawn()) { this.worldData.setSpawn(BlockPosition.ZERO.up(this.chunkProvider.getChunkGenerator().getSpawnHeight())); } else if (this.worldData.getType() == WorldType.DEBUG_ALL_BLOCK_STATES) { this.worldData.setSpawn(BlockPosition.ZERO.up()); } else { WorldChunkManager worldchunkmanager = this.chunkProvider.getChunkGenerator().getWorldChunkManager(); List list = worldchunkmanager.a(); Random random = new Random(this.getSeed()); BlockPosition blockposition = worldchunkmanager.a(0, 0, 256, list, random); ChunkCoordIntPair chunkcoordintpair = blockposition == null ? new ChunkCoordIntPair(0, 0) : new ChunkCoordIntPair(blockposition); // CraftBukkit start if (this.generator != null) { Random rand = new Random(this.getSeed()); org.bukkit.Location spawn = this.generator.getFixedSpawnLocation(((WorldServer) this).getWorld(), rand); if (spawn != null) { if (spawn.getWorld() != ((WorldServer) this).getWorld()) { throw new IllegalStateException("Cannot set spawn point for " + this.worldData.getName() + " to be in another world (" + spawn.getWorld().getName() + ")"); } else { this.worldData.setSpawn(new BlockPosition(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ())); return; } } } // CraftBukkit end if (blockposition == null) { WorldServer.a.warn("Unable to find spawn biome"); } boolean flag = false; Iterator iterator = TagsBlock.VALID_SPAWN.a().iterator(); while (iterator.hasNext()) { Block block = (Block) iterator.next(); if (worldchunkmanager.b().contains(block.getBlockData())) { flag = true; break; } } this.worldData.setSpawn(chunkcoordintpair.h().a(8, this.chunkProvider.getChunkGenerator().getSpawnHeight(), 8)); int i = 0; int j = 0; int k = 0; int l = -1; boolean flag1 = true; for (int i1 = 0; i1 < 1024; ++i1) { if (i > -16 && i <= 16 && j > -16 && j <= 16) { BlockPosition blockposition1 = this.worldProvider.a(new ChunkCoordIntPair(chunkcoordintpair.x + i, chunkcoordintpair.z + j), flag); if (blockposition1 != null) { this.worldData.setSpawn(blockposition1); break; } } if (i == j || i < 0 && i == -j || i > 0 && i == 1 - j) { int j1 = k; k = -l; l = j1; } i += k; j += l; } if (worldsettings.c()) { this.s(); } } } protected void s() { WorldGenBonusChest worldgenbonuschest = new WorldGenBonusChest(); for (int i = 0; i < 10; ++i) { int j = this.worldData.b() + this.random.nextInt(6) - this.random.nextInt(6); int k = this.worldData.d() + this.random.nextInt(6) - this.random.nextInt(6); BlockPosition blockposition = this.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES, new BlockPosition(j, 0, k)).up(); if (worldgenbonuschest.a(this, this.chunkProvider.getChunkGenerator(), this.random, blockposition, WorldGenFeatureConfiguration.e)) { break; } } } @Nullable public BlockPosition getDimensionSpawn() { return this.worldProvider.d(); } public void save(boolean flag, @Nullable IProgressUpdate iprogressupdate) throws ExceptionWorldConflict { ChunkProviderServer chunkproviderserver = this.getChunkProvider(); if (chunkproviderserver.d()) { if (flag) org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit // Paper - Incremental Auto Saving - Only fire event on full save timings.worldSave.startTimingUnsafe(); // Paper if (flag || server.serverAutoSave) { // Paper if (iprogressupdate != null) { iprogressupdate.a(new ChatMessage("menu.savingLevel", new Object[0])); } this.a(); if (iprogressupdate != null) { iprogressupdate.c(new ChatMessage("menu.savingChunks", new Object[0])); } } // Paper timings.worldSaveChunks.startTimingUnsafe(); // Paper chunkproviderserver.a(flag); timings.worldSaveChunks.stopTimingUnsafe(); // Paper // CraftBukkit - ArrayList -> Collection /* //Paper start - disable vanilla chunk GC java.util.Collection list = chunkproviderserver.a(); Iterator iterator = list.iterator(); while (iterator.hasNext()) { Chunk chunk = (Chunk) iterator.next(); if (chunk != null && !this.manager.a(chunk.locX, chunk.locZ)) { chunkproviderserver.unload(chunk); } }*/ // Paper end timings.worldSave.stopTimingUnsafe(); // Paper } } public void flushSave() { ChunkProviderServer chunkproviderserver = this.getChunkProvider(); if (chunkproviderserver.d()) { chunkproviderserver.c(); } } protected void a() throws ExceptionWorldConflict { timings.worldSaveLevel.startTimingUnsafe(); // Paper this.checkSession(); Iterator iterator = this.server.getWorlds().iterator(); while (iterator.hasNext()) { WorldServer worldserver = (WorldServer) iterator.next(); if (worldserver instanceof SecondaryWorldServer) { ((SecondaryWorldServer) worldserver).t_(); } } this.worldData.a(this.getWorldBorder().getSize()); this.worldData.d(this.getWorldBorder().getCenterX()); this.worldData.c(this.getWorldBorder().getCenterZ()); this.worldData.e(this.getWorldBorder().getDamageBuffer()); this.worldData.f(this.getWorldBorder().getDamageAmount()); this.worldData.h(this.getWorldBorder().getWarningDistance()); this.worldData.i(this.getWorldBorder().getWarningTime()); this.worldData.b(this.getWorldBorder().j()); this.worldData.c(this.getWorldBorder().i()); this.worldData.c(this.server.getBossBattleCustomData().c()); this.dataManager.saveWorldData(this.worldData, this.server.getPlayerList().t()); this.h().a(); timings.worldSaveLevel.stopTimingUnsafe(); // Paper } // CraftBukkit start public boolean addEntity(Entity entity, SpawnReason spawnReason) { // Changed signature, added SpawnReason // World.addEntity(Entity) will call this, and we still want to perform // existing entity checking when it's called with a SpawnReason return this.j(entity) ? super.addEntity(entity, spawnReason) : false; } // CraftBukkit end public void a(Stream stream) { stream.forEach((entity) -> { if (this.j(entity)) { this.entityList.add(entity); this.b(entity); } }); } private boolean j(Entity entity) { if (entity.dead) { // Paper start if (DEBUG_ENTITIES) { new Throwable("Tried to add entity " + entity + " but it was marked as removed already").printStackTrace(); // CraftBukkit getAddToWorldStackTrace(entity).printStackTrace(); } // Paper end return false; } else { UUID uuid = entity.getUniqueID(); if (this.entitiesByUUID.containsKey(uuid)) { Entity entity1 = (Entity) this.entitiesByUUID.get(uuid); if (this.g.contains(entity1) || entity1.dead) { // Paper - if dupe is dead, overwrite this.g.remove(entity1); } else { if (!(entity instanceof EntityHuman)) { if (DEBUG_ENTITIES && entity.world.paperConfig.duplicateUUIDMode != com.destroystokyo.paper.PaperWorldConfig.DuplicateUUIDMode.NOTHING) { WorldServer.a.error("Keeping entity {} that already exists with UUID {}", entity1, uuid.toString()); // CraftBukkit // Paper WorldServer.a.error("Deleting duplicate entity {}", entity); // Paper if (entity1.addedToWorldStack != null) { entity1.addedToWorldStack.printStackTrace(); } getAddToWorldStackTrace(entity).printStackTrace(); } return false; } WorldServer.a.warn("Force-added player with duplicate UUID {}", uuid.toString()); } this.removeEntity(entity1); } return true; } } protected void b(Entity entity) { super.b(entity); this.entitiesById.a(entity.getId(), entity); // Paper start if (DEBUG_ENTITIES) { entity.addedToWorldStack = getAddToWorldStackTrace(entity); } Entity old = this.entitiesByUUID.put(entity.getUniqueID(), entity); if (old != null && old.getId() != entity.getId() && old.valid && entity.world.paperConfig.duplicateUUIDMode != com.destroystokyo.paper.PaperWorldConfig.DuplicateUUIDMode.NOTHING) { Logger logger = LogManager.getLogger(); logger.error("Overwrote an existing entity " + old + " with " + entity); if (DEBUG_ENTITIES) { if (old.addedToWorldStack != null) { old.addedToWorldStack.printStackTrace(); } else { logger.error("Oddly, the old entity was not added to the world in the normal way. Plugins?"); } entity.addedToWorldStack.printStackTrace(); } } // Paper end Entity[] aentity = entity.bi(); if (aentity != null) { Entity[] aentity1 = aentity; int i = aentity.length; for (int j = 0; j < i; ++j) { Entity entity1 = aentity1[j]; this.entitiesById.a(entity1.getId(), entity1); } } } protected void c(Entity entity) { if (!this.entitiesByUUID.containsKey(entity.getUniqueID()) && !entity.valid) return; // Paper - Already removed, dont fire twice - this looks like it can happen even without our changes super.c(entity); this.entitiesById.d(entity.getId()); this.entitiesByUUID.remove(entity.getUniqueID()); Entity[] aentity = entity.bi(); if (aentity != null) { Entity[] aentity1 = aentity; int i = aentity.length; for (int j = 0; j < i; ++j) { Entity entity1 = aentity1[j]; this.entitiesById.d(entity1.getId()); } } } // CraftBukkit start public boolean strikeLightning(Entity entity) { return this.strikeLightning(entity, LightningStrikeEvent.Cause.UNKNOWN); } public boolean strikeLightning(Entity entity, LightningStrikeEvent.Cause cause) { LightningStrikeEvent lightning = new LightningStrikeEvent(this.getWorld(), (org.bukkit.entity.LightningStrike) entity.getBukkitEntity(), cause); this.getServer().getPluginManager().callEvent(lightning); if (lightning.isCancelled()) { return false; } // CraftBukkit end if (super.strikeLightning(entity)) { this.server.getPlayerList().sendPacketNearby((EntityHuman) null, entity.locX, entity.locY, entity.locZ, this.paperConfig.maxLightningFlashDistance, this, new PacketPlayOutSpawnEntityWeather(entity)); // CraftBukkit - Use dimension, // Paper - use world instead of dimension, limit lightning strike effect distance return true; } else { return false; } } public void broadcastEntityEffect(Entity entity, byte b0) { this.getTracker().sendPacketToEntity(entity, new PacketPlayOutEntityStatus(entity, b0)); } public ChunkProviderServer getChunkProvider() { return (ChunkProviderServer) super.getChunkProvider(); } public Explosion createExplosion(@Nullable Entity entity, DamageSource damagesource, double d0, double d1, double d2, float f, boolean flag, boolean flag1) { // CraftBukkit start Explosion explosion = super.createExplosion(entity, damagesource, d0, d1, d2, f, flag, flag1); if (explosion.wasCanceled) { return explosion; } /* Remove Explosion explosion = new Explosion(this, entity, d0, d1, d2, f, flag, flag1); if (damagesource != null) { explosion.a(damagesource); } explosion.a(); explosion.a(false); */ // CraftBukkit end - TODO: Check if explosions are still properly implemented if (!flag1) { explosion.clearBlocks(); } Iterator iterator = this.players.iterator(); while (iterator.hasNext()) { EntityHuman entityhuman = (EntityHuman) iterator.next(); if (entityhuman.d(d0, d1, d2) < 4096.0D) { ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutExplosion(d0, d1, d2, f, explosion.getBlocks(), (Vec3D) explosion.c().get(entityhuman))); } } return explosion; } public void playBlockAction(BlockPosition blockposition, Block block, int i, int j) { this.d.add(new BlockActionData(blockposition, block, i, j)); } private void an() { while (!this.d.isEmpty()) { BlockActionData blockactiondata = (BlockActionData) this.d.removeFirst(); if (this.a(blockactiondata)) { // CraftBukkit - this.worldProvider.dimension -> this.dimension, // Paper - dimension -> world this.server.getPlayerList().sendPacketNearby((EntityHuman) null, (double) blockactiondata.a().getX(), (double) blockactiondata.a().getY(), (double) blockactiondata.a().getZ(), 64.0D, this, new PacketPlayOutBlockAction(blockactiondata.a(), blockactiondata.b(), blockactiondata.c(), blockactiondata.d())); } } } private boolean a(BlockActionData blockactiondata) { IBlockData iblockdata = this.getType(blockactiondata.a()); return iblockdata.getBlock() == blockactiondata.b() ? iblockdata.a(this, blockactiondata.a(), blockactiondata.c(), blockactiondata.d()) : false; } public void close() { this.dataManager.a(); super.close(); } protected void w() { boolean flag = this.isRaining(); super.w(); /* CraftBukkit start if (this.o != this.p) { this.server.getPlayerList().a((Packet) (new PacketPlayOutGameStateChange(7, this.p)), this.worldProvider.getDimensionManager()); } if (this.q != this.r) { this.server.getPlayerList().a((Packet) (new PacketPlayOutGameStateChange(8, this.r)), this.worldProvider.getDimensionManager()); } if (flag != this.isRaining()) { if (flag) { this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(2, 0.0F)); } else { this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(1, 0.0F)); } this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(7, this.p)); this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(8, this.r)); } // */ if (flag != this.isRaining()) { // Only send weather packets to those affected for (int i = 0; i < this.players.size(); ++i) { if (((EntityPlayer) this.players.get(i)).world == this) { ((EntityPlayer) this.players.get(i)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false); } } } for (int i = 0; i < this.players.size(); ++i) { if (((EntityPlayer) this.players.get(i)).world == this) { ((EntityPlayer) this.players.get(i)).updateWeather(this.o, this.p, this.q, this.r); } } // CraftBukkit end } public TickListServer getBlockTickList() { return this.nextTickListBlock; } public TickListServer getFluidTickList() { return this.nextTickListFluid; } @Nonnull public MinecraftServer getMinecraftServer() { return this.server; } public EntityTracker getTracker() { return this.tracker; } public PlayerChunkMap getPlayerChunkMap() { return this.manager; } public PortalTravelAgent getTravelAgent() { return this.portalTravelAgent; } public DefinedStructureManager D() { return this.dataManager.h(); } public int a(T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6) { // CraftBukkit - visibility api support return sendParticles(null, t0, d0, d1, d2, i, d3, d4, d5, d6, false); } public int sendParticles(EntityPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) { // Paper start - Particle API Expansion return sendParticles(players, sender, t0, d0, d1, d2, i, d3, d4, d5, d6, force); } public int sendParticles(List receivers, EntityPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) { // Paper end PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(t0, force, (float) d0, (float) d1, (float) d2, (float) d3, (float) d4, (float) d5, (float) d6, i); // CraftBukkit end int j = 0; for (EntityHuman entityhuman : receivers) { // Paper - Particle API Expansion EntityPlayer entityplayer = (EntityPlayer) entityhuman; // Paper - Particle API Expansion if (sender != null && !entityplayer.getBukkitEntity().canSee(sender.getBukkitEntity())) continue; // CraftBukkit if (this.a(entityplayer, force, d0, d1, d2, packetplayoutworldparticles)) { // CraftBukkit ++j; } } return j; } public boolean a(EntityPlayer entityplayer, T t0, boolean flag, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6) { Packet packet = new PacketPlayOutWorldParticles(t0, flag, (float) d0, (float) d1, (float) d2, (float) d3, (float) d4, (float) d5, (float) d6, i); return this.a(entityplayer, flag, d0, d1, d2, packet); } private boolean a(EntityPlayer entityplayer, boolean flag, double d0, double d1, double d2, Packet packet) { if (entityplayer.getWorldServer() != this) { return false; } else { BlockPosition blockposition = entityplayer.getChunkCoordinates(); double d3 = blockposition.distanceSquared(d0, d1, d2); if (d3 > 1024.0D && (!flag || d3 > 262144.0D)) { return false; } else { entityplayer.playerConnection.sendPacket(packet); return true; } } } @Nullable public Entity getEntity(UUID uuid) { return (Entity) this.entitiesByUUID.get(uuid); } public ListenableFuture postToMainThread(Runnable runnable) { return this.server.postToMainThread(runnable); } // Akarin start @Override public void ensuresMainThread(Runnable runnable) { this.server.f.offer(ListenableFutureTask.create(runnable, null)); } // Akarin end public boolean isMainThread() { return this.server.isMainThread(); } @Nullable public BlockPosition a(String s, BlockPosition blockposition, int i, boolean flag) { return this.getChunkProvider().a(this, s, blockposition, i, flag); } public CraftingManager getCraftingManager() { return this.server.getCraftingManager(); } public TagRegistry F() { return this.server.getTagRegistry(); } }