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 }