mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-13 16:54:22 +00:00
Code to disable mods at runtime, or other times.
This commit is contained in:
1 parent
95f0447881
commit
751c5e39a4
8 files changed
+120
-24
No files matched your search
@@ -141,12 +141,6 @@ public class DummyModContainer implements ModContainer
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkMod()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayVersion()
|
||||
{
|
||||
@@ -186,4 +180,10 @@ public class DummyModContainer implements ModContainer
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Disableable canBeDisabled()
|
||||
{
|
||||
return Disableable.NEVER;
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import cpw.mods.fml.common.event.FMLEvent;
|
||||
import cpw.mods.fml.common.event.FMLFingerprintViolationEvent;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLInterModComms.IMCEvent;
|
||||
import cpw.mods.fml.common.event.FMLModDisabledEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLServerAboutToStartEvent;
|
||||
@@ -80,7 +81,6 @@ public class FMLModContainer implements ModContainer
|
||||
private EventBus eventBus;
|
||||
private LoadController controller;
|
||||
private DefaultArtifactVersion processedVersion;
|
||||
private boolean isNetworkMod;
|
||||
|
||||
private String annotationDependencies;
|
||||
private VersionRange minecraftAccepted;
|
||||
@@ -89,6 +89,7 @@ public class FMLModContainer implements ModContainer
|
||||
private Certificate certificate;
|
||||
private String modLanguage;
|
||||
private ILanguageAdapter languageAdapter;
|
||||
private Disableable disableability;
|
||||
private ListMultimap<Class<? extends FMLEvent>,Method> eventMethods;
|
||||
private Map<String, String> customModProperties;
|
||||
private ModCandidate candidate;
|
||||
@@ -103,6 +104,7 @@ public class FMLModContainer implements ModContainer
|
||||
.add(FMLServerStoppedEvent.class)
|
||||
.add(IMCEvent.class)
|
||||
.add(FMLFingerprintViolationEvent.class)
|
||||
.add(FMLModDisabledEvent.class)
|
||||
.build();
|
||||
|
||||
public FMLModContainer(String className, ModCandidate container, Map<String,Object> modDescriptor)
|
||||
@@ -491,7 +493,16 @@ public class FMLModContainer implements ModContainer
|
||||
customModProperties = EMPTY_PROPERTIES;
|
||||
}
|
||||
|
||||
|
||||
Boolean hasDisableableFlag = (Boolean) descriptor.get("canBeDeactivated");
|
||||
boolean hasReverseDepends = !event.getReverseDependencies().get(getModId()).isEmpty();
|
||||
if (hasDisableableFlag != null && hasDisableableFlag)
|
||||
{
|
||||
disableability = hasReverseDepends ? Disableable.DEPENDENCIES : Disableable.YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableability = hasReverseDepends ? Disableable.DEPENDENCIES : Disableable.RESTART;
|
||||
}
|
||||
Method factoryMethod = gatherAnnotations(clazz);
|
||||
modInstance = getLanguageAdapter().getNewInstance(this,clazz, modClassLoader, factoryMethod);
|
||||
NetworkRegistry.INSTANCE.register(this, clazz, (String)(descriptor.containsKey("acceptableRemoteVersions") ? descriptor.get("acceptableRemoteVersions") : null), event.getASMHarvestedData());
|
||||
@@ -544,12 +555,6 @@ public class FMLModContainer implements ModContainer
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkMod()
|
||||
{
|
||||
return isNetworkMod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayVersion()
|
||||
{
|
||||
@@ -605,4 +610,10 @@ public class FMLModContainer implements ModContainer
|
||||
descriptor.put("description", modMetadata.description);
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Disableable canBeDisabled()
|
||||
{
|
||||
return disableability;
|
||||
}
|
||||
}
|
||||
@@ -109,11 +109,6 @@ public class InjectedModContainer implements ModContainer
|
||||
return wrappedContainer.getProcessedVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkMod()
|
||||
{
|
||||
return wrappedContainer.isNetworkMod();
|
||||
}
|
||||
@Override
|
||||
public boolean isImmutable()
|
||||
{
|
||||
@@ -173,4 +168,10 @@ public class InjectedModContainer implements ModContainer
|
||||
{
|
||||
return wrappedContainer.getSharedModDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Disableable canBeDisabled()
|
||||
{
|
||||
return wrappedContainer.canBeDisabled();
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ package cpw.mods.fml.common;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -28,6 +29,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
@@ -35,6 +37,7 @@ import com.google.common.eventbus.Subscribe;
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.event.FMLEvent;
|
||||
import cpw.mods.fml.common.event.FMLLoadEvent;
|
||||
import cpw.mods.fml.common.event.FMLModDisabledEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLStateEvent;
|
||||
import cpw.mods.fml.common.functions.ArtifactVersionNameFunction;
|
||||
@@ -63,6 +66,20 @@ public class LoadController
|
||||
|
||||
}
|
||||
|
||||
void disableMod(ModContainer mod)
|
||||
{
|
||||
HashMap<String, EventBus> temporary = Maps.newHashMap(eventChannels);
|
||||
String modId = mod.getModId();
|
||||
EventBus bus = temporary.remove(modId);
|
||||
bus.post(new FMLModDisabledEvent());
|
||||
if (errors.get(modId).isEmpty())
|
||||
{
|
||||
eventChannels = ImmutableMap.copyOf(temporary);
|
||||
modStates.put(modId, ModState.DISABLED);
|
||||
modObjectList.remove(mod);
|
||||
activeModList.remove(mod);
|
||||
}
|
||||
}
|
||||
@Subscribe
|
||||
public void buildModList(FMLLoadEvent event)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ package cpw.mods.fml.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Comparator;
|
||||
@@ -29,14 +30,17 @@ 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.collect.ArrayListMultimap;
|
||||
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.LinkedHashMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.Multiset.Entry;
|
||||
import com.google.common.collect.Multisets;
|
||||
import com.google.common.collect.Ordering;
|
||||
@@ -45,6 +49,7 @@ import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.TreeMultimap;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.ModContainer.Disableable;
|
||||
import cpw.mods.fml.common.discovery.ModDiscoverer;
|
||||
import cpw.mods.fml.common.event.FMLInterModComms;
|
||||
import cpw.mods.fml.common.event.FMLLoadEvent;
|
||||
@@ -121,6 +126,10 @@ public class Loader
|
||||
* A named list of mods
|
||||
*/
|
||||
private Map<String, ModContainer> namedMods;
|
||||
/**
|
||||
* A reverse dependency graph for mods
|
||||
*/
|
||||
private ListMultimap<String, String> reverseDependencies;
|
||||
/**
|
||||
* The canonical configuration directory
|
||||
*/
|
||||
@@ -133,6 +142,7 @@ public class Loader
|
||||
private static File minecraftDir;
|
||||
private static List<String> injectedContainers;
|
||||
private ImmutableMap<String, String> fmlBrandingProperties;
|
||||
private File forcedModFile;
|
||||
|
||||
public static Loader instance()
|
||||
{
|
||||
@@ -187,6 +197,7 @@ public class Loader
|
||||
modVersions.put(mod.getModId(), mod.getProcessedVersion());
|
||||
}
|
||||
|
||||
ArrayListMultimap<String, String> reqList = ArrayListMultimap.create();
|
||||
for (ModContainer mod : getActiveModList())
|
||||
{
|
||||
if (!mod.acceptableMinecraftVersionRange().containsVersion(minecraft.getProcessedVersion()))
|
||||
@@ -196,6 +207,7 @@ public class Loader
|
||||
}
|
||||
Map<String,ArtifactVersion> names = Maps.uniqueIndex(mod.getRequirements(), new ArtifactVersionNameFunction());
|
||||
Set<ArtifactVersion> versionMissingMods = Sets.newHashSet();
|
||||
|
||||
Set<String> missingMods = Sets.difference(names.keySet(), modVersions.keySet());
|
||||
if (!missingMods.isEmpty())
|
||||
{
|
||||
@@ -206,6 +218,7 @@ public class Loader
|
||||
}
|
||||
throw new MissingModsException(versionMissingMods);
|
||||
}
|
||||
reqList.putAll(mod.getModId(), names.keySet());
|
||||
ImmutableList<ArtifactVersion> allDeps = ImmutableList.<ArtifactVersion>builder().addAll(mod.getDependants()).addAll(mod.getDependencies()).build();
|
||||
for (ArtifactVersion v : allDeps)
|
||||
{
|
||||
@@ -226,6 +239,7 @@ public class Loader
|
||||
|
||||
FMLLog.finer("All mod requirements are satisfied");
|
||||
|
||||
reverseDependencies = Multimaps.invertFrom(reqList, ArrayListMultimap.<String,String>create());
|
||||
ModSorter sorter = new ModSorter(getActiveModList(), namedMods);
|
||||
|
||||
try
|
||||
@@ -468,7 +482,7 @@ public class Loader
|
||||
}
|
||||
}
|
||||
modController.transition(LoaderState.CONSTRUCTING, false);
|
||||
modController.distributeStateMessage(LoaderState.CONSTRUCTING, modClassLoader, disc.getASMTable());
|
||||
modController.distributeStateMessage(LoaderState.CONSTRUCTING, modClassLoader, disc.getASMTable(), reverseDependencies);
|
||||
FMLLog.fine("Mod signature data");
|
||||
for (ModContainer mod : getActiveModList())
|
||||
{
|
||||
@@ -493,7 +507,7 @@ public class Loader
|
||||
FMLLog.finer("System property request managing the state of %d mods", sysPropertyStateList.size());
|
||||
Map<String, String> modStates = Maps.newHashMap();
|
||||
|
||||
File forcedModFile = new File(canonicalConfigDir, "fmlModState.properties");
|
||||
forcedModFile = new File(canonicalConfigDir, "fmlModState.properties");
|
||||
Properties forcedModListProperties = new Properties();
|
||||
if (forcedModFile.exists() && forcedModFile.isFile())
|
||||
{
|
||||
@@ -837,4 +851,40 @@ public class Loader
|
||||
modController.propogateStateMessage(new FMLModIdMappingEvent(remaps));
|
||||
}
|
||||
}
|
||||
|
||||
public void runtimeDisableMod(String modId)
|
||||
{
|
||||
ModContainer mc = namedMods.get(modId);
|
||||
Disableable disableable = mc.canBeDisabled();
|
||||
if (disableable == Disableable.NEVER)
|
||||
{
|
||||
FMLLog.info("Cannot disable mod %s - it is never allowed to be disabled", modId);
|
||||
return;
|
||||
}
|
||||
if (disableable == Disableable.DEPENDENCIES)
|
||||
{
|
||||
FMLLog.info("Cannot disable mod %s - there are dependent mods that require its presence", modId);
|
||||
return;
|
||||
}
|
||||
if (disableable == Disableable.YES)
|
||||
{
|
||||
FMLLog.info("Runtime disabling mod %s", modId);
|
||||
modController.disableMod(mc);
|
||||
List<ModContainer> localmods = Lists.newArrayList(mods);
|
||||
localmods.remove(mc);
|
||||
mods = ImmutableList.copyOf(localmods);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.load(new FileReader(forcedModFile));
|
||||
props.put(modId, "false");
|
||||
props.store(new FileWriter(forcedModFile), null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLLog.log(Level.INFO, e, "An error occurred writing the fml mod states file, your disabled change won't persist");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,9 @@ import cpw.mods.fml.common.versioning.VersionRange;
|
||||
|
||||
public interface ModContainer
|
||||
{
|
||||
public static enum Disableable {
|
||||
YES, RESTART, NEVER, DEPENDENCIES;
|
||||
}
|
||||
/**
|
||||
* The globally unique modid for this mod
|
||||
*/
|
||||
@@ -126,8 +129,6 @@ public interface ModContainer
|
||||
|
||||
boolean isImmutable();
|
||||
|
||||
boolean isNetworkMod();
|
||||
|
||||
String getDisplayVersion();
|
||||
|
||||
VersionRange acceptableMinecraftVersionRange();
|
||||
@@ -140,4 +141,6 @@ public interface ModContainer
|
||||
public Class<?> getCustomResourcePackClass();
|
||||
|
||||
Map<String, String> getSharedModDescriptor();
|
||||
|
||||
Disableable canBeDisabled();
|
||||
}
|
||||
@@ -5,13 +5,15 @@
|
||||
* are made available under the terms of the GNU Lesser Public License v2.1
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
*
|
||||
*
|
||||
* Contributors:
|
||||
* cpw - implementation
|
||||
*/
|
||||
|
||||
package cpw.mods.fml.common.event;
|
||||
|
||||
import com.google.common.collect.ListMultimap;
|
||||
|
||||
import cpw.mods.fml.common.LoaderState.ModState;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
import cpw.mods.fml.common.discovery.ASMDataTable;
|
||||
@@ -20,11 +22,14 @@ public class FMLConstructionEvent extends FMLStateEvent
|
||||
{
|
||||
private ModClassLoader modClassLoader;
|
||||
private ASMDataTable asmData;
|
||||
private ListMultimap<String,String> reverseDependencies;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public FMLConstructionEvent(Object... eventData)
|
||||
{
|
||||
this.modClassLoader = (ModClassLoader)eventData[0];
|
||||
this.asmData = (ASMDataTable) eventData[1];
|
||||
this.reverseDependencies = (ListMultimap<String, String>) eventData[2];
|
||||
}
|
||||
|
||||
public ModClassLoader getModClassLoader()
|
||||
@@ -42,4 +47,9 @@ public class FMLConstructionEvent extends FMLStateEvent
|
||||
{
|
||||
return asmData;
|
||||
}
|
||||
|
||||
public ListMultimap<String, String> getReverseDependencies()
|
||||
{
|
||||
return reverseDependencies;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package cpw.mods.fml.common.event;
|
||||
|
||||
public class FMLModDisabledEvent extends FMLEvent {
|
||||
}
|
||||
Reference in new issue
Block a user