2012-07-14 17:58:46 +00:00
package cpw.mods.fml.common ;
2012-07-24 01:20:37 +00:00
import java.util.List ;
2012-07-22 14:26:38 +00:00
import java.util.Map ;
2012-07-23 19:03:17 +00:00
import java.util.Map.Entry ;
2012-07-22 14:26:38 +00:00
import java.util.logging.Level ;
import com.google.common.base.Joiner ;
2012-07-23 19:03:17 +00:00
import com.google.common.collect.ArrayListMultimap ;
2012-08-11 06:43:04 +00:00
import com.google.common.collect.BiMap ;
import com.google.common.collect.ImmutableBiMap ;
2012-07-22 14:26:38 +00:00
import com.google.common.collect.ImmutableMap ;
2012-08-17 13:24:38 +00:00
import com.google.common.collect.ImmutableMap.Builder ;
2012-07-24 01:20:37 +00:00
import com.google.common.collect.Iterables ;
import com.google.common.collect.Lists ;
2012-07-22 14:26:38 +00:00
import com.google.common.collect.Multimap ;
import com.google.common.eventbus.EventBus ;
2012-07-14 17:58:46 +00:00
import com.google.common.eventbus.Subscribe ;
2012-07-22 14:26:38 +00:00
import cpw.mods.fml.common.LoaderState.ModState ;
2012-08-04 15:26:51 +00:00
import cpw.mods.fml.common.event.FMLLoadEvent ;
2012-08-11 06:43:04 +00:00
import cpw.mods.fml.common.event.FMLPreInitializationEvent ;
2012-07-14 17:58:46 +00:00
import cpw.mods.fml.common.event.FMLStateEvent ;
public class LoadController
{
2012-07-22 14:26:38 +00:00
private Loader loader ;
private EventBus masterChannel ;
private ImmutableMap < String , EventBus > eventChannels ;
private LoaderState state ;
2012-07-23 19:03:17 +00:00
private Multimap < String , ModState > modStates = ArrayListMultimap . create ( ) ;
private Multimap < String , Throwable > errors = ArrayListMultimap . create ( ) ;
2012-07-22 14:26:38 +00:00
private Map < String , ModContainer > modList ;
2012-07-24 01:20:37 +00:00
private List < ModContainer > activeModList = Lists . newArrayList ( ) ;
private String activeContainer ;
2012-08-11 06:43:04 +00:00
private BiMap < ModContainer , Object > modObjectList ;
2012-07-30 04:33:21 +00:00
2012-07-22 14:26:38 +00:00
public LoadController ( Loader loader )
{
this . loader = loader ;
this . masterChannel = new EventBus ( " FMLMainChannel " ) ;
this . masterChannel . register ( this ) ;
2012-07-30 04:33:21 +00:00
2012-08-04 15:26:51 +00:00
state = LoaderState . NOINIT ;
2012-08-11 15:44:55 +00:00
2012-08-04 15:26:51 +00:00
}
@Subscribe
public void buildModList ( FMLLoadEvent event )
{
this . modList = loader . getIndexedModList ( ) ;
2012-07-22 14:26:38 +00:00
Builder < String , EventBus > eventBus = ImmutableMap . builder ( ) ;
2012-07-30 04:33:21 +00:00
2012-07-24 01:20:37 +00:00
for ( ModContainer mod : loader . getModList ( ) )
2012-07-22 14:26:38 +00:00
{
EventBus bus = new EventBus ( mod . getModId ( ) ) ;
boolean isActive = mod . registerBus ( bus , this ) ;
if ( isActive )
{
2012-07-23 19:03:17 +00:00
FMLLog . fine ( " Activating mod %s " , mod . getModId ( ) ) ;
2012-07-24 01:20:37 +00:00
activeModList . add ( mod ) ;
2012-07-22 14:26:38 +00:00
modStates . put ( mod . getModId ( ) , ModState . UNLOADED ) ;
eventBus . put ( mod . getModId ( ) , bus ) ;
}
else
{
2012-07-23 19:03:17 +00:00
FMLLog . warning ( " Mod %s has been disabled through configuration " , mod . getModId ( ) ) ;
2012-07-22 14:26:38 +00:00
modStates . put ( mod . getModId ( ) , ModState . UNLOADED ) ;
modStates . put ( mod . getModId ( ) , ModState . DISABLED ) ;
}
}
2012-07-30 04:33:21 +00:00
2012-07-22 14:26:38 +00:00
eventChannels = eventBus . build ( ) ;
}
2012-07-14 17:58:46 +00:00
2012-08-02 04:38:30 +00:00
public void distributeStateMessage ( LoaderState state , Object . . . eventData )
2012-07-22 14:26:38 +00:00
{
if ( state . hasEvent ( ) )
{
masterChannel . post ( state . getEvent ( eventData ) ) ;
}
}
2012-07-30 04:33:21 +00:00
2012-07-23 19:03:17 +00:00
public void transition ( LoaderState desiredState )
2012-07-22 14:26:38 +00:00
{
2012-07-23 19:03:17 +00:00
LoaderState oldState = state ;
2012-07-22 14:26:38 +00:00
state = state . transition ( ! errors . isEmpty ( ) ) ;
2012-07-23 19:03:17 +00:00
if ( state ! = desiredState )
{
FMLLog . severe ( " Fatal errors were detected during the transition from %s to %s. Loading cannot continue " , oldState , desiredState ) ;
StringBuilder sb = new StringBuilder ( ) ;
printModStates ( sb ) ;
FMLLog . severe ( sb . toString ( ) ) ;
FMLLog . severe ( " The following problems were captured during this phase " ) ;
for ( Entry < String , Throwable > error : errors . entries ( ) )
{
FMLLog . log ( Level . SEVERE , error . getValue ( ) , " Caught exception from %s " , error . getKey ( ) ) ;
}
2012-07-30 04:33:21 +00:00
2012-07-24 01:20:37 +00:00
// Throw embedding the first error (usually the only one)
throw new LoaderException ( errors . values ( ) . iterator ( ) . next ( ) ) ;
2012-07-23 19:03:17 +00:00
}
2012-07-22 14:26:38 +00:00
}
2012-07-30 04:33:21 +00:00
2012-07-24 01:20:37 +00:00
public ModContainer activeContainer ( )
{
return activeContainer ! = null ? modList . get ( activeContainer ) : null ;
}
2012-08-11 06:43:04 +00:00
2012-07-14 17:58:46 +00:00
@Subscribe
2012-07-23 19:03:17 +00:00
public void propogateStateMessage ( FMLStateEvent stateEvent )
2012-07-22 14:26:38 +00:00
{
2012-08-11 20:21:03 +00:00
if ( stateEvent instanceof FMLPreInitializationEvent )
{
2012-08-16 00:05:12 +00:00
modObjectList = buildModObjectList ( ) ;
2012-08-11 20:21:03 +00:00
}
2012-07-22 14:26:38 +00:00
for ( Map . Entry < String , EventBus > entry : eventChannels . entrySet ( ) )
{
2012-07-24 01:20:37 +00:00
activeContainer = entry . getKey ( ) ;
2012-07-30 04:33:21 +00:00
stateEvent . applyModContainer ( activeContainer ( ) ) ;
2012-08-04 15:45:40 +00:00
FMLLog . finer ( " Posting state event %s to mod %s " , stateEvent , entry . getKey ( ) ) ;
2012-07-22 14:26:38 +00:00
entry . getValue ( ) . post ( stateEvent ) ;
2012-08-04 15:45:40 +00:00
FMLLog . finer ( " State event %s delivered to mod %s " , stateEvent , entry . getKey ( ) ) ;
2012-07-24 01:20:37 +00:00
activeContainer = null ;
2012-07-23 19:03:17 +00:00
if ( ! errors . containsKey ( entry . getKey ( ) ) )
2012-07-22 14:26:38 +00:00
{
modStates . put ( entry . getKey ( ) , stateEvent . getModState ( ) ) ;
}
else
{
modStates . put ( entry . getKey ( ) , ModState . ERRORED ) ;
}
}
}
2012-08-16 00:05:12 +00:00
public ImmutableBiMap < ModContainer , Object > buildModObjectList ( )
2012-08-11 06:43:04 +00:00
{
2012-08-11 15:44:55 +00:00
ImmutableBiMap . Builder < ModContainer , Object > builder = ImmutableBiMap . < ModContainer , Object > builder ( ) ;
2012-08-11 06:43:04 +00:00
for ( ModContainer mc : activeModList )
{
2012-08-16 00:05:12 +00:00
if ( ! mc . isImmutable ( ) & & mc . getMod ( ) ! = null )
2012-08-11 20:21:03 +00:00
{
builder . put ( mc , mc . getMod ( ) ) ;
}
2012-08-16 17:55:42 +00:00
if ( mc . getMod ( ) = = null & & ! mc . isImmutable ( ) & & state ! = LoaderState . CONSTRUCTING )
2012-08-16 00:05:12 +00:00
{
FMLLog . severe ( " There is a severe problem with %s - it appears not to have constructed correctly " , mc . getModId ( ) ) ;
if ( state ! = LoaderState . CONSTRUCTING )
{
this . errorOccurred ( mc , new RuntimeException ( ) ) ;
}
}
2012-08-11 06:43:04 +00:00
}
2012-08-16 00:05:12 +00:00
return builder . build ( ) ;
2012-08-11 06:43:04 +00:00
}
2012-08-11 15:44:55 +00:00
2012-07-22 14:26:38 +00:00
public void errorOccurred ( ModContainer modContainer , Throwable exception )
2012-07-14 17:58:46 +00:00
{
2012-07-23 19:03:17 +00:00
errors . put ( modContainer . getModId ( ) , exception ) ;
2012-07-22 14:26:38 +00:00
}
public void printModStates ( StringBuilder ret )
{
for ( String modId : modStates . keySet ( ) )
{
ModContainer mod = modList . get ( modId ) ;
ret . append ( " \ n \ t " ) . append ( mod . getName ( ) ) . append ( " ( " ) . append ( mod . getSource ( ) . getName ( ) ) . append ( " ) " ) ;
Joiner . on ( " -> " ) . appendTo ( ret , modStates . get ( modId ) ) ;
}
2012-07-14 17:58:46 +00:00
}
2012-07-24 01:20:37 +00:00
public List < ModContainer > getActiveModList ( )
{
return activeModList ;
}
public ModState getModState ( ModContainer selectedMod )
{
return Iterables . getLast ( modStates . get ( selectedMod . getModId ( ) ) , ModState . AVAILABLE ) ;
}
2012-08-04 15:26:51 +00:00
public void distributeStateMessage ( Class < ? > customEvent )
{
try
{
masterChannel . post ( customEvent . newInstance ( ) ) ;
}
catch ( Exception e )
{
FMLLog . log ( Level . SEVERE , e , " An unexpected exception " ) ;
throw new LoaderException ( e ) ;
}
}
2012-08-11 06:43:04 +00:00
public BiMap < ModContainer , Object > getModObjectList ( )
{
2012-08-16 00:05:12 +00:00
if ( modObjectList = = null )
{
FMLLog . severe ( " Detected an attempt by a mod %s to perform game activity during mod construction. This is a serious programming error. " , activeContainer ) ;
return buildModObjectList ( ) ;
}
2012-08-11 06:43:04 +00:00
return ImmutableBiMap . copyOf ( modObjectList ) ;
}
2012-08-13 19:26:29 +00:00
public boolean isInState ( LoaderState state )
{
return this . state = = state ;
}
2012-07-14 17:58:46 +00:00
}