package net.minecraft.server; import co.aikar.timings.Timings; import com.destroystokyo.paper.event.server.PaperServerListPingEvent; import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Queues; import com.google.common.collect.Sets; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFutureTask; import com.google.gson.JsonElement; import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfileRepository; import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; import com.mojang.datafixers.DataFixer; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.longs.LongIterator; import java.awt.GraphicsEnvironment; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.Proxy; import java.net.URLEncoder; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Random; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.BooleanSupplier; import javax.annotation.Nullable; import javax.imageio.ImageIO; import org.apache.commons.lang3.Validate; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; // CraftBukkit start import joptsimple.OptionSet; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.Main; import org.bukkit.event.server.ServerLoadEvent; // CraftBukkit end import org.spigotmc.SlackActivityAccountant; // Spigot import co.aikar.timings.MinecraftTimings; // Paper import co.aikar.timings.ThreadAssertion; public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStatistics, ICommandListener, Runnable { private static MinecraftServer SERVER; // Paper public static final Logger LOGGER = LogManager.getLogger(); public static final File a = new File("usercache.json"); public Convertable convertable; private final MojangStatisticsGenerator snooper = new MojangStatisticsGenerator("server", this, SystemUtils.getMonotonicMillis()); public File universe; private final List k = Lists.newArrayList(); public final MethodProfiler methodProfiler = new MethodProfiler(); private ServerConnection serverConnection; // Spigot private final ServerPing m = new ServerPing(); private final Random n = new Random(); public final DataFixer dataConverterManager; private String serverIp; private int q = -1; public final Map worldServer = new com.destroystokyo.paper.PaperWorldMap(); // Paper; private PlayerList playerList; private boolean isRunning = true; private boolean isRestarting = false; // Paper - flag to signify we're attempting to restart private boolean isStopped; private int ticks; protected final Proxy c; private IChatBaseComponent w; private int x; private boolean onlineMode; private boolean z; private boolean spawnAnimals; private boolean spawnNPCs; private boolean pvpMode; private boolean allowFlight; private String motd; private int F; private int G; public final long[] d = new long[100]; protected final Map e = com.koloboke.collect.map.hash.HashObjObjMaps.getDefaultFactory().withNullKeyAllowed(true).withKeyEquivalence(com.koloboke.collect.Equivalence.identity()).newUpdatableMap(); // Akarin - koloboke private KeyPair H; private String I; private String J; private boolean demoMode; private boolean M; private String N = ""; private String O = ""; private boolean P; private long lastOverloadTime; private IChatBaseComponent R; private boolean S; private boolean T; private final YggdrasilAuthenticationService U; private final MinecraftSessionService V; private final GameProfileRepository W; private final UserCache X; private long Y; protected final Queue> f = Queues.newConcurrentLinkedQueue(); private Thread serverThread; private long nextTick = SystemUtils.getMonotonicMillis(); private final IReloadableResourceManager ac; private final ResourcePackRepository resourcePackRepository; private ResourcePackSourceFolder resourcePackFolder; public CommandDispatcher commandDispatcher; private final CraftingManager ag; private final TagRegistry ah; private final ScoreboardServer ai; private final BossBattleCustomData aj; private final LootTableRegistry ak; private final AdvancementDataWorld al; private final CustomFunctionData am; private boolean an; private boolean forceUpgrade; private float ap; // CraftBukkit start public org.bukkit.craftbukkit.CraftServer server; public OptionSet options; public org.bukkit.command.ConsoleCommandSender console; public org.bukkit.command.RemoteConsoleCommandSender remoteConsole; //public ConsoleReader reader; // Paper public static int currentTick = 0; // Paper - Further improve tick loop public boolean serverAutoSave = false; // Paper public final Thread primaryThread; public java.util.Queue processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); public int autosavePeriod; public File bukkitDataPackFolder; public CommandDispatcher vanillaCommandDispatcher; public List expiringMaps = java.util.Collections.synchronizedList(new java.util.ArrayList<>()); // Paper // CraftBukkit end // Spigot start public static final int TPS = 20; public static final int TICK_TIME = 1000000000 / TPS; private static final int SAMPLE_INTERVAL = 20; // Paper public final double[] recentTps = new double[ 3 ]; public final SlackActivityAccountant slackActivityAccountant = new SlackActivityAccountant(); // Spigot end public MinecraftServer(OptionSet options, Proxy proxy, DataFixer datafixer, CommandDispatcher commanddispatcher, YggdrasilAuthenticationService yggdrasilauthenticationservice, MinecraftSessionService minecraftsessionservice, GameProfileRepository gameprofilerepository, UserCache usercache) { SERVER = this; // Paper - better singleton this.commandDispatcher = commanddispatcher; // CraftBukkit this.ac = new ResourceManager(EnumResourcePackType.SERVER_DATA); this.resourcePackRepository = new ResourcePackRepository<>(ResourcePackLoader::new); this.ag = new CraftingManager(); this.ah = new TagRegistry(); this.ai = new ScoreboardServer(this); this.aj = new BossBattleCustomData(this); this.ak = new LootTableRegistry(); this.al = new AdvancementDataWorld(); this.am = new CustomFunctionData(this); this.c = proxy; this.commandDispatcher = this.vanillaCommandDispatcher = commanddispatcher; // CraftBukkit this.U = yggdrasilauthenticationservice; this.V = minecraftsessionservice; this.W = gameprofilerepository; this.X = usercache; this.userCache = new AkarinUserCache(gameprofilerepository, usercache.file(), usercache.gson()); // Akarin // this.universe = file; // CraftBukkit // this.serverConnection = new ServerConnection(this); // CraftBukkit // Spigot // this.convertable = file == null ? null : new WorldLoaderServer(file.toPath(), file.toPath().resolve("../backups"), datafixer); // CraftBukkit - moved to DedicatedServer.init this.dataConverterManager = datafixer; this.ac.a((IResourcePackListener) this.ah); this.ac.a((IResourcePackListener) this.ag); this.ac.a((IResourcePackListener) this.ak); this.ac.a((IResourcePackListener) this.am); this.ac.a((IResourcePackListener) this.al); // CraftBukkit start this.options = options; // Paper start - Handled by TerminalConsoleAppender // Try to see if we're actually running in a terminal, disable jline if not /* if (System.console() == null && System.getProperty("jline.terminal") == null) { System.setProperty("jline.terminal", "jline.UnsupportedTerminal"); Main.useJline = false; } try { reader = new ConsoleReader(System.in, System.out); reader.setExpandEvents(false); // Avoid parsing exceptions for uncommonly used event designators } catch (Throwable e) { try { // Try again with jline disabled for Windows users without C++ 2008 Redistributable System.setProperty("jline.terminal", "jline.UnsupportedTerminal"); System.setProperty("user.language", "en"); Main.useJline = false; reader = new ConsoleReader(System.in, System.out); reader.setExpandEvents(false); } catch (IOException ex) { LOGGER.warn((String) null, ex); } } */ // Paper end Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this)); this.serverThread = primaryThread = new Thread(this, "Server thread"); // Moved from main } public abstract PropertyManager getPropertyManager(); // CraftBukkit end public abstract boolean init() throws IOException; public void convertWorld(String s) { if (this.getConvertable().isConvertable(s)) { MinecraftServer.LOGGER.info("Converting map!"); this.b((IChatBaseComponent) (new ChatMessage("menu.convertingLevel", new Object[0]))); this.getConvertable().convert(s, new IProgressUpdate() { private long b = SystemUtils.getMonotonicMillis(); public void a(IChatBaseComponent ichatbasecomponent) {} public void a(int i) { if (SystemUtils.getMonotonicMillis() - this.b >= 1000L) { this.b = SystemUtils.getMonotonicMillis(); MinecraftServer.LOGGER.info("Converting... {}%", i); } } public void c(IChatBaseComponent ichatbasecomponent) {} }); } if (this.forceUpgrade) { MinecraftServer.LOGGER.info("Forcing world upgrade! {}", s); // CraftBukkit WorldData worlddata = this.getConvertable().c(s); // CraftBukkit if (worlddata != null) { WorldUpgrader worldupgrader = new WorldUpgrader(s, this.getConvertable(), worlddata); // CraftBukkit IChatBaseComponent ichatbasecomponent = null; while (!worldupgrader.b()) { IChatBaseComponent ichatbasecomponent1 = worldupgrader.g(); if (ichatbasecomponent != ichatbasecomponent1) { ichatbasecomponent = ichatbasecomponent1; MinecraftServer.LOGGER.info(worldupgrader.g().getString()); } int i = worldupgrader.d(); if (i > 0) { int j = worldupgrader.e() + worldupgrader.f(); MinecraftServer.LOGGER.info("{}% completed ({} / {} chunks)...", MathHelper.d((float) j / (float) i * 100.0F), j, i); } if (this.isStopped()) { worldupgrader.a(); } else { try { Thread.sleep(1000L); } catch (InterruptedException interruptedexception) { ; } } } } } } protected synchronized void b(IChatBaseComponent ichatbasecomponent) { this.R = ichatbasecomponent; } public void a(String s, String s1, long i, WorldType worldtype, JsonElement jsonelement) { // this.convertWorld(s); // CraftBukkit - moved down this.b((IChatBaseComponent) (new ChatMessage("menu.loadingLevel", new Object[0]))); /* CraftBukkit start - Remove ticktime arrays and worldsettings IDataManager idatamanager = this.getConvertable().a(s, this); this.a(this.getWorld(), idatamanager); WorldData worlddata = idatamanager.getWorldData(); WorldSettings worldsettings; if (worlddata == null) { if (this.L()) { worldsettings = DemoWorldServer.a; } else { worldsettings = new WorldSettings(i, this.getGamemode(), this.getGenerateStructures(), this.isHardcore(), worldtype); worldsettings.setGeneratorSettings(jsonelement); if (this.M) { worldsettings.a(); } } worlddata = new WorldData(worldsettings, s1); } else { worlddata.a(s1); worldsettings = new WorldSettings(worlddata); } this.a(idatamanager.getDirectory(), worlddata); */ int worldCount = 3; for (int j = 0; j < worldCount; ++j) { WorldServer world; WorldData worlddata; byte dimension = 0; if (j == 1) { if (getAllowNether()) { dimension = -1; } else { continue; } } if (j == 2) { if (server.getAllowEnd()) { dimension = 1; } else { continue; } } String worldType = org.bukkit.World.Environment.getEnvironment(dimension).toString().toLowerCase(); String name = (dimension == 0) ? s : s + "_" + worldType; this.convertWorld(name); // Run conversion now org.bukkit.generator.ChunkGenerator gen = this.server.getGenerator(name); WorldSettings worldsettings = new WorldSettings(com.destroystokyo.paper.PaperConfig.seedOverride.getOrDefault(name, i), this.getGamemode(), this.getGenerateStructures(), this.isHardcore(), worldtype); // Paper worldsettings.setGeneratorSettings(jsonelement); if (j == 0) { IDataManager idatamanager = new ServerNBTManager(server.getWorldContainer(), s1, this, this.dataConverterManager); worlddata = idatamanager.getWorldData(); if (worlddata == null) { worlddata = new WorldData(worldsettings, s1); } worlddata.checkName(s1); // CraftBukkit - Migration did not rewrite the level.dat; This forces 1.8 to take the last loaded world as respawn (in this case the end) this.a(idatamanager.getDirectory(), worlddata); PersistentCollection persistentcollection = new PersistentCollection(idatamanager); if (this.L()) { world = (WorldServer) (new DemoWorldServer(this, idatamanager, persistentcollection, worlddata, DimensionManager.OVERWORLD, this.methodProfiler)).i_(); } else { world = (WorldServer) (new WorldServer(this, idatamanager, persistentcollection, worlddata, DimensionManager.OVERWORLD, this.methodProfiler, org.bukkit.World.Environment.getEnvironment(dimension), gen)).i_(); } world.a(worldsettings); this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, world.getScoreboard()); } else { String dim = "DIM" + dimension; File newWorld = new File(new File(name), dim); File oldWorld = new File(new File(s), dim); File oldLevelDat = new File(new File(s), "level.dat"); // The data folders exist on first run as they are created in the PersistentCollection constructor above, but the level.dat won't if (!newWorld.isDirectory() && oldWorld.isDirectory() && oldLevelDat.isFile()) { MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder required ----"); MinecraftServer.LOGGER.info("Unfortunately due to the way that Minecraft implemented multiworld support in 1.6, Bukkit requires that you move your " + worldType + " folder to a new location in order to operate correctly."); MinecraftServer.LOGGER.info("We will move this folder for you, but it will mean that you need to move it back should you wish to stop using Bukkit in the future."); MinecraftServer.LOGGER.info("Attempting to move " + oldWorld + " to " + newWorld + "..."); if (newWorld.exists()) { MinecraftServer.LOGGER.warn("A file or folder already exists at " + newWorld + "!"); MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----"); } else if (newWorld.getParentFile().mkdirs()) { if (oldWorld.renameTo(newWorld)) { MinecraftServer.LOGGER.info("Success! To restore " + worldType + " in the future, simply move " + newWorld + " to " + oldWorld); // Migrate world data too. try { com.google.common.io.Files.copy(oldLevelDat, new File(new File(name), "level.dat")); org.apache.commons.io.FileUtils.copyDirectory(new File(new File(s), "data"), new File(new File(name), "data")); } catch (IOException exception) { MinecraftServer.LOGGER.warn("Unable to migrate world data."); } MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder complete ----"); } else { MinecraftServer.LOGGER.warn("Could not move folder " + oldWorld + " to " + newWorld + "!"); MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----"); } } else { MinecraftServer.LOGGER.warn("Could not create path for " + newWorld + "!"); MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----"); } } IDataManager idatamanager = new ServerNBTManager(server.getWorldContainer(), name, this, this.dataConverterManager); // world =, b0 to dimension, s1 to name, added Environment and gen worlddata = idatamanager.getWorldData(); if (worlddata == null) { worlddata = new WorldData(worldsettings, name); } worlddata.checkName(name); // CraftBukkit - Migration did not rewrite the level.dat; This forces 1.8 to take the last loaded world as respawn (in this case the end) world = (WorldServer) new SecondaryWorldServer(this, idatamanager, DimensionManager.a(dimension), this.getWorldServer(DimensionManager.OVERWORLD), this.methodProfiler, worlddata, org.bukkit.World.Environment.getEnvironment(dimension), gen).i_(); } this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldInitEvent(world.getWorld())); world.addIWorldAccess(new WorldManager(this, world)); if (!this.H()) { world.getWorldData().setGameType(this.getGamemode()); } this.worldServer.put(world.dimension, world); this.getPlayerList().setPlayerFileData(world); if (worlddata.P() != null) { this.getBossBattleCustomData().a(worlddata.P()); } } this.a(this.getDifficulty()); this.a(this.getWorldServer(DimensionManager.OVERWORLD).worldMaps); // CraftBukkit end // Paper start - Handle collideRule team for player collision toggle final Scoreboard scoreboard = this.getScoreboard(); final java.util.Collection toRemove = scoreboard.getTeams().stream().filter(team -> team.getName().startsWith("collideRule_")).map(ScoreboardTeam::getName).collect(java.util.stream.Collectors.toList()); for (String teamName : toRemove) { scoreboard.removeTeam(scoreboard.getTeam(teamName)); // Clean up after ourselves } if (!com.destroystokyo.paper.PaperConfig.enablePlayerCollisions) { this.getPlayerList().collideRuleTeamName = org.apache.commons.lang3.StringUtils.left("collideRule_" + java.util.concurrent.ThreadLocalRandom.current().nextInt(), 16); ScoreboardTeam collideTeam = scoreboard.createTeam(this.getPlayerList().collideRuleTeamName); collideTeam.setCanSeeFriendlyInvisibles(false); // Because we want to mimic them not being on a team at all } // Paper end } protected void a(File file, WorldData worlddata) { this.resourcePackRepository.a((ResourcePackSource) (new ResourcePackSourceVanilla())); this.resourcePackFolder = new ResourcePackSourceFolder(new File(file, "datapacks")); // CraftBukkit start bukkitDataPackFolder = new File(new File(file, "datapacks"), "bukkit"); if (!bukkitDataPackFolder.exists()) { bukkitDataPackFolder.mkdirs(); } File mcMeta = new File(bukkitDataPackFolder, "pack.mcmeta"); if (!mcMeta.exists()) { try { com.google.common.io.Files.write("{\n" + " \"pack\": {\n" + " \"description\": \"Data pack for resources provided by Bukkit plugins\",\n" + " \"pack_format\": 1\n" + " }\n" + "}", mcMeta, com.google.common.base.Charsets.UTF_8); } catch (IOException ex) { throw new RuntimeException("Could not initialize Bukkit datapack", ex); } } // CraftBukkit end this.resourcePackRepository.a((ResourcePackSource) this.resourcePackFolder); this.resourcePackRepository.a(); List list = Lists.newArrayList(); Iterator iterator = worlddata.O().iterator(); while (iterator.hasNext()) { String s = (String) iterator.next(); ResourcePackLoader resourcepackloader = this.resourcePackRepository.a(s); if (resourcepackloader != null) { list.add(resourcepackloader); } else { MinecraftServer.LOGGER.warn("Missing data pack {}", s); } } this.resourcePackRepository.a((Collection) list); this.a(worlddata); } protected void a(PersistentCollection persistentcollection) { boolean flag = true; boolean flag1 = true; boolean flag2 = true; boolean flag3 = true; boolean flag4 = true; this.b((IChatBaseComponent) (new ChatMessage("menu.generatingTerrain", new Object[0]))); // CraftBukkit start - fire WorldLoadEvent and handle whether or not to keep the spawn in memory Stopwatch stopwatch = Stopwatch.createStarted(); boolean waitForChunks = Boolean.getBoolean("paper.waitforchunks"); // Paper for (WorldServer worldserver : this.getWorlds()) { MinecraftServer.LOGGER.info("Preparing start region for level " + worldserver.dimension + " (Seed: " + worldserver.getSeed() + ")"); if (!worldserver.getWorld().getKeepSpawnInMemory()) { continue; } BlockPosition blockposition = worldserver.getSpawn(); List list = worldserver.getChunkProvider().getSpiralOutChunks(blockposition, worldserver.paperConfig.keepLoadedRange >> 4); // Paper Set set = Sets.newConcurrentHashSet(); // Paper - remove arraylist creation, call spiral above if (this.isRunning()) { // Paper int expected = list.size(); // Paper CompletableFuture completablefuture = worldserver.getChunkProvider().loadAllChunks(list, (chunk) -> { // Paper set.add(chunk.getPos()); if (waitForChunks && (set.size() == expected || (set.size() < expected && set.size() % (set.size() / 10) == 0))) { this.a(new ChatMessage("menu.preparingSpawn", new Object[0]), set.size() * 100 / expected); // Paper } }); while (waitForChunks && !completablefuture.isDone() && isRunning()) { // Paper try { PaperAsyncChunkProvider.processMainThreadQueue(this); // Paper completablefuture.get(50L, TimeUnit.MILLISECONDS); // Paper } catch (InterruptedException interruptedexception) { throw new RuntimeException(interruptedexception); } catch (ExecutionException executionexception) { if (executionexception.getCause() instanceof RuntimeException) { throw (RuntimeException) executionexception.getCause(); } throw new RuntimeException(executionexception.getCause()); } catch (TimeoutException timeoutexception) { //this.a(new ChatMessage("menu.preparingSpawn", new Object[0]), set.size() * 100 / expected); // Paper } } if (waitForChunks) this.a(new ChatMessage("menu.preparingSpawn", new Object[0]), set.size() * 100 / expected); // Paper } } for (WorldServer world : com.google.common.collect.Lists.newArrayList(this.getWorlds())) { // Paper - avoid como if 1 world triggers another world this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(world.getWorld())); } // CraftBukkit end MinecraftServer.LOGGER.info("Time elapsed: {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS)); Iterator iterator = DimensionManager.b().iterator(); while (iterator.hasNext()) { DimensionManager dimensionmanager = (DimensionManager) iterator.next(); ForcedChunk forcedchunk = (ForcedChunk) persistentcollection.get(dimensionmanager, ForcedChunk::new, "chunks"); if (forcedchunk != null) { WorldServer worldserver1 = this.getWorldServer(dimensionmanager); LongIterator longiterator = forcedchunk.a().iterator(); while (longiterator.hasNext()) { this.a(new ChatMessage("menu.loadingForcedChunks", new Object[] { dimensionmanager}), forcedchunk.a().size() * 100 / 625); long k = longiterator.nextLong(); ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(k); worldserver1.getChunkProvider().getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z, true, true); } } } this.l(); } protected void a(String s, IDataManager idatamanager) { File file = new File(idatamanager.getDirectory(), "resources.zip"); if (file.isFile()) { try { this.setResourcePack("level://" + URLEncoder.encode(s, StandardCharsets.UTF_8.toString()) + "/" + "resources.zip", ""); } catch (UnsupportedEncodingException unsupportedencodingexception) { MinecraftServer.LOGGER.warn("Something went wrong url encoding {}", s); } } } public abstract boolean getGenerateStructures(); public abstract EnumGamemode getGamemode(); public abstract EnumDifficulty getDifficulty(); public abstract boolean isHardcore(); public abstract int j(); public abstract boolean k(); protected void a(IChatBaseComponent ichatbasecomponent, int i) { this.w = ichatbasecomponent; this.x = i; MinecraftServer.LOGGER.info("{}: {}%", ichatbasecomponent.getString(), i); } protected void l() { this.w = null; this.x = 0; // CraftBukkit Start this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD); this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP)); // CraftBukkit end } protected void saveChunks(boolean flag) { Iterator iterator = this.getWorlds().iterator(); while (iterator.hasNext()) { WorldServer worldserver = (WorldServer) iterator.next(); if (worldserver != null) { if (!flag) { MinecraftServer.LOGGER.info("Saving chunks for level '{}'/{}", worldserver.getWorldData().getName(), DimensionManager.a(worldserver.worldProvider.getDimensionManager())); } try { worldserver.save(true, (IProgressUpdate) null); } catch (ExceptionWorldConflict exceptionworldconflict) { MinecraftServer.LOGGER.warn(exceptionworldconflict.getMessage()); } } } } // CraftBukkit start private boolean hasStopped = false; private final Object stopLock = new Object(); // CraftBukkit end public void stop() throws ExceptionWorldConflict { // CraftBukkit - added throws // CraftBukkit start - prevent double stopping on multiple threads synchronized(stopLock) { if (hasStopped) return; hasStopped = true; } PaperAsyncChunkProvider.stop(this); // Paper // CraftBukkit end MinecraftServer.LOGGER.info("Stopping server"); MinecraftTimings.stopServer(); // Paper // CraftBukkit start if (this.server != null) { this.server.disablePlugins(); } // CraftBukkit end if (this.getServerConnection() != null) { this.getServerConnection().b(); } if (this.playerList != null) { MinecraftServer.LOGGER.info("Saving players"); this.playerList.savePlayers(); this.playerList.u(isRestarting); // Paper try { Thread.sleep(100); } catch (InterruptedException ex) {} // CraftBukkit - SPIGOT-625 - give server at least a chance to send packets } MinecraftServer.LOGGER.info("Saving worlds"); Iterator iterator = this.getWorlds().iterator(); WorldServer worldserver; while (iterator.hasNext()) { worldserver = (WorldServer) iterator.next(); if (worldserver != null) { worldserver.savingDisabled = false; } } this.saveChunks(false); iterator = this.getWorlds().iterator(); while (iterator.hasNext()) { worldserver = (WorldServer) iterator.next(); if (worldserver != null) { worldserver.close(); } } if (this.snooper.d()) { this.snooper.e(); } // Spigot start if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { LOGGER.info("Saving usercache.json"); this.getModernUserCache().save(false); // Paper // Akarin } // Spigot end } public String getServerIp() { return this.serverIp; } public void b(String s) { this.serverIp = s; } public boolean isRunning() { return this.isRunning; } // Paper start - allow passing of the intent to restart public void safeShutdown() { safeShutdown(false); } public void safeShutdown(boolean isRestarting) { this.isRunning = false; this.isRestarting = isRestarting; } // Paper end private boolean canSleepForTick() { return System.nanoTime() - lastTick + catchupTime < TICK_TIME; // Paper - improved "are we lagging" check to match our own } // Spigot Start private static double calcTps(double avg, double exp, double tps) { return ( avg * exp ) + ( tps * ( 1 - exp ) ); } // Paper start - Further improve server tick loop private static final long SEC_IN_NANO = 1000000000; private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L; private long lastTick = 0; private long catchupTime = 0; public final RollingAverage tps1 = new RollingAverage(60); public final RollingAverage tps5 = new RollingAverage(60 * 5); public final RollingAverage tps15 = new RollingAverage(60 * 15); public static class RollingAverage { private final int size; private long time; private java.math.BigDecimal total; private int index = 0; private final java.math.BigDecimal[] samples; private final long[] times; RollingAverage(int size) { this.size = size; this.time = size * SEC_IN_NANO; this.total = dec(TPS).multiply(dec(SEC_IN_NANO)).multiply(dec(size)); this.samples = new java.math.BigDecimal[size]; this.times = new long[size]; for (int i = 0; i < size; i++) { this.samples[i] = dec(TPS); this.times[i] = SEC_IN_NANO; } } private static java.math.BigDecimal dec(long t) { return new java.math.BigDecimal(t); } public void add(java.math.BigDecimal x, long t) { time -= times[index]; total = total.subtract(samples[index].multiply(dec(times[index]))); samples[index] = x; times[index] = t; time += t; total = total.add(x.multiply(dec(t))); if (++index == size) { index = 0; } } public double getAverage() { return total.divide(dec(time), 30, java.math.RoundingMode.HALF_UP).doubleValue(); } } private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal(1E9).multiply(new java.math.BigDecimal(SAMPLE_INTERVAL)); // Paper End // Spigot End public void run() { try { if (this.init()) { this.nextTick = SystemUtils.getMonotonicMillis(); this.m.setMOTD(new ChatComponentText(this.motd)); this.m.setServerInfo(new ServerPing.ServerData("1.13.2", 404)); this.a(this.m); // Spigot start org.spigotmc.WatchdogThread.hasStarted = true; // Paper io.akarin.server.core.AkarinAsyncExecutor.initalise(); // Akarin Arrays.fill( recentTps, 20 ); long start = System.nanoTime(), curTime, wait, tickSection = start; // Paper - Further improve server tick loop lastTick = start - TICK_TIME; // Paper while (this.isRunning) { curTime = System.nanoTime(); // Paper start - Further improve server tick loop wait = TICK_TIME - (curTime - lastTick); if (wait > 0) { if (catchupTime < 2E6) { wait += Math.abs(catchupTime); } else if (wait < catchupTime) { catchupTime -= wait; wait = 0; } else { wait -= catchupTime; catchupTime = 0; } } if (wait > 0) { Thread.sleep(wait / 1000000); curTime = System.nanoTime(); wait = TICK_TIME - (curTime - lastTick); } catchupTime = Math.min(MAX_CATCHUP_BUFFER, catchupTime - wait); if ( ++MinecraftServer.currentTick % SAMPLE_INTERVAL == 0 ) { final long diff = curTime - tickSection; java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP); tps1.add(currentTps, diff); tps5.add(currentTps, diff); tps15.add(currentTps, diff); // Backwards compat with bad plugins recentTps[0] = tps1.getAverage(); recentTps[1] = tps5.getAverage(); recentTps[2] = tps15.getAverage(); // Paper end tickSection = curTime; } lastTick = curTime; //MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit // Paper - don't overwrite current tick time this.a(this::canSleepForTick); this.nextTick += 50L; // Spigot end this.P = true; } } else { this.a((CrashReport) null); } } catch (Throwable throwable) { MinecraftServer.LOGGER.error("Encountered an unexpected exception", throwable); // Spigot Start if ( throwable.getCause() != null ) { MinecraftServer.LOGGER.error( "\tCause of unexpected exception was", throwable.getCause() ); } // Spigot End CrashReport crashreport; if (throwable instanceof ReportedException) { crashreport = this.b(((ReportedException) throwable).a()); } else { crashreport = this.b(new CrashReport("Exception in server tick loop", throwable)); } File file = new File(new File(this.s(), "crash-reports"), "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-server.txt"); if (crashreport.a(file)) { MinecraftServer.LOGGER.error("This crash report has been saved to: {}", file.getAbsolutePath()); } else { MinecraftServer.LOGGER.error("We were unable to save this crash report to disk."); } this.a(crashreport); } finally { try { org.spigotmc.WatchdogThread.doStop(); this.isStopped = true; this.stop(); } catch (Throwable throwable1) { MinecraftServer.LOGGER.error("Exception stopping the server", throwable1); } finally { // CraftBukkit start - Restore terminal to original settings try { net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender } catch (Exception ignored) { } // CraftBukkit end this.t(); } } } public void a(ServerPing serverping) { File file = this.c("server-icon.png"); if (!file.exists()) { file = this.getConvertable().b(this.getWorld(), "icon.png"); } if (file.isFile()) { ByteBuf bytebuf = Unpooled.buffer(); try { BufferedImage bufferedimage = ImageIO.read(file); Validate.validState(bufferedimage.getWidth() == 64, "Must be 64 pixels wide", new Object[0]); Validate.validState(bufferedimage.getHeight() == 64, "Must be 64 pixels high", new Object[0]); ImageIO.write(bufferedimage, "PNG", new ByteBufOutputStream(bytebuf)); ByteBuffer bytebuffer = Base64.getEncoder().encode(bytebuf.nioBuffer()); serverping.setFavicon("data:image/png;base64," + StandardCharsets.UTF_8.decode(bytebuffer)); } catch (Exception exception) { MinecraftServer.LOGGER.error("Couldn't load server icon", exception); } finally { bytebuf.release(); } } } public File s() { return new File("."); } protected void a(CrashReport crashreport) {} public void t() {} protected void a(BooleanSupplier booleansupplier) { co.aikar.timings.TimingsManager.FULL_SERVER_TICK.startTiming(); // Paper // Akarin this.slackActivityAccountant.tickStarted(); // Spigot long i = SystemUtils.getMonotonicNanos(); long startTime = i; // Paper ++this.ticks; if (this.S) { this.S = false; //this.methodProfiler.a(this.ticks); // Akarin - remove caller } //this.methodProfiler.enter(* // Akarin - remove caller this.b(booleansupplier); if (i - this.Y >= 5000000000L) { this.Y = i; this.m.setPlayerSample(new ServerPing.ServerPingPlayerSample(this.getMaxPlayers(), this.getPlayerCount())); GameProfile[] agameprofile = new GameProfile[Math.min(this.getPlayerCount(), org.spigotmc.SpigotConfig.playerSample)]; // Paper int j = MathHelper.nextInt(this.n, 0, this.getPlayerCount() - agameprofile.length); for (int k = 0; k < agameprofile.length; ++k) { agameprofile[k] = ((EntityPlayer) this.playerList.v().get(j + k)).getProfile(); } Collections.shuffle(Arrays.asList(agameprofile)); this.m.b().a(agameprofile); } //this.methodProfiler.enter(* // Akarin - remove caller serverAutoSave = (autosavePeriod > 0 && this.ticks % autosavePeriod == 0); // Paper int playerSaveInterval = com.destroystokyo.paper.PaperConfig.playerAutoSaveRate; if (playerSaveInterval < 0) { playerSaveInterval = autosavePeriod; } if (playerSaveInterval > 0) { // CraftBukkit // Paper this.playerList.savePlayers(playerSaveInterval); // Spigot Start } // Paper - Incremental Auto Saving // We replace this with saving each individual world as this.saveChunks(...) is broken, // and causes the main thread to sleep for random amounts of time depending on chunk activity // Also pass flag to only save modified chunks server.playerCommandState = true; for (World world : getWorlds()) { if (world.paperConfig.autoSavePeriod > 0) world.getWorld().save(false); // Paper - Incremental / Configurable Auto Saving } server.playerCommandState = false; // this.saveChunks(true); // Spigot End ////this.methodProfiler.exit(); // Akarin // Akarin - remove caller //} // Paper - Incremental Auto Saving //this.methodProfiler.enter(* // Akarin - remove caller if (getSnooperEnabled() && !this.snooper.d() && this.ticks > 100) { // Spigot this.snooper.a(); } if (getSnooperEnabled() && this.ticks % 6000 == 0) { // Spigot this.snooper.b(); } //this.methodProfiler.exit(); // Akarin //this.methodProfiler.enter(* // Akarin - remove caller long l = this.d[this.ticks % 100] = SystemUtils.getMonotonicNanos() - i; this.ap = this.ap * 0.8F + (float) l / 1000000.0F * 0.19999999F; //this.methodProfiler.exit(); // Akarin //this.methodProfiler.exit(); // Akarin org.spigotmc.WatchdogThread.tick(); // Spigot PaperLightingQueue.processQueue(startTime); // Paper expiringMaps.removeIf(ExpiringMap::clean); // Paper this.slackActivityAccountant.tickEnded(l); // Spigot co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTiming(); // Paper // Akarin } public void b(BooleanSupplier booleansupplier) { MinecraftTimings.bukkitSchedulerTimer.startTimingUnsafe(); // Paper // Akarin this.server.getScheduler().mainThreadHeartbeat(this.ticks); // CraftBukkit MinecraftTimings.bukkitSchedulerTimer.stopTimingUnsafe(); // Paper // Akarin MinecraftTimings.minecraftSchedulerTimer.startTimingUnsafe(); // Paper // Akarin //this.methodProfiler.enter(* // Akarin - remove caller FutureTask futuretask; while ((futuretask = (FutureTask) this.f.poll()) != null) { SystemUtils.a(futuretask, MinecraftServer.LOGGER); } PaperAsyncChunkProvider.processMainThreadQueue(this); // Paper MinecraftTimings.minecraftSchedulerTimer.stopTimingUnsafe(); // Paper // Akarin //this.methodProfiler.exitEnter("commandFunctions"); // Akarin MinecraftTimings.commandFunctionsTimer.startTimingUnsafe(); // Spigot // Akarin this.getFunctionData().tick(); MinecraftTimings.commandFunctionsTimer.stopTimingUnsafe(); // Spigot // Akarin //this.methodProfiler.exitEnter("levels"); // Akarin // CraftBukkit start // Run tasks that are waiting on processing MinecraftTimings.processQueueTimer.startTimingUnsafe(); // Spigot // Akarin while (!processQueue.isEmpty()) { processQueue.remove().run(); } MinecraftTimings.processQueueTimer.stopTimingUnsafe(); // Spigot // Akarin MinecraftTimings.chunkIOTickTimer.startTimingUnsafe(); // Spigot // Akarin org.bukkit.craftbukkit.chunkio.ChunkIOExecutor.tick(); MinecraftTimings.chunkIOTickTimer.stopTimingUnsafe(); // Spigot // Akarin MinecraftTimings.timeUpdateTimer.startTimingUnsafe(); // Spigot // Akarin // Send time updates to everyone, it will get the right time from the world the player is in. // Paper start - optimize time updates for (final WorldServer world : this.getWorlds()) { final boolean doDaylight = world.getGameRules().getBoolean("doDaylightCycle"); final long dayTime = world.getDayTime(); long worldTime = world.getTime(); final PacketPlayOutUpdateTime worldPacket = new PacketPlayOutUpdateTime(worldTime, dayTime, doDaylight); for (EntityHuman entityhuman : world.players) { if (!(entityhuman instanceof EntityPlayer) || (ticks + entityhuman.getId()) % 20 != 0) { continue; } EntityPlayer entityplayer = (EntityPlayer) entityhuman; long playerTime = entityplayer.getPlayerTime(); PacketPlayOutUpdateTime packet = (playerTime == dayTime) ? worldPacket : new PacketPlayOutUpdateTime(worldTime, playerTime, doDaylight); entityplayer.playerConnection.sendPacket(packet); // Add support for per player time } } // Paper end MinecraftTimings.timeUpdateTimer.stopTimingUnsafe(); // Spigot // Akarin // WorldServer worldserver; // CraftBukkit - dropped down long i; // CraftBukkit - dropTickTime for (Iterator iterator = this.getWorlds().iterator(); iterator.hasNext();) { WorldServer worldserver = (WorldServer) iterator.next(); PaperAsyncChunkProvider.processMainThreadQueue(worldserver); // Paper worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper TileEntityHopper.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper i = SystemUtils.getMonotonicNanos(); if (true || worldserver.worldProvider.getDimensionManager() == DimensionManager.OVERWORLD || this.getAllowNether()) { // CraftBukkit this.methodProfiler.a(() -> { return "dim-" + worldserver.worldProvider.getDimensionManager().getDimensionID(); }); /* Drop global time updates if (this.ticks % 20 == 0) { //this.methodProfiler.enter(* // Akarin - remove caller this.playerList.a((Packet) (new PacketPlayOutUpdateTime(worldserver.getTime(), worldserver.getDayTime(), worldserver.getGameRules().getBoolean("doDaylightCycle"))), worldserver.worldProvider.getDimensionManager()); //this.methodProfiler.exit(); // Akarin } // CraftBukkit end */ //this.methodProfiler.enter(* // Akarin - remove caller CrashReport crashreport; try { worldserver.timings.doTick.startTimingUnsafe(); // Spigot // Akarin worldserver.doTick(booleansupplier); worldserver.timings.doTick.stopTimingUnsafe(); // Spigot // Akarin } catch (Throwable throwable) { // Spigot Start try { crashreport = CrashReport.a(throwable, "Exception ticking world"); } catch (Throwable t){ throw new RuntimeException("Error generating crash report", t); } // Spigot End worldserver.a(crashreport); throw new ReportedException(crashreport); } try { worldserver.timings.tickEntities.startTimingUnsafe(); // Spigot // Akarin worldserver.tickEntities(); worldserver.timings.tickEntities.stopTimingUnsafe(); // Spigot // Akarin } catch (Throwable throwable1) { // Spigot Start try { crashreport = CrashReport.a(throwable1, "Exception ticking world entities"); } catch (Throwable t){ throw new RuntimeException("Error generating crash report", t); } // Spigot End worldserver.a(crashreport); throw new ReportedException(crashreport); } //this.methodProfiler.exit(); // Akarin //this.methodProfiler.enter(* // Akarin - remove caller if (playerList.players.size() > 0) worldserver.getTracker().updatePlayers(); // Paper - No players, why spend time tracking them? (See patch) //this.methodProfiler.exit(); // Akarin //this.methodProfiler.exit(); // Akarin worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions } } //this.methodProfiler.exitEnter("connection"); // Akarin MinecraftTimings.connectionTimer.startTimingUnsafe(); // Spigot // Akarin this.getServerConnection().c(); MinecraftTimings.connectionTimer.stopTimingUnsafe(); // Spigot // Akarin //this.methodProfiler.exitEnter("players"); // Akarin MinecraftTimings.playerListTimer.startTimingUnsafe(); // Spigot // Akarin this.playerList.tick(); MinecraftTimings.playerListTimer.stopTimingUnsafe(); // Spigot // Akarin //this.methodProfiler.exitEnter("tickables"); // Akarin MinecraftTimings.tickablesTimer.startTimingUnsafe(); // Spigot // Akarin for (int j = 0; j < this.k.size(); ++j) { ((ITickable) this.k.get(j)).tick(); } MinecraftTimings.tickablesTimer.stopTimingUnsafe(); // Spigot // Akarin //this.methodProfiler.exit(); // Akarin } public boolean getAllowNether() { return true; } public void a(ITickable itickable) { this.k.add(itickable); } public static void main(final OptionSet options) { // CraftBukkit - replaces main(String[] astring) DispenserRegistry.c(); try { /* CraftBukkit start - Replace everything boolean flag = true; String s = null; String s1 = "."; String s2 = null; boolean flag1 = false; boolean flag2 = false; boolean flag3 = false; int i = -1; for (int j = 0; j < astring.length; ++j) { String s3 = astring[j]; String s4 = j == astring.length - 1 ? null : astring[j + 1]; boolean flag4 = false; if (!"nogui".equals(s3) && !"--nogui".equals(s3)) { if ("--port".equals(s3) && s4 != null) { flag4 = true; try { i = Integer.parseInt(s4); } catch (NumberFormatException numberformatexception) { ; } } else if ("--singleplayer".equals(s3) && s4 != null) { flag4 = true; s = s4; } else if ("--universe".equals(s3) && s4 != null) { flag4 = true; s1 = s4; } else if ("--world".equals(s3) && s4 != null) { flag4 = true; s2 = s4; } else if ("--demo".equals(s3)) { flag1 = true; } else if ("--bonusChest".equals(s3)) { flag2 = true; } else if ("--forceUpgrade".equals(s3)) { flag3 = true; } } else { flag = false; } if (flag4) { ++j; } } */ // CraftBukkit end String s1 = "."; // PAIL? YggdrasilAuthenticationService yggdrasilauthenticationservice = new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY, UUID.randomUUID().toString()); // Paper MinecraftSessionService minecraftsessionservice = yggdrasilauthenticationservice.createMinecraftSessionService(); GameProfileRepository gameprofilerepository = yggdrasilauthenticationservice.createProfileRepository(); UserCache usercache = new UserCache(gameprofilerepository, new File(s1, MinecraftServer.a.getName())); final DedicatedServer dedicatedserver = new DedicatedServer(options, DataConverterRegistry.a(), yggdrasilauthenticationservice, minecraftsessionservice, gameprofilerepository, usercache); /* CraftBukkit start if (s != null) { dedicatedserver.h(s); } if (s2 != null) { dedicatedserver.setWorld(s2); } if (i >= 0) { dedicatedserver.setPort(i); } if (flag1) { dedicatedserver.c(true); } if (flag2) { dedicatedserver.d(true); } if (flag && !GraphicsEnvironment.isHeadless()) { dedicatedserver.aW(); } if (flag3) { dedicatedserver.setForceUpgrade(true); } dedicatedserver.v(); Thread thread = new Thread("Server Shutdown Thread") { public void run() { dedicatedserver.stop(); } }; thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(MinecraftServer.LOGGER)); Runtime.getRuntime().addShutdownHook(thread); */ if (options.has("port")) { int port = (Integer) options.valueOf("port"); if (port > 0) { dedicatedserver.setPort(port); } } if (options.has("universe")) { dedicatedserver.universe = (File) options.valueOf("universe"); } if (options.has("world")) { dedicatedserver.setWorld((String) options.valueOf("world")); } if (options.has("forceUpgrade")) { dedicatedserver.setForceUpgrade(true); } dedicatedserver.primaryThread.start(); // CraftBukkit end } catch (Exception exception) { MinecraftServer.LOGGER.fatal("Failed to start the minecraft server", exception); } } protected void setForceUpgrade(boolean flag) { this.forceUpgrade = flag; } public void v() { /* CraftBukkit start - prevent abuse this.serverThread = new Thread(this, "Server thread"); this.serverThread.setUncaughtExceptionHandler((thread, throwable) -> { MinecraftServer.LOGGER.error(throwable); }); this.serverThread.start(); // CraftBukkit end */ } public File c(String s) { return new File(this.s(), s); } public void info(String s) { MinecraftServer.LOGGER.info(s); } public void warning(String s) { MinecraftServer.LOGGER.warn(s); } public WorldServer getWorldServer(DimensionManager dimensionmanager) { return (WorldServer) this.worldServer.get(dimensionmanager); } public Iterable getWorlds() { return this.worldServer.values(); } public String getVersion() { return "1.13.2"; } public int getPlayerCount() { return this.playerList.getPlayerCount(); } public int getMaxPlayers() { return this.playerList.getMaxPlayers(); } public String[] getPlayers() { return this.playerList.f(); } public boolean isDebugging() { return this.getPropertyManager().getBoolean("debug", false); // CraftBukkit - don't hardcode } public void f(String s) { MinecraftServer.LOGGER.error(s); } public void g(String s) { if (this.isDebugging()) { MinecraftServer.LOGGER.info(s); } } public String getServerModName() { return "Paper"; //Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla! } public CrashReport b(CrashReport crashreport) { crashreport.g().a("Profiler Position", () -> { return this.methodProfiler.a() ? this.methodProfiler.f() : "N/A (disabled)"; }); if (this.playerList != null) { crashreport.g().a("Player Count", () -> { return this.playerList.getPlayerCount() + " / " + this.playerList.getMaxPlayers() + "; " + this.playerList.v(); }); } crashreport.g().a("Data Packs", () -> { StringBuilder stringbuilder = new StringBuilder(); Iterator iterator = this.resourcePackRepository.d().iterator(); while (iterator.hasNext()) { ResourcePackLoader resourcepackloader = (ResourcePackLoader) iterator.next(); if (stringbuilder.length() > 0) { stringbuilder.append(", "); } stringbuilder.append(resourcepackloader.e()); if (!resourcepackloader.c().a()) { stringbuilder.append(" (incompatible)"); } } return stringbuilder.toString(); }); return crashreport; } public boolean D() { return true; // CraftBukkit } public void sendMessage(IChatBaseComponent ichatbasecomponent) { MinecraftServer.LOGGER.info(org.bukkit.craftbukkit.util.CraftChatMessage.fromComponent(ichatbasecomponent, net.minecraft.server.EnumChatFormat.WHITE));// Paper - Log message with colors } public KeyPair E() { return this.H; } public int getPort() { return this.q; } public void setPort(int i) { this.q = i; } public String G() { return this.I; } public void h(String s) { this.I = s; } public boolean H() { return this.I != null; } public String getWorld() { return this.J; } public void setWorld(String s) { this.J = s; } public void a(KeyPair keypair) { this.H = keypair; } public void a(EnumDifficulty enumdifficulty) { Iterator iterator = this.getWorlds().iterator(); while (iterator.hasNext()) { WorldServer worldserver = (WorldServer) iterator.next(); if (worldserver.getWorldData().isHardcore()) { worldserver.getWorldData().setDifficulty(EnumDifficulty.HARD); worldserver.setSpawnFlags(true, true); } else if (this.H()) { worldserver.getWorldData().setDifficulty(enumdifficulty); worldserver.setSpawnFlags(worldserver.getDifficulty() != EnumDifficulty.PEACEFUL, true); } else { worldserver.getWorldData().setDifficulty(enumdifficulty); worldserver.setSpawnFlags(this.getSpawnMonsters(), this.spawnAnimals); } } } public boolean getSpawnMonsters() { return true; } public boolean L() { return this.demoMode; } public void c(boolean flag) { this.demoMode = flag; } public void d(boolean flag) { this.M = flag; } public Convertable getConvertable() { return this.convertable; } public String getResourcePack() { return this.N; } public String getResourcePackHash() { return this.O; } public void setResourcePack(String s, String s1) { this.N = s; this.O = s1; } public void a(MojangStatisticsGenerator mojangstatisticsgenerator) { mojangstatisticsgenerator.a("whitelist_enabled", false); mojangstatisticsgenerator.a("whitelist_count", 0); if (this.playerList != null) { mojangstatisticsgenerator.a("players_current", this.getPlayerCount()); mojangstatisticsgenerator.a("players_max", this.getMaxPlayers()); mojangstatisticsgenerator.a("players_seen", this.playerList.getSeenPlayers().length); } mojangstatisticsgenerator.a("uses_auth", this.onlineMode); mojangstatisticsgenerator.a("gui_state", this.ag() ? "enabled" : "disabled"); mojangstatisticsgenerator.a("run_time", (SystemUtils.getMonotonicMillis() - mojangstatisticsgenerator.g()) / 60L * 1000L); mojangstatisticsgenerator.a("avg_tick_ms", (int) (MathHelper.a(this.d) * 1.0E-6D)); int i = 0; Iterator iterator = this.getWorlds().iterator(); while (iterator.hasNext()) { WorldServer worldserver = (WorldServer) iterator.next(); if (worldserver != null) { WorldData worlddata = worldserver.getWorldData(); mojangstatisticsgenerator.a("world[" + i + "][dimension]", worldserver.worldProvider.getDimensionManager()); mojangstatisticsgenerator.a("world[" + i + "][mode]", worlddata.getGameType()); mojangstatisticsgenerator.a("world[" + i + "][difficulty]", worldserver.getDifficulty()); mojangstatisticsgenerator.a("world[" + i + "][hardcore]", worlddata.isHardcore()); mojangstatisticsgenerator.a("world[" + i + "][generator_name]", worlddata.getType().name()); mojangstatisticsgenerator.a("world[" + i + "][generator_version]", worlddata.getType().getVersion()); mojangstatisticsgenerator.a("world[" + i + "][height]", this.F); mojangstatisticsgenerator.a("world[" + i + "][chunks_loaded]", worldserver.getChunkProvider().g()); ++i; } } mojangstatisticsgenerator.a("worlds", i); } public boolean getSnooperEnabled() { return true; } public abstract boolean Q(); public boolean getOnlineMode() { return server.getOnlineMode(); // CraftBukkit } public void setOnlineMode(boolean flag) { this.onlineMode = flag; } public boolean S() { return this.z; } public void f(boolean flag) { this.z = flag; } public boolean getSpawnAnimals() { return this.spawnAnimals; } public void setSpawnAnimals(boolean flag) { this.spawnAnimals = flag; } public boolean getSpawnNPCs() { return this.spawnNPCs; } public abstract boolean V(); public void setSpawnNPCs(boolean flag) { this.spawnNPCs = flag; } public boolean getPVP() { return this.pvpMode; } public void setPVP(boolean flag) { this.pvpMode = flag; } public boolean getAllowFlight() { return this.allowFlight; } public void setAllowFlight(boolean flag) { this.allowFlight = flag; } public abstract boolean getEnableCommandBlock(); public String getMotd() { return this.motd; } public void setMotd(String s) { this.motd = s; } public int getMaxBuildHeight() { return this.F; } public void b(int i) { this.F = i; } public boolean isStopped() { return this.isStopped; } public PlayerList getPlayerList() { return this.playerList; } public void a(PlayerList playerlist) { this.playerList = playerlist; } public abstract boolean ad(); public void setGamemode(EnumGamemode enumgamemode) { Iterator iterator = this.getWorlds().iterator(); while (iterator.hasNext()) { WorldServer worldserver = (WorldServer) iterator.next(); worldserver.getWorldData().setGameType(enumgamemode); } } public ServerConnection getServerConnection() { return this.serverConnection == null ? this.serverConnection = new ServerConnection(this) : this.serverConnection; // Spigot } public boolean ag() { return false; } public abstract boolean a(EnumGamemode enumgamemode, boolean flag, int i); public int ah() { return this.ticks; } public void ai() { this.S = true; } public int getSpawnProtection() { return 16; } public boolean a(World world, BlockPosition blockposition, EntityHuman entityhuman) { return false; } public void setForceGamemode(boolean flag) { this.T = flag; } public boolean getForceGamemode() { return this.T; } public int getIdleTimeout() { return this.G; } public void setIdleTimeout(int i) { this.G = i; } public MinecraftSessionService getSessionService() { return ap(); } // Paper - OBFHELPER public MinecraftSessionService ap() { return this.V; } public GameProfileRepository getGameProfileRepository() { return this.W; } public UserCache getUserCache() { return this.X; } // Akarin start private final AkarinUserCache userCache; public AkarinUserCache getModernUserCache() { return userCache; } // Akarin end public ServerPing getServerPing() { return this.m; } public void at() { this.Y = 0L; } public int au() { return 29999984; } public ListenableFuture a(Callable callable) { Validate.notNull(callable); if (!this.isMainThread()) { // CraftBukkit && !this.isStopped()) { ListenableFutureTask listenablefuturetask = ListenableFutureTask.create(callable); this.f.offer(listenablefuturetask); // Akarin - add -> offer return listenablefuturetask; } else { try { return Futures.immediateFuture(callable.call()); } catch (Exception exception) { return Futures.immediateFailedCheckedFuture(exception); } } } // Akarin start @Override public void ensuresMainThread(Runnable runnable) { this.f.offer(ListenableFutureTask.create(runnable, null)); } // Akarin end public ListenableFuture postToMainThread(Runnable runnable) { Validate.notNull(runnable); return this.a(Executors.callable(runnable)); } public boolean isMainThread() { return ThreadAssertion.isMainThread() || Thread.currentThread() == this.serverThread; // Akarin } public int aw() { return 256; } public long ax() { return this.nextTick; } public Thread ay() { return this.serverThread; } public DataFixer az() { return this.dataConverterManager; } public int a(@Nullable WorldServer worldserver) { return worldserver != null ? worldserver.getGameRules().c("spawnRadius") : 10; } public AdvancementDataWorld getAdvancementData() { return this.al; } public CustomFunctionData getFunctionData() { return this.am; } public void reload() { if (!this.isMainThread()) { this.postToMainThread(this::reload); } else { this.getPlayerList().savePlayers(); this.resourcePackRepository.a(); this.a(this.getWorldServer(DimensionManager.OVERWORLD).getWorldData()); this.getPlayerList().reload(); } } private void a(WorldData worlddata) { List list = Lists.newArrayList(this.resourcePackRepository.d()); Iterator iterator = this.resourcePackRepository.b().iterator(); while (iterator.hasNext()) { ResourcePackLoader resourcepackloader = (ResourcePackLoader) iterator.next(); if (!worlddata.N().contains(resourcepackloader.e()) && !list.contains(resourcepackloader)) { MinecraftServer.LOGGER.info("Found new data pack {}, loading it automatically", resourcepackloader.e()); resourcepackloader.h().a(list, resourcepackloader, (resourcepackloader1) -> { return resourcepackloader1; }, false); } } this.resourcePackRepository.a((Collection) list); List list1 = Lists.newArrayList(); this.resourcePackRepository.d().forEach((resourcepackloader1) -> { list1.add(resourcepackloader1.d()); }); this.ac.a((List) list1); worlddata.O().clear(); worlddata.N().clear(); this.resourcePackRepository.d().forEach((resourcepackloader1) -> { worlddata.O().add(resourcepackloader1.e()); }); this.resourcePackRepository.b().forEach((resourcepackloader1) -> { if (!this.resourcePackRepository.d().contains(resourcepackloader1)) { worlddata.N().add(resourcepackloader1.e()); } }); } public void a(CommandListenerWrapper commandlistenerwrapper) { if (this.aQ()) { PlayerList playerlist = commandlistenerwrapper.getServer().getPlayerList(); WhiteList whitelist = playerlist.getWhitelist(); if (whitelist.isEnabled()) { List list = Lists.newArrayList(playerlist.v()); Iterator iterator = list.iterator(); while (iterator.hasNext()) { EntityPlayer entityplayer = (EntityPlayer) iterator.next(); if (!whitelist.isWhitelisted(entityplayer.getProfile())) { entityplayer.playerConnection.disconnect(new ChatMessage("multiplayer.disconnect.not_whitelisted", new Object[0])); } } } } } public IReloadableResourceManager getResourceManager() { return this.ac; } public ResourcePackRepository getResourcePackRepository() { return this.resourcePackRepository; } public CommandDispatcher getCommandDispatcher() { return this.commandDispatcher; } public CommandListenerWrapper getServerCommandListener() { return new CommandListenerWrapper(this, this.getWorldServer(DimensionManager.OVERWORLD) == null ? Vec3D.a : new Vec3D(this.getWorldServer(DimensionManager.OVERWORLD).getSpawn()), Vec2F.a, this.getWorldServer(DimensionManager.OVERWORLD), 4, "Server", new ChatComponentText("Server"), this, (Entity) null); } public boolean a() { return true; } public boolean b() { return true; } public CraftingManager getCraftingManager() { return this.ag; } public TagRegistry getTagRegistry() { return this.ah; } public ScoreboardServer getScoreboard() { return this.ai; } public LootTableRegistry getLootTableRegistry() { return this.ak; } public GameRules getGameRules() { return this.getWorldServer(DimensionManager.OVERWORLD).getGameRules(); } public BossBattleCustomData getBossBattleCustomData() { return this.aj; } public boolean aQ() { return this.an; } public void l(boolean flag) { this.an = flag; } public int a(GameProfile gameprofile) { if (this.getPlayerList().isOp(gameprofile)) { OpListEntry oplistentry = (OpListEntry) this.getPlayerList().getOPs().get(gameprofile); return oplistentry != null ? oplistentry.a() : (this.H() ? (this.G().equals(gameprofile.getName()) ? 4 : (this.getPlayerList().x() ? 4 : 0)) : this.j()); } else { return 0; } } // CraftBukkit start //@Deprecated // Akarin - remove deprecated public static MinecraftServer getServer() { return SERVER; } // CraftBukkit end }