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");
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 this.canSpawnStructures = this.settings.getBooleanProperty("generate-structures", true);
071 int var2 = this.settings.getIntProperty("gamemode", EnumGameType.SURVIVAL.getID());
072 this.gameType = WorldSettings.getGameTypeById(var2);
073 logger.info("Default game type: " + this.gameType);
074 InetAddress var3 = null;
075
076 if (this.getServerHostname().length() > 0)
077 {
078 var3 = InetAddress.getByName(this.getServerHostname());
079 }
080
081 if (this.getServerPort() < 0)
082 {
083 this.setServerPort(this.settings.getIntProperty("server-port", 25565));
084 }
085
086 logger.info("Generating keypair");
087 this.setKeyPair(CryptManager.createNewKeyPair());
088 logger.info("Starting Minecraft server on " + (this.getServerHostname().length() == 0 ? "*" : this.getServerHostname()) + ":" + this.getServerPort());
089
090 try
091 {
092 this.networkThread = new DedicatedServerListenThread(this, var3, this.getServerPort());
093 }
094 catch (IOException var16)
095 {
096 logger.warning("**** FAILED TO BIND TO PORT!");
097 logger.log(Level.WARNING, "The exception was: " + var16.toString());
098 logger.warning("Perhaps a server is already running on that port?");
099 return false;
100 }
101
102 if (!this.isServerInOnlineMode())
103 {
104 logger.warning("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
105 logger.warning("The server will make no attempt to authenticate usernames. Beware.");
106 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.");
107 logger.warning("To change this, set \"online-mode\" to \"true\" in the server.properties file.");
108 }
109
110 FMLCommonHandler.instance().onServerStarted();
111 this.setConfigurationManager(new DedicatedPlayerList(this));
112 long var4 = System.nanoTime();
113
114 if (this.getFolderName() == null)
115 {
116 this.setFolderName(this.settings.getProperty("level-name", "world"));
117 }
118
119 String var6 = this.settings.getProperty("level-seed", "");
120 String var7 = this.settings.getProperty("level-type", "DEFAULT");
121 String var8 = this.settings.getProperty("generator-settings", "");
122 long var9 = (new Random()).nextLong();
123
124 if (var6.length() > 0)
125 {
126 try
127 {
128 long var11 = Long.parseLong(var6);
129
130 if (var11 != 0L)
131 {
132 var9 = var11;
133 }
134 }
135 catch (NumberFormatException var15)
136 {
137 var9 = (long)var6.hashCode();
138 }
139 }
140
141 WorldType var17 = WorldType.parseWorldType(var7);
142
143 if (var17 == null)
144 {
145 var17 = WorldType.DEFAULT;
146 }
147
148 this.setBuildLimit(this.settings.getIntProperty("max-build-height", 256));
149 this.setBuildLimit((this.getBuildLimit() + 8) / 16 * 16);
150 this.setBuildLimit(MathHelper.clamp_int(this.getBuildLimit(), 64, 256));
151 this.settings.setProperty("max-build-height", Integer.valueOf(this.getBuildLimit()));
152 logger.info("Preparing level \"" + this.getFolderName() + "\"");
153 this.loadAllWorlds(this.getFolderName(), this.getFolderName(), var9, var17, var8);
154 long var12 = System.nanoTime() - var4;
155 String var14 = String.format("%.3fs", new Object[] {Double.valueOf((double)var12 / 1.0E9D)});
156 logger.info("Done (" + var14 + ")! For help, type \"help\" or \"?\"");
157
158 if (this.settings.getBooleanProperty("enable-query", false))
159 {
160 logger.info("Starting GS4 status listener");
161 this.theRConThreadQuery = new RConThreadQuery(this);
162 this.theRConThreadQuery.startThread();
163 }
164
165 if (this.settings.getBooleanProperty("enable-rcon", false))
166 {
167 logger.info("Starting remote control listener");
168 this.theRConThreadMain = new RConThreadMain(this);
169 this.theRConThreadMain.startThread();
170 }
171 FMLCommonHandler.instance().handleServerStarting(this);
172 return true;
173 }
174
175 public boolean canStructuresSpawn()
176 {
177 return this.canSpawnStructures;
178 }
179
180 public EnumGameType getGameType()
181 {
182 return this.gameType;
183 }
184
185 /**
186 * Defaults to "1" (Easy) for the dedicated server, defaults to "2" (Normal) on the client.
187 */
188 public int getDifficulty()
189 {
190 return this.settings.getIntProperty("difficulty", 1);
191 }
192
193 /**
194 * Defaults to false.
195 */
196 public boolean isHardcore()
197 {
198 return this.settings.getBooleanProperty("hardcore", false);
199 }
200
201 /**
202 * Called on exit from the main run() loop.
203 */
204 protected void finalTick(CrashReport par1CrashReport)
205 {
206 while (this.isServerRunning())
207 {
208 this.executePendingCommands();
209
210 try
211 {
212 Thread.sleep(10L);
213 }
214 catch (InterruptedException var3)
215 {
216 var3.printStackTrace();
217 }
218 }
219 }
220
221 /**
222 * Adds the server info, including from theWorldServer, to the crash report.
223 */
224 public CrashReport addServerInfoToCrashReport(CrashReport par1CrashReport)
225 {
226 par1CrashReport = super.addServerInfoToCrashReport(par1CrashReport);
227 par1CrashReport.addCrashSectionCallable("Type", new CallableType(this));
228 return par1CrashReport;
229 }
230
231 /**
232 * Directly calls System.exit(0), instantly killing the program.
233 */
234 protected void systemExitNow()
235 {
236 System.exit(0);
237 }
238
239 public void updateTimeLightAndEntities()
240 {
241 super.updateTimeLightAndEntities();
242 this.executePendingCommands();
243 }
244
245 public boolean getAllowNether()
246 {
247 return this.settings.getBooleanProperty("allow-nether", true);
248 }
249
250 public boolean allowSpawnMonsters()
251 {
252 return this.settings.getBooleanProperty("spawn-monsters", true);
253 }
254
255 public void addServerStatsToSnooper(PlayerUsageSnooper par1PlayerUsageSnooper)
256 {
257 par1PlayerUsageSnooper.addData("whitelist_enabled", Boolean.valueOf(this.getDedicatedPlayerList().isWhiteListEnabled()));
258 par1PlayerUsageSnooper.addData("whitelist_count", Integer.valueOf(this.getDedicatedPlayerList().getWhiteListedPlayers().size()));
259 super.addServerStatsToSnooper(par1PlayerUsageSnooper);
260 }
261
262 /**
263 * Returns whether snooping is enabled or not.
264 */
265 public boolean isSnooperEnabled()
266 {
267 return this.settings.getBooleanProperty("snooper-enabled", true);
268 }
269
270 public void addPendingCommand(String par1Str, ICommandSender par2ICommandSender)
271 {
272 this.pendingCommandList.add(new ServerCommand(par1Str, par2ICommandSender));
273 }
274
275 public void executePendingCommands()
276 {
277 while (!this.pendingCommandList.isEmpty())
278 {
279 ServerCommand var1 = (ServerCommand)this.pendingCommandList.remove(0);
280 this.getCommandManager().executeCommand(var1.sender, var1.command);
281 }
282 }
283
284 public boolean isDedicatedServer()
285 {
286 return true;
287 }
288
289 public DedicatedPlayerList getDedicatedPlayerList()
290 {
291 return (DedicatedPlayerList)super.getConfigurationManager();
292 }
293
294 public NetworkListenThread getNetworkThread()
295 {
296 return this.networkThread;
297 }
298
299 /**
300 * Gets an integer property. If it does not exist, set it to the specified value.
301 */
302 public int getIntProperty(String par1Str, int par2)
303 {
304 return this.settings.getIntProperty(par1Str, par2);
305 }
306
307 /**
308 * Gets a string property. If it does not exist, set it to the specified value.
309 */
310 public String getStringProperty(String par1Str, String par2Str)
311 {
312 return this.settings.getProperty(par1Str, par2Str);
313 }
314
315 /**
316 * Gets a boolean property. If it does not exist, set it to the specified value.
317 */
318 public boolean getBooleanProperty(String par1Str, boolean par2)
319 {
320 return this.settings.getBooleanProperty(par1Str, par2);
321 }
322
323 /**
324 * Saves an Object with the given property name.
325 */
326 public void setProperty(String par1Str, Object par2Obj)
327 {
328 this.settings.setProperty(par1Str, par2Obj);
329 }
330
331 /**
332 * Saves all of the server properties to the properties file.
333 */
334 public void saveProperties()
335 {
336 this.settings.saveProperties();
337 }
338
339 public String getSettingsFilePath()
340 {
341 File var1 = this.settings.getPropertiesFile();
342 return var1 != null ? var1.getAbsolutePath() : "No settings file";
343 }
344
345 public boolean getGuiEnabled()
346 {
347 return this.guiIsEnabled;
348 }
349
350 /**
351 * On dedicated does nothing. On integrated, sets commandsAllowedForAll, gameType and allows external connections.
352 */
353 public String shareToLAN(EnumGameType par1EnumGameType, boolean par2)
354 {
355 return "";
356 }
357
358 public boolean func_82356_Z()
359 {
360 return this.settings.getBooleanProperty("enable-command-block", false);
361 }
362
363 public int func_82357_ak()
364 {
365 return this.settings.getIntProperty("spawn-protection", super.func_82357_ak());
366 }
367
368 public ServerConfigurationManager getConfigurationManager()
369 {
370 return this.getDedicatedPlayerList();
371 }
372
373 @SideOnly(Side.SERVER)
374 public void func_82011_an()
375 {
376 ServerGUI.initGUI(this);
377 this.guiIsEnabled = true;
378 }
379 }