diff --git a/README.md b/README.md index e8ee9461..3c9aca9e 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ Modify all the things, then do it again! Melt down any metals you find. Turn everything into golems! +##Development +Install Forge as usual, and setup your IDE as with any other Forge project. Forge Multipart must be installed to `forge/mcp/jars/mods/` from the [Forge file server](http://files.minecraftforge.net/ForgeMultipart/). Copy `TCore_dummy.jar` to `forge/mcp/jars/mods/` to enable the Preloader (optional -- only needed when working on the preloader itself) + ##Compile from Source Run [Apache Ant](http://ant.apache.org/bindownload.cgi) in the repository root: `ant package` diff --git a/TCore_dummy.jar b/TCore_dummy.jar new file mode 100644 index 00000000..3a33363d Binary files /dev/null and b/TCore_dummy.jar differ diff --git a/build.xml b/build.xml index dbe52b05..b338b7ba 100644 --- a/build.xml +++ b/build.xml @@ -24,22 +24,26 @@ + + + + @@ -65,6 +69,7 @@ + @@ -78,6 +83,7 @@ + @@ -91,8 +97,8 @@ - + @@ -205,8 +211,9 @@ - - + + + @@ -224,6 +231,7 @@ + @@ -241,7 +249,7 @@ - + diff --git a/resources/PreloaderManifest.mf b/resources/PreloaderManifest.mf new file mode 100644 index 00000000..9318a994 --- /dev/null +++ b/resources/PreloaderManifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +FMLCorePlugin: tconstruct.preloader.TConstructLoaderContainer +FMLCorePluginContainsFMLMod: true diff --git a/resources/mcmod.info b/resources/mcmod.info index 098e0072..5a094e7f 100644 --- a/resources/mcmod.info +++ b/resources/mcmod.info @@ -16,6 +16,23 @@ "parent":"", "dependencies": [] }, + { + "modid": "TConstruct-Preloader", + "name": "Tinkers Corestruct", + "description": "Preloader for Tinkers Construct", + "version": "0.0.1", + "mcversion": "@MCVERSION@", + "url": "https://github.com/mDiyo/TinkersConstruct/tree/master/src/tconstruct/preloader", + "updateUrl": "", + "authors": [ + "AlgorithmX2", "Sunstrike" + ], + "credits": "", + "logoFile": "", + "screenshots": [], + "parent":"", + "dependencies": [] + }, { "modid": "TConstruct|CompatMineFactoryReloaded", "name": "TConstruct Compat: MFR", @@ -34,8 +51,8 @@ "dependencies": [ "TConstruct" ] - } - { + }, + { "modid": "TConstruct|CompatForgeMultiPart", "name": "TConstruct Compat: FMP", "description": "TConstruct support for forgemultipart", diff --git a/src/tconstruct/preloader/ASMInterfaceRepair.java b/src/tconstruct/preloader/ASMInterfaceRepair.java new file mode 100644 index 00000000..8b5cbe72 --- /dev/null +++ b/src/tconstruct/preloader/ASMInterfaceRepair.java @@ -0,0 +1,157 @@ +package tconstruct.preloader; + +/* + * ASMInterfaceRepair is derived from code graciously provided by AlgorithmX2 of Applied Energistics. + * The code was adapted for this loader by Sunstrike. Any queries should be directed to him, not AlgorithmX2. + */ + +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class ASMInterfaceRepair implements IClassTransformer { + + public static Map APIInterfaces = new HashMap(); + + @Override + public byte[] transform(String name, String transformedName, byte[] bytes) + { + if ( name.startsWith( "tconstruct." ) && ! name.startsWith( "tconstruct.preloader" ) ) + { + ClassReader cr = new ClassReader(bytes); + ClassNode cn = new ClassNode(); + cr.accept(cn, 0); + + boolean changed = false; + + if ( this.verifyAPI(cn) ) + changed = true; + + if ( changed ) + { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + cn.accept(cw); + bytes = cw.toByteArray(); + log( "Altering definition of " + transformedName ); + } + } + + return bytes; + } + + private boolean isInternal( String path ) + { + return path.startsWith( "java/" ) + || path.startsWith( "cpw/mods/fml/" ) + || path.startsWith( "tconstruct/" ) + || path.startsWith( "com/google/" ) + || path.startsWith( "net/minecraftforge/" ) + || path.startsWith( "net/minecraft/" ); + } + + private boolean isClassAvailable( String inf ) + { + if ( APIInterfaces.containsKey( inf ) ) + return APIInterfaces.get( inf ); + + boolean isAvailable = false; + Class obj = null; + + try + { + obj = Class.forName( inf.replace( "/", "." ) ); + //obj = ReflectionHelper.getClass( getClass().getClassLoader(), inf.replace( "/", "." ) ); + } + catch ( Throwable _ ) {} + + // java.io.InputStream is = this.getClass().getResourceAsStream( "/" + inf + ".class" ); + APIInterfaces.put( inf, isAvailable = ( obj != null) ); + return isAvailable; + } + + class SigChecker extends SignatureVisitor { + + private ASMInterfaceRepair asmTransformer; + public boolean isAvailable = true; + + public SigChecker(int api, ASMInterfaceRepair t) { + super(api); + asmTransformer = t; + } + + @Override + public void visitInnerClassType(String name) { + visitTypeVariable(name); + } + + @Override + public void visitClassType(String name) { + visitTypeVariable(name); + } + + @Override + public void visitTypeVariable(String className) { + if ( isInternal( className ) ) return; + isAvailable = isAvailable && asmTransformer.isClassAvailable( className ); + log( className + " is " + ( isAvailable ? "available" : "not available" ) ); + } + + } + + private boolean verifyAPI(ClassNode cn) + { + boolean changed = false; + + //log( "Examining " + cn.name ); + + Iterator mn = cn.methods.iterator(); + while ( mn.hasNext() ) + { + MethodNode meth = mn.next(); + + SigChecker sc = new SigChecker(1,this); + ( new SignatureReader(meth.desc) ).accept( sc ); + + boolean isAvailable = sc.isAvailable; + + if ( ! isAvailable ) + { + mn.remove(); + changed = true; + } + } + + Iterator i = cn.interfaces.iterator(); + while ( i.hasNext() ) + { + String inf = i.next(); + + if ( isInternal( inf ) ) + continue; + + boolean isAvailable = isClassAvailable( inf ); + log( inf + " is " + ( isAvailable ? "available" : "not available" ) ); + + if ( ! isAvailable ) + { + i.remove(); + changed = true; + } + } + + return changed; + } + + private void log(String string) { + //TConstructLoaderContainer.logger.info( string ); + } + +} diff --git a/src/tconstruct/preloader/TConstructLoaderContainer.java b/src/tconstruct/preloader/TConstructLoaderContainer.java new file mode 100644 index 00000000..4c66d33c --- /dev/null +++ b/src/tconstruct/preloader/TConstructLoaderContainer.java @@ -0,0 +1,110 @@ +package tconstruct.preloader; + +/* + * TConstructLoaderContainer is derived from code graciously provided by AlgorithmX2 of Applied Energistics. + * The code was adapted for this loader by Sunstrike. Any queries should be directed to him, not AlgorithmX2. + */ + +import com.google.common.eventbus.EventBus; +import cpw.mods.fml.common.DummyModContainer; +import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.LoadController; +import cpw.mods.fml.common.ModMetadata; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.relauncher.IFMLLoadingPlugin; +import net.minecraftforge.event.ForgeSubscribe; + +import java.util.Arrays; +import java.util.Map; +import java.util.logging.Logger; + +public class TConstructLoaderContainer extends DummyModContainer implements IFMLLoadingPlugin { + + private final String[] asmTransformers = new String[]{"tconstruct.preloader.ASMInterfaceRepair"}; + private final ModMetadata md = new ModMetadata(); + + protected static Logger logger = Logger.getLogger("TCon-Preloader"); + + public TConstructLoaderContainer() { + logger.setParent(FMLLog.getLogger()); + logger.info("Scalpel. Suction. Lumber axe. CLEAR! *zap*"); + logger.info("Constructing preloader (Modules: " + Arrays.toString(asmTransformers) + ")"); + md.autogenerated = true; + md.credits = "AlgorithmX2 (original) and Sunstrike (porting)"; + md.modId = getModId(); + md.version = getVersion(); + md.name = getName(); + md.authorList = Arrays.asList("AlgorithmX2", "Sunstrike"); + } + + @ForgeSubscribe + public void preInit(FMLPreInitializationEvent evt) { + + } + + @ForgeSubscribe + public void init(FMLInitializationEvent evt) { + + } + + @ForgeSubscribe + public void postInit(FMLPostInitializationEvent evt) { + + } + + @Override + public String getModId() { + return "TConstruct-Preloader"; + } + + @Override + public String getName() { + return "Tinkers Corestruct"; + } + + @Override + public String getVersion() { + return "0.0.1"; + } + + @Override + public String getDisplayVersion() { + return getVersion(); + } + + @Override + public ModMetadata getMetadata() { + return md; + } + + @Override + public boolean registerBus(EventBus bus, LoadController controller) { + bus.register(this); + return true; + } + + @Override + public String[] getLibraryRequestClass() { + return null; + } + + @Override + public String[] getASMTransformerClass() { + return asmTransformers; + } + + @Override + public String getModContainerClass() { + return "tconstruct.preloader.TConstructLoaderContainer"; + } + + @Override + public String getSetupClass() { + return null; + } + + @Override + public void injectData(Map data) {} +}