    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}