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