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.2");
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        /**
359         * Return whether command blocks are enabled.
360         */
361        public boolean isCommandBlockEnabled()
362        {
363            return this.settings.getBooleanProperty("enable-command-block", false);
364        }
365    
366        /**
367         * Return the spawn protection area's size.
368         */
369        public int getSpawnProtectionSize()
370        {
371            return this.settings.getIntProperty("spawn-protection", super.getSpawnProtectionSize());
372        }
373    
374        public ServerConfigurationManager getConfigurationManager()
375        {
376            return this.getDedicatedPlayerList();
377        }
378    
379        @SideOnly(Side.SERVER)
380        public void func_82011_an()
381        {
382            ServerGUI.initGUI(this);
383            this.guiIsEnabled = true;
384        }
385    }