package net.minecraft.server;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListenableFutureTask;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.GameProfileRepository;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.base64.Base64;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.Proxy;
import java.security.KeyPair;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import javax.imageio.ImageIO;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandResultStats;
import net.minecraft.command.ICommandManager;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.ServerCommandManager;
import net.minecraft.crash.CrashReport;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Bootstrap;
import net.minecraft.network.NetworkSystem;
import net.minecraft.network.ServerStatusResponse;
import net.minecraft.network.play.server.S03PacketTimeUpdate;
import net.minecraft.network.rcon.RConConsoleSource;
import net.minecraft.profiler.IPlayerUsage;
import net.minecraft.profiler.PlayerUsageSnooper;
import net.minecraft.profiler.Profiler;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.gui.IUpdatePlayerListBox;
import net.minecraft.server.management.PlayerProfileCache;
import net.minecraft.server.management.ServerConfigurationManager;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.IProgressUpdate;
import net.minecraft.util.IThreadListener;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ReportedException;
import net.minecraft.util.Vec3;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.MinecraftException;
import net.minecraft.world.World;
import net.minecraft.world.WorldManager;
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldServerMulti;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.WorldType;
import net.minecraft.world.chunk.storage.AnvilSaveConverter;
import net.minecraft.world.demo.DemoWorldServer;
import net.minecraft.world.storage.ISaveFormat;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.WorldInfo;
import org.apache.commons.lang3.Validate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public abstract class MinecraftServer implements ICommandSender, Runnable, IThreadListener, IPlayerUsage {
private static final Logger logger = LogManager.getLogger();
public static final File USER_CACHE_FILE = new File("usercache.json");
/**
* Instance of Minecraft Server.
*/
private static MinecraftServer mcServer;
private final ISaveFormat anvilConverterForAnvilFile;
/**
* The PlayerUsageSnooper instance.
*/
private final PlayerUsageSnooper usageSnooper = new PlayerUsageSnooper("server", this, getCurrentTimeMillis());
private final File anvilFile;
/**
* List of names of players who are online.
*/
private final List playersOnline = Lists.newArrayList();
private final ICommandManager commandManager;
public final Profiler theProfiler = new Profiler();
private final NetworkSystem networkSystem;
private final ServerStatusResponse statusResponse = new ServerStatusResponse();
private final Random random = new Random();
/**
* The server's hostname.
*/
private String hostname;
/**
* The server's port.
*/
private int serverPort = -1;
/**
* The server world instances.
*/
public WorldServer[] worldServers;
/**
* The ServerConfigurationManager instance.
*/
private ServerConfigurationManager serverConfigManager;
/**
* Indicates whether the server is running or not. Set to false to initiate
* a shutdown.
*/
private boolean serverRunning = true;
/**
* Indicates to other classes that the server is safely stopped.
*/
private boolean serverStopped;
/**
* Incremented every tick.
*/
private int tickCounter;
protected final Proxy serverProxy;
/**
* The task the server is currently working on(and will output on
* outputPercentRemaining).
*/
public String currentTask;
/**
* The percentage of the current task finished so far.
*/
public int percentDone;
/**
* True if the server is in online mode.
*/
private boolean onlineMode;
/**
* True if the server has animals turned on.
*/
private boolean canSpawnAnimals;
private boolean canSpawnNPCs;
/**
* Indicates whether PvP is active on the server or not.
*/
private boolean pvpEnabled;
/**
* Determines if flight is allowed or not.
*/
private boolean allowFlight;
/**
* The server MOTD string.
*/
private String motd;
/**
* Maximum build height.
*/
private int buildLimit;
private int maxPlayerIdleMinutes = 0;
public final long[] tickTimeArray = new long[100];
/**
* Stats are [dimension][tick%100] system.nanoTime is stored.
*/
public long[][] timeOfLastDimensionTick;
private KeyPair serverKeyPair;
/**
* Username of the server owner (for integrated servers)
*/
private String serverOwner;
private String folderName;
private boolean isDemo;
private boolean enableBonusChest;
/**
* If true, there is no need to save chunks or stop the server, because that
* is already being done.
*/
private boolean worldIsBeingDeleted;
/**
* The texture pack for the server
*/
private String resourcePackUrl = "";
private String resourcePackHash = "";
private boolean serverIsRunning;
/**
* Set when warned for "Can't keep up", which triggers again after 15
* seconds.
*/
private long timeOfLastWarning;
private String userMessage;
private boolean startProfiling;
private boolean isGamemodeForced;
private final YggdrasilAuthenticationService authService;
private final MinecraftSessionService sessionService;
private long nanoTimeSinceStatusRefresh = 0L;
private final GameProfileRepository profileRepo;
private final PlayerProfileCache profileCache;
protected final Queue futureTaskQueue = Queues.newArrayDeque();
private Thread serverThread;
private long currentTime = getCurrentTimeMillis();
private static final String __OBFID = "CL_00001462";
public MinecraftServer(File workDir, Proxy proxy, File profileCacheDir) {
this.serverProxy = proxy;
mcServer = this;
this.anvilFile = workDir;
this.networkSystem = new NetworkSystem(this);
this.profileCache = new PlayerProfileCache(this, profileCacheDir);
this.commandManager = this.createNewCommandManager();
this.anvilConverterForAnvilFile = new AnvilSaveConverter(workDir);
this.authService = new YggdrasilAuthenticationService(proxy, UUID.randomUUID().toString());
this.sessionService = this.authService.createMinecraftSessionService();
this.profileRepo = this.authService.createProfileRepository();
}
protected ServerCommandManager createNewCommandManager() {
return new ServerCommandManager();
}
/**
* Initialises the server and starts it.
*/
protected abstract boolean startServer() throws IOException;
protected void convertMapIfNeeded(String worldNameIn) {
if (this.getActiveAnvilConverter().isOldMapFormat(worldNameIn)) {
logger.info("Converting map!");
this.setUserMessage("menu.convertingLevel");
this.getActiveAnvilConverter().convertMapFormat(worldNameIn, new IProgressUpdate() {
private long startTime = System.currentTimeMillis();
private static final String __OBFID = "CL_00001417";
public void displaySavingString(String message) {
}
public void setLoadingProgress(int progress) {
if (System.currentTimeMillis() - this.startTime >= 1000L) {
this.startTime = System.currentTimeMillis();
MinecraftServer.logger.info("Converting... " + progress + "%");
}
}
public void displayLoadingString(String message) {
}
});
}
}
/**
* Typically "menu.convertingLevel", "menu.loadingLevel" or others.
*/
protected synchronized void setUserMessage(String message) {
this.userMessage = message;
}
protected void loadAllWorlds(String p_71247_1_, String p_71247_2_, long seed, WorldType type, String p_71247_6_) {
this.convertMapIfNeeded(p_71247_1_);
this.setUserMessage("menu.loadingLevel");
this.worldServers = new WorldServer[3];
this.timeOfLastDimensionTick = new long[this.worldServers.length][100];
ISaveHandler var7 = this.anvilConverterForAnvilFile.getSaveLoader(p_71247_1_, true);
this.setResourcePackFromWorld(this.getFolderName(), var7);
WorldInfo var9 = var7.loadWorldInfo();
WorldSettings var8;
if (var9 == null) {
if (this.isDemo()) {
var8 = DemoWorldServer.demoWorldSettings;
} else {
var8 = new WorldSettings(seed, this.getGameType(), this.canStructuresSpawn(), this.isHardcore(), type);
var8.setWorldName(p_71247_6_);
if (this.enableBonusChest) {
var8.enableBonusChest();
}
}
var9 = new WorldInfo(var8, p_71247_2_);
} else {
var9.setWorldName(p_71247_2_);
var8 = new WorldSettings(var9);
}
for (int var10 = 0; var10 < this.worldServers.length; ++var10) {
byte var11 = 0;
if (var10 == 1) {
var11 = -1;
}
if (var10 == 2) {
var11 = 1;
}
if (var10 == 0) {
if (this.isDemo()) {
this.worldServers[var10] = (WorldServer) (new DemoWorldServer(this, var7, var9, var11, this.theProfiler)).init();
} else {
this.worldServers[var10] = (WorldServer) (new WorldServer(this, var7, var9, var11, this.theProfiler)).init();
}
this.worldServers[var10].initialize(var8);
} else {
this.worldServers[var10] = (WorldServer) (new WorldServerMulti(this, var7, var11, this.worldServers[0], this.theProfiler)).init();
}
this.worldServers[var10].addWorldAccess(new WorldManager(this, this.worldServers[var10]));
if (!this.isSinglePlayer()) {
this.worldServers[var10].getWorldInfo().setGameType(this.getGameType());
}
}
this.serverConfigManager.setPlayerManager(this.worldServers);
this.setDifficultyForAllWorlds(this.getDifficulty());
this.initialWorldChunkLoad();
}
protected void initialWorldChunkLoad() {
boolean var1 = true;
boolean var2 = true;
boolean var3 = true;
boolean var4 = true;
int var5 = 0;
this.setUserMessage("menu.generatingTerrain");
byte var6 = 0;
logger.info("Preparing start region for level " + var6);
WorldServer var7 = this.worldServers[var6];
BlockPos var8 = var7.getSpawnPoint();
long var9 = getCurrentTimeMillis();
for (int var11 = -192; var11 <= 192 && this.isServerRunning(); var11 += 16) {
for (int var12 = -192; var12 <= 192 && this.isServerRunning(); var12 += 16) {
long var13 = getCurrentTimeMillis();
if (var13 - var9 > 1000L) {
this.outputPercentRemaining("Preparing spawn area", var5 * 100 / 625);
var9 = var13;
}
++var5;
var7.theChunkProviderServer.loadChunk(var8.getX() + var11 >> 4, var8.getZ() + var12 >> 4);
}
}
this.clearCurrentTask();
}
protected void setResourcePackFromWorld(String worldNameIn, ISaveHandler saveHandlerIn) {
File var3 = new File(saveHandlerIn.getWorldDirectory(), "resources.zip");
if (var3.isFile()) {
this.setResourcePack("level://" + worldNameIn + "/" + var3.getName(), "");
}
}
public abstract boolean canStructuresSpawn();
public abstract WorldSettings.GameType getGameType();
/**
* Get the server's difficulty
*/
public abstract EnumDifficulty getDifficulty();
/**
* Defaults to false.
*/
public abstract boolean isHardcore();
public abstract int getOpPermissionLevel();
/**
* Used to display a percent remaining given text and the percentage.
*/
protected void outputPercentRemaining(String message, int percent) {
this.currentTask = message;
this.percentDone = percent;
logger.info(message + ": " + percent + "%");
}
/**
* Set current task to null and set its percentage to 0.
*/
protected void clearCurrentTask() {
this.currentTask = null;
this.percentDone = 0;
}
/**
* par1 indicates if a log message should be output.
*/
protected void saveAllWorlds(boolean dontLog) {
if (!this.worldIsBeingDeleted) {
WorldServer[] var2 = this.worldServers;
int var3 = var2.length;
for (int var4 = 0; var4 < var3; ++var4) {
WorldServer var5 = var2[var4];
if (var5 != null) {
if (!dontLog) {
logger.info("Saving chunks for level \'" + var5.getWorldInfo().getWorldName() + "\'/" + var5.provider.getDimensionName());
}
try {
var5.saveAllChunks(true, (IProgressUpdate) null);
} catch (MinecraftException var7) {
logger.warn(var7.getMessage());
}
}
}
}
}
/**
* Saves all necessary data as preparation for stopping the server.
*/
public void stopServer() {
if (!this.worldIsBeingDeleted) {
logger.info("Stopping server");
if (this.getNetworkSystem() != null) {
this.getNetworkSystem().terminateEndpoints();
}
if (this.serverConfigManager != null) {
logger.info("Saving players");
this.serverConfigManager.saveAllPlayerData();
this.serverConfigManager.removeAllPlayers();
}
if (this.worldServers != null) {
logger.info("Saving worlds");
this.saveAllWorlds(false);
for (int var1 = 0; var1 < this.worldServers.length; ++var1) {
WorldServer var2 = this.worldServers[var1];
var2.flush();
}
}
if (this.usageSnooper.isSnooperRunning()) {
this.usageSnooper.stopSnooper();
}
}
}
/**
* "getHostname" is already taken, but both return the hostname.
*/
public String getServerHostname() {
return this.hostname;
}
public void setHostname(String host) {
this.hostname = host;
}
public boolean isServerRunning() {
return this.serverRunning;
}
/**
* Sets the serverRunning variable to false, in order to get the server to
* shut down.
*/
public void initiateShutdown() {
this.serverRunning = false;
}
public void run() {
try {
if (this.startServer()) {
this.currentTime = getCurrentTimeMillis();
long var1 = 0L;
this.statusResponse.setServerDescription(new ChatComponentText(this.motd));
this.statusResponse.setProtocolVersionInfo(new ServerStatusResponse.MinecraftProtocolVersionIdentifier("1.8", 47));
this.addFaviconToStatusResponse(this.statusResponse);
while (this.serverRunning) {
long var48 = getCurrentTimeMillis();
long var5 = var48 - this.currentTime;
if (var5 > 2000L && this.currentTime - this.timeOfLastWarning >= 15000L) {
logger.warn("Can\'t keep up! Did the system time change, or is the server overloaded? Running {}ms behind, skipping {} tick(s)", new Object[]{Long.valueOf(var5), Long.valueOf(var5 / 50L)});
var5 = 2000L;
this.timeOfLastWarning = this.currentTime;
}
if (var5 < 0L) {
logger.warn("Time ran backwards! Did the system time change?");
var5 = 0L;
}
var1 += var5;
this.currentTime = var48;
if (this.worldServers[0].areAllPlayersAsleep()) {
this.tick();
var1 = 0L;
} else {
while (var1 > 50L) {
var1 -= 50L;
this.tick();
}
}
Thread.sleep(Math.max(1L, 50L - var1));
this.serverIsRunning = true;
}
} else {
this.finalTick((CrashReport) null);
}
} catch (Throwable var46) {
logger.error("Encountered an unexpected exception", var46);
CrashReport var2 = null;
if (var46 instanceof ReportedException) {
var2 = this.addServerInfoToCrashReport(((ReportedException) var46).getCrashReport());
} else {
var2 = this.addServerInfoToCrashReport(new CrashReport("Exception in server tick loop", var46));
}
File var3 = new File(new File(this.getDataDirectory(), "crash-reports"), "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-server.txt");
if (var2.saveToFile(var3)) {
logger.error("This crash report has been saved to: " + var3.getAbsolutePath());
} else {
logger.error("We were unable to save this crash report to disk.");
}
this.finalTick(var2);
} finally {
try {
this.stopServer();
this.serverStopped = true;
} catch (Throwable var44) {
logger.error("Exception stopping the server", var44);
} finally {
this.systemExitNow();
}
}
}
private void addFaviconToStatusResponse(ServerStatusResponse response) {
File var2 = this.getFile("server-icon.png");
if (var2.isFile()) {
ByteBuf var3 = Unpooled.buffer();
try {
BufferedImage var4 = ImageIO.read(var2);
Validate.validState(var4.getWidth() == 64, "Must be 64 pixels wide", new Object[0]);
Validate.validState(var4.getHeight() == 64, "Must be 64 pixels high", new Object[0]);
ImageIO.write(var4, "PNG", new ByteBufOutputStream(var3));
ByteBuf var5 = Base64.encode(var3);
response.setFavicon("data:image/png;base64," + var5.toString(Charsets.UTF_8));
} catch (Exception var9) {
logger.error("Couldn\'t load server icon", var9);
} finally {
var3.release();
}
}
}
public File getDataDirectory() {
return new File(".");
}
/**
* Called on exit from the main run() loop.
*/
protected void finalTick(CrashReport report) {
}
/**
* Directly calls System.exit(0), instantly killing the program.
*/
protected void systemExitNow() {
}
/**
* Main function called by run() every loop.
*/
protected void tick() {
long var1 = System.nanoTime();
++this.tickCounter;
if (this.startProfiling) {
this.startProfiling = false;
this.theProfiler.profilingEnabled = true;
this.theProfiler.clearProfiling();
}
this.theProfiler.startSection("root");
this.updateTimeLightAndEntities();
if (var1 - this.nanoTimeSinceStatusRefresh >= 5000000000L) {
this.nanoTimeSinceStatusRefresh = var1;
this.statusResponse.setPlayerCountData(new ServerStatusResponse.PlayerCountData(this.getMaxPlayers(), this.getCurrentPlayerCount()));
GameProfile[] var3 = new GameProfile[Math.min(this.getCurrentPlayerCount(), 12)];
int var4 = MathHelper.getRandomIntegerInRange(this.random, 0, this.getCurrentPlayerCount() - var3.length);
for (int var5 = 0; var5 < var3.length; ++var5) {
var3[var5] = ((EntityPlayerMP) this.serverConfigManager.playerEntityList.get(var4 + var5)).getGameProfile();
}
Collections.shuffle(Arrays.asList(var3));
this.statusResponse.getPlayerCountData().setPlayers(var3);
}
if (this.tickCounter % 900 == 0) {
this.theProfiler.startSection("save");
this.serverConfigManager.saveAllPlayerData();
this.saveAllWorlds(true);
this.theProfiler.endSection();
}
this.theProfiler.startSection("tallying");
this.tickTimeArray[this.tickCounter % 100] = System.nanoTime() - var1;
this.theProfiler.endSection();
this.theProfiler.startSection("snooper");
if (!this.usageSnooper.isSnooperRunning() && this.tickCounter > 100) {
this.usageSnooper.startSnooper();
}
if (this.tickCounter % 6000 == 0) {
this.usageSnooper.addMemoryStatsToSnooper();
}
this.theProfiler.endSection();
this.theProfiler.endSection();
}
public void updateTimeLightAndEntities() {
this.theProfiler.startSection("jobs");
Queue var1 = this.futureTaskQueue;
synchronized (this.futureTaskQueue) {
while (!this.futureTaskQueue.isEmpty()) {
try {
((FutureTask) this.futureTaskQueue.poll()).run();
} catch (Throwable var9) {
logger.fatal(var9);
}
}
}
this.theProfiler.endStartSection("levels");
int var11;
for (var11 = 0; var11 < this.worldServers.length; ++var11) {
long var2 = System.nanoTime();
if (var11 == 0 || this.getAllowNether()) {
WorldServer var4 = this.worldServers[var11];
this.theProfiler.startSection(var4.getWorldInfo().getWorldName());
if (this.tickCounter % 20 == 0) {
this.theProfiler.startSection("timeSync");
this.serverConfigManager.sendPacketToAllPlayersInDimension(new S03PacketTimeUpdate(var4.getTotalWorldTime(), var4.getWorldTime(), var4.getGameRules().getGameRuleBooleanValue("doDaylightCycle")), var4.provider.getDimensionId());
this.theProfiler.endSection();
}
this.theProfiler.startSection("tick");
CrashReport var6;
try {
var4.tick();
} catch (Throwable var8) {
var6 = CrashReport.makeCrashReport(var8, "Exception ticking world");
var4.addWorldInfoToCrashReport(var6);
throw new ReportedException(var6);
}
try {
var4.updateEntities();
} catch (Throwable var7) {
var6 = CrashReport.makeCrashReport(var7, "Exception ticking world entities");
var4.addWorldInfoToCrashReport(var6);
throw new ReportedException(var6);
}
this.theProfiler.endSection();
this.theProfiler.startSection("tracker");
var4.getEntityTracker().updateTrackedEntities();
this.theProfiler.endSection();
this.theProfiler.endSection();
}
this.timeOfLastDimensionTick[var11][this.tickCounter % 100] = System.nanoTime() - var2;
}
this.theProfiler.endStartSection("connection");
this.getNetworkSystem().networkTick();
this.theProfiler.endStartSection("players");
this.serverConfigManager.onTick();
this.theProfiler.endStartSection("tickables");
for (var11 = 0; var11 < this.playersOnline.size(); ++var11) {
((IUpdatePlayerListBox) this.playersOnline.get(var11)).update();
}
this.theProfiler.endSection();
}
public boolean getAllowNether() {
return true;
}
public void registerTickable(IUpdatePlayerListBox tickable) {
this.playersOnline.add(tickable);
}
public static void main(String[] p_main_0_) {
Bootstrap.register();
try {
boolean var1 = true;
String var2 = null;
String var3 = ".";
String var4 = null;
boolean var5 = false;
boolean var6 = false;
int var7 = -1;
for (int var8 = 0; var8 < p_main_0_.length; ++var8) {
String var9 = p_main_0_[var8];
String var10 = var8 == p_main_0_.length - 1 ? null : p_main_0_[var8 + 1];
boolean var11 = false;
if (!var9.equals("nogui") && !var9.equals("--nogui")) {
if (var9.equals("--port") && var10 != null) {
var11 = true;
try {
var7 = Integer.parseInt(var10);
} catch (NumberFormatException var13) {
;
}
} else if (var9.equals("--singleplayer") && var10 != null) {
var11 = true;
var2 = var10;
} else if (var9.equals("--universe") && var10 != null) {
var11 = true;
var3 = var10;
} else if (var9.equals("--world") && var10 != null) {
var11 = true;
var4 = var10;
} else if (var9.equals("--demo")) {
var5 = true;
} else if (var9.equals("--bonusChest")) {
var6 = true;
}
} else {
var1 = false;
}
if (var11) {
++var8;
}
}
final DedicatedServer var15 = new DedicatedServer(new File(var3));
if (var2 != null) {
var15.setServerOwner(var2);
}
if (var4 != null) {
var15.setFolderName(var4);
}
if (var7 >= 0) {
var15.setServerPort(var7);
}
if (var5) {
var15.setDemo(true);
}
if (var6) {
var15.canCreateBonusChest(true);
}
if (var1 && !GraphicsEnvironment.isHeadless()) {
var15.setGuiEnabled();
}
var15.startServerThread();
Runtime.getRuntime().addShutdownHook(new Thread("Server Shutdown Thread") {
private static final String __OBFID = "CL_00001806";
public void run() {
var15.stopServer();
}
});
} catch (Exception var14) {
logger.fatal("Failed to start the minecraft server", var14);
}
}
public void startServerThread() {
this.serverThread = new Thread(this, "Server thread");
this.serverThread.start();
}
/**
* Returns a File object from the specified string.
*/
public File getFile(String fileName) {
return new File(this.getDataDirectory(), fileName);
}
/**
* Logs the message with a level of INFO.
*/
public void logInfo(String msg) {
logger.info(msg);
}
/**
* Logs the message with a level of WARN.
*/
public void logWarning(String msg) {
logger.warn(msg);
}
/**
* Gets the worldServer by the given dimension.
*/
public WorldServer worldServerForDimension(int dimension) {
return dimension == -1 ? this.worldServers[1] : (dimension == 1 ? this.worldServers[2] : this.worldServers[0]);
}
/**
* Returns the server's hostname.
*/
public String getHostname() {
return this.hostname;
}
/**
* Never used, but "getServerPort" is already taken.
*/
public int getPort() {
return this.serverPort;
}
/**
* Returns the server message of the day
*/
public String getMotd() {
return this.motd;
}
/**
* Returns the server's Minecraft version as string.
*/
public String getMinecraftVersion() {
return "1.8";
}
/**
* Returns the number of players currently on the server.
*/
public int getCurrentPlayerCount() {
return this.serverConfigManager.getCurrentPlayerCount();
}
/**
* Returns the maximum number of players allowed on the server.
*/
public int getMaxPlayers() {
return this.serverConfigManager.getMaxPlayers();
}
/**
* Returns an array of the usernames of all the connected players.
*/
public String[] getAllUsernames() {
return this.serverConfigManager.getAllUsernames();
}
/**
* Returns an array of the GameProfiles of all the connected players
*/
public GameProfile[] getGameProfiles() {
return this.serverConfigManager.getAllProfiles();
}
/**
* Used by RCon's Query in the form of "MajorServerMod 1.2.3: MyPlugin 1.3;
* AnotherPlugin 2.1; AndSoForth 1.0".
*/
public String getPlugins() {
return "";
}
/**
* Handle a command received by an RCon instance
*/
public String handleRConCommand(String command) {
RConConsoleSource.func_175570_h().resetLog();
this.commandManager.executeCommand(RConConsoleSource.func_175570_h(), command);
return RConConsoleSource.func_175570_h().getLogContents();
}
/**
* Returns true if debugging is enabled, false otherwise.
*/
public boolean isDebuggingEnabled() {
return false;
}
/**
* Logs the error message with a level of SEVERE.
*/
public void logSevere(String msg) {
logger.error(msg);
}
/**
* If isDebuggingEnabled(), logs the message with a level of INFO.
*/
public void logDebug(String msg) {
if (this.isDebuggingEnabled()) {
logger.info(msg);
}
}
public String getServerModName() {
return "vanilla";
}
/**
* Adds the server info, including from theWorldServer, to the crash report.
*/
public CrashReport addServerInfoToCrashReport(CrashReport report) {
report.getCategory().addCrashSectionCallable("Profiler Position", new Callable() {
private static final String __OBFID = "CL_00001418";
public String func_179879_a() {
return MinecraftServer.this.theProfiler.profilingEnabled ? MinecraftServer.this.theProfiler.getNameOfLastSection() : "N/A (disabled)";
}
public Object call() {
return this.func_179879_a();
}
});
if (this.serverConfigManager != null) {
report.getCategory().addCrashSectionCallable("Player Count", new Callable() {
private static final String __OBFID = "CL_00001419";
public String call() {
return MinecraftServer.this.serverConfigManager.getCurrentPlayerCount() + " / " + MinecraftServer.this.serverConfigManager.getMaxPlayers() + "; " + MinecraftServer.this.serverConfigManager.playerEntityList;
}
});
}
return report;
}
public List func_180506_a(ICommandSender p_180506_1_, String p_180506_2_, BlockPos p_180506_3_) {
ArrayList var4 = Lists.newArrayList();
if (p_180506_2_.startsWith("/")) {
p_180506_2_ = p_180506_2_.substring(1);
boolean var11 = !p_180506_2_.contains(" ");
List var12 = this.commandManager.getTabCompletionOptions(p_180506_1_, p_180506_2_, p_180506_3_);
if (var12 != null) {
Iterator var13 = var12.iterator();
while (var13.hasNext()) {
String var14 = (String) var13.next();
if (var11) {
var4.add("/" + var14);
} else {
var4.add(var14);
}
}
}
return var4;
} else {
String[] var5 = p_180506_2_.split(" ", -1);
String var6 = var5[var5.length - 1];
String[] var7 = this.serverConfigManager.getAllUsernames();
int var8 = var7.length;
for (int var9 = 0; var9 < var8; ++var9) {
String var10 = var7[var9];
if (CommandBase.doesStringStartWith(var6, var10)) {
var4.add(var10);
}
}
return var4;
}
}
/**
* Gets mcServer.
*/
public static MinecraftServer getServer() {
return mcServer;
}
public boolean func_175578_N() {
return this.anvilFile != null;
}
/**
* Gets the name of this command sender (usually username, but possibly
* "Rcon")
*/
public String getName() {
return "Server";
}
/**
* Notifies this sender of some sort of information. This is for messages
* intended to display to the user. Used for typical output (like "you asked
* for whether or not this game rule is set, so here's your answer"),
* warnings (like "I fetched this block for you by ID, but I'd like you to
* know that every time you do this, I die a little inside"), and errors
* (like "it's not called iron_pixacke, silly").
*/
public void addChatMessage(IChatComponent message) {
logger.info(message.getUnformattedText());
}
/**
* Returns true if the command sender is allowed to use the given command.
*/
public boolean canCommandSenderUseCommand(int permissionLevel, String command) {
return true;
}
public ICommandManager getCommandManager() {
return this.commandManager;
}
/**
* Gets KeyPair instanced in MinecraftServer.
*/
public KeyPair getKeyPair() {
return this.serverKeyPair;
}
/**
* Gets serverPort.
*/
public int getServerPort() {
return this.serverPort;
}
public void setServerPort(int port) {
this.serverPort = port;
}
/**
* Returns the username of the server owner (for integrated servers)
*/
public String getServerOwner() {
return this.serverOwner;
}
/**
* Sets the username of the owner of this server (in the case of an
* integrated server)
*/
public void setServerOwner(String owner) {
this.serverOwner = owner;
}
public boolean isSinglePlayer() {
return this.serverOwner != null;
}
public String getFolderName() {
return this.folderName;
}
public void setFolderName(String name) {
this.folderName = name;
}
public void setKeyPair(KeyPair keyPair) {
this.serverKeyPair = keyPair;
}
public void setDifficultyForAllWorlds(EnumDifficulty difficulty) {
for (int var2 = 0; var2 < this.worldServers.length; ++var2) {
WorldServer var3 = this.worldServers[var2];
if (var3 != null) {
if (var3.getWorldInfo().isHardcoreModeEnabled()) {
var3.getWorldInfo().setDifficulty(EnumDifficulty.HARD);
var3.setAllowedSpawnTypes(true, true);
} else if (this.isSinglePlayer()) {
var3.getWorldInfo().setDifficulty(difficulty);
var3.setAllowedSpawnTypes(var3.getDifficulty() != EnumDifficulty.PEACEFUL, true);
} else {
var3.getWorldInfo().setDifficulty(difficulty);
var3.setAllowedSpawnTypes(this.allowSpawnMonsters(), this.canSpawnAnimals);
}
}
}
}
protected boolean allowSpawnMonsters() {
return true;
}
/**
* Gets whether this is a demo or not.
*/
public boolean isDemo() {
return this.isDemo;
}
/**
* Sets whether this is a demo or not.
*/
public void setDemo(boolean demo) {
this.isDemo = demo;
}
public void canCreateBonusChest(boolean enable) {
this.enableBonusChest = enable;
}
public ISaveFormat getActiveAnvilConverter() {
return this.anvilConverterForAnvilFile;
}
/**
* WARNING : directly calls
* getActiveAnvilConverter().deleteWorldDirectory(theWorldServer[0].getSaveHandler().getWorldDirectoryName());
*/
public void deleteWorldAndStopServer() {
this.worldIsBeingDeleted = true;
this.getActiveAnvilConverter().flushCache();
for (int var1 = 0; var1 < this.worldServers.length; ++var1) {
WorldServer var2 = this.worldServers[var1];
if (var2 != null) {
var2.flush();
}
}
this.getActiveAnvilConverter().deleteWorldDirectory(this.worldServers[0].getSaveHandler().getWorldDirectoryName());
this.initiateShutdown();
}
public String getResourcePackUrl() {
return this.resourcePackUrl;
}
public String getResourcePackHash() {
return this.resourcePackHash;
}
public void setResourcePack(String url, String hash) {
this.resourcePackUrl = url;
this.resourcePackHash = hash;
}
public void addServerStatsToSnooper(PlayerUsageSnooper playerSnooper) {
playerSnooper.addClientStat("whitelist_enabled", Boolean.valueOf(false));
playerSnooper.addClientStat("whitelist_count", Integer.valueOf(0));
if (this.serverConfigManager != null) {
playerSnooper.addClientStat("players_current", Integer.valueOf(this.getCurrentPlayerCount()));
playerSnooper.addClientStat("players_max", Integer.valueOf(this.getMaxPlayers()));
playerSnooper.addClientStat("players_seen", Integer.valueOf(this.serverConfigManager.getAvailablePlayerDat().length));
}
playerSnooper.addClientStat("uses_auth", Boolean.valueOf(this.onlineMode));
playerSnooper.addClientStat("gui_state", this.getGuiEnabled() ? "enabled" : "disabled");
playerSnooper.addClientStat("run_time", Long.valueOf((getCurrentTimeMillis() - playerSnooper.getMinecraftStartTimeMillis()) / 60L * 1000L));
playerSnooper.addClientStat("avg_tick_ms", Integer.valueOf((int) (MathHelper.average(this.tickTimeArray) * 1.0E-6D)));
int var2 = 0;
if (this.worldServers != null) {
for (int var3 = 0; var3 < this.worldServers.length; ++var3) {
if (this.worldServers[var3] != null) {
WorldServer var4 = this.worldServers[var3];
WorldInfo var5 = var4.getWorldInfo();
playerSnooper.addClientStat("world[" + var2 + "][dimension]", Integer.valueOf(var4.provider.getDimensionId()));
playerSnooper.addClientStat("world[" + var2 + "][mode]", var5.getGameType());
playerSnooper.addClientStat("world[" + var2 + "][difficulty]", var4.getDifficulty());
playerSnooper.addClientStat("world[" + var2 + "][hardcore]", Boolean.valueOf(var5.isHardcoreModeEnabled()));
playerSnooper.addClientStat("world[" + var2 + "][generator_name]", var5.getTerrainType().getWorldTypeName());
playerSnooper.addClientStat("world[" + var2 + "][generator_version]", Integer.valueOf(var5.getTerrainType().getGeneratorVersion()));
playerSnooper.addClientStat("world[" + var2 + "][height]", Integer.valueOf(this.buildLimit));
playerSnooper.addClientStat("world[" + var2 + "][chunks_loaded]", Integer.valueOf(var4.getChunkProvider().getLoadedChunkCount()));
++var2;
}
}
}
playerSnooper.addClientStat("worlds", Integer.valueOf(var2));
}
public void addServerTypeToSnooper(PlayerUsageSnooper playerSnooper) {
playerSnooper.addStatToSnooper("singleplayer", Boolean.valueOf(this.isSinglePlayer()));
playerSnooper.addStatToSnooper("server_brand", this.getServerModName());
playerSnooper.addStatToSnooper("gui_supported", GraphicsEnvironment.isHeadless() ? "headless" : "supported");
playerSnooper.addStatToSnooper("dedicated", Boolean.valueOf(this.isDedicatedServer()));
}
/**
* Returns whether snooping is enabled or not.
*/
public boolean isSnooperEnabled() {
return true;
}
public abstract boolean isDedicatedServer();
public boolean isServerInOnlineMode() {
return this.onlineMode;
}
public void setOnlineMode(boolean online) {
this.onlineMode = online;
}
public boolean getCanSpawnAnimals() {
return this.canSpawnAnimals;
}
public void setCanSpawnAnimals(boolean spawnAnimals) {
this.canSpawnAnimals = spawnAnimals;
}
public boolean getCanSpawnNPCs() {
return this.canSpawnNPCs;
}
public void setCanSpawnNPCs(boolean spawnNpcs) {
this.canSpawnNPCs = spawnNpcs;
}
public boolean isPVPEnabled() {
return this.pvpEnabled;
}
public void setAllowPvp(boolean allowPvp) {
this.pvpEnabled = allowPvp;
}
public boolean isFlightAllowed() {
return this.allowFlight;
}
public void setAllowFlight(boolean allow) {
this.allowFlight = allow;
}
/**
* Return whether command blocks are enabled.
*/
public abstract boolean isCommandBlockEnabled();
public String getMOTD() {
return this.motd;
}
public void setMOTD(String motdIn) {
this.motd = motdIn;
}
public int getBuildLimit() {
return this.buildLimit;
}
public void setBuildLimit(int maxBuildHeight) {
this.buildLimit = maxBuildHeight;
}
public boolean isServerStopped() {
return this.serverStopped;
}
public ServerConfigurationManager getConfigurationManager() {
return this.serverConfigManager;
}
public void setConfigManager(ServerConfigurationManager configManager) {
this.serverConfigManager = configManager;
}
/**
* Sets the game type for all worlds.
*/
public void setGameType(WorldSettings.GameType gameMode) {
for (int var2 = 0; var2 < this.worldServers.length; ++var2) {
getServer().worldServers[var2].getWorldInfo().setGameType(gameMode);
}
}
public NetworkSystem getNetworkSystem() {
return this.networkSystem;
}
public boolean getGuiEnabled() {
return false;
}
/**
* On dedicated does nothing. On integrated, sets commandsAllowedForAll,
* gameType and allows external connections.
*/
public abstract String shareToLAN(WorldSettings.GameType type, boolean allowCheats);
public int getTickCounter() {
return this.tickCounter;
}
public void enableProfiling() {
this.startProfiling = true;
}
public BlockPos getPosition() {
return BlockPos.ORIGIN;
}
public Vec3 getPositionVector() {
return new Vec3(0.0D, 0.0D, 0.0D);
}
public World getEntityWorld() {
return this.worldServers[0];
}
public Entity getCommandSenderEntity() {
return null;
}
/**
* Return the spawn protection area's size.
*/
public int getSpawnProtectionSize() {
return 16;
}
public boolean isBlockProtected(World worldIn, BlockPos pos, EntityPlayer playerIn) {
return false;
}
public void setForceGamemode(boolean force) {
this.isGamemodeForced = force;
}
public boolean getForceGamemode() {
return this.isGamemodeForced;
}
public Proxy getServerProxy() {
return this.serverProxy;
}
public static long getCurrentTimeMillis() {
return System.currentTimeMillis();
}
public int getMaxPlayerIdleMinutes() {
return this.maxPlayerIdleMinutes;
}
public void setPlayerIdleTimeout(int idleTimeout) {
this.maxPlayerIdleMinutes = idleTimeout;
}
public IChatComponent getDisplayName() {
return new ChatComponentText(this.getName());
}
public boolean isAnnouncingPlayerAchievements() {
return true;
}
public MinecraftSessionService getMinecraftSessionService() {
return this.sessionService;
}
public GameProfileRepository getGameProfileRepository() {
return this.profileRepo;
}
public PlayerProfileCache getPlayerProfileCache() {
return this.profileCache;
}
public ServerStatusResponse getServerStatusResponse() {
return this.statusResponse;
}
public void refreshStatusNextTick() {
this.nanoTimeSinceStatusRefresh = 0L;
}
public Entity getEntityFromUuid(UUID uuid) {
WorldServer[] var2 = this.worldServers;
int var3 = var2.length;
for (int var4 = 0; var4 < var3; ++var4) {
WorldServer var5 = var2[var4];
if (var5 != null) {
Entity var6 = var5.getEntityFromUuid(uuid);
if (var6 != null) {
return var6;
}
}
}
return null;
}
public boolean sendCommandFeedback() {
return getServer().worldServers[0].getGameRules().getGameRuleBooleanValue("sendCommandFeedback");
}
public void func_174794_a(CommandResultStats.Type p_174794_1_, int p_174794_2_) {
}
public int getMaxWorldSize() {
return 29999984;
}
public ListenableFuture callFromMainThread(Callable callable) {
Validate.notNull(callable);
if (!this.isCallingFromMinecraftThread()) {
ListenableFutureTask var2 = ListenableFutureTask.create(callable);
Queue var3 = this.futureTaskQueue;
synchronized (this.futureTaskQueue) {
this.futureTaskQueue.add(var2);
return var2;
}
} else {
try {
return Futures.immediateFuture(callable.call());
} catch (Exception var6) {
return Futures.immediateFailedCheckedFuture(var6);
}
}
}
public ListenableFuture addScheduledTask(Runnable runnableToSchedule) {
Validate.notNull(runnableToSchedule);
return this.callFromMainThread(Executors.callable(runnableToSchedule));
}
public boolean isCallingFromMinecraftThread() {
return Thread.currentThread() == this.serverThread;
}
/**
* The compression treshold. If the packet is larger than the specified
* amount of bytes, it will be compressed
*/
public int getNetworkCompressionTreshold() {
return 256;
}
public long getCurrentTime() {
return this.currentTime;
}
public Thread getServerThread() {
return this.serverThread;
}
}