Reimplemented cable and parts rendering.
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package appeng.core;
|
||||
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import net.minecraftforge.fml.common.discovery.ASMDataTable;
|
||||
|
||||
import appeng.api.AEInjectable;
|
||||
import appeng.api.AEPlugin;
|
||||
import appeng.api.exceptions.AppEngException;
|
||||
|
||||
|
||||
/**
|
||||
* Loads AE plugins on startup and provides them with access to various components of the AE API.
|
||||
*/
|
||||
class PluginLoader
|
||||
{
|
||||
|
||||
public void loadPlugins( Collection<Object> injectables, ASMDataTable asmDataTable )
|
||||
{
|
||||
Map<Class<?>, Object> injectableMap = mapInjectables( injectables );
|
||||
findAndInstantiatePlugins( asmDataTable, injectableMap );
|
||||
}
|
||||
|
||||
private static void findAndInstantiatePlugins( ASMDataTable dataTable, Map<Class<?>, Object> injectableMap )
|
||||
{
|
||||
Set<ASMDataTable.ASMData> allAnnotated = dataTable.getAll( AEPlugin.class.getCanonicalName() );
|
||||
|
||||
for( ASMDataTable.ASMData candidate : allAnnotated )
|
||||
{
|
||||
|
||||
Class<?> aClass;
|
||||
try
|
||||
{
|
||||
aClass = Class.forName( candidate.getClassName() );
|
||||
}
|
||||
catch( ClassNotFoundException e )
|
||||
{
|
||||
AELog.error( e, "Couldn't find annotated AE plugin class " + candidate.getClassName() );
|
||||
throw new RuntimeException( "Couldn't find annotated AE plugin class " + candidate.getClassName(), e );
|
||||
}
|
||||
|
||||
// Try instantiating the plugin
|
||||
try
|
||||
{
|
||||
Object plugin = instantiatePlugin( aClass, injectableMap );
|
||||
AELog.info( "Loaded AE2 Plugin {}", plugin.getClass() );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
AELog.error( e, "Unable to instantiate AE plugin " + candidate.getClassName() );
|
||||
throw new RuntimeException( "Unable to instantiate AE plugin " + candidate.getClassName(), e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Object instantiatePlugin( Class<?> aClass, Map<Class<?>, Object> injectableMap ) throws Exception
|
||||
{
|
||||
|
||||
Constructor<?>[] constructors = aClass.getDeclaredConstructors();
|
||||
|
||||
if( constructors.length == 0 )
|
||||
{
|
||||
// This is the default no-arg constructor, although it seems pointless to instantiate anything but not take any AE dependencies as parameters
|
||||
return aClass.newInstance();
|
||||
}
|
||||
else if( constructors.length != 1 )
|
||||
{
|
||||
throw new IllegalArgumentException( "Expected a single constructor, but found: " + constructors.length );
|
||||
}
|
||||
|
||||
Constructor<?> constructor = constructors[0];
|
||||
constructor.setAccessible( true );
|
||||
|
||||
Object[] args = findInjectables( constructor, injectableMap );
|
||||
|
||||
return constructor.newInstance( args );
|
||||
}
|
||||
|
||||
private static Object[] findInjectables( Constructor<?> constructor, Map<Class<?>, Object> injectableMap )
|
||||
{
|
||||
|
||||
Class<?>[] types = constructor.getParameterTypes();
|
||||
Object[] args = new Object[types.length];
|
||||
|
||||
for( int i = 0; i < types.length; i++ )
|
||||
{
|
||||
args[i] = injectableMap.get( types[i] );
|
||||
if( args[i] == null )
|
||||
{
|
||||
throw new IllegalArgumentException( "Constructor has parameter of type " + types[i] + " which is not an injectable type."
|
||||
+ " Please see the documentation for @AEPlugin." );
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
private static Map<Class<?>, Object> mapInjectables( Collection<Object> injectables )
|
||||
{
|
||||
ImmutableMap.Builder<Class<?>, Object> builder = ImmutableMap.builder();
|
||||
|
||||
for( Object injectable : injectables )
|
||||
{
|
||||
// Get all super-interfaces that were annotated with @AEInjectable
|
||||
Set<Class<?>> injectableIfs = getInjectableInterfaces( injectable.getClass() );
|
||||
for( Class<?> injectableIf : injectableIfs )
|
||||
{
|
||||
builder.put( injectableIf, injectable );
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static Set<Class<?>> getInjectableInterfaces( Class<?> aClass )
|
||||
{
|
||||
Set<Class<?>> hierarchy = new HashSet<>();
|
||||
getFullHierarchy( aClass, hierarchy );
|
||||
|
||||
return hierarchy.stream()
|
||||
.filter( c -> c.getAnnotation( AEInjectable.class ) != null )
|
||||
.collect( Collectors.toSet() );
|
||||
}
|
||||
|
||||
// Recursively gather all superclasses and superinterfaces of the given class and put them into the given collection
|
||||
private static void getFullHierarchy( Class<?> aClass, Set<Class<?>> classes )
|
||||
{
|
||||
classes.add( aClass );
|
||||
for( Class<?> anIf : aClass.getInterfaces() )
|
||||
{
|
||||
getFullHierarchy( anIf, classes );
|
||||
}
|
||||
if( aClass.getSuperclass() != null )
|
||||
{
|
||||
getFullHierarchy( aClass.getSuperclass(), classes );
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user