Merge branch 'newfmlmod'

This commit is contained in:
Christian 2012-08-02 08:52:11 -02:30
commit 2df9ba14d4
206 changed files with 9665 additions and 6376 deletions

1
fml/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto

2
fml/.gitignore vendored
View File

@ -8,3 +8,5 @@
/eclipse/.metadata/
/target
fmlbranding.properties
/fernflower.zip
/commands.py.bck

View File

@ -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

View File

@ -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()

View File

@ -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>

View File

@ -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

View File

@ -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);

View File

@ -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;
}
/**

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,6 @@
package cpw.mods.fml.client.registry;
public class RenderingRegistry
{
}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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
}
}

View File

@ -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);
}
}

View File

@ -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);
}
/**

93
fml/commands.patch Normal file
View File

@ -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])

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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="";
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,9 @@
package cpw.mods.fml.common.event;
public class FMLEvent
{
public final String getEventType()
{
return getClass().getSimpleName();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,6 @@
package cpw.mods.fml.common.registry;
public interface BlockProxy
{
}

View File

@ -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);
}
}
}

View File

@ -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)
{

View File

@ -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);
}
}

View File

@ -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);

View File

@ -0,0 +1,6 @@
package cpw.mods.fml.common.registry;
public interface ItemProxy
{
}

View File

@ -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);
}
}
}

View File

@ -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()));
}
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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 =&gt; [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();
}
}

View File

@ -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);
}
}

View File

@ -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 );
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,11 @@
package cpw.mods.fml.relauncher;
public class ArgsWrapper
{
public ArgsWrapper(String[] args)
{
this.args=args;
}
public String[] args;
}

View File

@ -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";
}
}

View File

@ -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"};
}
}

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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;
}
}
}

View File

@ -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 };
}
}

View File

@ -0,0 +1,6 @@
package cpw.mods.fml.relauncher;
public interface IClassTransformer
{
public byte[] transform(String name, byte[] bytes);
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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