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