Merge branch 'newfmlmod'
This commit is contained in:
commit
2df9ba14d4
|
@ -0,0 +1 @@
|
|||
* text=auto
|
|
@ -8,3 +8,5 @@
|
|||
/eclipse/.metadata/
|
||||
/target
|
||||
fmlbranding.properties
|
||||
/fernflower.zip
|
||||
/commands.py.bck
|
||||
|
|
|
@ -3,6 +3,12 @@ under the GNU LGPL v2.1 or later.
|
|||
|
||||
Homepage: https://github.com/cpw/FML
|
||||
|
||||
This software includes portions from the Apache Maven project at
|
||||
http://maven.apache.org/ specifically the ComparableVersion.java code. It is
|
||||
included based on guidelines at
|
||||
http://www.softwarefreedom.org/resources/2007/gpl-non-gpl-collaboration.html
|
||||
with notices intact. The only change is a non-functional change of package name.
|
||||
|
||||
========
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
|
|
|
@ -1,66 +1,14 @@
|
|||
import sys
|
||||
import os, os.path, shutil
|
||||
import commands
|
||||
import fnmatch
|
||||
import re
|
||||
import subprocess, shlex
|
||||
|
||||
def cmdsplit(args):
|
||||
if os.sep == '\\':
|
||||
args = args.replace('\\', '\\\\')
|
||||
return shlex.split(args)
|
||||
import os, sys
|
||||
|
||||
def main():
|
||||
print("Applying patches")
|
||||
sys.stdout.flush()
|
||||
patches = os.path.abspath(sys.argv[1])
|
||||
work = os.path.normpath(sys.argv[2])
|
||||
mcp = os.path.normpath(sys.argv[3])
|
||||
temp = os.path.abspath('temp.patch')
|
||||
fml_dir = os.path.abspath(sys.argv[1])
|
||||
work_dir = os.path.normpath(sys.argv[2])
|
||||
mcp_dir = os.path.normpath(sys.argv[3])
|
||||
|
||||
cmd = cmdsplit('patch -p2 -i "%s" ' % temp)
|
||||
display = True
|
||||
sys.path.append(os.path.join(fml_dir, 'install'))
|
||||
from fml import apply_fml_patches
|
||||
|
||||
if os.name == 'nt':
|
||||
mcp = os.path.abspath(os.path.join(mcp, 'runtime', 'bin', 'applydiff.exe'))
|
||||
cmd = cmdsplit('"%s" -uf -p2 -i "%s"' % (mcp, temp))
|
||||
display = False
|
||||
|
||||
for path, _, filelist in os.walk(patches, followlinks=True):
|
||||
for cur_file in fnmatch.filter(filelist, '*.patch'):
|
||||
patch_file = os.path.normpath(os.path.join(patches, path[len(patches)+1:], cur_file))
|
||||
if display:
|
||||
print 'patching file %s' % os.path.join(path[len(patches)+1:], cur_file)
|
||||
normaliselines(patch_file, temp)
|
||||
process = subprocess.Popen(cmd, cwd=work, bufsize=-1)
|
||||
process.communicate()
|
||||
|
||||
if os.path.isfile(temp):
|
||||
os.remove(temp)
|
||||
|
||||
#Taken from MCP
|
||||
def normaliselines(in_filename, out_filename=None):
|
||||
in_filename = os.path.normpath(in_filename)
|
||||
if out_filename is None:
|
||||
tmp_filename = in_filename + '.tmp'
|
||||
else:
|
||||
out_filename = os.path.normpath(out_filename)
|
||||
tmp_filename = out_filename
|
||||
dir_name = os.path.dirname(out_filename)
|
||||
if dir_name:
|
||||
if not os.path.exists(dir_name):
|
||||
os.makedirs(dir_name)
|
||||
regex_ending = re.compile(r'\r?\n')
|
||||
with open(in_filename, 'rb') as in_file:
|
||||
with open(tmp_filename, 'wb') as out_file:
|
||||
buf = in_file.read()
|
||||
if os.linesep == '\r\n':
|
||||
buf = regex_ending.sub(r'\r\n', buf)
|
||||
else:
|
||||
buf = buf.replace('\r\n', '\n')
|
||||
out_file.write(buf)
|
||||
if out_filename is None:
|
||||
shutil.move(tmp_filename, in_filename)
|
||||
apply_fml_patches(fml_dir, mcp_dir, work_dir, False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
137
fml/build.xml
137
fml/build.xml
|
@ -29,7 +29,7 @@
|
|||
<arg value="${mcp.home}" />
|
||||
</exec>
|
||||
<propertyfile file="fmlversion.properties">
|
||||
<entry key="fmlbuild.build.number" type="int" value="${version.build}" />
|
||||
<entry key="fmlbuild.build.number" type="int" value="${version.build}"/>
|
||||
</propertyfile>
|
||||
</target>
|
||||
|
||||
|
@ -55,6 +55,10 @@
|
|||
<property name="mcp.srcdir" location="${mcp.home}/src" />
|
||||
<property name="client.mcp.srcdir" location="${mcp.srcdir}/minecraft" />
|
||||
<property name="server.mcp.srcdir" location="${mcp.srcdir}/minecraft_server" />
|
||||
<property name="clean.mcp.srcdir" location="${mcp.home}/src-base" />
|
||||
<property name="patch.mcp.srcdir" location="${mcp.home}/src-work" />
|
||||
<property name="tmp.mcp.srcdir" location="${mcp.home}/src-tmp" />
|
||||
<property name="renamed.mcp.srcdir" location="${mcp.home}/src-renamed" />
|
||||
<property name="common.src.dir" location="${basedir}/common" />
|
||||
<property name="client.src.dir" location="${basedir}/client" />
|
||||
<property name="server.src.dir" location="${basedir}/server" />
|
||||
|
@ -90,23 +94,23 @@
|
|||
<exec executable="${python.exe}" dir="${mcp.home}" failonerror="true">
|
||||
<arg value="${mcp.home}/runtime/recompile.py" />
|
||||
</exec>
|
||||
<fail message="Compilation failed">
|
||||
<condition>
|
||||
<not>
|
||||
<and>
|
||||
<available file="${mcp.home}/bin/minecraft/net/minecraft/client/Minecraft.class" />
|
||||
<available file="${mcp.home}/bin/minecraft_server/net/minecraft/server/MinecraftServer.class" />
|
||||
</and>
|
||||
</not>
|
||||
</condition>
|
||||
</fail>
|
||||
<fail message="Compilation failed">
|
||||
<condition>
|
||||
<not>
|
||||
<and>
|
||||
<available file="${mcp.home}/bin/minecraft/net/minecraft/client/Minecraft.class"/>
|
||||
<available file="${mcp.home}/bin/minecraft_server/net/minecraft/server/MinecraftServer.class"/>
|
||||
</and>
|
||||
</not>
|
||||
</condition>
|
||||
</fail>
|
||||
<exec executable="${python.exe}" dir="${mcp.home}">
|
||||
<arg value="${mcp.home}/runtime/reobfuscate.py" />
|
||||
</exec>
|
||||
<exec executable="${python.exe}" dir="${mcp.home}">
|
||||
<arg value="${basedir}/generatechangedfilelist.py" />
|
||||
<arg value="${mcp.home}" />
|
||||
<arg value="${basedir}/difflist.txt" />
|
||||
<arg value="${basedir}/generatechangedfilelist.py"/>
|
||||
<arg value="${mcp.home}"/>
|
||||
<arg value="${basedir}/difflist.txt"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
|
@ -150,9 +154,9 @@
|
|||
<mkdir dir="${basedir}/target" />
|
||||
<zip destfile="${basedir}/target/${jarname}.zip">
|
||||
<fileset dir="${output}" includes="**/*.class" />
|
||||
<zipfileset dir="${basedir}" includes="fmlversion.properties" />
|
||||
<zipfileset dir="${basedir}" includes="fmlversion.properties"/>
|
||||
<zipfileset dir="${basedir}" includes="LICENSE-fml.txt" />
|
||||
<zipfileset dir="${basedir}" includes="install/CREDITS-fml.txt" fullpath="CREDITS-fml.txt" />
|
||||
<zipfileset dir="${basedir}" includes="install/CREDITS-fml.txt" fullpath="CREDITS-fml.txt"/>
|
||||
<mappedresources>
|
||||
<concat>
|
||||
<fileset dir="${basedir}/install" includes="README.txt" />
|
||||
|
@ -204,11 +208,11 @@
|
|||
<target name="build" depends="buildenvsetup,merge-server,merge-client,build-server,build-client,build-source-pack" />
|
||||
|
||||
<target name="jenkinsbuild" depends="buildenvsetup,patch,build"/>
|
||||
|
||||
|
||||
<target name="patch" depends="buildenvsetup">
|
||||
<exec executable="${python.exe}" dir="${basedir}">
|
||||
<arg value="${basedir}/applypatches.py" />
|
||||
<arg value="${patch.src.dir}" />
|
||||
<arg value="${basedir}" />
|
||||
<arg value="${mcp.srcdir}" />
|
||||
<arg value="${mcp.home}" />
|
||||
</exec>
|
||||
|
@ -222,63 +226,104 @@
|
|||
</condition>
|
||||
<fail if="do.not.continue">You have decided not to continue. This script will stop now.</fail>
|
||||
<echo>Preparing the MCP environment at ${mcp.home}</echo>
|
||||
<exec executable="${python.exe}" dir="${basedir}">
|
||||
<!--<exec executable="${python.exe}" dir="${basedir}">
|
||||
<arg value="${basedir}/download_fernflower.py" />
|
||||
<arg value="${mcp.home}"/>
|
||||
</exec>
|
||||
</exec>-->
|
||||
<exec executable="${python.exe}" dir="${mcp.home}">
|
||||
<arg value="${mcp.home}/runtime/cleanup.py" />
|
||||
<arg value="-f" />
|
||||
</exec>
|
||||
<exec executable="${python.exe}" dir="${mcp.home}">
|
||||
<arg value="${mcp.home}/runtime/decompile.py" />
|
||||
<arg value="-d" />
|
||||
<arg value="-n" />
|
||||
<arg value="-r" />
|
||||
<exec executable="${python.exe}" dir="${basedir}">
|
||||
<arg value="${basedir}/decompile.py" />
|
||||
<arg value="${mcp.home}" />
|
||||
<arg value="${basedir}" />
|
||||
</exec>
|
||||
<exec executable="${python.exe}" dir="${mcp.home}">
|
||||
<!--<exec executable="${python.exe}" dir="${mcp.home}">
|
||||
<arg value="${basedir}/cleanup_source.py" />
|
||||
<arg value="${mcp.srcdir}" />
|
||||
</exec>-->
|
||||
<!--<exec executable="${python.exe}" dir="${mcp.home}">
|
||||
<arg value="${mcp.home}/runtime/updatemd5.py" />
|
||||
<arg value="-f" />
|
||||
</exec>
|
||||
<echo>Moving old patched sources at ${mcp.home}/src-work out of the way</echo>
|
||||
</exec>-->
|
||||
<echo>Moving old patched sources at ${patch.mcp.srcdir} out of the way</echo>
|
||||
<move todir="${mcp.home}/src-work${timestamp}" failonerror="false" verbose="true">
|
||||
<fileset dir="${mcp.home}/src-work"/>
|
||||
<fileset dir="${patch.mcp.srcdir}"/>
|
||||
</move>
|
||||
<echo>Deleting old patch references at ${mcp.home}/src-base</echo>
|
||||
<delete dir="${mcp.home}/src-base" failonerror="false"/>
|
||||
<echo>Creating new patch references at ${mcp.home}/src-base</echo>
|
||||
<copy todir="${mcp.home}/src-base">
|
||||
<fileset dir="${mcp.home}/src"/>
|
||||
<echo>Deleting old patch references at ${clean.mcp.srcdir}</echo>
|
||||
<delete dir="${clean.mcp.srcdir}" failonerror="false"/>
|
||||
<echo>Creating new patch references at ${clean.mcp.srcdir}</echo>
|
||||
<copy todir="${clean.mcp.srcdir}">
|
||||
<fileset dir="${mcp.srcdir}"/>
|
||||
</copy>
|
||||
<antcall target="cleanargo"/>
|
||||
<antcall target="patch"/>
|
||||
<echo>Creating clean patched references at ${mcp.home}/src-work</echo>
|
||||
<copy todir="${mcp.home}/src-work">
|
||||
<fileset dir="${mcp.home}/src"/>
|
||||
<echo>Creating clean patched references at ${patch.mcp.srcdir}</echo>
|
||||
<copy todir="${patch.mcp.srcdir}">
|
||||
<fileset dir="${mcp.srcdir}"/>
|
||||
</copy>
|
||||
<antcall target="writeversion"/>
|
||||
<echo>Setup complete! You should now be able to open ${basedir}/eclipse as a workspace in eclipse and import/refresh the FML-Server and FML-Client projects</echo>
|
||||
</target>
|
||||
|
||||
<target name="repatch" depends="buildenvsetup">
|
||||
<target name="repatch" depends="buildenvsetup,checkpatches">
|
||||
<echo>Moving old patched sources at ${mcp.home}/src-work out of the way</echo>
|
||||
<move todir="${mcp.home}/src-work${timestamp}" failonerror="false" verbose="true">
|
||||
<fileset dir="${mcp.home}/src-work"/>
|
||||
<fileset dir="${patch.mcp.srcdir}"/>
|
||||
</move>
|
||||
<delete dir="${mcp.home}/src"/>
|
||||
<copy todir="${mcp.home}/src">
|
||||
<fileset dir="${mcp.home}/src-base"/>
|
||||
<delete dir="${mcp.srcdir}"/>
|
||||
<copy todir="${mcp.srcdir}">
|
||||
<fileset dir="${clean.mcp.srcdir}"/>
|
||||
</copy>
|
||||
|
||||
<antcall target="cleanargo"/>
|
||||
|
||||
<antcall target="patch"/>
|
||||
<copy todir="${mcp.home}/src-work">
|
||||
<fileset dir="${mcp.home}/src"/>
|
||||
<copy todir="${patch.mcp.srcdir}">
|
||||
<fileset dir="${mcp.srcdir}"/>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
|
||||
<target name="cleanargo" depends="buildenvsetup">
|
||||
<delete dir="${client.mcp.srcdir}/argo"/>
|
||||
</target>
|
||||
|
||||
<target name="checkpatches" depends="buildenvsetup">
|
||||
<uptodate property="checkUptodate.uptodate">
|
||||
<srcfiles dir="${patch.mcp.srcdir}" includes="**/*.java">
|
||||
<present targetdir="${patch.src.dir}">
|
||||
<globmapper from="*.java" to="*.java.patch"/>
|
||||
</present>
|
||||
</srcfiles>
|
||||
<globmapper from="*.java" to="${patch.src.dir}/*.java.patch"/>
|
||||
</uptodate>
|
||||
<fail unless="checkUptodate.uptodate">
|
||||
A patch is out of date. Update your patches!
|
||||
</fail>
|
||||
</target>
|
||||
|
||||
<target name="updatepatches" depends="buildenvsetup">
|
||||
<exec executable="${python.exe}" dir="${basedir}">
|
||||
<arg value="${basedir}/update_patches.py" />
|
||||
<arg value="${mcp.home}"/>
|
||||
<arg value="${basedir}/patches"/>
|
||||
<arg value="${basedir}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="makerenamedsource" depends="buildenvsetup,repatch,merge-client,merge-server,buildandreobfmcp">
|
||||
<copy todir="${tmp.mcp.srcdir}">
|
||||
<fileset dir="${mcp.srcdir}"/>
|
||||
</copy>
|
||||
<exec executable="${python.exe}" dir="${mcp.home}">
|
||||
<arg value="${mcp.home}/runtime/updatenames.py" />
|
||||
<arg value="-f" />
|
||||
</exec>
|
||||
<copy todir="${renamed.mcp.srcdir}">
|
||||
<fileset dir="${mcp.srcdir}"/>
|
||||
</copy>
|
||||
<move todir="${mcp.srcdir}">
|
||||
<fileset dir="${tmp.mcp.srcdir}"/>
|
||||
</move>
|
||||
</target>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
package cpw.mods.fml.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import cpw.mods.fml.common.modloader.ModLoaderHelper;
|
||||
import cpw.mods.fml.common.modloader.ModLoaderModContainer;
|
||||
|
||||
import net.minecraft.src.BaseMod;
|
||||
import net.minecraft.src.Block;
|
||||
import net.minecraft.src.IBlockAccess;
|
||||
import net.minecraft.src.RenderBlocks;
|
||||
|
||||
public class BlockRenderManager
|
||||
{
|
||||
private static final BlockRenderManager INSTANCE = new BlockRenderManager();
|
||||
|
||||
private HashMap<Integer, BlockRenderInfo> blockModelIds = new HashMap<Integer, BlockRenderInfo>();
|
||||
|
||||
private int nextRenderId = 30;
|
||||
|
||||
public static BlockRenderManager instance()
|
||||
{
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param renderer
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param block
|
||||
* @param modelId
|
||||
* @return
|
||||
*/
|
||||
public boolean renderWorldBlock(RenderBlocks renderer, IBlockAccess world, int x, int y, int z, Block block, int modelId)
|
||||
{
|
||||
if (!blockModelIds.containsKey(modelId)) { return false; }
|
||||
BlockRenderInfo bri = blockModelIds.get(modelId);
|
||||
return bri.renderWorldBlock(world, x, y, z, block, modelId, renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param renderer
|
||||
* @param block
|
||||
* @param metadata
|
||||
* @param modelID
|
||||
*/
|
||||
public void renderInventoryBlock(RenderBlocks renderer, Block block, int metadata, int modelID)
|
||||
{
|
||||
if (!blockModelIds.containsKey(modelID)) { return; }
|
||||
BlockRenderInfo bri = blockModelIds.get(modelID);
|
||||
bri.renderInventoryBlock(block, metadata, modelID, renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param p_1219_0_
|
||||
* @return
|
||||
*/
|
||||
public boolean renderItemAsFull3DBlock(int modelId)
|
||||
{
|
||||
BlockRenderInfo bri = blockModelIds.get(modelId);
|
||||
if (bri != null) { return bri.shouldRender3DInInventory(); }
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mod
|
||||
* @param inventoryRenderer
|
||||
* @return
|
||||
*/
|
||||
public int obtainBlockModelIdFor(BaseMod mod, boolean inventoryRenderer)
|
||||
{
|
||||
ModLoaderModContainer mlmc=ModLoaderHelper.registerRenderHelper(mod);
|
||||
int renderId=nextRenderId++;
|
||||
BlockRenderInfo bri=new BlockRenderInfo(renderId, inventoryRenderer, mlmc);
|
||||
blockModelIds.put(renderId, bri);
|
||||
return renderId;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -32,20 +32,20 @@ public class FMLTextureFX extends TextureFX implements ITextureFX
|
|||
public int tileSizeSquareMask = 255;
|
||||
public boolean errored = false;
|
||||
protected Logger log = FMLCommonHandler.instance().getFMLLogger();
|
||||
|
||||
|
||||
public FMLTextureFX(int icon)
|
||||
{
|
||||
super(icon);
|
||||
}
|
||||
|
||||
|
||||
@Override public void setErrored(boolean err){ errored = err; }
|
||||
@Override public boolean getErrored(){ return errored; }
|
||||
@Override
|
||||
@Override
|
||||
public void onTexturePackChanged(RenderEngine engine, TexturePackBase texturepack, Dimension dimensions)
|
||||
{
|
||||
onTextureDimensionsUpdate(dimensions.width, dimensions.height);
|
||||
}
|
||||
@Override
|
||||
@Override
|
||||
public void onTextureDimensionsUpdate(int width, int height)
|
||||
{
|
||||
tileSizeBase = width >> 4;
|
||||
|
@ -58,9 +58,9 @@ public class FMLTextureFX extends TextureFX implements ITextureFX
|
|||
|
||||
protected void setup()
|
||||
{
|
||||
field_1127_a = new byte[tileSizeSquare << 2];
|
||||
field_76852_a = new byte[tileSizeSquare << 2];
|
||||
}
|
||||
|
||||
|
||||
public boolean unregister(RenderEngine engine, List<TextureFX> effects)
|
||||
{
|
||||
effects.remove(this);
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.Map;
|
|||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import cpw.mods.fml.common.FMLModContainer;
|
||||
import cpw.mods.fml.common.FMLModLoaderContainer;
|
||||
import cpw.mods.fml.common.FMLDummyContainer;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
@ -39,7 +39,6 @@ import net.minecraft.src.Tessellator;
|
|||
*/
|
||||
public class GuiModList extends GuiScreen
|
||||
{
|
||||
|
||||
private GuiScreen mainMenu;
|
||||
private GuiSlotModList modList;
|
||||
private int selected = -1;
|
||||
|
@ -55,98 +54,104 @@ public class GuiModList extends GuiScreen
|
|||
this.mainMenu=mainMenu;
|
||||
this.mods=new ArrayList<ModContainer>();
|
||||
FMLClientHandler.instance().addSpecialModEntries(mods);
|
||||
for (ModContainer mod : Loader.getModList()) {
|
||||
for (ModContainer mod : Loader.instance().getModList()) {
|
||||
if (mod.getMetadata()!=null && mod.getMetadata().parentMod != null) {
|
||||
continue;
|
||||
}
|
||||
mods.add(mod);
|
||||
}
|
||||
}
|
||||
|
||||
public void func_6448_a()
|
||||
|
||||
@Override
|
||||
public void func_73866_w_()
|
||||
{
|
||||
for (ModContainer mod : mods) {
|
||||
listWidth=Math.max(listWidth,getFontRenderer().func_871_a(mod.getName()) + 10);
|
||||
listWidth=Math.max(listWidth,getFontRenderer().func_871_a(mod.getVersion()) + 10);
|
||||
listWidth=Math.max(listWidth,getFontRenderer().func_78256_a(mod.getName()) + 10);
|
||||
listWidth=Math.max(listWidth,getFontRenderer().func_78256_a(mod.getVersion()) + 10);
|
||||
}
|
||||
listWidth=Math.min(listWidth, 150);
|
||||
StringTranslate translations = StringTranslate.func_20162_a();
|
||||
this.field_949_e.add(new GuiSmallButton(6, this.field_951_c / 2 - 75, this.field_950_d - 38, translations.func_20163_a("gui.done")));
|
||||
StringTranslate translations = StringTranslate.func_74808_a();
|
||||
this.field_73887_h.add(new GuiSmallButton(6, this.field_73880_f / 2 - 75, this.field_73881_g - 38, translations.func_74805_b("gui.done")));
|
||||
this.modList=new GuiSlotModList(this, mods, listWidth);
|
||||
this.modList.registerScrollButtons(this.field_949_e, 7, 8);
|
||||
this.modList.registerScrollButtons(this.field_73887_h, 7, 8);
|
||||
}
|
||||
|
||||
protected void func_572_a(GuiButton button) {
|
||||
if (button.field_937_g)
|
||||
@Override
|
||||
protected void func_73875_a(GuiButton button) {
|
||||
if (button.field_73742_g)
|
||||
{
|
||||
switch (button.field_938_f)
|
||||
switch (button.field_73741_f)
|
||||
{
|
||||
case 6:
|
||||
this.field_945_b.func_6272_a(this.mainMenu);
|
||||
this.field_73882_e.func_71373_a(this.mainMenu);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.func_572_a(button);
|
||||
super.func_73875_a(button);
|
||||
}
|
||||
|
||||
public int drawLine(String line, int offset, int shifty)
|
||||
{
|
||||
this.field_6451_g.func_873_b(line, offset, shifty, 0xd7edea);
|
||||
this.field_73886_k.func_78276_b(line, offset, shifty, 0xd7edea);
|
||||
return shifty + 10;
|
||||
}
|
||||
public void func_571_a(int p_571_1_, int p_571_2_, float p_571_3_)
|
||||
|
||||
@Override
|
||||
public void func_73863_a(int p_571_1_, int p_571_2_, float p_571_3_)
|
||||
{
|
||||
this.modList.drawScreen(p_571_1_, p_571_2_, p_571_3_);
|
||||
this.func_548_a(this.field_6451_g, "Mod List", this.field_951_c / 2, 16, 0xFFFFFF);
|
||||
this.func_73732_a(this.field_73886_k, "Mod List", this.field_73880_f / 2, 16, 0xFFFFFF);
|
||||
int offset = this.listWidth + 20;
|
||||
if (selectedMod != null) {
|
||||
if (selectedMod.getMetadata() != null) {
|
||||
if (!selectedMod.getMetadata().autogenerated) {
|
||||
int shifty = 35;
|
||||
if (!selectedMod.getMetadata().logoFile.isEmpty())
|
||||
{
|
||||
int texture = this.field_945_b.field_6315_n.func_1070_a(selectedMod.getMetadata().logoFile);
|
||||
int texture = this.field_73882_e.field_71446_o.func_78341_b(selectedMod.getMetadata().logoFile);
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
this.field_945_b.field_6315_n.func_1076_b(texture);
|
||||
Dimension dim = FMLClientHandler.instance().getTextureDimensions(texture);
|
||||
this.field_73882_e.field_71446_o.func_78342_b(texture);
|
||||
Dimension dim = TextureFXManager.instance().getTextureDimensions(texture);
|
||||
int top = 32;
|
||||
Tessellator tess = Tessellator.field_1512_a;
|
||||
tess.func_977_b();
|
||||
tess.func_983_a(offset, top + dim.height, field_923_k, 0, 1);
|
||||
tess.func_983_a(offset + dim.width, top + dim.height, field_923_k, 1, 1);
|
||||
tess.func_983_a(offset + dim.width, top, field_923_k, 1, 0);
|
||||
tess.func_983_a(offset, top, field_923_k, 0, 0);
|
||||
tess.func_982_a();
|
||||
|
||||
Tessellator tess = Tessellator.field_78398_a;
|
||||
tess.func_78382_b();
|
||||
tess.func_78374_a(offset, top + dim.height, field_73735_i, 0, 1);
|
||||
tess.func_78374_a(offset + dim.width, top + dim.height, field_73735_i, 1, 1);
|
||||
tess.func_78374_a(offset + dim.width, top, field_73735_i, 1, 0);
|
||||
tess.func_78374_a(offset, top, field_73735_i, 0, 0);
|
||||
tess.func_78381_a();
|
||||
|
||||
shifty += 65;
|
||||
}
|
||||
this.field_6451_g.func_50103_a(selectedMod.getMetadata().name, offset, shifty, 0xFFFFFF);
|
||||
this.field_73886_k.func_78261_a(selectedMod.getMetadata().name, offset, shifty, 0xFFFFFF);
|
||||
shifty += 12;
|
||||
|
||||
|
||||
shifty = drawLine(String.format("Version: %s (%s)", selectedMod.getMetadata().version, selectedMod.getVersion()), offset, shifty);
|
||||
shifty = drawLine(String.format("Mod State: %s", Loader.instance().getModState(selectedMod)), offset, shifty);
|
||||
if (!selectedMod.getMetadata().credits.isEmpty()) {
|
||||
shifty = drawLine(String.format("Credits: %s", selectedMod.getMetadata().credits), offset, shifty);
|
||||
}
|
||||
shifty = drawLine(String.format("Authors: %s", selectedMod.getMetadata().getAuthorList()), offset, shifty);
|
||||
shifty = drawLine(String.format("URL: %s", selectedMod.getMetadata().url), offset, shifty);
|
||||
shifty = drawLine(selectedMod.getMetadata().childMods.isEmpty() ? "No child mods for this mod" : String.format("Child mods: %s", selectedMod.getMetadata().getChildModList()), offset, shifty);
|
||||
this.getFontRenderer().func_27278_a(selectedMod.getMetadata().description, offset, shifty + 10, this.field_951_c - offset - 20, 0xDDDDDD);
|
||||
this.getFontRenderer().func_78279_b(selectedMod.getMetadata().description, offset, shifty + 10, this.field_73880_f - offset - 20, 0xDDDDDD);
|
||||
} else {
|
||||
offset = ( this.listWidth + this.field_951_c ) / 2;
|
||||
this.func_548_a(this.field_6451_g, selectedMod.getName(), offset, 35, 0xFFFFFF);
|
||||
this.func_548_a(this.field_6451_g, String.format("Version: %s",selectedMod.getVersion()), offset, 45, 0xFFFFFF);
|
||||
this.func_548_a(this.field_6451_g, "No mod information found", offset, 55, 0xDDDDDD);
|
||||
this.func_548_a(this.field_6451_g, "Ask your mod author to provide a mod .info file", offset, 65, 0xDDDDDD);
|
||||
offset = ( this.listWidth + this.field_73880_f ) / 2;
|
||||
this.func_73732_a(this.field_73886_k, selectedMod.getName(), offset, 35, 0xFFFFFF);
|
||||
this.func_73732_a(this.field_73886_k, String.format("Version: %s",selectedMod.getVersion()), offset, 45, 0xFFFFFF);
|
||||
this.func_73732_a(this.field_73886_k, String.format("Mod State: %s",Loader.instance().getModState(selectedMod)), offset, 55, 0xFFFFFF);
|
||||
this.func_73732_a(this.field_73886_k, "No mod information found", offset, 65, 0xDDDDDD);
|
||||
this.func_73732_a(this.field_73886_k, "Ask your mod author to provide a mod mcmod.info file", offset, 75, 0xDDDDDD);
|
||||
}
|
||||
}
|
||||
super.func_571_a(p_571_1_, p_571_2_, p_571_3_);
|
||||
super.func_73863_a(p_571_1_, p_571_2_, p_571_3_);
|
||||
}
|
||||
|
||||
Minecraft getMinecraftInstance() {
|
||||
return field_945_b;
|
||||
return field_73882_e;
|
||||
}
|
||||
|
||||
|
||||
FontRenderer getFontRenderer() {
|
||||
return field_6451_g;
|
||||
return field_73886_k;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -117,15 +117,15 @@ public abstract class GuiScrollingList
|
|||
|
||||
public void actionPerformed(GuiButton button)
|
||||
{
|
||||
if (button.field_937_g)
|
||||
if (button.field_73742_g)
|
||||
{
|
||||
if (button.field_938_f == this.scrollUpActionId)
|
||||
if (button.field_73741_f == this.scrollUpActionId)
|
||||
{
|
||||
this.scrollDistance -= (float)(this.slotHeight * 2 / 3);
|
||||
this.initialMouseClickY = -2.0F;
|
||||
this.applyScrollLimits();
|
||||
}
|
||||
else if (button.field_938_f == this.scrollDownActionId)
|
||||
else if (button.field_73741_f == this.scrollDownActionId)
|
||||
{
|
||||
this.scrollDistance += (float)(this.slotHeight * 2 / 3);
|
||||
this.initialMouseClickY = -2.0F;
|
||||
|
@ -249,17 +249,17 @@ public abstract class GuiScrollingList
|
|||
this.applyScrollLimits();
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glDisable(GL11.GL_FOG);
|
||||
Tessellator var18 = Tessellator.field_1512_a;
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.client.field_6315_n.func_1070_a("/gui/background.png"));
|
||||
Tessellator var18 = Tessellator.field_78398_a;
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.client.field_71446_o.func_78341_b("/gui/background.png"));
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
float var17 = 32.0F;
|
||||
var18.func_977_b();
|
||||
var18.func_990_b(2105376);
|
||||
var18.func_983_a((double)this.left, (double)this.bottom, 0.0D, (double)((float)this.left / var17), (double)((float)(this.bottom + (int)this.scrollDistance) / var17));
|
||||
var18.func_983_a((double)this.right, (double)this.bottom, 0.0D, (double)((float)this.right / var17), (double)((float)(this.bottom + (int)this.scrollDistance) / var17));
|
||||
var18.func_983_a((double)this.right, (double)this.top, 0.0D, (double)((float)this.right / var17), (double)((float)(this.top + (int)this.scrollDistance) / var17));
|
||||
var18.func_983_a((double)this.left, (double)this.top, 0.0D, (double)((float)this.left / var17), (double)((float)(this.top + (int)this.scrollDistance) / var17));
|
||||
var18.func_982_a();
|
||||
var18.func_78382_b();
|
||||
var18.func_78378_d(2105376);
|
||||
var18.func_78374_a((double)this.left, (double)this.bottom, 0.0D, (double)((float)this.left / var17), (double)((float)(this.bottom + (int)this.scrollDistance) / var17));
|
||||
var18.func_78374_a((double)this.right, (double)this.bottom, 0.0D, (double)((float)this.right / var17), (double)((float)(this.bottom + (int)this.scrollDistance) / var17));
|
||||
var18.func_78374_a((double)this.right, (double)this.top, 0.0D, (double)((float)this.right / var17), (double)((float)(this.top + (int)this.scrollDistance) / var17));
|
||||
var18.func_78374_a((double)this.left, (double)this.top, 0.0D, (double)((float)this.left / var17), (double)((float)(this.top + (int)this.scrollDistance) / var17));
|
||||
var18.func_78381_a();
|
||||
// boxRight = this.listWidth / 2 - 92 - 16;
|
||||
var10 = this.top + 4 - (int)this.scrollDistance;
|
||||
|
||||
|
@ -283,18 +283,18 @@ public abstract class GuiScrollingList
|
|||
int var15 = boxRight;
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
var18.func_977_b();
|
||||
var18.func_990_b(8421504);
|
||||
var18.func_983_a((double)var14, (double)(var19 + var13 + 2), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_983_a((double)var15, (double)(var19 + var13 + 2), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_983_a((double)var15, (double)(var19 - 2), 0.0D, 1.0D, 0.0D);
|
||||
var18.func_983_a((double)var14, (double)(var19 - 2), 0.0D, 0.0D, 0.0D);
|
||||
var18.func_990_b(0);
|
||||
var18.func_983_a((double)(var14 + 1), (double)(var19 + var13 + 1), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_983_a((double)(var15 - 1), (double)(var19 + var13 + 1), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_983_a((double)(var15 - 1), (double)(var19 - 1), 0.0D, 1.0D, 0.0D);
|
||||
var18.func_983_a((double)(var14 + 1), (double)(var19 - 1), 0.0D, 0.0D, 0.0D);
|
||||
var18.func_982_a();
|
||||
var18.func_78382_b();
|
||||
var18.func_78378_d(8421504);
|
||||
var18.func_78374_a((double)var14, (double)(var19 + var13 + 2), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_78374_a((double)var15, (double)(var19 + var13 + 2), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_78374_a((double)var15, (double)(var19 - 2), 0.0D, 1.0D, 0.0D);
|
||||
var18.func_78374_a((double)var14, (double)(var19 - 2), 0.0D, 0.0D, 0.0D);
|
||||
var18.func_78378_d(0);
|
||||
var18.func_78374_a((double)(var14 + 1), (double)(var19 + var13 + 1), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_78374_a((double)(var15 - 1), (double)(var19 + var13 + 1), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_78374_a((double)(var15 - 1), (double)(var19 - 1), 0.0D, 1.0D, 0.0D);
|
||||
var18.func_78374_a((double)(var14 + 1), (double)(var19 - 1), 0.0D, 0.0D, 0.0D);
|
||||
var18.func_78381_a();
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
@ -311,22 +311,22 @@ public abstract class GuiScrollingList
|
|||
GL11.glDisable(GL11.GL_ALPHA_TEST);
|
||||
GL11.glShadeModel(GL11.GL_SMOOTH);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
var18.func_977_b();
|
||||
var18.func_6513_a(0, 0);
|
||||
var18.func_983_a((double)this.left, (double)(this.top + var20), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_983_a((double)this.right, (double)(this.top + var20), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_6513_a(0, 255);
|
||||
var18.func_983_a((double)this.right, (double)this.top, 0.0D, 1.0D, 0.0D);
|
||||
var18.func_983_a((double)this.left, (double)this.top, 0.0D, 0.0D, 0.0D);
|
||||
var18.func_982_a();
|
||||
var18.func_977_b();
|
||||
var18.func_6513_a(0, 255);
|
||||
var18.func_983_a((double)this.left, (double)this.bottom, 0.0D, 0.0D, 1.0D);
|
||||
var18.func_983_a((double)this.right, (double)this.bottom, 0.0D, 1.0D, 1.0D);
|
||||
var18.func_6513_a(0, 0);
|
||||
var18.func_983_a((double)this.right, (double)(this.bottom - var20), 0.0D, 1.0D, 0.0D);
|
||||
var18.func_983_a((double)this.left, (double)(this.bottom - var20), 0.0D, 0.0D, 0.0D);
|
||||
var18.func_982_a();
|
||||
var18.func_78382_b();
|
||||
var18.func_78384_a(0, 0);
|
||||
var18.func_78374_a((double)this.left, (double)(this.top + var20), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_78374_a((double)this.right, (double)(this.top + var20), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_78384_a(0, 255);
|
||||
var18.func_78374_a((double)this.right, (double)this.top, 0.0D, 1.0D, 0.0D);
|
||||
var18.func_78374_a((double)this.left, (double)this.top, 0.0D, 0.0D, 0.0D);
|
||||
var18.func_78381_a();
|
||||
var18.func_78382_b();
|
||||
var18.func_78384_a(0, 255);
|
||||
var18.func_78374_a((double)this.left, (double)this.bottom, 0.0D, 0.0D, 1.0D);
|
||||
var18.func_78374_a((double)this.right, (double)this.bottom, 0.0D, 1.0D, 1.0D);
|
||||
var18.func_78384_a(0, 0);
|
||||
var18.func_78374_a((double)this.right, (double)(this.bottom - var20), 0.0D, 1.0D, 0.0D);
|
||||
var18.func_78374_a((double)this.left, (double)(this.bottom - var20), 0.0D, 0.0D, 0.0D);
|
||||
var18.func_78381_a();
|
||||
var19 = this.getContentHeight() - (this.bottom - this.top - 4);
|
||||
|
||||
if (var19 > 0)
|
||||
|
@ -350,27 +350,27 @@ public abstract class GuiScrollingList
|
|||
var14 = this.top;
|
||||
}
|
||||
|
||||
var18.func_977_b();
|
||||
var18.func_6513_a(0, 255);
|
||||
var18.func_983_a((double)scrollBarXStart, (double)this.bottom, 0.0D, 0.0D, 1.0D);
|
||||
var18.func_983_a((double)scrollBarXEnd, (double)this.bottom, 0.0D, 1.0D, 1.0D);
|
||||
var18.func_983_a((double)scrollBarXEnd, (double)this.top, 0.0D, 1.0D, 0.0D);
|
||||
var18.func_983_a((double)scrollBarXStart, (double)this.top, 0.0D, 0.0D, 0.0D);
|
||||
var18.func_982_a();
|
||||
var18.func_977_b();
|
||||
var18.func_6513_a(8421504, 255);
|
||||
var18.func_983_a((double)scrollBarXStart, (double)(var14 + var13), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_983_a((double)scrollBarXEnd, (double)(var14 + var13), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_983_a((double)scrollBarXEnd, (double)var14, 0.0D, 1.0D, 0.0D);
|
||||
var18.func_983_a((double)scrollBarXStart, (double)var14, 0.0D, 0.0D, 0.0D);
|
||||
var18.func_982_a();
|
||||
var18.func_977_b();
|
||||
var18.func_6513_a(12632256, 255);
|
||||
var18.func_983_a((double)scrollBarXStart, (double)(var14 + var13 - 1), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_983_a((double)(scrollBarXEnd - 1), (double)(var14 + var13 - 1), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_983_a((double)(scrollBarXEnd - 1), (double)var14, 0.0D, 1.0D, 0.0D);
|
||||
var18.func_983_a((double)scrollBarXStart, (double)var14, 0.0D, 0.0D, 0.0D);
|
||||
var18.func_982_a();
|
||||
var18.func_78382_b();
|
||||
var18.func_78384_a(0, 255);
|
||||
var18.func_78374_a((double)scrollBarXStart, (double)this.bottom, 0.0D, 0.0D, 1.0D);
|
||||
var18.func_78374_a((double)scrollBarXEnd, (double)this.bottom, 0.0D, 1.0D, 1.0D);
|
||||
var18.func_78374_a((double)scrollBarXEnd, (double)this.top, 0.0D, 1.0D, 0.0D);
|
||||
var18.func_78374_a((double)scrollBarXStart, (double)this.top, 0.0D, 0.0D, 0.0D);
|
||||
var18.func_78381_a();
|
||||
var18.func_78382_b();
|
||||
var18.func_78384_a(8421504, 255);
|
||||
var18.func_78374_a((double)scrollBarXStart, (double)(var14 + var13), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_78374_a((double)scrollBarXEnd, (double)(var14 + var13), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_78374_a((double)scrollBarXEnd, (double)var14, 0.0D, 1.0D, 0.0D);
|
||||
var18.func_78374_a((double)scrollBarXStart, (double)var14, 0.0D, 0.0D, 0.0D);
|
||||
var18.func_78381_a();
|
||||
var18.func_78382_b();
|
||||
var18.func_78384_a(12632256, 255);
|
||||
var18.func_78374_a((double)scrollBarXStart, (double)(var14 + var13 - 1), 0.0D, 0.0D, 1.0D);
|
||||
var18.func_78374_a((double)(scrollBarXEnd - 1), (double)(var14 + var13 - 1), 0.0D, 1.0D, 1.0D);
|
||||
var18.func_78374_a((double)(scrollBarXEnd - 1), (double)var14, 0.0D, 1.0D, 0.0D);
|
||||
var18.func_78374_a((double)scrollBarXStart, (double)var14, 0.0D, 0.0D, 0.0D);
|
||||
var18.func_78381_a();
|
||||
}
|
||||
|
||||
this.func_27257_b(mouseX, mouseY);
|
||||
|
@ -382,17 +382,17 @@ public abstract class GuiScrollingList
|
|||
|
||||
private void overlayBackground(int p_22239_1_, int p_22239_2_, int p_22239_3_, int p_22239_4_)
|
||||
{
|
||||
Tessellator var5 = Tessellator.field_1512_a;
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.client.field_6315_n.func_1070_a("/gui/background.png"));
|
||||
Tessellator var5 = Tessellator.field_78398_a;
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.client.field_71446_o.func_78341_b("/gui/background.png"));
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
float var6 = 32.0F;
|
||||
var5.func_977_b();
|
||||
var5.func_6513_a(4210752, p_22239_4_);
|
||||
var5.func_983_a(0.0D, (double)p_22239_2_, 0.0D, 0.0D, (double)((float)p_22239_2_ / var6));
|
||||
var5.func_983_a((double)this.listWidth + 30, (double)p_22239_2_, 0.0D, (double)((float)(this.listWidth + 30) / var6), (double)((float)p_22239_2_ / var6));
|
||||
var5.func_6513_a(4210752, p_22239_3_);
|
||||
var5.func_983_a((double)this.listWidth + 30, (double)p_22239_1_, 0.0D, (double)((float)(this.listWidth + 30) / var6), (double)((float)p_22239_1_ / var6));
|
||||
var5.func_983_a(0.0D, (double)p_22239_1_, 0.0D, 0.0D, (double)((float)p_22239_1_ / var6));
|
||||
var5.func_982_a();
|
||||
var5.func_78382_b();
|
||||
var5.func_78384_a(4210752, p_22239_4_);
|
||||
var5.func_78374_a(0.0D, (double)p_22239_2_, 0.0D, 0.0D, (double)((float)p_22239_2_ / var6));
|
||||
var5.func_78374_a((double)this.listWidth + 30, (double)p_22239_2_, 0.0D, (double)((float)(this.listWidth + 30) / var6), (double)((float)p_22239_2_ / var6));
|
||||
var5.func_78384_a(4210752, p_22239_3_);
|
||||
var5.func_78374_a((double)this.listWidth + 30, (double)p_22239_1_, 0.0D, (double)((float)(this.listWidth + 30) / var6), (double)((float)p_22239_1_ / var6));
|
||||
var5.func_78374_a(0.0D, (double)p_22239_1_, 0.0D, 0.0D, (double)((float)p_22239_1_ / var6));
|
||||
var5.func_78381_a();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package cpw.mods.fml.client;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.ModMetadata;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
@ -36,7 +37,7 @@ public class GuiSlotModList extends GuiScrollingList
|
|||
|
||||
public GuiSlotModList(GuiModList parent, ArrayList<ModContainer> mods, int listWidth)
|
||||
{
|
||||
super(parent.getMinecraftInstance(), listWidth, parent.field_950_d, 32, parent.field_950_d - 65 + 4, 10, 35);
|
||||
super(parent.getMinecraftInstance(), listWidth, parent.field_73881_g, 32, parent.field_73881_g - 65 + 4, 10, 35);
|
||||
this.parent=parent;
|
||||
this.mods=mods;
|
||||
}
|
||||
|
@ -62,7 +63,7 @@ public class GuiSlotModList extends GuiScrollingList
|
|||
@Override
|
||||
protected void drawBackground()
|
||||
{
|
||||
this.parent.func_578_i();
|
||||
this.parent.func_73873_v_();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,14 +71,23 @@ public class GuiSlotModList extends GuiScrollingList
|
|||
{
|
||||
return (this.getSize()) * 35 + 1;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void drawSlot(int listIndex, int var2, int var3, int var4, Tessellator var5)
|
||||
{
|
||||
ModContainer mc=mods.get(listIndex);
|
||||
this.parent.getFontRenderer().func_873_b(this.parent.getFontRenderer().func_50107_a(mc.getName(), listWidth - 11), this.left + 3 , var3 + 2, 0xFFFFFF);
|
||||
this.parent.getFontRenderer().func_873_b(this.parent.getFontRenderer().func_50107_a(mc.getVersion(), listWidth - 11), this.left + 3 , var3 + 12, 0xCCCCCC);
|
||||
this.parent.getFontRenderer().func_873_b(this.parent.getFontRenderer().func_50107_a(mc.getMetadata() !=null ? mc.getMetadata().getChildModCountString() : "Metadata not found", listWidth - 9), this.left + 3 , var3 + 22, 0xCCCCCC);
|
||||
if (Loader.instance().getModState(mc)==ModState.DISABLED)
|
||||
{
|
||||
this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getName(), listWidth - 11), this.left + 3 , var3 + 2, 0xFF2222);
|
||||
this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getVersion(), listWidth - 11), this.left + 3 , var3 + 12, 0xFF2222);
|
||||
this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a("DISABLED", listWidth - 11), this.left + 3 , var3 + 22, 0xFF2222);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getName(), listWidth - 11), this.left + 3 , var3 + 2, 0xFFFFFF);
|
||||
this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getVersion(), listWidth - 11), this.left + 3 , var3 + 12, 0xCCCCCC);
|
||||
this.parent.getFontRenderer().func_78276_b(this.parent.getFontRenderer().func_78269_a(mc.getMetadata() !=null ? mc.getMetadata().getChildModCountString() : "Metadata not found", listWidth - 9), this.left + 3 , var3 + 22, 0xCCCCCC);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* 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 org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import net.minecraft.src.KeyBinding;
|
||||
import cpw.mods.fml.common.IKeyHandler;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.modloader.ModLoaderModContainer;
|
||||
|
||||
/**
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class KeyBindingHandler implements IKeyHandler
|
||||
{
|
||||
|
||||
private boolean shouldRepeat;
|
||||
private KeyBinding keyBinding;
|
||||
private ModContainer modContainer;
|
||||
private boolean lastState = false;
|
||||
|
||||
/**
|
||||
* @param keyHandler
|
||||
* @param allowRepeat
|
||||
* @param modContainer
|
||||
*/
|
||||
public KeyBindingHandler(KeyBinding keyHandler, boolean allowRepeat, ModContainer modContainer)
|
||||
{
|
||||
this.keyBinding=keyHandler;
|
||||
this.shouldRepeat=allowRepeat;
|
||||
this.modContainer=modContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getKeyBinding()
|
||||
{
|
||||
return this.keyBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the modContainer
|
||||
*/
|
||||
public ModContainer getOwningContainer()
|
||||
{
|
||||
return modContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEndTick()
|
||||
{
|
||||
int keyCode = keyBinding.field_1370_b;
|
||||
boolean state = (keyCode < 0 ? Mouse.isButtonDown(keyCode + 100) : Keyboard.isKeyDown(keyCode));
|
||||
if (state && (!lastState || (lastState && shouldRepeat)))
|
||||
{
|
||||
modContainer.keyBindEvent(keyBinding);
|
||||
}
|
||||
lastState = state;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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.EnumSet;
|
||||
|
||||
import net.minecraft.src.KeyBinding;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import cpw.mods.fml.client.registry.KeyBindingRegistry;
|
||||
import cpw.mods.fml.common.TickType;
|
||||
import cpw.mods.fml.common.modloader.ModLoaderModContainer;
|
||||
import cpw.mods.fml.common.registry.TickRegistry;
|
||||
|
||||
/**
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class ModLoaderKeyBindingHandler extends KeyBindingRegistry.KeyHandler
|
||||
{
|
||||
private ModLoaderModContainer modContainer;
|
||||
private boolean downArmed;
|
||||
private boolean upArmed;
|
||||
|
||||
/**
|
||||
* @param keyHandler
|
||||
* @param allowRepeat
|
||||
* @param modContainer
|
||||
*/
|
||||
public ModLoaderKeyBindingHandler(KeyBinding keyBinding, boolean allowRepeat, ModLoaderModContainer modContainer)
|
||||
{
|
||||
super(keyBinding, allowRepeat);
|
||||
this.modContainer=modContainer;
|
||||
}
|
||||
|
||||
public void onRenderEndTick()
|
||||
{
|
||||
((net.minecraft.src.BaseMod)modContainer.getMod()).keyboardEvent(keyBinding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyDown(EnumSet<TickType> type, boolean end, boolean repeats)
|
||||
{
|
||||
if (!end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
upArmed = false;
|
||||
if (type.contains(TickType.GUILOAD)|| type.contains(TickType.GAME))
|
||||
{
|
||||
downArmed = true;
|
||||
}
|
||||
if (type.contains(TickType.RENDER) && downArmed)
|
||||
{
|
||||
onRenderEndTick();
|
||||
downArmed = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyUp(EnumSet<TickType> type, boolean end)
|
||||
{
|
||||
if (!end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
downArmed = false;
|
||||
if (type.contains(TickType.GUILOAD)|| type.contains(TickType.GAME))
|
||||
{
|
||||
upArmed = true;
|
||||
}
|
||||
if (type.contains(TickType.RENDER) && upArmed)
|
||||
{
|
||||
onRenderEndTick();
|
||||
upArmed = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<TickType> ticks()
|
||||
{
|
||||
return EnumSet.of(TickType.GAME, TickType.RENDER, TickType.GUILOAD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
return modContainer.getModId() +" KB "+keyBinding.field_74512_d;
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* 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.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import cpw.mods.fml.common.FMLModContainer;
|
||||
import cpw.mods.fml.common.IConsoleHandler;
|
||||
import cpw.mods.fml.common.ICraftingHandler;
|
||||
import cpw.mods.fml.common.IDispenseHandler;
|
||||
import cpw.mods.fml.common.IKeyHandler;
|
||||
import cpw.mods.fml.common.INetworkHandler;
|
||||
import cpw.mods.fml.common.IPickupNotifier;
|
||||
import cpw.mods.fml.common.IPlayerTracker;
|
||||
import cpw.mods.fml.common.IWorldGenerator;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.ModMetadata;
|
||||
|
||||
/**
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class OptifineModContainer extends FMLModContainer
|
||||
{
|
||||
private String optifineVersion;
|
||||
private ModMetadata metadata;
|
||||
/**
|
||||
* @param optifineConfig
|
||||
*/
|
||||
public OptifineModContainer(Class<?> optifineConfig)
|
||||
{
|
||||
super("Optifine");
|
||||
try
|
||||
{
|
||||
optifineVersion = (String) optifineConfig.getField("VERSION").get(null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "Optifine";
|
||||
}
|
||||
@Override
|
||||
public String getVersion()
|
||||
{
|
||||
return optifineVersion;
|
||||
}
|
||||
|
||||
}
|
|
@ -16,10 +16,11 @@ package cpw.mods.fml.client;
|
|||
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import net.minecraft.src.ModLoader;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.LoaderException;
|
||||
|
||||
/**
|
||||
|
@ -31,7 +32,7 @@ public class SpriteHelper
|
|||
private static HashMap<String, BitSet> spriteInfo = new HashMap<String, BitSet>();
|
||||
|
||||
private static void initMCSpriteMaps() {
|
||||
BitSet slots =
|
||||
BitSet slots =
|
||||
SpriteHelper.toBitSet(
|
||||
"0000000000000000" +
|
||||
"0000000000000000" +
|
||||
|
@ -50,7 +51,7 @@ public class SpriteHelper
|
|||
"0000000111111000" +
|
||||
"0000000000000000");
|
||||
spriteInfo.put("/terrain.png", slots);
|
||||
|
||||
|
||||
slots = SpriteHelper.toBitSet(
|
||||
"0000000000000000" +
|
||||
"0000000000000000" +
|
||||
|
@ -73,8 +74,8 @@ public class SpriteHelper
|
|||
/**
|
||||
* Register a sprite map for ModTextureStatic, to allow for other mods to override
|
||||
* your sprite page.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public static void registerSpriteMapForFile(String file, String spriteMap) {
|
||||
if (spriteInfo.size() == 0) {
|
||||
|
@ -86,20 +87,20 @@ public class SpriteHelper
|
|||
}
|
||||
spriteInfo.put(file, toBitSet(spriteMap));
|
||||
}
|
||||
|
||||
|
||||
public static int getUniqueSpriteIndex(String path)
|
||||
{
|
||||
if (!spriteInfo.containsKey("/terrain.png"))
|
||||
{
|
||||
initMCSpriteMaps();
|
||||
}
|
||||
|
||||
|
||||
BitSet slots = spriteInfo.get(path);
|
||||
|
||||
|
||||
if (slots == null)
|
||||
{
|
||||
Exception ex = new Exception(String.format("Invalid getUniqueSpriteIndex call for texture: %s", path));
|
||||
Loader.log.throwing("ModLoader", "getUniqueSpriteIndex", ex);
|
||||
FMLLog.log(Level.SEVERE, ex, "A critical error has been detected with sprite overrides");
|
||||
FMLCommonHandler.instance().raiseException(ex,"Invalid request to getUniqueSpriteIndex",true);
|
||||
}
|
||||
|
||||
|
@ -108,7 +109,7 @@ public class SpriteHelper
|
|||
if (ret == -1)
|
||||
{
|
||||
Exception ex = new Exception(String.format("No more sprite indicies left for: %s", path));
|
||||
Loader.log.throwing("ModLoader", "getUniqueSpriteIndex", ex);
|
||||
FMLLog.log(Level.SEVERE, ex, "There are no sprite indicies left for %s", path);
|
||||
FMLCommonHandler.instance().raiseException(ex,"No more sprite indicies left", true);
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -0,0 +1,342 @@
|
|||
package cpw.mods.fml.client;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
|
||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_BINDING_2D;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.src.KeyBinding;
|
||||
import net.minecraft.src.ModTextureStatic;
|
||||
import net.minecraft.src.Profiler;
|
||||
import net.minecraft.src.RenderEngine;
|
||||
import net.minecraft.src.TextureFX;
|
||||
import net.minecraft.src.TexturePackBase;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
public class TextureFXManager
|
||||
{
|
||||
private static final TextureFXManager INSTANCE = new TextureFXManager();
|
||||
|
||||
private class TextureProperties
|
||||
{
|
||||
private int textureId;
|
||||
private Dimension dim;
|
||||
}
|
||||
|
||||
private Map<Integer,TextureProperties> textureProperties = Maps.newHashMap();
|
||||
private Multimap<String, OverrideInfo> overrideInfo = ArrayListMultimap.create();
|
||||
private HashSet<OverrideInfo> animationSet = new HashSet<OverrideInfo>();
|
||||
|
||||
private List<TextureFX> addedTextureFX = new ArrayList<TextureFX>();
|
||||
|
||||
private Minecraft client;
|
||||
|
||||
public boolean onUpdateTextureEffect(TextureFX effect)
|
||||
{
|
||||
ITextureFX ifx = (effect instanceof ITextureFX ? ((ITextureFX)effect) : null);
|
||||
|
||||
if (ifx != null && ifx.getErrored())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
String name = effect.getClass().getSimpleName();
|
||||
FMLClientHandler.instance().profileStart(name);
|
||||
|
||||
try
|
||||
{
|
||||
if (!FMLClientHandler.instance().hasOptifine())
|
||||
{
|
||||
effect.func_76846_a();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLLog.warning("Texture FX %s has failed to animate. Likely caused by a texture pack change that they did not respond correctly to", name);
|
||||
if (ifx != null)
|
||||
{
|
||||
ifx.setErrored(true);
|
||||
}
|
||||
FMLClientHandler.instance().profileEnd();
|
||||
return false;
|
||||
}
|
||||
FMLClientHandler.instance().profileEnd();
|
||||
|
||||
if (ifx != null)
|
||||
{
|
||||
Dimension dim = getTextureDimensions(effect);
|
||||
int target = ((dim.width >> 4) * (dim.height >> 4)) << 2;
|
||||
if (effect.field_76852_a.length != target)
|
||||
{
|
||||
FMLLog.warning("Detected a texture FX sizing discrepancy in %s (%d, %d)", name, effect.field_76852_a.length, target);
|
||||
ifx.setErrored(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//Quick and dirty image scaling, no smoothing or fanciness, meant for speed as it will be called every tick.
|
||||
public void scaleTextureFXData(byte[] data, ByteBuffer buf, int target, int length)
|
||||
{
|
||||
int sWidth = (int)Math.sqrt(data.length / 4);
|
||||
int factor = target / sWidth;
|
||||
byte[] tmp = new byte[4];
|
||||
|
||||
buf.clear();
|
||||
|
||||
if (factor > 1)
|
||||
{
|
||||
for (int y = 0; y < sWidth; y++)
|
||||
{
|
||||
int sRowOff = sWidth * y;
|
||||
int tRowOff = target * y * factor;
|
||||
for (int x = 0; x < sWidth; x++)
|
||||
{
|
||||
int sPos = (x + sRowOff) * 4;
|
||||
tmp[0] = data[sPos + 0];
|
||||
tmp[1] = data[sPos + 1];
|
||||
tmp[2] = data[sPos + 2];
|
||||
tmp[3] = data[sPos + 3];
|
||||
|
||||
int tPosTop = (x * factor) + tRowOff;
|
||||
for (int y2 = 0; y2 < factor; y2++)
|
||||
{
|
||||
buf.position((tPosTop + (y2 * target)) * 4);
|
||||
for (int x2 = 0; x2 < factor; x2++)
|
||||
{
|
||||
buf.put(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf.position(0).limit(length);
|
||||
}
|
||||
|
||||
public void onPreRegisterEffect(TextureFX effect)
|
||||
{
|
||||
Dimension dim = getTextureDimensions(effect);
|
||||
if (effect instanceof ITextureFX)
|
||||
{
|
||||
((ITextureFX)effect).onTextureDimensionsUpdate(dim.width, dim.height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int getEffectTexture(TextureFX effect)
|
||||
{
|
||||
Integer id = effectTextures.get(effect);
|
||||
if (id != null)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
int old = GL11.glGetInteger(GL_TEXTURE_BINDING_2D);
|
||||
|
||||
effect.func_76845_a(client.field_71446_o);
|
||||
|
||||
id = GL11.glGetInteger(GL_TEXTURE_BINDING_2D);
|
||||
|
||||
GL11.glBindTexture(GL_TEXTURE_2D, old);
|
||||
|
||||
effectTextures.put(effect, id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public void onTexturePackChange(RenderEngine engine, TexturePackBase texturepack, List<TextureFX> effects)
|
||||
{
|
||||
pruneOldTextureFX(texturepack, effects);
|
||||
|
||||
for (TextureFX tex : effects)
|
||||
{
|
||||
if (tex instanceof ITextureFX)
|
||||
{
|
||||
((ITextureFX)tex).onTexturePackChanged(engine, texturepack, getTextureDimensions(tex));
|
||||
}
|
||||
}
|
||||
|
||||
loadTextures(texturepack);
|
||||
}
|
||||
|
||||
private HashMap<Integer, Dimension> textureDims = new HashMap<Integer, Dimension>();
|
||||
private IdentityHashMap<TextureFX, Integer> effectTextures = new IdentityHashMap<TextureFX, Integer>();
|
||||
private TexturePackBase earlyTexturePack;
|
||||
public void setTextureDimensions(int id, int width, int height, List<TextureFX> effects)
|
||||
{
|
||||
Dimension dim = new Dimension(width, height);
|
||||
textureDims.put(id, dim);
|
||||
|
||||
for (TextureFX tex : effects)
|
||||
{
|
||||
if (getEffectTexture(tex) == id && tex instanceof ITextureFX)
|
||||
{
|
||||
((ITextureFX)tex).onTextureDimensionsUpdate(width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dimension getTextureDimensions(TextureFX effect)
|
||||
{
|
||||
return getTextureDimensions(getEffectTexture(effect));
|
||||
}
|
||||
|
||||
public Dimension getTextureDimensions(int id)
|
||||
{
|
||||
return textureDims.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param anim
|
||||
*/
|
||||
public void addAnimation(TextureFX anim)
|
||||
{
|
||||
OverrideInfo info=new OverrideInfo();
|
||||
info.index=anim.field_76850_b;
|
||||
info.imageIndex=anim.field_76847_f;
|
||||
info.textureFX=anim;
|
||||
if (animationSet.contains(info)) {
|
||||
animationSet.remove(info);
|
||||
}
|
||||
animationSet.add(info);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param p_6531_1_
|
||||
*/
|
||||
public void loadTextures(TexturePackBase texturePack)
|
||||
{
|
||||
registerTextureOverrides(client.field_71446_o);
|
||||
}
|
||||
|
||||
|
||||
public void registerTextureOverrides(RenderEngine renderer) {
|
||||
for (ModContainer mod : Loader.instance().getActiveModList()) {
|
||||
registerAnimatedTexturesFor(mod);
|
||||
}
|
||||
|
||||
for (OverrideInfo animationOverride : animationSet) {
|
||||
renderer.func_78355_a(animationOverride.textureFX);
|
||||
addedTextureFX.add(animationOverride.textureFX);
|
||||
FMLCommonHandler.instance().getFMLLogger().finer(String.format("Registered texture override %d (%d) on %s (%d)", animationOverride.index, animationOverride.textureFX.field_76850_b, animationOverride.textureFX.getClass().getSimpleName(), animationOverride.textureFX.field_76847_f));
|
||||
}
|
||||
|
||||
for (String fileToOverride : overrideInfo.keySet()) {
|
||||
for (OverrideInfo override : overrideInfo.get(fileToOverride)) {
|
||||
try
|
||||
{
|
||||
BufferedImage image=loadImageFromTexturePack(renderer, override.override);
|
||||
ModTextureStatic mts=new ModTextureStatic(override.index, 1, override.texture, image);
|
||||
renderer.func_78355_a(mts);
|
||||
addedTextureFX.add(mts);
|
||||
FMLCommonHandler.instance().getFMLLogger().finer(String.format("Registered texture override %d (%d) on %s (%d)", override.index, mts.field_76850_b, override.texture, mts.field_76847_f));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
FMLCommonHandler.instance().getFMLLogger().throwing("FMLClientHandler", "registerTextureOverrides", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mod
|
||||
*/
|
||||
private void registerAnimatedTexturesFor(ModContainer mod)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field_6539_c
|
||||
*/
|
||||
public void onEarlyTexturePackLoad(TexturePackBase fallback)
|
||||
{
|
||||
if (client==null) {
|
||||
// We're far too early- let's wait
|
||||
this.earlyTexturePack = fallback;
|
||||
} else {
|
||||
loadTextures(fallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void pruneOldTextureFX(TexturePackBase var1, List<TextureFX> effects)
|
||||
{
|
||||
ListIterator<TextureFX> li = addedTextureFX.listIterator();
|
||||
while (li.hasNext())
|
||||
{
|
||||
TextureFX tex = li.next();
|
||||
if (tex instanceof FMLTextureFX)
|
||||
{
|
||||
if (((FMLTextureFX)tex).unregister(client.field_71446_o, effects))
|
||||
{
|
||||
li.remove();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
effects.remove(tex);
|
||||
li.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void addNewTextureOverride(String textureToOverride, String overridingTexturePath, int location) {
|
||||
OverrideInfo info = new OverrideInfo();
|
||||
info.index = location;
|
||||
info.override = overridingTexturePath;
|
||||
info.texture = textureToOverride;
|
||||
overrideInfo.put(textureToOverride, info);
|
||||
FMLLog.fine("Overriding %s @ %d with %s. %d slots remaining",textureToOverride, location, overridingTexturePath, SpriteHelper.freeSlotCount(textureToOverride));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param renderEngine
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public BufferedImage loadImageFromTexturePack(RenderEngine renderEngine, String path) throws IOException
|
||||
{
|
||||
InputStream image=client.field_71418_C.func_77292_e().func_77532_a(path);
|
||||
if (image==null) {
|
||||
throw new RuntimeException(String.format("The requested image path %s is not found",path));
|
||||
}
|
||||
BufferedImage result=ImageIO.read(image);
|
||||
if (result==null)
|
||||
{
|
||||
throw new RuntimeException(String.format("The requested image path %s appears to be corrupted",path));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static TextureFXManager instance()
|
||||
{
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package cpw.mods.fml.client.registry;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import net.minecraft.src.BiomeGenBase;
|
||||
import net.minecraft.src.TileEntity;
|
||||
import net.minecraft.src.TileEntityRenderer;
|
||||
import net.minecraft.src.TileEntitySpecialRenderer;
|
||||
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
import cpw.mods.fml.common.ObfuscationReflectionHelper;
|
||||
import cpw.mods.fml.common.registry.FMLRegistry;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import cpw.mods.fml.common.registry.IMinecraftRegistry;
|
||||
|
||||
public class ClientRegistry
|
||||
{
|
||||
/**
|
||||
*
|
||||
* Utility method for registering a tile entity and it's renderer at once - generally you should register them separately
|
||||
*
|
||||
* @param tileEntityClass
|
||||
* @param id
|
||||
* @param specialRenderer
|
||||
*/
|
||||
public static void registerTileEntity(Class <? extends TileEntity > tileEntityClass, String id, TileEntitySpecialRenderer specialRenderer)
|
||||
{
|
||||
GameRegistry.registerTileEntity(tileEntityClass, id);
|
||||
bindTileEntitySpecialRenderer(tileEntityClass, specialRenderer);
|
||||
}
|
||||
|
||||
public static void bindTileEntitySpecialRenderer(Class <? extends TileEntity> tileEntityClass, TileEntitySpecialRenderer specialRenderer)
|
||||
{
|
||||
TileEntityRenderer.field_76963_a.field_76966_m.put(tileEntityClass, specialRenderer);
|
||||
specialRenderer.func_76893_a(TileEntityRenderer.field_76963_a);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package cpw.mods.fml.client.registry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.minecraft.src.GameSettings;
|
||||
import net.minecraft.src.KeyBinding;
|
||||
|
||||
import cpw.mods.fml.common.ITickHandler;
|
||||
import cpw.mods.fml.common.TickType;
|
||||
import cpw.mods.fml.common.registry.TickRegistry;
|
||||
|
||||
public class KeyBindingRegistry
|
||||
{
|
||||
public static abstract class KeyHandler implements ITickHandler
|
||||
{
|
||||
protected KeyBinding keyBinding;
|
||||
protected boolean keyDown;
|
||||
protected boolean repeating;
|
||||
|
||||
public KeyHandler(KeyBinding keyBinding, boolean repeating)
|
||||
{
|
||||
this.keyBinding = keyBinding;
|
||||
this.repeating = repeating;
|
||||
}
|
||||
|
||||
public KeyBinding getKeyBinding()
|
||||
{
|
||||
return this.keyBinding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void tickStart(EnumSet<TickType> type, Object... tickData)
|
||||
{
|
||||
keyTick(type, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void tickEnd(EnumSet<TickType> type, Object... tickData)
|
||||
{
|
||||
keyTick(type, true);
|
||||
}
|
||||
|
||||
private void keyTick(EnumSet<TickType> type, boolean tickEnd)
|
||||
{
|
||||
int keyCode = keyBinding.field_74512_d;
|
||||
boolean state = (keyCode < 0 ? Mouse.isButtonDown(keyCode + 100) : Keyboard.isKeyDown(keyCode));
|
||||
if (state != keyDown || (state && repeating))
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
keyDown(type, tickEnd, state!=keyDown);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyUp(type, tickEnd);
|
||||
}
|
||||
keyDown = state;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void keyDown(EnumSet<TickType> types, boolean tickEnd, boolean isRepeat);
|
||||
public abstract void keyUp(EnumSet<TickType> types, boolean tickEnd);
|
||||
}
|
||||
|
||||
private static List<KeyHandler> keyHandlers = Lists.newArrayList();
|
||||
|
||||
public static void registerKeyBinding(KeyHandler handler) {
|
||||
keyHandlers.add(handler);
|
||||
}
|
||||
|
||||
public static void uploadKeyBindingsToGame(GameSettings settings)
|
||||
{
|
||||
ArrayList<KeyBinding> harvestedBindings = Lists.newArrayList();
|
||||
for (KeyHandler key : keyHandlers)
|
||||
{
|
||||
harvestedBindings.add(key.keyBinding);
|
||||
}
|
||||
KeyBinding[] modKeyBindings = harvestedBindings.toArray(new KeyBinding[harvestedBindings.size()]);
|
||||
KeyBinding[] allKeys = new KeyBinding[settings.field_74324_K.length + modKeyBindings.length];
|
||||
System.arraycopy(settings.field_74324_K, 0, allKeys, 0, settings.field_74324_K.length);
|
||||
System.arraycopy(modKeyBindings, 0, allKeys, settings.field_74324_K.length, modKeyBindings.length);
|
||||
settings.field_74324_K = allKeys;
|
||||
settings.func_74300_a();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package cpw.mods.fml.client.registry;
|
||||
|
||||
public class RenderingRegistry
|
||||
{
|
||||
|
||||
}
|
|
@ -42,7 +42,7 @@ public abstract class BaseMod implements cpw.mods.fml.common.modloader.BaseMod
|
|||
public final boolean doTickInGame(TickType tick, boolean tickEnd, Object minecraftInstance, Object... data)
|
||||
{
|
||||
Minecraft mc = (Minecraft) minecraftInstance;
|
||||
boolean hasWorld = mc.field_6324_e != null;
|
||||
boolean hasWorld = true;
|
||||
// World and render ticks
|
||||
if (tickEnd && ( tick==TickType.RENDER || tick==TickType.GAME ) && hasWorld) {
|
||||
return onTickInGame((Float) data[0], mc);
|
||||
|
@ -54,7 +54,7 @@ public abstract class BaseMod implements cpw.mods.fml.common.modloader.BaseMod
|
|||
{
|
||||
Minecraft mc = (Minecraft) minecraftInstance;
|
||||
if (tickEnd && ( tick==TickType.RENDER || tick==TickType.GAME ) || tick == TickType.GUILOAD) {
|
||||
return onTickInGUI((Float) data[0], mc, mc.field_6313_p);
|
||||
return onTickInGUI((Float) data[0], mc, mc.field_71462_r);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public abstract class BaseMod implements cpw.mods.fml.common.modloader.BaseMod
|
|||
}
|
||||
|
||||
@Override
|
||||
public final boolean dispense(double x, double y, double z, byte xVelocity, byte zVelocity, Object... data)
|
||||
public final boolean dispense(double x, double y, double z, int xVelocity, int zVelocity, Object... data)
|
||||
{
|
||||
return dispenseEntity((World)data[0], x, y, z, xVelocity, zVelocity, (ItemStack)data[1]);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ public abstract class BaseMod implements cpw.mods.fml.common.modloader.BaseMod
|
|||
@Override
|
||||
public final boolean onChat(Object... data)
|
||||
{
|
||||
receiveChatPacket(((Packet3Chat)data[0]).field_517_a);
|
||||
receiveChatPacket(((Packet3Chat)data[0]).field_73476_b);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ public abstract class BaseMod implements cpw.mods.fml.common.modloader.BaseMod
|
|||
{
|
||||
EntityItem item = (EntityItem) pickupData[0];
|
||||
EntityPlayer player = (EntityPlayer) pickupData[1];
|
||||
onItemPickup(player, item.field_801_a);
|
||||
onItemPickup(player, item.field_70294_a);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
package net.minecraft.src;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
import cpw.mods.fml.common.registry.FMLRegistry;
|
||||
import cpw.mods.fml.common.registry.IMinecraftRegistry;
|
||||
|
||||
public class ClientRegistry implements IMinecraftRegistry
|
||||
{
|
||||
|
||||
public static ClientRegistry instance() {
|
||||
return (ClientRegistry) FMLRegistry.instance();
|
||||
}
|
||||
@Override
|
||||
public void addRecipe(ItemStack output, Object... params)
|
||||
{
|
||||
CraftingManager.func_1120_a().func_1121_a(output, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addShapelessRecipe(ItemStack output, Object... params)
|
||||
{
|
||||
CraftingManager.func_1120_a().func_21187_b(output, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRecipe(IRecipe recipe)
|
||||
{
|
||||
CraftingManager.func_1120_a().func_25193_b().add(recipe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSmelting(int input, ItemStack output)
|
||||
{
|
||||
FurnaceRecipes.func_21200_a().func_21199_a(input, output);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBlock(Block block)
|
||||
{
|
||||
registerBlock(block, ItemBlock.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBlock(Block block, Class <? extends ItemBlock > itemclass)
|
||||
{
|
||||
try
|
||||
{
|
||||
assert block != null : "registerBlock: block cannot be null";
|
||||
assert itemclass != null : "registerBlock: itemclass cannot be null";
|
||||
int blockItemId = block.field_376_bc - 256;
|
||||
itemclass.getConstructor(int.class).newInstance(blockItemId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//HMMM
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerEntityID(Class <? extends Entity > entityClass, String entityName, int id)
|
||||
{
|
||||
EntityList.addNewEntityListMapping(entityClass, entityName, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerEntityID(Class <? extends Entity > entityClass, String entityName, int id, int backgroundEggColour, int foregroundEggColour)
|
||||
{
|
||||
EntityList.addNewEntityListMapping(entityClass, entityName, id, backgroundEggColour, foregroundEggColour);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerTileEntity(Class <? extends TileEntity > tileEntityClass, String id)
|
||||
{
|
||||
TileEntity.addNewTileEntityMapping(tileEntityClass, id);
|
||||
}
|
||||
|
||||
public void registerTileEntity(Class <? extends TileEntity > tileEntityClass, String id, TileEntitySpecialRenderer specialRenderer)
|
||||
{
|
||||
registerTileEntity(tileEntityClass, id);
|
||||
TileEntityRenderer.setTileEntityRenderer(tileEntityClass, specialRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBiome(BiomeGenBase biome)
|
||||
{
|
||||
FMLClientHandler.instance().addBiomeToDefaultWorldGenerator(biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSpawn(Class <? extends EntityLiving > entityClass, int weightedProb, int min, int max, EnumCreatureType typeOfCreature, BiomeGenBase... biomes)
|
||||
{
|
||||
for (BiomeGenBase biome : biomes)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
List<SpawnListEntry> spawns = biome.func_25063_a(typeOfCreature);
|
||||
|
||||
for (SpawnListEntry entry : spawns)
|
||||
{
|
||||
//Adjusting an existing spawn entry
|
||||
if (entry.field_25212_a == entityClass)
|
||||
{
|
||||
entry.field_35590_d = weightedProb;
|
||||
entry.field_35591_b = min;
|
||||
entry.field_35592_c = max;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spawns.add(new SpawnListEntry(entityClass, weightedProb, min, max));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addSpawn(String entityName, int weightedProb, int min, int max, EnumCreatureType spawnList, BiomeGenBase... biomes)
|
||||
{
|
||||
Class <? extends Entity > entityClazz = EntityList.getEntityToClassMapping().get(entityName);
|
||||
|
||||
if (EntityLiving.class.isAssignableFrom(entityClazz))
|
||||
{
|
||||
addSpawn((Class <? extends EntityLiving >) entityClazz, weightedProb, min, max, spawnList, biomes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBiome(BiomeGenBase biome)
|
||||
{
|
||||
FMLClientHandler.instance().removeBiomeFromDefaultWorldGenerator(biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSpawn(Class <? extends EntityLiving > entityClass, EnumCreatureType typeOfCreature, BiomeGenBase... biomes)
|
||||
{
|
||||
for (BiomeGenBase biome : biomes)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<SpawnListEntry> spawns = biome.func_25063_a(typeOfCreature).iterator();
|
||||
|
||||
while (spawns.hasNext())
|
||||
{
|
||||
SpawnListEntry entry = spawns.next();
|
||||
if (entry.field_25212_a == entityClass)
|
||||
{
|
||||
spawns.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void removeSpawn(String entityName, EnumCreatureType spawnList, BiomeGenBase... biomes)
|
||||
{
|
||||
Class <? extends Entity > entityClazz = EntityList.getEntityToClassMapping().get(entityName);
|
||||
|
||||
if (EntityLiving.class.isAssignableFrom(entityClazz))
|
||||
{
|
||||
removeSpawn((Class <? extends EntityLiving >) entityClazz, spawnList, biomes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,17 +20,17 @@ public class EntityRendererProxy extends EntityRenderer
|
|||
{
|
||||
|
||||
private Minecraft game;
|
||||
|
||||
|
||||
public EntityRendererProxy(Minecraft minecraft)
|
||||
{
|
||||
super(minecraft);
|
||||
game = minecraft;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void func_4136_b(float tick)
|
||||
public void func_78480_b(float tick)
|
||||
{
|
||||
super.func_4136_b(tick);
|
||||
super.func_78480_b(tick);
|
||||
//This is where ModLoader does all of it's ticking
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,15 @@ import java.util.List;
|
|||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import cpw.mods.fml.client.BlockRenderManager;
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
import cpw.mods.fml.client.TextureFXManager;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* A static hook library for optifine and other basemod editing code to access FML functions
|
||||
*
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
|
@ -35,54 +37,54 @@ public class FMLRenderAccessLibrary
|
|||
{
|
||||
return FMLCommonHandler.instance().getFMLLogger();
|
||||
}
|
||||
|
||||
|
||||
public static void log(Level level, String message)
|
||||
{
|
||||
getLogger().log(level, message);
|
||||
}
|
||||
|
||||
|
||||
public static void log(Level level, String message, Throwable throwable)
|
||||
{
|
||||
getLogger().log(level, message, throwable);
|
||||
}
|
||||
|
||||
|
||||
public static void setTextureDimensions(int textureId, int width, int height, List<TextureFX> textureFXList)
|
||||
{
|
||||
FMLClientHandler.instance().setTextureDimensions(textureId, width, height, textureFXList);
|
||||
TextureFXManager.instance().setTextureDimensions(textureId, width, height, textureFXList);
|
||||
}
|
||||
|
||||
|
||||
public static void preRegisterEffect(TextureFX textureFX)
|
||||
{
|
||||
FMLClientHandler.instance().onPreRegisterEffect(textureFX);
|
||||
TextureFXManager.instance().onPreRegisterEffect(textureFX);
|
||||
}
|
||||
|
||||
|
||||
public static boolean onUpdateTextureEffect(TextureFX textureFX)
|
||||
{
|
||||
return FMLClientHandler.instance().onUpdateTextureEffect(textureFX);
|
||||
return TextureFXManager.instance().onUpdateTextureEffect(textureFX);
|
||||
}
|
||||
|
||||
|
||||
public static Dimension getTextureDimensions(TextureFX textureFX)
|
||||
{
|
||||
return FMLClientHandler.instance().getTextureDimensions(textureFX);
|
||||
return TextureFXManager.instance().getTextureDimensions(textureFX);
|
||||
}
|
||||
|
||||
|
||||
public static void onTexturePackChange(RenderEngine engine, TexturePackBase texturePack, List<TextureFX> textureFXList)
|
||||
{
|
||||
FMLClientHandler.instance().onTexturePackChange(engine, texturePack, textureFXList);
|
||||
TextureFXManager.instance().onTexturePackChange(engine, texturePack, textureFXList);
|
||||
}
|
||||
|
||||
|
||||
public static boolean renderWorldBlock(RenderBlocks renderer, IBlockAccess world, int x, int y, int z, Block block, int modelId)
|
||||
{
|
||||
return FMLClientHandler.instance().renderWorldBlock(renderer, world, x, y, z, block, modelId);
|
||||
return BlockRenderManager.instance().renderWorldBlock(renderer, world, x, y, z, block, modelId);
|
||||
}
|
||||
|
||||
|
||||
public static void renderInventoryBlock(RenderBlocks renderer, Block block, int metadata, int modelID)
|
||||
{
|
||||
FMLClientHandler.instance().renderInventoryBlock(renderer, block, metadata, modelID);
|
||||
BlockRenderManager.instance().renderInventoryBlock(renderer, block, metadata, modelID);
|
||||
}
|
||||
|
||||
|
||||
public static boolean renderItemAsFull3DBlock(int modelId)
|
||||
{
|
||||
return FMLClientHandler.instance().renderItemAsFull3DBlock(modelId);
|
||||
return BlockRenderManager.instance().renderItemAsFull3DBlock(modelId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,14 +22,18 @@ import java.util.logging.Logger;
|
|||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import cpw.mods.fml.client.BlockRenderManager;
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
import cpw.mods.fml.client.SpriteHelper;
|
||||
import cpw.mods.fml.client.TextureFXManager;
|
||||
import cpw.mods.fml.client.registry.ClientRegistry;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ReflectionHelper;
|
||||
import cpw.mods.fml.common.modloader.ModLoaderHelper;
|
||||
import cpw.mods.fml.common.modloader.ModLoaderModContainer;
|
||||
import cpw.mods.fml.common.registry.FMLRegistry;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import cpw.mods.fml.common.ObfuscationReflectionHelper;
|
||||
|
||||
public class ModLoader
|
||||
{
|
||||
|
@ -72,7 +76,7 @@ public class ModLoader
|
|||
|
||||
public static void addAnimation(TextureFX anim)
|
||||
{
|
||||
FMLClientHandler.instance().addAnimation(anim);
|
||||
TextureFXManager.instance().addAnimation(anim);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,7 +169,7 @@ public class ModLoader
|
|||
*/
|
||||
public static void addOverride(String path, String overlayPath, int index)
|
||||
{
|
||||
FMLClientHandler.instance().addNewTextureOverride(path, overlayPath, index);
|
||||
TextureFXManager.instance().addNewTextureOverride(path, overlayPath, index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -176,7 +180,7 @@ public class ModLoader
|
|||
*/
|
||||
public static void addRecipe(ItemStack output, Object... params)
|
||||
{
|
||||
FMLRegistry.addRecipe(output, params);
|
||||
GameRegistry.addRecipe(output, params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,7 +191,7 @@ public class ModLoader
|
|||
*/
|
||||
public static void addShapelessRecipe(ItemStack output, Object... params)
|
||||
{
|
||||
FMLRegistry.addShapelessRecipe(output, params);
|
||||
GameRegistry.addShapelessRecipe(output, params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -288,7 +292,7 @@ public class ModLoader
|
|||
*/
|
||||
public static void genericContainerRemoval(World world, int x, int y, int z)
|
||||
{
|
||||
TileEntity te = world.func_603_b(x, y, z);
|
||||
/* TileEntity te = world.func_603_b(x, y, z);
|
||||
|
||||
if (!(te instanceof IInventory))
|
||||
{
|
||||
|
@ -334,7 +338,7 @@ public class ModLoader
|
|||
world.func_674_a(entityitem);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/ }
|
||||
|
||||
/**
|
||||
* Get a list of all BaseMod loaded into the system
|
||||
|
@ -375,7 +379,7 @@ public class ModLoader
|
|||
|
||||
/**
|
||||
* Get a value from a field using reflection
|
||||
* {@link ReflectionHelper#getPrivateValue(Class, Object, int)}
|
||||
* {@link ObfuscationReflectionHelper#getPrivateValue(Class, Object, int)}
|
||||
*
|
||||
* @param instanceclass
|
||||
* @param instance
|
||||
|
@ -384,12 +388,12 @@ public class ModLoader
|
|||
*/
|
||||
public static <T, E> T getPrivateValue(Class<? super E> instanceclass, E instance, int fieldindex)
|
||||
{
|
||||
return ReflectionHelper.getPrivateValue(instanceclass, instance, fieldindex);
|
||||
return ObfuscationReflectionHelper.getPrivateValue(instanceclass, instance, fieldindex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from a field using reflection
|
||||
* {@link ReflectionHelper#getPrivateValue(Class, Object, String)}
|
||||
* {@link ObfuscationReflectionHelper#getPrivateValue(Class, Object, String)}
|
||||
*
|
||||
* @param instanceclass
|
||||
* @param instance
|
||||
|
@ -398,7 +402,7 @@ public class ModLoader
|
|||
*/
|
||||
public static <T, E> T getPrivateValue(Class<? super E> instanceclass, E instance, String field)
|
||||
{
|
||||
return ReflectionHelper.getPrivateValue(instanceclass, instance, field);
|
||||
return ObfuscationReflectionHelper.getPrivateValue(instanceclass, instance, field);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -407,7 +411,7 @@ public class ModLoader
|
|||
*/
|
||||
public static int getUniqueBlockModelID(BaseMod mod, boolean inventoryRenderer)
|
||||
{
|
||||
return FMLClientHandler.instance().obtainBlockModelIdFor(mod, inventoryRenderer);
|
||||
return BlockRenderManager.instance().obtainBlockModelIdFor(mod, inventoryRenderer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -441,7 +445,7 @@ public class ModLoader
|
|||
|
||||
public static boolean isGUIOpen(Class<? extends GuiScreen> gui)
|
||||
{
|
||||
return FMLClientHandler.instance().getClient().field_6313_p!=null && FMLClientHandler.instance().getClient().field_6313_p.equals(gui);
|
||||
return FMLClientHandler.instance().getClient().field_71462_r != null && FMLClientHandler.instance().getClient().field_71462_r.equals(gui);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -466,7 +470,7 @@ public class ModLoader
|
|||
|
||||
public static BufferedImage loadImage(RenderEngine renderEngine, String path) throws Exception
|
||||
{
|
||||
return FMLClientHandler.instance().loadImageFromTexturePack(renderEngine, path);
|
||||
return TextureFXManager.instance().loadImageFromTexturePack(renderEngine, path);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -567,7 +571,7 @@ public class ModLoader
|
|||
|
||||
public static void registerKey(BaseMod mod, KeyBinding keyHandler, boolean allowRepeat)
|
||||
{
|
||||
FMLClientHandler.instance().registerKeyHandler(mod, keyHandler, allowRepeat);
|
||||
FMLClientHandler.instance().registerModLoaderKeyHandler(mod, keyHandler, allowRepeat);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -659,19 +663,19 @@ public class ModLoader
|
|||
@Deprecated
|
||||
public static boolean renderBlockIsItemFull3D(int modelID)
|
||||
{
|
||||
return FMLClientHandler.instance().renderItemAsFull3DBlock(modelID);
|
||||
return BlockRenderManager.instance().renderItemAsFull3DBlock(modelID);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void renderInvBlock(RenderBlocks renderer, Block block, int metadata, int modelID)
|
||||
{
|
||||
FMLClientHandler.instance().renderInventoryBlock(renderer, block, metadata, modelID);
|
||||
BlockRenderManager.instance().renderInventoryBlock(renderer, block, metadata, modelID);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static boolean renderWorldBlock(RenderBlocks renderer, IBlockAccess world, int x, int y, int z, Block block, int modelID)
|
||||
{
|
||||
return FMLClientHandler.instance().renderWorldBlock(renderer, world, x, y, z, block, modelID);
|
||||
return BlockRenderManager.instance().renderWorldBlock(renderer, world, x, y, z, block, modelID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -724,7 +728,7 @@ public class ModLoader
|
|||
|
||||
/**
|
||||
* Set a private field to a value using reflection
|
||||
* {@link ReflectionHelper#setPrivateValue(Class, Object, int, Object)}
|
||||
* {@link ObfuscationReflectionHelper#setPrivateValue(Class, Object, int, Object)}
|
||||
*
|
||||
* @param instanceclass
|
||||
* @param instance
|
||||
|
@ -733,12 +737,12 @@ public class ModLoader
|
|||
*/
|
||||
public static <T, E> void setPrivateValue(Class<? super T> instanceclass, T instance, int fieldindex, E value)
|
||||
{
|
||||
ReflectionHelper.setPrivateValue(instanceclass, instance, fieldindex, value);
|
||||
ObfuscationReflectionHelper.setPrivateValue(instanceclass, instance, value, fieldindex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a private field to a value using reflection
|
||||
* {@link ReflectionHelper#setPrivateValue(Class, Object, String, Object)}
|
||||
* {@link ObfuscationReflectionHelper#setPrivateValue(Class, Object, String, Object)}
|
||||
*
|
||||
* @param instanceclass
|
||||
* @param instance
|
||||
|
@ -747,7 +751,7 @@ public class ModLoader
|
|||
*/
|
||||
public static <T, E> void setPrivateValue(Class<? super T> instanceclass, T instance, String field, E value)
|
||||
{
|
||||
ReflectionHelper.setPrivateValue(instanceclass, instance, field, value);
|
||||
ObfuscationReflectionHelper.setPrivateValue(instanceclass, instance, value, field);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
--- commands.py
|
||||
+++ commands.py
|
||||
@@ -22,6 +22,7 @@
|
||||
import errno
|
||||
import shlex
|
||||
import platform
|
||||
+import pprint
|
||||
from hashlib import md5 # pylint: disable-msg=E0611
|
||||
from contextlib import closing
|
||||
from textwrap import TextWrapper
|
||||
@@ -502,6 +503,7 @@
|
||||
self.binclienttmp = os.path.normpath(config.get('OUTPUT', 'BinClientTemp'))
|
||||
self.binservertmp = os.path.normpath(config.get('OUTPUT', 'BinServerTemp'))
|
||||
self.srcclient = os.path.normpath(config.get('OUTPUT', 'SrcClient'))
|
||||
+ self.srcshared = os.path.normpath(os.path.join(self.dirsrc, 'common'))
|
||||
self.srcserver = os.path.normpath(config.get('OUTPUT', 'SrcServer'))
|
||||
self.testclient = config.get('OUTPUT', 'TestClient')
|
||||
self.testserver = config.get('OUTPUT', 'TestServer')
|
||||
@@ -1039,6 +1041,7 @@
|
||||
all_files = True
|
||||
append_pattern = False
|
||||
pkglist = filterdirs(pathsrclk[side], '*.java', append_pattern=append_pattern, all_files=all_files)
|
||||
+ pkglist = pkglist + filterdirs(self.srcshared, '*.java', append_pattern=True) #FML, Add Common folder
|
||||
dirs = ' '.join(pkglist)
|
||||
classpath = os.pathsep.join(cplk[side])
|
||||
forkcmd = self.cmdrecomp.format(classpath=classpath, sourcepath=pathsrclk[side], outpath=pathbinlk[side],
|
||||
@@ -1238,6 +1241,11 @@
|
||||
|
||||
# HINT: We pathwalk the sources
|
||||
for path, _, filelist in os.walk(pathsrclk[side], followlinks=True):
|
||||
+ for cur_file in fnmatch.filter(filelist, '*.java'):
|
||||
+ updatefile(os.path.normpath(os.path.join(path, cur_file)))
|
||||
+
|
||||
+ # FML, copy of the above, for the common folder
|
||||
+ for path, _, filelist in os.walk(self.srcshared, followlinks=True):
|
||||
for cur_file in fnmatch.filter(filelist, '*.java'):
|
||||
updatefile(os.path.normpath(os.path.join(path, cur_file)))
|
||||
return True
|
||||
@@ -1320,12 +1328,14 @@
|
||||
pathsrclk = {CLIENT: self.srcclient, SERVER: self.srcserver}
|
||||
|
||||
strip_comments(pathsrclk[side])
|
||||
+ strip_comments(self.srcshared)
|
||||
|
||||
def process_cleanup(self, side):
|
||||
"""Do lots of random cleanups including stripping comments, trailing whitespace and extra blank lines"""
|
||||
pathsrclk = {CLIENT: self.srcclient, SERVER: self.srcserver}
|
||||
|
||||
src_cleanup(pathsrclk[side], fix_imports=True, fix_unicode=True, fix_charval=True, fix_pi=True, fix_round=False)
|
||||
+ src_cleanup(self.srcshared, fix_imports=True, fix_unicode=True, fix_charval=True, fix_pi=True, fix_round=False)
|
||||
|
||||
def process_javadoc(self, side):
|
||||
"""Add CSV descriptions to methods and fields as javadoc"""
|
||||
@@ -1334,6 +1344,21 @@
|
||||
if not self.has_doc_csv:
|
||||
self.logger.warning('!! javadoc disabled due to no csvs !!')
|
||||
return False
|
||||
+
|
||||
+ #FML Recall this function on the common folder
|
||||
+ #Potential bug: If this is called without a subsiquent rename call, will cause double comments
|
||||
+ if pathsrclk[side] != self.srcshared:
|
||||
+ if side == CLIENT:
|
||||
+ tmp = self.srcclient
|
||||
+ self.srcclient = self.srcshared
|
||||
+ process_javadoc(self, side)
|
||||
+ self.srcclient = tmp
|
||||
+ else:
|
||||
+ tmp = self.srcserver
|
||||
+ self.srcserver = self.srcshared
|
||||
+ process_javadoc(self, side)
|
||||
+ self.srcserver = tmp
|
||||
+
|
||||
|
||||
#HINT: We read the relevant CSVs
|
||||
methodsreader = csv.DictReader(open(self.csvmethods, 'r'))
|
||||
@@ -1420,6 +1445,7 @@
|
||||
|
||||
# HINT: We create the list of source directories based on the list of packages
|
||||
pkglist = filterdirs(pathsrclk[side], '*.java', append_pattern=True)
|
||||
+ pkglist = pkglist + filterdirs(self.srcshared, '*.java', append_pattern=True) #FML, Add Common folder
|
||||
dirs = ' '.join(pkglist)
|
||||
forkcmd = self.cmdastyle.format(classes=dirs, conffile=self.astyleconf)
|
||||
self.runcmd(forkcmd)
|
||||
@@ -1592,6 +1618,9 @@
|
||||
sys.exit(1)
|
||||
|
||||
for entry in newfiles:
|
||||
+ if 'commands.py' in entry[0]: #FML, Disable updating of Commands.py
|
||||
+ print 'Update to runtime/commands.py found, but disbled due to using fml'
|
||||
+ continue
|
||||
if entry[3] == 'U':
|
||||
self.logger.info('Retrieving file from server : %s', entry[0])
|
||||
cur_file = os.path.normpath(entry[0])
|
|
@ -0,0 +1,120 @@
|
|||
package cpw.mods.fml.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.discovery.ContainerType;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
|
||||
public class DummyModContainer implements ModContainer
|
||||
{
|
||||
private ModMetadata md;
|
||||
|
||||
public DummyModContainer(ModMetadata md)
|
||||
{
|
||||
this.md = md;
|
||||
}
|
||||
|
||||
public DummyModContainer()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindMetadata(MetadataCollection mc)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxyInjector findSidedProxy()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArtifactVersion> getDependants()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArtifactVersion> getDependencies()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArtifactVersion> getRequirements()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModMetadata getMetadata()
|
||||
{
|
||||
return md;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getMod()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModId()
|
||||
{
|
||||
return md.modId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return md.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSortingRules()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getSource()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion()
|
||||
{
|
||||
return md.version;
|
||||
}
|
||||
|
||||
public boolean matches(Object mod)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabledState(boolean enabled)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerBus(EventBus bus, LoadController controller)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArtifactVersion getProcessedVersion()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -26,10 +26,10 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -38,7 +38,17 @@ import java.util.zip.ZipException;
|
|||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer.SourceType;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import cpw.mods.fml.common.discovery.ContainerType;
|
||||
import cpw.mods.fml.common.registry.TickRegistry;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
|
||||
|
||||
/**
|
||||
* The main class for non-obfuscated hook handling code
|
||||
|
@ -83,68 +93,20 @@ public class FMLCommonHandler
|
|||
|
||||
private Map<String,Properties> modLanguageData=new HashMap<String,Properties>();
|
||||
|
||||
private PriorityQueue<TickQueueElement> tickHandlers = new PriorityQueue<TickQueueElement>();
|
||||
|
||||
private List<IScheduledTickHandler> scheduledTicks = new ArrayList<IScheduledTickHandler>();
|
||||
|
||||
private Set<IWorldGenerator> worldGenerators = new HashSet<IWorldGenerator>();
|
||||
/**
|
||||
* We register our delegate here
|
||||
* @param handler
|
||||
*/
|
||||
|
||||
private static class TickQueueElement implements Comparable<TickQueueElement>
|
||||
{
|
||||
static long tickCounter = 0;
|
||||
public TickQueueElement(IScheduledTickHandler ticker)
|
||||
{
|
||||
this.ticker = ticker;
|
||||
update();
|
||||
}
|
||||
@Override
|
||||
public int compareTo(TickQueueElement o)
|
||||
{
|
||||
return (int)(next - o.next);
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
next = tickCounter + Math.max(ticker.nextTickSpacing(),1);
|
||||
}
|
||||
|
||||
private long next;
|
||||
private IScheduledTickHandler ticker;
|
||||
|
||||
public boolean scheduledNow()
|
||||
{
|
||||
return tickCounter >= next;
|
||||
}
|
||||
}
|
||||
|
||||
public void beginLoading(IFMLSidedHandler handler)
|
||||
{
|
||||
sidedDelegate = handler;
|
||||
getFMLLogger().info("Attempting early MinecraftForge initialization");
|
||||
FMLLog.info("Attempting early MinecraftForge initialization");
|
||||
callForgeMethod("initialize");
|
||||
getFMLLogger().info("Completed early MinecraftForge initialization");
|
||||
FMLLog.info("Completed early MinecraftForge initialization");
|
||||
}
|
||||
|
||||
public void rescheduleTicks()
|
||||
{
|
||||
sidedDelegate.profileStart("modTickScheduling");
|
||||
TickQueueElement.tickCounter++;
|
||||
scheduledTicks.clear();
|
||||
while (true)
|
||||
{
|
||||
if (tickHandlers.size()==0 || !tickHandlers.peek().scheduledNow())
|
||||
{
|
||||
break;
|
||||
}
|
||||
TickQueueElement tickQueueElement = tickHandlers.poll();
|
||||
tickQueueElement.update();
|
||||
tickHandlers.offer(tickQueueElement);
|
||||
scheduledTicks.add(tickQueueElement.ticker);
|
||||
}
|
||||
TickRegistry.updateTickQueue(scheduledTicks);
|
||||
sidedDelegate.profileEnd();
|
||||
}
|
||||
public void tickStart(EnumSet<TickType> ticks, Object ... data)
|
||||
|
@ -189,18 +151,6 @@ public class FMLCommonHandler
|
|||
sidedDelegate.profileEnd();
|
||||
}
|
||||
|
||||
public List<IKeyHandler> gatherKeyBindings() {
|
||||
List<IKeyHandler> allKeys=new ArrayList<IKeyHandler>();
|
||||
for (ModContainer mod : Loader.getModList())
|
||||
{
|
||||
allKeys.addAll(mod.getKeys());
|
||||
}
|
||||
for (ModContainer mod : auxilliaryContainers)
|
||||
{
|
||||
allKeys.addAll(mod.getKeys());
|
||||
}
|
||||
return allKeys;
|
||||
}
|
||||
/**
|
||||
* @return the instance
|
||||
*/
|
||||
|
@ -215,7 +165,7 @@ public class FMLCommonHandler
|
|||
*/
|
||||
public ModContainer findContainerFor(Object mod)
|
||||
{
|
||||
for (ModContainer mc : Loader.getModList())
|
||||
for (ModContainer mc : Loader.instance().getActiveModList())
|
||||
{
|
||||
if (mc.matches(mod))
|
||||
{
|
||||
|
@ -321,8 +271,7 @@ public class FMLCommonHandler
|
|||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
Loader.log.warning("Error building registration list");
|
||||
Loader.log.throwing("FMLHooks", "getPacketRegistry", e);
|
||||
FMLLog.log(Level.WARNING, e, "Error building registration list");
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
@ -344,7 +293,7 @@ public class FMLCommonHandler
|
|||
*/
|
||||
public Logger getFMLLogger()
|
||||
{
|
||||
return Loader.log;
|
||||
return FMLLog.getLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -361,31 +310,6 @@ public class FMLCommonHandler
|
|||
return sidedDelegate.getMinecraftLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a modloader mod?
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public boolean isModLoaderMod(Class<?> clazz)
|
||||
{
|
||||
return sidedDelegate.isModLoaderMod(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the modloader mod
|
||||
* @param clazz
|
||||
* @param canonicalPath
|
||||
* @return
|
||||
*/
|
||||
public ModContainer loadBaseModMod(Class<?> clazz, File canonicalFile)
|
||||
{
|
||||
return sidedDelegate.loadBaseModMod(clazz, canonicalFile);
|
||||
}
|
||||
|
||||
public File getMinecraftRootDirectory() {
|
||||
return sidedDelegate.getMinecraftRootDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
|
@ -456,12 +380,6 @@ public class FMLCommonHandler
|
|||
public int fuelLookup(int itemId, int itemDamage)
|
||||
{
|
||||
int fv = 0;
|
||||
|
||||
for (ModContainer mod : Loader.getModList())
|
||||
{
|
||||
fv = Math.max(fv, mod.lookupFuelValue(itemId, itemDamage));
|
||||
}
|
||||
|
||||
return fv;
|
||||
}
|
||||
|
||||
|
@ -490,6 +408,7 @@ public class FMLCommonHandler
|
|||
|
||||
private Class<?> forge;
|
||||
private boolean noForge;
|
||||
private List<String> brandings;
|
||||
|
||||
private Class<?> findMinecraftForge()
|
||||
{
|
||||
|
@ -527,87 +446,34 @@ public class FMLCommonHandler
|
|||
* @param string
|
||||
* @return
|
||||
*/
|
||||
public String[] getBrandingStrings(String mcVersion)
|
||||
public void computeBranding()
|
||||
{
|
||||
ArrayList<String> brandings=new ArrayList<String>();
|
||||
brandings.add(mcVersion);
|
||||
brandings.add(Loader.instance().getFMLVersionString());
|
||||
String forgeVersion = (String)callForgeMethod("getVersionString");
|
||||
if (forgeVersion != null)
|
||||
if (brandings == null)
|
||||
{
|
||||
brandings.add(forgeVersion);
|
||||
Builder brd = ImmutableList.<String>builder();
|
||||
brd.add(Loader.instance().getMCVersionString());
|
||||
brd.add(Loader.instance().getFMLVersionString());
|
||||
brd.addAll(sidedDelegate.getAdditionalBrandingInformation());
|
||||
try {
|
||||
Properties props=new Properties();
|
||||
props.load(getClass().getClassLoader().getResourceAsStream("fmlbranding.properties"));
|
||||
brd.add(props.getProperty("fmlbranding"));
|
||||
} catch (Exception ex) {
|
||||
// Ignore - no branding file found
|
||||
}
|
||||
int tModCount = Loader.instance().getModList().size();
|
||||
int aModCount = Loader.instance().getActiveModList().size();
|
||||
brd.add(String.format("%d mod%s loaded, %d mod%s active", tModCount, tModCount!=1 ? "s" :"", aModCount, aModCount!=1 ? "s" :"" ));
|
||||
brandings = brd.build();
|
||||
}
|
||||
brandings.addAll(sidedDelegate.getAdditionalBrandingInformation());
|
||||
try {
|
||||
Properties props=new Properties();
|
||||
props.load(FMLCommonHandler.class.getClassLoader().getResourceAsStream("fmlbranding.properties"));
|
||||
brandings.add(props.getProperty("fmlbranding"));
|
||||
} catch (Exception ex) {
|
||||
// Ignore - no branding file found
|
||||
}
|
||||
brandings.add(String.format("%d mod%s loaded",Loader.getModList().size(), Loader.getModList().size()!=1?"s":""));
|
||||
Collections.reverse(brandings);
|
||||
return brandings.toArray(new String[brandings.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mod
|
||||
*/
|
||||
public void loadMetadataFor(ModContainer mod)
|
||||
public List<String> getBrandings()
|
||||
{
|
||||
if (mod.getSourceType()==SourceType.JAR) {
|
||||
ZipFile jar = null;
|
||||
try
|
||||
{
|
||||
jar = new ZipFile(mod.getSource());
|
||||
ZipEntry infoFile=jar.getEntry("mcmod.info");
|
||||
if (infoFile!=null) {
|
||||
InputStream input=jar.getInputStream(infoFile);
|
||||
ModMetadata data=sidedDelegate.readMetadataFrom(input, mod);
|
||||
mod.setMetadata(data);
|
||||
} else {
|
||||
getFMLLogger().fine(String.format("Failed to find mcmod.info file in %s for %s", mod.getSource().getName(), mod.getName()));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Something wrong but we don't care
|
||||
getFMLLogger().fine(String.format("Failed to find mcmod.info file in %s for %s", mod.getSource().getName(), mod.getName()));
|
||||
getFMLLogger().throwing("FMLCommonHandler", "loadMetadataFor", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (jar!=null)
|
||||
{
|
||||
try
|
||||
{
|
||||
jar.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// GO AWAY
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try
|
||||
{
|
||||
InputStream input=Loader.instance().getModClassLoader().getResourceAsStream(mod.getName()+".info");
|
||||
if (input==null) {
|
||||
input=Loader.instance().getModClassLoader().getResourceAsStream("net/minecraft/src/"+mod.getName()+".info");
|
||||
}
|
||||
if (input!=null) {
|
||||
ModMetadata data=sidedDelegate.readMetadataFrom(input, mod);
|
||||
mod.setMetadata(data);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Something wrong but we don't care
|
||||
getFMLLogger().fine(String.format("Failed to find %s.info file in %s for %s", mod.getName(), mod.getSource().getName(), mod.getName()));
|
||||
getFMLLogger().throwing("FMLCommonHandler", "loadMetadataFor", e);
|
||||
}
|
||||
if (brandings == null)
|
||||
{
|
||||
computeBranding();
|
||||
}
|
||||
return ImmutableList.copyOf(brandings);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -632,29 +498,52 @@ public class FMLCommonHandler
|
|||
|
||||
public void handleWorldGeneration(int chunkX, int chunkZ, long worldSeed, Object... data)
|
||||
{
|
||||
Random fmlRandom = new Random(worldSeed);
|
||||
long xSeed = fmlRandom.nextLong() >> 2 + 1L;
|
||||
long zSeed = fmlRandom.nextLong() >> 2 + 1L;
|
||||
fmlRandom.setSeed((xSeed * chunkX + zSeed * chunkZ) ^ worldSeed);
|
||||
|
||||
for (IWorldGenerator generator : worldGenerators)
|
||||
{
|
||||
generator.generate(fmlRandom, chunkX, chunkZ, data);
|
||||
}
|
||||
GameRegistry.generateWorld(chunkX, chunkZ, worldSeed, data);
|
||||
}
|
||||
|
||||
public void registerTickHandler(ITickHandler handler)
|
||||
public void onPostServerTick()
|
||||
{
|
||||
registerScheduledTickHandler(new SingleIntervalHandler(handler));
|
||||
tickEnd(EnumSet.of(TickType.GAME));
|
||||
}
|
||||
|
||||
public void registerScheduledTickHandler(IScheduledTickHandler handler)
|
||||
/**
|
||||
* Every tick just after world and other ticks occur
|
||||
*/
|
||||
public void onPostWorldTick(Object world)
|
||||
{
|
||||
tickHandlers.add(new TickQueueElement(handler));
|
||||
tickEnd(EnumSet.of(TickType.WORLD), world);
|
||||
}
|
||||
|
||||
public void registerWorldGenerator(IWorldGenerator generator)
|
||||
public void onPreServerTick()
|
||||
{
|
||||
worldGenerators.add(generator);
|
||||
tickStart(EnumSet.of(TickType.GAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Every tick just before world and other ticks occur
|
||||
*/
|
||||
public void onPreWorldTick(Object world)
|
||||
{
|
||||
tickStart(EnumSet.of(TickType.WORLD), world);
|
||||
}
|
||||
|
||||
public void onWorldLoadTick()
|
||||
{
|
||||
tickStart(EnumSet.of(TickType.WORLDLOAD));
|
||||
}
|
||||
|
||||
public void handleServerStarting(MinecraftServer server)
|
||||
{
|
||||
Loader.instance().serverStarting(server);
|
||||
}
|
||||
|
||||
public void handleServerStarted()
|
||||
{
|
||||
Loader.instance().serverStarted();
|
||||
}
|
||||
|
||||
public void handleServerStopping()
|
||||
{
|
||||
Loader.instance().serverStopping();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class FMLDummyContainer extends DummyModContainer
|
||||
{
|
||||
public FMLDummyContainer()
|
||||
{
|
||||
super(new ModMetadata());
|
||||
ModMetadata meta = getMetadata();
|
||||
meta.modId="FML";
|
||||
meta.name="Forge Mod Loader";
|
||||
meta.version=Loader.instance().getFMLVersionString();
|
||||
meta.credits="Made possible with help from many people";
|
||||
meta.authorList=Arrays.asList("cpw, LexManos");
|
||||
meta.description="The Forge Mod Loader provides the ability for systems to load mods " +
|
||||
"from the file system. It also provides key capabilities for mods to be able " +
|
||||
"to cooperate and provide a good modding environment. " +
|
||||
"The mod loading system is compatible with ModLoader, all your ModLoader " +
|
||||
"mods should work.";
|
||||
meta.url="https://github.com/cpw/FML/wiki";
|
||||
meta.updateUrl="https://github.com/cpw/FML/wiki";
|
||||
meta.screenshots=new String[0];
|
||||
meta.logoFile="";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package cpw.mods.fml.common;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class FMLLog
|
||||
{
|
||||
private static cpw.mods.fml.relauncher.FMLLog coreLog = cpw.mods.fml.relauncher.FMLLog.log;
|
||||
|
||||
public static void log(Level level, String format, Object... data)
|
||||
{
|
||||
coreLog.log(level, String.format(format, data));
|
||||
}
|
||||
|
||||
public static void log(Level level, Throwable ex, String format, Object... data)
|
||||
{
|
||||
coreLog.log(level, String.format(format, data), ex);
|
||||
}
|
||||
|
||||
public static void severe(String format, Object... data)
|
||||
{
|
||||
log(Level.SEVERE, format, data);
|
||||
}
|
||||
|
||||
public static void warning(String format, Object... data)
|
||||
{
|
||||
log(Level.WARNING, format, data);
|
||||
}
|
||||
|
||||
public static void info(String format, Object... data)
|
||||
{
|
||||
log(Level.INFO, format, data);
|
||||
}
|
||||
|
||||
public static void fine(String format, Object... data)
|
||||
{
|
||||
log(Level.FINE, format, data);
|
||||
}
|
||||
|
||||
public static void finer(String format, Object... data)
|
||||
{
|
||||
log(Level.FINER, format, data);
|
||||
}
|
||||
|
||||
public static void finest(String format, Object... data)
|
||||
{
|
||||
log(Level.FINEST, format, data);
|
||||
}
|
||||
public static Logger getLogger()
|
||||
{
|
||||
return coreLog.getLogger();
|
||||
}
|
||||
}
|
|
@ -13,111 +13,76 @@
|
|||
package cpw.mods.fml.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.Mod.Block;
|
||||
import cpw.mods.fml.common.Mod.Instance;
|
||||
import cpw.mods.fml.common.Mod.Metadata;
|
||||
import cpw.mods.fml.common.discovery.ContainerType;
|
||||
import cpw.mods.fml.common.event.FMLConstructionEvent;
|
||||
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.common.registry.FMLRegistry;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||
|
||||
public class FMLModContainer implements ModContainer
|
||||
{
|
||||
private Mod modDescriptor;
|
||||
private Object modInstance;
|
||||
private File source;
|
||||
private ModMetadata modMetadata;
|
||||
private String className;
|
||||
private Map<String, Object> descriptor;
|
||||
private boolean enabled = true;
|
||||
private List<ArtifactVersion> requirements;
|
||||
private List<ArtifactVersion> dependencies;
|
||||
private List<ArtifactVersion> dependants;
|
||||
private boolean overridesMetadata;
|
||||
private EventBus eventBus;
|
||||
private LoadController controller;
|
||||
private Multimap<Class<? extends Annotation>, Object> annotations;
|
||||
private DefaultArtifactVersion processedVersion;
|
||||
|
||||
public FMLModContainer(String dummy)
|
||||
public FMLModContainer(String className, File modSource, Map<String,Object> modDescriptor)
|
||||
{
|
||||
this(new File(dummy));
|
||||
}
|
||||
public FMLModContainer(File source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public FMLModContainer(Class<?> clazz)
|
||||
{
|
||||
if (clazz == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
modDescriptor = clazz.getAnnotation(Mod.class);
|
||||
|
||||
try
|
||||
{
|
||||
modInstance = clazz.newInstance();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.className = className;
|
||||
this.source = modSource;
|
||||
this.descriptor = modDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsPreInit()
|
||||
public String getModId()
|
||||
{
|
||||
return modDescriptor.wantsPreInit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsPostInit()
|
||||
{
|
||||
return modDescriptor.wantsPostInit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInit()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public static ModContainer buildFor(Class<?> clazz)
|
||||
{
|
||||
return new FMLModContainer(clazz);
|
||||
return (String) descriptor.get("modid");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return modMetadata.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModState getModState()
|
||||
public String getVersion()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextState()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
@Override
|
||||
public String getSortingRules()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object mod)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
return modMetadata.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -126,267 +91,250 @@ public class FMLModContainer implements ModContainer
|
|||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getMod()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lookupFuelValue(int itemId, int itemDamage)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsPickupNotification()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPickupNotifier getPickupNotifier()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#wantsToDispense()
|
||||
*/
|
||||
@Override
|
||||
public boolean wantsToDispense()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getDispenseHandler()
|
||||
*/
|
||||
@Override
|
||||
public IDispenseHandler getDispenseHandler()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#wantsCraftingNotification()
|
||||
*/
|
||||
@Override
|
||||
public boolean wantsCraftingNotification()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getCraftingHandler()
|
||||
*/
|
||||
@Override
|
||||
public ICraftingHandler getCraftingHandler()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getDependencies()
|
||||
*/
|
||||
@Override
|
||||
public List<String> getDependencies()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getPreDepends()
|
||||
*/
|
||||
@Override
|
||||
public List<String> getPreDepends()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getPostDepends()
|
||||
*/
|
||||
@Override
|
||||
public List<String> getPostDepends()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return new ArrayList<String>(0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getSource().getName();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#wantsNetworkPackets()
|
||||
*/
|
||||
@Override
|
||||
public boolean wantsNetworkPackets()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getNetworkHandler()
|
||||
*/
|
||||
@Override
|
||||
public INetworkHandler getNetworkHandler()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#ownsNetworkChannel(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean ownsNetworkChannel(String channel)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#wantsConsoleCommands()
|
||||
*/
|
||||
@Override
|
||||
public boolean wantsConsoleCommands()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getConsoleHandler()
|
||||
*/
|
||||
@Override
|
||||
public IConsoleHandler getConsoleHandler()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#wantsPlayerTracking()
|
||||
*/
|
||||
@Override
|
||||
public boolean wantsPlayerTracking()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getPlayerTracker()
|
||||
*/
|
||||
@Override
|
||||
public IPlayerTracker getPlayerTracker()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getKeys()
|
||||
*/
|
||||
@Override
|
||||
public List<IKeyHandler> getKeys()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getSourceType()
|
||||
*/
|
||||
@Override
|
||||
public SourceType getSourceType()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#setSourceType(cpw.mods.fml.common.ModContainer.SourceType)
|
||||
*/
|
||||
@Override
|
||||
public void setSourceType(SourceType type)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getMetadata()
|
||||
*/
|
||||
@Override
|
||||
public ModMetadata getMetadata()
|
||||
{
|
||||
return modMetadata;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#setMetadata(cpw.mods.fml.common.ModMetadata)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setMetadata(ModMetadata meta)
|
||||
public void bindMetadata(MetadataCollection mc)
|
||||
{
|
||||
this.modMetadata=meta;
|
||||
modMetadata = mc.getMetadataForId(getModId(), descriptor);
|
||||
|
||||
if (descriptor.containsKey("usesMetadata"))
|
||||
{
|
||||
overridesMetadata = !((Boolean)descriptor.get("usesMetadata")).booleanValue();
|
||||
}
|
||||
|
||||
if (overridesMetadata || !modMetadata.useDependencyInformation)
|
||||
{
|
||||
List<ArtifactVersion> requirements = Lists.newArrayList();
|
||||
List<ArtifactVersion> dependencies = Lists.newArrayList();
|
||||
List<ArtifactVersion> dependants = Lists.newArrayList();
|
||||
Loader.instance().computeDependencies((String) descriptor.get("dependencies"), requirements, dependencies, dependants);
|
||||
modMetadata.requiredMods = requirements;
|
||||
modMetadata.dependencies = dependencies;
|
||||
modMetadata.dependants = dependants;
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#gatherRenderers(java.util.Map)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void gatherRenderers(Map renderers)
|
||||
public void setEnabledState(boolean enabled)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
this.enabled = enabled;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#requestAnimations()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void requestAnimations()
|
||||
public List<ArtifactVersion> getRequirements()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
return modMetadata.requiredMods;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getVersion()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String getVersion()
|
||||
public List<ArtifactVersion> getDependencies()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return modMetadata.dependencies;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#findSidedProxy()
|
||||
*/
|
||||
|
||||
@Override
|
||||
public List<ArtifactVersion> getDependants()
|
||||
{
|
||||
return modMetadata.dependants;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSortingRules()
|
||||
{
|
||||
return modMetadata.printableSortingRules();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object mod)
|
||||
{
|
||||
return mod == modInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getMod()
|
||||
{
|
||||
return modInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxyInjector findSidedProxy()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#keyBindEvernt(java.lang.Object)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void keyBindEvent(Object keyBinding)
|
||||
public boolean registerBus(EventBus bus, LoadController controller)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
if (this.enabled)
|
||||
{
|
||||
FMLLog.fine("Enabling mod %s", getModId());
|
||||
this.eventBus = bus;
|
||||
this.controller = controller;
|
||||
eventBus.register(this);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Multimap<Class<? extends Annotation>, Object> gatherAnnotations(Class<?> clazz) throws Exception
|
||||
{
|
||||
Multimap<Class<? extends Annotation>,Object> anns = ArrayListMultimap.create();
|
||||
|
||||
for (Field f : clazz.getDeclaredFields())
|
||||
{
|
||||
for (Annotation a : f.getAnnotations())
|
||||
{
|
||||
f.setAccessible(true);
|
||||
anns.put(a.annotationType(), f);
|
||||
}
|
||||
}
|
||||
|
||||
for (Method m : clazz.getDeclaredMethods())
|
||||
{
|
||||
for (Annotation a : m.getAnnotations())
|
||||
{
|
||||
Class<?>[] paramTypes;
|
||||
if (a.annotationType() == Mod.PreInit.class)
|
||||
{
|
||||
paramTypes = Mod.PreInit.paramTypes;
|
||||
}
|
||||
else if (a.annotationType() == Mod.Init.class)
|
||||
{
|
||||
paramTypes = Mod.Init.paramTypes;
|
||||
}
|
||||
else if (a.annotationType() == Mod.PostInit.class)
|
||||
{
|
||||
paramTypes = Mod.PostInit.paramTypes;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (Arrays.equals(m.getParameterTypes(), paramTypes))
|
||||
{
|
||||
m.setAccessible(true);
|
||||
anns.put(a.annotationType(), m);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.severe("The mod %s appears to have an invalid method annotation %s. This annotation can only apply to methods with argument types %s -it will not be called", getModId(), a.annotationType().getSimpleName(), Arrays.toString(paramTypes));
|
||||
}
|
||||
}
|
||||
}
|
||||
return anns;
|
||||
}
|
||||
|
||||
private void processFieldAnnotations() throws Exception
|
||||
{
|
||||
// Instance annotation
|
||||
for (Object o : annotations.get(Instance.class))
|
||||
{
|
||||
Field f = (Field) o;
|
||||
f.set(modInstance, modInstance);
|
||||
}
|
||||
|
||||
for (Object o : annotations.get(Metadata.class))
|
||||
{
|
||||
Field f = (Field) o;
|
||||
f.set(modInstance, modMetadata);
|
||||
}
|
||||
|
||||
for (Object o : annotations.get(Block.class))
|
||||
{
|
||||
Field f = (Field) o;
|
||||
f.set(modInstance, GameRegistry.buildBlock(this, f.getType(), f.getAnnotation(Block.class)));
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void constructMod(FMLConstructionEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
ModClassLoader modClassLoader = event.getModClassLoader();
|
||||
modClassLoader.addFile(source);
|
||||
Class<?> clazz = Class.forName(className, true, modClassLoader);
|
||||
annotations = gatherAnnotations(clazz);
|
||||
modInstance = clazz.newInstance();
|
||||
processFieldAnnotations();
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
controller.errorOccurred(this, e);
|
||||
Throwables.propagateIfPossible(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void preInitMod(FMLPreInitializationEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (Object o : annotations.get(Mod.PreInit.class))
|
||||
{
|
||||
Method m = (Method) o;
|
||||
m.invoke(modInstance, event);
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
controller.errorOccurred(this, t);
|
||||
Throwables.propagateIfPossible(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void initMod(FMLInitializationEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (Object o : annotations.get(Mod.Init.class))
|
||||
{
|
||||
Method m = (Method) o;
|
||||
m.invoke(modInstance, event);
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
controller.errorOccurred(this, t);
|
||||
Throwables.propagateIfPossible(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void postInitMod(FMLPostInitializationEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (Object o : annotations.get(Mod.PostInit.class))
|
||||
{
|
||||
Method m = (Method) o;
|
||||
m.invoke(modInstance, event);
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
controller.errorOccurred(this, t);
|
||||
Throwables.propagateIfPossible(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArtifactVersion getProcessedVersion()
|
||||
{
|
||||
if (processedVersion == null)
|
||||
{
|
||||
processedVersion = new DefaultArtifactVersion(getModId(), getVersion());
|
||||
}
|
||||
return processedVersion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class FMLModLoaderContainer extends FMLModContainer
|
||||
{
|
||||
|
||||
/**
|
||||
* @param dummy
|
||||
*/
|
||||
public FMLModLoaderContainer()
|
||||
{
|
||||
super("Forge Mod Loader");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.FMLModContainer#getMetadata()
|
||||
*/
|
||||
@Override
|
||||
public ModMetadata getMetadata()
|
||||
{
|
||||
if (super.getMetadata()==null) {
|
||||
ModMetadata md=new ModMetadata(this);
|
||||
setMetadata(md);
|
||||
md.name="Forge Mod Loader";
|
||||
md.version=Loader.instance().getFMLVersionString();
|
||||
md.credits="Made possible with help from many people";
|
||||
md.authorList=Arrays.asList("cpw, LexManos");
|
||||
md.description="The Forge Mod Loader provides the ability for systems to load mods " +
|
||||
"from the file system. It also provides key capabilities for mods to be able " +
|
||||
"to cooperate and provide a good modding environment. " +
|
||||
"The mod loading system is compatible with ModLoader, all your ModLoader " +
|
||||
"mods should work.";
|
||||
md.url="https://github.com/cpw/FML/wiki";
|
||||
md.updateUrl="https://github.com/cpw/FML/wiki";
|
||||
md.screenshots=new String[0];
|
||||
md.logoFile="";
|
||||
}
|
||||
return super.getMetadata();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.FMLModContainer#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "Forge Mod Loader";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.FMLModContainer#getVersion()
|
||||
*/
|
||||
@Override
|
||||
public String getVersion()
|
||||
{
|
||||
return Loader.instance().getFMLVersionString();
|
||||
}
|
||||
}
|
|
@ -15,6 +15,6 @@ package cpw.mods.fml.common;
|
|||
|
||||
public interface IDispenseHandler
|
||||
{
|
||||
boolean dispense(double x, double y, double z, byte xVelocity, byte zVelocity, Object... data);
|
||||
boolean dispense(double x, double y, double z, int xVelocity, int zVelocity, Object... data);
|
||||
|
||||
}
|
||||
|
|
|
@ -13,19 +13,26 @@ import cpw.mods.fml.common.modloader.ModProperty;
|
|||
public interface IFMLSidedHandler
|
||||
{
|
||||
Logger getMinecraftLogger();
|
||||
File getMinecraftRootDirectory();
|
||||
boolean isModLoaderMod(Class<?> clazz);
|
||||
ModContainer loadBaseModMod(Class<?> clazz, File canonicalFile);
|
||||
|
||||
Object getMinecraftInstance();
|
||||
|
||||
String getCurrentLanguage();
|
||||
|
||||
Properties getCurrentLanguageTable();
|
||||
|
||||
String getObjectName(Object minecraftObject);
|
||||
ModMetadata readMetadataFrom(InputStream input, ModContainer mod) throws Exception;
|
||||
|
||||
void profileStart(String profileLabel);
|
||||
|
||||
void profileEnd();
|
||||
|
||||
ModProperty getModLoaderPropertyFor(Field f);
|
||||
|
||||
List<String> getAdditionalBrandingInformation();
|
||||
|
||||
Side getSide();
|
||||
|
||||
ProxyInjector findSidedProxyOn(BaseMod mod);
|
||||
|
||||
void haltGame(String message, Throwable exception);
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
/**
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public interface IKeyHandler
|
||||
{
|
||||
|
||||
Object getKeyBinding();
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
ModContainer getOwningContainer();
|
||||
|
||||
void onEndTick();
|
||||
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
package cpw.mods.fml.common;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.event.FMLStateEvent;
|
||||
|
||||
public class LoadController
|
||||
{
|
||||
private Loader loader;
|
||||
private EventBus masterChannel;
|
||||
private ImmutableMap<String,EventBus> eventChannels;
|
||||
private LoaderState state;
|
||||
private Multimap<String, ModState> modStates = ArrayListMultimap.create();
|
||||
private Multimap<String, Throwable> errors = ArrayListMultimap.create();
|
||||
private Map<String, ModContainer> modList;
|
||||
private List<ModContainer> activeModList = Lists.newArrayList();
|
||||
private String activeContainer;
|
||||
|
||||
public LoadController(Loader loader)
|
||||
{
|
||||
this.loader = loader;
|
||||
this.modList = loader.getIndexedModList();
|
||||
this.masterChannel = new EventBus("FMLMainChannel");
|
||||
this.masterChannel.register(this);
|
||||
|
||||
Builder<String, EventBus> eventBus = ImmutableMap.builder();
|
||||
|
||||
for (ModContainer mod : loader.getModList())
|
||||
{
|
||||
EventBus bus = new EventBus(mod.getModId());
|
||||
boolean isActive = mod.registerBus(bus, this);
|
||||
if (isActive)
|
||||
{
|
||||
FMLLog.fine("Activating mod %s", mod.getModId());
|
||||
activeModList.add(mod);
|
||||
modStates.put(mod.getModId(), ModState.UNLOADED);
|
||||
eventBus.put(mod.getModId(), bus);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.warning("Mod %s has been disabled through configuration", mod.getModId());
|
||||
modStates.put(mod.getModId(), ModState.UNLOADED);
|
||||
modStates.put(mod.getModId(), ModState.DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
eventChannels = eventBus.build();
|
||||
|
||||
state = LoaderState.NOINIT;
|
||||
}
|
||||
|
||||
public void distributeStateMessage(LoaderState state, Object... eventData)
|
||||
{
|
||||
if (state.hasEvent())
|
||||
{
|
||||
masterChannel.post(state.getEvent(eventData));
|
||||
}
|
||||
}
|
||||
|
||||
public void transition(LoaderState desiredState)
|
||||
{
|
||||
LoaderState oldState = state;
|
||||
state = state.transition(!errors.isEmpty());
|
||||
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());
|
||||
}
|
||||
|
||||
// Throw embedding the first error (usually the only one)
|
||||
throw new LoaderException(errors.values().iterator().next());
|
||||
}
|
||||
}
|
||||
|
||||
public ModContainer activeContainer()
|
||||
{
|
||||
return activeContainer!=null ? modList.get(activeContainer) : null;
|
||||
}
|
||||
@Subscribe
|
||||
public void propogateStateMessage(FMLStateEvent stateEvent)
|
||||
{
|
||||
for (Map.Entry<String,EventBus> entry : eventChannels.entrySet())
|
||||
{
|
||||
activeContainer = entry.getKey();
|
||||
stateEvent.applyModContainer(activeContainer());
|
||||
entry.getValue().post(stateEvent);
|
||||
activeContainer = null;
|
||||
if (!errors.containsKey(entry.getKey()))
|
||||
{
|
||||
modStates.put(entry.getKey(), stateEvent.getModState());
|
||||
}
|
||||
else
|
||||
{
|
||||
modStates.put(entry.getKey(), ModState.ERRORED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void errorOccurred(ModContainer modContainer, Throwable exception)
|
||||
{
|
||||
errors.put(modContainer.getModId(), exception);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
public List<ModContainer> getActiveModList()
|
||||
{
|
||||
return activeModList;
|
||||
}
|
||||
|
||||
public ModState getModState(ModContainer selectedMod)
|
||||
{
|
||||
return Iterables.getLast(modStates.get(selectedMod.getModId()), ModState.AVAILABLE);
|
||||
}
|
||||
}
|
|
@ -14,7 +14,8 @@
|
|||
package cpw.mods.fml.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
|
@ -22,69 +23,76 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.ConsoleHandler;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer.SourceType;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Splitter.MapSplitter;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.discovery.ContainerType;
|
||||
import cpw.mods.fml.common.discovery.ModDiscoverer;
|
||||
import cpw.mods.fml.common.functions.ModIdFunction;
|
||||
import cpw.mods.fml.common.toposort.ModSorter;
|
||||
import cpw.mods.fml.common.toposort.ModSortingException;
|
||||
import cpw.mods.fml.common.toposort.TopologicalSort;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.VersionParser;
|
||||
|
||||
/**
|
||||
* The loader class performs the actual loading of the mod code from disk.
|
||||
*
|
||||
* <p>There are several {@link State}s to mod loading, triggered in two different stages from the FML handler code's hooks into the
|
||||
* minecraft code.</p>
|
||||
* <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>
|
||||
*
|
||||
* <ol>
|
||||
* <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>
|
||||
* <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>
|
||||
* <li>UP. The Loader is complete</li>
|
||||
* <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>
|
||||
* <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>
|
||||
* </ol>
|
||||
*
|
||||
* Phase 1 code triggers the LOADING and PREINIT states. Phase 2 code triggers the INIT and POSTINIT states.
|
||||
* Phase 1 code triggers the LOADING and PREINIT states. Phase 2 code triggers
|
||||
* the INIT and POSTINIT states.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class Loader
|
||||
{
|
||||
private static Pattern zipJar = Pattern.compile("(.+).(zip|jar)$");
|
||||
private static Pattern modClass = Pattern.compile("(.+/|)(mod\\_[^\\s$]+).class$");
|
||||
|
||||
/**
|
||||
* The state enum used to help track state progression for the loader
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
private enum State
|
||||
{
|
||||
NOINIT, LOADING, PREINIT, INIT, POSTINIT, UP, ERRORED
|
||||
};
|
||||
|
||||
private static final Splitter DEPENDENCYPARTSPLITTER = Splitter.on(":").omitEmptyStrings().trimResults();
|
||||
private static final Splitter DEPENDENCYSPLITTER = Splitter.on(";").omitEmptyStrings().trimResults();
|
||||
/**
|
||||
* The singleton instance
|
||||
*/
|
||||
private static Loader instance;
|
||||
/**
|
||||
* Our special logger for logging issues to. We copy various assets from the Minecraft logger to acheive a similar appearance.
|
||||
*/
|
||||
public static Logger log = Logger.getLogger("ForgeModLoader");
|
||||
|
||||
|
||||
/**
|
||||
* Build information for tracking purposes.
|
||||
*/
|
||||
|
@ -95,10 +103,6 @@ public class Loader
|
|||
private static String mccversion;
|
||||
private static String mcsversion;
|
||||
|
||||
/**
|
||||
* The {@link State} of the loader
|
||||
*/
|
||||
private State state;
|
||||
/**
|
||||
* The class loader we load the mods into.
|
||||
*/
|
||||
|
@ -119,8 +123,14 @@ public class Loader
|
|||
* The canonical minecraft directory
|
||||
*/
|
||||
private File canonicalMinecraftDir;
|
||||
/**
|
||||
* The captured error
|
||||
*/
|
||||
private Exception capturedError;
|
||||
private File canonicalModsDir;
|
||||
private LoadController modController;
|
||||
|
||||
private static File minecraftDir;
|
||||
|
||||
public static Loader instance()
|
||||
{
|
||||
|
@ -132,188 +142,129 @@ public class Loader
|
|||
return instance;
|
||||
}
|
||||
|
||||
public static void injectData(Object... data)
|
||||
{
|
||||
major = (String) data[0];
|
||||
minor = (String) data[1];
|
||||
rev = (String) data[2];
|
||||
build = (String) data[3];
|
||||
mccversion = (String) data[4];
|
||||
mcsversion = (String) data[5];
|
||||
minecraftDir = (File) data[6];
|
||||
}
|
||||
|
||||
private Loader()
|
||||
{
|
||||
FMLLogFormatter formatter=new FMLLogFormatter();
|
||||
if (FMLCommonHandler.instance().getMinecraftLogger()!=null) {
|
||||
Loader.log.setParent(FMLCommonHandler.instance().getMinecraftLogger());
|
||||
} else {
|
||||
ConsoleHandler ch=new ConsoleHandler();
|
||||
Loader.log.setUseParentHandlers(false);
|
||||
Loader.log.addHandler(ch);
|
||||
ch.setFormatter(formatter);
|
||||
|
||||
}
|
||||
Loader.log.setLevel(Level.ALL);
|
||||
try
|
||||
{
|
||||
File logPath=new File(FMLCommonHandler.instance().getMinecraftRootDirectory().getCanonicalPath(),"ForgeModLoader-%g.log");
|
||||
FileHandler fileHandler = new FileHandler(logPath.getPath(), 0, 3);
|
||||
// We're stealing minecraft's log formatter
|
||||
fileHandler.setFormatter(new FMLLogFormatter());
|
||||
fileHandler.setLevel(Level.ALL);
|
||||
Loader.log.addHandler(fileHandler);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Whatever - give up
|
||||
}
|
||||
InputStream stream = Loader.class.getClassLoader().getResourceAsStream("fmlversion.properties");
|
||||
Properties properties = new Properties();
|
||||
|
||||
if (stream != null) {
|
||||
try {
|
||||
properties.load(stream);
|
||||
major = properties.getProperty("fmlbuild.major.number","none");
|
||||
minor = properties.getProperty("fmlbuild.minor.number","none");
|
||||
rev = properties.getProperty("fmlbuild.revision.number","none");
|
||||
build = properties.getProperty("fmlbuild.build.number","none");
|
||||
mccversion = properties.getProperty("fmlbuild.mcclientversion","none");
|
||||
mcsversion = properties.getProperty("fmlbuild.mcserverversion","none");
|
||||
} catch (IOException ex) {
|
||||
Loader.log.log(Level.SEVERE,"Could not get FML version information - corrupted installation detected!", ex);
|
||||
throw new LoaderException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
log.info(String.format("Forge Mod Loader version %s.%s.%s.%s for Minecraft c:%s, s:%s loading", major, minor, rev, build, mccversion, mcsversion));
|
||||
modClassLoader = new ModClassLoader();
|
||||
modClassLoader = new ModClassLoader(getClass().getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
private void sortModList()
|
||||
{
|
||||
log.fine("Verifying mod dependencies are satisfied");
|
||||
|
||||
for (ModContainer mod : mods)
|
||||
{
|
||||
if (!namedMods.keySet().containsAll(mod.getDependencies()))
|
||||
{
|
||||
log.severe(String.format("The mod %s requires mods %s to be available, one or more are not", mod.getName(), mod.getDependencies()));
|
||||
LoaderException le = new LoaderException();
|
||||
log.throwing("Loader", "sortModList", le);
|
||||
throw new LoaderException();
|
||||
}
|
||||
}
|
||||
|
||||
log.fine("All dependencies are satisfied");
|
||||
ModSorter sorter = new ModSorter(mods, namedMods);
|
||||
|
||||
FMLLog.fine("Verifying mod requirements are satisfied");
|
||||
try
|
||||
{
|
||||
log.fine("Sorting mods into an ordered list");
|
||||
mods = sorter.sort();
|
||||
log.fine("Sorted mod list:");
|
||||
Map<String, ArtifactVersion> modVersions = Maps.newHashMap();
|
||||
for (ModContainer mod : mods)
|
||||
{
|
||||
log.fine(String.format("\t%s: %s (%s)", mod.getName(), mod.getSource().getName(), mod.getSortingRules()));
|
||||
modVersions.put(mod.getModId(), mod.getProcessedVersion());
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException iae)
|
||||
{
|
||||
log.severe("A dependency cycle was detected in the input mod set so they cannot be loaded in order");
|
||||
log.throwing("Loader", "sortModList", iae);
|
||||
throw new LoaderException(iae);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The first mod initialization stage, performed immediately after the jar files and mod classes are loaded,
|
||||
* {@link State#PREINIT}. The mods are configured from their configuration data and instantiated (for BaseMod mods).
|
||||
*/
|
||||
private void preModInit()
|
||||
{
|
||||
state = State.PREINIT;
|
||||
log.fine("Beginning mod pre-initialization");
|
||||
|
||||
for (ModContainer mod : mods)
|
||||
{
|
||||
if (mod.wantsPreInit())
|
||||
for (ModContainer mod : mods)
|
||||
{
|
||||
log.finer(String.format("Pre-initializing %s", mod.getSource()));
|
||||
try
|
||||
ImmutableList<ArtifactVersion> allDeps = ImmutableList.<ArtifactVersion>builder().addAll(mod.getDependants()).addAll(mod.getDependencies()).build();
|
||||
for (ArtifactVersion v : allDeps)
|
||||
{
|
||||
mod.preInit();
|
||||
if (modVersions.containsKey(v.getLabel()))
|
||||
{
|
||||
if (!v.containsVersion(modVersions.get(v.getLabel())))
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, "The mod %s (%s) requires mods %s to be available, one or more are not", mod.getModId(), mod.getName(), allDeps);
|
||||
throw new LoaderException();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
log.log(Level.SEVERE, String.format("The mod from file %s has failed to load. This is likely a mod installation error.", mod.getSource().getName()), t);
|
||||
throw new LoaderException(t);
|
||||
}
|
||||
namedMods.put(mod.getName(), mod);
|
||||
}
|
||||
mod.nextState();
|
||||
}
|
||||
// Link up mod metadatas
|
||||
|
||||
for (ModContainer mod : mods) {
|
||||
if (mod.getMetadata()!=null) {
|
||||
mod.getMetadata().associate(namedMods);
|
||||
}
|
||||
|
||||
FMLCommonHandler.instance().injectSidedProxyDelegate(mod);
|
||||
}
|
||||
log.fine("Mod pre-initialization complete");
|
||||
}
|
||||
FMLLog.fine("All mod requirements are satisfied");
|
||||
|
||||
/**
|
||||
* The main mod initialization stage, performed on the sorted mod list.
|
||||
*/
|
||||
private void modInit()
|
||||
{
|
||||
state = State.INIT;
|
||||
log.fine("Beginning mod initialization");
|
||||
ModSorter sorter = new ModSorter(mods, namedMods);
|
||||
|
||||
for (ModContainer mod : mods)
|
||||
{
|
||||
log.finer(String.format("Initializing %s", mod.getName()));
|
||||
mod.init();
|
||||
mod.nextState();
|
||||
}
|
||||
|
||||
log.fine("Mod initialization complete");
|
||||
}
|
||||
|
||||
private void postModInit()
|
||||
{
|
||||
state = State.POSTINIT;
|
||||
log.fine("Beginning mod post-initialization");
|
||||
|
||||
for (ModContainer mod : mods)
|
||||
{
|
||||
if (mod.wantsPostInit())
|
||||
try
|
||||
{
|
||||
log.finer(String.format("Post-initializing %s", mod.getName()));
|
||||
mod.postInit();
|
||||
mod.nextState();
|
||||
FMLLog.fine("Sorting mods into an ordered list");
|
||||
mods = sorter.sort();
|
||||
FMLLog.fine("Mod sorting completed successfully");
|
||||
}
|
||||
catch (ModSortingException sortException)
|
||||
{
|
||||
FMLLog.severe("A dependency cycle was detected in the input mod set so an ordering cannot be determined");
|
||||
FMLLog.severe("The visited mod list is %s", sortException.getExceptionData().getVisitedNodes());
|
||||
FMLLog.severe("The first mod in the cycle is %s", sortException.getExceptionData().getFirstBadNode());
|
||||
FMLLog.log(Level.SEVERE, sortException, "The full error");
|
||||
throw new LoaderException(sortException);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
FMLLog.fine("Mod sorting data:");
|
||||
for (ModContainer mod : mods)
|
||||
{
|
||||
FMLLog.fine("\t%s(%s): %s (%s)", mod.getModId(), mod.getName(), mod.getSource().getName(), mod.getSortingRules());
|
||||
}
|
||||
if (mods.size()==0)
|
||||
{
|
||||
FMLLog.fine("No mods found to sort");
|
||||
}
|
||||
}
|
||||
|
||||
log.fine("Mod post-initialization complete");
|
||||
}
|
||||
|
||||
/**
|
||||
* The primary loading code
|
||||
*
|
||||
* This is visited during first initialization by Minecraft to scan and load the mods
|
||||
* from all sources
|
||||
* 1. The minecraft jar itself (for loading of in jar mods- I would like to remove this if possible but forge depends on it at present)
|
||||
* 2. The mods directory with expanded subdirs, searching for mods named mod_*.class
|
||||
* 3. The mods directory for zip and jar files, searching for mod classes named mod_*.class again
|
||||
* This is visited during first initialization by Minecraft to scan and load
|
||||
* the mods from all sources 1. The minecraft jar itself (for loading of in
|
||||
* jar mods- I would like to remove this if possible but forge depends on it
|
||||
* at present) 2. The mods directory with expanded subdirs, searching for
|
||||
* mods named mod_*.class 3. The mods directory for zip and jar files,
|
||||
* searching for mod classes named mod_*.class again
|
||||
*
|
||||
* The found resources are first loaded into the {@link #modClassLoader} (always) then scanned for class resources matching the specification above.
|
||||
* The found resources are first loaded into the {@link #modClassLoader}
|
||||
* (always) then scanned for class resources matching the specification
|
||||
* above.
|
||||
*
|
||||
* If they provide the {@link Mod} annotation, they will be loaded as "FML mods", which currently is effectively a NO-OP.
|
||||
* If they are determined to be {@link BaseMod} subclasses they are loaded as such.
|
||||
* If they provide the {@link Mod} annotation, they will be loaded as
|
||||
* "FML mods", which currently is effectively a NO-OP. If they are
|
||||
* determined to be {@link BaseMod} subclasses they are loaded as such.
|
||||
*
|
||||
* Finally, if they are successfully loaded as classes, they are then added to the available mod list.
|
||||
* Finally, if they are successfully loaded as classes, they are then added
|
||||
* to the available mod list.
|
||||
*/
|
||||
private void load()
|
||||
private void identifyMods()
|
||||
{
|
||||
ModDiscoverer discoverer = new ModDiscoverer();
|
||||
FMLLog.fine("Attempting to load mods contained in the minecraft jar file and associated classes");
|
||||
discoverer.findClasspathMods(modClassLoader);
|
||||
FMLLog.fine("Minecraft jar mods loaded successfully");
|
||||
|
||||
FMLLog.info("Searching %s for mods", canonicalModsDir.getAbsolutePath());
|
||||
discoverer.findModDirMods(canonicalModsDir);
|
||||
|
||||
mods = discoverer.identifyMods();
|
||||
namedMods = Maps.uniqueIndex(mods, new ModIdFunction());
|
||||
FMLLog.info("Forge Mod Loader has identified %d mod%s to load", mods.size(), mods.size() != 1 ? "s" : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private void initializeLoader()
|
||||
{
|
||||
File minecraftDir = FMLCommonHandler.instance().getMinecraftRootDirectory();
|
||||
File modsDir = new File(minecraftDir, "mods");
|
||||
File configDir = new File(minecraftDir, "config");
|
||||
String canonicalModsPath;
|
||||
|
@ -325,313 +276,125 @@ public class Loader
|
|||
canonicalModsPath = modsDir.getCanonicalPath();
|
||||
canonicalConfigPath = configDir.getCanonicalPath();
|
||||
canonicalConfigDir = configDir.getCanonicalFile();
|
||||
canonicalModsDir = modsDir.getCanonicalFile();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
log.severe(String.format("Failed to resolve mods directory mods %s", modsDir.getAbsolutePath()));
|
||||
log.throwing("fml.server.Loader", "initialize", ioe);
|
||||
FMLLog.log(Level.SEVERE, ioe, "Failed to resolve loader directories: mods : %s ; config %s", canonicalModsDir.getAbsolutePath(),
|
||||
configDir.getAbsolutePath());
|
||||
throw new LoaderException(ioe);
|
||||
}
|
||||
|
||||
if (!modsDir.exists())
|
||||
if (!canonicalModsDir.exists())
|
||||
{
|
||||
log.fine(String.format("No mod directory found, creating one: %s", canonicalModsPath));
|
||||
|
||||
try
|
||||
FMLLog.info("No mod directory found, creating one: %s", canonicalModsPath);
|
||||
boolean dirMade = canonicalModsDir.mkdir();
|
||||
if (!dirMade)
|
||||
{
|
||||
modsDir.mkdir();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.throwing("fml.server.Loader", "initialize", e);
|
||||
throw new LoaderException(e);
|
||||
FMLLog.severe("Unable to create the mod directory %s", canonicalModsPath);
|
||||
throw new LoaderException();
|
||||
}
|
||||
FMLLog.info("Mod directory created successfully");
|
||||
}
|
||||
|
||||
if (!configDir.exists())
|
||||
if (!canonicalConfigDir.exists())
|
||||
{
|
||||
log.fine(String.format("No config directory found, creating one: %s", canonicalConfigPath));
|
||||
|
||||
try
|
||||
FMLLog.fine("No config directory found, creating one: %s", canonicalConfigPath);
|
||||
boolean dirMade = canonicalConfigDir.mkdir();
|
||||
if (!dirMade)
|
||||
{
|
||||
configDir.mkdir();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.throwing("fml.server.Loader", "initialize", e);
|
||||
throw new LoaderException(e);
|
||||
FMLLog.severe("Unable to create the config directory %s", canonicalConfigPath);
|
||||
throw new LoaderException();
|
||||
}
|
||||
FMLLog.info("Config directory created successfully");
|
||||
}
|
||||
|
||||
if (!modsDir.isDirectory())
|
||||
if (!canonicalModsDir.isDirectory())
|
||||
{
|
||||
log.severe(String.format("Attempting to load mods from %s, which is not a directory", canonicalModsPath));
|
||||
LoaderException loaderException = new LoaderException();
|
||||
log.throwing("fml.server.Loader", "initialize", loaderException);
|
||||
throw loaderException;
|
||||
FMLLog.severe("Attempting to load mods from %s, which is not a directory", canonicalModsPath);
|
||||
throw new LoaderException();
|
||||
}
|
||||
|
||||
if (!configDir.isDirectory())
|
||||
{
|
||||
log.severe(String.format("Attempting to load configuration from %s, which is not a directory", canonicalConfigPath));
|
||||
LoaderException loaderException = new LoaderException();
|
||||
log.throwing("fml.server.Loader", "initialize", loaderException);
|
||||
throw loaderException;
|
||||
}
|
||||
|
||||
state = State.LOADING;
|
||||
log.fine("Attempting to load mods contained in the minecraft jar file and associated classes");
|
||||
File[] minecraftSources=modClassLoader.getParentSources();
|
||||
if (minecraftSources.length==1 && minecraftSources[0].isFile()) {
|
||||
log.fine(String.format("Minecraft is a file at %s, loading",minecraftSources[0].getAbsolutePath()));
|
||||
attemptFileLoad(minecraftSources[0], SourceType.CLASSPATH);
|
||||
} else {
|
||||
for (int i=0; i<minecraftSources.length; i++) {
|
||||
if (minecraftSources[i].isFile()) {
|
||||
log.fine(String.format("Found a minecraft related file at %s, loading",minecraftSources[i].getAbsolutePath()));
|
||||
attemptFileLoad(minecraftSources[i], SourceType.CLASSPATH);
|
||||
} else if (minecraftSources[i].isDirectory()) {
|
||||
log.fine(String.format("Found a minecraft related directory at %s, loading",minecraftSources[i].getAbsolutePath()));
|
||||
attemptDirLoad(minecraftSources[i],"",SourceType.CLASSPATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
log.fine("Minecraft jar mods loaded successfully");
|
||||
|
||||
log.info(String.format("Loading mods from %s", canonicalModsPath));
|
||||
File[] modList = modsDir.listFiles();
|
||||
// Sort the files into alphabetical order first
|
||||
Arrays.sort(modList);
|
||||
|
||||
for (File modFile : modList)
|
||||
{
|
||||
if (modFile.isDirectory())
|
||||
{
|
||||
log.fine(String.format("Found a directory %s, attempting to load it", modFile.getName()));
|
||||
boolean modFound = attemptDirLoad(modFile,"", SourceType.DIR);
|
||||
|
||||
if (modFound)
|
||||
{
|
||||
log.fine(String.format("Directory %s loaded successfully", modFile.getName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
log.info(String.format("Directory %s contained no mods", modFile.getName()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Matcher matcher = zipJar.matcher(modFile.getName());
|
||||
|
||||
if (matcher.matches())
|
||||
{
|
||||
log.fine(String.format("Found a zip or jar file %s, attempting to load it", matcher.group(0)));
|
||||
boolean modFound = attemptFileLoad(modFile, SourceType.JAR);
|
||||
|
||||
if (modFound)
|
||||
{
|
||||
log.fine(String.format("File %s loaded successfully", matcher.group(0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
log.info(String.format("File %s contained no mods", matcher.group(0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state == State.ERRORED)
|
||||
{
|
||||
log.severe("A problem has occured during mod loading. Likely a corrupt jar is located in your mods directory");
|
||||
throw new LoaderException(capturedError);
|
||||
}
|
||||
|
||||
log.info(String.format("Forge Mod Loader has loaded %d mods", mods.size()));
|
||||
}
|
||||
|
||||
private boolean attemptDirLoad(File modDir, String path, SourceType sourceType)
|
||||
{
|
||||
if (path.length()==0) {
|
||||
extendClassLoader(modDir);
|
||||
}
|
||||
boolean foundAModClass = false;
|
||||
File[] content = modDir.listFiles(new FileFilter()
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File file)
|
||||
{
|
||||
return (file.isFile() && modClass.matcher(file.getName()).find()) || file.isDirectory();
|
||||
}
|
||||
});
|
||||
|
||||
// Always sort our content
|
||||
Arrays.sort(content);
|
||||
for (File file : content)
|
||||
{
|
||||
if (file.isDirectory()) {
|
||||
log.finest(String.format("Recursing into package %s", path+file.getName()));
|
||||
foundAModClass|=attemptDirLoad(file,path+file.getName()+".", sourceType);
|
||||
continue;
|
||||
}
|
||||
Matcher fname = modClass.matcher(file.getName());
|
||||
if (!fname.find()) {
|
||||
continue;
|
||||
}
|
||||
String clazzName=path+fname.group(2);
|
||||
try
|
||||
{
|
||||
log.fine(String.format("Found a mod class %s in directory %s, attempting to load it", clazzName, modDir.getName()));
|
||||
loadModClass(modDir, file.getName(), clazzName, sourceType);
|
||||
log.fine(String.format("Successfully loaded mod class %s", file.getName()));
|
||||
foundAModClass = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.severe(String.format("File %s failed to read properly", file.getName()));
|
||||
log.throwing("fml.server.Loader", "attemptDirLoad", e);
|
||||
state = State.ERRORED;
|
||||
capturedError = e;
|
||||
}
|
||||
}
|
||||
|
||||
return foundAModClass;
|
||||
}
|
||||
|
||||
private void loadModClass(File classSource, String classFileName, String clazzName, SourceType sourceType)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> clazz = Class.forName(clazzName, false, modClassLoader);
|
||||
|
||||
ModContainer mod=null;
|
||||
if (clazz.isAnnotationPresent(Mod.class))
|
||||
{
|
||||
// an FML mod
|
||||
log.severe("Currently, the FML mod type is disabled");
|
||||
throw new LoaderException();
|
||||
// log.fine(String.format("FML mod class %s found, loading", clazzName));
|
||||
// mod = FMLModContainer.buildFor(clazz);
|
||||
// log.fine(String.format("FML mod class %s loaded", clazzName));
|
||||
}
|
||||
else if (FMLCommonHandler.instance().isModLoaderMod(clazz))
|
||||
{
|
||||
log.fine(String.format("ModLoader BaseMod class %s found, loading", clazzName));
|
||||
mod = FMLCommonHandler.instance().loadBaseModMod(clazz, classSource.getCanonicalFile());
|
||||
log.fine(String.format("ModLoader BaseMod class %s loaded", clazzName));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unrecognized
|
||||
}
|
||||
if (mod!=null) {
|
||||
mod.setSourceType(sourceType);
|
||||
FMLCommonHandler.instance().loadMetadataFor(mod);
|
||||
mods.add(mod);
|
||||
mod.nextState();
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
log.warning(String.format("Failed to load mod class %s in %s", classFileName, classSource.getAbsoluteFile()));
|
||||
log.throwing("fml.server.Loader", "attemptLoad", e);
|
||||
throw new LoaderException(e);
|
||||
FMLLog.severe("Attempting to load configuration from %s, which is not a directory", canonicalConfigPath);
|
||||
throw new LoaderException();
|
||||
}
|
||||
}
|
||||
|
||||
private void extendClassLoader(File file)
|
||||
public List<ModContainer> getModList()
|
||||
{
|
||||
try
|
||||
{
|
||||
modClassLoader.addFile(file);
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
throw new LoaderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean attemptFileLoad(File modFile, SourceType sourceType)
|
||||
{
|
||||
extendClassLoader(modFile);
|
||||
boolean foundAModClass = false;
|
||||
|
||||
ZipFile jar = null;
|
||||
try
|
||||
{
|
||||
jar = new ZipFile(modFile);
|
||||
|
||||
for (ZipEntry ze : Collections.list(jar.entries()))
|
||||
{
|
||||
Matcher match = modClass.matcher(ze.getName());
|
||||
|
||||
if (match.matches())
|
||||
{
|
||||
String pkg = match.group(1).replace('/', '.');
|
||||
String clazzName = pkg + match.group(2);
|
||||
log.fine(String.format("Found a mod class %s in file %s, attempting to load it", clazzName, modFile.getName()));
|
||||
loadModClass(modFile, ze.getName(), clazzName, sourceType);
|
||||
log.fine(String.format("Mod class %s loaded successfully", clazzName, modFile.getName()));
|
||||
foundAModClass = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.severe(String.format("Zip file %s failed to read properly", modFile.getName()));
|
||||
log.throwing("fml.server.Loader", "attemptFileLoad", e);
|
||||
state = State.ERRORED;
|
||||
capturedError = e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (jar != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
jar.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return foundAModClass;
|
||||
}
|
||||
|
||||
public static List<ModContainer> getModList()
|
||||
{
|
||||
return instance().mods;
|
||||
return ImmutableList.copyOf(instance().mods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the hook to start mod loading. We trigger the {@link #load()} and {@link #preModInit()} phases here.
|
||||
* Finally, the mod list is frozen completely and is consider immutable from then on.
|
||||
* Called from the hook to start mod loading. We trigger the
|
||||
* {@link #identifyMods()} and {@link #preModInit()} phases here. Finally,
|
||||
* the mod list is frozen completely and is consider immutable from then on.
|
||||
*/
|
||||
public void loadMods()
|
||||
{
|
||||
state = State.NOINIT;
|
||||
mods = new ArrayList<ModContainer>();
|
||||
namedMods = new HashMap<String, ModContainer>();
|
||||
load();
|
||||
preModInit();
|
||||
initializeLoader();
|
||||
mods = Lists.newArrayList();
|
||||
namedMods = Maps.newHashMap();
|
||||
modController = new LoadController(this);
|
||||
modController.transition(LoaderState.LOADING);
|
||||
identifyMods();
|
||||
disableRequestedMods();
|
||||
sortModList();
|
||||
// Make mod list immutable
|
||||
mods = Collections.unmodifiableList(mods);
|
||||
mods = ImmutableList.copyOf(mods);
|
||||
modController.transition(LoaderState.CONSTRUCTING);
|
||||
modController.distributeStateMessage(LoaderState.CONSTRUCTING, modClassLoader);
|
||||
modController.transition(LoaderState.PREINITIALIZATION);
|
||||
modController.distributeStateMessage(LoaderState.PREINITIALIZATION);
|
||||
modController.transition(LoaderState.INITIALIZATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the initialization of the mods {@link #initializeMods()} and {@link #postModInit()} and mark ourselves up and ready to run.
|
||||
*/
|
||||
public void initializeMods()
|
||||
private void disableRequestedMods()
|
||||
{
|
||||
modInit();
|
||||
postModInit();
|
||||
for (ModContainer mod : getModList()) {
|
||||
mod.nextState();
|
||||
String disabledModList = System.getProperty("fml.disabledMods", "");
|
||||
FMLLog.fine("Received a system property request \'%s\'",disabledModList);
|
||||
Map<String, String> sysPropertyStateList = Splitter.on(CharMatcher.anyOf(";:"))
|
||||
.omitEmptyStrings().trimResults().withKeyValueSeparator("=")
|
||||
.split(disabledModList);
|
||||
FMLLog.fine("System property request managing the state of %d mods", sysPropertyStateList.size());
|
||||
Map<String, String> modStates = Maps.newHashMap();
|
||||
|
||||
File disabledModFile = new File(canonicalConfigDir, "fmlModState.properties");
|
||||
Properties disabledModListProperties = new Properties();
|
||||
if (disabledModFile.exists() && disabledModFile.isFile())
|
||||
{
|
||||
FMLLog.fine("Found a mod state file %s", disabledModFile.getName());
|
||||
try
|
||||
{
|
||||
disabledModListProperties.load(new FileReader(disabledModFile));
|
||||
FMLLog.fine("Loaded states for %d mods from file", disabledModListProperties.size());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLLog.log(Level.INFO, e, "An error occurred reading the fmlModState.properties file");
|
||||
}
|
||||
}
|
||||
modStates.putAll(Maps.fromProperties(disabledModListProperties));
|
||||
modStates.putAll(sysPropertyStateList);
|
||||
FMLLog.fine("After merging, found state information for %d mods", modStates.size());
|
||||
|
||||
Map<String, Boolean> isEnabled = Maps.transformValues(modStates, new Function<String, Boolean>()
|
||||
{
|
||||
public Boolean apply(String input)
|
||||
{
|
||||
return !Boolean.parseBoolean(input);
|
||||
}
|
||||
});
|
||||
|
||||
for (Map.Entry<String, Boolean> entry : isEnabled.entrySet())
|
||||
{
|
||||
if (namedMods.containsKey(entry.getKey()))
|
||||
{
|
||||
FMLLog.info("Setting mod %s to enabled state %b", entry.getKey(), entry.getValue());
|
||||
namedMods.get(entry.getKey()).setEnabledState(entry.getValue());
|
||||
}
|
||||
}
|
||||
state = State.UP;
|
||||
log.info(String.format("Forge Mod Loader load complete, %d mods loaded", mods.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -655,13 +418,13 @@ public class Loader
|
|||
|
||||
public String getCrashInformation()
|
||||
{
|
||||
StringBuffer ret = new StringBuffer();
|
||||
for (String brand : FMLCommonHandler.instance().getBrandingStrings(String.format("Forge Mod Loader version %s.%s.%s.%s for Minecraft %s", major, minor, rev, build, mccversion))) {
|
||||
ret.append(brand).append("\n");
|
||||
}
|
||||
for (ModContainer mod : mods)
|
||||
StringBuilder ret = new StringBuilder();
|
||||
List<String> branding = FMLCommonHandler.instance().getBrandings();
|
||||
|
||||
Joiner.on(' ').skipNulls().appendTo(ret, branding.subList(1, branding.size()));
|
||||
if (modController!=null)
|
||||
{
|
||||
ret.append(String.format("\t%s : %s (%s)\n",mod.getName(), mod.getModState(), mod.getSource().getName()));
|
||||
modController.printModStates(ret);
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
@ -681,4 +444,139 @@ public class Loader
|
|||
{
|
||||
return modClassLoader;
|
||||
}
|
||||
|
||||
public void computeDependencies(String dependencyString, List<ArtifactVersion> requirements, List<ArtifactVersion> dependencies, List<ArtifactVersion> dependants)
|
||||
{
|
||||
if (dependencyString == null || dependencyString.length() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
boolean parseFailure=false;
|
||||
|
||||
for (String dep : DEPENDENCYSPLITTER.split(dependencyString))
|
||||
{
|
||||
List<String> depparts = Lists.newArrayList(DEPENDENCYPARTSPLITTER.split(dep));
|
||||
// Need two parts to the string
|
||||
if (depparts.size() != 2)
|
||||
{
|
||||
parseFailure=true;
|
||||
continue;
|
||||
}
|
||||
String instruction = depparts.get(0);
|
||||
String target = depparts.get(1);
|
||||
boolean targetIsAll = target.startsWith("*");
|
||||
|
||||
// Cannot have an "all" relationship with anything except pure *
|
||||
if (targetIsAll && target.length()>1)
|
||||
{
|
||||
parseFailure = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is a required element, add it to the required list
|
||||
if ("required-before".equals(instruction) || "required-after".equals(instruction))
|
||||
{
|
||||
// You can't require everything
|
||||
if (!targetIsAll)
|
||||
{
|
||||
requirements.add(VersionParser.parseVersionReference(target));
|
||||
}
|
||||
else
|
||||
{
|
||||
parseFailure=true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// You cannot have a versioned dependency on everything
|
||||
if (targetIsAll && target.indexOf('@')>-1)
|
||||
{
|
||||
parseFailure = true;
|
||||
continue;
|
||||
}
|
||||
// before elements are things we are loaded before (so they are our dependants)
|
||||
if ("required-before".equals(instruction) || "before".equals(instruction))
|
||||
{
|
||||
dependants.add(VersionParser.parseVersionReference(target));
|
||||
}
|
||||
// after elements are things that load before we do (so they are out dependencies)
|
||||
else if ("required-after".equals(instruction) || "after".equals(instruction))
|
||||
{
|
||||
dependencies.add(VersionParser.parseVersionReference(target));
|
||||
}
|
||||
else
|
||||
{
|
||||
parseFailure=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (parseFailure)
|
||||
{
|
||||
FMLLog.log(Level.WARNING, "Unable to parse dependency string %s", dependencyString);
|
||||
throw new LoaderException();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String,ModContainer> getIndexedModList()
|
||||
{
|
||||
return ImmutableMap.copyOf(namedMods);
|
||||
}
|
||||
|
||||
public void initializeMods()
|
||||
{
|
||||
// Mod controller should be in the initialization state here
|
||||
modController.distributeStateMessage(LoaderState.INITIALIZATION);
|
||||
modController.transition(LoaderState.POSTINITIALIZATION);
|
||||
modController.distributeStateMessage(LoaderState.POSTINITIALIZATION);
|
||||
modController.transition(LoaderState.AVAILABLE);
|
||||
modController.distributeStateMessage(LoaderState.AVAILABLE);
|
||||
FMLLog.info("Forge Mod Loader has successfully loaded %d mod%s", mods.size(), mods.size()==1 ? "" : "s");
|
||||
}
|
||||
|
||||
public Callable getCallableCrashInformation()
|
||||
{
|
||||
return new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception
|
||||
{
|
||||
return getCrashInformation();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public List<ModContainer> getActiveModList()
|
||||
{
|
||||
return modController.getActiveModList();
|
||||
}
|
||||
|
||||
public ModState getModState(ModContainer selectedMod)
|
||||
{
|
||||
return modController.getModState(selectedMod);
|
||||
}
|
||||
|
||||
public String getMCVersionString()
|
||||
{
|
||||
return "Minecraft " + mccversion;
|
||||
}
|
||||
|
||||
public void serverStarting(Object server)
|
||||
{
|
||||
modController.distributeStateMessage(LoaderState.SERVER_STARTING, server);
|
||||
modController.transition(LoaderState.SERVER_STARTING);
|
||||
}
|
||||
|
||||
public void serverStarted()
|
||||
{
|
||||
modController.distributeStateMessage(LoaderState.SERVER_STARTED);
|
||||
modController.transition(LoaderState.SERVER_STARTED);
|
||||
}
|
||||
|
||||
public void serverStopping()
|
||||
{
|
||||
modController.distributeStateMessage(LoaderState.SERVER_STOPPING);
|
||||
modController.transition(LoaderState.SERVER_STOPPING);
|
||||
modController.transition(LoaderState.AVAILABLE);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
package cpw.mods.fml.common;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import cpw.mods.fml.common.event.FMLConstructionEvent;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLServerStarted;
|
||||
import cpw.mods.fml.common.event.FMLServerStarting;
|
||||
import cpw.mods.fml.common.event.FMLServerStopping;
|
||||
import cpw.mods.fml.common.event.FMLStateEvent;
|
||||
|
||||
/**
|
||||
* The state enum used to help track state progression for the loader
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public enum LoaderState
|
||||
{
|
||||
NOINIT("Uninitialized",null),
|
||||
LOADING("Loading",null),
|
||||
CONSTRUCTING("Constructing mods",FMLConstructionEvent.class),
|
||||
PREINITIALIZATION("Pre-initializing mods", FMLPreInitializationEvent.class),
|
||||
INITIALIZATION("Initializing mods", FMLInitializationEvent.class),
|
||||
POSTINITIALIZATION("Post-initializing mods", FMLPostInitializationEvent.class),
|
||||
AVAILABLE("Mod loading complete", FMLLoadCompleteEvent.class),
|
||||
SERVER_STARTING("Server starting", FMLServerStarting.class),
|
||||
SERVER_STARTED("Server started", FMLServerStarted.class),
|
||||
SERVER_STOPPING("Server stopping", FMLServerStopping.class),
|
||||
ERRORED("Mod Loading errored",null);
|
||||
|
||||
|
||||
private Class<? extends FMLStateEvent> eventClass;
|
||||
private String name;
|
||||
|
||||
private LoaderState(String name, Class<? extends FMLStateEvent> event)
|
||||
{
|
||||
this.name = name;
|
||||
this.eventClass = event;
|
||||
}
|
||||
|
||||
public LoaderState transition(boolean errored)
|
||||
{
|
||||
if (errored)
|
||||
{
|
||||
return ERRORED;
|
||||
}
|
||||
// stopping -> available
|
||||
if (this == SERVER_STOPPING)
|
||||
{
|
||||
return AVAILABLE;
|
||||
}
|
||||
return values()[ordinal() < values().length ? ordinal()+1 : ordinal()];
|
||||
}
|
||||
|
||||
public boolean hasEvent()
|
||||
{
|
||||
return eventClass != null;
|
||||
}
|
||||
|
||||
public FMLStateEvent getEvent(Object... eventData)
|
||||
{
|
||||
try
|
||||
{
|
||||
return eventClass.getConstructor(Object[].class).newInstance((Object)eventData);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
public LoaderState requiredState()
|
||||
{
|
||||
if (this == NOINIT) return NOINIT;
|
||||
return LoaderState.values()[this.ordinal()-1];
|
||||
}
|
||||
public enum ModState
|
||||
{
|
||||
UNLOADED("Unloaded"),
|
||||
LOADED("Loaded"),
|
||||
CONSTRUCTED("Constructed"),
|
||||
PREINITIALIZED("Pre-initialized"),
|
||||
INITIALIZED("Initialized"),
|
||||
POSTINITIALIZED("Post-initialized"),
|
||||
AVAILABLE("Available"),
|
||||
DISABLED("Disabled"),
|
||||
ERRORED("Errored");
|
||||
|
||||
private String label;
|
||||
|
||||
private ModState(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return this.label;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package cpw.mods.fml.common;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import argo.jdom.JdomParser;
|
||||
import argo.jdom.JsonNode;
|
||||
import argo.jdom.JsonRootNode;
|
||||
import argo.saj.InvalidSyntaxException;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public class MetadataCollection
|
||||
{
|
||||
private static JdomParser parser = new JdomParser();
|
||||
private Map<String, ModMetadata> metadatas = Maps.newHashMap();
|
||||
private int metadataVersion = 1;
|
||||
|
||||
public static MetadataCollection from(InputStream inputStream)
|
||||
{
|
||||
if (inputStream == null)
|
||||
{
|
||||
return new MetadataCollection();
|
||||
}
|
||||
|
||||
InputStreamReader reader = new InputStreamReader(inputStream);
|
||||
try
|
||||
{
|
||||
JsonRootNode root = parser.parse(reader);
|
||||
if (root.hasElements())
|
||||
{
|
||||
return parse10ModInfo(root);
|
||||
}
|
||||
else
|
||||
{
|
||||
return parseModInfo(root);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static MetadataCollection parseModInfo(JsonRootNode root)
|
||||
{
|
||||
MetadataCollection mc = new MetadataCollection();
|
||||
mc.metadataVersion = Integer.parseInt(root.getNumberValue("modinfoversion"));
|
||||
mc.parseModMetadataList(root.getNode("modlist"));
|
||||
return mc;
|
||||
}
|
||||
|
||||
private static MetadataCollection parse10ModInfo(JsonRootNode root)
|
||||
{
|
||||
MetadataCollection mc = new MetadataCollection();
|
||||
mc.parseModMetadataList(root);
|
||||
return mc;
|
||||
}
|
||||
|
||||
private void parseModMetadataList(JsonNode metadataList)
|
||||
{
|
||||
for (JsonNode node : metadataList.getElements())
|
||||
{
|
||||
ModMetadata mmd = new ModMetadata(node);
|
||||
metadatas.put(mmd.modId, mmd);
|
||||
}
|
||||
}
|
||||
|
||||
public ModMetadata getMetadataForId(String modId, Map<String, Object> extraData)
|
||||
{
|
||||
if (!metadatas.containsKey(modId))
|
||||
{
|
||||
ModMetadata dummy = new ModMetadata();
|
||||
dummy.modId = modId;
|
||||
dummy.name = (String) extraData.get("name");
|
||||
dummy.version = (String) extraData.get("version");
|
||||
dummy.autogenerated = true;
|
||||
metadatas.put(modId, dummy);
|
||||
}
|
||||
return metadatas.get(modId);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,23 +13,136 @@
|
|||
*/
|
||||
package cpw.mods.fml.common;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
|
||||
import net.minecraft.src.ItemBlock;
|
||||
|
||||
/**
|
||||
* A possible future way to indicate mods to the system is to use an annotation style
|
||||
*
|
||||
* The new mod style in FML 1.3
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Mod
|
||||
{
|
||||
String name() default "";
|
||||
String version() default "";
|
||||
boolean wantsPreInit() default false;
|
||||
boolean wantsPostInit() default false;
|
||||
public @interface PreInit {}
|
||||
public @interface Init {}
|
||||
public @interface PostInit {}
|
||||
/**
|
||||
* The unique mod identifier for this mod
|
||||
* @return
|
||||
*/
|
||||
String modid();
|
||||
/**
|
||||
* A user friendly name for the mod
|
||||
* @return
|
||||
*/
|
||||
String name() default "";
|
||||
/**
|
||||
* A version string for this mod
|
||||
* @return
|
||||
*/
|
||||
String version() default "";
|
||||
/**
|
||||
* A simple dependency string for this mod (see modloader's "priorities" string specification)
|
||||
* @return
|
||||
*/
|
||||
String dependencies() default "";
|
||||
/**
|
||||
* Whether to use the mcmod.info metadata by default for this mod.
|
||||
* If true, settings in the mcmod.info file will override settings in these annotations.
|
||||
* @return
|
||||
*/
|
||||
boolean useMetadata() default false;
|
||||
|
||||
/**
|
||||
* Mark the designated method as being called at the "pre-initialization" phase
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface PreInit {
|
||||
static Class<?>[] paramTypes = new Class[] { FMLPreInitializationEvent.class };
|
||||
}
|
||||
/**
|
||||
* Mark the designated method as being called at the "initialization" phase
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Init {
|
||||
static Class<?>[] paramTypes = new Class[] { FMLInitializationEvent.class };
|
||||
}
|
||||
/**
|
||||
* Mark the designated method as being called at the "post-initialization" phase
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface PostInit {
|
||||
static Class<?>[] paramTypes = new Class[] { FMLPostInitializationEvent.class };
|
||||
}
|
||||
/**
|
||||
* Populate the annotated field with the mod instance.
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Instance {}
|
||||
/**
|
||||
* Populate the annotated field with the mod's metadata.
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Metadata {}
|
||||
/**
|
||||
* Populate the annotated field with an instance of the Block as specified
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Block {
|
||||
/**
|
||||
* The block's name
|
||||
* @return
|
||||
*/
|
||||
String name();
|
||||
/**
|
||||
* The associated ItemBlock subtype for the item (can be null for an ItemBlock)
|
||||
* @return
|
||||
*/
|
||||
Class<?> itemTypeClass() default ItemBlock.class;
|
||||
}
|
||||
/**
|
||||
* Populate the annotated field with an Item
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Item {
|
||||
/**
|
||||
* The name of the item
|
||||
* @return
|
||||
*/
|
||||
String name();
|
||||
/**
|
||||
* The type of the item
|
||||
* @return
|
||||
*/
|
||||
String typeClass();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,61 +19,64 @@ import java.net.MalformedURLException;
|
|||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import cpw.mods.fml.common.discovery.ModCandidate;
|
||||
import cpw.mods.fml.relauncher.FMLRelauncher;
|
||||
import cpw.mods.fml.relauncher.RelaunchClassLoader;
|
||||
|
||||
/**
|
||||
* A simple delegating class loader used to load mods into the system
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class ModClassLoader extends URLClassLoader
|
||||
{
|
||||
|
||||
public ModClassLoader()
|
||||
{
|
||||
super(new URL[0], ModClassLoader.class.getClassLoader());
|
||||
}
|
||||
private static final List<String> STANDARD_LIBRARIES = ImmutableList.of("jinput.jar", "lwjgl.jar", "lwjgl_util.jar");
|
||||
private RelaunchClassLoader mainClassLoader;
|
||||
|
||||
public ModClassLoader(ClassLoader parent) {
|
||||
super(new URL[0], null);
|
||||
this.mainClassLoader = (RelaunchClassLoader)parent;
|
||||
}
|
||||
|
||||
public void addFile(File modFile) throws MalformedURLException
|
||||
{
|
||||
ClassLoader cl=getParent();
|
||||
if (cl instanceof URLClassLoader) {
|
||||
URLClassLoader ucl=(URLClassLoader) cl;
|
||||
URL url = modFile.toURI().toURL();
|
||||
try {
|
||||
Method addUrl=URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
addUrl.setAccessible(true);
|
||||
addUrl.invoke(ucl, url);
|
||||
} catch (Exception e) {
|
||||
Loader.log.severe("A fatal error occured attempting to load a file into the classloader");
|
||||
throw new LoaderException(e);
|
||||
mainClassLoader.addURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
return mainClassLoader.loadClass(name);
|
||||
}
|
||||
|
||||
public File[] getParentSources() {
|
||||
List<URL> urls=mainClassLoader.getSources();
|
||||
File[] sources=new File[urls.size()];
|
||||
try
|
||||
{
|
||||
for (int i = 0; i<urls.size(); i++)
|
||||
{
|
||||
sources[i]=new File(urls.get(i).toURI());
|
||||
}
|
||||
return sources;
|
||||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, "Unable to process our input to locate the minecraft code", e);
|
||||
throw new LoaderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public File[] getParentSources() {
|
||||
ClassLoader cl=getParent();
|
||||
if (cl instanceof URLClassLoader) {
|
||||
URLClassLoader ucl=(URLClassLoader) cl;
|
||||
URL[] pUrl=ucl.getURLs();
|
||||
File[] sources=new File[pUrl.length];
|
||||
try
|
||||
{
|
||||
for (int i=0; i<pUrl.length; i++) {
|
||||
sources[i]=new File(pUrl[i].toURI());
|
||||
}
|
||||
return sources;
|
||||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
Loader.log.throwing("ModClassLoader", "getParentSources", e);
|
||||
}
|
||||
}
|
||||
Loader.log.severe("Unable to process our input to locate the minecraft code");
|
||||
throw new LoaderException();
|
||||
|
||||
public List<String> getDefaultLibraries()
|
||||
{
|
||||
return STANDARD_LIBRARIES;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,20 @@ package cpw.mods.fml.common;
|
|||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer.SourceType;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
|
||||
/**
|
||||
* The container that wraps around mods in the system.
|
||||
* <p>The philosophy is that individual mod implementation technologies should not impact the actual loading and management
|
||||
* of mod code. This interface provides a mechanism by which we can wrap actual mod code so that the loader and other
|
||||
* facilities can treat mods at arms length.</p>
|
||||
* <p>
|
||||
* The philosophy is that individual mod implementation technologies should not
|
||||
* impact the actual loading and management of mod code. This interface provides
|
||||
* a mechanism by which we can wrap actual mod code so that the loader and other
|
||||
* facilities can treat mods at arms length.
|
||||
* </p>
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
|
@ -31,183 +36,116 @@ import cpw.mods.fml.common.ModContainer.SourceType;
|
|||
|
||||
public interface ModContainer
|
||||
{
|
||||
public enum ModState {
|
||||
UNLOADED("Unloaded"), LOADED("Loaded"), PREINITIALIZED("Pre-initialized"), INITIALIZED("Initialized"), POSTINITIALIZED("Post-initialized"), AVAILABLE("Available");
|
||||
private String label;
|
||||
/**
|
||||
* The globally unique modid for this mod
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getModId();
|
||||
|
||||
private ModState(String label) {
|
||||
this.label=label;
|
||||
}
|
||||
public String toString() {
|
||||
return this.label;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SourceType {
|
||||
JAR, CLASSPATH, DIR;
|
||||
}
|
||||
/**
|
||||
* The enclosed mod wants to be called during pre-initialization.
|
||||
* @return
|
||||
*/
|
||||
boolean wantsPreInit();
|
||||
/**
|
||||
* The enclosed mod wants to be called during post-initialization.
|
||||
* @return
|
||||
*/
|
||||
boolean wantsPostInit();
|
||||
/**
|
||||
* Called when pre-initialization occurs.
|
||||
*/
|
||||
void preInit();
|
||||
/**
|
||||
* Called when main initialization occurs.
|
||||
*/
|
||||
void init();
|
||||
/**
|
||||
* Called when post-initialization occurs.
|
||||
*/
|
||||
void postInit();
|
||||
/**
|
||||
* The name of the mod
|
||||
* A human readable name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* The state of the mod
|
||||
* A human readable version identifier
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ModState getModState();
|
||||
String getVersion();
|
||||
|
||||
/**
|
||||
* Move to the next mod state
|
||||
* The location on the file system which this mod came from
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
void nextState();
|
||||
File getSource();
|
||||
|
||||
/**
|
||||
* Does this mod match the supplied mod?
|
||||
* The metadata for this mod
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ModMetadata getMetadata();
|
||||
|
||||
/**
|
||||
* Attach this mod to it's metadata from the supplied metadata collection
|
||||
*
|
||||
* @param mc
|
||||
*/
|
||||
void bindMetadata(MetadataCollection mc);
|
||||
|
||||
/**
|
||||
* Set the enabled/disabled state of this mod
|
||||
*
|
||||
* @param enabled
|
||||
*/
|
||||
void setEnabledState(boolean enabled);
|
||||
|
||||
/**
|
||||
* A list of the modids that this mod requires loaded prior to loading
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<ArtifactVersion> getRequirements();
|
||||
|
||||
/**
|
||||
* A list of modids that should be loaded prior to this one. The special
|
||||
* value <strong>*</strong> indicates to load <em>before</em> any other mod.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<ArtifactVersion> getDependencies();
|
||||
|
||||
/**
|
||||
* A list of modids that should be loaded <em>after</em> this one. The
|
||||
* special value <strong>*</strong> indicates to load <em>after</em> any
|
||||
* other mod.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<ArtifactVersion> getDependants();
|
||||
|
||||
/**
|
||||
* A representative string encapsulating the sorting preferences for this
|
||||
* mod
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getSortingRules();
|
||||
|
||||
/**
|
||||
* Register the event bus for the mod and the controller for error handling
|
||||
* Returns if this bus was successfully registered - disabled mods and other
|
||||
* mods that don't need real events should return false and avoid further
|
||||
* processing
|
||||
*
|
||||
* @param bus
|
||||
* @param controller
|
||||
* @return
|
||||
*/
|
||||
boolean registerBus(EventBus bus, LoadController controller);
|
||||
|
||||
/**
|
||||
* Does this mod match the supplied mod
|
||||
*
|
||||
* @param mod
|
||||
* @return
|
||||
*/
|
||||
boolean matches(Object mod);
|
||||
|
||||
/**
|
||||
* The source of this mod: the file on the file system
|
||||
* @return
|
||||
*/
|
||||
File getSource();
|
||||
/**
|
||||
* Returns the sorting rules as a string for printing
|
||||
* @return
|
||||
*/
|
||||
String getSortingRules();
|
||||
/**
|
||||
* The actual mod object itself
|
||||
* Get the actual mod object
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Object getMod();
|
||||
/**
|
||||
* Lookup the fuel value for the supplied item/damage with this mod.
|
||||
* @param itemId
|
||||
* @param itemDamage
|
||||
* @return
|
||||
*/
|
||||
int lookupFuelValue(int itemId, int itemDamage);
|
||||
/**
|
||||
* This mod wants to be notified when an object is picked up.
|
||||
* @return
|
||||
*/
|
||||
boolean wantsPickupNotification();
|
||||
/**
|
||||
* The pickup notifier for this mod.
|
||||
* @return
|
||||
*/
|
||||
IPickupNotifier getPickupNotifier();
|
||||
/**
|
||||
* This mod wants to have special dispenser handling.
|
||||
* @return
|
||||
*/
|
||||
boolean wantsToDispense();
|
||||
/**
|
||||
* The dispensing handler.
|
||||
* @return
|
||||
*/
|
||||
IDispenseHandler getDispenseHandler();
|
||||
/**
|
||||
* This mod wants notification of crafting and/or smelting events.
|
||||
* @return
|
||||
*/
|
||||
boolean wantsCraftingNotification();
|
||||
/**
|
||||
* The crafting and smelting handler for this mod.
|
||||
* @return
|
||||
*/
|
||||
ICraftingHandler getCraftingHandler();
|
||||
/**
|
||||
* The strong dependencies of this mod. If the named mods in this list are not present, the game will abort.
|
||||
* @return
|
||||
*/
|
||||
List<String> getDependencies();
|
||||
/**
|
||||
* Get a list of mods to load before this one. The special value "*" indicates to load <i>after</i> all other mods (except other "*" mods).
|
||||
* @return
|
||||
*/
|
||||
List<String> getPreDepends();
|
||||
/**
|
||||
* Get a list of mods to load after this one. The special value "*" indicates to load <i>before</i> all other mods (except other "*" mods).
|
||||
* @return
|
||||
*/
|
||||
List<String> getPostDepends();
|
||||
/**
|
||||
* This mod wants packets from the client, and wants them handled by FML.
|
||||
* @return
|
||||
*/
|
||||
boolean wantsNetworkPackets();
|
||||
/**
|
||||
* The network handler for this mod.
|
||||
* @return
|
||||
*/
|
||||
INetworkHandler getNetworkHandler();
|
||||
/**
|
||||
* Does this mod own this channel?
|
||||
* @param channel
|
||||
* @return
|
||||
*/
|
||||
boolean ownsNetworkChannel(String channel);
|
||||
|
||||
/**
|
||||
* Does this mod want commands from the console?
|
||||
* @return
|
||||
*/
|
||||
boolean wantsConsoleCommands();
|
||||
|
||||
IConsoleHandler getConsoleHandler();
|
||||
|
||||
boolean wantsPlayerTracking();
|
||||
|
||||
IPlayerTracker getPlayerTracker();
|
||||
|
||||
List<IKeyHandler> getKeys();
|
||||
|
||||
SourceType getSourceType();
|
||||
|
||||
void setSourceType(SourceType type);
|
||||
|
||||
ModMetadata getMetadata();
|
||||
void setMetadata(ModMetadata meta);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void gatherRenderers(Map renderers);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void requestAnimations();
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
String getVersion();
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
ArtifactVersion getProcessedVersion();
|
||||
|
||||
ProxyInjector findSidedProxy();
|
||||
|
||||
void keyBindEvent(Object keyBinding);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package cpw.mods.fml.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import cpw.mods.fml.common.discovery.asm.ASMModParser;
|
||||
import cpw.mods.fml.common.discovery.asm.ModAnnotation;
|
||||
import cpw.mods.fml.common.modloader.ModLoaderModContainer;
|
||||
|
||||
public class ModContainerFactory
|
||||
{
|
||||
private static Pattern modClass = Pattern.compile(".*(\\.|)(mod\\_[^\\s$]+)$");
|
||||
private static ModContainerFactory INSTANCE = new ModContainerFactory();
|
||||
public static ModContainerFactory instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
public ModContainer build(ASMModParser modParser, File modSource)
|
||||
{
|
||||
String className = modParser.getASMType().getClassName();
|
||||
if (modParser.isBaseMod() && modClass.matcher(className).find())
|
||||
{
|
||||
FMLLog.fine("Identified a BaseMod type mod %s", className);
|
||||
return new ModLoaderModContainer(className, modSource, modParser.getBaseModProperties());
|
||||
}
|
||||
|
||||
for (ModAnnotation ann : modParser.getAnnotations())
|
||||
{
|
||||
if (ann.getASMType().equals(Type.getType(Mod.class)))
|
||||
{
|
||||
FMLLog.fine("Identified a FMLMod type mod %s", className);
|
||||
return new FMLModContainer(className, modSource, ann.getValues());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -20,85 +20,142 @@ import java.io.InputStreamReader;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import argo.jdom.JsonNode;
|
||||
import argo.jdom.JsonStringNode;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import cpw.mods.fml.common.functions.ModNameFunction;
|
||||
import cpw.mods.fml.common.modloader.ModLoaderModContainer;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.VersionParser;
|
||||
|
||||
import static argo.jdom.JsonNodeBuilders.*;
|
||||
|
||||
/**
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class ModMetadata
|
||||
{
|
||||
public enum ModType { MODLOADER, FML };
|
||||
public ModContainer mod;
|
||||
public ModType type;
|
||||
|
||||
private static final class JsonStringConverter implements Function<JsonNode, Object>
|
||||
{
|
||||
public Object apply(JsonNode arg0)
|
||||
{
|
||||
if (arg0.hasElements())
|
||||
{
|
||||
return Lists.transform(arg0.getElements(), new JsonArrayConverter());
|
||||
}
|
||||
else
|
||||
{
|
||||
return arg0.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JsonArrayConverter implements Function<JsonNode, String>
|
||||
{
|
||||
public String apply(JsonNode arg0)
|
||||
{
|
||||
return arg0.getText();
|
||||
}
|
||||
}
|
||||
|
||||
public String modId;
|
||||
public String name;
|
||||
public String description;
|
||||
|
||||
public String url="";
|
||||
public String updateUrl="";
|
||||
|
||||
public String logoFile="";
|
||||
public String version="";
|
||||
public List<String> authorList=new ArrayList<String>(1);
|
||||
public String credits="";
|
||||
public String parent="";
|
||||
|
||||
public String url = "";
|
||||
public String updateUrl = "";
|
||||
|
||||
public String logoFile = "";
|
||||
public String version = "";
|
||||
public List<String> authorList = Lists.newArrayList();
|
||||
public String credits = "";
|
||||
public String parent = "";
|
||||
public String[] screenshots;
|
||||
|
||||
|
||||
public ModContainer parentMod;
|
||||
public List<ModContainer> childMods = new ArrayList<ModContainer>(1);
|
||||
public List<ModContainer> childMods = Lists.newArrayList();
|
||||
|
||||
public boolean useDependencyInformation;
|
||||
public List<ArtifactVersion> requiredMods;
|
||||
public List<ArtifactVersion> dependencies;
|
||||
public List<ArtifactVersion> dependants;
|
||||
public boolean autogenerated;
|
||||
|
||||
/**
|
||||
* @param mod2
|
||||
* @param type2
|
||||
*/
|
||||
public ModMetadata(ModContainer mod)
|
||||
public ModMetadata(JsonNode node)
|
||||
{
|
||||
this.mod=mod;
|
||||
this.type=(mod instanceof FMLModContainer ? ModType.FML : ModType.MODLOADER);
|
||||
}
|
||||
|
||||
public void associate(Map<String, ModContainer> mods) {
|
||||
if (parent!=null && parent.length() > 0) {
|
||||
ModContainer mc=mods.get(parent);
|
||||
if (mc!=null && mc.getMetadata()!=null) {
|
||||
mc.getMetadata().childMods.add(mod);
|
||||
parentMod = mc;
|
||||
}
|
||||
}
|
||||
Map<JsonStringNode, Object> processedFields = Maps.transformValues(node.getFields(), new JsonStringConverter());
|
||||
modId = (String)processedFields.get(aStringBuilder("modid"));
|
||||
name = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("name")));
|
||||
description = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("description")));
|
||||
url = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("url")));
|
||||
updateUrl = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("updateUrl")));
|
||||
logoFile = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("logoFile")));
|
||||
version = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("version")));
|
||||
credits = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("credits")));
|
||||
parent = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("parent")));
|
||||
authorList = Optional.fromNullable((List<String>)processedFields.get(aStringBuilder("authorList"))).or(authorList);
|
||||
requiredMods = processReferences((List<String>)processedFields.get(aStringBuilder("requiredMods")));
|
||||
dependencies = processReferences((List<String>)processedFields.get(aStringBuilder("dependencies")));
|
||||
dependants = processReferences((List<String>)processedFields.get(aStringBuilder("dependants")));
|
||||
useDependencyInformation = Boolean.parseBoolean(Strings.nullToEmpty((String)processedFields.get(aStringBuilder("useDependencyInformation"))));
|
||||
}
|
||||
|
||||
ModMetadata()
|
||||
{
|
||||
}
|
||||
|
||||
private List<ArtifactVersion> processReferences(List<String> refs)
|
||||
{
|
||||
List<ArtifactVersion> res = Lists.newArrayList();
|
||||
if (refs == null)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
for (String ref : refs)
|
||||
{
|
||||
res.add(VersionParser.parseVersionReference(ref));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String getChildModCountString()
|
||||
{
|
||||
return String.format("%d child mod%s", childMods.size(), childMods.size()!=1 ? "s" : "");
|
||||
return String.format("%d child mod%s", childMods.size(), childMods.size() != 1 ? "s" : "");
|
||||
}
|
||||
|
||||
public String getAuthorList() {
|
||||
StringBuilder sb=new StringBuilder();
|
||||
for (int i=0; i<authorList.size(); i++) {
|
||||
sb.append(authorList.get(i));
|
||||
if (i<authorList.size()-1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
public String getAuthorList()
|
||||
{
|
||||
return Joiner.on(", ").join(authorList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String getChildModList()
|
||||
{
|
||||
StringBuilder sb=new StringBuilder();
|
||||
for (int i=0; i<childMods.size(); i++) {
|
||||
sb.append(childMods.get(i).getMetadata().name);
|
||||
if (i<childMods.size()-1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
return Joiner.on(", ").join(Lists.transform(childMods, new ModNameFunction()));
|
||||
}
|
||||
|
||||
public String printableSortingRules()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper.UnableToAccessFieldException;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper.UnableToFindFieldException;
|
||||
|
||||
/**
|
||||
* Some reflection helper code.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class ObfuscationReflectionHelper
|
||||
{
|
||||
public static boolean obfuscation;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T, E> T getPrivateValue(Class<? super E> classToAccess, E instance, int fieldIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReflectionHelper.getPrivateValue(classToAccess, instance, fieldIndex);
|
||||
}
|
||||
catch (UnableToAccessFieldException e)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, e, "There was a problem getting field index %d from %s", fieldIndex, classToAccess.getName());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T, E> T getPrivateValue(Class<? super E> classToAccess, E instance, String... fieldNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReflectionHelper.getPrivateValue(classToAccess, instance, fieldNames);
|
||||
}
|
||||
catch (UnableToFindFieldException e)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE,e,"Unable to locate any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName());
|
||||
throw e;
|
||||
}
|
||||
catch (UnableToAccessFieldException e)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, e, "Unable to access any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static <T, E> void setPrivateValue(Class<? super T> classToAccess, T instance, int fieldIndex, E value)
|
||||
{
|
||||
setPrivateValue(classToAccess, instance, value, fieldIndex);
|
||||
}
|
||||
|
||||
public static <T, E> void setPrivateValue(Class<? super T> classToAccess, T instance, E value, int fieldIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
ReflectionHelper.setPrivateValue(classToAccess, instance, value, fieldIndex);
|
||||
}
|
||||
catch (UnableToAccessFieldException e)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, e, "There was a problem setting field index %d on type %s", fieldIndex, classToAccess.getName());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static <T, E> void setPrivateValue(Class<? super T> classToAccess, T instance, String fieldName, E value)
|
||||
{
|
||||
setPrivateValue(classToAccess, instance, value, fieldName);
|
||||
}
|
||||
|
||||
public static <T, E> void setPrivateValue(Class<? super T> classToAccess, T instance, E value, String... fieldNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
ReflectionHelper.setPrivateValue(classToAccess, instance, value, fieldNames);
|
||||
}
|
||||
catch (UnableToFindFieldException e)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, e, "Unable to locate any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName());
|
||||
throw e;
|
||||
}
|
||||
catch (UnableToAccessFieldException e)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, e, "Unable to set any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static void detectObfuscation(Class<?> clazz)
|
||||
{
|
||||
obfuscation = !clazz.getSimpleName().equals("World");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
/**
|
||||
* Some reflection helper code.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class ReflectionHelper
|
||||
{
|
||||
public static boolean obfuscation;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T, E> T getPrivateValue(Class <? super E > classToAccess, E instance, int fieldIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field f = classToAccess.getDeclaredFields()[fieldIndex];
|
||||
f.setAccessible(true);
|
||||
return (T) f.get(instance);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLCommonHandler.instance().getFMLLogger().severe(String.format("There was a problem getting field %d from %s", fieldIndex, classToAccess.getName()));
|
||||
FMLCommonHandler.instance().getFMLLogger().throwing("ReflectionHelper", "getPrivateValue", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T, E> T getPrivateValue(Class <? super E > classToAccess, E instance, String fieldName)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field f = classToAccess.getDeclaredField(fieldName);
|
||||
f.setAccessible(true);
|
||||
return (T) f.get(instance);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if ((fieldName.length() > 3 && !obfuscation) || (fieldName.length() <= 3 && obfuscation)) {
|
||||
FMLCommonHandler.instance().getFMLLogger().severe(String.format("There was a problem getting field %s from %s", fieldName, classToAccess.getName()));
|
||||
FMLCommonHandler.instance().getFMLLogger().throwing("ReflectionHelper", "getPrivateValue", e);
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, int fieldIndex, E value)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field f = classToAccess.getDeclaredFields()[fieldIndex];
|
||||
f.setAccessible(true);
|
||||
f.set(instance, value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLCommonHandler.instance().getFMLLogger().severe(String.format("There was a problem setting field %d from %s", fieldIndex, classToAccess.getName()));
|
||||
FMLCommonHandler.instance().getFMLLogger().throwing("ReflectionHelper", "getPrivateValue", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, String fieldName, E value)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field f = classToAccess.getDeclaredField(fieldName);
|
||||
f.setAccessible(true);
|
||||
f.set(instance, value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if ((fieldName.length() > 3 && !obfuscation) || (fieldName.length() <= 3 && obfuscation)) {
|
||||
FMLCommonHandler.instance().getFMLLogger().severe(String.format("There was a problem setting field %s from %s", fieldName, classToAccess.getName()));
|
||||
FMLCommonHandler.instance().getFMLLogger().throwing("ReflectionHelper", "getPrivateValue", e);
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static void detectObfuscation(Class<?> clazz)
|
||||
{
|
||||
obfuscation=!clazz.getSimpleName().equals("World");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package cpw.mods.fml.common.asm;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import cpw.mods.fml.common.registry.BlockProxy;
|
||||
import cpw.mods.fml.relauncher.IClassTransformer;
|
||||
|
||||
public class ASMTransformer implements IClassTransformer
|
||||
{
|
||||
@Override
|
||||
public byte[] transform(String name, byte[] bytes)
|
||||
{
|
||||
if ("net.minecraft.src.Block".equals(name))
|
||||
{
|
||||
ClassReader cr = new ClassReader(bytes);
|
||||
ClassNode cn = new ClassNode(Opcodes.ASM4);
|
||||
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||
cn.interfaces.add(Type.getInternalName(BlockProxy.class));
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
cn.accept(cw);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package cpw.mods.fml.common.discovery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
public enum ContainerType
|
||||
{
|
||||
JAR(JarDiscoverer.class),
|
||||
DIR(DirectoryDiscoverer.class);
|
||||
|
||||
private ITypeDiscoverer discoverer;
|
||||
|
||||
private ContainerType(Class<? extends ITypeDiscoverer> discovererClass)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.discoverer = discovererClass.newInstance();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ModContainer> findMods(ModCandidate candidate)
|
||||
{
|
||||
return discoverer.discover(candidate);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package cpw.mods.fml.common.discovery;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.MetadataCollection;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.ModContainerFactory;
|
||||
import cpw.mods.fml.common.discovery.asm.ASMModParser;
|
||||
|
||||
public class DirectoryDiscoverer implements ITypeDiscoverer
|
||||
{
|
||||
private class ClassFilter implements FileFilter
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File file)
|
||||
{
|
||||
return (file.isFile() && classFile.matcher(file.getName()).find()) || file.isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModContainer> discover(ModCandidate candidate)
|
||||
{
|
||||
List<ModContainer> found = Lists.newArrayList();
|
||||
FMLLog.fine("Examining directory %s for potential mods", candidate.getModContainer().getName());
|
||||
exploreFileSystem("", candidate.getModContainer(), found, candidate, null);
|
||||
return found;
|
||||
}
|
||||
|
||||
public void exploreFileSystem(String path, File modDir, List<ModContainer> harvestedMods, ModCandidate candidate, MetadataCollection mc)
|
||||
{
|
||||
if (path.length() == 0)
|
||||
{
|
||||
File metadata = new File(modDir, "mcmod.info");
|
||||
try
|
||||
{
|
||||
FileInputStream fis = new FileInputStream(metadata);
|
||||
mc = MetadataCollection.from(fis);
|
||||
fis.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
mc = MetadataCollection.from(null);
|
||||
}
|
||||
}
|
||||
|
||||
File[] content = modDir.listFiles(new ClassFilter());
|
||||
|
||||
// Always sort our content
|
||||
Arrays.sort(content);
|
||||
for (File file : content)
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
FMLLog.finest("Recursing into package %s", path + file.getName());
|
||||
exploreFileSystem(path + file.getName() + ".", file, harvestedMods, candidate, mc);
|
||||
continue;
|
||||
}
|
||||
Matcher match = classFile.matcher(file.getName());
|
||||
|
||||
if (match.matches())
|
||||
{
|
||||
ASMModParser modParser = null;
|
||||
try
|
||||
{
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
modParser = new ASMModParser(fis);
|
||||
fis.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
|
||||
modParser.validate();
|
||||
ModContainer container = ModContainerFactory.instance().build(modParser, candidate.getModContainer());
|
||||
if (container!=null)
|
||||
{
|
||||
harvestedMods.add(container);
|
||||
container.bindMetadata(mc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package cpw.mods.fml.common.discovery;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
public interface ITypeDiscoverer
|
||||
{
|
||||
public static Pattern classFile = Pattern.compile("([^\\s$]+).class$");
|
||||
|
||||
public List<ModContainer> discover(ModCandidate candidate);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package cpw.mods.fml.common.discovery;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.MetadataCollection;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.ModContainerFactory;
|
||||
import cpw.mods.fml.common.discovery.asm.ASMModParser;
|
||||
|
||||
public class JarDiscoverer implements ITypeDiscoverer
|
||||
{
|
||||
@Override
|
||||
public List<ModContainer> discover(ModCandidate candidate)
|
||||
{
|
||||
List<ModContainer> foundMods = Lists.newArrayList();
|
||||
FMLLog.fine("Examining file %s for potential mods", candidate.getModContainer().getName());
|
||||
ZipFile jar = null;
|
||||
try
|
||||
{
|
||||
jar = new ZipFile(candidate.getModContainer());
|
||||
|
||||
ZipEntry modInfo = jar.getEntry("mcmod.info");
|
||||
MetadataCollection mc = null;
|
||||
if (modInfo != null)
|
||||
{
|
||||
FMLLog.finer("Located mcmod.info file in file %s", candidate.getModContainer().getName());
|
||||
mc = MetadataCollection.from(jar.getInputStream(modInfo));
|
||||
}
|
||||
for (ZipEntry ze : Collections.list(jar.entries()))
|
||||
{
|
||||
Matcher match = classFile.matcher(ze.getName());
|
||||
if (match.matches())
|
||||
{
|
||||
ASMModParser modParser = new ASMModParser(jar.getInputStream(ze));
|
||||
modParser.validate();
|
||||
ModContainer container = ModContainerFactory.instance().build(modParser, candidate.getModContainer());
|
||||
if (container!=null)
|
||||
{
|
||||
foundMods.add(container);
|
||||
container.bindMetadata(mc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLLog.warning("Zip file %s failed to read properly, it will be ignored", candidate.getModContainer().getName());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (jar != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
jar.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundMods;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package cpw.mods.fml.common.discovery;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
|
||||
public class ModCandidate
|
||||
{
|
||||
private File classPathRoot;
|
||||
private File modContainer;
|
||||
private ContainerType sourceType;
|
||||
private boolean classpath;
|
||||
|
||||
public ModCandidate(File classPathRoot, File modContainer, ContainerType sourceType)
|
||||
{
|
||||
this(classPathRoot, modContainer, sourceType, false);
|
||||
}
|
||||
public ModCandidate(File classPathRoot, File modContainer, ContainerType sourceType, boolean classpath)
|
||||
{
|
||||
this.classPathRoot = classPathRoot;
|
||||
this.modContainer = modContainer;
|
||||
this.sourceType = sourceType;
|
||||
this.classpath = classpath;
|
||||
}
|
||||
|
||||
public File getClassPathRoot()
|
||||
{
|
||||
return classPathRoot;
|
||||
}
|
||||
|
||||
public File getModContainer()
|
||||
{
|
||||
return modContainer;
|
||||
}
|
||||
|
||||
public ContainerType getSourceType()
|
||||
{
|
||||
return sourceType;
|
||||
}
|
||||
public List<ModContainer> explore()
|
||||
{
|
||||
return sourceType.findMods(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package cpw.mods.fml.common.discovery;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.LoaderException;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.relauncher.RelaunchLibraryManager;
|
||||
|
||||
public class ModDiscoverer
|
||||
{
|
||||
private static Pattern zipJar = Pattern.compile("(.+).(zip|jar)$");
|
||||
|
||||
private List<ModCandidate> candidates = Lists.newArrayList();
|
||||
|
||||
public void findClasspathMods(ModClassLoader modClassLoader)
|
||||
{
|
||||
List<String> knownLibraries = ImmutableList.<String>builder().addAll(modClassLoader.getDefaultLibraries()).addAll(RelaunchLibraryManager.getLibraries()).build();
|
||||
File[] minecraftSources = modClassLoader.getParentSources();
|
||||
if (minecraftSources.length == 1 && minecraftSources[0].isFile())
|
||||
{
|
||||
FMLLog.fine("Minecraft is a file at %s, loading", minecraftSources[0].getAbsolutePath());
|
||||
candidates.add(new ModCandidate(minecraftSources[0], minecraftSources[0], ContainerType.JAR));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < minecraftSources.length; i++)
|
||||
{
|
||||
if (minecraftSources[i].isFile())
|
||||
{
|
||||
if (knownLibraries.contains(minecraftSources[i].getName()))
|
||||
{
|
||||
FMLLog.fine("Skipping known library file %s", minecraftSources[i].getAbsolutePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.fine("Found a minecraft related file at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath());
|
||||
candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.JAR, true));
|
||||
}
|
||||
}
|
||||
else if (minecraftSources[i].isDirectory())
|
||||
{
|
||||
FMLLog.fine("Found a minecraft related directory at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath());
|
||||
candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.DIR, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void findModDirMods(File modsDir)
|
||||
{
|
||||
File[] modList = modsDir.listFiles();
|
||||
// Sort the files into alphabetical order first
|
||||
Arrays.sort(modList);
|
||||
|
||||
for (File modFile : modList)
|
||||
{
|
||||
if (modFile.isDirectory())
|
||||
{
|
||||
FMLLog.fine("Found a candidate mod directory %s", modFile.getName());
|
||||
candidates.add(new ModCandidate(modFile, modFile, ContainerType.DIR));
|
||||
}
|
||||
else
|
||||
{
|
||||
Matcher matcher = zipJar.matcher(modFile.getName());
|
||||
|
||||
if (matcher.matches())
|
||||
{
|
||||
FMLLog.fine("Found a candidate zip or jar file %s", matcher.group(0));
|
||||
candidates.add(new ModCandidate(modFile, modFile, ContainerType.JAR));
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.fine("Ignoring unknown file %s in mods directory", modFile.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<ModContainer> identifyMods()
|
||||
{
|
||||
List<ModContainer> modList = Lists.newArrayList();
|
||||
|
||||
for (ModCandidate candidate : candidates)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<ModContainer> mods = candidate.explore();
|
||||
modList.addAll(mods);
|
||||
}
|
||||
catch (LoaderException le)
|
||||
{
|
||||
FMLLog.log(Level.WARNING, le, "Identified a problem with the mod candidate %s, ignoring this source", candidate.getModContainer());
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
Throwables.propagate(t);
|
||||
}
|
||||
}
|
||||
|
||||
return modList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
package cpw.mods.fml.common.discovery.asm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.src.BaseMod;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import cpw.mods.fml.common.LoaderException;
|
||||
|
||||
public class ASMModParser
|
||||
{
|
||||
|
||||
private Type asmType;
|
||||
private int classVersion;
|
||||
private Type asmSuperType;
|
||||
private LinkedList<ModAnnotation> annotations = Lists.newLinkedList();
|
||||
private String baseModProperties;
|
||||
|
||||
static enum AnnotationType
|
||||
{
|
||||
CLASS, FIELD, METHOD;
|
||||
}
|
||||
|
||||
public ASMModParser(InputStream stream) throws IOException
|
||||
{
|
||||
ClassReader reader = new ClassReader(stream);
|
||||
reader.accept(new ModClassVisitor(this), 0);
|
||||
}
|
||||
|
||||
public void beginNewTypeName(String typeQName, int classVersion, String superClassQName)
|
||||
{
|
||||
this.asmType = Type.getObjectType(typeQName);
|
||||
this.classVersion = classVersion;
|
||||
this.asmSuperType = Type.getObjectType(superClassQName);
|
||||
}
|
||||
|
||||
public void startClassAnnotation(String annotationName)
|
||||
{
|
||||
ModAnnotation ann = new ModAnnotation(AnnotationType.CLASS, Type.getType(annotationName), this.asmType.getClassName());
|
||||
annotations.addFirst(ann);
|
||||
}
|
||||
|
||||
public void addAnnotationProperty(String key, Object value)
|
||||
{
|
||||
annotations.getFirst().values.put(key, value);
|
||||
}
|
||||
|
||||
public void startFieldAnnotation(String fieldName, String annotationName)
|
||||
{
|
||||
ModAnnotation ann = new ModAnnotation(AnnotationType.FIELD, Type.getType(annotationName), fieldName);
|
||||
annotations.addFirst(ann);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return Objects.toStringHelper("ASMAnnotationDiscoverer")
|
||||
.add("className", asmType.getClassName())
|
||||
.add("classVersion", classVersion)
|
||||
.add("superName", asmSuperType.getClassName())
|
||||
.add("annotations", annotations)
|
||||
.add("isBaseMod", isBaseMod())
|
||||
.add("baseModProperties", baseModProperties)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Type getASMType()
|
||||
{
|
||||
return asmType;
|
||||
}
|
||||
|
||||
public int getClassVersion()
|
||||
{
|
||||
return classVersion;
|
||||
}
|
||||
|
||||
public Type getASMSuperType()
|
||||
{
|
||||
return asmSuperType;
|
||||
}
|
||||
|
||||
public LinkedList<ModAnnotation> getAnnotations()
|
||||
{
|
||||
return annotations;
|
||||
}
|
||||
|
||||
public void validate()
|
||||
{
|
||||
// if (classVersion > 50.0)
|
||||
// {
|
||||
//
|
||||
// throw new LoaderException(new RuntimeException("Mod compiled for Java 7 detected"));
|
||||
// }
|
||||
}
|
||||
|
||||
public boolean isBaseMod()
|
||||
{
|
||||
return getASMSuperType().equals(Type.getType(BaseMod.class));
|
||||
}
|
||||
|
||||
public void setBaseModProperties(String foundProperties)
|
||||
{
|
||||
this.baseModProperties = foundProperties;
|
||||
}
|
||||
|
||||
public String getBaseModProperties()
|
||||
{
|
||||
return this.baseModProperties;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package cpw.mods.fml.common.discovery.asm;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import cpw.mods.fml.common.discovery.asm.ASMModParser.AnnotationType;
|
||||
|
||||
public class ModAnnotation
|
||||
{
|
||||
AnnotationType type;
|
||||
Type asmType;
|
||||
String member;
|
||||
Map<String,Object> values = Maps.newHashMap();
|
||||
public ModAnnotation(AnnotationType type, Type asmType, String member)
|
||||
{
|
||||
this.type = type;
|
||||
this.asmType = asmType;
|
||||
this.member = member;
|
||||
}
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return Objects.toStringHelper("Annotation")
|
||||
.add("type",type)
|
||||
.add("name",asmType.getClassName())
|
||||
.add("member",member)
|
||||
.add("values", values)
|
||||
.toString();
|
||||
}
|
||||
public AnnotationType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
public Type getASMType()
|
||||
{
|
||||
return asmType;
|
||||
}
|
||||
public String getMember()
|
||||
{
|
||||
return member;
|
||||
}
|
||||
public Map<String, Object> getValues()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package cpw.mods.fml.common.discovery.asm;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public class ModAnnotationVisitor extends AnnotationVisitor
|
||||
{
|
||||
private ASMModParser discoverer;
|
||||
|
||||
public ModAnnotationVisitor(ASMModParser discoverer)
|
||||
{
|
||||
super(Opcodes.ASM4);
|
||||
this.discoverer = discoverer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String key, Object value)
|
||||
{
|
||||
discoverer.addAnnotationProperty(key, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package cpw.mods.fml.common.discovery.asm;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public class ModClassVisitor extends ClassVisitor
|
||||
{
|
||||
private ASMModParser discoverer;
|
||||
|
||||
public ModClassVisitor(ASMModParser discoverer)
|
||||
{
|
||||
super(Opcodes.ASM4);
|
||||
this.discoverer = discoverer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
discoverer.beginNewTypeName(name, version, superName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible)
|
||||
{
|
||||
discoverer.startClassAnnotation(annotationName);
|
||||
return new ModAnnotationVisitor(discoverer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value)
|
||||
{
|
||||
return new ModFieldVisitor(name, discoverer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
|
||||
{
|
||||
if (discoverer.isBaseMod() && name.equals("getPriorities") && desc.equals(Type.getMethodDescriptor(Type.getType(String.class))))
|
||||
{
|
||||
return new ModMethodVisitor(name, discoverer);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package cpw.mods.fml.common.discovery.asm;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public class ModFieldVisitor extends FieldVisitor
|
||||
{
|
||||
|
||||
private String fieldName;
|
||||
private ASMModParser discoverer;
|
||||
|
||||
public ModFieldVisitor(String name, ASMModParser discoverer)
|
||||
{
|
||||
super(Opcodes.ASM4);
|
||||
this.fieldName = name;
|
||||
this.discoverer = discoverer;
|
||||
}
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible)
|
||||
{
|
||||
discoverer.startFieldAnnotation(fieldName, annotationName);
|
||||
return new ModAnnotationVisitor(discoverer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package cpw.mods.fml.common.discovery.asm;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
public class ModMethodVisitor extends MethodVisitor
|
||||
{
|
||||
|
||||
private ASMModParser discoverer;
|
||||
private boolean inCode;
|
||||
private LinkedList<Label> labels = Lists.newLinkedList();
|
||||
private String foundProperties;
|
||||
private boolean validProperties;
|
||||
|
||||
public ModMethodVisitor(String name, ASMModParser discoverer)
|
||||
{
|
||||
super(Opcodes.ASM4);
|
||||
this.discoverer = discoverer;
|
||||
}
|
||||
@Override
|
||||
public void visitCode()
|
||||
{
|
||||
labels.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object cst)
|
||||
{
|
||||
if (cst instanceof String && labels.size() == 1)
|
||||
{
|
||||
foundProperties = (String) cst;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void visitInsn(int opcode)
|
||||
{
|
||||
if (Opcodes.ARETURN == opcode && labels.size() == 1 && foundProperties != null)
|
||||
{
|
||||
validProperties = true;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void visitLabel(Label label)
|
||||
{
|
||||
labels.push(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
if (validProperties)
|
||||
{
|
||||
discoverer.setBaseModProperties(foundProperties);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
|
||||
public class FMLConstructionEvent extends FMLStateEvent
|
||||
{
|
||||
private ModClassLoader modClassLoader;
|
||||
|
||||
public FMLConstructionEvent(Object... eventData)
|
||||
{
|
||||
this.modClassLoader = (ModClassLoader)eventData[0];
|
||||
}
|
||||
|
||||
public ModClassLoader getModClassLoader()
|
||||
{
|
||||
return modClassLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModState getModState()
|
||||
{
|
||||
return ModState.CONSTRUCTED;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
public class FMLEvent
|
||||
{
|
||||
public final String getEventType()
|
||||
{
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
|
||||
public class FMLInitializationEvent extends FMLStateEvent
|
||||
{
|
||||
|
||||
public FMLInitializationEvent(Object... data)
|
||||
{
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModState getModState()
|
||||
{
|
||||
return ModState.INITIALIZED;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState;
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
|
||||
public class FMLLoadCompleteEvent extends FMLStateEvent
|
||||
{
|
||||
|
||||
public FMLLoadCompleteEvent(Object... data)
|
||||
{
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModState getModState()
|
||||
{
|
||||
return ModState.AVAILABLE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
|
||||
public class FMLPostInitializationEvent extends FMLStateEvent
|
||||
{
|
||||
public FMLPostInitializationEvent(Object... data)
|
||||
{
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModState getModState()
|
||||
{
|
||||
return ModState.POSTINITIALIZED;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.ModMetadata;
|
||||
|
||||
public class FMLPreInitializationEvent extends FMLStateEvent
|
||||
{
|
||||
private ModMetadata modMetadata;
|
||||
private File sourceFile;
|
||||
|
||||
public FMLPreInitializationEvent(Object... data)
|
||||
{
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModState getModState()
|
||||
{
|
||||
return ModState.PREINITIALIZED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyModContainer(ModContainer activeContainer)
|
||||
{
|
||||
this.modMetadata = activeContainer.getMetadata();
|
||||
this.sourceFile = activeContainer.getSource();
|
||||
}
|
||||
|
||||
public File getSourceFile()
|
||||
{
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
public ModMetadata getModMetadata()
|
||||
{
|
||||
return modMetadata;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState;
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
|
||||
public class FMLServerStarted extends FMLStateEvent
|
||||
{
|
||||
|
||||
public FMLServerStarted(Object... data)
|
||||
{
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModState getModState()
|
||||
{
|
||||
return ModState.AVAILABLE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState;
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
|
||||
public class FMLServerStarting extends FMLStateEvent
|
||||
{
|
||||
|
||||
private Object server;
|
||||
|
||||
public FMLServerStarting(Object... data)
|
||||
{
|
||||
super(data);
|
||||
this.server = data[0];
|
||||
}
|
||||
@Override
|
||||
public ModState getModState()
|
||||
{
|
||||
return ModState.AVAILABLE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState;
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
|
||||
public class FMLServerStopping extends FMLStateEvent
|
||||
{
|
||||
|
||||
public FMLServerStopping(Object... data)
|
||||
{
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModState getModState()
|
||||
{
|
||||
return ModState.AVAILABLE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
public abstract class FMLStateEvent extends FMLEvent
|
||||
{
|
||||
public FMLStateEvent(Object... data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public abstract ModState getModState();
|
||||
|
||||
public void applyModContainer(ModContainer activeContainer)
|
||||
{
|
||||
// NO OP
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package cpw.mods.fml.common.functions;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
public final class ModIdFunction implements Function<ModContainer, String>
|
||||
{
|
||||
public String apply(ModContainer container)
|
||||
{
|
||||
return container.getModId();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package cpw.mods.fml.common.functions;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
public class ModNameFunction implements Function<ModContainer, String>
|
||||
{
|
||||
@Override
|
||||
public String apply(ModContainer input)
|
||||
{
|
||||
return input.getName();
|
||||
}
|
||||
|
||||
}
|
|
@ -29,23 +29,41 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.IConsoleHandler;
|
||||
import cpw.mods.fml.common.ICraftingHandler;
|
||||
import cpw.mods.fml.common.IDispenseHandler;
|
||||
import cpw.mods.fml.common.IFMLSidedHandler;
|
||||
import cpw.mods.fml.common.IKeyHandler;
|
||||
import cpw.mods.fml.common.INetworkHandler;
|
||||
import cpw.mods.fml.common.IPickupNotifier;
|
||||
import cpw.mods.fml.common.IPlayerTracker;
|
||||
import cpw.mods.fml.common.IWorldGenerator;
|
||||
import cpw.mods.fml.common.LoadController;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.LoaderException;
|
||||
import cpw.mods.fml.common.LoaderState;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.MetadataCollection;
|
||||
import cpw.mods.fml.common.discovery.ContainerType;
|
||||
import cpw.mods.fml.common.event.FMLConstructionEvent;
|
||||
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.common.registry.TickRegistry;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.ModContainer.ModState;
|
||||
import cpw.mods.fml.common.ModContainer.SourceType;
|
||||
import cpw.mods.fml.common.ModMetadata;
|
||||
import cpw.mods.fml.common.ProxyInjector;
|
||||
import cpw.mods.fml.common.TickType;
|
||||
|
@ -53,26 +71,30 @@ import cpw.mods.fml.common.TickType;
|
|||
public class ModLoaderModContainer implements ModContainer
|
||||
{
|
||||
private static final ProxyInjector NULLPROXY = new ProxyInjector("","","",null);
|
||||
private Class <? extends BaseMod > modClazz;
|
||||
private BaseMod mod;
|
||||
public BaseMod mod;
|
||||
private File modSource;
|
||||
private ArrayList<String> dependencies;
|
||||
private ArrayList<String> preDependencies;
|
||||
private ArrayList<String> postDependencies;
|
||||
private ArrayList<IKeyHandler> keyHandlers;
|
||||
private ModState state;
|
||||
private SourceType sourceType;
|
||||
public List<ArtifactVersion> requirements = Lists.newArrayList();
|
||||
public ArrayList<ArtifactVersion> dependencies = Lists.newArrayList();
|
||||
public ArrayList<ArtifactVersion> dependants = Lists.newArrayList();
|
||||
private ContainerType sourceType;
|
||||
private ModMetadata metadata;
|
||||
private ProxyInjector sidedProxy;
|
||||
private BaseModTicker gameTickHandler;
|
||||
private BaseModTicker guiTickHandler;
|
||||
private String modClazzName;
|
||||
private String modId;
|
||||
private EventBus bus;
|
||||
private LoadController controller;
|
||||
private boolean enabled = true;
|
||||
private String sortingProperties;
|
||||
private ArtifactVersion processedVersion;
|
||||
|
||||
public ModLoaderModContainer(Class <? extends BaseMod > modClazz, File modSource)
|
||||
public ModLoaderModContainer(String className, File modSource, String sortingProperties)
|
||||
{
|
||||
this.modClazz = modClazz;
|
||||
this.modClazzName = className;
|
||||
this.modSource = modSource;
|
||||
// We are unloaded
|
||||
nextState();
|
||||
this.modId = className.contains(".") ? className.substring(className.lastIndexOf('.')+1) : className;
|
||||
this.sortingProperties = sortingProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,66 +108,14 @@ public class ModLoaderModContainer implements ModContainer
|
|||
this.guiTickHandler = new BaseModTicker(instance, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsPreInit()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsPostInit()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInit()
|
||||
{
|
||||
try
|
||||
{
|
||||
EnumSet<TickType> ticks = EnumSet.noneOf(TickType.class);
|
||||
this.gameTickHandler = new BaseModTicker(ticks, false);
|
||||
this.guiTickHandler = new BaseModTicker(ticks.clone(), true);
|
||||
configureMod();
|
||||
mod = modClazz.newInstance();
|
||||
this.gameTickHandler.setMod(mod);
|
||||
this.guiTickHandler.setMod(mod);
|
||||
FMLCommonHandler.instance().registerTickHandler(this.gameTickHandler);
|
||||
FMLCommonHandler.instance().registerTickHandler(this.guiTickHandler);
|
||||
FMLCommonHandler.instance().registerWorldGenerator(this.mod);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new LoaderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModState getModState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextState()
|
||||
{
|
||||
if (state==null) {
|
||||
state=ModState.UNLOADED;
|
||||
return;
|
||||
}
|
||||
if (state.ordinal()+1<ModState.values().length) {
|
||||
state=ModState.values()[state.ordinal()+1];
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void configureMod()
|
||||
private void configureMod(Class<? extends BaseMod> modClazz)
|
||||
{
|
||||
IFMLSidedHandler sideHandler = FMLCommonHandler.instance().getSidedDelegate();
|
||||
File configDir = Loader.instance().getConfigDir();
|
||||
String modConfigName = modClazz.getSimpleName();
|
||||
File modConfig = new File(configDir, String.format("%s.cfg", modConfigName));
|
||||
File modConfig = new File(configDir, String.format("%s.cfg", modClazzName));
|
||||
Properties props = new Properties();
|
||||
|
||||
boolean existingConfigFound = false;
|
||||
|
@ -155,15 +125,14 @@ public class ModLoaderModContainer implements ModContainer
|
|||
{
|
||||
try
|
||||
{
|
||||
Loader.log.fine(String.format("Reading existing configuration file for %s : %s", modConfigName, modConfig.getName()));
|
||||
FMLLog.fine("Reading existing configuration file for %s : %s", modClazzName, modConfig.getName());
|
||||
FileReader configReader = new FileReader(modConfig);
|
||||
props.load(configReader);
|
||||
configReader.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Loader.log.severe(String.format("Error occured reading mod configuration file %s", modConfig.getName()));
|
||||
Loader.log.throwing("ModLoaderModContainer", "configureMod", e);
|
||||
FMLLog.log(Level.SEVERE, e, "Error occured reading mod configuration file %s", modConfig.getName());
|
||||
throw new LoaderException(e);
|
||||
}
|
||||
existingConfigFound = true;
|
||||
|
@ -194,19 +163,18 @@ public class ModLoaderModContainer implements ModContainer
|
|||
{
|
||||
defaultValue = f.get(null);
|
||||
propertyValue = props.getProperty(propertyName, extractValue(defaultValue));
|
||||
Object currentValue = parseValue(propertyValue, property, f.getType(), propertyName, modConfigName);
|
||||
Loader.log.finest(String.format("Configuration for %s.%s found values default: %s, configured: %s, interpreted: %s", modConfigName, propertyName, defaultValue, propertyValue, currentValue));
|
||||
Object currentValue = parseValue(propertyValue, property, f.getType(), propertyName, modClazzName);
|
||||
FMLLog.finest("Configuration for %s.%s found values default: %s, configured: %s, interpreted: %s", modClazzName, propertyName, defaultValue, propertyValue, currentValue);
|
||||
|
||||
if (currentValue != null && !currentValue.equals(defaultValue))
|
||||
{
|
||||
Loader.log.finest(String.format("Configuration for %s.%s value set to: %s", modConfigName, propertyName, currentValue));
|
||||
FMLLog.finest("Configuration for %s.%s value set to: %s", modClazzName, propertyName, currentValue);
|
||||
f.set(null, currentValue);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Loader.log.severe(String.format("Invalid configuration found for %s in %s", propertyName, modConfig.getName()));
|
||||
Loader.log.throwing("ModLoaderModContainer", "configureMod", e);
|
||||
FMLLog.log(Level.SEVERE, e, "Invalid configuration found for %s in %s", propertyName, modConfig.getName());
|
||||
throw new LoaderException(e);
|
||||
}
|
||||
finally
|
||||
|
@ -243,22 +211,22 @@ public class ModLoaderModContainer implements ModContainer
|
|||
{
|
||||
if (!mlPropFound && !existingConfigFound)
|
||||
{
|
||||
Loader.log.fine(String.format("No MLProp configuration for %s found or required. No file written", modConfigName));
|
||||
FMLLog.fine("No MLProp configuration for %s found or required. No file written", modClazzName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mlPropFound && existingConfigFound)
|
||||
{
|
||||
File mlPropBackup = new File(modConfig.getParent(),modConfig.getName()+".bak");
|
||||
Loader.log.fine(String.format("MLProp configuration file for %s found but not required. Attempting to rename file to %s", modConfigName, mlPropBackup.getName()));
|
||||
FMLLog.fine("MLProp configuration file for %s found but not required. Attempting to rename file to %s", modClazzName, mlPropBackup.getName());
|
||||
boolean renamed = modConfig.renameTo(mlPropBackup);
|
||||
if (renamed)
|
||||
{
|
||||
Loader.log.fine(String.format("Unused MLProp configuration file for %s renamed successfully to %s", modConfigName, mlPropBackup.getName()));
|
||||
FMLLog.fine("Unused MLProp configuration file for %s renamed successfully to %s", modClazzName, mlPropBackup.getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
Loader.log.fine(String.format("Unused MLProp configuration file for %s renamed UNSUCCESSFULLY to %s", modConfigName, mlPropBackup.getName()));
|
||||
FMLLog.fine("Unused MLProp configuration file for %s renamed UNSUCCESSFULLY to %s", modClazzName, mlPropBackup.getName());
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -268,12 +236,11 @@ public class ModLoaderModContainer implements ModContainer
|
|||
FileWriter configWriter = new FileWriter(modConfig);
|
||||
props.store(configWriter, comments.toString());
|
||||
configWriter.close();
|
||||
Loader.log.fine(String.format("Configuration for %s written to %s", modConfigName, modConfig.getName()));
|
||||
FMLLog.fine("Configuration for %s written to %s", modClazzName, modConfig.getName());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Loader.log.warning(String.format("Error trying to write the config file %s", modConfig.getName()));
|
||||
Loader.log.throwing("ModLoaderModContainer", "configureMod", e);
|
||||
FMLLog.log(Level.SEVERE, e, "Error trying to write the config file %s", modConfig.getName());
|
||||
throw new LoaderException(e);
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +291,7 @@ public class ModLoaderModContainer implements ModContainer
|
|||
|
||||
if (n.doubleValue() < property.min() || n.doubleValue() > property.max())
|
||||
{
|
||||
Loader.log.warning(String.format("Configuration for %s.%s found value %s outside acceptable range %s,%s", modConfigName,propertyName, n, property.min(), property.max()));
|
||||
FMLLog.warning("Configuration for %s.%s found value %s outside acceptable range %s,%s", modConfigName,propertyName, n, property.min(), property.max());
|
||||
return null;
|
||||
}
|
||||
else
|
||||
|
@ -350,22 +317,11 @@ public class ModLoaderModContainer implements ModContainer
|
|||
throw new IllegalArgumentException("MLProp declared on non-standard type");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
mod.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit()
|
||||
{
|
||||
mod.modsLoaded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return mod != null ? mod.getName() : modClazz.getSimpleName();
|
||||
return mod != null ? mod.getName() : modId;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
@ -377,16 +333,13 @@ public class ModLoaderModContainer implements ModContainer
|
|||
@Override
|
||||
public String getSortingRules()
|
||||
{
|
||||
if (mod!=null) {
|
||||
return mod.getPriorities();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
return sortingProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object mod)
|
||||
{
|
||||
return modClazz.isInstance(mod);
|
||||
return this.mod == mod;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -398,7 +351,7 @@ public class ModLoaderModContainer implements ModContainer
|
|||
{
|
||||
ArrayList<A> modList = new ArrayList<A>();
|
||||
|
||||
for (ModContainer mc : Loader.getModList())
|
||||
for (ModContainer mc : Loader.instance().getActiveModList())
|
||||
{
|
||||
if (mc instanceof ModLoaderModContainer && mc.getMod()!=null)
|
||||
{
|
||||
|
@ -422,258 +375,35 @@ public class ModLoaderModContainer implements ModContainer
|
|||
}
|
||||
|
||||
@Override
|
||||
public int lookupFuelValue(int itemId, int itemDamage)
|
||||
public List<ArtifactVersion> getRequirements()
|
||||
{
|
||||
return mod.addFuel(itemId, itemDamage);
|
||||
return requirements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsPickupNotification()
|
||||
public List<ArtifactVersion> getDependants()
|
||||
{
|
||||
return true;
|
||||
return dependants;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPickupNotifier getPickupNotifier()
|
||||
public List<ArtifactVersion> getDependencies()
|
||||
{
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsToDispense()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDispenseHandler getDispenseHandler()
|
||||
{
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsCraftingNotification()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICraftingHandler getCraftingHandler()
|
||||
{
|
||||
return mod;
|
||||
}
|
||||
|
||||
private void computeDependencies()
|
||||
{
|
||||
dependencies = new ArrayList<String>();
|
||||
preDependencies = new ArrayList<String>();
|
||||
postDependencies = new ArrayList<String>();
|
||||
|
||||
if (mod.getPriorities() == null || mod.getPriorities().length() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
boolean parseFailure=false;
|
||||
StringTokenizer st = new StringTokenizer(mod.getPriorities(), ";");
|
||||
|
||||
for (; st.hasMoreTokens();)
|
||||
{
|
||||
String dep = st.nextToken();
|
||||
String[] depparts = dep.split(":");
|
||||
|
||||
if (depparts.length < 2)
|
||||
{
|
||||
parseFailure=true;
|
||||
continue;
|
||||
}
|
||||
else if ("required-before".equals(depparts[0]) || "required-after".equals(depparts[0]))
|
||||
{
|
||||
if (!depparts[1].trim().equals("*")) {
|
||||
dependencies.add(depparts[1]);
|
||||
} else {
|
||||
parseFailure=true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ("required-before".equals(depparts[0]) || "before".equals(depparts[0]))
|
||||
{
|
||||
postDependencies.add(depparts[1]);
|
||||
} else if ("required-after".equals(depparts[0]) || "after".equals(depparts[0]))
|
||||
{
|
||||
preDependencies.add(depparts[1]);
|
||||
} else {
|
||||
parseFailure=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (parseFailure) {
|
||||
FMLCommonHandler.instance().getFMLLogger().warning(String.format("The mod %s has an incorrect dependency string {%s}", mod.getName(), mod.getPriorities()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDependencies()
|
||||
{
|
||||
if (dependencies == null)
|
||||
{
|
||||
computeDependencies();
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPostDepends()
|
||||
{
|
||||
if (dependencies == null)
|
||||
{
|
||||
computeDependencies();
|
||||
}
|
||||
|
||||
return postDependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPreDepends()
|
||||
{
|
||||
if (dependencies == null)
|
||||
{
|
||||
computeDependencies();
|
||||
}
|
||||
return preDependencies;
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return modClazz.getSimpleName();
|
||||
return modId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsNetworkPackets()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public INetworkHandler getNetworkHandler()
|
||||
{
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ownsNetworkChannel(String channel)
|
||||
{
|
||||
return FMLCommonHandler.instance().getChannelListFor(this).contains(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsConsoleCommands()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IConsoleHandler getConsoleHandler()
|
||||
{
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsPlayerTracking()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPlayerTracker getPlayerTracker()
|
||||
{
|
||||
return mod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param keyHandler
|
||||
* @param allowRepeat
|
||||
*/
|
||||
public void addKeyHandler(IKeyHandler handler)
|
||||
{
|
||||
if (keyHandlers==null) {
|
||||
keyHandlers=new ArrayList<IKeyHandler>();
|
||||
}
|
||||
|
||||
Iterator<IKeyHandler> itr = keyHandlers.iterator();
|
||||
while(itr.hasNext())
|
||||
{
|
||||
IKeyHandler old = itr.next();
|
||||
if (old.getKeyBinding() == handler.getKeyBinding())
|
||||
{
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
|
||||
keyHandlers.add(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IKeyHandler> getKeys()
|
||||
{
|
||||
if (keyHandlers==null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return keyHandlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceType(SourceType type) {
|
||||
this.sourceType=type;
|
||||
}
|
||||
@Override
|
||||
public SourceType getSourceType()
|
||||
{
|
||||
return sourceType;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getMetadata()
|
||||
*/
|
||||
@Override
|
||||
public ModMetadata getMetadata()
|
||||
{
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#setMetadata(cpw.mods.fml.common.ModMetadata)
|
||||
*/
|
||||
@Override
|
||||
public void setMetadata(ModMetadata meta)
|
||||
{
|
||||
this.metadata=meta;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#gatherRenderers(java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public void gatherRenderers(Map renderers)
|
||||
{
|
||||
mod.onRenderHarvest(renderers);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#requestAnimations()
|
||||
*/
|
||||
@Override
|
||||
public void requestAnimations()
|
||||
{
|
||||
mod.onRegisterAnimations();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#getVersion()
|
||||
*/
|
||||
@Override
|
||||
public String getVersion()
|
||||
{
|
||||
|
@ -684,9 +414,6 @@ public class ModLoaderModContainer implements ModContainer
|
|||
return mod.getVersion();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#findSidedProxy()
|
||||
*/
|
||||
@Override
|
||||
public ProxyInjector findSidedProxy()
|
||||
{
|
||||
|
@ -700,15 +427,6 @@ public class ModLoaderModContainer implements ModContainer
|
|||
return sidedProxy == NULLPROXY ? null : sidedProxy;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see cpw.mods.fml.common.ModContainer#keyBindEvernt(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void keyBindEvent(Object keybinding)
|
||||
{
|
||||
mod.keyBindingEvent(keybinding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
|
@ -723,4 +441,121 @@ public class ModLoaderModContainer implements ModContainer
|
|||
{
|
||||
return this.guiTickHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModId()
|
||||
{
|
||||
return modId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindMetadata(MetadataCollection mc)
|
||||
{
|
||||
Map<String, Object> dummyMetadata = ImmutableMap.<String,Object>builder().put("name", modId).put("version", "").build();
|
||||
this.metadata = mc.getMetadataForId(modId, dummyMetadata);
|
||||
Loader.instance().computeDependencies(sortingProperties, getRequirements(), getDependencies(), getDependants());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabledState(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerBus(EventBus bus, LoadController controller)
|
||||
{
|
||||
if (this.enabled)
|
||||
{
|
||||
FMLLog.fine("Enabling mod %s", getModId());
|
||||
this.bus = bus;
|
||||
this.controller = controller;
|
||||
bus.register(this);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Lifecycle mod events
|
||||
|
||||
@Subscribe
|
||||
public void constructMod(FMLConstructionEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
ModClassLoader modClassLoader = event.getModClassLoader();
|
||||
modClassLoader.addFile(modSource);
|
||||
Class<? extends BaseMod> modClazz = (Class<? extends BaseMod>) Class.forName(modClazzName, true, modClassLoader);
|
||||
configureMod(modClazz);
|
||||
mod = (BaseMod)modClazz.newInstance();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
controller.errorOccurred(this, e);
|
||||
Throwables.propagateIfPossible(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void preInit(FMLPreInitializationEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
EnumSet<TickType> ticks = EnumSet.noneOf(TickType.class);
|
||||
this.gameTickHandler = new BaseModTicker(ticks, false);
|
||||
this.guiTickHandler = new BaseModTicker(ticks.clone(), true);
|
||||
this.gameTickHandler.setMod(mod);
|
||||
this.guiTickHandler.setMod(mod);
|
||||
TickRegistry.registerTickHandler(this.gameTickHandler);
|
||||
TickRegistry.registerTickHandler(this.guiTickHandler);
|
||||
GameRegistry.registerWorldGenerator(this.mod);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
controller.errorOccurred(this, e);
|
||||
Throwables.propagateIfPossible(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void init(FMLInitializationEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
mod.load();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
controller.errorOccurred(this, t);
|
||||
Throwables.propagateIfPossible(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void postInit(FMLPostInitializationEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
mod.modsLoaded();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
controller.errorOccurred(this, t);
|
||||
Throwables.propagateIfPossible(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArtifactVersion getProcessedVersion()
|
||||
{
|
||||
if (processedVersion == null)
|
||||
{
|
||||
processedVersion = new DefaultArtifactVersion(modId, getVersion());
|
||||
}
|
||||
return processedVersion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package cpw.mods.fml.common.registry;
|
||||
|
||||
public interface BlockProxy
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package cpw.mods.fml.common.registry;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.src.BiomeGenBase;
|
||||
import net.minecraft.src.Entity;
|
||||
import net.minecraft.src.EntityList;
|
||||
import net.minecraft.src.EntityLiving;
|
||||
import net.minecraft.src.EnumCreatureType;
|
||||
import net.minecraft.src.SpawnListEntry;
|
||||
|
||||
public class EntityRegistry
|
||||
{
|
||||
|
||||
public static void registerEntityID(Class <? extends Entity > entityClass, String entityName, int id)
|
||||
{
|
||||
EntityList.func_75618_a(entityClass, entityName, id);
|
||||
}
|
||||
|
||||
public void registerEntityID(Class <? extends Entity > entityClass, String entityName, int id, int backgroundEggColour, int foregroundEggColour)
|
||||
{
|
||||
EntityList.func_75614_a(entityClass, entityName, id, backgroundEggColour, foregroundEggColour);
|
||||
}
|
||||
|
||||
public void addSpawn(Class <? extends EntityLiving > entityClass, int weightedProb, int min, int max, EnumCreatureType typeOfCreature, BiomeGenBase... biomes)
|
||||
{
|
||||
for (BiomeGenBase biome : biomes)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
List<SpawnListEntry> spawns = biome.func_76747_a(typeOfCreature);
|
||||
|
||||
for (SpawnListEntry entry : spawns)
|
||||
{
|
||||
//Adjusting an existing spawn entry
|
||||
if (entry.field_76300_b == entityClass)
|
||||
{
|
||||
entry.field_76292_a = weightedProb;
|
||||
entry.field_76301_c = min;
|
||||
entry.field_76299_d = max;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spawns.add(new SpawnListEntry(entityClass, weightedProb, min, max));
|
||||
}
|
||||
}
|
||||
|
||||
public void addSpawn(String entityName, int weightedProb, int min, int max, EnumCreatureType spawnList, BiomeGenBase... biomes)
|
||||
{
|
||||
Class <? extends Entity > entityClazz = (Class<? extends Entity>) EntityList.field_75625_b.get(entityName);
|
||||
|
||||
if (EntityLiving.class.isAssignableFrom(entityClazz))
|
||||
{
|
||||
addSpawn((Class <? extends EntityLiving >) entityClazz, weightedProb, min, max, spawnList, biomes);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSpawn(Class <? extends EntityLiving > entityClass, EnumCreatureType typeOfCreature, BiomeGenBase... biomes)
|
||||
{
|
||||
for (BiomeGenBase biome : biomes)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<SpawnListEntry> spawns = biome.func_76747_a(typeOfCreature).iterator();
|
||||
|
||||
while (spawns.hasNext())
|
||||
{
|
||||
SpawnListEntry entry = spawns.next();
|
||||
if (entry.field_76300_b == entityClass)
|
||||
{
|
||||
spawns.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSpawn(String entityName, EnumCreatureType spawnList, BiomeGenBase... biomes)
|
||||
{
|
||||
Class <? extends Entity > entityClazz = (Class<? extends Entity>) EntityList.field_75625_b.get(entityName);
|
||||
|
||||
if (EntityLiving.class.isAssignableFrom(entityClazz))
|
||||
{
|
||||
removeSpawn((Class <? extends EntityLiving >) entityClazz, spawnList, biomes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -13,20 +13,19 @@
|
|||
*/
|
||||
package cpw.mods.fml.common.registry;
|
||||
|
||||
|
||||
import net.minecraft.src.BiomeGenBase;
|
||||
import net.minecraft.src.Block;
|
||||
import net.minecraft.src.Entity;
|
||||
import net.minecraft.src.EntityLiving;
|
||||
import net.minecraft.src.EnumCreatureType;
|
||||
import net.minecraft.src.IRecipe;
|
||||
import net.minecraft.src.ItemBlock;
|
||||
import net.minecraft.src.ItemStack;
|
||||
import net.minecraft.src.TileEntity;
|
||||
|
||||
|
||||
public class FMLRegistry
|
||||
{
|
||||
private static IMinecraftRegistry instance;
|
||||
static IMinecraftRegistry instance;
|
||||
|
||||
public static void registerRegistry(IMinecraftRegistry registry)
|
||||
{
|
||||
|
@ -37,45 +36,6 @@ public class FMLRegistry
|
|||
|
||||
instance = registry;
|
||||
}
|
||||
public static void addRecipe(ItemStack output, Object... params)
|
||||
{
|
||||
instance.addRecipe(output, params);
|
||||
}
|
||||
|
||||
public static void addShapelessRecipe(ItemStack output, Object... params)
|
||||
{
|
||||
instance.addShapelessRecipe(output, params);
|
||||
}
|
||||
|
||||
public static void addRecipe(IRecipe recipe)
|
||||
{
|
||||
instance.addRecipe(recipe);
|
||||
}
|
||||
|
||||
public static void addSmelting(int input, ItemStack output)
|
||||
{
|
||||
instance.addSmelting(input, output);
|
||||
}
|
||||
|
||||
public static void registerBlock(Block block)
|
||||
{
|
||||
instance.registerBlock(block);
|
||||
}
|
||||
|
||||
public static void registerBlock(Block block, Class <? extends ItemBlock > itemclass)
|
||||
{
|
||||
instance.registerBlock(block, itemclass);
|
||||
}
|
||||
|
||||
public static void registerEntityID(Class <? extends Entity > entityClass, String entityName, int id)
|
||||
{
|
||||
instance.registerEntityID(entityClass, entityName, id);
|
||||
}
|
||||
|
||||
public static void registerEntityID(Class <? extends Entity > entityClass, String entityName, int id, int backgroundEggColour, int foregroundEggColour)
|
||||
{
|
||||
instance.registerEntityID(entityClass, entityName, id, backgroundEggColour, foregroundEggColour);
|
||||
}
|
||||
|
||||
public static void registerTileEntity(Class <? extends TileEntity > tileEntityClass, String id)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
package cpw.mods.fml.common.registry;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import net.minecraft.src.BiomeGenBase;
|
||||
import net.minecraft.src.CraftingManager;
|
||||
import net.minecraft.src.FurnaceRecipes;
|
||||
import net.minecraft.src.IRecipe;
|
||||
import net.minecraft.src.ItemBlock;
|
||||
import net.minecraft.src.ItemStack;
|
||||
import net.minecraft.src.TileEntity;
|
||||
import net.minecraft.src.WorldType;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.IWorldGenerator;
|
||||
import cpw.mods.fml.common.LoaderException;
|
||||
import cpw.mods.fml.common.Mod.Block;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
public class GameRegistry
|
||||
{
|
||||
private static Multimap<ModContainer, BlockProxy> blockRegistry = ArrayListMultimap.create();
|
||||
private static Multimap<ModContainer, ItemProxy> itemRegistry = ArrayListMultimap.create();
|
||||
private static Set<IWorldGenerator> worldGenerators = new HashSet<IWorldGenerator>();
|
||||
|
||||
public static void registerWorldGenerator(IWorldGenerator generator)
|
||||
{
|
||||
worldGenerators.add(generator);
|
||||
}
|
||||
|
||||
public static void generateWorld(int chunkX, int chunkZ, long worldSeed, Object... data)
|
||||
{
|
||||
Random fmlRandom = new Random(worldSeed);
|
||||
long xSeed = fmlRandom.nextLong() >> 2 + 1L;
|
||||
long zSeed = fmlRandom.nextLong() >> 2 + 1L;
|
||||
fmlRandom.setSeed((xSeed * chunkX + zSeed * chunkZ) ^ worldSeed);
|
||||
|
||||
for (IWorldGenerator generator : worldGenerators)
|
||||
{
|
||||
generator.generate(fmlRandom, chunkX, chunkZ, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Object buildBlock(ModContainer container, Class<?> type, Block annotation) throws Exception
|
||||
{
|
||||
Object o = type.getConstructor(int.class).newInstance(findSpareBlockId());
|
||||
registerBlock((net.minecraft.src.Block) o);
|
||||
return o;
|
||||
}
|
||||
|
||||
private static int findSpareBlockId()
|
||||
{
|
||||
return 250;
|
||||
}
|
||||
|
||||
public static void registerBlock(net.minecraft.src.Block block)
|
||||
{
|
||||
registerBlock(block, ItemBlock.class);
|
||||
}
|
||||
|
||||
public static void registerBlock(net.minecraft.src.Block block, Class<? extends ItemBlock> itemclass)
|
||||
{
|
||||
try
|
||||
{
|
||||
assert block != null : "registerBlock: block cannot be null";
|
||||
assert itemclass != null : "registerBlock: itemclass cannot be null";
|
||||
int blockItemId = block.field_71990_ca - 256;
|
||||
itemclass.getConstructor(int.class).newInstance(blockItemId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, e, "Caught an exception during block registration");
|
||||
throw new LoaderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addRecipe(ItemStack output, Object... params)
|
||||
{
|
||||
CraftingManager.func_77594_a().func_77595_a(output, params);
|
||||
}
|
||||
|
||||
public static void addShapelessRecipe(ItemStack output, Object... params)
|
||||
{
|
||||
CraftingManager.func_77594_a().func_77596_b(output, params);
|
||||
}
|
||||
|
||||
public static void addRecipe(IRecipe recipe)
|
||||
{
|
||||
CraftingManager.func_77594_a().func_77592_b().add(recipe);
|
||||
}
|
||||
|
||||
public static void addSmelting(int input, ItemStack output, float xp)
|
||||
{
|
||||
FurnaceRecipes.func_77602_a().func_77600_a(input, output, xp);
|
||||
}
|
||||
|
||||
public static void registerTileEntity(Class<? extends TileEntity> tileEntityClass, String id)
|
||||
{
|
||||
TileEntity.func_70306_a(tileEntityClass, id);
|
||||
}
|
||||
|
||||
public static void addBiome(BiomeGenBase biome)
|
||||
{
|
||||
WorldType.field_77137_b.addNewBiome(biome);
|
||||
}
|
||||
|
||||
public static void removeBiome(BiomeGenBase biome)
|
||||
{
|
||||
WorldType.field_77137_b.removeBiome(biome);
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ public interface IMinecraftRegistry
|
|||
|
||||
public abstract void registerBlock(Block block);
|
||||
|
||||
public abstract void addSmelting(int input, ItemStack output);
|
||||
public abstract void addSmelting(int input, ItemStack output, float xp);
|
||||
|
||||
public abstract void addShapelessRecipe(ItemStack output, Object... params);
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package cpw.mods.fml.common.registry;
|
||||
|
||||
public interface ItemProxy
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package cpw.mods.fml.common.registry;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import com.google.common.collect.Queues;
|
||||
|
||||
import cpw.mods.fml.common.IScheduledTickHandler;
|
||||
import cpw.mods.fml.common.ITickHandler;
|
||||
import cpw.mods.fml.common.SingleIntervalHandler;
|
||||
|
||||
public class TickRegistry
|
||||
{
|
||||
|
||||
/**
|
||||
* We register our delegate here
|
||||
* @param handler
|
||||
*/
|
||||
|
||||
public static class TickQueueElement implements Comparable<TickQueueElement>
|
||||
{
|
||||
public static long tickCounter = 0;
|
||||
public TickQueueElement(IScheduledTickHandler ticker)
|
||||
{
|
||||
this.ticker = ticker;
|
||||
update();
|
||||
}
|
||||
@Override
|
||||
public int compareTo(TickQueueElement o)
|
||||
{
|
||||
return (int)(next - o.next);
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
next = tickCounter + Math.max(ticker.nextTickSpacing(),1);
|
||||
}
|
||||
|
||||
private long next;
|
||||
public IScheduledTickHandler ticker;
|
||||
|
||||
public boolean scheduledNow()
|
||||
{
|
||||
return tickCounter >= next;
|
||||
}
|
||||
}
|
||||
|
||||
private static PriorityQueue<TickQueueElement> tickHandlers = Queues.newPriorityQueue();
|
||||
|
||||
public static void registerScheduledTickHandler(IScheduledTickHandler handler)
|
||||
{
|
||||
tickHandlers.add(new TickQueueElement(handler));
|
||||
}
|
||||
|
||||
public static void registerTickHandler(ITickHandler handler)
|
||||
{
|
||||
registerScheduledTickHandler(new SingleIntervalHandler(handler));
|
||||
}
|
||||
|
||||
public static void updateTickQueue(List<IScheduledTickHandler> ticks)
|
||||
{
|
||||
ticks.clear();
|
||||
TickQueueElement.tickCounter++;
|
||||
while (true)
|
||||
{
|
||||
if (tickHandlers.size()==0 || !tickHandlers.peek().scheduledNow())
|
||||
{
|
||||
break;
|
||||
}
|
||||
TickRegistry.TickQueueElement tickQueueElement = tickHandlers.poll();
|
||||
tickQueueElement.update();
|
||||
tickHandlers.offer(tickQueueElement);
|
||||
ticks.add(tickQueueElement.ticker);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,9 +16,11 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import cpw.mods.fml.common.DummyModContainer;
|
||||
import cpw.mods.fml.common.FMLModContainer;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.toposort.TopologicalSort.DirectedGraph;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
|
||||
/**
|
||||
* @author cpw
|
||||
|
@ -28,10 +30,10 @@ public class ModSorter
|
|||
{
|
||||
private DirectedGraph<ModContainer> modGraph;
|
||||
|
||||
private ModContainer beforeAll = new FMLModContainer("DummyBeforeAll");
|
||||
private ModContainer afterAll = new FMLModContainer("DummyAfterAll");
|
||||
private ModContainer before = new FMLModContainer("DummyBefore");
|
||||
private ModContainer after = new FMLModContainer("DummyAfter");
|
||||
private ModContainer beforeAll = new DummyModContainer();
|
||||
private ModContainer afterAll = new DummyModContainer();
|
||||
private ModContainer before = new DummyModContainer();
|
||||
private ModContainer after = new DummyModContainer();
|
||||
|
||||
public ModSorter(List<ModContainer> modList, Map<String, ModContainer> nameLookup)
|
||||
{
|
||||
|
@ -59,11 +61,11 @@ public class ModSorter
|
|||
boolean preDepAdded = false;
|
||||
boolean postDepAdded = false;
|
||||
|
||||
for (String dep : mod.getPreDepends())
|
||||
for (ArtifactVersion dep : mod.getDependencies())
|
||||
{
|
||||
preDepAdded = true;
|
||||
|
||||
if (dep.equals("*"))
|
||||
if (dep.getLabel().equals("*"))
|
||||
{
|
||||
// We are "after" everything
|
||||
modGraph.addEdge(mod, afterAll);
|
||||
|
@ -73,17 +75,17 @@ public class ModSorter
|
|||
else
|
||||
{
|
||||
modGraph.addEdge(before, mod);
|
||||
if (nameLookup.containsKey(dep)) {
|
||||
modGraph.addEdge(nameLookup.get(dep), mod);
|
||||
if (nameLookup.containsKey(dep.getLabel())) {
|
||||
modGraph.addEdge(nameLookup.get(dep.getLabel()), mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String dep : mod.getPostDepends())
|
||||
for (ArtifactVersion dep : mod.getDependants())
|
||||
{
|
||||
postDepAdded = true;
|
||||
|
||||
if (dep.equals("*"))
|
||||
if (dep.getLabel().equals("*"))
|
||||
{
|
||||
// We are "before" everything
|
||||
modGraph.addEdge(beforeAll, mod);
|
||||
|
@ -93,8 +95,8 @@ public class ModSorter
|
|||
else
|
||||
{
|
||||
modGraph.addEdge(mod, after);
|
||||
if (nameLookup.containsKey(dep)) {
|
||||
modGraph.addEdge(mod, nameLookup.get(dep));
|
||||
if (nameLookup.containsKey(dep.getLabel())) {
|
||||
modGraph.addEdge(mod, nameLookup.get(dep.getLabel()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package cpw.mods.fml.common.toposort;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
public class ModSortingException extends RuntimeException
|
||||
{
|
||||
public class SortingExceptionData<T>
|
||||
{
|
||||
public SortingExceptionData(T node, Set<T> visitedNodes)
|
||||
{
|
||||
this.firstBadNode = node;
|
||||
this.visitedNodes = visitedNodes;
|
||||
}
|
||||
|
||||
private T firstBadNode;
|
||||
private Set<T> visitedNodes;
|
||||
|
||||
public T getFirstBadNode()
|
||||
{
|
||||
return firstBadNode;
|
||||
}
|
||||
public Set<T> getVisitedNodes()
|
||||
{
|
||||
return visitedNodes;
|
||||
}
|
||||
}
|
||||
|
||||
private SortingExceptionData sortingExceptionData;
|
||||
|
||||
public <T> ModSortingException(String string, T node, Set<T> visitedNodes)
|
||||
{
|
||||
super(string);
|
||||
this.sortingExceptionData = new SortingExceptionData(node, visitedNodes);
|
||||
}
|
||||
|
||||
public <T> SortingExceptionData<T> getExceptionData()
|
||||
{
|
||||
return sortingExceptionData;
|
||||
}
|
||||
|
||||
}
|
|
@ -39,7 +39,7 @@ public class TopologicalSort
|
|||
{
|
||||
private final Map<T, SortedSet<T>> graph = new HashMap<T, SortedSet<T>>();
|
||||
private List<T> orderedNodes = new ArrayList<T>();
|
||||
|
||||
|
||||
public boolean addNode(T node)
|
||||
{
|
||||
// Ignore nodes already added
|
||||
|
@ -176,7 +176,7 @@ public class TopologicalSort
|
|||
}
|
||||
|
||||
System.out.printf("%s: %s\n%s\n%s\n", node, sortedResult, visitedNodes, expandedNodes);
|
||||
throw new IllegalArgumentException("There was a cycle detected in the input graph, sorting is not possible");
|
||||
throw new ModSortingException("There was a cycle detected in the input graph, sorting is not possible", node, visitedNodes);
|
||||
}
|
||||
|
||||
// Visit this node
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package cpw.mods.fml.common.versioning;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Describes an artifact version in terms of its components, converts it to/from a string and
|
||||
* compares two versions.
|
||||
*
|
||||
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
|
||||
*/
|
||||
public interface ArtifactVersion
|
||||
extends Comparable<ArtifactVersion>
|
||||
{
|
||||
String getLabel();
|
||||
|
||||
boolean containsVersion(ArtifactVersion source);
|
||||
}
|
|
@ -0,0 +1,467 @@
|
|||
package cpw.mods.fml.common.versioning;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Generic implementation of version comparison.
|
||||
*
|
||||
* <p>Features:
|
||||
* <ul>
|
||||
* <li>mixing of '<code>-</code>' (dash) and '<code>.</code>' (dot) separators,</li>
|
||||
* <li>transition between characters and digits also constitutes a separator:
|
||||
* <code>1.0alpha1 => [1, 0, alpha, 1]</code></li>
|
||||
* <li>unlimited number of version components,</li>
|
||||
* <li>version components in the text can be digits or strings,</li>
|
||||
* <li>strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering.
|
||||
* Well-known qualifiers (case insensitive) are:<ul>
|
||||
* <li><code>snapshot</code></li>
|
||||
* <li><code>alpha</code> or <code>a</code></li>
|
||||
* <li><code>beta</code> or <code>b</code></li>
|
||||
* <li><code>milestone</code> or <code>m</code></li>
|
||||
* <li><code>rc</code> or <code>cr</code></li>
|
||||
* <li><code>(the empty string)</code> or <code>ga</code> or <code>final</code></li>
|
||||
* <li><code>sp</code></li>
|
||||
* </ul>
|
||||
* Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive),
|
||||
* </li>
|
||||
* <li>a dash usually precedes a qualifier, and is always less important than something preceded with a dot.</li>
|
||||
* </ul></p>
|
||||
*
|
||||
* @see <a href="https://cwiki.apache.org/confluence/display/MAVENOLD/Versioning">"Versioning" on Maven Wiki</a>
|
||||
* @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
|
||||
* @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
|
||||
*/
|
||||
public class ComparableVersion
|
||||
implements Comparable<ComparableVersion>
|
||||
{
|
||||
private String value;
|
||||
|
||||
private String canonical;
|
||||
|
||||
private ListItem items;
|
||||
|
||||
private interface Item
|
||||
{
|
||||
final int INTEGER_ITEM = 0;
|
||||
final int STRING_ITEM = 1;
|
||||
final int LIST_ITEM = 2;
|
||||
|
||||
int compareTo( Item item );
|
||||
|
||||
int getType();
|
||||
|
||||
boolean isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a numeric item in the version item list.
|
||||
*/
|
||||
private static class IntegerItem
|
||||
implements Item
|
||||
{
|
||||
private static final BigInteger BigInteger_ZERO = new BigInteger( "0" );
|
||||
|
||||
private final BigInteger value;
|
||||
|
||||
public static final IntegerItem ZERO = new IntegerItem();
|
||||
|
||||
private IntegerItem()
|
||||
{
|
||||
this.value = BigInteger_ZERO;
|
||||
}
|
||||
|
||||
public IntegerItem( String str )
|
||||
{
|
||||
this.value = new BigInteger( str );
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return INTEGER_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull()
|
||||
{
|
||||
return BigInteger_ZERO.equals( value );
|
||||
}
|
||||
|
||||
public int compareTo( Item item )
|
||||
{
|
||||
if ( item == null )
|
||||
{
|
||||
return BigInteger_ZERO.equals( value ) ? 0 : 1; // 1.0 == 1, 1.1 > 1
|
||||
}
|
||||
|
||||
switch ( item.getType() )
|
||||
{
|
||||
case INTEGER_ITEM:
|
||||
return value.compareTo( ( (IntegerItem) item ).value );
|
||||
|
||||
case STRING_ITEM:
|
||||
return 1; // 1.1 > 1-sp
|
||||
|
||||
case LIST_ITEM:
|
||||
return 1; // 1.1 > 1-1
|
||||
|
||||
default:
|
||||
throw new RuntimeException( "invalid item: " + item.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a string in the version item list, usually a qualifier.
|
||||
*/
|
||||
private static class StringItem
|
||||
implements Item
|
||||
{
|
||||
private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" };
|
||||
|
||||
private static final List<String> _QUALIFIERS = Arrays.asList( QUALIFIERS );
|
||||
|
||||
private static final Properties ALIASES = new Properties();
|
||||
static
|
||||
{
|
||||
ALIASES.put( "ga", "" );
|
||||
ALIASES.put( "final", "" );
|
||||
ALIASES.put( "cr", "rc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes
|
||||
* the version older than one without a qualifier, or more recent.
|
||||
*/
|
||||
private static final String RELEASE_VERSION_INDEX = String.valueOf( _QUALIFIERS.indexOf( "" ) );
|
||||
|
||||
private String value;
|
||||
|
||||
public StringItem( String value, boolean followedByDigit )
|
||||
{
|
||||
if ( followedByDigit && value.length() == 1 )
|
||||
{
|
||||
// a1 = alpha-1, b1 = beta-1, m1 = milestone-1
|
||||
switch ( value.charAt( 0 ) )
|
||||
{
|
||||
case 'a':
|
||||
value = "alpha";
|
||||
break;
|
||||
case 'b':
|
||||
value = "beta";
|
||||
break;
|
||||
case 'm':
|
||||
value = "milestone";
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.value = ALIASES.getProperty( value , value );
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return STRING_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull()
|
||||
{
|
||||
return ( comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ) == 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a comparable value for a qualifier.
|
||||
*
|
||||
* This method takes into account the ordering of known qualifiers then unknown qualifiers with lexical ordering.
|
||||
*
|
||||
* just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1
|
||||
* or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character,
|
||||
* so this is still fast. If more characters are needed then it requires a lexical sort anyway.
|
||||
*
|
||||
* @param qualifier
|
||||
* @return an equivalent value that can be used with lexical comparison
|
||||
*/
|
||||
public static String comparableQualifier( String qualifier )
|
||||
{
|
||||
int i = _QUALIFIERS.indexOf( qualifier );
|
||||
|
||||
return i == -1 ? ( _QUALIFIERS.size() + "-" + qualifier ) : String.valueOf( i );
|
||||
}
|
||||
|
||||
public int compareTo( Item item )
|
||||
{
|
||||
if ( item == null )
|
||||
{
|
||||
// 1-rc < 1, 1-ga > 1
|
||||
return comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX );
|
||||
}
|
||||
switch ( item.getType() )
|
||||
{
|
||||
case INTEGER_ITEM:
|
||||
return -1; // 1.any < 1.1 ?
|
||||
|
||||
case STRING_ITEM:
|
||||
return comparableQualifier( value ).compareTo( comparableQualifier( ( (StringItem) item ).value ) );
|
||||
|
||||
case LIST_ITEM:
|
||||
return -1; // 1.any < 1-1
|
||||
|
||||
default:
|
||||
throw new RuntimeException( "invalid item: " + item.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a version list item. This class is used both for the global item list and for sub-lists (which start
|
||||
* with '-(number)' in the version specification).
|
||||
*/
|
||||
private static class ListItem
|
||||
extends ArrayList<Item>
|
||||
implements Item
|
||||
{
|
||||
public int getType()
|
||||
{
|
||||
return LIST_ITEM;
|
||||
}
|
||||
|
||||
public boolean isNull()
|
||||
{
|
||||
return ( size() == 0 );
|
||||
}
|
||||
|
||||
void normalize()
|
||||
{
|
||||
for( ListIterator<Item> iterator = listIterator( size() ); iterator.hasPrevious(); )
|
||||
{
|
||||
Item item = iterator.previous();
|
||||
if ( item.isNull() )
|
||||
{
|
||||
iterator.remove(); // remove null trailing items: 0, "", empty list
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo( Item item )
|
||||
{
|
||||
if ( item == null )
|
||||
{
|
||||
if ( size() == 0 )
|
||||
{
|
||||
return 0; // 1-0 = 1- (normalize) = 1
|
||||
}
|
||||
Item first = get( 0 );
|
||||
return first.compareTo( null );
|
||||
}
|
||||
switch ( item.getType() )
|
||||
{
|
||||
case INTEGER_ITEM:
|
||||
return -1; // 1-1 < 1.0.x
|
||||
|
||||
case STRING_ITEM:
|
||||
return 1; // 1-1 > 1-sp
|
||||
|
||||
case LIST_ITEM:
|
||||
Iterator<Item> left = iterator();
|
||||
Iterator<Item> right = ( (ListItem) item ).iterator();
|
||||
|
||||
while ( left.hasNext() || right.hasNext() )
|
||||
{
|
||||
Item l = left.hasNext() ? left.next() : null;
|
||||
Item r = right.hasNext() ? right.next() : null;
|
||||
|
||||
// if this is shorter, then invert the compare and mul with -1
|
||||
int result = l == null ? -1 * r.compareTo( l ) : l.compareTo( r );
|
||||
|
||||
if ( result != 0 )
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
throw new RuntimeException( "invalid item: " + item.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder( "(" );
|
||||
for( Iterator<Item> iter = iterator(); iter.hasNext(); )
|
||||
{
|
||||
buffer.append( iter.next() );
|
||||
if ( iter.hasNext() )
|
||||
{
|
||||
buffer.append( ',' );
|
||||
}
|
||||
}
|
||||
buffer.append( ')' );
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public ComparableVersion( String version )
|
||||
{
|
||||
parseVersion( version );
|
||||
}
|
||||
|
||||
public final void parseVersion( String version )
|
||||
{
|
||||
this.value = version;
|
||||
|
||||
items = new ListItem();
|
||||
|
||||
version = version.toLowerCase( Locale.ENGLISH );
|
||||
|
||||
ListItem list = items;
|
||||
|
||||
Stack<Item> stack = new Stack<Item>();
|
||||
stack.push( list );
|
||||
|
||||
boolean isDigit = false;
|
||||
|
||||
int startIndex = 0;
|
||||
|
||||
for ( int i = 0; i < version.length(); i++ )
|
||||
{
|
||||
char c = version.charAt( i );
|
||||
|
||||
if ( c == '.' )
|
||||
{
|
||||
if ( i == startIndex )
|
||||
{
|
||||
list.add( IntegerItem.ZERO );
|
||||
}
|
||||
else
|
||||
{
|
||||
list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
|
||||
}
|
||||
startIndex = i + 1;
|
||||
}
|
||||
else if ( c == '-' )
|
||||
{
|
||||
if ( i == startIndex )
|
||||
{
|
||||
list.add( IntegerItem.ZERO );
|
||||
}
|
||||
else
|
||||
{
|
||||
list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
|
||||
}
|
||||
startIndex = i + 1;
|
||||
|
||||
if ( isDigit )
|
||||
{
|
||||
list.normalize(); // 1.0-* = 1-*
|
||||
|
||||
if ( ( i + 1 < version.length() ) && Character.isDigit( version.charAt( i + 1 ) ) )
|
||||
{
|
||||
// new ListItem only if previous were digits and new char is a digit,
|
||||
// ie need to differentiate only 1.1 from 1-1
|
||||
list.add( list = new ListItem() );
|
||||
|
||||
stack.push( list );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( Character.isDigit( c ) )
|
||||
{
|
||||
if ( !isDigit && i > startIndex )
|
||||
{
|
||||
list.add( new StringItem( version.substring( startIndex, i ), true ) );
|
||||
startIndex = i;
|
||||
}
|
||||
|
||||
isDigit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isDigit && i > startIndex )
|
||||
{
|
||||
list.add( parseItem( true, version.substring( startIndex, i ) ) );
|
||||
startIndex = i;
|
||||
}
|
||||
|
||||
isDigit = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( version.length() > startIndex )
|
||||
{
|
||||
list.add( parseItem( isDigit, version.substring( startIndex ) ) );
|
||||
}
|
||||
|
||||
while ( !stack.isEmpty() )
|
||||
{
|
||||
list = (ListItem) stack.pop();
|
||||
list.normalize();
|
||||
}
|
||||
|
||||
canonical = items.toString();
|
||||
}
|
||||
|
||||
private static Item parseItem( boolean isDigit, String buf )
|
||||
{
|
||||
return isDigit ? new IntegerItem( buf ) : new StringItem( buf, false );
|
||||
}
|
||||
|
||||
public int compareTo( ComparableVersion o )
|
||||
{
|
||||
return items.compareTo( o.items );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean equals( Object o )
|
||||
{
|
||||
return ( o instanceof ComparableVersion ) && canonical.equals( ( (ComparableVersion) o ).canonical );
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return canonical.hashCode();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package cpw.mods.fml.common.versioning;
|
||||
|
||||
public class DefaultArtifactVersion implements ArtifactVersion
|
||||
{
|
||||
|
||||
private ComparableVersion comparableVersion;
|
||||
private String label;
|
||||
private boolean unbounded;
|
||||
private VersionRange range;
|
||||
|
||||
public DefaultArtifactVersion(String versionNumber)
|
||||
{
|
||||
comparableVersion = new ComparableVersion(versionNumber);
|
||||
range = VersionRange.createFromVersion(versionNumber, this);
|
||||
}
|
||||
|
||||
public DefaultArtifactVersion(String label, VersionRange range)
|
||||
{
|
||||
this.label = label;
|
||||
this.range = range;
|
||||
}
|
||||
public DefaultArtifactVersion(String label, String version)
|
||||
{
|
||||
this(version);
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public DefaultArtifactVersion(String string, boolean unbounded)
|
||||
{
|
||||
this.label = string;
|
||||
this.unbounded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
return ((DefaultArtifactVersion)obj).containsVersion(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ArtifactVersion o)
|
||||
{
|
||||
return unbounded ? 0 : this.comparableVersion.compareTo(((DefaultArtifactVersion)o).comparableVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsVersion(ArtifactVersion source)
|
||||
{
|
||||
if (!source.getLabel().equals(getLabel()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (unbounded)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (range != null)
|
||||
{
|
||||
return range.containsVersion(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return label == null ? comparableVersion.toString() : label + ( unbounded ? "" : "@" + range);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package cpw.mods.fml.common.versioning;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Occurs when a version is invalid.
|
||||
*
|
||||
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
|
||||
*/
|
||||
public class InvalidVersionSpecificationException
|
||||
extends Exception
|
||||
{
|
||||
public InvalidVersionSpecificationException( String message )
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
package cpw.mods.fml.common.versioning;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Describes a restriction in versioning.
|
||||
*
|
||||
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
|
||||
*/
|
||||
public class Restriction
|
||||
{
|
||||
private final ArtifactVersion lowerBound;
|
||||
|
||||
private final boolean lowerBoundInclusive;
|
||||
|
||||
private final ArtifactVersion upperBound;
|
||||
|
||||
private final boolean upperBoundInclusive;
|
||||
|
||||
public static final Restriction EVERYTHING = new Restriction( null, false, null, false );
|
||||
|
||||
public Restriction( ArtifactVersion lowerBound, boolean lowerBoundInclusive, ArtifactVersion upperBound,
|
||||
boolean upperBoundInclusive )
|
||||
{
|
||||
this.lowerBound = lowerBound;
|
||||
this.lowerBoundInclusive = lowerBoundInclusive;
|
||||
this.upperBound = upperBound;
|
||||
this.upperBoundInclusive = upperBoundInclusive;
|
||||
}
|
||||
|
||||
public ArtifactVersion getLowerBound()
|
||||
{
|
||||
return lowerBound;
|
||||
}
|
||||
|
||||
public boolean isLowerBoundInclusive()
|
||||
{
|
||||
return lowerBoundInclusive;
|
||||
}
|
||||
|
||||
public ArtifactVersion getUpperBound()
|
||||
{
|
||||
return upperBound;
|
||||
}
|
||||
|
||||
public boolean isUpperBoundInclusive()
|
||||
{
|
||||
return upperBoundInclusive;
|
||||
}
|
||||
|
||||
public boolean containsVersion( ArtifactVersion version )
|
||||
{
|
||||
if ( lowerBound != null )
|
||||
{
|
||||
int comparison = lowerBound.compareTo( version );
|
||||
|
||||
if ( ( comparison == 0 ) && !lowerBoundInclusive )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( comparison > 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( upperBound != null )
|
||||
{
|
||||
int comparison = upperBound.compareTo( version );
|
||||
|
||||
if ( ( comparison == 0 ) && !upperBoundInclusive )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( comparison < 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int result = 13;
|
||||
|
||||
if ( lowerBound == null )
|
||||
{
|
||||
result += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += lowerBound.hashCode();
|
||||
}
|
||||
|
||||
result *= lowerBoundInclusive ? 1 : 2;
|
||||
|
||||
if ( upperBound == null )
|
||||
{
|
||||
result -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
result -= upperBound.hashCode();
|
||||
}
|
||||
|
||||
result *= upperBoundInclusive ? 2 : 3;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( Object other )
|
||||
{
|
||||
if ( this == other )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !( other instanceof Restriction ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Restriction restriction = (Restriction) other;
|
||||
if ( lowerBound != null )
|
||||
{
|
||||
if ( !lowerBound.equals( restriction.lowerBound ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( restriction.lowerBound != null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( lowerBoundInclusive != restriction.lowerBoundInclusive )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( upperBound != null )
|
||||
{
|
||||
if ( !upperBound.equals( restriction.upperBound ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( restriction.upperBound != null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( upperBoundInclusive != restriction.upperBoundInclusive )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
buf.append( isLowerBoundInclusive() ? "[" : "(" );
|
||||
if ( getLowerBound() != null )
|
||||
{
|
||||
buf.append( getLowerBound().toString() );
|
||||
}
|
||||
buf.append( "," );
|
||||
if ( getUpperBound() != null )
|
||||
{
|
||||
buf.append( getUpperBound().toString() );
|
||||
}
|
||||
buf.append( isUpperBoundInclusive() ? "]" : ")" );
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package cpw.mods.fml.common.versioning;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.LoaderException;
|
||||
|
||||
/**
|
||||
* Parses version strings according to the specification here:
|
||||
* http://docs.codehaus.org/display/MAVEN/Versioning
|
||||
* and allows for comparison of versions based on that document.
|
||||
* Bounded version specifications are defined as
|
||||
* http://maven.apache.org/plugins/maven-enforcer-plugin/rules/versionRanges.html
|
||||
*
|
||||
* Borrows heavily from maven version range management code
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class VersionParser
|
||||
{
|
||||
private static final Splitter SEPARATOR = Splitter.on('@').omitEmptyStrings().trimResults();
|
||||
public static ArtifactVersion parseVersionReference(String labelledRef)
|
||||
{
|
||||
if (Strings.isNullOrEmpty(labelledRef))
|
||||
{
|
||||
throw new RuntimeException(String.format("Empty reference %s", labelledRef));
|
||||
}
|
||||
List<String> parts = Lists.newArrayList(SEPARATOR.split(labelledRef));
|
||||
if (parts.size()>2)
|
||||
{
|
||||
throw new RuntimeException(String.format("Invalid versioned reference %s", labelledRef));
|
||||
}
|
||||
if (parts.size()==1)
|
||||
{
|
||||
return new DefaultArtifactVersion(parts.get(0), true);
|
||||
}
|
||||
return new DefaultArtifactVersion(parts.get(0),parseRange(parts.get(1)));
|
||||
}
|
||||
|
||||
public static boolean satisfies(ArtifactVersion target, ArtifactVersion source)
|
||||
{
|
||||
return target.containsVersion(source);
|
||||
}
|
||||
|
||||
public static VersionRange parseRange(String range)
|
||||
{
|
||||
try
|
||||
{
|
||||
return VersionRange.createFromVersionSpec(range);
|
||||
}
|
||||
catch (InvalidVersionSpecificationException e)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, e, "Unable to parse a version range specification successfully %s", range);
|
||||
throw new LoaderException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,540 @@
|
|||
package cpw.mods.fml.common.versioning;
|
||||
/*
|
||||
* Modifications by cpw under LGPL 2.1 or later
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
/**
|
||||
* Construct a version range from a specification.
|
||||
*
|
||||
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
|
||||
*/
|
||||
public class VersionRange
|
||||
{
|
||||
private final ArtifactVersion recommendedVersion;
|
||||
|
||||
private final List<Restriction> restrictions;
|
||||
|
||||
private VersionRange( ArtifactVersion recommendedVersion,
|
||||
List<Restriction> restrictions )
|
||||
{
|
||||
this.recommendedVersion = recommendedVersion;
|
||||
this.restrictions = restrictions;
|
||||
}
|
||||
|
||||
public ArtifactVersion getRecommendedVersion()
|
||||
{
|
||||
return recommendedVersion;
|
||||
}
|
||||
|
||||
public List<Restriction> getRestrictions()
|
||||
{
|
||||
return restrictions;
|
||||
}
|
||||
|
||||
public VersionRange cloneOf()
|
||||
{
|
||||
List<Restriction> copiedRestrictions = null;
|
||||
|
||||
if ( restrictions != null )
|
||||
{
|
||||
copiedRestrictions = new ArrayList<Restriction>();
|
||||
|
||||
if ( !restrictions.isEmpty() )
|
||||
{
|
||||
copiedRestrictions.addAll( restrictions );
|
||||
}
|
||||
}
|
||||
|
||||
return new VersionRange( recommendedVersion, copiedRestrictions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a version range from a string representation
|
||||
* <p/>
|
||||
* Some spec examples are
|
||||
* <ul>
|
||||
* <li><code>1.0</code> Version 1.0</li>
|
||||
* <li><code>[1.0,2.0)</code> Versions 1.0 (included) to 2.0 (not included)</li>
|
||||
* <li><code>[1.0,2.0]</code> Versions 1.0 to 2.0 (both included)</li>
|
||||
* <li><code>[1.5,)</code> Versions 1.5 and higher</li>
|
||||
* <li><code>(,1.0],[1.2,)</code> Versions up to 1.0 (included) and 1.2 or higher</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param spec string representation of a version or version range
|
||||
* @return a new {@link VersionRange} object that represents the spec
|
||||
* @throws InvalidVersionSpecificationException
|
||||
*
|
||||
*/
|
||||
public static VersionRange createFromVersionSpec( String spec )
|
||||
throws InvalidVersionSpecificationException
|
||||
{
|
||||
if ( spec == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Restriction> restrictions = new ArrayList<Restriction>();
|
||||
String process = spec;
|
||||
ArtifactVersion version = null;
|
||||
ArtifactVersion upperBound = null;
|
||||
ArtifactVersion lowerBound = null;
|
||||
|
||||
while ( process.startsWith( "[" ) || process.startsWith( "(" ) )
|
||||
{
|
||||
int index1 = process.indexOf( ")" );
|
||||
int index2 = process.indexOf( "]" );
|
||||
|
||||
int index = index2;
|
||||
if ( index2 < 0 || index1 < index2 )
|
||||
{
|
||||
if ( index1 >= 0 )
|
||||
{
|
||||
index = index1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( index < 0 )
|
||||
{
|
||||
throw new InvalidVersionSpecificationException( "Unbounded range: " + spec );
|
||||
}
|
||||
|
||||
Restriction restriction = parseRestriction( process.substring( 0, index + 1 ) );
|
||||
if ( lowerBound == null )
|
||||
{
|
||||
lowerBound = restriction.getLowerBound();
|
||||
}
|
||||
if ( upperBound != null )
|
||||
{
|
||||
if ( restriction.getLowerBound() == null || restriction.getLowerBound().compareTo( upperBound ) < 0 )
|
||||
{
|
||||
throw new InvalidVersionSpecificationException( "Ranges overlap: " + spec );
|
||||
}
|
||||
}
|
||||
restrictions.add( restriction );
|
||||
upperBound = restriction.getUpperBound();
|
||||
|
||||
process = process.substring( index + 1 ).trim();
|
||||
|
||||
if ( process.length() > 0 && process.startsWith( "," ) )
|
||||
{
|
||||
process = process.substring( 1 ).trim();
|
||||
}
|
||||
}
|
||||
|
||||
if ( process.length() > 0 )
|
||||
{
|
||||
if ( restrictions.size() > 0 )
|
||||
{
|
||||
throw new InvalidVersionSpecificationException(
|
||||
"Only fully-qualified sets allowed in multiple set scenario: " + spec );
|
||||
}
|
||||
else
|
||||
{
|
||||
version = new DefaultArtifactVersion( process );
|
||||
restrictions.add( Restriction.EVERYTHING );
|
||||
}
|
||||
}
|
||||
|
||||
return new VersionRange( version, restrictions );
|
||||
}
|
||||
|
||||
private static Restriction parseRestriction( String spec )
|
||||
throws InvalidVersionSpecificationException
|
||||
{
|
||||
boolean lowerBoundInclusive = spec.startsWith( "[" );
|
||||
boolean upperBoundInclusive = spec.endsWith( "]" );
|
||||
|
||||
String process = spec.substring( 1, spec.length() - 1 ).trim();
|
||||
|
||||
Restriction restriction;
|
||||
|
||||
int index = process.indexOf( "," );
|
||||
|
||||
if ( index < 0 )
|
||||
{
|
||||
if ( !lowerBoundInclusive || !upperBoundInclusive )
|
||||
{
|
||||
throw new InvalidVersionSpecificationException( "Single version must be surrounded by []: " + spec );
|
||||
}
|
||||
|
||||
ArtifactVersion version = new DefaultArtifactVersion( process );
|
||||
|
||||
restriction = new Restriction( version, lowerBoundInclusive, version, upperBoundInclusive );
|
||||
}
|
||||
else
|
||||
{
|
||||
String lowerBound = process.substring( 0, index ).trim();
|
||||
String upperBound = process.substring( index + 1 ).trim();
|
||||
if ( lowerBound.equals( upperBound ) )
|
||||
{
|
||||
throw new InvalidVersionSpecificationException( "Range cannot have identical boundaries: " + spec );
|
||||
}
|
||||
|
||||
ArtifactVersion lowerVersion = null;
|
||||
if ( lowerBound.length() > 0 )
|
||||
{
|
||||
lowerVersion = new DefaultArtifactVersion( lowerBound );
|
||||
}
|
||||
ArtifactVersion upperVersion = null;
|
||||
if ( upperBound.length() > 0 )
|
||||
{
|
||||
upperVersion = new DefaultArtifactVersion( upperBound );
|
||||
}
|
||||
|
||||
if ( upperVersion != null && lowerVersion != null && upperVersion.compareTo( lowerVersion ) < 0 )
|
||||
{
|
||||
throw new InvalidVersionSpecificationException( "Range defies version ordering: " + spec );
|
||||
}
|
||||
|
||||
restriction = new Restriction( lowerVersion, lowerBoundInclusive, upperVersion, upperBoundInclusive );
|
||||
}
|
||||
|
||||
return restriction;
|
||||
}
|
||||
|
||||
public static VersionRange createFromVersion( String version , ArtifactVersion existing)
|
||||
{
|
||||
List<Restriction> restrictions = Collections.emptyList();
|
||||
if (existing == null)
|
||||
{
|
||||
existing = new DefaultArtifactVersion( version );
|
||||
}
|
||||
return new VersionRange(existing , restrictions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new <code>VersionRange</code> that is a restriction of this
|
||||
* version range and the specified version range.
|
||||
* <p>
|
||||
* Note: Precedence is given to the recommended version from this version range over the
|
||||
* recommended version from the specified version range.
|
||||
* </p>
|
||||
*
|
||||
* @param restriction the <code>VersionRange</code> that will be used to restrict this version
|
||||
* range.
|
||||
* @return the <code>VersionRange</code> that is a restriction of this version range and the
|
||||
* specified version range.
|
||||
* <p>
|
||||
* The restrictions of the returned version range will be an intersection of the restrictions
|
||||
* of this version range and the specified version range if both version ranges have
|
||||
* restrictions. Otherwise, the restrictions on the returned range will be empty.
|
||||
* </p>
|
||||
* <p>
|
||||
* The recommended version of the returned version range will be the recommended version of
|
||||
* this version range, provided that ranges falls within the intersected restrictions. If
|
||||
* the restrictions are empty, this version range's recommended version is used if it is not
|
||||
* <code>null</code>. If it is <code>null</code>, the specified version range's recommended
|
||||
* version is used (provided it is non-<code>null</code>). If no recommended version can be
|
||||
* obtained, the returned version range's recommended version is set to <code>null</code>.
|
||||
* </p>
|
||||
* @throws NullPointerException if the specified <code>VersionRange</code> is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public VersionRange restrict( VersionRange restriction )
|
||||
{
|
||||
List<Restriction> r1 = this.restrictions;
|
||||
List<Restriction> r2 = restriction.restrictions;
|
||||
List<Restriction> restrictions;
|
||||
|
||||
if ( r1.isEmpty() || r2.isEmpty() )
|
||||
{
|
||||
restrictions = Collections.emptyList();
|
||||
}
|
||||
else
|
||||
{
|
||||
restrictions = intersection( r1, r2 );
|
||||
}
|
||||
|
||||
ArtifactVersion version = null;
|
||||
if ( restrictions.size() > 0 )
|
||||
{
|
||||
for ( Restriction r : restrictions )
|
||||
{
|
||||
if ( recommendedVersion != null && r.containsVersion( recommendedVersion ) )
|
||||
{
|
||||
// if we find the original, use that
|
||||
version = recommendedVersion;
|
||||
break;
|
||||
}
|
||||
else if ( version == null && restriction.getRecommendedVersion() != null
|
||||
&& r.containsVersion( restriction.getRecommendedVersion() ) )
|
||||
{
|
||||
// use this if we can, but prefer the original if possible
|
||||
version = restriction.getRecommendedVersion();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Either the original or the specified version ranges have no restrictions
|
||||
else if ( recommendedVersion != null )
|
||||
{
|
||||
// Use the original recommended version since it exists
|
||||
version = recommendedVersion;
|
||||
}
|
||||
else if ( restriction.recommendedVersion != null )
|
||||
{
|
||||
// Use the recommended version from the specified VersionRange since there is no
|
||||
// original recommended version
|
||||
version = restriction.recommendedVersion;
|
||||
}
|
||||
/* TODO: should throw this immediately, but need artifact
|
||||
else
|
||||
{
|
||||
throw new OverConstrainedVersionException( "Restricting incompatible version ranges" );
|
||||
}
|
||||
*/
|
||||
|
||||
return new VersionRange( version, restrictions );
|
||||
}
|
||||
|
||||
private List<Restriction> intersection( List<Restriction> r1, List<Restriction> r2 )
|
||||
{
|
||||
List<Restriction> restrictions = new ArrayList<Restriction>( r1.size() + r2.size() );
|
||||
Iterator<Restriction> i1 = r1.iterator();
|
||||
Iterator<Restriction> i2 = r2.iterator();
|
||||
Restriction res1 = i1.next();
|
||||
Restriction res2 = i2.next();
|
||||
|
||||
boolean done = false;
|
||||
while ( !done )
|
||||
{
|
||||
if ( res1.getLowerBound() == null || res2.getUpperBound() == null
|
||||
|| res1.getLowerBound().compareTo( res2.getUpperBound() ) <= 0 )
|
||||
{
|
||||
if ( res1.getUpperBound() == null || res2.getLowerBound() == null
|
||||
|| res1.getUpperBound().compareTo( res2.getLowerBound() ) >= 0 )
|
||||
{
|
||||
ArtifactVersion lower;
|
||||
ArtifactVersion upper;
|
||||
boolean lowerInclusive;
|
||||
boolean upperInclusive;
|
||||
|
||||
// overlaps
|
||||
if ( res1.getLowerBound() == null )
|
||||
{
|
||||
lower = res2.getLowerBound();
|
||||
lowerInclusive = res2.isLowerBoundInclusive();
|
||||
}
|
||||
else if ( res2.getLowerBound() == null )
|
||||
{
|
||||
lower = res1.getLowerBound();
|
||||
lowerInclusive = res1.isLowerBoundInclusive();
|
||||
}
|
||||
else
|
||||
{
|
||||
int comparison = res1.getLowerBound().compareTo( res2.getLowerBound() );
|
||||
if ( comparison < 0 )
|
||||
{
|
||||
lower = res2.getLowerBound();
|
||||
lowerInclusive = res2.isLowerBoundInclusive();
|
||||
}
|
||||
else if ( comparison == 0 )
|
||||
{
|
||||
lower = res1.getLowerBound();
|
||||
lowerInclusive = res1.isLowerBoundInclusive() && res2.isLowerBoundInclusive();
|
||||
}
|
||||
else
|
||||
{
|
||||
lower = res1.getLowerBound();
|
||||
lowerInclusive = res1.isLowerBoundInclusive();
|
||||
}
|
||||
}
|
||||
|
||||
if ( res1.getUpperBound() == null )
|
||||
{
|
||||
upper = res2.getUpperBound();
|
||||
upperInclusive = res2.isUpperBoundInclusive();
|
||||
}
|
||||
else if ( res2.getUpperBound() == null )
|
||||
{
|
||||
upper = res1.getUpperBound();
|
||||
upperInclusive = res1.isUpperBoundInclusive();
|
||||
}
|
||||
else
|
||||
{
|
||||
int comparison = res1.getUpperBound().compareTo( res2.getUpperBound() );
|
||||
if ( comparison < 0 )
|
||||
{
|
||||
upper = res1.getUpperBound();
|
||||
upperInclusive = res1.isUpperBoundInclusive();
|
||||
}
|
||||
else if ( comparison == 0 )
|
||||
{
|
||||
upper = res1.getUpperBound();
|
||||
upperInclusive = res1.isUpperBoundInclusive() && res2.isUpperBoundInclusive();
|
||||
}
|
||||
else
|
||||
{
|
||||
upper = res2.getUpperBound();
|
||||
upperInclusive = res2.isUpperBoundInclusive();
|
||||
}
|
||||
}
|
||||
|
||||
// don't add if they are equal and one is not inclusive
|
||||
if ( lower == null || upper == null || lower.compareTo( upper ) != 0 )
|
||||
{
|
||||
restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) );
|
||||
}
|
||||
else if ( lowerInclusive && upperInclusive )
|
||||
{
|
||||
restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) );
|
||||
}
|
||||
|
||||
//noinspection ObjectEquality
|
||||
if ( upper == res2.getUpperBound() )
|
||||
{
|
||||
// advance res2
|
||||
if ( i2.hasNext() )
|
||||
{
|
||||
res2 = i2.next();
|
||||
}
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// advance res1
|
||||
if ( i1.hasNext() )
|
||||
{
|
||||
res1 = i1.next();
|
||||
}
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// move on to next in r1
|
||||
if ( i1.hasNext() )
|
||||
{
|
||||
res1 = i1.next();
|
||||
}
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// move on to next in r2
|
||||
if ( i2.hasNext() )
|
||||
{
|
||||
res2 = i2.next();
|
||||
}
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return restrictions;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
if ( recommendedVersion != null )
|
||||
{
|
||||
return recommendedVersion.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Joiner.on(',').join(restrictions);
|
||||
}
|
||||
}
|
||||
|
||||
public ArtifactVersion matchVersion( List<ArtifactVersion> versions )
|
||||
{
|
||||
// TODO: could be more efficient by sorting the list and then moving along the restrictions in order?
|
||||
|
||||
ArtifactVersion matched = null;
|
||||
for ( ArtifactVersion version : versions )
|
||||
{
|
||||
if ( containsVersion( version ) )
|
||||
{
|
||||
// valid - check if it is greater than the currently matched version
|
||||
if ( matched == null || version.compareTo( matched ) > 0 )
|
||||
{
|
||||
matched = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
public boolean containsVersion( ArtifactVersion version )
|
||||
{
|
||||
for ( Restriction restriction : restrictions )
|
||||
{
|
||||
if ( restriction.containsVersion( version ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasRestrictions()
|
||||
{
|
||||
return !restrictions.isEmpty() && recommendedVersion == null;
|
||||
}
|
||||
|
||||
public boolean equals( Object obj )
|
||||
{
|
||||
if ( this == obj )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ( !( obj instanceof VersionRange ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
VersionRange other = (VersionRange) obj;
|
||||
|
||||
boolean equals =
|
||||
recommendedVersion == other.recommendedVersion
|
||||
|| ( ( recommendedVersion != null ) && recommendedVersion.equals( other.recommendedVersion ) );
|
||||
equals &=
|
||||
restrictions == other.restrictions
|
||||
|| ( ( restrictions != null ) && restrictions.equals( other.restrictions ) );
|
||||
return equals;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
int hash = 7;
|
||||
hash = 31 * hash + ( recommendedVersion == null ? 0 : recommendedVersion.hashCode() );
|
||||
hash = 31 * hash + ( restrictions == null ? 0 : restrictions.hashCode() );
|
||||
return hash;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
public class ArgsWrapper
|
||||
{
|
||||
public ArgsWrapper(String[] args)
|
||||
{
|
||||
this.args=args;
|
||||
}
|
||||
|
||||
public String[] args;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
public class CoreFMLLibraries implements ILibrarySet
|
||||
{
|
||||
private static String[] libraries = { "argo-2.25.jar","guava-12.0.1.jar","asm-all-4.0.jar" };
|
||||
private static String[] checksums = { "bb672829fde76cb163004752b86b0484bd0a7f4b", "b8e78b9af7bf45900e14c6f958486b6ca682195f", "98308890597acb64047f7e896638e0d98753ae82" };
|
||||
|
||||
@Override
|
||||
public String[] getLibraries()
|
||||
{
|
||||
return libraries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getHashes()
|
||||
{
|
||||
return checksums;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRootURL()
|
||||
{
|
||||
return "http://cloud.github.com/downloads/cpw/FML/%s";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
public class FMLCorePlugin implements IFMLLoadingPlugin
|
||||
{
|
||||
@Override
|
||||
public String[] getLibraryRequestClass()
|
||||
{
|
||||
return new String[] {"cpw.mods.fml.relauncher.CoreFMLLibraries"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getASMTransformerClass()
|
||||
{
|
||||
return new String[] {"cpw.mods.fml.common.asm.ASMTransformer"};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.logging.ConsoleHandler;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import cpw.mods.fml.relauncher.FMLLogFormatter;
|
||||
|
||||
public class FMLLog
|
||||
{
|
||||
|
||||
private static class LoggingOutStream extends ByteArrayOutputStream
|
||||
{
|
||||
private Logger log;
|
||||
private StringBuilder currentMessage;
|
||||
|
||||
public LoggingOutStream(Logger log)
|
||||
{
|
||||
this.log = log;
|
||||
this.currentMessage = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException
|
||||
{
|
||||
String record;
|
||||
synchronized(this)
|
||||
{
|
||||
super.flush();
|
||||
record = this.toString();
|
||||
super.reset();
|
||||
|
||||
currentMessage.append(record);
|
||||
if (currentMessage.lastIndexOf(FMLLogFormatter.LINE_SEPARATOR)>=0)
|
||||
{
|
||||
// Are we longer than just the line separator?
|
||||
if (currentMessage.length()>FMLLogFormatter.LINE_SEPARATOR.length())
|
||||
{
|
||||
// Trim the line separator
|
||||
currentMessage.setLength(currentMessage.length()-FMLLogFormatter.LINE_SEPARATOR.length());
|
||||
log.log(Level.INFO, currentMessage.toString());
|
||||
}
|
||||
currentMessage.setLength(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Our special logger for logging issues to. We copy various assets from the
|
||||
* Minecraft logger to acheive a similar appearance.
|
||||
*/
|
||||
public static FMLLog log = new FMLLog();
|
||||
|
||||
static File minecraftHome;
|
||||
private static boolean configured;
|
||||
private Logger myLog;
|
||||
|
||||
private FMLLog()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Configure the FML logger
|
||||
*/
|
||||
private static void configureLogging()
|
||||
{
|
||||
LogManager.getLogManager().reset();
|
||||
Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
|
||||
globalLogger.setLevel(Level.OFF);
|
||||
|
||||
log.myLog = Logger.getLogger("ForgeModLoader");
|
||||
|
||||
Logger stdOut = Logger.getLogger("STDOUT");
|
||||
stdOut.setParent(log.myLog);
|
||||
Logger stdErr = Logger.getLogger("STDERR");
|
||||
stdErr.setParent(log.myLog);
|
||||
FMLLogFormatter formatter = new FMLLogFormatter();
|
||||
|
||||
// Console handler captures the normal stderr before it gets replaced
|
||||
ConsoleHandler ch = new ConsoleHandler();
|
||||
ch.setLevel(Level.parse(System.getProperty("fml.log.level","INFO")));
|
||||
log.myLog.setUseParentHandlers(false);
|
||||
log.myLog.addHandler(ch);
|
||||
ch.setFormatter(formatter);
|
||||
log.myLog.setLevel(Level.ALL);
|
||||
try
|
||||
{
|
||||
File logPath = new File(minecraftHome, "ForgeModLoader-%g.log");
|
||||
FileHandler fileHandler = new FileHandler(logPath.getPath(), 0, 3);
|
||||
fileHandler.setFormatter(formatter);
|
||||
fileHandler.setLevel(Level.ALL);
|
||||
log.myLog.addHandler(fileHandler);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
|
||||
// Set system out to a log stream
|
||||
System.setOut(new PrintStream(new LoggingOutStream(stdOut), true));
|
||||
System.setErr(new PrintStream(new LoggingOutStream(stdErr), true));
|
||||
|
||||
// Reset global logging to shut up other logging sources (thanks guava!)
|
||||
configured = true;
|
||||
}
|
||||
|
||||
public static void log(Level level, String format, Object... data)
|
||||
{
|
||||
if (!configured)
|
||||
{
|
||||
configureLogging();
|
||||
}
|
||||
log.myLog.log(level, String.format(format, data));
|
||||
}
|
||||
|
||||
public static void log(Level level, Throwable ex, String format, Object... data)
|
||||
{
|
||||
if (!configured)
|
||||
{
|
||||
configureLogging();
|
||||
}
|
||||
log.myLog.log(level, String.format(format, data), ex);
|
||||
}
|
||||
|
||||
public static void severe(String format, Object... data)
|
||||
{
|
||||
log(Level.SEVERE, format, data);
|
||||
}
|
||||
|
||||
public static void warning(String format, Object... data)
|
||||
{
|
||||
log(Level.WARNING, format, data);
|
||||
}
|
||||
|
||||
public static void info(String format, Object... data)
|
||||
{
|
||||
log(Level.INFO, format, data);
|
||||
}
|
||||
|
||||
public static void fine(String format, Object... data)
|
||||
{
|
||||
log(Level.FINE, format, data);
|
||||
}
|
||||
|
||||
public static void finer(String format, Object... data)
|
||||
{
|
||||
log(Level.FINER, format, data);
|
||||
}
|
||||
|
||||
public static void finest(String format, Object... data)
|
||||
{
|
||||
log(Level.FINEST, format, data);
|
||||
}
|
||||
public Logger getLogger()
|
||||
{
|
||||
return myLog;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package cpw.mods.fml.common;
|
||||
package cpw.mods.fml.relauncher;
|
||||
|
||||
/**
|
||||
* Copied from ConsoleLogFormatter for shared use on the client
|
||||
*
|
||||
*
|
||||
*/
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
@ -13,6 +13,7 @@ import java.util.logging.LogRecord;
|
|||
|
||||
final class FMLLogFormatter extends Formatter
|
||||
{
|
||||
static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
public String format(LogRecord record)
|
||||
|
@ -50,8 +51,16 @@ final class FMLLogFormatter extends Formatter
|
|||
msg.append(" [" + lvl.getLocalizedName() + "] ");
|
||||
}
|
||||
|
||||
if (record.getLoggerName() != null)
|
||||
{
|
||||
msg.append("["+record.getLoggerName()+"] ");
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.append("[] ");
|
||||
}
|
||||
msg.append(record.getMessage());
|
||||
msg.append(System.getProperty("line.separator"));
|
||||
msg.append(LINE_SEPARATOR);
|
||||
Throwable thr = record.getThrown();
|
||||
|
||||
if (thr != null)
|
|
@ -0,0 +1,269 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.applet.AppletStub;
|
||||
import java.awt.Dialog.ModalityType;
|
||||
import java.awt.HeadlessException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.ProgressMonitorInputStream;
|
||||
|
||||
public class FMLRelauncher
|
||||
{
|
||||
private static FMLRelauncher INSTANCE;
|
||||
private RelaunchClassLoader classLoader;
|
||||
private Object newApplet;
|
||||
private Class<? super Object> appletClass;
|
||||
|
||||
private JDialog popupWindow;
|
||||
|
||||
public static void handleClientRelaunch(ArgsWrapper wrap)
|
||||
{
|
||||
instance().relaunchClient(wrap);
|
||||
}
|
||||
|
||||
public static void handleServerRelaunch(ArgsWrapper wrap)
|
||||
{
|
||||
instance().relaunchServer(wrap);
|
||||
}
|
||||
|
||||
static FMLRelauncher instance()
|
||||
{
|
||||
if (INSTANCE == null)
|
||||
{
|
||||
INSTANCE = new FMLRelauncher();
|
||||
}
|
||||
return INSTANCE;
|
||||
|
||||
}
|
||||
|
||||
private FMLRelauncher()
|
||||
{
|
||||
URLClassLoader ucl = (URLClassLoader)getClass().getClassLoader();
|
||||
|
||||
classLoader = new RelaunchClassLoader(ucl.getURLs());
|
||||
|
||||
}
|
||||
private void showWindow()
|
||||
{
|
||||
try
|
||||
{
|
||||
popupWindow = new JDialog(null, "FML Initial Setup", ModalityType.MODELESS);
|
||||
JOptionPane optPane = new JOptionPane("<html><font size=\"+1\">FML Setup</font><br/><br/>FML is performing some configuration, please wait</html>", JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[0]);
|
||||
popupWindow.add(optPane);
|
||||
popupWindow.pack();
|
||||
popupWindow.setLocationRelativeTo(null);
|
||||
popupWindow.setVisible(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
popupWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void relaunchClient(ArgsWrapper wrap)
|
||||
{
|
||||
showWindow();
|
||||
// Now we re-inject the home into the "new" minecraft under our control
|
||||
Class<? super Object> client;
|
||||
try
|
||||
{
|
||||
File minecraftHome = computeExistingClientHome();
|
||||
setupHome(minecraftHome);
|
||||
|
||||
client = ReflectionHelper.getClass(classLoader, "net.minecraft.client.Minecraft");
|
||||
ReflectionHelper.setPrivateValue(client, null, minecraftHome, "field_71463_am", "am", "minecraftDir");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (popupWindow!=null)
|
||||
{
|
||||
popupWindow.setVisible(false);
|
||||
popupWindow.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ReflectionHelper.findMethod(client, null, new String[] { "fmlReentry" }, ArgsWrapper.class).invoke(null, wrap);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// Hmmm
|
||||
}
|
||||
}
|
||||
|
||||
private void relaunchServer(ArgsWrapper wrap)
|
||||
{
|
||||
// Now we re-inject the home into the "new" minecraft under our control
|
||||
Class<? super Object> server;
|
||||
File minecraftHome = new File(".");
|
||||
setupHome(minecraftHome);
|
||||
|
||||
server = ReflectionHelper.getClass(classLoader, "net.minecraft.server.MinecraftServer");
|
||||
try
|
||||
{
|
||||
ReflectionHelper.findMethod(server, null, new String[] { "fmlReentry" }, ArgsWrapper.class).invoke(null, wrap);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// Hmmm
|
||||
}
|
||||
}
|
||||
|
||||
private void setupHome(File minecraftHome)
|
||||
{
|
||||
FMLVersionData.build(minecraftHome, classLoader);
|
||||
FMLLog.info("Forge Mod Loader version %s.%s.%s.%s for Minecraft client:%s, server:%s loading", FMLVersionData.major, FMLVersionData.minor, FMLVersionData.rev, FMLVersionData.build, FMLVersionData.mccversion, FMLVersionData.mcsversion);
|
||||
|
||||
try
|
||||
{
|
||||
RelaunchLibraryManager.handleLaunch(minecraftHome, classLoader);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
if (popupWindow != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
String logFile = new File(minecraftHome,"ForgeModLoader-0.log").getCanonicalPath();
|
||||
JOptionPane.showMessageDialog(popupWindow,
|
||||
String.format("<html><div align=\"center\"><font size=\"+1\">There was a fatal error starting up minecraft and FML</font></div><br/>" +
|
||||
"Minecraft cannot launch in it's current configuration<br/>" +
|
||||
"Please consult the file <i><a href=\"file:///%s\">%s</a></i> for further information</html>", logFile, logFile
|
||||
), "Fatal FML error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// ah well, we tried
|
||||
}
|
||||
}
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private File computeExistingClientHome()
|
||||
{
|
||||
Class<? super Object> mcMaster = ReflectionHelper.getClass(getClass().getClassLoader(), "net.minecraft.client.Minecraft");
|
||||
// We force minecraft to setup it's homedir very early on so we can inject stuff into it
|
||||
Method setupHome = ReflectionHelper.findMethod(mcMaster, null, new String[] { "func_71380_b", "getMinecraftDir", "b"} );
|
||||
try
|
||||
{
|
||||
setupHome.invoke(null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Hmmm
|
||||
}
|
||||
File minecraftHome = ReflectionHelper.getPrivateValue(mcMaster, null, "field_71463_am", "am", "minecraftDir");
|
||||
return minecraftHome;
|
||||
}
|
||||
|
||||
public static void appletEntry(Applet minecraftApplet)
|
||||
{
|
||||
instance().relaunchApplet(minecraftApplet);
|
||||
}
|
||||
|
||||
private void relaunchApplet(Applet minecraftApplet)
|
||||
{
|
||||
appletClass = ReflectionHelper.getClass(classLoader, "net.minecraft.client.MinecraftApplet");
|
||||
if (minecraftApplet.getClass().getClassLoader() == classLoader)
|
||||
{
|
||||
try
|
||||
{
|
||||
newApplet = minecraftApplet;
|
||||
ReflectionHelper.findMethod(appletClass, newApplet, new String[] {"fmlInitReentry"}).invoke(newApplet);
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
setupHome(computeExistingClientHome());
|
||||
|
||||
Class<? super Object> parentAppletClass = ReflectionHelper.getClass(getClass().getClassLoader(), "java.applet.Applet");
|
||||
|
||||
try
|
||||
{
|
||||
newApplet = appletClass.newInstance();
|
||||
Object appletContainer = ReflectionHelper.getPrivateValue(ReflectionHelper.getClass(getClass().getClassLoader(), "java.awt.Component"), minecraftApplet, "parent");
|
||||
|
||||
Class<? super Object> launcherClass = ReflectionHelper.getClass(getClass().getClassLoader(), "net.minecraft.Launcher");
|
||||
if (launcherClass.isInstance(appletContainer))
|
||||
{
|
||||
ReflectionHelper.findMethod(ReflectionHelper.getClass(getClass().getClassLoader(), "java.awt.Container"), minecraftApplet, new String[] { "removeAll" }).invoke(appletContainer);
|
||||
ReflectionHelper.findMethod(launcherClass, appletContainer, new String[] { "replace" }, parentAppletClass).invoke(appletContainer, newApplet);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.severe("Found unknown applet parent %s, unable to inject!\n", launcherClass);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (popupWindow!=null)
|
||||
{
|
||||
popupWindow.setVisible(false);
|
||||
popupWindow.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void appletStart(Applet applet)
|
||||
{
|
||||
instance().startApplet(applet);
|
||||
}
|
||||
|
||||
private void startApplet(Applet applet)
|
||||
{
|
||||
if (applet.getClass().getClassLoader() == classLoader)
|
||||
{
|
||||
try
|
||||
{
|
||||
ReflectionHelper.findMethod(appletClass, newApplet, new String[] {"fmlStartReentry"}).invoke(newApplet);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public InputStream wrapStream(InputStream inputStream, String infoString)
|
||||
{
|
||||
if (popupWindow!=null)
|
||||
{
|
||||
return new ProgressMonitorInputStream(popupWindow, infoString, inputStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
return inputStream;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class FMLVersionData
|
||||
{
|
||||
static File minecraftHome;
|
||||
static String major;
|
||||
static String minor;
|
||||
static String rev;
|
||||
static String build;
|
||||
static String mccversion;
|
||||
static String mcsversion;
|
||||
|
||||
static void build(File mcHome, RelaunchClassLoader classLoader)
|
||||
{
|
||||
minecraftHome = mcHome;
|
||||
InputStream stream = classLoader.getResourceAsStream("fmlversion.properties");
|
||||
Properties properties = new Properties();
|
||||
|
||||
if (stream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
properties.load(stream);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
FMLLog.log(Level.SEVERE, ex, "Could not get FML version information - corrupted installation detected!");
|
||||
}
|
||||
}
|
||||
|
||||
major = properties.getProperty("fmlbuild.major.number", "missing");
|
||||
minor = properties.getProperty("fmlbuild.minor.number", "missing");
|
||||
rev = properties.getProperty("fmlbuild.revision.number", "missing");
|
||||
build = properties.getProperty("fmlbuild.build.number", "missing");
|
||||
mccversion = properties.getProperty("fmlbuild.mcclientversion", "missing");
|
||||
mcsversion = properties.getProperty("fmlbuild.mcserverversion", "missing");
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static Object[] data()
|
||||
{
|
||||
return new Object[] { major, minor, rev, build, mccversion, mcsversion, minecraftHome };
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
public interface IClassTransformer
|
||||
{
|
||||
public byte[] transform(String name, byte[] bytes);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
/**
|
||||
* The base plugin that provides class name meta information to FML to
|
||||
* enhance the classloading lifecycle for mods in FML
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public interface IFMLLoadingPlugin
|
||||
{
|
||||
/**
|
||||
* Return a list of classes that implement the ILibrarySet interface
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String[] getLibraryRequestClass();
|
||||
/**
|
||||
* Return a list of classes that implements the IClassTransformer interface
|
||||
* @return
|
||||
*/
|
||||
String[] getASMTransformerClass();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
/**
|
||||
* Interface for certain core plugins to register libraries to
|
||||
* be loaded in by the FML class loader at launch time
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public interface ILibrarySet
|
||||
{
|
||||
/**
|
||||
* Return a list of libraries available from a common location
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String[] getLibraries();
|
||||
/**
|
||||
* Return the string encoded sha1 hash for each library in the returned list
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String[] getHashes();
|
||||
/**
|
||||
* Return the root URL format string from which this library set can be obtained
|
||||
* There needs to be a single %s string substitution which is the library name
|
||||
* @return
|
||||
*/
|
||||
String getRootURL();
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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.relauncher;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
/**
|
||||
* Some reflection helper code.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class ReflectionHelper
|
||||
{
|
||||
public static class UnableToFindMethodException extends RuntimeException
|
||||
{
|
||||
private String[] methodNames;
|
||||
|
||||
public UnableToFindMethodException(String[] methodNames, Exception failed)
|
||||
{
|
||||
super(failed);
|
||||
this.methodNames = methodNames;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class UnableToFindClassException extends RuntimeException
|
||||
{
|
||||
private String[] classNames;
|
||||
|
||||
public UnableToFindClassException(String[] classNames, Exception err)
|
||||
{
|
||||
super(err);
|
||||
this.classNames = classNames;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class UnableToAccessFieldException extends RuntimeException
|
||||
{
|
||||
|
||||
private String[] fieldNameList;
|
||||
|
||||
public UnableToAccessFieldException(String[] fieldNames, Exception e)
|
||||
{
|
||||
super(e);
|
||||
this.fieldNameList = fieldNames;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnableToFindFieldException extends RuntimeException
|
||||
{
|
||||
private String[] fieldNameList;
|
||||
public UnableToFindFieldException(String[] fieldNameList, Exception e)
|
||||
{
|
||||
super(e);
|
||||
this.fieldNameList = fieldNameList;
|
||||
}
|
||||
}
|
||||
|
||||
public static Field findField(Class<?> clazz, String... fieldNames)
|
||||
{
|
||||
Exception failed = null;
|
||||
for (String fieldName : fieldNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field f = clazz.getDeclaredField(fieldName);
|
||||
f.setAccessible(true);
|
||||
return f;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
failed = e;
|
||||
}
|
||||
}
|
||||
throw new UnableToFindFieldException(fieldNames, failed);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T, E> T getPrivateValue(Class <? super E > classToAccess, E instance, int fieldIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field f = classToAccess.getDeclaredFields()[fieldIndex];
|
||||
f.setAccessible(true);
|
||||
return (T) f.get(instance);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new UnableToAccessFieldException(new String[0], e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T, E> T getPrivateValue(Class <? super E > classToAccess, E instance, String... fieldNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (T) findField(classToAccess, fieldNames).get(instance);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new UnableToAccessFieldException(fieldNames, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, E value, int fieldIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field f = classToAccess.getDeclaredFields()[fieldIndex];
|
||||
f.setAccessible(true);
|
||||
f.set(instance, value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new UnableToAccessFieldException(new String[0] , e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, E value, String... fieldNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
findField(classToAccess, fieldNames).set(instance, value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new UnableToAccessFieldException(fieldNames, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<? super Object> getClass(ClassLoader loader, String... classNames)
|
||||
{
|
||||
Exception err = null;
|
||||
for (String className : classNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (Class<? super Object>) Class.forName(className, false, loader);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err = e;
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnableToFindClassException(classNames, err);
|
||||
}
|
||||
|
||||
|
||||
public static <E> Method findMethod(Class<? super E> clazz, E instance, String[] methodNames, Class<?>... methodTypes)
|
||||
{
|
||||
Exception failed = null;
|
||||
for (String methodName : methodNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
Method m = clazz.getDeclaredMethod(methodName, methodTypes);
|
||||
m.setAccessible(true);
|
||||
return m;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
failed = e;
|
||||
}
|
||||
}
|
||||
throw new UnableToFindMethodException(methodNames, failed);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RelaunchClassLoader extends URLClassLoader
|
||||
{
|
||||
private static String[] excludedPackages = {
|
||||
"java.", "sun.", "javax.",
|
||||
"cpw.mods.fml.relauncher.", "net.minecraftforge.classloading."
|
||||
};
|
||||
|
||||
private static String[] transformerExclusions =
|
||||
{
|
||||
"org.objectweb.asm.", "com.google.common."
|
||||
};
|
||||
private List<URL> sources;
|
||||
private ClassLoader parent;
|
||||
|
||||
private List<IClassTransformer> transformers;
|
||||
private Map<String, Class> cachedClasses;
|
||||
|
||||
public RelaunchClassLoader(URL[] sources)
|
||||
{
|
||||
super(sources, null);
|
||||
this.sources = new ArrayList<URL>(Arrays.asList(sources));
|
||||
this.parent = getClass().getClassLoader();
|
||||
this.cachedClasses = new HashMap<String,Class>(1000);
|
||||
this.transformers = new ArrayList<IClassTransformer>(2);
|
||||
ReflectionHelper.setPrivateValue(ClassLoader.class, null, this, "scl");
|
||||
Thread.currentThread().setContextClassLoader(this);
|
||||
}
|
||||
|
||||
public void registerTransformer(String transformerClassName)
|
||||
{
|
||||
try
|
||||
{
|
||||
transformers.add((IClassTransformer) loadClass(transformerClassName).newInstance());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// error registering transformer
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
for (String st : excludedPackages)
|
||||
{
|
||||
if (name.startsWith(st))
|
||||
{
|
||||
return parent.loadClass(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (cachedClasses.containsKey(name))
|
||||
{
|
||||
return cachedClasses.get(name);
|
||||
}
|
||||
|
||||
for (String st : transformerExclusions)
|
||||
{
|
||||
if (name.startsWith(st))
|
||||
{
|
||||
Class<?> cl = super.findClass(name);
|
||||
cachedClasses.put(name, cl);
|
||||
return cl;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
byte[] basicClass = readFully(findResource(name.replace('.', '/').concat(".class")).openStream());
|
||||
byte[] transformedClass = runTransformers(name, basicClass);
|
||||
Class<?> cl = defineClass(name, transformedClass, 0, transformedClass.length);
|
||||
cachedClasses.put(name, cl);
|
||||
return cl;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new ClassNotFoundException(name, e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] runTransformers(String name, byte[] basicClass)
|
||||
{
|
||||
for (IClassTransformer transformer : transformers)
|
||||
{
|
||||
basicClass = transformer.transform(name, basicClass);
|
||||
}
|
||||
return basicClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(URL url)
|
||||
{
|
||||
super.addURL(url);
|
||||
sources.add(url);
|
||||
}
|
||||
|
||||
public List<URL> getSources()
|
||||
{
|
||||
return sources;
|
||||
}
|
||||
|
||||
|
||||
private byte[] readFully(InputStream stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(stream.available());
|
||||
int r;
|
||||
while ((r = stream.read()) != -1)
|
||||
{
|
||||
bos.write(r);
|
||||
}
|
||||
|
||||
return bos.toByteArray();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
/// HMMM
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue