2012-05-04 17:02:12 -04:00
/*
* The FML Forge Mod Loader suite. Copyright (C) 2012 cpw
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package cpw.mods.fml.client ;
import java.util.ArrayList ;
2012-06-01 23:07:32 -04:00
import java.util.Arrays ;
2012-05-07 17:44:49 -04:00
import java.util.List ;
2012-05-11 16:23:26 -04:00
import java.util.Map ;
2012-12-12 19:23:40 -05:00
import java.util.Map.Entry ;
2012-05-04 17:02:12 -04:00
import java.util.logging.Logger ;
import net.minecraft.client.Minecraft ;
2013-12-11 18:46:25 -05:00
import net.minecraft.client.entity.EntityClientPlayerMP ;
2012-12-08 20:21:03 -08:00
import net.minecraft.client.gui.GuiScreen ;
2013-12-28 17:51:40 -05:00
import net.minecraft.client.gui.GuiSelectWorld ;
2012-12-08 20:21:03 -08:00
import net.minecraft.client.multiplayer.WorldClient ;
2013-12-11 18:46:25 -05:00
import net.minecraft.client.renderer.entity.Render ;
import net.minecraft.client.renderer.entity.RenderManager ;
2013-12-02 23:46:42 -05:00
import net.minecraft.client.resources.IReloadableResourceManager ;
import net.minecraft.client.resources.IResourcePack ;
2012-12-08 20:21:03 -08:00
import net.minecraft.crash.CrashReport ;
import net.minecraft.entity.Entity ;
import net.minecraft.entity.player.EntityPlayer ;
2013-09-27 10:45:20 -04:00
import net.minecraft.launchwrapper.Launch ;
2013-12-31 09:45:26 -05:00
import net.minecraft.network.INetHandler ;
2013-12-06 11:17:40 -05:00
import net.minecraft.network.NetworkManager ;
2012-08-09 09:21:16 -04:00
import net.minecraft.server.MinecraftServer ;
2013-12-26 12:41:49 -05:00
import org.apache.logging.log4j.Level ;
2012-08-17 09:24:38 -04:00
import com.google.common.base.Throwables ;
2012-11-16 22:39:47 -05:00
import com.google.common.collect.ImmutableList ;
2012-08-17 09:24:38 -04:00
import com.google.common.collect.ImmutableMap ;
2013-07-10 15:47:13 -04:00
import com.google.common.collect.Maps ;
2013-12-11 18:46:25 -05:00
import cpw.mods.fml.client.registry.RenderingRegistry ;
2012-07-23 16:33:17 -02:30
import cpw.mods.fml.common.DummyModContainer ;
2012-10-24 09:41:46 -04:00
import cpw.mods.fml.common.DuplicateModsFoundException ;
2012-05-24 21:06:27 -04:00
import cpw.mods.fml.common.FMLCommonHandler ;
2012-07-23 16:33:17 -02:30
import cpw.mods.fml.common.FMLLog ;
2012-05-24 21:06:27 -04:00
import cpw.mods.fml.common.IFMLSidedHandler ;
import cpw.mods.fml.common.Loader ;
2012-07-05 15:35:38 -04:00
import cpw.mods.fml.common.LoaderException ;
2012-07-23 16:33:17 -02:30
import cpw.mods.fml.common.MetadataCollection ;
2012-08-23 13:43:25 -04:00
import cpw.mods.fml.common.MissingModsException ;
2012-05-24 21:06:27 -04:00
import cpw.mods.fml.common.ModContainer ;
import cpw.mods.fml.common.ModMetadata ;
2012-07-22 11:56:38 -02:30
import cpw.mods.fml.common.ObfuscationReflectionHelper ;
2012-10-02 01:29:46 -04:00
import cpw.mods.fml.common.WrongMinecraftVersionException ;
2013-12-24 00:47:10 -05:00
import cpw.mods.fml.common.registry.GameData ;
2013-05-27 10:28:00 -04:00
import cpw.mods.fml.common.toposort.ModSortingException ;
2012-12-15 23:21:26 -05:00
import cpw.mods.fml.relauncher.Side ;
2012-05-04 17:02:12 -04:00
2012-05-11 15:18:26 -04:00
2012-05-04 17:02:12 -04:00
/**
* Handles primary communication from hooked code into the system
2012-06-26 15:29:34 -04:00
*
2013-07-02 19:39:02 -04:00
* The FML entry point is {@link #beginMinecraftLoading(Minecraft, List)} called from
2012-09-15 18:04:56 -07:00
* {@link Minecraft}
2012-06-26 15:29:34 -04:00
*
2012-05-04 17:02:12 -04:00
* Obfuscated code should focus on this class and other members of the "server"
* (or "client") code
2012-06-26 15:29:34 -04:00
*
2012-05-04 17:02:12 -04:00
* The actual mod loading is handled at arms length by {@link Loader}
2012-06-26 15:29:34 -04:00
*
2012-05-04 17:02:12 -04:00
* It is expected that a similar class will exist for each target environment:
* Bukkit and Client side.
2012-06-26 15:29:34 -04:00
*
2012-05-04 17:02:12 -04:00
* It should not be directly modified.
2012-06-26 15:29:34 -04:00
*
2012-05-04 17:02:12 -04:00
* @author cpw
2012-06-26 15:29:34 -04:00
*
2012-05-04 17:02:12 -04:00
*/
public class FMLClientHandler implements IFMLSidedHandler
{
/**
* The singleton
*/
private static final FMLClientHandler INSTANCE = new FMLClientHandler ();
/**
* A reference to the server itself
*/
private Minecraft client ;
2012-06-26 15:29:34 -04:00
2012-07-23 16:33:17 -02:30
private DummyModContainer optifineContainer ;
2012-06-26 15:29:34 -04:00
2013-11-10 11:49:06 -05:00
@SuppressWarnings ( "unused" )
2012-07-04 00:16:30 -04:00
private boolean guiLoaded ;
2013-11-10 11:49:06 -05:00
@SuppressWarnings ( "unused" )
2012-07-23 16:33:17 -02:30
private boolean serverIsRunning ;
2012-08-23 13:43:25 -04:00
private MissingModsException modsMissing ;
2013-05-27 10:28:00 -04:00
private ModSortingException modSorting ;
2013-07-28 20:52:12 +02:00
private boolean loading = true ;
2012-08-28 22:15:18 -04:00
2012-10-02 01:29:46 -04:00
private WrongMinecraftVersionException wrongMC ;
2012-10-16 12:39:04 -04:00
private CustomModLoadingErrorDisplayException customError ;
2012-10-24 09:41:46 -04:00
private DuplicateModsFoundException dupesFound ;
2012-12-07 01:52:16 -05:00
private boolean serverShouldBeKilledQuietly ;
2013-12-02 23:46:42 -05:00
private List < IResourcePack > resourcePackList ;
2013-07-02 01:39:40 -04:00
2013-11-10 11:49:06 -05:00
@SuppressWarnings ( "unused" )
2013-12-02 23:46:42 -05:00
private IReloadableResourceManager resourceManager ;
2013-07-10 15:47:13 -04:00
2013-12-02 23:46:42 -05:00
private Map < String , IResourcePack > resourcePackMap ;
2013-07-10 15:47:13 -04:00
2012-09-15 18:04:56 -07:00
/**
2012-10-25 16:18:42 -04:00
* Called to start the whole game off
2012-09-15 18:04:56 -07:00
*
2012-10-25 16:18:42 -04:00
* @param minecraft The minecraft instance being launched
2013-07-02 19:39:02 -04:00
* @param resourcePackList The resource pack list we will populate with mods
2013-07-10 15:47:13 -04:00
* @param resourceManager The resource manager
2012-09-15 18:04:56 -07:00
*/
2013-11-10 11:49:06 -05:00
@SuppressWarnings ( "unchecked" )
2013-12-02 23:46:42 -05:00
public void beginMinecraftLoading ( Minecraft minecraft , @SuppressWarnings ( "rawtypes" ) List resourcePackList , IReloadableResourceManager resourceManager )
2012-05-04 17:02:12 -04:00
{
2013-03-10 01:15:16 -05:00
client = minecraft ;
2013-07-02 01:39:40 -04:00
this . resourcePackList = resourcePackList ;
2013-07-10 15:47:13 -04:00
this . resourceManager = resourceManager ;
this . resourcePackMap = Maps . newHashMap ();
2012-07-30 22:31:07 -04:00
if ( minecraft . func_71355_q ())
2012-07-23 22:50:37 -02:30
{
FMLLog . severe ( "DEMO MODE DETECTED, FML will not work. Finishing now." );
haltGame ( "FML will not run in demo mode" , new RuntimeException ());
return ;
}
2012-07-30 22:31:07 -04:00
2012-06-07 19:25:49 -04:00
FMLCommonHandler . instance (). beginLoading ( this );
2012-06-01 14:55:49 -04:00
try
{
Class <?> optifineConfig = Class . forName ( "Config" , false , Loader . instance (). getModClassLoader ());
2012-07-23 16:33:17 -02:30
String optifineVersion = ( String ) optifineConfig . getField ( "VERSION" ). get ( null );
Map < String , Object > dummyOptifineMeta = ImmutableMap . < String , Object > builder (). put ( "name" , "Optifine" ). put ( "version" , optifineVersion ). build ();
2012-08-23 16:43:28 -04:00
ModMetadata optifineMetadata = MetadataCollection . from ( getClass (). getResourceAsStream ( "optifinemod.info" ), "optifine" ). getMetadataForId ( "optifine" , dummyOptifineMeta );
2012-07-23 16:33:17 -02:30
optifineContainer = new DummyModContainer ( optifineMetadata );
FMLLog . info ( "Forge Mod Loader has detected optifine %s, enabling compatibility features" , optifineContainer . getVersion ());
2012-06-01 14:55:49 -04:00
}
catch ( Exception e )
{
2012-06-01 23:07:32 -04:00
optifineContainer = null ;
2012-06-01 14:55:49 -04:00
}
2012-07-03 22:39:35 -04:00
try
{
Loader . instance (). loadMods ();
}
2012-10-02 01:29:46 -04:00
catch ( WrongMinecraftVersionException wrong )
{
wrongMC = wrong ;
}
2012-10-24 09:41:46 -04:00
catch ( DuplicateModsFoundException dupes )
{
dupesFound = dupes ;
}
2012-08-23 13:43:25 -04:00
catch ( MissingModsException missing )
{
modsMissing = missing ;
}
2013-05-27 10:28:00 -04:00
catch ( ModSortingException sorting )
{
modSorting = sorting ;
}
2012-10-16 12:39:04 -04:00
catch ( CustomModLoadingErrorDisplayException custom )
{
2013-12-16 11:47:48 -05:00
FMLLog . log ( Level . ERROR , custom , "A custom exception was thrown by a mod, the game will now halt" );
2012-10-16 12:39:04 -04:00
customError = custom ;
}
2012-07-03 22:39:35 -04:00
catch ( LoaderException le )
{
haltGame ( "There was a severe problem during mod loading that has caused the game to fail" , le );
return ;
}
2013-09-27 10:45:20 -04:00
Map < String , Map < String , String >> sharedModList = ( Map < String , Map < String , String >> ) Launch . blackboard . get ( "modList" );
if ( sharedModList == null )
{
sharedModList = Maps . newHashMap ();
Launch . blackboard . put ( "modList" , sharedModList );
}
for ( ModContainer mc : Loader . instance (). getActiveModList ())
{
Map < String , String > sharedModDescriptor = mc . getSharedModDescriptor ();
if ( sharedModDescriptor != null )
{
String sharedModId = "fml:" + mc . getModId ();
sharedModList . put ( sharedModId , sharedModDescriptor );
}
}
2012-05-04 17:02:12 -04:00
}
2012-07-03 22:39:35 -04:00
@Override
public void haltGame ( String message , Throwable t )
{
2012-07-30 22:31:07 -04:00
client . func_71377_b ( new CrashReport ( message , t ));
2012-07-23 22:50:37 -02:30
throw Throwables . propagate ( t );
2012-07-03 22:39:35 -04:00
}
2012-05-04 17:02:12 -04:00
/**
2012-05-07 17:44:49 -04:00
* Called a bit later on during initialization to finish loading mods
* Also initializes key bindings
2012-06-26 15:29:34 -04:00
*
2012-05-04 17:02:12 -04:00
*/
2013-12-11 18:46:25 -05:00
@SuppressWarnings ({ "deprecation" , "unchecked" })
2012-08-02 02:08:30 -02:30
public void finishMinecraftLoading ()
2012-05-04 17:02:12 -04:00
{
2013-05-27 10:28:00 -04:00
if ( modsMissing != null || wrongMC != null || customError != null || dupesFound != null || modSorting != null )
2012-08-23 13:43:25 -04:00
{
return ;
}
2012-07-03 22:39:35 -04:00
try
{
Loader . instance (). initializeMods ();
}
2012-10-16 12:39:04 -04:00
catch ( CustomModLoadingErrorDisplayException custom )
{
2013-12-16 11:47:48 -05:00
FMLLog . log ( Level . ERROR , custom , "A custom exception was thrown by a mod, the game will now halt" );
2012-10-16 12:39:04 -04:00
customError = custom ;
return ;
}
2012-07-03 22:39:35 -04:00
catch ( LoaderException le )
{
haltGame ( "There was a severe problem during mod loading that has caused the game to fail" , le );
return ;
}
2013-11-10 11:49:06 -05:00
2013-07-03 22:29:10 -07:00
// Reload resources
2013-12-16 11:47:48 -05:00
// client.func_110436_a();
2013-12-11 18:46:25 -05:00
RenderingRegistry . instance (). loadEntityRenderers (( Map < Class <? extends Entity > , Render > ) RenderManager . field_78727_a . field_78729_o );
2012-08-28 22:15:18 -04:00
loading = false ;
2012-08-13 19:57:40 -04:00
}
2012-07-29 22:54:59 -04:00
2013-11-10 11:49:06 -05:00
@SuppressWarnings ( "unused" )
2013-09-27 10:45:20 -04:00
public void extendModList ()
{
2013-11-10 11:49:06 -05:00
@SuppressWarnings ( "unchecked" )
2013-09-27 10:45:20 -04:00
Map < String , Map < String , String >> modList = ( Map < String , Map < String , String >> ) Launch . blackboard . get ( "modList" );
if ( modList != null )
{
for ( Entry < String , Map < String , String >> modEntry : modList . entrySet ())
{
String sharedModId = modEntry . getKey ();
String system = sharedModId . split ( ":" ) [ 0 ] ;
if ( "fml" . equals ( system ))
{
continue ;
}
Map < String , String > mod = modEntry . getValue ();
String modSystem = mod . get ( "modsystem" ); // the modsystem (FML uses FML or ModLoader)
String modId = mod . get ( "id" ); // unique ID
String modVersion = mod . get ( "version" ); // version
String modName = mod . get ( "name" ); // a human readable name
String modURL = mod . get ( "url" ); // a URL for the mod (can be empty string)
String modAuthors = mod . get ( "authors" ); // a csv of authors (can be empty string)
String modDescription = mod . get ( "description" ); // a (potentially) multiline description (can be empty string)
}
}
}
2012-08-23 13:43:25 -04:00
public void onInitializationComplete ()
2012-08-13 19:57:40 -04:00
{
2012-10-02 01:29:46 -04:00
if ( wrongMC != null )
{
2013-12-02 23:46:42 -05:00
showGuiScreen ( new GuiWrongMinecraft ( wrongMC ));
2012-10-02 01:29:46 -04:00
}
else if ( modsMissing != null )
2012-08-23 13:43:25 -04:00
{
2013-12-02 23:46:42 -05:00
showGuiScreen ( new GuiModsMissing ( modsMissing ));
2012-08-23 13:43:25 -04:00
}
2012-10-24 09:41:46 -04:00
else if ( dupesFound != null )
{
2013-12-02 23:46:42 -05:00
showGuiScreen ( new GuiDupesFound ( dupesFound ));
2012-10-24 09:41:46 -04:00
}
2013-05-27 10:28:00 -04:00
else if ( modSorting != null )
{
2013-12-02 23:46:42 -05:00
showGuiScreen ( new GuiSortingProblem ( modSorting ));
2013-05-27 10:28:00 -04:00
}
else if ( customError != null )
2012-10-16 12:39:04 -04:00
{
2013-12-02 23:46:42 -05:00
showGuiScreen ( new GuiCustomModLoadingErrorScreen ( customError ));
2012-10-16 12:39:04 -04:00
}
2012-08-23 13:43:25 -04:00
else
{
}
2012-05-04 17:02:12 -04:00
}
/**
* Get the server instance
*/
public Minecraft getClient ()
{
return client ;
}
/**
* Get a handle to the client's logger instance
* The client actually doesn't have one- so we return null
*/
public Logger getMinecraftLogger ()
{
return null ;
}
/**
* @return the instance
*/
public static FMLClientHandler instance ()
{
return INSTANCE ;
}
2012-05-07 17:44:49 -04:00
/**
* @param player
* @param gui
*/
public void displayGuiScreen ( EntityPlayer player , GuiScreen gui )
{
2012-07-30 22:31:07 -04:00
if ( client . field_71439_g == player && gui != null ) {
2013-12-02 23:46:42 -05:00
client . func_147108_a ( gui );
2012-05-07 17:44:49 -04:00
}
}
2012-06-01 14:55:49 -04:00
/**
* @param mods
*/
public void addSpecialModEntries ( ArrayList < ModContainer > mods )
{
if ( optifineContainer != null ) {
mods . add ( optifineContainer );
}
}
2012-06-01 23:07:32 -04:00
@Override
public List < String > getAdditionalBrandingInformation ()
{
if ( optifineContainer != null )
{
return Arrays . asList ( String . format ( "Optifine %s" , optifineContainer . getVersion ()));
} else {
2012-11-16 22:39:47 -05:00
return ImmutableList . < String > of ();
2012-06-01 23:07:32 -04:00
}
}
2012-06-02 15:13:55 -04:00
@Override
public Side getSide ()
{
return Side . CLIENT ;
}
2012-07-30 22:31:07 -04:00
public boolean hasOptifine ()
{
return optifineContainer != null ;
2012-07-06 10:29:17 -04:00
}
2012-08-08 00:31:24 -04:00
@Override
public void showGuiScreen ( Object clientGuiElement )
{
GuiScreen gui = ( GuiScreen ) clientGuiElement ;
2013-12-02 23:46:42 -05:00
client . func_147108_a ( gui );
2012-08-08 00:31:24 -04:00
}
2012-08-09 01:58:14 -04:00
2013-12-11 18:46:25 -05:00
public WorldClient getWorldClient ()
2012-08-09 01:58:14 -04:00
{
2013-12-11 18:46:25 -05:00
return client . field_71441_e ;
}
2012-08-09 01:58:14 -04:00
2013-12-11 18:46:25 -05:00
public EntityClientPlayerMP getClientPlayerEntity ()
{
return client . field_71439_g ;
2012-08-09 01:58:14 -04:00
}
2012-08-09 08:40:32 -04:00
2012-08-09 09:21:16 -04:00
@Override
public void beginServerLoading ( MinecraftServer server )
{
2012-12-07 01:52:16 -05:00
serverShouldBeKilledQuietly = false ;
2012-08-09 09:21:16 -04:00
// NOOP
}
@Override
public void finishServerLoading ()
{
// NOOP
}
2012-08-11 11:01:18 -04:00
@Override
public MinecraftServer getServer ()
{
return client . func_71401_C ();
}
2012-08-12 22:45:18 -04:00
2013-12-10 17:29:26 -05:00
public void displayMissingMods ( Object modMissingPacket )
2012-08-26 22:13:43 -04:00
{
2013-12-10 17:29:26 -05:00
// showGuiScreen(new GuiModsMissingForServer(modMissingPacket));
2012-08-26 22:13:43 -04:00
}
2012-08-28 22:15:18 -04:00
/**
* If the client is in the midst of loading, we disable saving so that custom settings aren't wiped out
*/
public boolean isLoading ()
{
return loading ;
}
2012-09-06 10:03:30 -04:00
2012-12-07 01:52:16 -05:00
@Override
public boolean shouldServerShouldBeKilledQuietly ()
{
return serverShouldBeKilledQuietly ;
}
2013-04-20 22:55:56 -04:00
/**
* Is this GUI type open?
*
* @param gui The type of GUI to test for
* @return if a GUI of this type is open
*/
public boolean isGUIOpen ( Class <? extends GuiScreen > gui )
{
return client . field_71462_r != null && client . field_71462_r . getClass (). equals ( gui );
}
2013-07-02 01:39:40 -04:00
@Override
public void addModAsResource ( ModContainer container )
{
2013-07-02 11:11:50 -04:00
Class <?> resourcePackType = container . getCustomResourcePackClass ();
if ( resourcePackType != null )
2013-07-02 01:39:40 -04:00
{
2013-07-02 11:11:50 -04:00
try
{
2013-12-02 23:46:42 -05:00
IResourcePack pack = ( IResourcePack ) resourcePackType . getConstructor ( ModContainer . class ). newInstance ( container );
2013-07-02 11:11:50 -04:00
resourcePackList . add ( pack );
2013-07-10 15:47:13 -04:00
resourcePackMap . put ( container . getModId (), pack );
2013-07-02 11:11:50 -04:00
}
catch ( NoSuchMethodException e )
{
2013-12-16 11:47:48 -05:00
FMLLog . log ( Level . ERROR , "The container %s (type %s) returned an invalid class for it's resource pack." , container . getName (), container . getClass (). getName ());
2013-07-02 11:11:50 -04:00
return ;
}
catch ( Exception e )
{
2013-12-16 11:47:48 -05:00
FMLLog . log ( Level . ERROR , e , "An unexpected exception occurred constructing the custom resource pack for %s" , container . getName ());
2013-07-02 11:11:50 -04:00
throw Throwables . propagate ( e );
}
2013-07-02 01:39:40 -04:00
}
}
2013-07-10 00:42:40 -04:00
@Override
public void updateResourcePackList ()
{
client . func_110436_a ();
}
2013-07-10 15:47:13 -04:00
2013-12-02 23:46:42 -05:00
public IResourcePack getResourcePackFor ( String modId )
2013-07-10 15:47:13 -04:00
{
return resourcePackMap . get ( modId );
}
2013-09-13 19:04:25 -05:00
@Override
public String getCurrentLanguage ()
{
return client . func_135016_M (). func_135041_c (). func_135034_a ();
}
2013-09-20 17:02:56 -04:00
@Override
public void serverStopped ()
{
// If the server crashes during startup, it might hang the client- reset the client so it can abend properly.
2013-09-22 16:56:24 +01:00
MinecraftServer server = getServer ();
if ( server != null && ! server . func_71200_ad ())
2013-09-20 17:02:56 -04:00
{
2013-09-22 16:56:24 +01:00
ObfuscationReflectionHelper . setPrivateValue ( MinecraftServer . class , server , true , "field_71296" + "_Q" , "serverIs" + "Running" );
2013-09-20 17:02:56 -04:00
}
}
2013-12-06 11:17:40 -05:00
2013-12-31 09:45:26 -05:00
@Override
public INetHandler getClientPlayHandler ()
{
return this . client . func_147114_u ();
}
2013-12-06 11:17:40 -05:00
@Override
public NetworkManager getClientToServerNetworkManager ()
{
2013-12-06 14:52:33 -05:00
return this . client . func_147114_u () != null ? this . client . func_147114_u (). func_147298_b () : null ;
2013-12-06 11:17:40 -05:00
}
2013-12-24 00:47:10 -05:00
2013-12-26 12:41:49 -05:00
public void handleClientWorldClosing ( WorldClient world )
2013-12-24 00:47:10 -05:00
{
2013-12-26 12:41:49 -05:00
NetworkManager client = getClientToServerNetworkManager ();
// ONLY revert a non-local connection
if ( client != null && ! client . func_150731_c ())
{
GameData . revertToFrozen ();
}
2013-12-24 00:47:10 -05:00
}
2013-12-28 17:51:40 -05:00
public void tryLoadWorld ( GuiSelectWorld selectWorldGUI , int selectedIndex )
{
selectWorldGUI . func_146615_e ( selectedIndex );
}
2012-05-04 17:02:12 -04:00
}