Fix up versioned dependencies so they work a lot better, also add in a missing mods screen

This commit is contained in:
Christian 2012-08-23 13:43:25 -04:00
parent e6dce6cdbc
commit 4b6b090712
13 changed files with 148 additions and 24 deletions

View file

@ -46,6 +46,7 @@ import cpw.mods.fml.common.IFMLSidedHandler;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.LoaderException;
import cpw.mods.fml.common.MetadataCollection;
import cpw.mods.fml.common.MissingModsException;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.ModMetadata;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
@ -102,6 +103,8 @@ public class FMLClientHandler implements IFMLSidedHandler
private boolean serverIsRunning;
private MissingModsException modsMissing;
public void beginMinecraftLoading(Minecraft minecraft)
{
if (minecraft.func_71355_q())
@ -133,6 +136,10 @@ public class FMLClientHandler implements IFMLSidedHandler
{
Loader.instance().loadMods();
}
catch (MissingModsException missing)
{
modsMissing = missing;
}
catch (LoaderException le)
{
haltGame("There was a severe problem during mod loading that has caused the game to fail", le);
@ -154,6 +161,10 @@ public class FMLClientHandler implements IFMLSidedHandler
@SuppressWarnings("deprecation")
public void finishMinecraftLoading()
{
if (modsMissing != null)
{
return;
}
try
{
Loader.instance().initializeMods();
@ -169,9 +180,16 @@ public class FMLClientHandler implements IFMLSidedHandler
KeyBindingRegistry.instance().uploadKeyBindingsToGame(client.field_71474_y);
}
public void reloadTextureFX()
public void onInitializationComplete()
{
TextureFXManager.instance().loadTextures(client.field_71418_C.func_77292_e());
if (modsMissing != null)
{
client.func_71373_a(new ModsMissingGuiScreen(modsMissing));
}
else
{
TextureFXManager.instance().loadTextures(client.field_71418_C.func_77292_e());
}
}
/**
* Get the server instance

View file

@ -0,0 +1,34 @@
package cpw.mods.fml.client;
import cpw.mods.fml.common.MissingModsException;
import cpw.mods.fml.common.versioning.ArtifactVersion;
import net.minecraft.src.GuiErrorScreen;
public class ModsMissingGuiScreen extends GuiErrorScreen
{
private MissingModsException modsMissing;
public ModsMissingGuiScreen(MissingModsException modsMissing)
{
this.modsMissing = modsMissing;
}
@Override
public void func_73863_a(int p_73863_1_, int p_73863_2_, float p_73863_3_)
{
this.func_73873_v_();
int offset = 85 - modsMissing.missingMods.size() * 10;
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, "The mods and versions listed below could not be found", this.field_73880_f / 2, offset, 0xFFFFFF);
offset+=5;
for (ArtifactVersion v : modsMissing.missingMods)
{
offset+=10;
this.func_73732_a(this.field_73886_k, String.format("%s : %s", v.getLabel(), v.getVersionString()), 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

@ -3,14 +3,17 @@ package cpw.mods.fml.common;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import com.google.common.eventbus.EventBus;
import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
public class DummyModContainer implements ModContainer
{
private ModMetadata md;
private ArtifactVersion processedVersion;
public DummyModContainer(ModMetadata md)
{
@ -39,9 +42,9 @@ public class DummyModContainer implements ModContainer
}
@Override
public List<ArtifactVersion> getRequirements()
public Set<ArtifactVersion> getRequirements()
{
return Collections.emptyList();
return Collections.emptySet();
}
@Override
@ -105,7 +108,11 @@ public class DummyModContainer implements ModContainer
@Override
public ArtifactVersion getProcessedVersion()
{
return null;
if (processedVersion == null)
{
processedVersion = new DefaultArtifactVersion(getModId(), getVersion());
}
return processedVersion;
}
@Override

View file

@ -19,6 +19,7 @@ import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
@ -27,6 +28,7 @@ import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
@ -125,7 +127,7 @@ public class FMLModContainer implements ModContainer
if (overridesMetadata || !modMetadata.useDependencyInformation)
{
List<ArtifactVersion> requirements = Lists.newArrayList();
Set<ArtifactVersion> requirements = Sets.newHashSet();
List<ArtifactVersion> dependencies = Lists.newArrayList();
List<ArtifactVersion> dependants = Lists.newArrayList();
annotationDependencies = (String) descriptor.get("dependencies");
@ -133,11 +135,18 @@ public class FMLModContainer implements ModContainer
modMetadata.requiredMods = requirements;
modMetadata.dependencies = dependencies;
modMetadata.dependants = dependants;
FMLLog.finest("Parsed dependency info : %s %s %s", requirements, dependencies, dependants);
}
if (Strings.isNullOrEmpty(modMetadata.name))
{
FMLLog.info("Mod %s is missing a required element, name. Substituting %s", getModId(), getModId());
modMetadata.name = getModId();
}
if (Strings.isNullOrEmpty(modMetadata.version))
{
FMLLog.warning("Mod %s is missing a required element, version. Substituting 1", getModId());
modMetadata.version = "1";
}
}
@Override
@ -147,7 +156,7 @@ public class FMLModContainer implements ModContainer
}
@Override
public List<ArtifactVersion> getRequirements()
public Set<ArtifactVersion> getRequirements()
{
return modMetadata.requiredMods;
}
@ -167,7 +176,7 @@ public class FMLModContainer implements ModContainer
@Override
public String getSortingRules()
{
return (overridesMetadata ? annotationDependencies : modMetadata.printableSortingRules());
return ((overridesMetadata || !modMetadata.useDependencyInformation) ? annotationDependencies : modMetadata.printableSortingRules());
}
@Override

View file

@ -2,6 +2,7 @@ package cpw.mods.fml.common;
import java.io.File;
import java.util.List;
import java.util.Set;
import com.google.common.eventbus.EventBus;
@ -53,7 +54,7 @@ public class InjectedModContainer implements ModContainer
wrappedContainer.setEnabledState(enabled);
}
public List<ArtifactVersion> getRequirements()
public Set<ArtifactVersion> getRequirements()
{
return wrappedContainer.getRequirements();
}

View file

@ -20,6 +20,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.logging.Level;
@ -30,14 +31,17 @@ import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Multiset.Entry;
import com.google.common.collect.Multisets;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets.SetView;
import com.google.common.collect.TreeMultimap;
import cpw.mods.fml.common.LoaderState.ModState;
@ -173,7 +177,7 @@ public class Loader
FMLLog.fine("Verifying mod requirements are satisfied");
try
{
Map<String, ArtifactVersion> modVersions = Maps.newHashMap();
BiMap<String, ArtifactVersion> modVersions = HashBiMap.create();
for (ModContainer mod : mods)
{
modVersions.put(mod.getModId(), mod.getProcessedVersion());
@ -181,18 +185,29 @@ public class Loader
for (ModContainer mod : mods)
{
Set<ArtifactVersion> missingMods = Sets.difference(mod.getRequirements(), modVersions.values());
if (!missingMods.isEmpty())
{
FMLLog.severe("The mod %s (%s) requires mods %s to be available", mod.getModId(), mod.getName(), missingMods);
throw new MissingModsException(missingMods);
}
ImmutableList<ArtifactVersion> allDeps = ImmutableList.<ArtifactVersion>builder().addAll(mod.getDependants()).addAll(mod.getDependencies()).build();
for (ArtifactVersion v : allDeps)
{
missingMods = Sets.newHashSet();
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();
missingMods.add(v);
}
}
}
if (!missingMods.isEmpty())
{
FMLLog.severe("The mod %s (%s) requires mod versions %s to be available", mod.getModId(), mod.getName(), missingMods);
throw new MissingModsException(missingMods);
}
}
FMLLog.fine("All mod requirements are satisfied");
@ -506,7 +521,7 @@ public class Loader
return modClassLoader;
}
public void computeDependencies(String dependencyString, List<ArtifactVersion> requirements, List<ArtifactVersion> dependencies, List<ArtifactVersion> dependants)
public void computeDependencies(String dependencyString, Set<ArtifactVersion> requirements, List<ArtifactVersion> dependencies, List<ArtifactVersion> dependants)
{
if (dependencyString == null || dependencyString.length() == 0)
{

View file

@ -0,0 +1,19 @@
package cpw.mods.fml.common;
import java.util.Set;
import com.google.common.collect.Sets.SetView;
import cpw.mods.fml.common.versioning.ArtifactVersion;
public class MissingModsException extends RuntimeException
{
public Set<ArtifactVersion> missingMods;
public MissingModsException(Set<ArtifactVersion> missingMods)
{
this.missingMods = missingMods;
}
}

View file

@ -15,6 +15,7 @@ package cpw.mods.fml.common;
import java.io.File;
import java.util.List;
import java.util.Set;
import com.google.common.eventbus.EventBus;
@ -90,7 +91,7 @@ public interface ModContainer
*
* @return
*/
List<ArtifactVersion> getRequirements();
Set<ArtifactVersion> getRequirements();
/**
* A list of modids that should be loaded prior to this one. The special

View file

@ -16,8 +16,10 @@ package cpw.mods.fml.common;
import static argo.jdom.JsonNodeBuilders.aStringBuilder;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import argo.jdom.JsonNode;
@ -82,7 +84,7 @@ public class ModMetadata
public List<ModContainer> childMods = Lists.newArrayList();
public boolean useDependencyInformation;
public List<ArtifactVersion> requiredMods;
public Set<ArtifactVersion> requiredMods;
public List<ArtifactVersion> dependencies;
public List<ArtifactVersion> dependants;
public boolean autogenerated;
@ -109,9 +111,9 @@ public class ModMetadata
credits = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("credits")));
parent = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("parent")));
authorList = Objects.firstNonNull(((List<String>)processedFields.get(aStringBuilder("authors"))),Objects.firstNonNull(((List<String>)processedFields.get(aStringBuilder("authorList"))), 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")));
requiredMods = processReferences(processedFields.get(aStringBuilder("requiredMods")), Set.class);
dependencies = processReferences(processedFields.get(aStringBuilder("dependencies")), List.class);
dependants = processReferences(processedFields.get(aStringBuilder("dependants")), List.class);
useDependencyInformation = Boolean.parseBoolean(Strings.nullToEmpty((String)processedFields.get(aStringBuilder("useDependencyInformation"))));
}
@ -119,14 +121,23 @@ public class ModMetadata
{
}
private List<ArtifactVersion> processReferences(List<String> refs)
private <T extends Collection<ArtifactVersion>> T processReferences(Object refs, Class<? extends T> retType)
{
List<ArtifactVersion> res = Lists.newArrayList();
T res = null;
try
{
res = retType.newInstance();
}
catch (Exception e)
{
// unpossible
}
if (refs == null)
{
return res;
}
for (String ref : refs)
for (String ref : ((List<String>)refs))
{
res.add(VersionParser.parseVersionReference(ref));
}

View file

@ -24,6 +24,7 @@ import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import com.google.common.base.Strings;
@ -65,7 +66,7 @@ public class ModLoaderModContainer implements ModContainer
{
public BaseModProxy mod;
private File modSource;
public List<ArtifactVersion> requirements = Lists.newArrayList();
public Set<ArtifactVersion> requirements = Sets.newHashSet();
public ArrayList<ArtifactVersion> dependencies = Lists.newArrayList();
public ArrayList<ArtifactVersion> dependants = Lists.newArrayList();
private ContainerType sourceType;
@ -381,7 +382,7 @@ public class ModLoaderModContainer implements ModContainer
}
@Override
public List<ArtifactVersion> getRequirements()
public Set<ArtifactVersion> getRequirements()
{
return requirements;
}

View file

@ -30,5 +30,7 @@ public interface ArtifactVersion
{
String getLabel();
String getVersionString();
boolean containsVersion(ArtifactVersion source);
}

View file

@ -70,6 +70,12 @@ public class DefaultArtifactVersion implements ArtifactVersion
}
}
@Override
public String getVersionString()
{
return comparableVersion==null ? "any" : comparableVersion.toString();
}
@Override
public String toString()
{

View file

@ -53,7 +53,7 @@
{
this.func_71352_k();
}
+ FMLClientHandler.instance().reloadTextureFX();
+ FMLClientHandler.instance().onInitializationComplete();
}
private void func_71357_I() throws LWJGLException