Mods can now declare a range of minecraft versions they will run against

This commit is contained in:
Christian 2012-10-02 01:29:46 -04:00
parent 7cd5ae04f7
commit 9a8a38d345
12 changed files with 151 additions and 4 deletions

View file

@ -54,6 +54,7 @@ import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.ModMetadata; import cpw.mods.fml.common.ModMetadata;
import cpw.mods.fml.common.ObfuscationReflectionHelper; import cpw.mods.fml.common.ObfuscationReflectionHelper;
import cpw.mods.fml.common.Side; import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.WrongMinecraftVersionException;
import cpw.mods.fml.common.network.EntitySpawnAdjustmentPacket; import cpw.mods.fml.common.network.EntitySpawnAdjustmentPacket;
import cpw.mods.fml.common.network.EntitySpawnPacket; import cpw.mods.fml.common.network.EntitySpawnPacket;
import cpw.mods.fml.common.network.ModMissingPacket; import cpw.mods.fml.common.network.ModMissingPacket;
@ -104,6 +105,8 @@ public class FMLClientHandler implements IFMLSidedHandler
private boolean loading; private boolean loading;
private WrongMinecraftVersionException wrongMC;
/** /**
* Called to start the whole game off from * Called to start the whole game off from
* {@link MinecraftServer#startServer} * {@link MinecraftServer#startServer}
@ -142,6 +145,10 @@ public class FMLClientHandler implements IFMLSidedHandler
{ {
Loader.instance().loadMods(); Loader.instance().loadMods();
} }
catch (WrongMinecraftVersionException wrong)
{
wrongMC = wrong;
}
catch (MissingModsException missing) catch (MissingModsException missing)
{ {
modsMissing = missing; modsMissing = missing;
@ -167,7 +174,7 @@ public class FMLClientHandler implements IFMLSidedHandler
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void finishMinecraftLoading() public void finishMinecraftLoading()
{ {
if (modsMissing != null) if (modsMissing != null || wrongMC != null)
{ {
return; return;
} }
@ -189,7 +196,11 @@ public class FMLClientHandler implements IFMLSidedHandler
public void onInitializationComplete() public void onInitializationComplete()
{ {
if (modsMissing != null) if (wrongMC != null)
{
client.func_71373_a(new GuiWrongMinecraft(wrongMC));
}
else if (modsMissing != null)
{ {
client.func_71373_a(new GuiModsMissing(modsMissing)); client.func_71373_a(new GuiModsMissing(modsMissing));
} }

View file

@ -0,0 +1,35 @@
package cpw.mods.fml.client;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.WrongMinecraftVersionException;
import cpw.mods.fml.common.versioning.ArtifactVersion;
import net.minecraft.src.GuiErrorScreen;
import net.minecraft.src.GuiScreen;
public class GuiWrongMinecraft extends GuiErrorScreen
{
private WrongMinecraftVersionException wrongMC;
public GuiWrongMinecraft(WrongMinecraftVersionException wrongMC)
{
this.wrongMC = wrongMC;
}
@Override
public void func_73866_w_()
{
super.func_73866_w_();
}
@Override
public void func_73863_a(int p_73863_1_, int p_73863_2_, float p_73863_3_)
{
this.func_73873_v_();
int offset = 75;
this.func_73732_a(this.field_73886_k, "Forge Mod Loader has found a problem with your minecraft installation", this.field_73880_f / 2, offset, 0xFFFFFF);
offset+=10;
this.func_73732_a(this.field_73886_k, String.format("The mod listed below does not want to run in Minecraft version %s", Loader.instance().getMinecraftModContainer().getVersion()), this.field_73880_f / 2, offset, 0xFFFFFF);
offset+=5;
offset+=10;
this.func_73732_a(this.field_73886_k, String.format("%s (%s) wants Minecraft %s", wrongMC.mod.getName(), wrongMC.mod.getModId(), wrongMC.mod.acceptableMinecraftVersionRange()), this.field_73880_f / 2, offset, 0xEEEEEE);
offset+=20;
this.func_73732_a(this.field_73886_k, "The file 'ForgeModLoader-client-0.log' contains more information", this.field_73880_f / 2, offset, 0xFFFFFF);
}
}

View file

@ -9,6 +9,7 @@ import com.google.common.eventbus.EventBus;
import cpw.mods.fml.common.versioning.ArtifactVersion; import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.DefaultArtifactVersion; import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
import cpw.mods.fml.common.versioning.VersionRange;
public class DummyModContainer implements ModContainer public class DummyModContainer implements ModContainer
{ {
@ -132,4 +133,9 @@ public class DummyModContainer implements ModContainer
{ {
return md.version; return md.version;
} }
@Override
public VersionRange acceptableMinecraftVersionRange()
{
return Loader.instance().getMinecraftModContainer().getStaticVersionRange();
}
} }

View file

@ -56,6 +56,8 @@ import cpw.mods.fml.common.event.FMLStateEvent;
import cpw.mods.fml.common.network.FMLNetworkHandler; import cpw.mods.fml.common.network.FMLNetworkHandler;
import cpw.mods.fml.common.versioning.ArtifactVersion; import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.DefaultArtifactVersion; import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
import cpw.mods.fml.common.versioning.VersionParser;
import cpw.mods.fml.common.versioning.VersionRange;
public class FMLModContainer implements ModContainer public class FMLModContainer implements ModContainer
{ {
@ -84,6 +86,7 @@ public class FMLModContainer implements ModContainer
.build(); .build();
private static final BiMap<Class<? extends Annotation>, Class<? extends FMLStateEvent>> modTypeAnnotations = modAnnotationTypes.inverse(); private static final BiMap<Class<? extends Annotation>, Class<? extends FMLStateEvent>> modTypeAnnotations = modAnnotationTypes.inverse();
private String annotationDependencies; private String annotationDependencies;
private VersionRange minecraftAccepted;
public FMLModContainer(String className, File modSource, Map<String,Object> modDescriptor) public FMLModContainer(String className, File modSource, Map<String,Object> modDescriptor)
@ -175,6 +178,16 @@ public class FMLModContainer implements ModContainer
FMLLog.warning("Mod %s is missing the required element 'version' and no fallback can be found. Substituting '1.0'.", getModId()); FMLLog.warning("Mod %s is missing the required element 'version' and no fallback can be found. Substituting '1.0'.", getModId());
modMetadata.version = internalVersion = "1.0"; modMetadata.version = internalVersion = "1.0";
} }
String mcVersionString = (String) descriptor.get("acceptedMinecraftVersions");
if (!Strings.isNullOrEmpty(mcVersionString))
{
minecraftAccepted = VersionParser.parseRange(mcVersionString);
}
else
{
minecraftAccepted = Loader.instance().getMinecraftModContainer().getStaticVersionRange();
}
} }
public Properties searchForVersionProperties() public Properties searchForVersionProperties()
@ -457,4 +470,10 @@ public class FMLModContainer implements ModContainer
{ {
return modMetadata.version; return modMetadata.version;
} }
@Override
public VersionRange acceptableMinecraftVersionRange()
{
return minecraftAccepted;
}
} }

View file

@ -7,6 +7,7 @@ import java.util.Set;
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.EventBus;
import cpw.mods.fml.common.versioning.ArtifactVersion; import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.VersionRange;
public class InjectedModContainer implements ModContainer public class InjectedModContainer implements ModContainer
{ {
@ -110,4 +111,10 @@ public class InjectedModContainer implements ModContainer
{ {
return wrappedContainer.getDisplayVersion(); return wrappedContainer.getDisplayVersion();
} }
@Override
public VersionRange acceptableMinecraftVersionRange()
{
return wrappedContainer.acceptableMinecraftVersionRange();
}
} }

View file

@ -132,6 +132,7 @@ public class Loader
private Exception capturedError; private Exception capturedError;
private File canonicalModsDir; private File canonicalModsDir;
private LoadController modController; private LoadController modController;
private MinecraftDummyContainer minecraft;
private static File minecraftDir; private static File minecraftDir;
private static List<String> injectedContainers; private static List<String> injectedContainers;
@ -167,6 +168,8 @@ public class Loader
FMLLog.severe("This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file", mccversion, actualMCVersion); FMLLog.severe("This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file", mccversion, actualMCVersion);
throw new LoaderException(); throw new LoaderException();
} }
minecraft = new MinecraftDummyContainer(actualMCVersion);
} }
/** /**
@ -187,6 +190,11 @@ public class Loader
for (ModContainer mod : getActiveModList()) for (ModContainer mod : getActiveModList())
{ {
if (!mod.acceptableMinecraftVersionRange().containsVersion(minecraft.getProcessedVersion()))
{
FMLLog.severe("The mod %s does not wish to run in Minecraft version %s. You will have to remove it to play.", mod.getModId(), getMCVersionString());
throw new WrongMinecraftVersionException(mod);
}
Map<String,ArtifactVersion> names = Maps.uniqueIndex(mod.getRequirements(), new Function<ArtifactVersion, String>() Map<String,ArtifactVersion> names = Maps.uniqueIndex(mod.getRequirements(), new Function<ArtifactVersion, String>()
{ {
public String apply(ArtifactVersion v) public String apply(ArtifactVersion v)
@ -194,8 +202,8 @@ public class Loader
return v.getLabel(); return v.getLabel();
} }
}); });
Set<String> missingMods = Sets.difference(names.keySet(), modVersions.keySet());
Set<ArtifactVersion> versionMissingMods = Sets.newHashSet(); Set<ArtifactVersion> versionMissingMods = Sets.newHashSet();
Set<String> missingMods = Sets.difference(names.keySet(), modVersions.keySet());
if (!missingMods.isEmpty()) if (!missingMods.isEmpty())
{ {
FMLLog.severe("The mod %s (%s) requires mods %s to be available", mod.getModId(), mod.getName(), missingMods); FMLLog.severe("The mod %s (%s) requires mods %s to be available", mod.getModId(), mod.getName(), missingMods);
@ -707,4 +715,9 @@ public class Loader
{ {
return modController.isInState(state); return modController.isInState(state);
} }
public MinecraftDummyContainer getMinecraftModContainer()
{
return minecraft;
}
} }

View file

@ -0,0 +1,26 @@
package cpw.mods.fml.common;
import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
import cpw.mods.fml.common.versioning.VersionParser;
import cpw.mods.fml.common.versioning.VersionRange;
public class MinecraftDummyContainer extends DummyModContainer
{
private VersionRange staticRange;
public MinecraftDummyContainer(String actualMCVersion)
{
super(new ModMetadata());
getMetadata().modId = "Minecraft";
getMetadata().name = "Minecraft";
getMetadata().version = actualMCVersion;
staticRange = VersionParser.parseRange("["+actualMCVersion+"]");
}
public VersionRange getStaticVersionRange()
{
return staticRange;
}
}

View file

@ -52,6 +52,13 @@ public @interface Mod
*/ */
boolean useMetadata() default false; boolean useMetadata() default false;
/**
* The acceptable range of minecraft versions that this mod will load and run in
* The default ("empty string") indicates that only the current minecraft version is acceptable.
* FML will refuse to run with an error if the minecraft version is not in this range across all mods.
* @return A version range as specified by the maven version range specification or the empty string
*/
String acceptedMinecraftVersions() default "";
/** /**
* Mark the designated method as being called at the "pre-initialization" phase * Mark the designated method as being called at the "pre-initialization" phase
* @author cpw * @author cpw

View file

@ -20,6 +20,7 @@ import java.util.Set;
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.EventBus;
import cpw.mods.fml.common.versioning.ArtifactVersion; import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.VersionRange;
/** /**
* The container that wraps around mods in the system. * The container that wraps around mods in the system.
@ -126,4 +127,6 @@ public interface ModContainer
boolean isNetworkMod(); boolean isNetworkMod();
String getDisplayVersion(); String getDisplayVersion();
VersionRange acceptableMinecraftVersionRange();
} }

View file

@ -0,0 +1,13 @@
package cpw.mods.fml.common;
public class WrongMinecraftVersionException extends RuntimeException
{
public ModContainer mod;
public WrongMinecraftVersionException(ModContainer mod)
{
this.mod = mod;
}
}

View file

@ -65,6 +65,7 @@ import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.TickRegistry; import cpw.mods.fml.common.registry.TickRegistry;
import cpw.mods.fml.common.versioning.ArtifactVersion; import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.DefaultArtifactVersion; import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
import cpw.mods.fml.common.versioning.VersionRange;
public class ModLoaderModContainer implements ModContainer public class ModLoaderModContainer implements ModContainer
{ {
@ -609,4 +610,10 @@ public class ModLoaderModContainer implements ModContainer
{ {
serverCommands .add(command); serverCommands .add(command);
} }
@Override
public VersionRange acceptableMinecraftVersionRange()
{
return Loader.instance().getMinecraftModContainer().getStaticVersionRange();
}
} }

View file

@ -22,7 +22,7 @@ import cpw.mods.fml.common.network.NetworkMod.SidedPacketHandler;
import cpw.mods.fml.common.network.Player; import cpw.mods.fml.common.network.Player;
import cpw.mods.fml.common.ModMetadata; import cpw.mods.fml.common.ModMetadata;
@Mod(modid="MockMod", name="Mock Mod",version="1.2.3", dependencies="after:FML@(3.0.184.0,3.0.184.1]", useMetadata=true) @Mod(modid="MockMod", name="Mock Mod",version="1.2.3", dependencies="after:FML@[3.1.29,)", useMetadata=true,acceptedMinecraftVersions="[1.4,),[12w27a,)")
@NetworkMod(channels={"MockMod"},clientSideRequired=true,packetHandler=MockMod.PacketHandler.class,clientPacketHandlerSpec= @NetworkMod(channels={"MockMod"},clientSideRequired=true,packetHandler=MockMod.PacketHandler.class,clientPacketHandlerSpec=
@SidedPacketHandler(packetHandler=TestClass.class,channels={"Fish"}),tinyPacketHandler=MockMod.PacketHandler.class) @SidedPacketHandler(packetHandler=TestClass.class,channels={"Fish"}),tinyPacketHandler=MockMod.PacketHandler.class)
public class MockMod public class MockMod