001 package net.minecraft.server.dedicated; 002 003 import cpw.mods.fml.common.FMLCommonHandler; 004 import cpw.mods.fml.relauncher.Side; 005 import cpw.mods.fml.relauncher.SideOnly; 006 import java.io.File; 007 import java.io.IOException; 008 import java.net.InetAddress; 009 import java.util.ArrayList; 010 import java.util.Collections; 011 import java.util.List; 012 import java.util.Random; 013 import java.util.logging.Level; 014 import net.minecraft.command.ICommandSender; 015 import net.minecraft.command.ServerCommand; 016 import net.minecraft.crash.CrashReport; 017 import net.minecraft.network.NetworkListenThread; 018 import net.minecraft.network.rcon.IServer; 019 import net.minecraft.network.rcon.RConThreadMain; 020 import net.minecraft.network.rcon.RConThreadQuery; 021 import net.minecraft.profiler.PlayerUsageSnooper; 022 import net.minecraft.server.MinecraftServer; 023 import net.minecraft.server.gui.ServerGUI; 024 import net.minecraft.server.management.ServerConfigurationManager; 025 import net.minecraft.util.CryptManager; 026 import net.minecraft.util.MathHelper; 027 import net.minecraft.world.EnumGameType; 028 import net.minecraft.world.WorldSettings; 029 import net.minecraft.world.WorldType; 030 031 public class DedicatedServer extends MinecraftServer implements IServer 032 { 033 private final List pendingCommandList = Collections.synchronizedList(new ArrayList()); 034 private RConThreadQuery theRConThreadQuery; 035 private RConThreadMain theRConThreadMain; 036 private PropertyManager settings; 037 private boolean canSpawnStructures; 038 private EnumGameType gameType; 039 private NetworkListenThread networkThread; 040 private boolean guiIsEnabled = false; 041 042 public DedicatedServer(File par1File) 043 { 044 super(par1File); 045 new DedicatedServerSleepThread(this); 046 } 047 048 /** 049 * Initialises the server and starts it. 050 */ 051 protected boolean startServer() throws IOException 052 { 053 DedicatedServerCommandThread var1 = new DedicatedServerCommandThread(this); 054 var1.setDaemon(true); 055 var1.start(); 056 ConsoleLogManager.init(); 057 logger.info("Starting minecraft server version 1.4.7"); 058 059 if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) 060 { 061 logger.warning("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); 062 } 063 064 FMLCommonHandler.instance().onServerStart(this); 065 066 logger.info("Loading properties"); 067 this.settings = new PropertyManager(new File("server.properties")); 068 069 if (this.isSinglePlayer()) 070 { 071 this.setHostname("127.0.0.1"); 072 } 073 else 074 { 075 this.setOnlineMode(this.settings.getBooleanProperty("online-mode", true)); 076 this.setHostname(this.settings.getProperty("server-ip", "")); 077 } 078 079 this.setCanSpawnAnimals(this.settings.getBooleanProperty("spawn-animals", true)); 080 this.setCanSpawnNPCs(this.settings.getBooleanProperty("spawn-npcs", true)); 081 this.setAllowPvp(this.settings.getBooleanProperty("pvp", true)); 082 this.setAllowFlight(this.settings.getBooleanProperty("allow-flight", false)); 083 this.setTexturePack(this.settings.getProperty("texture-pack", "")); 084 this.setMOTD(this.settings.getProperty("motd", "A Minecraft Server")); 085 086 if (this.settings.getIntProperty("difficulty", 1) < 0) 087 { 088 this.settings.setProperty("difficulty", Integer.valueOf(0)); 089 } 090 else if (this.settings.getIntProperty("difficulty", 1) > 3) 091 { 092 this.settings.setProperty("difficulty", Integer.valueOf(3)); 093 } 094 095 this.canSpawnStructures = this.settings.getBooleanProperty("generate-structures", true); 096 int var2 = this.settings.getIntProperty("gamemode", EnumGameType.SURVIVAL.getID()); 097 this.gameType = WorldSettings.getGameTypeById(var2); 098 logger.info("Default game type: " + this.gameType); 099 InetAddress var3 = null; 100 101 if (this.getServerHostname().length() > 0) 102 { 103 var3 = InetAddress.getByName(this.getServerHostname()); 104 } 105 106 if (this.getServerPort() < 0) 107 { 108 this.setServerPort(this.settings.getIntProperty("server-port", 25565)); 109 } 110 111 logger.info("Generating keypair"); 112 this.setKeyPair(CryptManager.createNewKeyPair()); 113 logger.info("Starting Minecraft server on " + (this.getServerHostname().length() == 0 ? "*" : this.getServerHostname()) + ":" + this.getServerPort()); 114 115 try 116 { 117 this.networkThread = new DedicatedServerListenThread(this, var3, this.getServerPort()); 118 } 119 catch (IOException var16) 120 { 121 logger.warning("**** FAILED TO BIND TO PORT!"); 122 logger.log(Level.WARNING, "The exception was: " + var16.toString()); 123 logger.warning("Perhaps a server is already running on that port?"); 124 return false; 125 } 126 127 if (!this.isServerInOnlineMode()) 128 { 129 logger.warning("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); 130 logger.warning("The server will make no attempt to authenticate usernames. Beware."); 131 logger.warning("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose."); 132 logger.warning("To change this, set \"online-mode\" to \"true\" in the server.properties file."); 133 } 134 135 FMLCommonHandler.instance().onServerStarted(); 136 137 this.setConfigurationManager(new DedicatedPlayerList(this)); 138 long var4 = System.nanoTime(); 139 140 if (this.getFolderName() == null) 141 { 142 this.setFolderName(this.settings.getProperty("level-name", "world")); 143 } 144 145 String var6 = this.settings.getProperty("level-seed", ""); 146 String var7 = this.settings.getProperty("level-type", "DEFAULT"); 147 String var8 = this.settings.getProperty("generator-settings", ""); 148 long var9 = (new Random()).nextLong(); 149 150 if (var6.length() > 0) 151 { 152 try 153 { 154 long var11 = Long.parseLong(var6); 155 156 if (var11 != 0L) 157 { 158 var9 = var11; 159 } 160 } 161 catch (NumberFormatException var15) 162 { 163 var9 = (long)var6.hashCode(); 164 } 165 } 166 167 WorldType var17 = WorldType.parseWorldType(var7); 168 169 if (var17 == null) 170 { 171 var17 = WorldType.DEFAULT; 172 } 173 174 this.setBuildLimit(this.settings.getIntProperty("max-build-height", 256)); 175 this.setBuildLimit((this.getBuildLimit() + 8) / 16 * 16); 176 this.setBuildLimit(MathHelper.clamp_int(this.getBuildLimit(), 64, 256)); 177 this.settings.setProperty("max-build-height", Integer.valueOf(this.getBuildLimit())); 178 logger.info("Preparing level \"" + this.getFolderName() + "\""); 179 this.loadAllWorlds(this.getFolderName(), this.getFolderName(), var9, var17, var8); 180 long var12 = System.nanoTime() - var4; 181 String var14 = String.format("%.3fs", new Object[] {Double.valueOf((double)var12 / 1.0E9D)}); 182 logger.info("Done (" + var14 + ")! For help, type \"help\" or \"?\""); 183 184 if (this.settings.getBooleanProperty("enable-query", false)) 185 { 186 logger.info("Starting GS4 status listener"); 187 this.theRConThreadQuery = new RConThreadQuery(this); 188 this.theRConThreadQuery.startThread(); 189 } 190 191 if (this.settings.getBooleanProperty("enable-rcon", false)) 192 { 193 logger.info("Starting remote control listener"); 194 this.theRConThreadMain = new RConThreadMain(this); 195 this.theRConThreadMain.startThread(); 196 } 197 198 FMLCommonHandler.instance().handleServerStarting(this); 199 200 return true; 201 } 202 203 public boolean canStructuresSpawn() 204 { 205 return this.canSpawnStructures; 206 } 207 208 public EnumGameType getGameType() 209 { 210 return this.gameType; 211 } 212 213 /** 214 * Defaults to "1" (Easy) for the dedicated server, defaults to "2" (Normal) on the client. 215 */ 216 public int getDifficulty() 217 { 218 return this.settings.getIntProperty("difficulty", 1); 219 } 220 221 /** 222 * Defaults to false. 223 */ 224 public boolean isHardcore() 225 { 226 return this.settings.getBooleanProperty("hardcore", false); 227 } 228 229 /** 230 * Called on exit from the main run() loop. 231 */ 232 protected void finalTick(CrashReport par1CrashReport) 233 { 234 while (this.isServerRunning()) 235 { 236 this.executePendingCommands(); 237 238 try 239 { 240 Thread.sleep(10L); 241 } 242 catch (InterruptedException var3) 243 { 244 var3.printStackTrace(); 245 } 246 } 247 } 248 249 /** 250 * Adds the server info, including from theWorldServer, to the crash report. 251 */ 252 public CrashReport addServerInfoToCrashReport(CrashReport par1CrashReport) 253 { 254 par1CrashReport = super.addServerInfoToCrashReport(par1CrashReport); 255 par1CrashReport.func_85056_g().addCrashSectionCallable("Is Modded", new CallableType(this)); 256 par1CrashReport.func_85056_g().addCrashSectionCallable("Type", new CallableServerType(this)); 257 return par1CrashReport; 258 } 259 260 /** 261 * Directly calls System.exit(0), instantly killing the program. 262 */ 263 protected void systemExitNow() 264 { 265 System.exit(0); 266 } 267 268 public void updateTimeLightAndEntities() 269 { 270 super.updateTimeLightAndEntities(); 271 this.executePendingCommands(); 272 } 273 274 public boolean getAllowNether() 275 { 276 return this.settings.getBooleanProperty("allow-nether", true); 277 } 278 279 public boolean allowSpawnMonsters() 280 { 281 return this.settings.getBooleanProperty("spawn-monsters", true); 282 } 283 284 public void addServerStatsToSnooper(PlayerUsageSnooper par1PlayerUsageSnooper) 285 { 286 par1PlayerUsageSnooper.addData("whitelist_enabled", Boolean.valueOf(this.getDedicatedPlayerList().isWhiteListEnabled())); 287 par1PlayerUsageSnooper.addData("whitelist_count", Integer.valueOf(this.getDedicatedPlayerList().getWhiteListedPlayers().size())); 288 super.addServerStatsToSnooper(par1PlayerUsageSnooper); 289 } 290 291 /** 292 * Returns whether snooping is enabled or not. 293 */ 294 public boolean isSnooperEnabled() 295 { 296 return this.settings.getBooleanProperty("snooper-enabled", true); 297 } 298 299 public void addPendingCommand(String par1Str, ICommandSender par2ICommandSender) 300 { 301 this.pendingCommandList.add(new ServerCommand(par1Str, par2ICommandSender)); 302 } 303 304 public void executePendingCommands() 305 { 306 while (!this.pendingCommandList.isEmpty()) 307 { 308 ServerCommand var1 = (ServerCommand)this.pendingCommandList.remove(0); 309 this.getCommandManager().executeCommand(var1.sender, var1.command); 310 } 311 } 312 313 public boolean isDedicatedServer() 314 { 315 return true; 316 } 317 318 public DedicatedPlayerList getDedicatedPlayerList() 319 { 320 return (DedicatedPlayerList)super.getConfigurationManager(); 321 } 322 323 public NetworkListenThread getNetworkThread() 324 { 325 return this.networkThread; 326 } 327 328 /** 329 * Gets an integer property. If it does not exist, set it to the specified value. 330 */ 331 public int getIntProperty(String par1Str, int par2) 332 { 333 return this.settings.getIntProperty(par1Str, par2); 334 } 335 336 /** 337 * Gets a string property. If it does not exist, set it to the specified value. 338 */ 339 public String getStringProperty(String par1Str, String par2Str) 340 { 341 return this.settings.getProperty(par1Str, par2Str); 342 } 343 344 /** 345 * Gets a boolean property. If it does not exist, set it to the specified value. 346 */ 347 public boolean getBooleanProperty(String par1Str, boolean par2) 348 { 349 return this.settings.getBooleanProperty(par1Str, par2); 350 } 351 352 /** 353 * Saves an Object with the given property name. 354 */ 355 public void setProperty(String par1Str, Object par2Obj) 356 { 357 this.settings.setProperty(par1Str, par2Obj); 358 } 359 360 /** 361 * Saves all of the server properties to the properties file. 362 */ 363 public void saveProperties() 364 { 365 this.settings.saveProperties(); 366 } 367 368 /** 369 * Returns the filename where server properties are stored 370 */ 371 public String getSettingsFilename() 372 { 373 File var1 = this.settings.getPropertiesFile(); 374 return var1 != null ? var1.getAbsolutePath() : "No settings file"; 375 } 376 377 public boolean getGuiEnabled() 378 { 379 return this.guiIsEnabled; 380 } 381 382 /** 383 * On dedicated does nothing. On integrated, sets commandsAllowedForAll, gameType and allows external connections. 384 */ 385 public String shareToLAN(EnumGameType par1EnumGameType, boolean par2) 386 { 387 return ""; 388 } 389 390 /** 391 * Return whether command blocks are enabled. 392 */ 393 public boolean isCommandBlockEnabled() 394 { 395 return this.settings.getBooleanProperty("enable-command-block", false); 396 } 397 398 /** 399 * Return the spawn protection area's size. 400 */ 401 public int getSpawnProtectionSize() 402 { 403 return this.settings.getIntProperty("spawn-protection", super.getSpawnProtectionSize()); 404 } 405 406 public ServerConfigurationManager getConfigurationManager() 407 { 408 return this.getDedicatedPlayerList(); 409 } 410 411 @SideOnly(Side.SERVER) 412 public void enableGui() 413 { 414 ServerGUI.initGUI(this); 415 this.guiIsEnabled = true; 416 } 417 }