001package net.minecraft.server.integrated;
002
003import cpw.mods.fml.common.FMLCommonHandler;
004import cpw.mods.fml.relauncher.Side;
005import cpw.mods.fml.relauncher.SideOnly;
006import java.io.File;
007import java.io.IOException;
008import net.minecraft.client.Minecraft;
009import net.minecraft.client.multiplayer.ThreadLanServerPing;
010import net.minecraft.crash.CrashReport;
011import net.minecraft.network.NetworkListenThread;
012import net.minecraft.profiler.PlayerUsageSnooper;
013import net.minecraft.server.MinecraftServer;
014import net.minecraft.util.CryptManager;
015import net.minecraft.world.EnumGameType;
016import net.minecraft.world.WorldManager;
017import net.minecraft.world.WorldServer;
018import net.minecraft.world.WorldServerMulti;
019import net.minecraft.world.WorldSettings;
020import net.minecraft.world.WorldType;
021import net.minecraft.world.demo.DemoWorldServer;
022import net.minecraft.world.storage.ISaveHandler;
023
024import net.minecraftforge.common.DimensionManager;
025import net.minecraftforge.common.MinecraftForge;
026import net.minecraftforge.event.world.WorldEvent;
027
028@SideOnly(Side.CLIENT)
029public class IntegratedServer extends MinecraftServer
030{
031    /** The Minecraft instance. */
032    private final Minecraft mc;
033    private final WorldSettings theWorldSettings;
034
035    /** Instance of IntegratedServerListenThread. */
036    private IntegratedServerListenThread theServerListeningThread;
037    private boolean isGamePaused = false;
038    private boolean isPublic;
039    private ThreadLanServerPing lanServerPing;
040
041    public IntegratedServer(Minecraft par1Minecraft, String par2Str, String par3Str, WorldSettings par4WorldSettings)
042    {
043        super(new File(Minecraft.getMinecraftDir(), "saves"));
044        this.setServerOwner(par1Minecraft.session.username);
045        this.setFolderName(par2Str);
046        this.setWorldName(par3Str);
047        this.setDemo(par1Minecraft.isDemo());
048        this.canCreateBonusChest(par4WorldSettings.isBonusChestEnabled());
049        this.setBuildLimit(256);
050        this.setConfigurationManager(new IntegratedPlayerList(this));
051        this.mc = par1Minecraft;
052        this.theWorldSettings = par4WorldSettings;
053
054        try
055        {
056            this.theServerListeningThread = new IntegratedServerListenThread(this);
057        }
058        catch (IOException var6)
059        {
060            throw new Error();
061        }
062    }
063
064    protected void loadAllWorlds(String par1Str, String par2Str, long par3, WorldType par5WorldType, String par6Str)
065    {
066        this.convertMapIfNeeded(par1Str);
067        ISaveHandler var7 = this.getActiveAnvilConverter().getSaveLoader(par1Str, true);
068
069        WorldServer overWorld = (isDemo() ? new DemoWorldServer(this, var7, par2Str, 0, theProfiler) : new WorldServer(this, var7, par2Str, 0, theWorldSettings, theProfiler));
070        for (int dim : DimensionManager.getStaticDimensionIDs())
071        {
072            WorldServer world = (dim == 0 ? overWorld : new WorldServerMulti(this, var7, par2Str, dim, theWorldSettings, overWorld, theProfiler));
073            world.addWorldAccess(new WorldManager(this, world));
074            if (!this.isSinglePlayer())
075            {
076                world.getWorldInfo().setGameType(this.getGameType());
077            }
078
079            MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(world));
080        }
081
082        this.getConfigurationManager().setPlayerManager(new WorldServer[]{ overWorld });
083        this.setDifficultyForAllWorlds(this.getDifficulty());
084        this.initialWorldChunkLoad();
085    }
086
087    /**
088     * Initialises the server and starts it.
089     */
090    protected boolean startServer() throws IOException
091    {
092        logger.info("Starting integrated minecraft server version 1.4.7");
093        this.setOnlineMode(false);
094        this.setCanSpawnAnimals(true);
095        this.setCanSpawnNPCs(true);
096        this.setAllowPvp(true);
097        this.setAllowFlight(true);
098        logger.info("Generating keypair");
099        this.setKeyPair(CryptManager.createNewKeyPair());
100        this.loadAllWorlds(this.getFolderName(), this.getWorldName(), this.theWorldSettings.getSeed(), this.theWorldSettings.getTerrainType(), this.theWorldSettings.func_82749_j());
101        this.setMOTD(this.getServerOwner() + " - " + this.worldServers[0].getWorldInfo().getWorldName());
102        FMLCommonHandler.instance().handleServerStarting(this);
103        return true;
104    }
105
106    /**
107     * Main function called by run() every loop.
108     */
109    public void tick()
110    {
111        boolean var1 = this.isGamePaused;
112        this.isGamePaused = this.theServerListeningThread.isGamePaused();
113
114        if (!var1 && this.isGamePaused)
115        {
116            logger.info("Saving and pausing game...");
117            this.getConfigurationManager().saveAllPlayerData();
118            this.saveAllWorlds(false);
119        }
120
121        if (!this.isGamePaused)
122        {
123            super.tick();
124        }
125    }
126
127    public boolean canStructuresSpawn()
128    {
129        return false;
130    }
131
132    public EnumGameType getGameType()
133    {
134        return this.theWorldSettings.getGameType();
135    }
136
137    /**
138     * Defaults to "1" (Easy) for the dedicated server, defaults to "2" (Normal) on the client.
139     */
140    public int getDifficulty()
141    {
142        return this.mc.gameSettings.difficulty;
143    }
144
145    /**
146     * Defaults to false.
147     */
148    public boolean isHardcore()
149    {
150        return this.theWorldSettings.getHardcoreEnabled();
151    }
152
153    protected File getDataDirectory()
154    {
155        return this.mc.mcDataDir;
156    }
157
158    public boolean isDedicatedServer()
159    {
160        return false;
161    }
162
163    /**
164     * Gets the IntergratedServerListenThread.
165     */
166    public IntegratedServerListenThread getServerListeningThread()
167    {
168        return this.theServerListeningThread;
169    }
170
171    /**
172     * Called on exit from the main run() loop.
173     */
174    protected void finalTick(CrashReport par1CrashReport)
175    {
176        this.mc.crashed(par1CrashReport);
177    }
178
179    /**
180     * Adds the server info, including from theWorldServer, to the crash report.
181     */
182    public CrashReport addServerInfoToCrashReport(CrashReport par1CrashReport)
183    {
184        par1CrashReport = super.addServerInfoToCrashReport(par1CrashReport);
185        par1CrashReport.func_85056_g().addCrashSectionCallable("Type", new CallableType3(this));
186        par1CrashReport.func_85056_g().addCrashSectionCallable("Is Modded", new CallableIsModded(this));
187        return par1CrashReport;
188    }
189
190    public void addServerStatsToSnooper(PlayerUsageSnooper par1PlayerUsageSnooper)
191    {
192        super.addServerStatsToSnooper(par1PlayerUsageSnooper);
193        par1PlayerUsageSnooper.addData("snooper_partner", this.mc.getPlayerUsageSnooper().getUniqueID());
194    }
195
196    /**
197     * Returns whether snooping is enabled or not.
198     */
199    public boolean isSnooperEnabled()
200    {
201        return Minecraft.getMinecraft().isSnooperEnabled();
202    }
203
204    /**
205     * On dedicated does nothing. On integrated, sets commandsAllowedForAll, gameType and allows external connections.
206     */
207    public String shareToLAN(EnumGameType par1EnumGameType, boolean par2)
208    {
209        try
210        {
211            String var3 = this.theServerListeningThread.func_71755_c();
212            System.out.println("Started on " + var3);
213            this.isPublic = true;
214            this.lanServerPing = new ThreadLanServerPing(this.getMOTD(), var3);
215            this.lanServerPing.start();
216            this.getConfigurationManager().setGameType(par1EnumGameType);
217            this.getConfigurationManager().setCommandsAllowedForAll(par2);
218            return var3;
219        }
220        catch (IOException var4)
221        {
222            return null;
223        }
224    }
225
226    /**
227     * Saves all necessary data as preparation for stopping the server.
228     */
229    public void stopServer()
230    {
231        super.stopServer();
232
233        if (this.lanServerPing != null)
234        {
235            this.lanServerPing.interrupt();
236            this.lanServerPing = null;
237        }
238    }
239
240    /**
241     * Sets the serverRunning variable to false, in order to get the server to shut down.
242     */
243    public void initiateShutdown()
244    {
245        super.initiateShutdown();
246
247        if (this.lanServerPing != null)
248        {
249            this.lanServerPing.interrupt();
250            this.lanServerPing = null;
251        }
252    }
253
254    /**
255     * Returns true if this integrated server is open to LAN
256     */
257    public boolean getPublic()
258    {
259        return this.isPublic;
260    }
261
262    /**
263     * Sets the game type for all worlds.
264     */
265    public void setGameType(EnumGameType par1EnumGameType)
266    {
267        this.getConfigurationManager().setGameType(par1EnumGameType);
268    }
269
270    /**
271     * Return whether command blocks are enabled.
272     */
273    public boolean isCommandBlockEnabled()
274    {
275        return true;
276    }
277
278    public NetworkListenThread getNetworkThread()
279    {
280        return this.getServerListeningThread();
281    }
282}