Holy Moly, it's a big fat commit of broken code!
This commit is contained in:
parent
5b05e103f4
commit
c1f0e1b68f
63 changed files with 2027 additions and 542 deletions
62
mods.toml
Normal file
62
mods.toml
Normal file
|
@ -0,0 +1,62 @@
|
|||
# The name of the mod loader type to load
|
||||
modLoader="javafml"
|
||||
# A version range to match for said mod loader
|
||||
loaderVersion="[2.0,)"
|
||||
# A URL to query for updates
|
||||
updateJSONURL="http://myurl.me/"
|
||||
# A URL to refer people to when problems occur with this mod
|
||||
issueTrackerURL="http://my.issue.tracker/"
|
||||
# Extra mod loader property
|
||||
randomScalaProperty=fishy
|
||||
# Arbitrary key-value property pairs available to mods
|
||||
[properties]
|
||||
key="value"
|
||||
|
||||
# A list of mods - how many allowed here is determined by the individual mod loader
|
||||
[[mods]]
|
||||
# The modid of the mod
|
||||
modId="inventorysorter"
|
||||
# The version number of the mod
|
||||
version="1.1"
|
||||
# A display name for the mod
|
||||
displayName="Inventory Sorter"
|
||||
# The description text for the mod (multi line!)
|
||||
description='''
|
||||
This is my mod, there may be
|
||||
others, but this one is mine
|
||||
'''
|
||||
# A random extra property for a mod loader
|
||||
randomExtraProperty=somevalue
|
||||
# Arbitrary key-value pairs
|
||||
[inventorysorter.properties]
|
||||
key="value"
|
||||
# A list of dependencies
|
||||
[[inventorysorter.dependencies]]
|
||||
# the modid of the dependency
|
||||
modid="forge"
|
||||
# Does this dependency have to exist - if not, ordering below must be specified
|
||||
mandatory=true
|
||||
# The version range of the dependency
|
||||
versionRange="[14.23.2.0,)"
|
||||
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
|
||||
ordering=NONE
|
||||
# Side this dependency is applied on - BOTH, CLIENT or SERVER
|
||||
side=BOTH
|
||||
# Here's another dependency
|
||||
[[inventorysorter.dependencies]]
|
||||
modid="minecraft"
|
||||
mandatory=true
|
||||
versionRange="[1.12.2]"
|
||||
ordering=NONE
|
||||
side=BOTH
|
||||
# Here's another mod in this jar
|
||||
[[mods]]
|
||||
# Note that other mod types may want to add additional key-value pairs in here
|
||||
modId="inventorysortertoo"
|
||||
# ${jarVersion} will read the Implementation-Version of the jar file
|
||||
version="${jarVersion}"
|
||||
displayName="Inventory Sorter as well"
|
||||
description='''
|
||||
This is also my mod, there may be
|
||||
others, but this one is mine
|
||||
'''
|
|
@ -28,6 +28,7 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.common.ForgeModContainer;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.ForgeVersion.Status;
|
||||
import net.minecraftforge.fml.client.ClientModLoader;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
@ -55,16 +56,7 @@ public class NotificationModUpdateScreen extends GuiScreen
|
|||
{
|
||||
if (modButton != null)
|
||||
{
|
||||
for (ModContainer mod : Loader.instance().getModList())
|
||||
{
|
||||
Status status = ForgeVersion.getResult(mod).status;
|
||||
if (status == Status.OUTDATED || status == Status.BETA_OUTDATED)
|
||||
{
|
||||
// TODO: Needs better visualization, maybe stacked icons
|
||||
// drawn in a terrace-like pattern?
|
||||
showNotification = Status.OUTDATED;
|
||||
}
|
||||
}
|
||||
showNotification = ClientModLoader.checkForUpdates();
|
||||
}
|
||||
hasCheckedForUpdates = true;
|
||||
}
|
||||
|
|
|
@ -67,23 +67,24 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
|||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.registry.IRegistry;
|
||||
import net.minecraftforge.client.model.animation.AnimationItemOverrideList;
|
||||
import net.minecraftforge.client.model.animation.ModelBlockAnimation;
|
||||
import net.minecraftforge.common.ForgeModContainer;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.Models;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
import net.minecraftforge.common.model.animation.IClip;
|
||||
import net.minecraftforge.common.property.IExtendedBlockState;
|
||||
import net.minecraftforge.common.property.Properties;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fml.client.FMLClientHandler;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.ProgressManager;
|
||||
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
|
||||
import net.minecraftforge.fml.common.registry.ForgeRegistries;
|
||||
import net.minecraftforge.logging.ModelLoaderErrorMessage;
|
||||
import net.minecraftforge.registries.IRegistryDelegate;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
@ -105,13 +106,15 @@ import com.google.common.collect.ImmutableMap;
|
|||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.MODELLOADING;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
public final class ModelLoader extends ModelBakery
|
||||
{
|
||||
private final Map<ModelResourceLocation, IModel> stateModels = Maps.newHashMap();
|
||||
|
@ -128,9 +131,6 @@ public final class ModelLoader extends ModelBakery
|
|||
return isLoading;
|
||||
}
|
||||
|
||||
private final boolean enableVerboseMissingInfo = (Boolean)Launch.blackboard.get("fml.deobfuscatedEnvironment") || Boolean.parseBoolean(System.getProperty("forge.verboseMissingModelLogging", "false"));
|
||||
private final int verboseMissingInfoCount = Integer.parseInt(System.getProperty("forge.verboseMissingModelLoggingCount", "5"));
|
||||
|
||||
public ModelLoader(IResourceManager manager, TextureMap map, BlockModelShapes shapes)
|
||||
{
|
||||
super(manager, map, shapes);
|
||||
|
@ -915,7 +915,7 @@ public final class ModelLoader extends ModelBakery
|
|||
}
|
||||
}
|
||||
|
||||
private static class ItemLoadingException extends ModelLoaderRegistry.LoaderException
|
||||
public static class ItemLoadingException extends ModelLoaderRegistry.LoaderException
|
||||
{
|
||||
private final Exception normalException;
|
||||
private final Exception blockstateException;
|
||||
|
@ -933,93 +933,15 @@ public final class ModelLoader extends ModelBakery
|
|||
*/
|
||||
public void onPostBakeEvent(IRegistry<ModelResourceLocation, IBakedModel> modelRegistry)
|
||||
{
|
||||
if (!isLoading) return;
|
||||
|
||||
IBakedModel missingModel = modelRegistry.getObject(MODEL_MISSING);
|
||||
Map<String, Integer> modelErrors = Maps.newHashMap();
|
||||
Set<ResourceLocation> printedBlockStateErrors = Sets.newHashSet();
|
||||
Multimap<ModelResourceLocation, IBlockState> reverseBlockMap = null;
|
||||
Multimap<ModelResourceLocation, String> reverseItemMap = HashMultimap.create();
|
||||
if(enableVerboseMissingInfo)
|
||||
{
|
||||
reverseBlockMap = HashMultimap.create();
|
||||
for(Map.Entry<IBlockState, ModelResourceLocation> entry : blockModelShapes.getBlockStateMapper().putAllStateModelLocations().entrySet())
|
||||
{
|
||||
reverseBlockMap.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
ForgeRegistries.ITEMS.forEach(item ->
|
||||
{
|
||||
for(String s : getVariantNames(item))
|
||||
{
|
||||
ModelResourceLocation memory = getInventoryVariant(s);
|
||||
reverseItemMap.put(memory, item.getRegistryName().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(Map.Entry<ResourceLocation, Exception> entry : loadingExceptions.entrySet())
|
||||
{
|
||||
// ignoring pure ResourceLocation arguments, all things we care about pass ModelResourceLocation
|
||||
if(entry.getKey() instanceof ModelResourceLocation)
|
||||
{
|
||||
ModelResourceLocation location = (ModelResourceLocation)entry.getKey();
|
||||
IBakedModel model = modelRegistry.getObject(location);
|
||||
if(model == null || model == missingModel || model instanceof FancyMissingModel.BakedModel)
|
||||
{
|
||||
String domain = entry.getKey().getResourceDomain();
|
||||
Integer errorCountBox = modelErrors.get(domain);
|
||||
int errorCount = errorCountBox == null ? 0 : errorCountBox;
|
||||
errorCount++;
|
||||
if(errorCount < verboseMissingInfoCount)
|
||||
{
|
||||
String errorMsg = "Exception loading model for variant " + entry.getKey();
|
||||
if(enableVerboseMissingInfo)
|
||||
{
|
||||
Collection<IBlockState> blocks = reverseBlockMap.get(location);
|
||||
if(!blocks.isEmpty())
|
||||
{
|
||||
if(blocks.size() == 1)
|
||||
{
|
||||
errorMsg += " for blockstate \"" + blocks.iterator().next() + "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg += " for blockstates [\"" + Joiner.on("\", \"").join(blocks) + "\"]";
|
||||
}
|
||||
}
|
||||
Collection<String> items = reverseItemMap.get(location);
|
||||
if(!items.isEmpty())
|
||||
{
|
||||
if(!blocks.isEmpty()) errorMsg += " and";
|
||||
if(items.size() == 1)
|
||||
{
|
||||
errorMsg += " for item \"" + items.iterator().next() + "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg += " for items [\"" + Joiner.on("\", \"").join(items) + "\"]";
|
||||
}
|
||||
}
|
||||
}
|
||||
if(entry.getValue() instanceof ItemLoadingException)
|
||||
{
|
||||
ItemLoadingException ex = (ItemLoadingException)entry.getValue();
|
||||
FMLLog.log.error("{}, normal location exception: ", errorMsg, ex.normalException);
|
||||
FMLLog.log.error("{}, blockstate location exception: ", errorMsg, ex.blockstateException);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.error(errorMsg, entry.getValue());
|
||||
}
|
||||
ResourceLocation blockstateLocation = new ResourceLocation(location.getResourceDomain(), location.getResourcePath());
|
||||
if(loadingExceptions.containsKey(blockstateLocation) && !printedBlockStateErrors.contains(blockstateLocation))
|
||||
{
|
||||
FMLLog.log.error("Exception loading blockstate for the variant {}: ", location, loadingExceptions.get(blockstateLocation));
|
||||
printedBlockStateErrors.add(blockstateLocation);
|
||||
}
|
||||
}
|
||||
modelErrors.put(domain, errorCount);
|
||||
}
|
||||
fmlLog.debug(MODELLOADING, ()-> new ModelLoaderErrorMessage((ModelResourceLocation)entry.getKey(), entry.getValue(), modelRegistry, this.blockModelShapes, this::getVariantNames));
|
||||
final ModelResourceLocation location = (ModelResourceLocation)entry.getKey();
|
||||
final IBakedModel model = modelRegistry.getObject(location);
|
||||
if(model == null)
|
||||
{
|
||||
modelRegistry.putObject(location, missingModel);
|
||||
|
@ -1031,28 +953,13 @@ public final class ModelLoader extends ModelBakery
|
|||
IBakedModel model = modelRegistry.getObject(missing);
|
||||
if(model == null || model == missingModel)
|
||||
{
|
||||
String domain = missing.getResourceDomain();
|
||||
Integer errorCountBox = modelErrors.get(domain);
|
||||
int errorCount = errorCountBox == null ? 0 : errorCountBox;
|
||||
errorCount++;
|
||||
if(errorCount < verboseMissingInfoCount)
|
||||
{
|
||||
FMLLog.log.fatal("Model definition for location {} not found", missing);
|
||||
}
|
||||
modelErrors.put(domain, errorCount);
|
||||
fmlLog.debug(MODELLOADING, ()-> new ModelLoaderErrorMessage(missing, null, modelRegistry, this.blockModelShapes, this::getVariantNames));
|
||||
}
|
||||
if(model == null)
|
||||
{
|
||||
modelRegistry.putObject(missing, missingModel);
|
||||
}
|
||||
}
|
||||
for(Map.Entry<String, Integer> e : modelErrors.entrySet())
|
||||
{
|
||||
if(e.getValue() >= verboseMissingInfoCount)
|
||||
{
|
||||
FMLLog.log.fatal("Suppressed additional {} model loading errors for domain {}", e.getValue() - verboseMissingInfoCount, e.getKey());
|
||||
}
|
||||
}
|
||||
loadingExceptions.clear();
|
||||
missingVariants.clear();
|
||||
isLoading = false;
|
||||
|
|
|
@ -23,10 +23,15 @@ import static net.minecraftforge.common.ForgeVersion.Status.*;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -35,6 +40,12 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.electronwill.nightconfig.core.Config;
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import com.electronwill.nightconfig.core.path.PathConfig;
|
||||
import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
@ -57,7 +68,7 @@ public class ForgeVersion
|
|||
//This number is incremented every minecraft release, never reset
|
||||
public static final int minorVersion = 23;
|
||||
//This number is incremented every time a interface changes or new major feature is added, and reset every Minecraft version
|
||||
public static final int revisionVersion = 4;
|
||||
public static final int revisionVersion = 2;
|
||||
//This number is incremented every time Jenkins builds Forge, and never reset. Should always be 0 in the repo code.
|
||||
public static final int buildVersion = 0;
|
||||
// This is the minecraft version we're building for - used in various places in Forge/FML code
|
||||
|
@ -69,7 +80,7 @@ public class ForgeVersion
|
|||
@SuppressWarnings("unused")
|
||||
private static String target = null;
|
||||
|
||||
private static final Logger log = LogManager.getLogger(MOD_ID + ".VersionCheck");
|
||||
private static final Logger log = LogManager.getLogger("ForgeVersionCheck");
|
||||
|
||||
private static final int MAX_HTTP_REDIRECTS = Integer.getInteger("http.maxRedirects", 20);
|
||||
|
||||
|
@ -110,6 +121,27 @@ public class ForgeVersion
|
|||
return String.format("%d.%d.%d.%d", majorVersion, minorVersion, revisionVersion, buildVersion);
|
||||
}
|
||||
|
||||
public static List<ModInfo> getModInfos()
|
||||
{
|
||||
PathConfig minecraftmod;
|
||||
PathConfig forgemod;
|
||||
try
|
||||
{
|
||||
minecraftmod = PathConfig.of(Paths.get(ForgeVersion.class.getClassLoader().getResource("minecraftmod.toml").toURI()));
|
||||
forgemod = PathConfig.of(Paths.get(ForgeVersion.class.getClassLoader().getResource("forgemod.toml").toURI()));
|
||||
minecraftmod.load();
|
||||
forgemod.load();
|
||||
}
|
||||
catch (URISyntaxException | NullPointerException e)
|
||||
{
|
||||
throw new RuntimeException("Missing toml configs for minecraft and forge!", e);
|
||||
}
|
||||
return Arrays.asList(
|
||||
new ModInfo(null, minecraftmod),
|
||||
new ModInfo(null, forgemod)
|
||||
);
|
||||
}
|
||||
|
||||
public static enum Status
|
||||
{
|
||||
PENDING(),
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraftforge.fml.ModThreadContext;
|
||||
import net.minecraftforge.fml.common.LoaderState;
|
||||
import org.apache.logging.log4j.Level;
|
||||
|
||||
|
@ -177,9 +178,7 @@ public abstract class FluidRegistry
|
|||
|
||||
private static String uniqueName(Fluid fluid)
|
||||
{
|
||||
ModContainer activeModContainer = Loader.instance().activeModContainer();
|
||||
String activeModContainerName = activeModContainer == null ? "minecraft" : activeModContainer.getModId();
|
||||
return activeModContainerName+":"+fluid.getName();
|
||||
return ModThreadContext.get().getCurrentContainer().getPrefix() +":"+fluid.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.CrashReportCategory;
|
||||
import net.minecraftforge.fml.common.ICrashCallable;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import net.minecraftforge.fml.relauncher.CoreModManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CrashReportExtender
|
||||
{
|
||||
private static List<ICrashCallable> crashCallables = new ArrayList<>();
|
||||
|
||||
static {
|
||||
registerCrashCallable(new ICrashCallable() {
|
||||
@Override
|
||||
public String call()
|
||||
{
|
||||
return "New FML!";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
return "FML";
|
||||
}
|
||||
});
|
||||
|
||||
registerCrashCallable(new ICrashCallable()
|
||||
{
|
||||
@Override
|
||||
public String call()
|
||||
{
|
||||
return "Nothing";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
return "Loaded coremods (and transformers)";
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void enhanceCrashReport(final CrashReport crashReport, final CrashReportCategory category)
|
||||
{
|
||||
for (final ICrashCallable call: crashCallables)
|
||||
{
|
||||
category.addDetail(call.getLabel(), call);
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerCrashCallable(ICrashCallable callable)
|
||||
{
|
||||
crashCallables.add(callable);
|
||||
}
|
||||
|
||||
public static void addCrashReportHeader(StringBuilder stringbuilder, CrashReport crashReport)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.fml.common.MinecraftDummyContainer;
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
|
||||
public class DefaultModContainers
|
||||
{
|
||||
// no construction
|
||||
private DefaultModContainers() {}
|
||||
|
||||
public static final ModContainer MINECRAFT = new MinecraftDummyContainer(ForgeVersion.mcVersion);
|
||||
}
|
28
src/main/java/net/minecraftforge/fml/FMLEnvironment.java
Normal file
28
src/main/java/net/minecraftforge/fml/FMLEnvironment.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.api.Side;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
|
||||
public class FMLEnvironment
|
||||
{
|
||||
public static final Side side = FMLLoader.getSide();
|
||||
}
|
43
src/main/java/net/minecraftforge/fml/Java9BackportUtils.java
Normal file
43
src/main/java/net/minecraftforge/fml/Java9BackportUtils.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Java9BackportUtils
|
||||
{
|
||||
public static <T, U, A, R>
|
||||
Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper,
|
||||
Collector<? super U, A, R> downstream) {
|
||||
BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
|
||||
return Collector.of(downstream.supplier(),
|
||||
(r, t) -> {
|
||||
try (Stream<? extends U> result = mapper.apply(t)) {
|
||||
if (result != null)
|
||||
result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
|
||||
}
|
||||
},
|
||||
downstream.combiner(), downstream.finisher(),
|
||||
downstream.characteristics().toArray(new Collector.Characteristics[0]));
|
||||
}
|
||||
}
|
|
@ -21,19 +21,45 @@ package net.minecraftforge.fml;
|
|||
|
||||
import com.google.common.base.Strings;
|
||||
import cpw.mods.modlauncher.Launcher;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.properties.PropertyEnum;
|
||||
import net.minecraft.block.state.BlockStateContainer;
|
||||
import net.minecraft.item.EnumDyeColor;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.apache.logging.log4j.core.config.Configuration;
|
||||
import org.apache.logging.log4j.core.config.ConfigurationFactory;
|
||||
import org.apache.logging.log4j.core.config.Configurator;
|
||||
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
|
||||
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
|
||||
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
|
||||
import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
|
||||
import org.apache.logging.log4j.core.filter.MarkerFilter;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static cpw.mods.modlauncher.Logging.CLASSLOADING;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
public class LaunchTesting
|
||||
{
|
||||
public static void main(String... args) throws InterruptedException
|
||||
{
|
||||
Configurator.setRootLevel(Level.DEBUG);
|
||||
final MarkerFilter classloadingFilter = MarkerFilter.createFilter("CLASSLOADING", Filter.Result.DENY, Filter.Result.NEUTRAL);
|
||||
final MarkerFilter launchpluginFilter = MarkerFilter.createFilter("LAUNCHPLUGIN", Filter.Result.DENY, Filter.Result.NEUTRAL);
|
||||
final LoggerContext logcontext = LoggerContext.getContext(false);
|
||||
// logcontext.getConfiguration().addFilter(classloadingFilter);
|
||||
logcontext.getConfiguration().addFilter(launchpluginFilter);
|
||||
logcontext.updateLoggers();
|
||||
hackNatives();
|
||||
Launcher.main("--launchTarget", "devfml","--gameDir", "projects/run", "--accessToken", "blah", "--version", "FMLDev");
|
||||
Launcher.main("--launchTarget", "devfmlclient","--gameDir", "projects/run",
|
||||
"--accessToken", "blah", "--version", "FMLDev", "--assetIndex", "1.12",
|
||||
"--assetsDir","/home/cpw/.gradle/caches/minecraft/assets",
|
||||
"--userProperties", "{}");
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,11 @@ import org.apache.logging.log4j.core.config.Configurator;
|
|||
public class Logging
|
||||
{
|
||||
public static final Logger fmlLog = LogManager.getLogger("FML");
|
||||
|
||||
// Lots of markers
|
||||
public static final Marker CORE = MarkerManager.getMarker("CORE");
|
||||
public static final Marker LOADING = MarkerManager.getMarker("LOADING");
|
||||
public static final Marker SCAN = MarkerManager.getMarker("SCAN");
|
||||
public static final Marker SPLASH = MarkerManager.getMarker("SPLASH");
|
||||
public static final Marker MODELLOADING = MarkerManager.getMarker("MODELLOADING");
|
||||
}
|
||||
|
|
37
src/main/java/net/minecraftforge/fml/ModThreadContext.java
Normal file
37
src/main/java/net/minecraftforge/fml/ModThreadContext.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
|
||||
public class ModThreadContext
|
||||
{
|
||||
private static ThreadLocal<ModThreadContext> context = ThreadLocal.withInitial(ModThreadContext::new);
|
||||
|
||||
public static ModThreadContext get() {
|
||||
return context.get();
|
||||
}
|
||||
|
||||
private ModContainer currentContainer;
|
||||
|
||||
public ModContainer getCurrentContainer() {
|
||||
return currentContainer == null ? DefaultModContainers.MINECRAFT : currentContainer;
|
||||
}
|
||||
}
|
52
src/main/java/net/minecraftforge/fml/SidedExecutor.java
Normal file
52
src/main/java/net/minecraftforge/fml/SidedExecutor.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.api.Side;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class SidedExecutor
|
||||
{
|
||||
private SidedExecutor() {}
|
||||
|
||||
/**
|
||||
* Run the callable in the supplier only on the specified {@link Side}
|
||||
*
|
||||
* @param side The side to run on
|
||||
* @param toRun A supplier of the callable to run (Supplier wrapper to ensure classloading only on the appropriate side)
|
||||
* @param <T> The return type from the callable
|
||||
* @return The callable's result
|
||||
*/
|
||||
public static <T> T runOn(Side side, Supplier<Callable<T>> toRun) {
|
||||
if (side == Side.CLIENT) {
|
||||
try
|
||||
{
|
||||
return toRun.get().call();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
67
src/main/java/net/minecraftforge/fml/StringSubstitutor.java
Normal file
67
src/main/java/net/minecraftforge/fml/StringSubstitutor.java
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import org.apache.commons.lang3.text.StrLookup;
|
||||
import org.apache.commons.lang3.text.StrSubstitutor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StringSubstitutor
|
||||
{
|
||||
private static final Map<String,String> globals = ImmutableMap.of(
|
||||
"mcVersion", ForgeVersion.mcVersion,
|
||||
"forgeVersion", ForgeVersion.getVersion(),
|
||||
"mcpVersion", ForgeVersion.mcpVersion);
|
||||
|
||||
public static String replace(final String in, final ModFile file) {
|
||||
return new StrSubstitutor(getStringLookup(file)).replace(in);
|
||||
}
|
||||
|
||||
private static StrLookup<String> getStringLookup(final ModFile file) {
|
||||
return new StrLookup<String>()
|
||||
{
|
||||
@Override
|
||||
public String lookup(String key)
|
||||
{
|
||||
final String[] parts = key.split("\\.");
|
||||
if (parts.length == 1) return key;
|
||||
final String pfx = parts[0];
|
||||
if ("global".equals(pfx))
|
||||
{
|
||||
return globals.get(parts[1]);
|
||||
}
|
||||
else if ("file".equals(pfx))
|
||||
{
|
||||
return String.valueOf(file.getSubstitutionMap().get().get(parts[1]));
|
||||
}
|
||||
return key;
|
||||
}
|
||||
};
|
||||
}
|
||||
private static List<String> split(final String in) {
|
||||
return Arrays.asList(in.split("."));
|
||||
}
|
||||
}
|
|
@ -19,6 +19,13 @@
|
|||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import org.apache.commons.lang3.text.StrSubstitutor;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Created by cpw on 05/06/17.
|
||||
*/
|
||||
|
@ -32,4 +39,19 @@ public class StringUtils
|
|||
String lowerSearch = toLowerCase(search);
|
||||
return java.util.stream.Stream.of(endings).anyMatch(lowerSearch::endsWith);
|
||||
}
|
||||
|
||||
public static URL toURL(final String string) {
|
||||
try
|
||||
{
|
||||
return new URL(string);
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String parseStringFormat(final String input, final Map<String, String> properties) {
|
||||
return StrSubstitutor.replace(input, properties);
|
||||
}
|
||||
}
|
||||
|
|
50
src/main/java/net/minecraftforge/fml/TomlConverters.java
Normal file
50
src/main/java/net/minecraftforge/fml/TomlConverters.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml;
|
||||
|
||||
import com.electronwill.nightconfig.core.conversion.Converter;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public final class TomlConverters
|
||||
{
|
||||
public static class StringToURL implements Converter<URL, String> {
|
||||
|
||||
@Override
|
||||
public URL convertToField(String value)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new URL(value);
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
throw new RuntimeException("Invalid URL specified", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertFromField(URL value)
|
||||
{
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.client;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class BrandingControl
|
||||
{
|
||||
private static List<String> brandings;
|
||||
private static List<String> brandingsNoMC;
|
||||
|
||||
private static void computeBranding()
|
||||
{
|
||||
if (brandings == null)
|
||||
{
|
||||
ImmutableList.Builder<String> brd = ImmutableList.builder();
|
||||
brd.add("Minecraft " + ForgeVersion.mcVersion);
|
||||
brd.add("MCP " + ForgeVersion.mcpVersion);
|
||||
brd.add("Forge " + ForgeVersion.getVersion());
|
||||
int tModCount = 2;
|
||||
|
||||
brd.add(MessageFormat.format("{0,choice,0#No mods|1#1 mod|1<{0} mods} loaded", tModCount));
|
||||
brandings = brd.build();
|
||||
brandingsNoMC = brandings.subList(1, brandings.size());
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getBrandings(boolean includeMC, boolean reverse)
|
||||
{
|
||||
computeBranding();
|
||||
if (includeMC) {
|
||||
return reverse ? Lists.reverse(brandings) : brandings;
|
||||
} else {
|
||||
return reverse ? Lists.reverse(brandingsNoMC) : brandingsNoMC;
|
||||
}
|
||||
}
|
||||
|
||||
private static final List<String> defaultClientBranding = Stream.of("fml", "forge").collect(Collectors.toList());
|
||||
public static String getClientBranding() {
|
||||
return defaultClientBranding.stream().collect(Collectors.joining(","));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.client;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.resources.data.MetadataSerializer;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ClientModLoader
|
||||
{
|
||||
/**
|
||||
* Mod loading entrypoint for the client
|
||||
* @param minecraft
|
||||
* @param defaultResourcePacks
|
||||
* @param mcResourceManager
|
||||
* @param metadataSerializer_
|
||||
*/
|
||||
public static void begin(Minecraft minecraft, List<IResourcePack> defaultResourcePacks, IReloadableResourceManager mcResourceManager, MetadataSerializer metadataSerializer_)
|
||||
{
|
||||
SplashProgress.start();
|
||||
FMLLoader.getModLoader().loadMods();
|
||||
minecraft.refreshResources();
|
||||
}
|
||||
|
||||
public static void end()
|
||||
{
|
||||
SplashProgress.finish();
|
||||
}
|
||||
|
||||
public static ForgeVersion.Status checkForUpdates()
|
||||
{
|
||||
return ForgeVersion.Status.UP_TO_DATE;
|
||||
}
|
||||
|
||||
public static void complete()
|
||||
{
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.enableTexture2D();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.client;
|
||||
|
||||
public class FMLClientConfig
|
||||
{
|
||||
|
||||
}
|
|
@ -1031,13 +1031,6 @@ public class FMLClientHandler implements IFMLSidedHandler
|
|||
@Override
|
||||
public void processWindowMessages()
|
||||
{
|
||||
// workaround for windows requiring messages being processed on the main thread
|
||||
if (LWJGLUtil.getPlatform() != LWJGLUtil.PLATFORM_WINDOWS) return;
|
||||
// If we can't grab the mutex, the update call is blocked, probably in native code, just skip it and carry on
|
||||
// We'll get another go next time
|
||||
if (!SplashProgress.mutex.tryAcquire()) return;
|
||||
Display.processMessages();
|
||||
SplashProgress.mutex.release();
|
||||
}
|
||||
// From FontRenderer.renderCharAtPos
|
||||
private static final String ALLOWED_CHARS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
package net.minecraftforge.fml.client;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SPLASH;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL12.*;
|
||||
|
||||
|
@ -60,18 +62,18 @@ import net.minecraft.client.resources.SimpleResource;
|
|||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.CrashReportExtender;
|
||||
import net.minecraftforge.fml.common.EnhancedRuntimeException;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.ICrashCallable;
|
||||
import net.minecraftforge.fml.common.ProgressManager;
|
||||
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
|
||||
import net.minecraftforge.fml.common.asm.FMLSanityChecker;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.LWJGLUtil;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.Drawable;
|
||||
import org.lwjgl.opengl.SharedDrawable;
|
||||
|
@ -94,7 +96,7 @@ public class SplashProgress
|
|||
private static SplashFontRenderer fontRenderer;
|
||||
|
||||
private static final IResourcePack mcPack = Minecraft.getMinecraft().mcDefaultResourcePack;
|
||||
private static final IResourcePack fmlPack = createResourcePack(FMLSanityChecker.fmlLocation);
|
||||
private static final IResourcePack fmlPack = mcPack;
|
||||
private static IResourcePack miscPack;
|
||||
|
||||
private static Texture fontTexture;
|
||||
|
@ -121,7 +123,18 @@ public class SplashProgress
|
|||
private static final int TIMING_FRAME_COUNT = 200;
|
||||
private static final int TIMING_FRAME_THRESHOLD = TIMING_FRAME_COUNT * 5 * 1000000; // 5 ms per frame, scaled to nanos
|
||||
|
||||
static final Semaphore mutex = new Semaphore(1);
|
||||
private static final Semaphore mutex = new Semaphore(1);
|
||||
|
||||
public static Void processMessages() {
|
||||
// workaround for windows requiring messages being processed on the main thread
|
||||
if (LWJGLUtil.getPlatform() != LWJGLUtil.PLATFORM_WINDOWS) return null;
|
||||
// If we can't grab the mutex, the update call is blocked, probably in native code, just skip it and carry on
|
||||
// We'll get another go next time
|
||||
if (!SplashProgress.mutex.tryAcquire()) return null;
|
||||
Display.processMessages();
|
||||
SplashProgress.mutex.release();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getString(String name, String def)
|
||||
{
|
||||
|
@ -160,16 +173,10 @@ public class SplashProgress
|
|||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
FMLLog.log.info("Could not load splash.properties, will create a default one");
|
||||
fmlLog.info(SPLASH, "Could not load splash.properties, will create a default one");
|
||||
}
|
||||
|
||||
//Some systems do not support this and have weird effects, so we need to detect and disable them by default.
|
||||
//The user can always force enable it if they want to take the responsibility for bugs.
|
||||
boolean defaultEnabled = true;
|
||||
|
||||
// Enable if we have the flag, and there's either no optifine, or optifine has added a key to the blackboard ("optifine.ForgeSplashCompatible")
|
||||
// Optifine authors - add this key to the blackboard if you feel your modifications are now compatible with this code.
|
||||
enabled = getBool("enabled", defaultEnabled) && ( (!FMLClientHandler.instance().hasOptifine()) || Launch.blackboard.containsKey("optifine.ForgeSplashCompatible"));
|
||||
enabled = getBool("enabled", true);
|
||||
rotate = getBool("rotate", false);
|
||||
showMemory = getBool("showMemory", true);
|
||||
logoOffset = getInt("logoOffset", 0);
|
||||
|
@ -202,7 +209,7 @@ public class SplashProgress
|
|||
|
||||
if(!enabled) return;
|
||||
// getting debug info out of the way, while we still can
|
||||
FMLCommonHandler.instance().registerCrashCallable(new ICrashCallable()
|
||||
CrashReportExtender.registerCrashCallable(new ICrashCallable()
|
||||
{
|
||||
@Override
|
||||
public String call() throws Exception
|
||||
|
@ -222,7 +229,7 @@ public class SplashProgress
|
|||
CrashReport report = CrashReport.makeCrashReport(new Throwable(), "Loading screen debug info");
|
||||
StringBuilder systemDetailsBuilder = new StringBuilder();
|
||||
report.getCategory().appendToStringBuilder(systemDetailsBuilder);
|
||||
FMLLog.log.info(systemDetailsBuilder.toString());
|
||||
fmlLog.info(SPLASH, systemDetailsBuilder.toString());
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -390,13 +397,13 @@ public class SplashProgress
|
|||
if (!isDisplayVSyncForced)
|
||||
{
|
||||
isDisplayVSyncForced = true;
|
||||
FMLLog.log.info("Using alternative sync timing : {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming);
|
||||
fmlLog.info(SPLASH,"Using alternative sync timing : {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming);
|
||||
}
|
||||
try { Thread.sleep(16); } catch (InterruptedException ie) {}
|
||||
} else
|
||||
{
|
||||
if (framecount ==TIMING_FRAME_COUNT) {
|
||||
FMLLog.log.info("Using sync timing. {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming);
|
||||
fmlLog.info("Using sync timing. {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming);
|
||||
}
|
||||
Display.sync(100);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraftforge.fml.StringUtils;
|
||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
||||
import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;
|
||||
import net.minecraftforge.fml.common.versioning.VersionRange;
|
||||
|
@ -97,6 +98,12 @@ public class DummyModContainer implements ModContainer
|
|||
return md.modId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefix()
|
||||
{
|
||||
return StringUtils.toLowerCase(getModId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
|
|
|
@ -19,27 +19,18 @@
|
|||
|
||||
package net.minecraftforge.fml.common;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.CrashReportCategory;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
|
@ -61,6 +52,7 @@ import net.minecraftforge.client.model.animation.Animation;
|
|||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.util.CompoundDataFixer;
|
||||
import net.minecraftforge.fml.client.BrandingControl;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.EventBus;
|
||||
import net.minecraftforge.fml.common.gameevent.InputEvent;
|
||||
|
@ -70,22 +62,17 @@ import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
|
|||
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
|
||||
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||
import net.minecraftforge.fml.common.thread.SidedThreadGroup;
|
||||
import net.minecraftforge.fml.relauncher.CoreModManager;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.server.FMLServerHandler;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The main class for non-obfuscated hook handling code
|
||||
*
|
||||
|
@ -113,7 +100,6 @@ public class FMLCommonHandler
|
|||
private boolean noForge;
|
||||
private List<String> brandings;
|
||||
private List<String> brandingsNoMC;
|
||||
private List<ICrashCallable> crashCallables = Lists.newArrayList(Loader.instance().getCallableCrashInformation());
|
||||
private Set<SaveHandler> handlerSet = Collections.newSetFromMap(new MapMaker().weakKeys().<SaveHandler,Boolean>makeMap());
|
||||
private WeakReference<SaveHandler> handlerToCheck;
|
||||
private EventBus eventBus = MinecraftForge.EVENT_BUS;
|
||||
|
@ -121,26 +107,6 @@ public class FMLCommonHandler
|
|||
|
||||
private FMLCommonHandler()
|
||||
{
|
||||
registerCrashCallable(new ICrashCallable()
|
||||
{
|
||||
@Override
|
||||
public String call() throws Exception
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Joiner joiner = Joiner.on("\n ");
|
||||
for(String coreMod : CoreModManager.getTransformers().keySet())
|
||||
{
|
||||
builder.append("\n" + coreMod + "\n ").append(joiner.join(CoreModManager.getTransformers().get(coreMod)));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
return "Loaded coremods (and transformers)";
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* The FML event bus. Subscribe here for FML related events
|
||||
|
@ -224,34 +190,11 @@ public class FMLCommonHandler
|
|||
}
|
||||
|
||||
|
||||
public void computeBranding()
|
||||
{
|
||||
if (brandings == null)
|
||||
{
|
||||
Builder<String> brd = ImmutableList.builder();
|
||||
brd.add(Loader.instance().getMCVersionString());
|
||||
brd.add(Loader.instance().getMCPVersionString());
|
||||
brd.add("Powered by Forge " + ForgeVersion.getVersion());
|
||||
if (sidedDelegate!=null)
|
||||
{
|
||||
brd.addAll(sidedDelegate.getAdditionalBrandingInformation());
|
||||
}
|
||||
if (Loader.instance().getFMLBrandingProperties().containsKey("fmlbranding"))
|
||||
{
|
||||
brd.add(Loader.instance().getFMLBrandingProperties().get("fmlbranding"));
|
||||
}
|
||||
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();
|
||||
brandingsNoMC = brandings.subList(1, brandings.size());
|
||||
}
|
||||
}
|
||||
public List<String> getBrandings(boolean includeMC)
|
||||
{
|
||||
if (brandings == null)
|
||||
{
|
||||
computeBranding();
|
||||
BrandingControl.computeBranding();
|
||||
}
|
||||
return includeMC ? ImmutableList.copyOf(brandings) : ImmutableList.copyOf(brandingsNoMC);
|
||||
}
|
||||
|
@ -370,19 +313,6 @@ public class FMLCommonHandler
|
|||
bus().post(new TickEvent.PlayerTickEvent(Phase.END, player));
|
||||
}
|
||||
|
||||
public void registerCrashCallable(ICrashCallable callable)
|
||||
{
|
||||
crashCallables.add(callable);
|
||||
}
|
||||
|
||||
public void enhanceCrashReport(CrashReport crashReport, CrashReportCategory category)
|
||||
{
|
||||
for (ICrashCallable call: crashCallables)
|
||||
{
|
||||
category.addDetail(call.getLabel(), call);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleWorldDataSave(SaveHandler handler, WorldInfo worldInfo, NBTTagCompound tagCompound)
|
||||
{
|
||||
for (ModContainer mc : Loader.instance().getModList())
|
||||
|
@ -709,47 +639,6 @@ public class FMLCommonHandler
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a lang file, first searching for a marker to enable the 'extended' format {escape characters}
|
||||
* If the marker is not found it simply returns and let the vanilla code load things.
|
||||
* The Marker is 'PARSE_ESCAPES' by itself on a line starting with '#' as such:
|
||||
* #PARSE_ESCAPES
|
||||
*
|
||||
* @param table The Map to load each key/value pair into.
|
||||
* @param inputstream Input stream containing the lang file.
|
||||
* @return A new InputStream that vanilla uses to load normal Lang files, Null if this is a 'enhanced' file and loading is done.
|
||||
*/
|
||||
@Nullable
|
||||
public InputStream loadLanguage(Map<String, String> table, InputStream inputstream) throws IOException
|
||||
{
|
||||
byte[] data = IOUtils.toByteArray(inputstream);
|
||||
|
||||
boolean isEnhanced = false;
|
||||
for (String line : IOUtils.readLines(new ByteArrayInputStream(data), StandardCharsets.UTF_8))
|
||||
{
|
||||
if (!line.isEmpty() && line.charAt(0) == '#')
|
||||
{
|
||||
line = line.substring(1).trim();
|
||||
if (line.equals("PARSE_ESCAPES"))
|
||||
{
|
||||
isEnhanced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEnhanced)
|
||||
return new ByteArrayInputStream(data);
|
||||
|
||||
Properties props = new Properties();
|
||||
props.load(new InputStreamReader(new ByteArrayInputStream(data), StandardCharsets.UTF_8));
|
||||
for (Entry<Object, Object> e : props.entrySet())
|
||||
{
|
||||
table.put((String)e.getKey(), (String)e.getValue());
|
||||
}
|
||||
props.clear();
|
||||
return null;
|
||||
}
|
||||
public String stripSpecialChars(String message)
|
||||
{
|
||||
return sidedDelegate != null ? sidedDelegate.stripSpecialChars(message) : message;
|
||||
|
|
|
@ -54,10 +54,13 @@ import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;
|
|||
import net.minecraftforge.fml.common.versioning.DependencyParser;
|
||||
import net.minecraftforge.fml.common.versioning.VersionParser;
|
||||
import net.minecraftforge.fml.common.versioning.VersionRange;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
@ -73,10 +76,11 @@ import com.google.common.collect.Maps;
|
|||
import com.google.common.collect.SetMultimap;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import org.apache.logging.log4j.message.FormattedMessage;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public class FMLModContainer implements ModContainer
|
||||
{
|
||||
private Object modInstance;
|
||||
|
@ -105,6 +109,8 @@ public class FMLModContainer implements ModContainer
|
|||
private URL updateJSONUrl;
|
||||
private int classVersion;
|
||||
|
||||
private Logger modLog;
|
||||
|
||||
public FMLModContainer(String className, ModCandidate container, Map<String, Object> modDescriptor)
|
||||
{
|
||||
this.className = className;
|
||||
|
@ -126,6 +132,22 @@ public class FMLModContainer implements ModContainer
|
|||
FMLLog.log.trace("Using custom language adapter {} for {} (modid: {})", languageAdapterType, this.className, getModId());
|
||||
}
|
||||
sanityCheckModId();
|
||||
|
||||
modLog = LogManager.getLogger(getModId());
|
||||
}
|
||||
|
||||
public FMLModContainer(ModInfo info, String className, ClassLoader modClassLoader)
|
||||
{
|
||||
try
|
||||
{
|
||||
final Class<?> aClass = Class.forName(className, true, modClassLoader);
|
||||
LogManager.getLogger("FML").error("Loaded {} with {}", aClass, aClass.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LogManager.getLogger("FML").error(CORE, "Failed to load class {}", className, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void sanityCheckModId()
|
||||
|
@ -212,15 +234,15 @@ public class FMLModContainer implements ModContainer
|
|||
modMetadata.requiredMods = info.requirements;
|
||||
modMetadata.dependencies = info.dependencies;
|
||||
modMetadata.dependants = info.dependants;
|
||||
FMLLog.log.trace("Parsed dependency info for {}: Requirements: {} After:{} Before:{}", getModId(), info.requirements, info.dependencies, info.dependants);
|
||||
modLog.trace("Parsed dependency info : Requirements: {} After:{} Before:{}", info.requirements, info.dependencies, info.dependants);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.trace("Using mcmod dependency info for {}: {} {} {}", getModId(), modMetadata.requiredMods, modMetadata.dependencies, modMetadata.dependants);
|
||||
modLog.trace("Using mcmod dependency info : {} {} {}", modMetadata.requiredMods, modMetadata.dependencies, modMetadata.dependants);
|
||||
}
|
||||
if (Strings.isNullOrEmpty(modMetadata.name))
|
||||
{
|
||||
FMLLog.log.info("Mod {} is missing the required element 'name'. Substituting {}", getModId(), getModId());
|
||||
modLog.info("Mod {} is missing the required element 'name'. Substituting {}", getModId(), getModId());
|
||||
modMetadata.name = getModId();
|
||||
}
|
||||
internalVersion = (String)descriptor.get("version");
|
||||
|
@ -230,18 +252,18 @@ public class FMLModContainer implements ModContainer
|
|||
if (versionProps != null)
|
||||
{
|
||||
internalVersion = versionProps.getProperty(getModId() + ".version");
|
||||
FMLLog.log.debug("Found version {} for mod {} in version.properties, using", internalVersion, getModId());
|
||||
modLog.debug("Found version {} for mod {} in version.properties, using", internalVersion, getModId());
|
||||
}
|
||||
|
||||
}
|
||||
if (Strings.isNullOrEmpty(internalVersion) && !Strings.isNullOrEmpty(modMetadata.version))
|
||||
{
|
||||
FMLLog.log.warn("Mod {} is missing the required element 'version' and a version.properties file could not be found. Falling back to metadata version {}", getModId(), modMetadata.version);
|
||||
modLog.warn("Mod {} is missing the required element 'version' and a version.properties file could not be found. Falling back to metadata version {}", getModId(), modMetadata.version);
|
||||
internalVersion = modMetadata.version;
|
||||
}
|
||||
if (Strings.isNullOrEmpty(internalVersion))
|
||||
{
|
||||
FMLLog.log.warn("Mod {} is missing the required element 'version' and no fallback can be found. Substituting '1.0'.", getModId());
|
||||
modLog.warn("Mod {} is missing the required element 'version' and no fallback can be found. Substituting '1.0'.", getModId());
|
||||
modMetadata.version = internalVersion = "1.0";
|
||||
}
|
||||
|
||||
|
@ -269,7 +291,7 @@ public class FMLModContainer implements ModContainer
|
|||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
FMLLog.log.debug("Specified json URL for mod '{}' is invalid: {}", getModId(), jsonURL);
|
||||
modLog.debug("Specified json URL invalid: {}", jsonURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +301,7 @@ public class FMLModContainer implements ModContainer
|
|||
{
|
||||
try
|
||||
{
|
||||
FMLLog.log.debug("Attempting to load the file version.properties from {} to locate a version number for mod {}", getSource().getName(), getModId());
|
||||
modLog.debug("Attempting to load the file version.properties from {} to locate a version number for {}", getSource().getName(), getModId());
|
||||
Properties version = null;
|
||||
if (getSource().isFile())
|
||||
{
|
||||
|
@ -316,7 +338,7 @@ public class FMLModContainer implements ModContainer
|
|||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
FMLLog.log.trace("Failed to find a usable version.properties file for mod {}", getModId());
|
||||
modLog.trace("Failed to find a usable version.properties file");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -368,7 +390,7 @@ public class FMLModContainer implements ModContainer
|
|||
{
|
||||
if (this.enabled)
|
||||
{
|
||||
FMLLog.log.debug("Enabling mod {}", getModId());
|
||||
modLog.debug("Enabling mod {}", getModId());
|
||||
this.eventBus = bus;
|
||||
this.controller = controller;
|
||||
eventBus.register(this);
|
||||
|
@ -381,7 +403,8 @@ public class FMLModContainer implements ModContainer
|
|||
}
|
||||
|
||||
@Nullable
|
||||
private Method gatherAnnotations(Class<?> clazz)
|
||||
@SuppressWarnings("unchecked")
|
||||
private Method gatherAnnotations(Class<?> clazz) throws Exception
|
||||
{
|
||||
Method factoryMethod = null;
|
||||
for (Method m : clazz.getDeclaredMethods())
|
||||
|
@ -393,13 +416,11 @@ public class FMLModContainer implements ModContainer
|
|||
if (m.getParameterTypes().length == 1 && FMLEvent.class.isAssignableFrom(m.getParameterTypes()[0]))
|
||||
{
|
||||
m.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends FMLEvent> parameterType = (Class<? extends FMLEvent>) m.getParameterTypes()[0];
|
||||
eventMethods.put(parameterType, m);
|
||||
eventMethods.put((Class<? extends FMLEvent>)m.getParameterTypes()[0], m);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.error("The mod {} appears to have an invalid event annotation {}. This annotation can only apply to methods with recognized event arguments - it will not be called", getModId(), a.annotationType().getSimpleName());
|
||||
modLog.error("The mod {} appears to have an invalid event annotation {}. This annotation can only apply to methods with recognized event arguments - it will not be called", getModId(), a.annotationType().getSimpleName());
|
||||
}
|
||||
}
|
||||
else if (a.annotationType().equals(Mod.InstanceFactory.class))
|
||||
|
@ -411,11 +432,11 @@ public class FMLModContainer implements ModContainer
|
|||
}
|
||||
else if (!(Modifier.isStatic(m.getModifiers()) && m.getParameterTypes().length == 0))
|
||||
{
|
||||
FMLLog.log.error("The InstanceFactory annotation can only apply to a static method, taking zero arguments - it will be ignored on {}({}) for mod {}", m.getName(), Arrays.asList(m.getParameterTypes()), getModId());
|
||||
modLog.error("The InstanceFactory annotation can only apply to a static method, taking zero arguments - it will be ignored on {}({})", m.getName(), Arrays.asList(m.getParameterTypes()));
|
||||
}
|
||||
else if (factoryMethod != null)
|
||||
{
|
||||
FMLLog.log.error("The InstanceFactory annotation can only be used once, the application to {}({}) will be ignored for mod {}", m.getName(), Arrays.asList(m.getParameterTypes()), getModId());
|
||||
modLog.error("The InstanceFactory annotation can only be used once, the application to {}({}) will be ignored", m.getName(), Arrays.asList(m.getParameterTypes()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +444,7 @@ public class FMLModContainer implements ModContainer
|
|||
return factoryMethod;
|
||||
}
|
||||
|
||||
private void processFieldAnnotations(ASMDataTable asmDataTable) throws IllegalAccessException
|
||||
private void processFieldAnnotations(ASMDataTable asmDataTable) throws Exception
|
||||
{
|
||||
SetMultimap<String, ASMData> annotations = asmDataTable.getAnnotationsFor(this);
|
||||
|
||||
|
@ -482,7 +503,7 @@ public class FMLModContainer implements ModContainer
|
|||
}
|
||||
catch (ReflectiveOperationException e)
|
||||
{
|
||||
FMLLog.log.warn("Attempting to load @{} in class {} for {} and failing", annotationName, targets.getClassName(), mc.getModId(), e);
|
||||
modLog.warn("Attempting to load @{} in class {} for {} and failing", annotationName, targets.getClassName(), mc.getModId(), e);
|
||||
}
|
||||
}
|
||||
if (f != null)
|
||||
|
@ -493,7 +514,7 @@ public class FMLModContainer implements ModContainer
|
|||
target = modInstance;
|
||||
if (!modInstance.getClass().equals(clz))
|
||||
{
|
||||
FMLLog.log.warn("Unable to inject @{} in non-static field {}.{} for {} as it is NOT the primary mod instance", annotationName, targets.getClassName(), targets.getObjectName(), mc.getModId());
|
||||
modLog.warn("Unable to inject @{} in non-static field {}.{} for {} as it is NOT the primary mod instance", annotationName, targets.getClassName(), targets.getObjectName(), mc.getModId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -505,108 +526,85 @@ public class FMLModContainer implements ModContainer
|
|||
@Subscribe
|
||||
public void constructMod(FMLConstructionEvent event)
|
||||
{
|
||||
ModClassLoader modClassLoader = event.getModClassLoader();
|
||||
try
|
||||
{
|
||||
ModClassLoader modClassLoader = event.getModClassLoader();
|
||||
modClassLoader.addFile(source);
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
FormattedMessage message = new FormattedMessage("{} Failed to add file to classloader: {}", getModId(), source);
|
||||
throw new LoaderException(message.getFormattedMessage(), e);
|
||||
}
|
||||
modClassLoader.clearNegativeCacheFor(candidate.getClassList());
|
||||
modClassLoader.clearNegativeCacheFor(candidate.getClassList());
|
||||
|
||||
//Only place I could think to add this...
|
||||
MinecraftForge.preloadCrashClasses(event.getASMHarvestedData(), getModId(), candidate.getClassList());
|
||||
//Only place I could think to add this...
|
||||
MinecraftForge.preloadCrashClasses(event.getASMHarvestedData(), getModId(), candidate.getClassList());
|
||||
|
||||
Class<?> clazz;
|
||||
try
|
||||
{
|
||||
clazz = Class.forName(className, true, modClassLoader);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
FormattedMessage message = new FormattedMessage("{} Failed load class: {}", getModId(), className);
|
||||
throw new LoaderException(message.getFormattedMessage(), e);
|
||||
}
|
||||
Class<?> clazz = Class.forName(className, true, modClassLoader);
|
||||
|
||||
Certificate[] certificates = clazz.getProtectionDomain().getCodeSource().getCertificates();
|
||||
ImmutableList<String> certList = CertificateHelper.getFingerprints(certificates);
|
||||
sourceFingerprints = ImmutableSet.copyOf(certList);
|
||||
Certificate[] certificates = clazz.getProtectionDomain().getCodeSource().getCertificates();
|
||||
ImmutableList<String> certList = CertificateHelper.getFingerprints(certificates);
|
||||
sourceFingerprints = ImmutableSet.copyOf(certList);
|
||||
|
||||
String expectedFingerprint = (String)descriptor.get("certificateFingerprint");
|
||||
String expectedFingerprint = (String)descriptor.get("certificateFingerprint");
|
||||
|
||||
fingerprintNotPresent = true;
|
||||
fingerprintNotPresent = true;
|
||||
|
||||
if (expectedFingerprint != null && !expectedFingerprint.isEmpty())
|
||||
{
|
||||
if (!sourceFingerprints.contains(expectedFingerprint))
|
||||
if (expectedFingerprint != null && !expectedFingerprint.isEmpty())
|
||||
{
|
||||
Level warnLevel = source.isDirectory() ? Level.TRACE : Level.ERROR;
|
||||
FMLLog.log.log(warnLevel, "The mod {} is expecting signature {} for source {}, however there is no signature matching that description", getModId(), expectedFingerprint, source.getName());
|
||||
if (!sourceFingerprints.contains(expectedFingerprint))
|
||||
{
|
||||
Level warnLevel = Level.ERROR;
|
||||
if (source.isDirectory())
|
||||
{
|
||||
warnLevel = Level.TRACE;
|
||||
}
|
||||
modLog.log(warnLevel, "The mod {} is expecting signature {} for source {}, however there is no signature matching that description", getModId(), expectedFingerprint, source.getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
certificate = certificates[certList.indexOf(expectedFingerprint)];
|
||||
fingerprintNotPresent = false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> props = (List<Map<String, Object>>)descriptor.get("customProperties");
|
||||
if (props != null)
|
||||
{
|
||||
com.google.common.collect.ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
|
||||
for (Map<String, Object> p : props)
|
||||
{
|
||||
builder.put((String)p.get("k"), (String)p.get("v"));
|
||||
}
|
||||
customModProperties = builder.build();
|
||||
}
|
||||
else
|
||||
{
|
||||
certificate = certificates[certList.indexOf(expectedFingerprint)];
|
||||
fingerprintNotPresent = false;
|
||||
customModProperties = EMPTY_PROPERTIES;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, String>> props = (List<Map<String, String>>)descriptor.get("customProperties");
|
||||
if (props != null)
|
||||
{
|
||||
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
|
||||
for (Map<String, String> p : props)
|
||||
Boolean hasDisableableFlag = (Boolean)descriptor.get("canBeDeactivated");
|
||||
boolean hasReverseDepends = !event.getReverseDependencies().get(getModId()).isEmpty();
|
||||
if (hasDisableableFlag != null && hasDisableableFlag)
|
||||
{
|
||||
builder.put(p.get("k"), p.get("v"));
|
||||
disableability = hasReverseDepends ? Disableable.DEPENDENCIES : Disableable.YES;
|
||||
}
|
||||
customModProperties = builder.build();
|
||||
}
|
||||
else
|
||||
{
|
||||
customModProperties = EMPTY_PROPERTIES;
|
||||
}
|
||||
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());
|
||||
if (fingerprintNotPresent)
|
||||
{
|
||||
eventBus.post(new FMLFingerprintViolationEvent(source.isDirectory(), source, ImmutableSet.copyOf(this.sourceFingerprints), expectedFingerprint));
|
||||
}
|
||||
ProxyInjector.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide(), getLanguageAdapter());
|
||||
AutomaticEventSubscriber.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide());
|
||||
ConfigManager.sync(this.getModId(), Config.Type.INSTANCE);
|
||||
|
||||
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);
|
||||
ILanguageAdapter languageAdapter = getLanguageAdapter();
|
||||
try
|
||||
{
|
||||
modInstance = languageAdapter.getNewInstance(this, clazz, modClassLoader, factoryMethod);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FormattedMessage message = new FormattedMessage("{} Failed to load new mod instance.", getModId());
|
||||
throw new LoaderException(message.getFormattedMessage(), e);
|
||||
}
|
||||
NetworkRegistry.INSTANCE.register(this, clazz, (String)(descriptor.getOrDefault("acceptableRemoteVersions", null)), event.getASMHarvestedData());
|
||||
if (fingerprintNotPresent)
|
||||
{
|
||||
eventBus.post(new FMLFingerprintViolationEvent(source.isDirectory(), source, ImmutableSet.copyOf(this.sourceFingerprints), expectedFingerprint));
|
||||
}
|
||||
ProxyInjector.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide(), languageAdapter);
|
||||
AutomaticEventSubscriber.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide());
|
||||
ConfigManager.sync(this.getModId(), Config.Type.INSTANCE);
|
||||
|
||||
try
|
||||
{
|
||||
processFieldAnnotations(event.getASMHarvestedData());
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
catch (Throwable e)
|
||||
{
|
||||
FormattedMessage message = new FormattedMessage("{} Failed to process field annotations.", getModId());
|
||||
throw new LoaderException(message.getFormattedMessage(), e);
|
||||
controller.errorOccurred(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -757,19 +757,6 @@ public class Loader
|
|||
|
||||
public ICrashCallable getCallableCrashInformation()
|
||||
{
|
||||
return new ICrashCallable() {
|
||||
@Override
|
||||
public String call() throws Exception
|
||||
{
|
||||
return getCrashInformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
return "FML";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public List<ModContainer> getActiveModList()
|
||||
|
|
|
@ -61,42 +61,6 @@ public @interface Mod
|
|||
* By default, you will have a resource domain that matches the modid. All these uses require that constraints are imposed on the format of the modid.
|
||||
*/
|
||||
String modid();
|
||||
|
||||
/**
|
||||
* An optional GUI factory for this mod. This is the name of a class implementing {@link IModGuiFactory} that will be instantiated
|
||||
* on the client side, and will have certain configuration/options guis requested from it.
|
||||
*
|
||||
* @return The name of a class implementing {@link IModGuiFactory}
|
||||
*/
|
||||
String guiFactory() default "";
|
||||
|
||||
/**
|
||||
* A list of custom properties for this mod. Completely up to the mod author if/when they
|
||||
* want to put anything in here.
|
||||
* @return an optional list of custom properties
|
||||
*/
|
||||
CustomProperty[] customProperties() default {};
|
||||
|
||||
/**
|
||||
* A custom key => value property pair for use with {@link Mod#customProperties()}
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({})
|
||||
@interface CustomProperty
|
||||
{
|
||||
/**
|
||||
* A key. Should be unique.
|
||||
* @return A key
|
||||
*/
|
||||
String k();
|
||||
/**
|
||||
* A value. Can be anything.
|
||||
* @return A value
|
||||
*/
|
||||
String v();
|
||||
}
|
||||
/**
|
||||
* Marks the associated method as handling an FML lifecycle event.
|
||||
* The method must have a single parameter, one of the following types. This annotation
|
||||
|
|
|
@ -51,11 +51,13 @@ public interface ModContainer
|
|||
{
|
||||
public static enum Disableable {
|
||||
YES, RESTART, NEVER, DEPENDENCIES;
|
||||
|
||||
}
|
||||
/**
|
||||
* The globally unique modid for this mod
|
||||
*/
|
||||
String getModId();
|
||||
String getPrefix();
|
||||
|
||||
/**
|
||||
* A human readable name
|
||||
|
|
|
@ -24,6 +24,16 @@ import java.util.List;
|
|||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import net.minecraftforge.api.Side;
|
||||
import net.minecraftforge.fml.SidedExecutor;
|
||||
import net.minecraftforge.fml.client.SplashProgress;
|
||||
import org.apache.logging.log4j.message.MessageFormatMessage;
|
||||
import org.apache.logging.log4j.message.StringFormattedMessage;
|
||||
import org.lwjgl.LWJGLUtil;
|
||||
import org.lwjgl.opengl.Display;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SPLASH;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
/**
|
||||
* Not a fully fleshed out API, may change in future MC versions.
|
||||
|
@ -52,7 +62,7 @@ public class ProgressManager
|
|||
{
|
||||
bar.timeEachStep();
|
||||
}
|
||||
FMLCommonHandler.instance().processWindowMessages();
|
||||
SidedExecutor.runOn(Side.CLIENT, ()->SplashProgress::processMessages);
|
||||
return bar;
|
||||
}
|
||||
|
||||
|
@ -71,17 +81,13 @@ public class ProgressManager
|
|||
{
|
||||
long newTime = System.nanoTime();
|
||||
if (bar.timeEachStep)
|
||||
{
|
||||
String timeString = String.format("%.3f", ((float) (newTime - bar.lastTime) / 1000000 / 1000));
|
||||
FMLLog.log.debug("Bar Step: {} - {} took {}s", bar.getTitle(), bar.getMessage(), timeString);
|
||||
}
|
||||
String timeString = String.format("%.3f", ((float) (newTime - bar.startTime) / 1000000 / 1000));
|
||||
fmlLog.debug(SPLASH, () -> new MessageFormatMessage("Bar Step: {0} - {1} took {2,number,0.000}ms", bar.getTitle(), bar.getMessage(), (newTime - bar.lastTime) / 1.0e6));
|
||||
if (bar.getSteps() == 1)
|
||||
FMLLog.log.debug("Bar Finished: {} - {} took {}s", bar.getTitle(), bar.getMessage(), timeString);
|
||||
fmlLog.debug(SPLASH, () -> new MessageFormatMessage("Bar Finished: {0} - {1} took {2,number,0.000}ms", bar.getTitle(), bar.getMessage(), (newTime - bar.lastTime) / 1.0e6));
|
||||
else
|
||||
FMLLog.log.debug("Bar Finished: {} took {}s", bar.getTitle(), timeString);
|
||||
fmlLog.debug(SPLASH, () -> new MessageFormatMessage("Bar Finished: {0} took {1,number,0.000}ms", bar.getTitle(), (newTime - bar.lastTime) / 1.0e6));
|
||||
}
|
||||
FMLCommonHandler.instance().processWindowMessages();
|
||||
SidedExecutor.runOn(Side.CLIENT, ()->SplashProgress::processMessages);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -124,7 +130,7 @@ public class ProgressManager
|
|||
if (timeEachStep && step != 0)
|
||||
{
|
||||
long newTime = System.nanoTime();
|
||||
FMLLog.log.debug(String.format("Bar Step: %s - %s took %.3fs", getTitle(), getMessage(), ((float)(newTime - lastTime) / 1000000 / 1000)));
|
||||
fmlLog.debug(SPLASH,new MessageFormatMessage("Bar Step: {0} - {1} took {2,number,0.000}ms", getTitle(), getMessage(), (newTime - lastTime) / 1.0e6));
|
||||
lastTime = newTime;
|
||||
}
|
||||
step++;
|
||||
|
|
|
@ -24,8 +24,11 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import net.minecraftforge.fml.common.DummyModContainer;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.ModAPIManager;
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
import net.minecraftforge.fml.common.toposort.TopologicalSort.DirectedGraph;
|
||||
|
@ -137,7 +140,23 @@ public class ModSorter
|
|||
|
||||
public List<ModContainer> sort()
|
||||
{
|
||||
List<ModContainer> sortedList = TopologicalSort.topologicalSort(modGraph);
|
||||
List<ModContainer> sortedList;
|
||||
try
|
||||
{
|
||||
sortedList = TopologicalSort.topologicalSort(modGraph);
|
||||
}
|
||||
catch (TopologicalSort.TopoSortException tse)
|
||||
{
|
||||
FMLLog.log.fatal("Mod Sorting failed.");
|
||||
FMLLog.log.fatal("Visiting node {}", tse.getNode());
|
||||
FMLLog.log.fatal("Current sorted list : {}", tse.getSortedResult());
|
||||
FMLLog.log.fatal("Visited set for this node : {}", tse.getVisitedNodes());
|
||||
FMLLog.log.fatal("Explored node set : {}", tse.getExpandedNodes());
|
||||
Sets.SetView<?> cycleList = Sets.difference(tse.getVisitedNodes(), tse.getExpandedNodes());
|
||||
FMLLog.log.fatal("Likely cycle is in : {}", cycleList);
|
||||
|
||||
throw new ModSortingException("There was a cycle detected in the input graph, sorting is not possible", tse.getNode(), cycleList);
|
||||
}
|
||||
sortedList.removeAll(Arrays.asList(new ModContainer[] {beforeAll, before, after, afterAll}));
|
||||
return sortedList;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public class ModSortingException extends EnhancedRuntimeException implements IDi
|
|||
public <T> ModSortingException(String string, T node, Set<T> visitedNodes)
|
||||
{
|
||||
super(string);
|
||||
this.sortingExceptionData = new SortingExceptionData<T>(node, visitedNodes);
|
||||
this.sortingExceptionData = new SortingExceptionData<>(node, visitedNodes);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -32,11 +32,6 @@ import java.util.Set;
|
|||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Sets.SetView;
|
||||
|
||||
/**
|
||||
* Topological sort for mod loading
|
||||
*
|
||||
|
@ -48,8 +43,8 @@ public class TopologicalSort
|
|||
{
|
||||
public static class DirectedGraph<T> implements Iterable<T>
|
||||
{
|
||||
private final Map<T, SortedSet<T>> graph = new HashMap<T, SortedSet<T>>();
|
||||
private List<T> orderedNodes = new ArrayList<T>();
|
||||
private final Map<T, SortedSet<T>> graph = new HashMap<>();
|
||||
private List<T> orderedNodes = new ArrayList<>();
|
||||
|
||||
public boolean addNode(T node)
|
||||
{
|
||||
|
@ -60,7 +55,7 @@ public class TopologicalSort
|
|||
}
|
||||
|
||||
orderedNodes.add(node);
|
||||
graph.put(node, new TreeSet<T>(Comparator.comparingInt(o -> orderedNodes.indexOf(o))));
|
||||
graph.put(node, new TreeSet<>(Comparator.comparingInt(o -> orderedNodes.indexOf(o))));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -136,10 +131,10 @@ public class TopologicalSort
|
|||
public static <T> List<T> topologicalSort(DirectedGraph<T> graph)
|
||||
{
|
||||
DirectedGraph<T> rGraph = reverse(graph);
|
||||
List<T> sortedResult = new ArrayList<T>();
|
||||
Set<T> visitedNodes = new HashSet<T>();
|
||||
List<T> sortedResult = new ArrayList<>();
|
||||
Set<T> visitedNodes = new HashSet<>();
|
||||
// A list of "fully explored" nodes. Leftovers in here indicate cycles in the graph
|
||||
Set<T> expandedNodes = new HashSet<T>();
|
||||
Set<T> expandedNodes = new HashSet<>();
|
||||
|
||||
for (T node : rGraph)
|
||||
{
|
||||
|
@ -151,7 +146,7 @@ public class TopologicalSort
|
|||
|
||||
public static <T> DirectedGraph<T> reverse(DirectedGraph<T> graph)
|
||||
{
|
||||
DirectedGraph<T> result = new DirectedGraph<T>();
|
||||
DirectedGraph<T> result = new DirectedGraph<>();
|
||||
|
||||
for (T node : graph)
|
||||
{
|
||||
|
@ -169,7 +164,7 @@ public class TopologicalSort
|
|||
return result;
|
||||
}
|
||||
|
||||
public static <T> void explore(T node, DirectedGraph<T> graph, List<T> sortedResult, Set<T> visitedNodes, Set<T> expandedNodes)
|
||||
private static <T> void explore(T node, DirectedGraph<T> graph, List<T> sortedResult, Set<T> visitedNodes, Set<T> expandedNodes)
|
||||
{
|
||||
// Have we been here before?
|
||||
if (visitedNodes.contains(node))
|
||||
|
@ -181,14 +176,7 @@ public class TopologicalSort
|
|||
return;
|
||||
}
|
||||
|
||||
FMLLog.log.fatal("Mod Sorting failed.");
|
||||
FMLLog.log.fatal("Visiting node {}", node);
|
||||
FMLLog.log.fatal("Current sorted list : {}", sortedResult);
|
||||
FMLLog.log.fatal("Visited set for this node : {}", visitedNodes);
|
||||
FMLLog.log.fatal("Explored node set : {}", expandedNodes);
|
||||
SetView<T> cycleList = Sets.difference(visitedNodes, expandedNodes);
|
||||
FMLLog.log.fatal("Likely cycle is in : {}", cycleList);
|
||||
throw new ModSortingException("There was a cycle detected in the input graph, sorting is not possible", node, cycleList);
|
||||
throw new TopoSortException(node, sortedResult, visitedNodes, expandedNodes);
|
||||
}
|
||||
|
||||
// Visit this node
|
||||
|
@ -205,4 +193,39 @@ public class TopologicalSort
|
|||
// And mark ourselves as explored
|
||||
expandedNodes.add(node);
|
||||
}
|
||||
|
||||
static class TopoSortException extends RuntimeException {
|
||||
private final Object node;
|
||||
private final List<?> sortedResult;
|
||||
private final Set<?> visitedNodes;
|
||||
private final Set<?> expandedNodes;
|
||||
|
||||
public TopoSortException(Object node, List<?> sortedResult, Set<?> visitedNodes, Set<?> expandedNodes)
|
||||
{
|
||||
this.node = node;
|
||||
this.sortedResult = sortedResult;
|
||||
this.visitedNodes = visitedNodes;
|
||||
this.expandedNodes = expandedNodes;
|
||||
}
|
||||
|
||||
public Object getNode()
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
public List<?> getSortedResult()
|
||||
{
|
||||
return sortedResult;
|
||||
}
|
||||
|
||||
public Set<?> getVisitedNodes()
|
||||
{
|
||||
return visitedNodes;
|
||||
}
|
||||
|
||||
public Set<?> getExpandedNodes()
|
||||
{
|
||||
return expandedNodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ package net.minecraftforge.fml.common.versioning;
|
|||
*
|
||||
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
|
||||
*/
|
||||
public class InvalidVersionSpecificationException extends Exception
|
||||
public class InvalidVersionSpecificationException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
76
src/main/java/net/minecraftforge/fml/hooks/LanguageHook.java
Normal file
76
src/main/java/net/minecraftforge/fml/hooks/LanguageHook.java
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.hooks;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class LanguageHook
|
||||
{
|
||||
/**
|
||||
* Loads a lang file, first searching for a marker to enable the 'extended' format {escape characters}
|
||||
* If the marker is not found it simply returns and let the vanilla code load things.
|
||||
* The Marker is 'PARSE_ESCAPES' by itself on a line starting with '#' as such:
|
||||
* #PARSE_ESCAPES
|
||||
*
|
||||
* @param table The Map to load each key/value pair into.
|
||||
* @param inputstream Input stream containing the lang file.
|
||||
* @return A new InputStream that vanilla uses to load normal Lang files, Null if this is a 'enhanced' file and loading is done.
|
||||
*/
|
||||
@Nullable
|
||||
public static InputStream loadLanguage(Map<String, String> table, InputStream inputstream) throws IOException
|
||||
{
|
||||
byte[] data = IOUtils.toByteArray(inputstream);
|
||||
|
||||
boolean isEnhanced = false;
|
||||
for (String line : IOUtils.readLines(new ByteArrayInputStream(data), StandardCharsets.UTF_8))
|
||||
{
|
||||
if (!line.isEmpty() && line.charAt(0) == '#')
|
||||
{
|
||||
line = line.substring(1).trim();
|
||||
if (line.equals("PARSE_ESCAPES"))
|
||||
{
|
||||
isEnhanced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEnhanced)
|
||||
return new ByteArrayInputStream(data);
|
||||
|
||||
Properties props = new Properties();
|
||||
props.load(new InputStreamReader(new ByteArrayInputStream(data), StandardCharsets.UTF_8));
|
||||
for (Map.Entry<Object, Object> e : props.entrySet())
|
||||
{
|
||||
table.put((String)e.getKey(), (String)e.getValue());
|
||||
}
|
||||
props.clear();
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -20,6 +20,8 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraftforge.api.Side;
|
||||
|
||||
public abstract class FMLCommonLaunchHandler
|
||||
{
|
||||
|
@ -27,4 +29,11 @@ public abstract class FMLCommonLaunchHandler
|
|||
{
|
||||
// We need to check for deobf and patched jar here and if not, build one.
|
||||
}
|
||||
|
||||
public abstract Side getSidedness();
|
||||
|
||||
protected void beforeStart(ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
FMLLoader.beforeStart(launchClassLoader);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@ package net.minecraftforge.fml.loading;
|
|||
|
||||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraft.client.main.Main;
|
||||
import net.minecraftforge.api.Side;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
|
@ -31,12 +33,12 @@ import java.util.concurrent.Callable;
|
|||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
public class FMLDevLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
public class FMLDevClientLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
{
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "devfml";
|
||||
return "devfmlclient";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,10 +57,13 @@ public class FMLDevLaunchProvider extends FMLCommonLaunchHandler implements ILau
|
|||
}
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ClassLoader launchClassLoader)
|
||||
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
return () -> {
|
||||
Main.main(arguments);
|
||||
fmlLog.debug(CORE, "Launching minecraft in {} with arguments {}", launchClassLoader, arguments);
|
||||
super.beforeStart(launchClassLoader);
|
||||
launchClassLoader.setTargetPackageFilter(cn -> !cn.startsWith("net.minecraftforge.fml.loading."));
|
||||
Class.forName("net.minecraft.client.main.Main", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
@ -68,4 +73,10 @@ public class FMLDevLaunchProvider extends FMLCommonLaunchHandler implements ILau
|
|||
{
|
||||
fmlLog.debug(CORE, "No jar creation necessary. Launch is dev environment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Side getSidedness()
|
||||
{
|
||||
return Side.CLIENT;
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import net.minecraftforge.fml.common.FMLModContainer;
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
|
@ -52,9 +53,9 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModContainer loadMod(ModFile file, ClassLoader modClassLoader)
|
||||
public ModContainer loadMod(final ModInfo info, final ClassLoader modClassLoader)
|
||||
{
|
||||
return null;
|
||||
return new FMLModContainer(info, className, modClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,13 +75,7 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
|||
.peek(ad -> fmlLog.debug(SCAN, "Found @Mod class {} with id {}", ad.getClassType().getClassName(), ad.getAnnotationData().get("modid")))
|
||||
.map(ad -> new FMLModTarget(ad.getClassType().getClassName(), (String)ad.getAnnotationData().get("modid")))
|
||||
.collect(Collectors.toMap(FMLModTarget::getModId, Function.identity()));
|
||||
modTargetMap.forEach((key, value) -> scanResult.getFile().claimLanguage(key, value));
|
||||
scanResult.addLanguageLoader(modTargetMap);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModContainer> buildModContainers(List<ModInfo> modFiles, ClassLoader modClassLoader)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraft.client.main.Main;
|
||||
import net.minecraftforge.api.Side;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.Callable;
|
||||
|
@ -40,10 +42,16 @@ public class FMLLaunchProvider extends FMLCommonLaunchHandler implements ILaunch
|
|||
}
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ClassLoader launchClassLoader)
|
||||
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
return () -> {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Side getSidedness()
|
||||
{
|
||||
return Side.CLIENT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,14 @@ package net.minecraftforge.fml.loading;
|
|||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformationService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
|
||||
import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
|
||||
import net.minecraftforge.api.Side;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.fml.common.FMLPaths;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModDiscoverer;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.forgespi.ICoreModProvider;
|
||||
|
@ -51,6 +55,10 @@ public class FMLLoader
|
|||
private static ModDiscoverer modDiscoverer;
|
||||
private static ICoreModProvider coreModProvider;
|
||||
private static LanguageLoadingProvider languageLoadingProvider;
|
||||
private static Side side;
|
||||
private static ModList modList;
|
||||
private static ClassLoader launchClassLoader;
|
||||
private static ModLoader modLoader;
|
||||
|
||||
static void onInitialLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
|
||||
{
|
||||
|
@ -90,29 +98,31 @@ public class FMLLoader
|
|||
languageLoadingProvider = new LanguageLoadingProvider();
|
||||
}
|
||||
|
||||
static void setupLaunchHandler(final IEnvironment environment) throws IncompatibleEnvironmentException
|
||||
static void setupLaunchHandler(final IEnvironment environment)
|
||||
{
|
||||
final String launchTarget = environment.getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).orElse("MISSING");
|
||||
final Optional<ILaunchHandlerService> launchHandler = environment.findLaunchHandler(launchTarget);
|
||||
fmlLog.debug(CORE, "Using {} as launch service", launchTarget);
|
||||
if (!launchHandler.isPresent()) {
|
||||
fmlLog.error(CORE,"Missing LaunchHandler {}, cannot continue", launchTarget);
|
||||
throw new IncompatibleEnvironmentException("Missing launch handler");
|
||||
throw new RuntimeException("Missing launch handler");
|
||||
}
|
||||
|
||||
if (!(launchHandler.get() instanceof FMLCommonLaunchHandler)) {
|
||||
fmlLog.error(CORE, "Incompatible Launch handler found - type {}, cannot continue", launchHandler.get().getClass().getName());
|
||||
throw new IncompatibleEnvironmentException("Incompatible launch handler found");
|
||||
throw new RuntimeException("Incompatible launch handler found");
|
||||
}
|
||||
|
||||
FMLCommonLaunchHandler commonLaunchHandler = (FMLCommonLaunchHandler)launchHandler.get();
|
||||
commonLaunchHandler.setup(environment);
|
||||
side = commonLaunchHandler.getSidedness();
|
||||
}
|
||||
public static void beginModScan()
|
||||
{
|
||||
fmlLog.debug(SCAN,"Scanning for Mod Locators");
|
||||
modDiscoverer = new ModDiscoverer();
|
||||
modDiscoverer.discoverMods();
|
||||
final BackgroundScanHandler backgroundScanHandler = modDiscoverer.discoverMods();
|
||||
modList = backgroundScanHandler.getModList();
|
||||
}
|
||||
|
||||
public static ICoreModProvider getCoreModProvider() {
|
||||
|
@ -147,4 +157,20 @@ public class FMLLoader
|
|||
fmlLog.debug(SCAN, "Adding Access Transformer in {}", modName.getFilePath());
|
||||
accessTransformer.addResource(atPath, modName.getFileName());
|
||||
}
|
||||
|
||||
public static Side getSide()
|
||||
{
|
||||
return side;
|
||||
}
|
||||
|
||||
public static void beforeStart(ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
modLoader = new ModLoader(launchClassLoader.getInstance(), modList);
|
||||
modLoader.classloadModFiles();
|
||||
}
|
||||
|
||||
public static ModLoader getModLoader()
|
||||
{
|
||||
return modLoader;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,8 @@ public class FMLServiceProvider implements ITransformationService
|
|||
FMLPaths.setup(environment);
|
||||
fmlLog.debug(CORE,"Loading configuration");
|
||||
FMLConfig.load();
|
||||
fmlLog.debug(CORE, "Preparing launch handler");
|
||||
FMLLoader.setupLaunchHandler(environment);
|
||||
fmlLog.debug(CORE,"Initiating mod scan");
|
||||
FMLLoader.beginModScan();
|
||||
fmlLog.debug(CORE, "Loading access transformers");
|
||||
|
|
|
@ -40,8 +40,6 @@ public interface IModLanguageProvider
|
|||
Consumer<ScanResult> getFileVisitor();
|
||||
|
||||
interface IModLanguageLoader {
|
||||
ModContainer loadMod(ModFile file, ClassLoader modClassLoader);
|
||||
ModContainer loadMod(ModInfo info, ClassLoader modClassLoader);
|
||||
}
|
||||
|
||||
List<ModContainer> buildModContainers(List<ModInfo> modFiles, ClassLoader modClassLoader);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
||||
import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;
|
||||
import net.minecraftforge.fml.common.versioning.VersionRange;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
@ -36,18 +40,41 @@ public class LanguageLoadingProvider
|
|||
{
|
||||
private final List<IModLanguageProvider> languageProviders = new ArrayList<>();
|
||||
private final ServiceLoader<IModLanguageProvider> serviceLoader;
|
||||
private final Map<String, IModLanguageProvider> languageProviderMap = new HashMap<>();
|
||||
private final Map<String, ModLanguageWrapper> languageProviderMap = new HashMap<>();
|
||||
|
||||
private static class ModLanguageWrapper {
|
||||
private final IModLanguageProvider modLanguageProvider;
|
||||
private final ArtifactVersion version;
|
||||
|
||||
public ModLanguageWrapper(IModLanguageProvider modLanguageProvider, ArtifactVersion version)
|
||||
{
|
||||
this.modLanguageProvider = modLanguageProvider;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public ArtifactVersion getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public IModLanguageProvider getModLanguageProvider()
|
||||
{
|
||||
return modLanguageProvider;
|
||||
}
|
||||
}
|
||||
LanguageLoadingProvider() {
|
||||
serviceLoader = ServiceLoader.load(IModLanguageProvider.class);
|
||||
serviceLoader.forEach(languageProviders::add);
|
||||
|
||||
languageProviders.forEach(lp -> {
|
||||
final Package pkg = lp.getClass().getPackage();
|
||||
fmlLog.debug(CORE, "Found system classpath language provider {}, version {}", lp.name(), pkg.getImplementationVersion());
|
||||
String implementationVersion = pkg.getImplementationVersion();
|
||||
if (implementationVersion == null) {
|
||||
implementationVersion = ForgeVersion.getVersion();
|
||||
}
|
||||
fmlLog.debug(CORE, "Found system classpath language provider {}, version {}", lp.name(), implementationVersion);
|
||||
languageProviderMap.put(lp.name(), new ModLanguageWrapper(lp, new DefaultArtifactVersion(implementationVersion)));
|
||||
});
|
||||
|
||||
languageProviders.forEach(lp->languageProviderMap.put(lp.name(), lp));
|
||||
}
|
||||
|
||||
public void addAdditionalLanguages(List<ModFile> modFiles)
|
||||
|
@ -57,8 +84,15 @@ public class LanguageLoadingProvider
|
|||
serviceLoader.reload();
|
||||
}
|
||||
|
||||
public IModLanguageProvider getLanguage(String name)
|
||||
{
|
||||
return languageProviderMap.get(name);
|
||||
public IModLanguageProvider findLanguage(String modLoader, VersionRange modLoaderVersion) {
|
||||
final ModLanguageWrapper mlw = languageProviderMap.get(modLoader);
|
||||
if (mlw == null) {
|
||||
throw new MissingLanguageException("Missing language "+modLoader);
|
||||
}
|
||||
if (!modLoaderVersion.containsVersion(mlw.getVersion())) {
|
||||
throw new MissingLanguageException("Missing language "+ modLoader + " matching range "+modLoaderVersion + " found "+mlw.getVersion());
|
||||
}
|
||||
|
||||
return mlw.getModLanguageProvider();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.loading;
|
||||
|
||||
public class MissingLanguageException extends RuntimeException
|
||||
{
|
||||
public MissingLanguageException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
77
src/main/java/net/minecraftforge/fml/loading/ModList.java
Normal file
77
src/main/java/net/minecraftforge/fml/loading/ModList.java
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.loading;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Master list of all mods
|
||||
*/
|
||||
public class ModList
|
||||
{
|
||||
private final List<ModFile> modFiles;
|
||||
private final List<ModInfo> sortedList;
|
||||
private BackgroundScanHandler scanner;
|
||||
|
||||
public ModList(final List<ModFile> modFiles, final List<ModInfo> sortedList)
|
||||
{
|
||||
this.modFiles = modFiles;
|
||||
this.sortedList = sortedList;
|
||||
}
|
||||
|
||||
public void addCoreMods()
|
||||
{
|
||||
modFiles.stream().map(ModFile::getCoreMods).flatMap(List::stream).forEach(FMLLoader.getCoreModProvider()::addCoreMod);
|
||||
}
|
||||
|
||||
public void addAccessTransformers()
|
||||
{
|
||||
modFiles.forEach(mod -> mod.getAccessTransformer().ifPresent(path -> FMLLoader.addAccessTransformer(path, mod)));
|
||||
}
|
||||
|
||||
public void addForScanning(BackgroundScanHandler backgroundScanHandler)
|
||||
{
|
||||
this.scanner = backgroundScanHandler;
|
||||
backgroundScanHandler.setModList(this);
|
||||
modFiles.forEach(backgroundScanHandler::submitForScanning);
|
||||
}
|
||||
|
||||
public List<ModFile> getModFiles()
|
||||
{
|
||||
return modFiles;
|
||||
}
|
||||
|
||||
public Path findResource(final String className)
|
||||
{
|
||||
for (final ModFile mf : modFiles) {
|
||||
final Path resource = mf.findResource(className);
|
||||
if (resource != null) return resource;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
54
src/main/java/net/minecraftforge/fml/loading/ModLoader.java
Normal file
54
src/main/java/net/minecraftforge/fml/loading/ModLoader.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.loading;
|
||||
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ModLoader
|
||||
{
|
||||
private final ClassLoader launchClassLoader;
|
||||
private final ModList modList;
|
||||
private final ModLoadingClassLoader modClassLoader;
|
||||
|
||||
public ModLoader(final ClassLoader launchClassLoader, final ModList modList)
|
||||
{
|
||||
this.launchClassLoader = launchClassLoader;
|
||||
this.modList = modList;
|
||||
this.modClassLoader = new ModLoadingClassLoader(this, this.launchClassLoader);
|
||||
}
|
||||
|
||||
public void classloadModFiles()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ModList getModList()
|
||||
{
|
||||
return modList;
|
||||
}
|
||||
|
||||
public void loadMods() {
|
||||
final List<ModContainer> collect = modList.getModFiles().stream().map(mf -> mf.buildMods(this.modClassLoader)).flatMap(Collection::stream).collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.loading;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.SecureClassLoader;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
|
||||
public class ModLoadingClassLoader extends SecureClassLoader
|
||||
{
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
// We use a custom URL format : modjar:modid!/path/in/jarfile
|
||||
URL.setURLStreamHandlerFactory(protocol -> "modjar".equals(protocol) ? new URLStreamHandler() {
|
||||
@Override
|
||||
protected URLConnection openConnection(URL url) throws IOException {
|
||||
return new URLConnection(url) {
|
||||
@Override
|
||||
public void connect()
|
||||
{
|
||||
url.get
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseURL(URL u, String spec, int start, int limit)
|
||||
{
|
||||
|
||||
}
|
||||
} : null);
|
||||
}
|
||||
|
||||
private ModLoader modLoader;
|
||||
|
||||
protected ModLoadingClassLoader(ModLoader modLoader, ClassLoader parent) {
|
||||
super(parent);
|
||||
this.modLoader = modLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getResource(String name)
|
||||
{
|
||||
return super.getResource(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
LogManager.getLogger("FML").debug(LOADING, "Loading class {}", name);
|
||||
final String className = name.replace('.','/').concat(".class");
|
||||
final Path classResource = modLoader.getModList().findResource(className);
|
||||
if (classResource != null) {
|
||||
try {
|
||||
final byte[] bytes = Files.readAllBytes(classResource);
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new ClassNotFoundException("Failed to load class file " + classResource + " for "+ className, e);
|
||||
}
|
||||
}
|
||||
throw new ClassNotFoundException("Failed to find class file "+ className);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URL findResource(String name)
|
||||
{
|
||||
return super.findResource(name);
|
||||
}
|
||||
}
|
112
src/main/java/net/minecraftforge/fml/loading/ModSorter.java
Normal file
112
src/main/java/net/minecraftforge/fml/loading/ModSorter.java
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.loading;
|
||||
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.fml.Java9BackportUtils;
|
||||
import net.minecraftforge.fml.Logging;
|
||||
import net.minecraftforge.fml.common.DuplicateModsFoundException;
|
||||
import net.minecraftforge.fml.common.MissingModsException;
|
||||
import net.minecraftforge.fml.common.toposort.TopologicalSort;
|
||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
|
||||
public class ModSorter
|
||||
{
|
||||
private final List<ModFile> modFiles;
|
||||
private List<ModInfo> sortedList;
|
||||
private Map<String, ModInfo> modIdNameLookup;
|
||||
|
||||
public ModSorter(final List<ModFile> modFiles)
|
||||
{
|
||||
this.modFiles = modFiles;
|
||||
}
|
||||
|
||||
public static ModList sort(List<ModFile> mods)
|
||||
{
|
||||
final ModSorter ms = new ModSorter(mods);
|
||||
ms.buildUniqueList();
|
||||
ms.verifyDependencyVersions();
|
||||
ms.sort();
|
||||
return new ModList(ms.modFiles, ms.sortedList);
|
||||
}
|
||||
|
||||
private void sort() {
|
||||
final TopologicalSort.DirectedGraph<ModInfo> topoGraph = new TopologicalSort.DirectedGraph<>();
|
||||
modFiles.stream().map(ModFile::getModInfos).
|
||||
flatMap(Collection::stream).forEach(topoGraph::addNode);
|
||||
modFiles.stream().map(ModFile::getModInfos).
|
||||
flatMap(Collection::stream).map(ModInfo::getDependencies).flatMap(Collection::stream).forEach(dep->addDependency(topoGraph, dep));
|
||||
}
|
||||
|
||||
private void addDependency(TopologicalSort.DirectedGraph<ModInfo> topoGraph, ModInfo.ModVersion dep)
|
||||
{
|
||||
}
|
||||
|
||||
private void buildUniqueList()
|
||||
{
|
||||
final Stream<ModInfo> modInfos = modFiles.stream().map(ModFile::getModInfos).flatMap(Collection::stream);
|
||||
final Map<String, List<ModInfo>> modIds = modInfos.collect(Collectors.groupingBy(ModInfo::getModId));
|
||||
|
||||
// TODO: make this figure out dupe handling better
|
||||
final List<Map.Entry<String, List<ModInfo>>> dupedMods = modIds.entrySet().stream().filter(e -> e.getValue().size() > 1).collect(Collectors.toList());
|
||||
|
||||
if (!dupedMods.isEmpty()) {
|
||||
throw new DuplicateModsFoundException(null);
|
||||
}
|
||||
|
||||
modIdNameLookup = modIds.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
|
||||
}
|
||||
|
||||
private void verifyDependencyVersions()
|
||||
{
|
||||
final Map<String, ArtifactVersion> modVersions = Stream.concat(modFiles.stream().map(ModFile::getModInfos).
|
||||
flatMap(Collection::stream), ForgeVersion.getModInfos().stream()).collect(Collectors.toMap(ModInfo::getModId, ModInfo::getVersion));
|
||||
final Map<ModInfo, List<ModInfo.ModVersion>> modVersionDependencies = modFiles.stream().
|
||||
map(ModFile::getModInfos).flatMap(Collection::stream).
|
||||
collect(Collectors.groupingBy(Function.identity(), Java9BackportUtils.flatMapping(e -> e.getDependencies().stream(), Collectors.toList())));
|
||||
final Set<ModInfo.ModVersion> mandatoryModVersions = modVersionDependencies.values().stream().flatMap(Collection::stream).
|
||||
filter(mv -> mv.isMandatory() && mv.getSide().isCorrectSide()).collect(Collectors.toSet());
|
||||
LogManager.getLogger("FML").debug(LOADING, "Found {} mandatory requirements", mandatoryModVersions.size());
|
||||
final Set<ModInfo.ModVersion> missingVersions = mandatoryModVersions.stream().filter(mv->this.modVersionMatches(mv, modVersions)).collect(Collectors.toSet());
|
||||
LogManager.getLogger("FML").debug(LOADING, "Found {} mandatory mod requirements missing", missingVersions.size());
|
||||
|
||||
if (!missingVersions.isEmpty()) {
|
||||
throw new MissingModsException(null,null,null);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean modVersionMatches(final ModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
|
||||
{
|
||||
return !modVersions.containsKey(mv.getModId()) || !mv.getVersionRange().containsVersion(modVersions.get(mv.getModId()));
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import net.minecraftforge.fml.loading.ModList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -38,6 +39,7 @@ public class BackgroundScanHandler
|
|||
private final List<ModFile> pendingFiles;
|
||||
private final List<ModFile> scannedFiles;
|
||||
private final List<ModFile> allFiles;
|
||||
private ModList modList;
|
||||
|
||||
public BackgroundScanHandler() {
|
||||
modContentScanner = Executors.newSingleThreadExecutor(r -> {
|
||||
|
@ -84,4 +86,14 @@ public class BackgroundScanHandler
|
|||
public List<ModFile> getAllFiles() {
|
||||
return allFiles;
|
||||
}
|
||||
|
||||
public void setModList(ModList modList)
|
||||
{
|
||||
this.modList = modList;
|
||||
}
|
||||
|
||||
public ModList getModList()
|
||||
{
|
||||
return modList;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
public class InvalidModFileException extends RuntimeException
|
||||
{
|
||||
private final ModFile.ModFileInfo modFileInfo;
|
||||
|
||||
public InvalidModFileException(String message, ModFile.ModFileInfo modFileInfo)
|
||||
{
|
||||
super(message);
|
||||
this.modFileInfo = modFileInfo;
|
||||
}
|
||||
}
|
|
@ -21,13 +21,13 @@ package net.minecraftforge.fml.loading.moddiscovery;
|
|||
|
||||
import cpw.mods.modlauncher.ServiceLoaderStreamUtils;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.LanguageLoadingProvider;
|
||||
import net.minecraftforge.fml.loading.ModList;
|
||||
import net.minecraftforge.fml.loading.ModSorter;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -61,11 +61,19 @@ public class ModDiscoverer {
|
|||
FMLLoader.getLanguageLoadingProvider().addAdditionalLanguages(modFiles.get(ModFile.Type.LANGPROVIDER));
|
||||
BackgroundScanHandler backgroundScanHandler = new BackgroundScanHandler();
|
||||
final List<ModFile> mods = modFiles.get(ModFile.Type.MOD);
|
||||
mods.forEach(ModFile::identifyMods);
|
||||
for (Iterator<ModFile> iterator = mods.iterator(); iterator.hasNext(); )
|
||||
{
|
||||
ModFile mod = iterator.next();
|
||||
if (!mod.identifyMods()) {
|
||||
fmlLog.debug(SCAN, "Removing file {} from further analysis - it is invalid", mod);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
fmlLog.debug(SCAN,"Found {} mod files with {} mods", mods::size, ()->mods.stream().mapToInt(mf -> mf.getModInfos().size()).sum());
|
||||
mods.stream().map(ModFile::getCoreMods).flatMap(List::stream).forEach(FMLLoader.getCoreModProvider()::addCoreMod);
|
||||
mods.forEach(mod -> mod.getAccessTransformer().ifPresent(path -> FMLLoader.addAccessTransformer(path, mod)));
|
||||
mods.forEach(backgroundScanHandler::submitForScanning);
|
||||
final ModList sortedMods = ModSorter.sort(mods);
|
||||
sortedMods.addCoreMods();
|
||||
sortedMods.addAccessTransformers();
|
||||
sortedMods.addForScanning(backgroundScanHandler);
|
||||
return backgroundScanHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,24 @@
|
|||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraftforge.common.config.ConfigCategory;
|
||||
import net.minecraftforge.fml.StringUtils;
|
||||
import net.minecraftforge.fml.common.ModContainer;
|
||||
import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;
|
||||
import net.minecraftforge.fml.common.versioning.VersionRange;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.IModLanguageProvider;
|
||||
import net.minecraftforge.fml.loading.ModLoadingClassLoader;
|
||||
|
||||
import javax.swing.text.html.Option;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -32,6 +45,7 @@ import java.util.concurrent.CompletableFuture;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -48,10 +62,29 @@ public class ModFile
|
|||
DEFAULTMANIFEST.getMainAttributes().putValue("FMLModType", "MOD");
|
||||
}
|
||||
|
||||
private final String jarVersion;
|
||||
private Map<String, Object> fileProperties;
|
||||
private IModLanguageProvider loader;
|
||||
|
||||
public void claimLanguage(String modId, IModLanguageProvider.IModLanguageLoader loader)
|
||||
public void setFileProperties(Map<String, Object> fileProperties)
|
||||
{
|
||||
this.modInfoMap.get(modId).setLoader(loader);
|
||||
this.fileProperties = fileProperties;
|
||||
}
|
||||
|
||||
public IModLanguageProvider getLoader()
|
||||
{
|
||||
return loader;
|
||||
}
|
||||
|
||||
public Path findResource(String className)
|
||||
{
|
||||
return locator.findPath(this, className);
|
||||
}
|
||||
|
||||
public List<ModContainer> buildMods(ModLoadingClassLoader modClassLoader)
|
||||
{
|
||||
return getScanResult().getTargets().entrySet().stream().
|
||||
map(e->e.getValue().loadMod(this.modInfoMap.get(e.getKey()), modClassLoader)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
@ -60,9 +93,9 @@ public class ModFile
|
|||
private final Path filePath;
|
||||
private final Type modFileType;
|
||||
private final Manifest manifest;
|
||||
private List<ModInfo> modInfos;
|
||||
private Map<String, ModInfo> modInfoMap;
|
||||
private final IModLocator locator;
|
||||
private ModFileInfo modFileInfo;
|
||||
private Map<String, ModInfo> modInfoMap;
|
||||
private ScanResult fileScanResult;
|
||||
private CompletableFuture<ScanResult> futureScanResult;
|
||||
private List<CoreModFile> coreMods;
|
||||
|
@ -78,8 +111,12 @@ public class ModFile
|
|||
else fmlLog.debug(SCAN,"Mod file {} is missing a manifest", file);
|
||||
final Optional<String> value = Optional.ofNullable(manifest.getMainAttributes().getValue(TYPE));
|
||||
modFileType = Type.valueOf(value.orElse("MOD"));
|
||||
jarVersion = Optional.ofNullable(manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION)).orElse("NONE");
|
||||
}
|
||||
|
||||
public Supplier<Map<String,Object>> getSubstitutionMap() {
|
||||
return () -> ImmutableMap.<String,Object>builder().put("jarVersion", jarVersion).putAll(fileProperties).build();
|
||||
}
|
||||
public Type getType() {
|
||||
return modFileType;
|
||||
}
|
||||
|
@ -89,19 +126,22 @@ public class ModFile
|
|||
}
|
||||
|
||||
public List<ModInfo> getModInfos() {
|
||||
return modInfos;
|
||||
return modFileInfo.getMods();
|
||||
}
|
||||
|
||||
public Optional<Path> getAccessTransformer() {
|
||||
return Optional.ofNullable(Files.exists(accessTransformer) ? accessTransformer : null);
|
||||
}
|
||||
public void identifyMods() {
|
||||
this.modInfos = ModFileParser.readModList(this);
|
||||
this.modInfos.forEach(mi-> fmlLog.debug(LOADING,"Found mod {} for language {}", mi.getModId(), mi.getModLoader()));
|
||||
this.modInfoMap = this.modInfos.stream().collect(Collectors.toMap(ModInfo::getModId, Function.identity()));
|
||||
public boolean identifyMods() {
|
||||
this.modFileInfo = ModFileParser.readModList(this);
|
||||
if (this.modFileInfo == null) return false;
|
||||
fmlLog.debug(LOADING,"Loading mod file {} with language {}", this.getFilePath(), this.modFileInfo.modLoader);
|
||||
this.modInfoMap = this.getModInfos().stream().collect(Collectors.toMap(ModInfo::getModId, Function.identity()));
|
||||
this.coreMods = ModFileParser.getCoreMods(this);
|
||||
this.coreMods.forEach(mi-> fmlLog.debug(LOADING,"Found coremod {}", mi.getPath()));
|
||||
this.accessTransformer = locator.findPath(this, "META-INF", "accesstransformer.cfg");
|
||||
this.loader = FMLLoader.getLanguageLoadingProvider().findLanguage(this.modFileInfo.modLoader, this.modFileInfo.modLoaderVersion);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -152,4 +192,54 @@ public class ModFile
|
|||
public IModLocator getLocator() {
|
||||
return locator;
|
||||
}
|
||||
|
||||
public ModFileInfo getModFileInfo() {
|
||||
return modFileInfo;
|
||||
}
|
||||
public static class ModFileInfo {
|
||||
private final UnmodifiableConfig config;
|
||||
private final ModFile modFile;
|
||||
private final URL updateJSONURL;
|
||||
private final URL issueURL;
|
||||
private final String modLoader;
|
||||
private final VersionRange modLoaderVersion;
|
||||
private final List<ModInfo> mods;
|
||||
private final Map<String,Object> properties;
|
||||
|
||||
public ModFileInfo(final ModFile modFile, final UnmodifiableConfig config)
|
||||
{
|
||||
this.modFile = modFile;
|
||||
this.config = config;
|
||||
this.modLoader = config.<String>getOptional("modLoader").
|
||||
orElseThrow(()->new InvalidModFileException("Missing ModLoader in file", this));
|
||||
this.modLoaderVersion = config.<String>getOptional("loaderVersion").
|
||||
map(VersionRange::createFromVersionSpec).
|
||||
orElseThrow(()->new InvalidModFileException("Missing ModLoader version in file", this));
|
||||
this.properties = config.<UnmodifiableConfig>getOptional("properties").
|
||||
map(UnmodifiableConfig::valueMap).orElse(Collections.emptyMap());
|
||||
this.modFile.setFileProperties(this.properties);
|
||||
final ArrayList<UnmodifiableConfig> modConfigs = config.getOrElse("mods", ArrayList::new);
|
||||
if (modConfigs.isEmpty()) {
|
||||
throw new InvalidModFileException("Missing mods list", this);
|
||||
}
|
||||
this.mods = modConfigs.stream().map(mi-> new ModInfo(this, mi)).collect(Collectors.toList());
|
||||
this.updateJSONURL = config.<String>getOptional("updateJSONURL").map(StringUtils::toURL).orElse(null);
|
||||
this.issueURL = config.<String>getOptional("issueTrackerURL").map(StringUtils::toURL).orElse(null);
|
||||
}
|
||||
|
||||
public List<ModInfo> getMods()
|
||||
{
|
||||
return mods;
|
||||
}
|
||||
|
||||
public ModFile getFile()
|
||||
{
|
||||
return this.modFile;
|
||||
}
|
||||
|
||||
public UnmodifiableConfig getConfig()
|
||||
{
|
||||
return this.config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,10 @@
|
|||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.electronwill.nightconfig.core.path.PathConfig;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
||||
import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;
|
||||
import org.apache.commons.lang3.text.StrSubstitutor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
@ -35,26 +32,27 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
public class ModFileParser {
|
||||
protected static List<ModInfo> readModList(final ModFile modFile) {
|
||||
public static ModFile.ModFileInfo readModList(final ModFile modFile) {
|
||||
fmlLog.debug(LOADING,"Parsing mod file candidate {}", modFile.getFilePath());
|
||||
try {
|
||||
final Path modsjson = modFile.getLocator().findPath(modFile, "META-INF", "mods.json");
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
gsonBuilder.registerTypeAdapter(ModInfo.class, (InstanceCreator<ModInfo>)ic -> new ModInfo(modFile, null, null, null, null, null, null, null));
|
||||
gsonBuilder.registerTypeAdapter(ArtifactVersion.class, (JsonDeserializer<ArtifactVersion>) (element, type, context) -> new DefaultArtifactVersion(element.getAsString()));
|
||||
Gson gson = gsonBuilder.create();
|
||||
final ModInfo[] modInfos = gson.fromJson(Files.newBufferedReader(modsjson), ModInfo[].class);
|
||||
return Stream.of(modInfos).collect(Collectors.toList());
|
||||
} catch (IOException e) {
|
||||
fmlLog.debug(LOADING,"Ignoring invalid JAR file {}", modFile.getFilePath());
|
||||
return Collections.emptyList();
|
||||
final Path modsjson = modFile.getLocator().findPath(modFile, "META-INF", "mods.toml");
|
||||
if (!Files.exists(modsjson)) {
|
||||
fmlLog.warn(LOADING, "Mod file {} is missing mods.toml file", modFile);
|
||||
return null;
|
||||
}
|
||||
return loadModFile(modFile, modsjson);
|
||||
}
|
||||
|
||||
public static ModFile.ModFileInfo loadModFile(final ModFile file, final Path modsjson)
|
||||
{
|
||||
final PathConfig pathConfig = PathConfig.builder(modsjson).build();
|
||||
pathConfig.load();
|
||||
pathConfig.close();
|
||||
return new ModFile.ModFileInfo(file, pathConfig);
|
||||
}
|
||||
|
||||
protected static List<CoreModFile> getCoreMods(final ModFile modFile) {
|
||||
|
|
|
@ -19,40 +19,60 @@
|
|||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import net.minecraftforge.fml.FMLEnvironment;
|
||||
import net.minecraftforge.fml.StringSubstitutor;
|
||||
import net.minecraftforge.fml.StringUtils;
|
||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
||||
import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;
|
||||
import net.minecraftforge.fml.common.versioning.VersionRange;
|
||||
import net.minecraftforge.fml.loading.IModLanguageProvider;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ModInfo {
|
||||
private final ModFile owningFile;
|
||||
private static final DefaultArtifactVersion DEFAULT_VERSION = new DefaultArtifactVersion("1");
|
||||
public static final VersionRange UNBOUNDED = VersionRange.createFromVersionSpec("");
|
||||
private final ModFile.ModFileInfo owningFile;
|
||||
private final String modId;
|
||||
private final ArtifactVersion version;
|
||||
private final String displayName;
|
||||
private final String description;
|
||||
private final URL updateJSONURL;
|
||||
private final String modLoader;
|
||||
private final List<ModInfo.ModVersion> dependencies;
|
||||
private IModLanguageProvider.IModLanguageLoader loader;
|
||||
private final Map<String,Object> properties;
|
||||
private final UnmodifiableConfig modConfig;
|
||||
|
||||
public ModInfo(final ModFile owningFile, final String modLoader, final String modId, final String displayName, final ArtifactVersion version, final String description, final URL updateJSONURL, final List<ModInfo.ModVersion> dependencies) {
|
||||
public ModInfo(final ModFile.ModFileInfo owningFile, final UnmodifiableConfig modConfig)
|
||||
{
|
||||
this.owningFile = owningFile;
|
||||
this.modLoader = modLoader;
|
||||
this.modId = modId;
|
||||
this.displayName = displayName;
|
||||
this.version = version;
|
||||
this.description = description;
|
||||
this.updateJSONURL = updateJSONURL;
|
||||
this.dependencies = dependencies;
|
||||
this.modConfig = modConfig;
|
||||
this.modId = modConfig.<String>getOptional("modId").orElseThrow(() -> new InvalidModFileException("Missing modId entry", owningFile));
|
||||
this.version = modConfig.<String>getOptional("version").
|
||||
map(s->StringSubstitutor.replace(s, owningFile != null ? owningFile.getFile() : null )).
|
||||
map(DefaultArtifactVersion::new).orElse(DEFAULT_VERSION);
|
||||
this.displayName = modConfig.<String>getOptional("displayName").orElse(null);
|
||||
this.description = modConfig.get("description");
|
||||
if (owningFile != null) {
|
||||
this.dependencies = owningFile.getConfig().<List<UnmodifiableConfig>>getOptional(Arrays.asList("dependencies", this.modId)).
|
||||
orElse(Collections.emptyList()).stream().map(dep -> new ModVersion(this, dep)).collect(Collectors.toList());
|
||||
this.properties = owningFile.getConfig().<UnmodifiableConfig>getOptional(Arrays.asList("modproperties", this.modId)).
|
||||
map(UnmodifiableConfig::valueMap).orElse(Collections.emptyMap());
|
||||
} else {
|
||||
this.dependencies = Collections.emptyList();
|
||||
this.properties = Collections.emptyMap();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ModFile getOwningFile() {
|
||||
return owningFile;
|
||||
}
|
||||
|
||||
public String getModLoader() {
|
||||
return modLoader;
|
||||
return owningFile.getFile();
|
||||
}
|
||||
|
||||
public String getModId() {
|
||||
|
@ -63,32 +83,72 @@ public class ModInfo {
|
|||
return version;
|
||||
}
|
||||
|
||||
public void setLoader(IModLanguageProvider.IModLanguageLoader loader)
|
||||
{
|
||||
this.loader = loader;
|
||||
public List<ModInfo.ModVersion> getDependencies() {
|
||||
return this.dependencies;
|
||||
}
|
||||
|
||||
public enum Ordering {
|
||||
BEFORE, AFTER, NONE;
|
||||
BEFORE, AFTER, NONE
|
||||
}
|
||||
|
||||
public enum DependencySide {
|
||||
CLIENT, SERVER, BOTH;
|
||||
|
||||
public boolean isCorrectSide()
|
||||
{
|
||||
return this == BOTH || FMLEnvironment.side.name().equals(this.name());
|
||||
}
|
||||
}
|
||||
|
||||
public static class ModVersion {
|
||||
private ModInfo owner;
|
||||
private final String modId;
|
||||
private final ArtifactVersion version;
|
||||
private final VersionRange versionRange;
|
||||
private final boolean mandatory;
|
||||
private final Ordering ordering;
|
||||
private final DependencySide side;
|
||||
|
||||
public ModVersion(final String modId, final ArtifactVersion version, final boolean mandatory, final Ordering ordering, final DependencySide side) {
|
||||
this.modId = modId;
|
||||
this.version = version;
|
||||
this.mandatory = mandatory;
|
||||
this.ordering = ordering;
|
||||
this.side = side;
|
||||
ModVersion(final ModInfo owner, final UnmodifiableConfig config) {
|
||||
this.owner = owner;
|
||||
this.modId = config.get("modId");
|
||||
this.versionRange = config.getOptional("versionRange").map(String.class::cast).
|
||||
map(VersionRange::createFromVersionSpec).orElse(UNBOUNDED);
|
||||
this.mandatory = config.get("mandatory");
|
||||
this.ordering = config.getOptional("ordering").map(String.class::cast).
|
||||
map(Ordering::valueOf).orElse(Ordering.NONE);
|
||||
this.side = config.getOptional("side").map(String.class::cast).
|
||||
map(DependencySide::valueOf).orElse(DependencySide.BOTH);
|
||||
}
|
||||
|
||||
|
||||
public String getModId()
|
||||
{
|
||||
return modId;
|
||||
}
|
||||
|
||||
public VersionRange getVersionRange()
|
||||
{
|
||||
return versionRange;
|
||||
}
|
||||
|
||||
public boolean isMandatory()
|
||||
{
|
||||
return mandatory;
|
||||
}
|
||||
|
||||
public Ordering getOrdering()
|
||||
{
|
||||
return ordering;
|
||||
}
|
||||
|
||||
public DependencySide getSide()
|
||||
{
|
||||
return side;
|
||||
}
|
||||
|
||||
public void setOwner(final ModInfo owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.minecraftforge.fml.loading.FMLJavaModLanguageProvider;
|
||||
import net.minecraftforge.fml.loading.IModLanguageProvider;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -31,6 +34,7 @@ public class ScanResult {
|
|||
private final ModFile file;
|
||||
private final List<ScanResult.AnnotationData> annotations = new ArrayList<>();
|
||||
private final List<ScanResult.ClassData> classes = new ArrayList<>();
|
||||
private Map<String,? extends IModLanguageProvider.IModLanguageLoader> modTargets;
|
||||
|
||||
public ScanResult(final ModFile file) {
|
||||
this.file = file;
|
||||
|
@ -52,6 +56,17 @@ public class ScanResult {
|
|||
return annotations;
|
||||
}
|
||||
|
||||
public void addLanguageLoader(Map<String,? extends IModLanguageProvider.IModLanguageLoader> modTargetMap)
|
||||
{
|
||||
modTargets = modTargetMap;
|
||||
}
|
||||
|
||||
public Map<String, ? extends IModLanguageProvider.IModLanguageLoader> getTargets()
|
||||
{
|
||||
return modTargets;
|
||||
}
|
||||
|
||||
|
||||
public static class ClassData {
|
||||
private final Type clazz;
|
||||
private final Type parent;
|
||||
|
|
|
@ -45,9 +45,9 @@ public class Scanner {
|
|||
public ScanResult scan() {
|
||||
ScanResult result = new ScanResult(fileToScan);
|
||||
fileToScan.scanFile(p -> fileVisitor(p, result));
|
||||
final Set<IModLanguageProvider> modLoaders = fileToScan.getModInfos().stream().map(ModInfo::getModLoader).map(FMLLoader.getLanguageLoadingProvider()::getLanguage).collect(Collectors.toSet());
|
||||
modLoaders.stream().peek(ml-> fmlLog.debug(SCAN, "Scanning {} with language loader {}", fileToScan.getFilePath(), ml.name()))
|
||||
.map(IModLanguageProvider::getFileVisitor).forEach(c->c.accept(result));
|
||||
final IModLanguageProvider loader = fileToScan.getLoader();
|
||||
fmlLog.debug(SCAN, "Scanning {} with language loader {}", fileToScan.getFilePath(), loader.name());
|
||||
loader.getFileVisitor().accept(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2018.
|
||||
*
|
||||
* 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 version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* 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 net.minecraftforge.logging;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.BlockModelShapes;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.registry.IRegistry;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.registry.ForgeRegistries;
|
||||
import org.apache.logging.log4j.message.SimpleMessage;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static net.minecraftforge.client.model.ModelLoader.getInventoryVariant;
|
||||
|
||||
public class ModelLoaderErrorMessage extends SimpleMessage
|
||||
{
|
||||
private final ModelResourceLocation resourceLocation;
|
||||
private final Exception exception;
|
||||
private final IRegistry<ModelResourceLocation, IBakedModel> modelRegistry;
|
||||
|
||||
private static Multimap<ModelResourceLocation, IBlockState> reverseBlockMap = HashMultimap.create();
|
||||
private static Multimap<ModelResourceLocation, String> reverseItemMap = HashMultimap.create();
|
||||
|
||||
private static void buildLookups(final BlockModelShapes blockModelShapes, Function<Item,Iterable<String>> itemNameLookup) {
|
||||
if (!reverseBlockMap.isEmpty()) return;
|
||||
for(Map.Entry<IBlockState, ModelResourceLocation> entry : blockModelShapes.getBlockStateMapper().putAllStateModelLocations().entrySet())
|
||||
{
|
||||
reverseBlockMap.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
ForgeRegistries.ITEMS.forEach(item ->
|
||||
{
|
||||
for(String s : itemNameLookup.apply(item))
|
||||
{
|
||||
ModelResourceLocation memory = getInventoryVariant(s);
|
||||
reverseItemMap.put(memory, item.getRegistryName().toString());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public ModelLoaderErrorMessage(ModelResourceLocation resourceLocation, Exception exception, IRegistry<ModelResourceLocation, IBakedModel> modelRegistry, BlockModelShapes blockModelShapes, Function<Item, Iterable<String>> itemNameLookup)
|
||||
{
|
||||
// if we're logging these error messages, this will get built for reference
|
||||
buildLookups(blockModelShapes, itemNameLookup);
|
||||
this.resourceLocation = resourceLocation;
|
||||
this.exception = exception;
|
||||
this.modelRegistry = modelRegistry;
|
||||
}
|
||||
|
||||
private void stuffs() {
|
||||
String domain = resourceLocation.getResourceDomain();
|
||||
String errorMsg = "Exception loading model for variant " + resourceLocation;
|
||||
Collection<IBlockState> blocks = reverseBlockMap.get(resourceLocation);
|
||||
if(!blocks.isEmpty())
|
||||
{
|
||||
if(blocks.size() == 1)
|
||||
{
|
||||
errorMsg += " for blockstate \"" + blocks.iterator().next() + "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg += " for blockstates [\"" + Joiner.on("\", \"").join(blocks) + "\"]";
|
||||
}
|
||||
}
|
||||
Collection<String> items = reverseItemMap.get(resourceLocation);
|
||||
if(!items.isEmpty())
|
||||
{
|
||||
if(!blocks.isEmpty()) errorMsg += " and";
|
||||
if(items.size() == 1)
|
||||
{
|
||||
errorMsg += " for item \"" + items.iterator().next() + "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg += " for items [\"" + Joiner.on("\", \"").join(items) + "\"]";
|
||||
}
|
||||
}
|
||||
if(exception instanceof ModelLoader.ItemLoadingException)
|
||||
{
|
||||
ModelLoader.ItemLoadingException ex = (ModelLoader.ItemLoadingException)exception;
|
||||
// FMLLog.log.error("{}, normal location exception: ", errorMsg, ex.normalException);
|
||||
// FMLLog.log.error("{}, blockstate location exception: ", errorMsg, ex.blockstateException);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FMLLog.log.error(errorMsg, entry.getValue());
|
||||
}
|
||||
// ResourceLocation blockstateLocation = new ResourceLocation(resourceLocation.getResourceDomain(), resourceLocation.getResourcePath());
|
||||
// if(loadingExceptions.containsKey(blockstateLocation) && !printedBlockStateErrors.contains(blockstateLocation))
|
||||
// {
|
||||
// FMLLog.log.error("Exception loading blockstate for the variant {}: ", location, loadingExceptions.get(blockstateLocation));
|
||||
// printedBlockStateErrors.add(blockstateLocation);
|
||||
// }
|
||||
}
|
||||
@Override
|
||||
public void formatTo(StringBuilder buffer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ import java.util.Map.Entry;
|
|||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraftforge.fml.ModThreadContext;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import java.util.Set;
|
||||
|
@ -277,8 +278,7 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
|
|||
|
||||
int add(int id, V value)
|
||||
{
|
||||
ModContainer mc = Loader.instance().activeModContainer();
|
||||
String owner = mc == null || (mc instanceof InjectedModContainer && ((InjectedModContainer)mc).wrappedContainer instanceof FMLContainer) ? null : mc.getModId().toLowerCase();
|
||||
final String owner = ModThreadContext.get().getCurrentContainer().getPrefix();
|
||||
return add(id, value, owner);
|
||||
}
|
||||
|
||||
|
@ -430,7 +430,7 @@ public class ForgeRegistry<V extends IForgeRegistryEntry<V>> implements IForgeRe
|
|||
{
|
||||
try
|
||||
{
|
||||
ReflectionHelper.findMethod(BitSet.class, "trimToSize", null).invoke(this.availabilityMap);
|
||||
// ReflectionHelper.findMethod(BitSet.class, "trimToSize", null).invoke(this.availabilityMap);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -49,6 +49,7 @@ import net.minecraft.world.biome.Biome;
|
|||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.event.RegistryEvent.MissingMappings;
|
||||
import net.minecraftforge.fml.Logging;
|
||||
import net.minecraftforge.fml.common.EnhancedRuntimeException;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.fml.common.FMLContainer;
|
||||
|
@ -83,6 +84,8 @@ import javax.annotation.Nullable;
|
|||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.logging.log4j.Level;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
/**
|
||||
* INTERNAL ONLY
|
||||
* MODDERS SHOULD HAVE NO REASON TO USE THIS CLASS
|
||||
|
@ -201,7 +204,7 @@ public class GameData
|
|||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public static void vanillaSnapshot()
|
||||
{
|
||||
FMLLog.log.debug("Creating vanilla freeze snapshot");
|
||||
fmlLog.debug("Creating vanilla freeze snapshot");
|
||||
for (Map.Entry<ResourceLocation, ForgeRegistry<? extends IForgeRegistryEntry<?>>> r : RegistryManager.ACTIVE.registries.entrySet())
|
||||
{
|
||||
final Class<? extends IForgeRegistryEntry> clazz = RegistryManager.ACTIVE.getSuperType(r.getKey());
|
||||
|
@ -214,7 +217,7 @@ public class GameData
|
|||
});
|
||||
RegistryManager.VANILLA.registries.forEach(LOCK_VANILLA);
|
||||
RegistryManager.ACTIVE.registries.forEach(LOCK_VANILLA);
|
||||
FMLLog.log.debug("Vanilla freeze snapshot created");
|
||||
fmlLog.debug("Vanilla freeze snapshot created");
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
net.minecraftforge.fml.loading.FMLLaunchProvider
|
||||
net.minecraftforge.fml.loading.FMLDevLaunchProvider
|
||||
net.minecraftforge.fml.loading.FMLDevClientLaunchProvider
|
6
src/main/resources/forgemod.toml
Normal file
6
src/main/resources/forgemod.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
modId="forge"
|
||||
version="${global.forgeVersion}"
|
||||
displayName="Forge"
|
||||
description='''
|
||||
Forge, the magic
|
||||
'''
|
6
src/main/resources/minecraftmod.toml
Normal file
6
src/main/resources/minecraftmod.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
modId="minecraft"
|
||||
version="${global.mcVersion}"
|
||||
displayName="Minecraft"
|
||||
description='''
|
||||
Minecraft, a modded story
|
||||
'''
|
37
src/test/java/net/minecraftforge/fml/test/ModsTomlTest.java
Normal file
37
src/test/java/net/minecraftforge/fml/test/ModsTomlTest.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
package net.minecraftforge.fml.test;
|
||||
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileParser;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class ModsTomlTest
|
||||
{
|
||||
@Test
|
||||
public void testTomlLoad() throws URISyntaxException
|
||||
{
|
||||
final URL resource = getClass().getClassLoader().getResource("mods.toml");
|
||||
final Path path = Paths.get(resource.toURI());
|
||||
final ModFile.ModFileInfo modFileInfo = ModFileParser.loadModFile(null, path);
|
||||
modFileInfo.getMods();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTomlInJar() throws URISyntaxException, IOException
|
||||
{
|
||||
final URL resource = getClass().getClassLoader().getResource("mod.jar");
|
||||
|
||||
final FileSystem fileSystem = FileSystems.newFileSystem(Paths.get(resource.toURI()), getClass().getClassLoader());
|
||||
final Path path = fileSystem.getPath("META-INF", "mods.toml");
|
||||
ModFileParser.loadModFile(null, path);
|
||||
}
|
||||
}
|
5
src/test/resources/blah.json
Normal file
5
src/test/resources/blah.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"reply": {
|
||||
"message": "no"
|
||||
}
|
||||
}
|
71
src/test/resources/mods.toml
Normal file
71
src/test/resources/mods.toml
Normal file
|
@ -0,0 +1,71 @@
|
|||
# The name of the mod loader type to load
|
||||
modLoader="javafml"
|
||||
# A version range to match for said mod loader
|
||||
loaderVersion="[2.0,)"
|
||||
# A URL to query for updates
|
||||
updateJSONURL="http://myurl.me/"
|
||||
# A URL to refer people to when problems occur with this mod
|
||||
issueTrackerURL="http://my.issue.tracker/"
|
||||
# Extra mod loader property
|
||||
randomScalaProperty="fishy"
|
||||
# Arbitrary key-value property pairs available to mods
|
||||
[properties]
|
||||
key="value"
|
||||
|
||||
# A list of mods - how many allowed here is determined by the individual mod loader
|
||||
[[mods]]
|
||||
# The modid of the mod
|
||||
modId="inventorysorter"
|
||||
# The version number of the mod
|
||||
version="1.1"
|
||||
# A display name for the mod
|
||||
displayName="Inventory Sorter"
|
||||
# The description text for the mod (multi line!)
|
||||
description='''
|
||||
This is my mod, there may be
|
||||
others, but this one is mine
|
||||
'''
|
||||
# A random extra property for a mod loader
|
||||
randomExtraProperty="somevalue"
|
||||
# Arbitrary key-value pairs
|
||||
[modproperties.inventorysorter]
|
||||
key="value"
|
||||
# A list of dependencies
|
||||
[[dependencies.inventorysorter]]
|
||||
# the modid of the dependency
|
||||
modId="forge"
|
||||
# Does this dependency have to exist - if not, ordering below must be specified
|
||||
mandatory=true
|
||||
# The version range of the dependency
|
||||
versionRange="[14.23.2.0,)"
|
||||
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
|
||||
ordering="NONE"
|
||||
# Side this dependency is applied on - BOTH, CLIENT or SERVER
|
||||
side="BOTH"
|
||||
# Here's another dependency
|
||||
[[dependencies.inventorysorter]]
|
||||
modId="minecraft"
|
||||
mandatory=true
|
||||
versionRange="[1.12.2]"
|
||||
ordering="NONE"
|
||||
side="BOTH"
|
||||
# Here's another mod in this jar
|
||||
[[mods]]
|
||||
# Note that other mod types may want to add additional key-value pairs in here
|
||||
modId="inventorysortertoo"
|
||||
# ${jarVersion} will read the Implementation-Version of the jar file
|
||||
version="${jarVersion}"
|
||||
displayName="Inventory Sorter as well"
|
||||
description='''
|
||||
This is also my mod, there may be
|
||||
others, but this one is mine
|
||||
'''
|
||||
[[dependencies.inventorysortertoo]]
|
||||
modId="minecraft"
|
||||
mandatory=true
|
||||
versionRange="[1.12.2]"
|
||||
ordering="NONE"
|
||||
side="BOTH"
|
||||
[[mods]]
|
||||
# A minimal mod
|
||||
modId="minimalmod"
|
Loading…
Reference in a new issue