2012-03-30 14:11:13 +00:00
/ *
2016-06-23 03:49:47 +00:00
* Minecraft Forge
2018-07-01 21:17:28 +00:00
* Copyright ( c ) 2016 - 2018 .
2013-03-08 00:37:52 +00:00
*
2016-06-23 03:49:47 +00:00
* 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 version 2 . 1
* of the License .
*
* 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
2012-03-30 14:11:13 +00:00
* /
2013-03-08 00:25:48 +00:00
2014-09-23 05:01:24 +00:00
package net.minecraftforge.fml.common ;
2012-03-28 20:44:36 +00:00
import java.io.File ;
2018-04-15 00:00:38 +00:00
import java.io.FileInputStream ;
import java.io.FileOutputStream ;
2012-03-28 20:44:36 +00:00
import java.io.IOException ;
2016-12-21 19:13:27 +00:00
import java.io.InputStream ;
2018-04-15 00:00:38 +00:00
import java.io.InputStreamReader ;
import java.io.OutputStreamWriter ;
2012-08-31 00:10:13 +00:00
import java.net.MalformedURLException ;
2018-04-15 00:00:38 +00:00
import java.nio.charset.StandardCharsets ;
2014-03-24 20:16:36 +00:00
import java.util.ArrayList ;
2012-08-14 17:36:29 +00:00
import java.util.Comparator ;
2013-12-09 06:22:24 +00:00
import java.util.Iterator ;
2012-03-28 20:44:36 +00:00
import java.util.List ;
2012-03-30 05:12:59 +00:00
import java.util.Map ;
2012-05-10 13:42:31 +00:00
import java.util.Properties ;
2012-08-23 17:43:25 +00:00
import java.util.Set ;
2014-03-24 20:16:36 +00:00
2015-11-28 08:01:31 +00:00
import net.minecraft.util.ResourceLocation ;
2017-10-03 05:13:30 +00:00
import net.minecraftforge.common.ForgeVersion ;
2016-01-12 00:04:22 +00:00
import net.minecraftforge.common.capabilities.CapabilityManager ;
2016-10-11 05:15:35 +00:00
import net.minecraftforge.common.config.ConfigManager ;
2017-06-14 17:14:56 +00:00
import net.minecraftforge.common.crafting.CraftingHelper ;
2018-06-15 19:03:35 +00:00
import net.minecraftforge.fml.ModContainer ;
import net.minecraftforge.fml.ModContainer.Disableable ;
2015-05-11 03:55:11 +00:00
import net.minecraftforge.fml.common.ProgressManager.ProgressBar ;
2014-09-23 05:01:24 +00:00
import net.minecraftforge.fml.common.event.FMLLoadEvent ;
import net.minecraftforge.fml.common.event.FMLModIdMappingEvent ;
2015-11-28 08:01:31 +00:00
import net.minecraftforge.fml.common.registry.* ;
2014-09-23 05:01:24 +00:00
import net.minecraftforge.fml.common.toposort.ModSorter ;
import net.minecraftforge.fml.common.toposort.ModSortingException ;
import net.minecraftforge.fml.common.toposort.TopologicalSort ;
import net.minecraftforge.fml.common.toposort.ModSortingException.SortingExceptionData ;
import net.minecraftforge.fml.common.versioning.ArtifactVersion ;
2017-10-03 05:13:30 +00:00
import net.minecraftforge.fml.common.versioning.DependencyParser ;
2014-09-23 05:01:24 +00:00
import net.minecraftforge.fml.common.versioning.VersionParser ;
2018-06-21 19:37:32 +00:00
import net.minecraftforge.fml.relauncher.ModListHelper ;
2017-06-19 22:02:18 +00:00
import net.minecraftforge.registries.GameData ;
import net.minecraftforge.registries.ObjectHolderRegistry ;
2014-09-23 05:01:24 +00:00
2016-12-23 23:23:31 +00:00
import org.apache.commons.io.IOUtils ;
2013-12-16 16:47:48 +00:00
import org.apache.logging.log4j.Level ;
2014-03-24 20:16:36 +00:00
2012-07-22 14:26:38 +00:00
import com.google.common.base.CharMatcher ;
import com.google.common.base.Joiner ;
import com.google.common.base.Splitter ;
2013-12-17 15:51:00 +00:00
import com.google.common.collect.ArrayListMultimap ;
2012-08-11 06:43:04 +00:00
import com.google.common.collect.BiMap ;
2012-08-23 17:43:25 +00:00
import com.google.common.collect.HashBiMap ;
2012-07-22 14:26:38 +00:00
import com.google.common.collect.ImmutableList ;
import com.google.common.collect.ImmutableMap ;
2012-08-14 17:36:29 +00:00
import com.google.common.collect.ImmutableMultiset ;
2014-06-27 02:09:50 +00:00
import com.google.common.collect.Iterables ;
2012-10-24 13:41:46 +00:00
import com.google.common.collect.LinkedHashMultimap ;
2013-12-17 15:51:00 +00:00
import com.google.common.collect.ListMultimap ;
2012-07-22 14:26:38 +00:00
import com.google.common.collect.Lists ;
import com.google.common.collect.Maps ;
2013-12-17 15:51:00 +00:00
import com.google.common.collect.Multimaps ;
2012-08-14 17:36:29 +00:00
import com.google.common.collect.Multiset.Entry ;
import com.google.common.collect.Multisets ;
import com.google.common.collect.Ordering ;
2013-11-10 16:49:06 +00:00
import com.google.common.collect.SetMultimap ;
import com.google.common.collect.Sets ;
2012-08-14 17:36:29 +00:00
import com.google.common.collect.TreeMultimap ;
2015-04-25 05:30:17 +00:00
import com.google.gson.JsonArray ;
import com.google.gson.JsonElement ;
import com.google.gson.JsonObject ;
import com.google.gson.JsonParser ;
2014-03-24 20:16:36 +00:00
2017-01-11 23:17:56 +00:00
import javax.annotation.Nullable ;
2012-04-05 20:22:47 +00:00
/ * *
* The loader class performs the actual loading of the mod code from disk .
2012-07-30 02:54:59 +00:00
*
2012-07-22 14:26:38 +00:00
* < p >
* There are several { @link LoaderState } s to mod loading , triggered in two
* different stages from the FML handler code ' s hooks into the minecraft code .
* < / p >
2012-07-30 02:54:59 +00:00
*
2012-04-05 20:22:47 +00:00
* < ol >
2012-07-22 14:26:38 +00:00
* < li > LOADING . Scanning the filesystem for mod containers to load ( zips , jars ,
* directories ) , adding them to the { @link # modClassLoader } Scanning , the loaded
* containers for mod classes to load and registering them appropriately . < / li >
* < li > PREINIT . The mod classes are configured , they are sorted into a load
* order , and instances of the mods are constructed . < / li >
* < li > INIT . The mod instances are initialized . For BaseMod mods , this involves
* calling the load method . < / li >
* < li > POSTINIT . The mod instances are post initialized . For BaseMod mods this
* involves calling the modsLoaded method . < / li >
2012-04-05 20:22:47 +00:00
* < li > UP . The Loader is complete < / li >
2012-07-22 14:26:38 +00:00
* < li > ERRORED . The loader encountered an error during the LOADING phase and
* dropped to this state instead . It will not complete loading from this state ,
* but it attempts to continue loading before abandoning and giving a fatal
* error . < / li >
2012-04-05 20:22:47 +00:00
* < / ol >
2012-07-30 02:54:59 +00:00
*
2012-07-22 14:26:38 +00:00
* Phase 1 code triggers the LOADING and PREINIT states . Phase 2 code triggers
* the INIT and POSTINIT states .
2012-07-30 02:54:59 +00:00
*
2012-04-05 20:22:47 +00:00
* @author cpw
2012-07-30 02:54:59 +00:00
*
2012-04-05 20:22:47 +00:00
* /
2015-11-27 03:38:21 +00:00
@SuppressWarnings ( " unused " )
2012-04-05 14:07:52 +00:00
public class Loader
{
2017-10-03 05:13:30 +00:00
public static final String MC_VERSION = ForgeVersion . mcVersion ;
2012-04-05 20:22:47 +00:00
/ * *
* The singleton instance
* /
2012-04-05 14:07:52 +00:00
private static Loader instance ;
2012-04-05 20:22:47 +00:00
/ * *
* Build information for tracking purposes .
* /
2012-05-10 13:42:31 +00:00
private static String major ;
private static String minor ;
private static String rev ;
private static String build ;
2012-07-02 16:24:37 +00:00
private static String mccversion ;
2012-10-25 13:02:49 +00:00
private static String mcpversion ;
2012-04-05 14:07:52 +00:00
2012-04-05 20:22:47 +00:00
/ * *
* The class loader we load the mods into .
* /
2012-04-05 14:07:52 +00:00
private ModClassLoader modClassLoader ;
2012-04-05 20:22:47 +00:00
/ * *
* The sorted list of mods .
* /
2012-04-05 14:07:52 +00:00
private List < ModContainer > mods ;
2012-04-05 20:22:47 +00:00
/ * *
* A named list of mods
* /
2012-04-05 14:07:52 +00:00
private Map < String , ModContainer > namedMods ;
2013-12-17 15:51:00 +00:00
/ * *
* A reverse dependency graph for mods
* /
private ListMultimap < String , String > reverseDependencies ;
2012-04-05 20:22:47 +00:00
/ * *
* The canonical configuration directory
* /
2012-04-05 14:07:52 +00:00
private File canonicalConfigDir ;
2012-07-22 14:26:38 +00:00
private File canonicalModsDir ;
private LoadController modController ;
2012-10-02 05:29:46 +00:00
private MinecraftDummyContainer minecraft ;
2013-08-28 17:18:28 +00:00
private MCPDummyContainer mcp ;
2012-06-26 20:24:50 +00:00
2012-07-31 02:31:07 +00:00
private static File minecraftDir ;
2012-08-04 15:26:51 +00:00
private static List < String > injectedContainers ;
2013-03-30 16:12:54 +00:00
private ImmutableMap < String , String > fmlBrandingProperties ;
2013-12-17 15:51:00 +00:00
private File forcedModFile ;
2014-05-08 14:22:02 +00:00
private ModDiscoverer discoverer ;
2015-04-21 03:34:36 +00:00
private ProgressBar progressBar ;
2012-07-31 02:31:07 +00:00
2012-04-05 14:07:52 +00:00
public static Loader instance ( )
{
if ( instance = = null )
{
instance = new Loader ( ) ;
}
return instance ;
2012-04-03 16:03:21 +00:00
}
2012-04-05 20:22:47 +00:00
2013-11-10 16:49:06 +00:00
@SuppressWarnings ( " unchecked " )
2012-07-31 02:31:07 +00:00
public static void injectData ( Object . . . data )
2012-07-14 17:58:46 +00:00
{
2012-07-31 02:31:07 +00:00
major = ( String ) data [ 0 ] ;
minor = ( String ) data [ 1 ] ;
rev = ( String ) data [ 2 ] ;
build = ( String ) data [ 3 ] ;
mccversion = ( String ) data [ 4 ] ;
2012-10-25 13:02:49 +00:00
mcpversion = ( String ) data [ 5 ] ;
2012-07-31 02:31:07 +00:00
minecraftDir = ( File ) data [ 6 ] ;
2012-08-04 15:26:51 +00:00
injectedContainers = ( List < String > ) data [ 7 ] ;
2012-07-31 02:31:07 +00:00
}
2012-07-30 02:54:59 +00:00
2012-07-31 02:31:07 +00:00
private Loader ( )
{
2012-07-14 17:58:46 +00:00
modClassLoader = new ModClassLoader ( getClass ( ) . getClassLoader ( ) ) ;
2016-07-19 23:21:52 +00:00
if ( mccversion ! = null & & ! mccversion . equals ( MC_VERSION ) )
2012-08-13 04:17:34 +00:00
{
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( " This version of FML is built for Minecraft {}, we have detected Minecraft {} in your minecraft jar file " , mccversion , MC_VERSION ) ;
2015-03-27 08:17:57 +00:00
throw new LoaderException ( String . format ( " This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file " , mccversion , MC_VERSION ) ) ;
2012-08-13 04:17:34 +00:00
}
2012-10-02 05:29:46 +00:00
2014-06-26 18:37:28 +00:00
minecraft = new MinecraftDummyContainer ( MC_VERSION ) ;
2016-12-21 19:13:27 +00:00
InputStream mcpModInputStream = getClass ( ) . getResourceAsStream ( " /mcpmod.info " ) ;
try
{
mcp = new MCPDummyContainer ( MetadataCollection . from ( mcpModInputStream , " MCP " ) . getMetadataForId ( " mcp " , null ) ) ;
}
finally
{
IOUtils . closeQuietly ( mcpModInputStream ) ;
}
2012-07-14 17:58:46 +00:00
}
2012-04-05 20:22:47 +00:00
/ * *
2012-07-22 14:26:38 +00:00
* Sort the mods into a sorted list , using dependency information from the
* containers . The sorting is performed using a { @link TopologicalSort }
* based on the pre - and post - dependency information provided by the mods .
2012-04-05 20:22:47 +00:00
* /
2012-04-05 14:07:52 +00:00
private void sortModList ( )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . trace ( " Verifying mod requirements are satisfied " ) ;
2018-04-15 01:17:06 +00:00
List < WrongMinecraftVersionException > wrongMinecraftExceptions = new ArrayList < > ( ) ;
List < MissingModsException > missingModsExceptions = new ArrayList < > ( ) ;
2012-07-14 17:58:46 +00:00
try
2012-04-05 14:07:52 +00:00
{
2012-08-23 17:43:25 +00:00
BiMap < String , ArtifactVersion > modVersions = HashBiMap . create ( ) ;
2014-06-27 02:09:50 +00:00
for ( ModContainer mod : Iterables . concat ( getActiveModList ( ) , ModAPIManager . INSTANCE . getAPIList ( ) ) )
2012-04-05 14:07:52 +00:00
{
2012-07-30 21:01:27 +00:00
modVersions . put ( mod . getModId ( ) , mod . getProcessedVersion ( ) ) ;
}
2013-12-17 15:51:00 +00:00
ArrayListMultimap < String , String > reqList = ArrayListMultimap . create ( ) ;
2012-08-23 18:33:54 +00:00
for ( ModContainer mod : getActiveModList ( ) )
2012-07-30 21:01:27 +00:00
{
2017-08-06 23:00:16 +00:00
if ( ! mod . acceptableMinecraftVersionRange ( ) . containsVersion ( minecraft . getProcessedVersion ( ) ) )
2012-10-02 05:29:46 +00:00
{
2017-08-06 23:00:16 +00:00
FMLLog . log . fatal ( " The mod {} does not wish to run in Minecraft version {}. You will have to remove it to play. " , mod . getModId ( ) , getMCVersionString ( ) ) ;
2017-02-24 01:15:11 +00:00
WrongMinecraftVersionException ret = new WrongMinecraftVersionException ( mod , getMCVersionString ( ) ) ;
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( ret . getMessage ( ) ) ;
2017-02-24 01:15:11 +00:00
wrongMinecraftExceptions . add ( ret ) ;
continue ;
2012-10-02 05:29:46 +00:00
}
2013-12-17 15:51:00 +00:00
2018-05-12 19:58:52 +00:00
reqList . putAll ( mod . getModId ( ) , Iterables . transform ( mod . getRequirements ( ) , ArtifactVersion : : getLabel ) ) ;
Set < ArtifactVersion > allDeps = Sets . newHashSet ( ) ;
allDeps . addAll ( mod . getDependants ( ) ) ;
allDeps . addAll ( mod . getDependencies ( ) ) ;
allDeps . addAll ( mod . getRequirements ( ) ) ;
2018-04-15 01:17:06 +00:00
MissingModsException missingModsException = new MissingModsException ( mod . getModId ( ) , mod . getName ( ) ) ;
for ( ArtifactVersion acceptedVersion : allDeps )
2012-07-14 17:58:46 +00:00
{
2018-05-12 19:58:52 +00:00
boolean required = mod . getRequirements ( ) . contains ( acceptedVersion ) ;
if ( required | | modVersions . containsKey ( acceptedVersion . getLabel ( ) ) )
2012-07-30 21:01:27 +00:00
{
2018-04-15 01:17:06 +00:00
ArtifactVersion currentVersion = modVersions . get ( acceptedVersion . getLabel ( ) ) ;
2018-05-12 19:58:52 +00:00
if ( currentVersion = = null | | ! acceptedVersion . containsVersion ( currentVersion ) )
2012-07-30 21:01:27 +00:00
{
2018-04-15 01:17:06 +00:00
missingModsException . addMissingMod ( acceptedVersion , currentVersion , required ) ;
2012-07-30 21:01:27 +00:00
}
}
2012-07-14 17:58:46 +00:00
}
2018-04-15 01:17:06 +00:00
if ( ! missingModsException . getMissingModInfos ( ) . isEmpty ( ) )
2012-08-23 17:43:25 +00:00
{
2018-04-15 01:17:06 +00:00
FMLLog . log . fatal ( missingModsException . toString ( ) ) ;
missingModsExceptions . add ( missingModsException ) ;
2012-08-23 17:43:25 +00:00
}
2012-04-05 14:07:52 +00:00
}
2017-02-24 01:15:11 +00:00
if ( wrongMinecraftExceptions . isEmpty ( ) & & missingModsExceptions . isEmpty ( ) )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . trace ( " All mod requirements are satisfied " ) ;
2017-02-24 01:15:11 +00:00
}
else if ( missingModsExceptions . size ( ) = = 1 & & wrongMinecraftExceptions . isEmpty ( ) )
{
throw missingModsExceptions . get ( 0 ) ;
}
else if ( wrongMinecraftExceptions . size ( ) = = 1 & & missingModsExceptions . isEmpty ( ) )
{
throw wrongMinecraftExceptions . get ( 0 ) ;
}
else
{
throw new MultipleModsErrored ( wrongMinecraftExceptions , missingModsExceptions ) ;
}
2012-07-30 02:54:59 +00:00
2018-04-15 01:17:06 +00:00
reverseDependencies = Multimaps . invertFrom ( reqList , ArrayListMultimap . create ( ) ) ;
2012-08-23 18:33:54 +00:00
ModSorter sorter = new ModSorter ( getActiveModList ( ) , namedMods ) ;
2012-04-05 14:07:52 +00:00
2012-07-14 17:58:46 +00:00
try
{
2017-06-23 05:33:11 +00:00
FMLLog . log . trace ( " Sorting mods into an ordered list " ) ;
2012-08-23 19:29:17 +00:00
List < ModContainer > sortedMods = sorter . sort ( ) ;
2012-08-24 15:58:18 +00:00
// Reset active list to the sorted list
modController . getActiveModList ( ) . clear ( ) ;
modController . getActiveModList ( ) . addAll ( sortedMods ) ;
// And inject the sorted list into the overall list
2012-08-23 19:29:17 +00:00
mods . removeAll ( sortedMods ) ;
sortedMods . addAll ( mods ) ;
mods = sortedMods ;
2017-06-23 05:33:11 +00:00
FMLLog . log . trace ( " Mod sorting completed successfully " ) ;
2012-07-14 17:58:46 +00:00
}
catch ( ModSortingException sortException )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( " A dependency cycle was detected in the input mod set so an ordering cannot be determined " ) ;
2013-05-27 15:03:23 +00:00
SortingExceptionData < ModContainer > exceptionData = sortException . getExceptionData ( ) ;
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( " The first mod in the cycle is {} " , exceptionData . getFirstBadNode ( ) ) ;
FMLLog . log . fatal ( " The mod cycle involves " ) ;
2013-05-27 15:03:23 +00:00
for ( ModContainer mc : exceptionData . getVisitedNodes ( ) )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( " {} : before: {}, after: {} " , mc . toString ( ) , mc . getDependants ( ) , mc . getDependencies ( ) ) ;
2013-05-27 15:03:23 +00:00
}
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " The full error " , sortException ) ;
2013-05-27 14:46:22 +00:00
throw sortException ;
2012-07-14 17:58:46 +00:00
}
}
finally
2012-04-05 14:07:52 +00:00
{
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " Mod sorting data " ) ;
2013-01-30 23:57:21 +00:00
int unprintedMods = mods . size ( ) ;
2012-08-23 18:33:54 +00:00
for ( ModContainer mod : getActiveModList ( ) )
2012-05-10 08:00:07 +00:00
{
2012-08-04 15:26:51 +00:00
if ( ! mod . isImmutable ( ) )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " \ t{}({}:{}): {} ({}) " , mod . getModId ( ) , mod . getName ( ) , mod . getVersion ( ) , mod . getSource ( ) . getName ( ) , mod . getSortingRules ( ) ) ;
2013-01-30 23:57:21 +00:00
unprintedMods - - ;
2012-08-04 15:26:51 +00:00
}
2012-07-23 19:03:17 +00:00
}
2013-01-30 23:57:21 +00:00
if ( unprintedMods = = mods . size ( ) )
2012-07-30 02:54:59 +00:00
{
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " No user mods found to sort " ) ;
2012-05-10 08:00:07 +00:00
}
2012-04-05 14:07:52 +00:00
}
2012-07-14 17:58:46 +00:00
2012-03-28 20:44:36 +00:00
}
2012-04-05 14:07:52 +00:00
2012-04-05 20:22:47 +00:00
/ * *
2012-07-22 14:26:38 +00:00
* The primary loading code
2012-07-30 02:54:59 +00:00
*
*
2012-07-22 14:26:38 +00:00
* The found resources are first loaded into the { @link # modClassLoader }
* ( always ) then scanned for class resources matching the specification
* above .
2012-07-30 02:54:59 +00:00
*
2012-07-22 14:26:38 +00:00
* If they provide the { @link Mod } annotation , they will be loaded as
2013-11-10 18:15:26 +00:00
* " FML mods "
2012-07-30 02:54:59 +00:00
*
2012-07-22 14:26:38 +00:00
* Finally , if they are successfully loaded as classes , they are then added
* to the available mod list .
2012-04-05 20:22:47 +00:00
* /
2016-06-13 13:33:26 +00:00
private ModDiscoverer identifyMods ( List < String > additionalContainers )
2012-04-05 14:07:52 +00:00
{
2016-06-13 13:33:26 +00:00
injectedContainers . addAll ( additionalContainers ) ;
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " Building injected Mod Containers {} " , injectedContainers ) ;
2016-12-17 20:56:10 +00:00
mods . add ( minecraft ) ;
2012-10-25 13:02:49 +00:00
// Add in the MCP mod container
2012-10-26 11:55:23 +00:00
mods . add ( new InjectedModContainer ( mcp , new File ( " minecraft.jar " ) ) ) ;
2012-08-04 15:26:51 +00:00
for ( String cont : injectedContainers )
{
ModContainer mc ;
try
{
mc = ( ModContainer ) Class . forName ( cont , true , modClassLoader ) . newInstance ( ) ;
}
catch ( Exception e )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " A problem occurred instantiating the injected mod container {} " , cont , e ) ;
2012-08-04 15:26:51 +00:00
throw new LoaderException ( e ) ;
}
2013-08-27 16:31:37 +00:00
mods . add ( new InjectedModContainer ( mc , mc . getSource ( ) ) ) ;
2012-08-04 15:26:51 +00:00
}
2012-07-22 14:26:38 +00:00
ModDiscoverer discoverer = new ModDiscoverer ( ) ;
2012-04-05 14:07:52 +00:00
2018-04-11 20:10:27 +00:00
//if (!FMLForgePlugin.RUNTIME_DEOBF) //Only descover mods in the classpath if we're in the dev env.
{ //TODO: Move this to GradleStart? And add a specific mod canidate for Forge itself.
2018-04-10 23:01:35 +00:00
FMLLog . log . debug ( " Attempting to load mods contained in the minecraft jar file and associated classes " ) ;
discoverer . findClasspathMods ( modClassLoader ) ;
FMLLog . log . debug ( " Minecraft jar mods loaded successfully " ) ;
}
List < Artifact > maven_canidates = LibraryManager . flattenLists ( minecraftDir ) ;
List < File > file_canidates = LibraryManager . gatherLegacyCanidates ( minecraftDir ) ;
for ( Artifact artifact : maven_canidates )
2013-07-03 03:03:01 +00:00
{
2018-04-10 23:01:35 +00:00
artifact = Repository . resolveAll ( artifact ) ;
if ( artifact ! = null )
{
File target = artifact . getFile ( ) ;
if ( ! file_canidates . contains ( target ) )
file_canidates . add ( target ) ;
}
}
//Do we want to sort the full list after resolving artifacts?
//TODO: Add dependency gathering?
for ( File mod : file_canidates )
{
// skip loaded coremods
if ( CoreModManager . getIgnoredMods ( ) . contains ( mod . getName ( ) ) )
{
FMLLog . log . trace ( " Skipping already parsed coremod or tweaker {} " , mod . getName ( ) ) ;
}
else
{
FMLLog . log . debug ( " Found a candidate zip or jar file {} " , mod . getName ( ) ) ;
discoverer . addCandidate ( new ModCandidate ( mod , mod , ContainerType . JAR ) ) ;
}
2013-07-03 03:03:01 +00:00
}
2012-04-05 14:07:52 +00:00
2012-08-04 15:26:51 +00:00
mods . addAll ( discoverer . identifyMods ( ) ) ;
2012-08-14 17:36:29 +00:00
identifyDuplicates ( mods ) ;
2017-06-25 01:08:20 +00:00
namedMods = Maps . uniqueIndex ( mods , ModContainer : : getModId ) ;
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " Forge Mod Loader has identified {} mod{} to load " , mods . size ( ) , mods . size ( ) ! = 1 ? " s " : " " ) ;
2012-08-06 13:52:42 +00:00
return discoverer ;
2012-03-28 20:44:36 +00:00
}
2012-04-05 14:07:52 +00:00
2012-08-14 17:36:29 +00:00
private class ModIdComparator implements Comparator < ModContainer >
{
@Override
public int compare ( ModContainer o1 , ModContainer o2 )
{
return o1 . getModId ( ) . compareTo ( o2 . getModId ( ) ) ;
}
}
private void identifyDuplicates ( List < ModContainer > mods )
{
TreeMultimap < ModContainer , File > dupsearch = TreeMultimap . create ( new ModIdComparator ( ) , Ordering . arbitrary ( ) ) ;
for ( ModContainer mc : mods )
{
if ( mc . getSource ( ) ! = null )
{
dupsearch . put ( mc , mc . getSource ( ) ) ;
}
}
ImmutableMultiset < ModContainer > duplist = Multisets . copyHighestCountFirst ( dupsearch . keys ( ) ) ;
2012-10-24 13:41:46 +00:00
SetMultimap < ModContainer , File > dupes = LinkedHashMultimap . create ( ) ;
2012-08-14 17:36:29 +00:00
for ( Entry < ModContainer > e : duplist . entrySet ( ) )
{
if ( e . getCount ( ) > 1 )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( " Found a duplicate mod {} at {} " , e . getElement ( ) . getModId ( ) , dupsearch . get ( e . getElement ( ) ) ) ;
2012-10-24 13:41:46 +00:00
dupes . putAll ( e . getElement ( ) , dupsearch . get ( e . getElement ( ) ) ) ;
2012-08-14 17:36:29 +00:00
}
}
2012-10-24 13:41:46 +00:00
if ( ! dupes . isEmpty ( ) )
{
2013-08-28 17:18:28 +00:00
throw new DuplicateModsFoundException ( dupes ) ;
2012-10-24 13:41:46 +00:00
}
2012-08-14 17:36:29 +00:00
}
2012-04-05 20:22:47 +00:00
/ * *
2013-01-22 02:37:29 +00:00
*
2012-04-05 20:22:47 +00:00
* /
2012-07-22 14:26:38 +00:00
private void initializeLoader ( )
2012-04-05 14:07:52 +00:00
{
File modsDir = new File ( minecraftDir , " mods " ) ;
File configDir = new File ( minecraftDir , " config " ) ;
String canonicalModsPath ;
String canonicalConfigPath ;
try
{
canonicalModsPath = modsDir . getCanonicalPath ( ) ;
canonicalConfigPath = configDir . getCanonicalPath ( ) ;
canonicalConfigDir = configDir . getCanonicalFile ( ) ;
2012-07-22 14:26:38 +00:00
canonicalModsDir = modsDir . getCanonicalFile ( ) ;
2012-04-05 14:07:52 +00:00
}
catch ( IOException ioe )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " Failed to resolve loader directories: mods : {} ; config {} " , canonicalModsDir . getAbsolutePath ( ) ,
configDir . getAbsolutePath ( ) , ioe ) ;
2012-04-05 14:07:52 +00:00
throw new LoaderException ( ioe ) ;
}
2012-07-22 14:26:38 +00:00
if ( ! canonicalModsDir . exists ( ) )
2012-04-05 14:07:52 +00:00
{
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " No mod directory found, creating one: {} " , canonicalModsPath ) ;
2012-07-22 14:26:38 +00:00
boolean dirMade = canonicalModsDir . mkdir ( ) ;
if ( ! dirMade )
2012-04-05 14:07:52 +00:00
{
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( " Unable to create the mod directory {} " , canonicalModsPath ) ;
2015-03-27 08:17:57 +00:00
throw new LoaderException ( String . format ( " Unable to create the mod directory %s " , canonicalModsPath ) ) ;
2012-04-05 14:07:52 +00:00
}
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " Mod directory created successfully " ) ;
2012-04-05 14:07:52 +00:00
}
2012-07-22 14:26:38 +00:00
if ( ! canonicalConfigDir . exists ( ) )
2012-04-05 14:07:52 +00:00
{
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " No config directory found, creating one: {} " , canonicalConfigPath ) ;
2012-07-22 14:26:38 +00:00
boolean dirMade = canonicalConfigDir . mkdir ( ) ;
if ( ! dirMade )
2012-04-05 14:07:52 +00:00
{
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( " Unable to create the config directory {} " , canonicalConfigPath ) ;
2012-07-22 14:26:38 +00:00
throw new LoaderException ( ) ;
2012-04-05 14:07:52 +00:00
}
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " Config directory created successfully " ) ;
2012-04-05 14:07:52 +00:00
}
2012-07-22 14:26:38 +00:00
if ( ! canonicalModsDir . isDirectory ( ) )
2012-04-05 14:07:52 +00:00
{
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( " Attempting to load mods from {}, which is not a directory " , canonicalModsPath ) ;
2012-07-22 14:26:38 +00:00
throw new LoaderException ( ) ;
2012-04-05 14:07:52 +00:00
}
if ( ! configDir . isDirectory ( ) )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . fatal ( " Attempting to load configuration from {}, which is not a directory " , canonicalConfigPath ) ;
2012-07-22 14:26:38 +00:00
throw new LoaderException ( ) ;
2012-03-28 20:44:36 +00:00
}
2015-04-25 05:30:17 +00:00
readInjectedDependencies ( ) ;
2012-03-28 20:44:36 +00:00
}
2012-04-05 14:07:52 +00:00
2012-07-24 01:20:37 +00:00
public List < ModContainer > getModList ( )
2012-04-05 14:07:52 +00:00
{
2012-10-18 18:41:32 +00:00
return instance ( ) . mods ! = null ? ImmutableList . copyOf ( instance ( ) . mods ) : ImmutableList . < ModContainer > of ( ) ;
2012-03-28 20:44:36 +00:00
}
2012-04-05 14:07:52 +00:00
2016-07-20 20:03:56 +00:00
/ * *
* Used to setup a testharness with a single dummy mod instance for use with various testing hooks
2016-11-28 04:58:19 +00:00
* @param containers A list of dummy containers that will be returned as " active " for all queries
2016-07-20 20:03:56 +00:00
* /
2016-11-28 04:58:19 +00:00
public void setupTestHarness ( ModContainer . . . containers )
2016-07-20 20:03:56 +00:00
{
modController = new LoadController ( this ) ;
2016-11-28 04:58:19 +00:00
mods = Lists . newArrayList ( containers ) ;
2017-06-25 01:08:20 +00:00
namedMods = Maps . uniqueIndex ( mods , ModContainer : : getModId ) ;
2016-07-20 20:03:56 +00:00
modController . transition ( LoaderState . LOADING , false ) ;
modController . transition ( LoaderState . CONSTRUCTING , false ) ;
ObjectHolderRegistry . INSTANCE . findObjectHolders ( new ASMDataTable ( ) ) ;
2016-11-28 04:58:19 +00:00
modController . forceActiveContainer ( containers [ 0 ] ) ;
2016-07-20 20:03:56 +00:00
}
2018-05-13 05:39:42 +00:00
2012-04-05 20:22:47 +00:00
/ * *
2012-07-22 14:26:38 +00:00
* Called from the hook to start mod loading . We trigger the
2018-05-13 05:39:42 +00:00
* { @link # identifyMods ( List ) } and Constructing , Preinitalization , and Initalization phases here . Finally ,
2012-07-22 14:26:38 +00:00
* the mod list is frozen completely and is consider immutable from then on .
2016-07-20 20:03:56 +00:00
* @param injectedModContainers containers to inject
2012-04-05 20:22:47 +00:00
* /
2016-06-13 13:33:26 +00:00
public void loadMods ( List < String > injectedModContainers )
2012-04-05 14:07:52 +00:00
{
2015-04-24 21:11:49 +00:00
progressBar = ProgressManager . push ( " Loading " , 7 ) ;
2015-04-24 20:00:22 +00:00
progressBar . step ( " Constructing Mods " ) ;
2012-07-22 14:26:38 +00:00
initializeLoader ( ) ;
2012-08-02 04:38:30 +00:00
mods = Lists . newArrayList ( ) ;
namedMods = Maps . newHashMap ( ) ;
2012-07-30 21:01:27 +00:00
modController = new LoadController ( this ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . LOADING , false ) ;
2016-06-13 13:33:26 +00:00
discoverer = identifyMods ( injectedModContainers ) ;
2014-05-08 14:22:02 +00:00
ModAPIManager . INSTANCE . manageAPI ( modClassLoader , discoverer ) ;
2012-07-22 14:26:38 +00:00
disableRequestedMods ( ) ;
2012-08-23 18:33:54 +00:00
modController . distributeStateMessage ( FMLLoadEvent . class ) ;
2012-04-05 14:07:52 +00:00
sortModList ( ) ;
2013-10-31 02:20:28 +00:00
ModAPIManager . INSTANCE . cleanupAPIContainers ( modController . getActiveModList ( ) ) ;
ModAPIManager . INSTANCE . cleanupAPIContainers ( mods ) ;
2012-07-22 14:26:38 +00:00
mods = ImmutableList . copyOf ( mods ) ;
2014-05-08 14:22:02 +00:00
for ( File nonMod : discoverer . getNonModLibs ( ) )
2012-08-31 00:10:13 +00:00
{
if ( nonMod . isFile ( ) )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " FML has found a non-mod file {} in your mods directory. It will now be injected into your classpath. This could severe stability issues, it should be removed if possible. " , nonMod . getName ( ) ) ;
2012-08-31 00:10:13 +00:00
try
{
modClassLoader . addFile ( nonMod ) ;
}
catch ( MalformedURLException e )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " Encountered a weird problem with non-mod file injection : {} " , nonMod . getName ( ) , e ) ;
2012-08-31 00:10:13 +00:00
}
}
}
2016-10-11 05:15:35 +00:00
ConfigManager . loadData ( discoverer . getASMTable ( ) ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . CONSTRUCTING , false ) ;
2014-05-08 14:22:02 +00:00
modController . distributeStateMessage ( LoaderState . CONSTRUCTING , modClassLoader , discoverer . getASMTable ( ) , reverseDependencies ) ;
2015-06-10 05:25:13 +00:00
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " Mod signature data " ) ;
FMLLog . log . debug ( " \ tValid Signatures: " ) ;
2015-06-10 05:25:13 +00:00
for ( ModContainer mod : getActiveModList ( ) )
{
if ( mod . getSigningCertificate ( ) ! = null )
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " \ t \ t({}) {} \ t({} \ t{}) \ t{} " , CertificateHelper . getFingerprint ( mod . getSigningCertificate ( ) ) , mod . getModId ( ) , mod . getName ( ) , mod . getVersion ( ) , mod . getSource ( ) . getName ( ) ) ;
2015-06-10 05:25:13 +00:00
}
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " \ tMissing Signatures: " ) ;
2012-12-18 00:55:46 +00:00
for ( ModContainer mod : getActiveModList ( ) )
{
2015-06-10 05:25:13 +00:00
if ( mod . getSigningCertificate ( ) = = null )
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " \ t \ t{} \ t({} \ t{}) \ t{} " , mod . getModId ( ) , mod . getName ( ) , mod . getVersion ( ) , mod . getSource ( ) . getName ( ) ) ;
2012-12-18 00:55:46 +00:00
}
2013-01-31 01:55:12 +00:00
if ( getActiveModList ( ) . isEmpty ( ) )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " No user mod signature data found " ) ;
2013-01-31 01:55:12 +00:00
}
2015-04-24 20:00:22 +00:00
progressBar . step ( " Initializing mods Phase 1 " ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . PREINITIALIZATION , false ) ;
2014-05-08 14:22:02 +00:00
}
public void preinitializeMods ( )
{
2014-05-08 14:40:52 +00:00
if ( ! modController . isInState ( LoaderState . PREINITIALIZATION ) )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . warn ( " There were errors previously. Not beginning mod initialization phase " ) ;
2014-05-08 14:40:52 +00:00
return ;
}
2017-06-19 22:02:18 +00:00
GameData . fireCreateRegistryEvents ( ) ;
2014-07-12 16:03:34 +00:00
ObjectHolderRegistry . INSTANCE . findObjectHolders ( discoverer . getASMTable ( ) ) ;
2015-05-30 18:07:54 +00:00
ItemStackHolderInjector . INSTANCE . findHolders ( discoverer . getASMTable ( ) ) ;
2016-01-12 00:04:22 +00:00
CapabilityManager . INSTANCE . injectCapabilities ( discoverer . getASMTable ( ) ) ;
2017-06-21 01:39:55 +00:00
modController . distributeStateMessage ( LoaderState . PREINITIALIZATION , discoverer . getASMTable ( ) , canonicalConfigDir ) ;
2017-07-13 21:45:13 +00:00
GameData . fireRegistryEvents ( rl - > ! rl . equals ( GameData . RECIPES ) ) ;
2016-09-18 01:08:42 +00:00
FMLCommonHandler . instance ( ) . fireSidedRegistryEvents ( ) ;
2014-05-25 02:32:24 +00:00
ObjectHolderRegistry . INSTANCE . applyObjectHolders ( ) ;
2015-05-30 18:07:54 +00:00
ItemStackHolderInjector . INSTANCE . inject ( ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . INITIALIZATION , false ) ;
2015-04-24 21:11:49 +00:00
progressBar . step ( " Initializing Minecraft Engine " ) ;
2012-03-28 20:44:36 +00:00
}
2012-07-22 14:26:38 +00:00
private void disableRequestedMods ( )
2012-04-05 14:07:52 +00:00
{
2012-08-23 21:37:44 +00:00
String forcedModList = System . getProperty ( " fml.modStates " , " " ) ;
2017-06-23 05:33:11 +00:00
FMLLog . log . trace ( " Received a system property request \ '{} \ ' " , forcedModList ) ;
2012-07-22 14:26:38 +00:00
Map < String , String > sysPropertyStateList = Splitter . on ( CharMatcher . anyOf ( " ;: " ) )
. omitEmptyStrings ( ) . trimResults ( ) . withKeyValueSeparator ( " = " )
2012-08-23 21:37:44 +00:00
. split ( forcedModList ) ;
2017-06-23 05:33:11 +00:00
FMLLog . log . trace ( " System property request managing the state of {} mods " , sysPropertyStateList . size ( ) ) ;
2012-07-22 14:26:38 +00:00
Map < String , String > modStates = Maps . newHashMap ( ) ;
2012-07-30 02:54:59 +00:00
2013-12-17 15:51:00 +00:00
forcedModFile = new File ( canonicalConfigDir , " fmlModState.properties " ) ;
2012-08-23 21:37:44 +00:00
Properties forcedModListProperties = new Properties ( ) ;
if ( forcedModFile . exists ( ) & & forcedModFile . isFile ( ) )
2012-07-22 14:26:38 +00:00
{
2017-06-23 05:33:11 +00:00
FMLLog . log . trace ( " Found a mod state file {} " , forcedModFile . getName ( ) ) ;
2012-07-22 14:26:38 +00:00
try
{
2018-04-15 00:00:38 +00:00
forcedModListProperties . load ( new InputStreamReader ( new FileInputStream ( forcedModFile ) , StandardCharsets . UTF_8 ) ) ;
2017-06-23 05:33:11 +00:00
FMLLog . log . trace ( " Loaded states for {} mods from file " , forcedModListProperties . size ( ) ) ;
2012-07-22 14:26:38 +00:00
}
catch ( Exception e )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " An error occurred reading the fmlModState.properties file " , e ) ;
2012-07-22 14:26:38 +00:00
}
}
2012-08-23 21:37:44 +00:00
modStates . putAll ( Maps . fromProperties ( forcedModListProperties ) ) ;
2012-07-22 14:26:38 +00:00
modStates . putAll ( sysPropertyStateList ) ;
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " After merging, found state information for {} mods " , modStates . size ( ) ) ;
2012-07-22 14:26:38 +00:00
2017-06-25 01:08:20 +00:00
Map < String , Boolean > isEnabled = Maps . transformValues ( modStates , Boolean : : parseBoolean ) ;
2012-07-30 02:54:59 +00:00
2012-07-22 14:26:38 +00:00
for ( Map . Entry < String , Boolean > entry : isEnabled . entrySet ( ) )
{
if ( namedMods . containsKey ( entry . getKey ( ) ) )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " Setting mod {} to enabled state {} " , entry . getKey ( ) , entry . getValue ( ) ) ;
2012-07-22 14:26:38 +00:00
namedMods . get ( entry . getKey ( ) ) . setEnabledState ( entry . getValue ( ) ) ;
}
2012-05-10 13:42:31 +00:00
}
2012-03-28 20:44:36 +00:00
}
2012-04-05 14:07:52 +00:00
2012-04-05 20:22:47 +00:00
/ * *
* Query if we know of a mod named modname
2012-07-30 02:54:59 +00:00
*
2012-04-05 20:22:47 +00:00
* @param modname
2012-09-16 01:04:56 +00:00
* @return If the mod is loaded
2012-04-05 20:22:47 +00:00
* /
2012-04-05 14:07:52 +00:00
public static boolean isModLoaded ( String modname )
{
2012-08-23 21:08:18 +00:00
return instance ( ) . namedMods . containsKey ( modname ) & & instance ( ) . modController . getModState ( instance . namedMods . get ( modname ) ) ! = ModState . DISABLED ;
2012-03-28 20:44:36 +00:00
}
2012-04-05 20:22:47 +00:00
2012-04-05 14:07:52 +00:00
public File getConfigDir ( )
{
return canonicalConfigDir ;
2012-03-28 20:44:36 +00:00
}
2012-06-26 20:24:50 +00:00
2012-05-06 23:32:59 +00:00
public String getCrashInformation ( )
{
2013-03-10 16:12:22 +00:00
// Handle being called before we've begun setup
if ( modController = = null )
{
return " " ;
}
2012-07-22 14:26:38 +00:00
StringBuilder ret = new StringBuilder ( ) ;
2013-12-06 16:17:40 +00:00
List < String > branding = FMLCommonHandler . instance ( ) . getBrandings ( false ) ;
2012-07-30 02:54:59 +00:00
2013-12-06 16:17:40 +00:00
Joiner . on ( ' ' ) . skipNulls ( ) . appendTo ( ret , branding ) ;
2013-08-28 17:18:28 +00:00
if ( modController ! = null )
2012-07-23 19:03:17 +00:00
{
modController . printModStates ( ret ) ;
}
2012-05-10 13:42:31 +00:00
return ret . toString ( ) ;
2012-05-06 23:32:59 +00:00
}
2012-05-11 05:45:36 +00:00
public String getFMLVersionString ( )
{
2015-06-01 20:29:34 +00:00
return " 8.0.99.99 " ;
2012-05-11 05:45:36 +00:00
}
2012-05-15 19:52:19 +00:00
2015-12-01 18:08:35 +00:00
public ModClassLoader getModClassLoader ( )
2012-05-15 19:52:19 +00:00
{
return modClassLoader ;
}
2012-07-22 14:26:38 +00:00
2017-10-03 05:13:30 +00:00
/ * *
* @deprecated use { @link DependencyParser # parseDependencies ( String ) }
* /
@Deprecated // TODO: remove in 1.13
2012-08-23 17:43:25 +00:00
public void computeDependencies ( String dependencyString , Set < ArtifactVersion > requirements , List < ArtifactVersion > dependencies , List < ArtifactVersion > dependants )
2012-07-22 14:26:38 +00:00
{
2017-10-03 05:13:30 +00:00
DependencyParser dependencyParser = new DependencyParser ( " unknown " , FMLCommonHandler . instance ( ) . getSide ( ) ) ;
DependencyParser . DependencyInfo info = dependencyParser . parseDependencies ( dependencyString ) ;
requirements . addAll ( info . requirements ) ;
dependencies . addAll ( info . dependencies ) ;
dependants . addAll ( info . dependants ) ;
2012-07-22 14:26:38 +00:00
}
public Map < String , ModContainer > getIndexedModList ( )
{
2018-05-10 05:40:14 +00:00
return namedMods ! = null ? ImmutableMap . copyOf ( namedMods ) : ImmutableMap . of ( ) ;
2012-07-22 14:26:38 +00:00
}
2012-07-23 19:03:17 +00:00
public void initializeMods ( )
{
2015-05-03 02:13:41 +00:00
progressBar . step ( " Initializing mods Phase 2 " ) ;
2017-06-24 00:52:59 +00:00
CraftingHelper . loadRecipes ( false ) ;
2012-07-23 19:03:17 +00:00
// Mod controller should be in the initialization state here
2012-08-02 04:38:30 +00:00
modController . distributeStateMessage ( LoaderState . INITIALIZATION ) ;
2015-04-24 20:00:22 +00:00
progressBar . step ( " Initializing mods Phase 3 " ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . POSTINITIALIZATION , false ) ;
2012-10-24 20:39:55 +00:00
modController . distributeStateMessage ( FMLInterModComms . IMCEvent . class ) ;
2015-05-30 18:07:54 +00:00
ItemStackHolderInjector . INSTANCE . inject ( ) ;
2012-08-02 04:38:30 +00:00
modController . distributeStateMessage ( LoaderState . POSTINITIALIZATION ) ;
2015-04-21 03:34:36 +00:00
progressBar . step ( " Finishing up " ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . AVAILABLE , false ) ;
2012-08-02 04:38:30 +00:00
modController . distributeStateMessage ( LoaderState . AVAILABLE ) ;
2017-06-19 22:02:18 +00:00
GameData . freezeData ( ) ;
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " Forge Mod Loader has successfully loaded {} mod{} " , mods . size ( ) , mods . size ( ) = = 1 ? " " : " s " ) ;
2015-04-24 21:47:39 +00:00
progressBar . step ( " Completing Minecraft initialization " ) ;
2012-07-23 19:03:17 +00:00
}
2012-07-24 01:20:37 +00:00
2012-08-21 22:48:12 +00:00
public ICrashCallable getCallableCrashInformation ( )
2012-07-24 01:20:37 +00:00
{
}
public List < ModContainer > getActiveModList ( )
{
2012-10-18 18:41:32 +00:00
return modController ! = null ? modController . getActiveModList ( ) : ImmutableList . < ModContainer > of ( ) ;
2012-07-24 01:20:37 +00:00
}
public ModState getModState ( ModContainer selectedMod )
{
return modController . getModState ( selectedMod ) ;
}
2012-07-31 02:31:07 +00:00
public String getMCVersionString ( )
{
return " Minecraft " + mccversion ;
}
2012-08-02 04:38:30 +00:00
2013-01-22 14:11:44 +00:00
public boolean serverStarting ( Object server )
2012-08-02 04:38:30 +00:00
{
2013-01-22 14:11:44 +00:00
try
{
modController . distributeStateMessage ( LoaderState . SERVER_STARTING , server ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . SERVER_STARTING , false ) ;
2013-01-22 14:11:44 +00:00
}
catch ( Throwable t )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " A fatal exception occurred during the server starting event " , t ) ;
2013-01-22 14:11:44 +00:00
return false ;
}
return true ;
2012-08-02 04:38:30 +00:00
}
2012-08-04 15:26:51 +00:00
2012-08-02 04:38:30 +00:00
public void serverStarted ( )
{
modController . distributeStateMessage ( LoaderState . SERVER_STARTED ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . SERVER_STARTED , false ) ;
2012-08-02 04:38:30 +00:00
}
2012-08-04 15:26:51 +00:00
2012-08-02 04:38:30 +00:00
public void serverStopping ( )
{
modController . distributeStateMessage ( LoaderState . SERVER_STOPPING ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . SERVER_STOPPING , false ) ;
2012-08-02 04:38:30 +00:00
}
2012-08-11 06:43:04 +00:00
public BiMap < ModContainer , Object > getModObjectList ( )
{
return modController . getModObjectList ( ) ;
}
public BiMap < Object , ModContainer > getReversedModObjectList ( )
{
return getModObjectList ( ) . inverse ( ) ;
}
2012-08-13 19:26:29 +00:00
2017-01-11 23:17:56 +00:00
@Nullable
2012-08-13 19:26:29 +00:00
public ModContainer activeModContainer ( )
{
2012-12-07 06:52:16 +00:00
return modController ! = null ? modController . activeContainer ( ) : null ;
2012-08-13 19:26:29 +00:00
}
public boolean isInState ( LoaderState state )
{
return modController . isInState ( state ) ;
}
2012-10-02 05:29:46 +00:00
public MinecraftDummyContainer getMinecraftModContainer ( )
{
return minecraft ;
}
2012-10-24 20:39:55 +00:00
2013-08-28 17:18:28 +00:00
public boolean hasReachedState ( LoaderState state )
{
return modController ! = null ? modController . hasReachedState ( state ) : false ;
}
2012-10-25 13:02:49 +00:00
2013-08-28 17:18:28 +00:00
public String getMCPVersionString ( )
{
2015-11-13 07:59:43 +00:00
return String . format ( " MCP %s " , mcpversion ) ;
2013-08-28 17:18:28 +00:00
}
2012-12-31 04:52:38 +00:00
public void serverStopped ( )
{
modController . distributeStateMessage ( LoaderState . SERVER_STOPPED ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . SERVER_STOPPED , true ) ;
modController . transition ( LoaderState . AVAILABLE , true ) ;
2012-12-31 04:52:38 +00:00
}
2013-01-22 14:11:44 +00:00
2013-01-24 15:23:36 +00:00
public boolean serverAboutToStart ( Object server )
2013-01-22 14:11:44 +00:00
{
try
{
modController . distributeStateMessage ( LoaderState . SERVER_ABOUT_TO_START , server ) ;
2013-06-11 18:41:19 +00:00
modController . transition ( LoaderState . SERVER_ABOUT_TO_START , false ) ;
2013-01-22 14:11:44 +00:00
}
catch ( Throwable t )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " A fatal exception occurred during the server about to start event " , t ) ;
2013-01-22 14:11:44 +00:00
return false ;
}
return true ;
}
2013-03-23 19:39:34 +00:00
2013-03-30 16:12:54 +00:00
public Map < String , String > getFMLBrandingProperties ( )
{
if ( fmlBrandingProperties = = null )
{
Properties loaded = new Properties ( ) ;
try
{
loaded . load ( getClass ( ) . getClassLoader ( ) . getResourceAsStream ( " fmlbranding.properties " ) ) ;
}
2013-03-31 14:01:46 +00:00
catch ( Exception e )
2013-03-30 16:12:54 +00:00
{
// File not found - ignore
}
fmlBrandingProperties = Maps . fromProperties ( loaded ) ;
}
return fmlBrandingProperties ;
}
2013-06-27 12:38:11 +00:00
public Map < String , String > getCustomModProperties ( String modId )
{
return getIndexedModList ( ) . get ( modId ) . getCustomModProperties ( ) ;
}
2013-12-09 06:22:24 +00:00
boolean checkRemoteModList ( Map < String , String > modList , Side side )
{
Set < String > remoteModIds = modList . keySet ( ) ;
Set < String > localModIds = namedMods . keySet ( ) ;
Set < String > difference = Sets . newLinkedHashSet ( Sets . difference ( localModIds , remoteModIds ) ) ;
for ( Iterator < String > iterator = difference . iterator ( ) ; iterator . hasNext ( ) ; )
{
String missingRemotely = iterator . next ( ) ;
ModState modState = modController . getModState ( namedMods . get ( missingRemotely ) ) ;
if ( modState = = ModState . DISABLED )
{
iterator . remove ( ) ;
}
}
2014-09-23 02:29:40 +00:00
if ( difference . size ( ) > 0 )
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " Attempting connection with missing mods {} at {} " , difference , side ) ;
2013-12-09 06:22:24 +00:00
return true ;
}
2013-12-11 00:25:49 +00:00
2017-06-21 01:39:55 +00:00
public void fireRemapEvent ( Map < ResourceLocation , Map < ResourceLocation , Integer [ ] > > remaps , boolean isFreezing )
2013-12-11 00:25:49 +00:00
{
2016-07-19 23:21:52 +00:00
if ( modController ! = null )
{
2017-06-21 01:39:55 +00:00
modController . propogateStateMessage ( new FMLModIdMappingEvent ( remaps , isFreezing ) ) ;
2016-07-19 23:21:52 +00:00
}
2013-12-11 00:25:49 +00:00
}
2013-12-17 15:51:00 +00:00
public void runtimeDisableMod ( String modId )
{
ModContainer mc = namedMods . get ( modId ) ;
Disableable disableable = mc . canBeDisabled ( ) ;
if ( disableable = = Disableable . NEVER )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " Cannot disable mod {} - it is never allowed to be disabled " , modId ) ;
2013-12-17 15:51:00 +00:00
return ;
}
if ( disableable = = Disableable . DEPENDENCIES )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " Cannot disable mod {} - there are dependent mods that require its presence " , modId ) ;
2013-12-17 15:51:00 +00:00
return ;
}
if ( disableable = = Disableable . YES )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " Runtime disabling mod {} " , modId ) ;
2013-12-17 15:51:00 +00:00
modController . disableMod ( mc ) ;
List < ModContainer > localmods = Lists . newArrayList ( mods ) ;
localmods . remove ( mc ) ;
mods = ImmutableList . copyOf ( localmods ) ;
}
try
{
Properties props = new Properties ( ) ;
2018-04-15 00:00:38 +00:00
props . load ( new InputStreamReader ( new FileInputStream ( forcedModFile ) , StandardCharsets . UTF_8 ) ) ;
2013-12-17 15:51:00 +00:00
props . put ( modId , " false " ) ;
2018-04-15 00:00:38 +00:00
props . store ( new OutputStreamWriter ( new FileOutputStream ( forcedModFile ) , StandardCharsets . UTF_8 ) , null ) ;
2013-12-17 15:51:00 +00:00
}
catch ( Exception e )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . info ( " An error occurred writing the fml mod states file, your disabled change won't persist " , e ) ;
2013-12-17 15:51:00 +00:00
}
}
2015-04-24 21:11:49 +00:00
public void loadingComplete ( )
{
ProgressManager . pop ( progressBar ) ;
progressBar = null ;
}
2015-04-25 05:30:17 +00:00
private ListMultimap < String , ArtifactVersion > injectedBefore = ArrayListMultimap . create ( ) ;
private ListMultimap < String , ArtifactVersion > injectedAfter = ArrayListMultimap . create ( ) ;
private void readInjectedDependencies ( )
{
File injectedDepFile = new File ( getConfigDir ( ) , " injectedDependencies.json " ) ;
if ( ! injectedDepFile . exists ( ) )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " File {} not found. No dependencies injected " , injectedDepFile . getAbsolutePath ( ) ) ;
2015-04-25 05:30:17 +00:00
return ;
}
JsonParser parser = new JsonParser ( ) ;
JsonElement injectedDeps ;
try
{
2018-04-15 00:00:38 +00:00
injectedDeps = parser . parse ( new InputStreamReader ( new FileInputStream ( injectedDepFile ) , StandardCharsets . UTF_8 ) ) ;
2015-04-25 05:30:17 +00:00
for ( JsonElement el : injectedDeps . getAsJsonArray ( ) )
{
JsonObject jo = el . getAsJsonObject ( ) ;
String modId = jo . get ( " modId " ) . getAsString ( ) ;
JsonArray deps = jo . get ( " deps " ) . getAsJsonArray ( ) ;
for ( JsonElement dep : deps )
{
JsonObject depObj = dep . getAsJsonObject ( ) ;
String type = depObj . get ( " type " ) . getAsString ( ) ;
if ( type . equals ( " before " ) ) {
injectedBefore . put ( modId , VersionParser . parseVersionReference ( depObj . get ( " target " ) . getAsString ( ) ) ) ;
} else if ( type . equals ( " after " ) ) {
injectedAfter . put ( modId , VersionParser . parseVersionReference ( depObj . get ( " target " ) . getAsString ( ) ) ) ;
} else {
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " Invalid dependency type {} " , type ) ;
2015-04-25 05:30:17 +00:00
throw new RuntimeException ( " Unable to parse type " ) ;
}
}
}
} catch ( Exception e )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " Unable to parse {} - skipping " , injectedDepFile ) ;
FMLLog . log . throwing ( Level . ERROR , e ) ;
2015-04-25 05:30:17 +00:00
return ;
}
2017-06-23 05:33:11 +00:00
FMLLog . log . debug ( " Loaded {} injected dependencies on modIds: {} " , injectedBefore . size ( ) , injectedBefore . keySet ( ) ) ;
2015-04-25 05:30:17 +00:00
}
List < ArtifactVersion > getInjectedBefore ( String modId )
{
return injectedBefore . get ( modId ) ;
}
List < ArtifactVersion > getInjectedAfter ( String modId )
{
return injectedAfter . get ( modId ) ;
}
2015-05-07 18:17:45 +00:00
public final LoaderState getLoaderState ( )
{
return modController ! = null ? modController . getState ( ) : LoaderState . NOINIT ;
}
2016-10-08 23:30:53 +00:00
2017-01-11 23:17:56 +00:00
public void setActiveModContainer ( @Nullable ModContainer container )
2016-10-08 23:30:53 +00:00
{
this . modController . forceActiveContainer ( container ) ;
}
2015-04-29 18:37:09 +00:00
}