mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-12 08:17:35 +00:00
separated fmllauncher code from main forge mod code. This enables much
stronger classloader separation between the two sides. Forge now loads as a regular mod. Still needs a bunch of debugging, but structure looks good and game loads in forge dev.
This commit is contained in:
1 parent
558e1d2fb0
commit
48846bc0ba
72 files changed
+693
-755
No files matched your search
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public class FileUtils
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
public static Path getOrCreateDirectory(Path dirPath, String dirLabel) {
|
||||
if (!Files.isDirectory(dirPath))
|
||||
{
|
||||
LOGGER.debug(CORE,"Making {} directory : {}", dirLabel, dirPath);
|
||||
try {
|
||||
Files.createDirectory(dirPath);
|
||||
} catch (IOException e) {
|
||||
if (e instanceof FileAlreadyExistsException) {
|
||||
LOGGER.error(CORE,"Failed to create {} directory - there is a file in the way", dirLabel);
|
||||
} else {
|
||||
LOGGER.error(CORE,"Problem with creating {} directory (Permissions?)", dirLabel, e);
|
||||
}
|
||||
throw new RuntimeException("Problem creating directory", e);
|
||||
}
|
||||
LOGGER.debug(CORE,"Created {} directory : {}", dirLabel, dirPath);
|
||||
} else {
|
||||
LOGGER.debug(CORE,"Found existing {} directory : {}", dirLabel, dirPath);
|
||||
}
|
||||
return dirPath;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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]));
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,9 @@ public class LaunchTesting
|
||||
"--version", "FMLDev",
|
||||
"--assetIndex", "1.13",
|
||||
"--assetsDir", assets,
|
||||
"--userProperties", "{}");
|
||||
"--userProperties", "{}",
|
||||
"--fml.forgeVersion", "24.0.0",
|
||||
"--fml.mcVersion", "1.13");
|
||||
} else if (Objects.equals(target, "fmldevserver")) {
|
||||
String[] launchargs = ObjectArrays.concat(new String[] {"--launchTarget", target,
|
||||
"--gameDir", "."}, args, String.class);
|
||||
|
||||
@@ -21,6 +21,7 @@ package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraftforge.fml.common.event.ModLifecycleEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLModContainer;
|
||||
import net.minecraftforge.fml.language.ILifecycleEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
@@ -46,7 +47,7 @@ public enum LifecycleEventProvider
|
||||
}
|
||||
|
||||
|
||||
public static class LifecycleEvent {
|
||||
public static class LifecycleEvent implements ILifecycleEvent<LifecycleEvent> {
|
||||
private final ModLoadingStage stage;
|
||||
|
||||
public LifecycleEvent(ModLoadingStage stage)
|
||||
|
||||
@@ -92,7 +92,7 @@ public class ModList
|
||||
}
|
||||
|
||||
public void dispatchLifeCycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent, final Consumer<List<ModLoadingException>> errorHandler) {
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.preLifecycleEvent(lifecycleEvent));
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
|
||||
DeferredWorkQueue.deferredWorkQueue.clear();
|
||||
try
|
||||
{
|
||||
@@ -105,7 +105,7 @@ public class ModList
|
||||
LOGGER.debug(LOADING, "Dispatching synchronous work, {} jobs", DeferredWorkQueue.deferredWorkQueue.size());
|
||||
DeferredWorkQueue.deferredWorkQueue.forEach(FutureTask::run);
|
||||
LOGGER.debug(LOADING, "Synchronous work queue complete");
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.postLifecycleEvent(lifecycleEvent));
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
|
||||
}
|
||||
|
||||
public void setLoadedMods(final List<ModContainer> modContainers)
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.SecureClassLoader;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
|
||||
@@ -39,8 +40,11 @@ public class ModLoadingClassLoader extends SecureClassLoader
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
private final Predicate<String> classLoadingPredicate;
|
||||
|
||||
protected ModLoadingClassLoader(final ClassLoader parent) {
|
||||
super(parent);
|
||||
this.classLoadingPredicate = FMLLoader.getClassLoaderExclusions();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,21 +53,29 @@ public class ModLoadingClassLoader extends SecureClassLoader
|
||||
return super.getResource(name);
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
|
||||
{
|
||||
|
||||
final String className = name.replace('.', '/').concat(".class");
|
||||
final Path classResource = FMLLoader.getLoadingModList().findResource(className);
|
||||
if (classResource != null)
|
||||
{
|
||||
return findClass(name);
|
||||
}
|
||||
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
if (!classLoadingPredicate.test(name)) {
|
||||
LOGGER.debug(LOADING, "Delegating to parent {}", name);
|
||||
return getParent().loadClass(name);
|
||||
}
|
||||
LOGGER.debug(LOADING, "Loading class {}", name);
|
||||
final String className = name.replace('.','/').concat(".class");
|
||||
final Path classResource = FMLLoader.getLoadingModList().findResource(className);
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.gui;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.common.toposort.ModSortingException;
|
||||
import net.minecraftforge.fml.common.toposort.ModSortingException.SortingExceptionData;
|
||||
|
||||
public class GuiSortingProblem extends GuiScreen {
|
||||
private SortingExceptionData<ModContainer> failedList;
|
||||
|
||||
public GuiSortingProblem(ModSortingException modSorting)
|
||||
{
|
||||
this.failedList = modSorting.getExceptionData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui()
|
||||
{
|
||||
super.initGui();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouseX, int mouseY, float partialTicks)
|
||||
{
|
||||
this.drawDefaultBackground();
|
||||
int offset = Math.max(85 - (failedList.getVisitedNodes().size() + 3) * 10, 10);
|
||||
this.drawCenteredString(this.fontRenderer, "Forge Mod Loader has found a problem with your minecraft installation", this.width / 2, offset, 0xFFFFFF);
|
||||
offset+=10;
|
||||
this.drawCenteredString(this.fontRenderer, "A mod sorting cycle was detected and loading cannot continue", this.width / 2, offset, 0xFFFFFF);
|
||||
offset+=10;
|
||||
this.drawCenteredString(this.fontRenderer, String.format("The first mod in the cycle is %s", failedList.getFirstBadNode()), this.width / 2, offset, 0xFFFFFF);
|
||||
offset+=10;
|
||||
this.drawCenteredString(this.fontRenderer, "The remainder of the cycle involves these mods", this.width / 2, offset, 0xFFFFFF);
|
||||
offset+=5;
|
||||
for (ModContainer mc : failedList.getVisitedNodes())
|
||||
{/* TODO Mod dependencies
|
||||
offset+=10;
|
||||
this.drawCenteredString(this.fontRenderer, String.format("%s : before: %s, after: %s", mc.toString(), mc.getDependants(), mc.getDependencies()), this.width / 2, offset, 0xEEEEEE);
|
||||
*/}
|
||||
offset+=20;
|
||||
this.drawCenteredString(this.fontRenderer, "The file 'ForgeModLoader-client-0.log' contains more information", this.width / 2, offset, 0xFFFFFF);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.common.toposort;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.client.IDisplayableError;
|
||||
import net.minecraftforge.fml.client.gui.GuiSortingProblem;
|
||||
import net.minecraftforge.fml.common.EnhancedRuntimeException;
|
||||
|
||||
import net.minecraftforge.fml.common.EnhancedRuntimeException.WrappedPrintStream;
|
||||
|
||||
public class ModSortingException extends EnhancedRuntimeException implements IDisplayableError
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public class SortingExceptionData<T>
|
||||
{
|
||||
public SortingExceptionData(T node, Set<T> visitedNodes)
|
||||
{
|
||||
this.firstBadNode = node;
|
||||
this.visitedNodes = visitedNodes;
|
||||
}
|
||||
|
||||
private T firstBadNode;
|
||||
private Set<T> visitedNodes;
|
||||
|
||||
public T getFirstBadNode()
|
||||
{
|
||||
return firstBadNode;
|
||||
}
|
||||
public Set<T> getVisitedNodes()
|
||||
{
|
||||
return visitedNodes;
|
||||
}
|
||||
}
|
||||
|
||||
private SortingExceptionData<?> sortingExceptionData;
|
||||
|
||||
public <T> ModSortingException(String string, T node, Set<T> visitedNodes)
|
||||
{
|
||||
super(string);
|
||||
this.sortingExceptionData = new SortingExceptionData<>(node, visitedNodes);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> SortingExceptionData<T> getExceptionData()
|
||||
{
|
||||
return (SortingExceptionData<T>) sortingExceptionData;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void printStackTrace(WrappedPrintStream stream)
|
||||
{
|
||||
SortingExceptionData<ModContainer> exceptionData = getExceptionData();
|
||||
stream.println("A dependency cycle was detected in the input mod set so an ordering cannot be determined");
|
||||
stream.println("The first mod in the cycle is " + exceptionData.getFirstBadNode());
|
||||
stream.println("The mod cycle involves:");
|
||||
for (ModContainer mc : exceptionData.getVisitedNodes())
|
||||
{/* TODO Mod dependencies
|
||||
stream.println(String.format("\t%s : before: %s, after: %s", mc.toString(), mc.getDependants(), mc.getDependencies()));
|
||||
*/}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public GuiScreen createGui()
|
||||
{
|
||||
return new GuiSortingProblem(this);
|
||||
}
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.common.toposort;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import net.minecraftforge.fml.loading.EarlyLoadingException;
|
||||
import org.apache.logging.log4j.message.Message;
|
||||
import org.apache.logging.log4j.util.StringBuilderFormattable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Topological sort for mod loading
|
||||
*
|
||||
* Based on a variety of sources, including http://keithschwarz.com/interesting/code/?dir=topological-sort
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class TopologicalSort
|
||||
{
|
||||
public static class DirectedGraph<T> implements Iterable<T>
|
||||
{
|
||||
private final Map<T, SortedSet<T>> graph = new HashMap<>();
|
||||
private List<T> orderedNodes = new ArrayList<>();
|
||||
|
||||
public boolean addNode(T node)
|
||||
{
|
||||
// Ignore nodes already added
|
||||
if (graph.containsKey(node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
orderedNodes.add(node);
|
||||
graph.put(node, new TreeSet<>(Comparator.comparingInt(o -> orderedNodes.indexOf(o))));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addEdge(T from, T to)
|
||||
{
|
||||
if (!(graph.containsKey(from) && graph.containsKey(to)))
|
||||
{
|
||||
throw new NoSuchElementException("Missing nodes from graph");
|
||||
}
|
||||
|
||||
graph.get(from).add(to);
|
||||
}
|
||||
|
||||
public void removeEdge(T from, T to)
|
||||
{
|
||||
if (!(graph.containsKey(from) && graph.containsKey(to)))
|
||||
{
|
||||
throw new NoSuchElementException("Missing nodes from graph");
|
||||
}
|
||||
|
||||
graph.get(from).remove(to);
|
||||
}
|
||||
|
||||
public boolean edgeExists(T from, T to)
|
||||
{
|
||||
if (!(graph.containsKey(from) && graph.containsKey(to)))
|
||||
{
|
||||
throw new NoSuchElementException("Missing nodes from graph");
|
||||
}
|
||||
|
||||
return graph.get(from).contains(to);
|
||||
}
|
||||
|
||||
public Set<T> edgesFrom(T from)
|
||||
{
|
||||
if (!graph.containsKey(from))
|
||||
{
|
||||
throw new NoSuchElementException("Missing node from graph");
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSortedSet(graph.get(from));
|
||||
}
|
||||
@Override
|
||||
public Iterator<T> iterator()
|
||||
{
|
||||
return orderedNodes.iterator();
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return graph.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return graph.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return graph.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the input graph into a topologically sorted list
|
||||
*
|
||||
* Uses the reverse depth first search as outlined in ...
|
||||
* @param graph
|
||||
* @return The sorted mods list.
|
||||
*/
|
||||
public static <T> List<T> topologicalSort(DirectedGraph<T> graph)
|
||||
{
|
||||
DirectedGraph<T> rGraph = reverse(graph);
|
||||
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<>();
|
||||
|
||||
for (T node : rGraph)
|
||||
{
|
||||
explore(node, rGraph, sortedResult, visitedNodes, expandedNodes);
|
||||
}
|
||||
|
||||
return sortedResult;
|
||||
}
|
||||
|
||||
public static <T> DirectedGraph<T> reverse(DirectedGraph<T> graph)
|
||||
{
|
||||
DirectedGraph<T> result = new DirectedGraph<>();
|
||||
|
||||
for (T node : graph)
|
||||
{
|
||||
result.addNode(node);
|
||||
}
|
||||
|
||||
for (T from : graph)
|
||||
{
|
||||
for (T to : graph.edgesFrom(from))
|
||||
{
|
||||
result.addEdge(to, from);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
// And have completed this node before
|
||||
if (expandedNodes.contains(node))
|
||||
{
|
||||
// Then we're fine
|
||||
return;
|
||||
}
|
||||
|
||||
throw new TopoSortException(new TopoSortException.TopoSortExceptionData<>(node, sortedResult, visitedNodes, expandedNodes));
|
||||
}
|
||||
|
||||
// Visit this node
|
||||
visitedNodes.add(node);
|
||||
|
||||
// Recursively explore inbound edges
|
||||
for (T inbound : graph.edgesFrom(node))
|
||||
{
|
||||
explore(inbound, graph, sortedResult, visitedNodes, expandedNodes);
|
||||
}
|
||||
|
||||
// Add ourselves now
|
||||
sortedResult.add(node);
|
||||
// And mark ourselves as explored
|
||||
expandedNodes.add(node);
|
||||
}
|
||||
|
||||
public static class TopoSortException extends RuntimeException {
|
||||
private final TopoSortExceptionData<?> topoSortData;
|
||||
|
||||
public static class TopoSortExceptionData<T> implements Message, StringBuilderFormattable
|
||||
{
|
||||
private final List<T> sortedResult;
|
||||
private final Set<T> visitedNodes;
|
||||
private final Set<T> expandedNodes;
|
||||
private final T node;
|
||||
|
||||
TopoSortExceptionData(T node, List<T> sortedResult, Set<T> visitedNodes, Set<T> expandedNodes)
|
||||
{
|
||||
this.node = node;
|
||||
this.sortedResult = sortedResult;
|
||||
this.visitedNodes = visitedNodes;
|
||||
this.expandedNodes = expandedNodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormattedMessage()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormat()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getParameters()
|
||||
{
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getThrowable()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void formatTo(StringBuilder buffer)
|
||||
{
|
||||
buffer.append("Mod Sorting failed.\n");
|
||||
buffer.append("Visiting node {}\n").append(String.valueOf(node));
|
||||
buffer.append("Current sorted list : {}\n").append(String.valueOf(sortedResult));
|
||||
buffer.append("Visited set for this node : {}\n").append(String.valueOf(visitedNodes));
|
||||
buffer.append("Explored node set : {}\n").append(expandedNodes);
|
||||
buffer.append("Likely cycle is in : {}\n").append(Sets.difference(visitedNodes, expandedNodes));
|
||||
}
|
||||
|
||||
public List<EarlyLoadingException.ExceptionData> toExceptionData(Function<T, String> nodeMapper) {
|
||||
return Collections.singletonList(
|
||||
new EarlyLoadingException.ExceptionData("fml.messages.cycleproblem",
|
||||
nodeMapper.apply(node),
|
||||
visitedNodes.stream().map(nodeMapper).collect(Collectors.joining(","))));
|
||||
}
|
||||
}
|
||||
|
||||
public <T> TopoSortException(TopoSortExceptionData<T> data)
|
||||
{
|
||||
this.topoSortData = data;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TopoSortExceptionData<T> getData() {
|
||||
return (TopoSortExceptionData<T>)this.topoSortData;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package net.minecraftforge.fml.javafmlmod;
|
||||
|
||||
import net.minecraftforge.fml.LifecycleEventProvider;
|
||||
import net.minecraftforge.fml.language.ILifecycleEvent;
|
||||
import net.minecraftforge.fml.language.IModLanguageProvider;
|
||||
import net.minecraftforge.fml.language.IModInfo;
|
||||
import net.minecraftforge.fml.language.ModFileScanData;
|
||||
@@ -32,6 +32,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
@@ -100,12 +101,7 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preLifecycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent)
|
||||
{
|
||||
}
|
||||
public <R extends ILifecycleEvent<R>> void consumeLifecycleEvent(final Supplier<R> consumeEvent) {
|
||||
|
||||
@Override
|
||||
public void postLifecycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.language;
|
||||
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
public interface IModFileInfo
|
||||
{
|
||||
List<IModInfo> getMods();
|
||||
|
||||
UnmodifiableConfig getConfig();
|
||||
|
||||
URL getUpdateURL(IModFileInfo modFileInfo);
|
||||
|
||||
String getModLoader();
|
||||
|
||||
VersionRange getModLoaderVersion();
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.language;
|
||||
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import net.minecraftforge.fml.loading.MavenVersionAdapter;
|
||||
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IModInfo
|
||||
{
|
||||
VersionRange UNBOUNDED = MavenVersionAdapter.createFromVersionSpec("");
|
||||
|
||||
IModFileInfo getOwningFile();
|
||||
|
||||
String getModId();
|
||||
|
||||
String getDisplayName();
|
||||
|
||||
String getDescription();
|
||||
|
||||
ArtifactVersion getVersion();
|
||||
|
||||
List<ModVersion> getDependencies();
|
||||
|
||||
UnmodifiableConfig getModConfig();
|
||||
|
||||
enum Ordering {
|
||||
BEFORE, AFTER, NONE
|
||||
}
|
||||
|
||||
enum DependencySide {
|
||||
CLIENT, SERVER, BOTH;
|
||||
|
||||
public boolean isCorrectSide()
|
||||
{
|
||||
return this == BOTH || FMLEnvironment.dist.name().equals(this.name());
|
||||
}
|
||||
}
|
||||
|
||||
class ModVersion {
|
||||
private IModInfo owner;
|
||||
private final String modId;
|
||||
private final VersionRange versionRange;
|
||||
private final boolean mandatory;
|
||||
private final Ordering ordering;
|
||||
private final DependencySide side;
|
||||
|
||||
public ModVersion(final IModInfo owner, final UnmodifiableConfig config) {
|
||||
this.owner = owner;
|
||||
this.modId = config.get("modId");
|
||||
this.versionRange = config.getOptional("versionRange").map(String.class::cast).
|
||||
map(MavenVersionAdapter::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 IModInfo owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public IModInfo getOwner()
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.language;
|
||||
|
||||
import net.minecraftforge.fml.LifecycleEventProvider;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Loaded as a ServiceLoader, from the classpath. ExtensionPoint are loaded from
|
||||
* the mods directory, with the FMLType META-INF of LANGPROVIDER.
|
||||
*
|
||||
* Version data is read from the manifest's implementation version.
|
||||
*/
|
||||
public interface IModLanguageProvider
|
||||
{
|
||||
String name();
|
||||
|
||||
Consumer<ModFileScanData> getFileVisitor();
|
||||
|
||||
void preLifecycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent);
|
||||
void postLifecycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent);
|
||||
|
||||
interface IModLanguageLoader {
|
||||
<T> T loadMod(IModInfo info, ClassLoader modClassLoader, ModFileScanData modFileScanResults);
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.language;
|
||||
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ModFileScanData
|
||||
{
|
||||
private final List<ModFileScanData.AnnotationData> annotations = new ArrayList<>();
|
||||
private final List<ModFileScanData.ClassData> classes = new ArrayList<>();
|
||||
private Map<String,? extends IModLanguageProvider.IModLanguageLoader> modTargets;
|
||||
private Map<String,?> functionalScanners;
|
||||
|
||||
public static Predicate<Type> interestingAnnotations() {
|
||||
return t->true;
|
||||
}
|
||||
|
||||
public List<ModFileScanData.ClassData> getClasses() {
|
||||
return classes;
|
||||
}
|
||||
|
||||
public List<ModFileScanData.AnnotationData> getAnnotations() {
|
||||
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;
|
||||
private final Set<Type> interfaces;
|
||||
|
||||
public ClassData(final Type clazz, final Type parent, final Set<Type> interfaces) {
|
||||
this.clazz = clazz;
|
||||
this.parent = parent;
|
||||
this.interfaces = interfaces;
|
||||
}
|
||||
|
||||
}
|
||||
public static class AnnotationData {
|
||||
private final Type annotationType;
|
||||
private final Type clazz;
|
||||
private final String memberName;
|
||||
private final Map<String,Object> annotationData;
|
||||
|
||||
|
||||
public AnnotationData(final Type annotationType, final Type clazz, final String memberName, final Map<String, Object> annotationData) {
|
||||
this.annotationType = annotationType;
|
||||
this.clazz = clazz;
|
||||
this.memberName = memberName;
|
||||
this.annotationData = annotationData;
|
||||
}
|
||||
|
||||
public Type getAnnotationType() {
|
||||
return annotationType;
|
||||
}
|
||||
|
||||
public Type getClassType() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public String getMemberName() {
|
||||
return memberName;
|
||||
}
|
||||
|
||||
public Map<String, Object> getAnnotationData() {
|
||||
return annotationData;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.electronwill.nightconfig.core.file.FileConfig;
|
||||
import net.minecraftforge.fml.language.IModInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class DefaultModInfos
|
||||
{
|
||||
static {
|
||||
FileConfig minecraftmod; FileConfig forgemod;
|
||||
try
|
||||
{
|
||||
final URI jarFileURI = DefaultModInfos.class.getClassLoader().getResource("minecraftmod.toml").toURI();
|
||||
if (Objects.equals(jarFileURI.getScheme(), "jar")) {
|
||||
// Initialize the filesystem for the forge jar, because otherwise this barfs?
|
||||
FileSystems.newFileSystem(jarFileURI, new HashMap<>());
|
||||
}
|
||||
minecraftmod = FileConfig.of(Paths.get(jarFileURI));
|
||||
minecraftmod.load();
|
||||
}
|
||||
catch (IOException | URISyntaxException | NullPointerException e)
|
||||
{
|
||||
throw new RuntimeException("Missing toml configs for minecraft and forge!", e);
|
||||
}
|
||||
minecraftModInfo = new ModInfo(null, minecraftmod);
|
||||
|
||||
}
|
||||
|
||||
public static final IModInfo minecraftModInfo;
|
||||
|
||||
// no construction
|
||||
private DefaultModInfos() {}
|
||||
|
||||
public static List<IModInfo> getModInfos()
|
||||
{
|
||||
return Arrays.asList(minecraftModInfo);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Thrown during early loading phase, and collected by the LoadingModList for handoff to the client
|
||||
* or server.
|
||||
*/
|
||||
public class EarlyLoadingException extends RuntimeException {
|
||||
public static class ExceptionData {
|
||||
|
||||
|
||||
private final String i18message;
|
||||
private final Object[] args;
|
||||
public ExceptionData(final String message, Object... args) {
|
||||
this.i18message = message;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public String getI18message() {
|
||||
return i18message;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
}
|
||||
private final List<ExceptionData> errorMessages;
|
||||
|
||||
public List<ExceptionData> getAllData() {
|
||||
return errorMessages;
|
||||
}
|
||||
|
||||
EarlyLoadingException(final String message, final Throwable originalException, List<ExceptionData> errorMessages) {
|
||||
super(message, originalException);
|
||||
this.errorMessages = errorMessages;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.relauncher.libraries.LibraryManager;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.versions.mcp.MCPVersion;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class FMLClientLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "fmlclient";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path[] identifyTransformationTargets()
|
||||
{
|
||||
Path libsPath = findLibsPath();
|
||||
Path patchedBinariesPath = libsPath.resolve(Paths.get(ForgeVersion.getGroup().replace('.', File.separatorChar), "forge", MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion(), "forge-" + MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion() + "-client.jar"));
|
||||
Path srgMcPath = libsPath.resolve(Paths.get("net","minecraft", "client", MCPVersion.getMCPandMCVersion(), "client-"+MCPVersion.getMCPandMCVersion()+"-srg.jar"));
|
||||
LOGGER.info("SRG MC at {} is {}", srgMcPath.toString(), Files.exists(srgMcPath) ? "present" : "missing");
|
||||
LOGGER.info("Forge patches at {} is {}", patchedBinariesPath.toString(), Files.exists(patchedBinariesPath) ? "present" : "missing");
|
||||
LOGGER.info("Forge at {} is {}", getForgePath().toString(), Files.exists(getForgePath()) ? "present" : "missing");
|
||||
if (!(Files.exists(srgMcPath) && Files.exists(patchedBinariesPath) && Files.exists(getForgePath()))) {
|
||||
throw new RuntimeException("Failed to find patched jars");
|
||||
}
|
||||
return super.commonLibPaths(new Path[] {getForgePath(), patchedBinariesPath, srgMcPath});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
return () -> {
|
||||
super.beforeStart(launchClassLoader);
|
||||
launchClassLoader.addTargetPackageFilter(getPackagePredicate());
|
||||
Class.forName("net.minecraft.client.main.Main", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(final IEnvironment environment) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dist getDist()
|
||||
{
|
||||
return Dist.CLIENT;
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.ObjectArrays;
|
||||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public abstract class FMLCommonLaunchHandler
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final List<String> SKIPPACKAGES = Arrays.asList(
|
||||
// standard libs
|
||||
"joptsimple.", "org.lwjgl.", "com.mojang.guava.", "com.google.", "org.apache.commons.", "io.netty.",
|
||||
"org.apache.logging.log4j.", "org.apache.http.", "org.apache.maven.", "org.objectweb.asm.",
|
||||
"paulscode.sound.", "com.ibm.icu.", "sun.", "gnu.trove.", "com.electronwill.nightconfig.",
|
||||
"net.minecraftforge.fml.loading.", "net.minecraftforge.fml.language.", "net.minecraftforge.versions.",
|
||||
"net.minecraftforge.eventbus.", "net.minecraftforge.api."
|
||||
);
|
||||
|
||||
private Path forgePath;
|
||||
|
||||
protected Predicate<String> getPackagePredicate() {
|
||||
return cn -> SKIPPACKAGES.stream().noneMatch(cn::startsWith);
|
||||
}
|
||||
|
||||
public void setup(final IEnvironment environment)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Path findLibsPath() {
|
||||
final Path asm = findJarPathFor("org/objectweb/asm/Opcodes.class", "asm");
|
||||
// go up SIX parents to find the libs dir
|
||||
final Path libs = asm.getParent().getParent().getParent().getParent().getParent().getParent();
|
||||
LOGGER.debug(CORE, "Found probable library path {}", libs);
|
||||
return libs;
|
||||
}
|
||||
Path findJarPathFor(final String className, final String jarName) {
|
||||
final URL resource = getClass().getClassLoader().getResource(className);
|
||||
try {
|
||||
Path path;
|
||||
final URI uri = resource.toURI();
|
||||
if (uri.getRawSchemeSpecificPart().contains("!")) {
|
||||
path = Paths.get(new URI(uri.getRawSchemeSpecificPart().split("!")[0]));
|
||||
} else {
|
||||
path = Paths.get(new URI("file://"+uri.getRawSchemeSpecificPart().substring(0, uri.getRawSchemeSpecificPart().length()-className.length())));
|
||||
}
|
||||
LOGGER.debug(CORE, "Found JAR {} at path {}", jarName, path.toString());
|
||||
return path;
|
||||
} catch (URISyntaxException e) {
|
||||
LOGGER.error(CORE, "Failed to find JAR for class {} - {}", className, jarName);
|
||||
throw new RuntimeException("Unable to locate "+className+" - "+jarName, e);
|
||||
}
|
||||
}
|
||||
Path[] commonLibPaths(Path[] extras) {
|
||||
final Path realms = findJarPathFor("com/mojang/realmsclient/RealmsVersion.class", "realms");
|
||||
return ObjectArrays.concat(extras, realms);
|
||||
}
|
||||
|
||||
Path getForgePath() {
|
||||
if (forgePath == null) {
|
||||
forgePath = findJarPathFor("net/minecraftforge/versions/forge/ForgeVersion.class", "forge");
|
||||
LOGGER.debug(CORE, "Found forge path {}", forgePath);
|
||||
}
|
||||
return forgePath;
|
||||
}
|
||||
public abstract Dist getDist();
|
||||
|
||||
protected void beforeStart(ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
FMLLoader.beforeStart(launchClassLoader, getForgePath());
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.electronwill.nightconfig.core.ConfigSpec;
|
||||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import com.electronwill.nightconfig.core.io.WritingMode;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public class FMLConfig
|
||||
{
|
||||
private static FMLConfig INSTANCE = new FMLConfig();
|
||||
private static ConfigSpec configSpec = new ConfigSpec();
|
||||
static {
|
||||
configSpec.define("splashscreen", Boolean.TRUE);
|
||||
configSpec.defineInList("side", Dist.CLIENT.name(), Arrays.stream(Dist.values()).map(Enum::name).collect(Collectors.toList()));
|
||||
configSpec.defineInRange("maxframerate", 60, 10, 120);
|
||||
configSpec.defineInRange("minframerate", 60, 10, 120);
|
||||
/* Tests that we know work and shouldn't be done in runtime.
|
||||
configSpec.defineInList(Arrays.asList("tasty","flavour"), Dist.CLIENT.name(), Arrays.stream(Dist.values()).map(Enum::name).collect(Collectors.toList()));
|
||||
configSpec.defineInList(Arrays.asList("tasty","teaser"), Dist.CLIENT.name(), Arrays.stream(Dist.values()).map(Enum::name).collect(Collectors.toList()));
|
||||
configSpec.define("longstring", StringUtils.repeat("AAAA", 10000), s->s!=null && ((String)s).length()>0);
|
||||
*/
|
||||
}
|
||||
|
||||
private CommentedFileConfig configData;
|
||||
|
||||
private void loadFrom(final Path configFile)
|
||||
{
|
||||
configData = CommentedFileConfig.builder(configFile).sync().
|
||||
defaultResource("/META-INF/defaultfmlconfig.toml").
|
||||
autosave().autoreload().
|
||||
writingMode(WritingMode.REPLACE).
|
||||
build();
|
||||
configData.load();
|
||||
if (!configSpec.isCorrect(configData)) {
|
||||
LogManager.getLogger().warn(CORE, "Configuration file {} is not correct. Correcting", configFile);
|
||||
configSpec.correct(configData, (action, path, incorrectValue, correctedValue) ->
|
||||
LogManager.getLogger().warn(CORE, "Incorrect key {} was corrected from {} to {}", path, incorrectValue, correctedValue));
|
||||
}
|
||||
configData.save();
|
||||
}
|
||||
|
||||
public static void load()
|
||||
{
|
||||
final Path configFile = FMLPaths.FMLCONFIG.get();
|
||||
INSTANCE.loadFrom(configFile);
|
||||
LogManager.getLogger().debug(CORE, "Loaded FML config from {}", FMLPaths.FMLCONFIG.get());
|
||||
LogManager.getLogger().debug(CORE, "Splash screen is {}", INSTANCE.splashScreenEnabled());
|
||||
}
|
||||
|
||||
public boolean splashScreenEnabled() {
|
||||
return configData.<Boolean>getOptional("splashscreen").orElse(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public class FMLDevClientLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "fmldevclient";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path[] identifyTransformationTargets()
|
||||
{
|
||||
return super.commonLibPaths(new Path[] {getForgePath()});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
return () -> {
|
||||
LOGGER.debug(CORE, "Launching minecraft in {} with arguments {}", launchClassLoader, arguments);
|
||||
super.beforeStart(launchClassLoader);
|
||||
launchClassLoader.addTargetPackageFilter(getPackagePredicate());
|
||||
Class.forName("net.minecraft.client.main.Main", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(IEnvironment environment)
|
||||
{
|
||||
LOGGER.debug(CORE, "No jar creation necessary. Launch is dev environment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dist getDist()
|
||||
{
|
||||
return Dist.CLIENT;
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public class FMLDevServerLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "fmldevserver";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path[] identifyTransformationTargets()
|
||||
{
|
||||
return super.commonLibPaths(new Path[] { getForgePath() });
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
return () -> {
|
||||
LOGGER.debug(CORE, "Launching minecraft in {} with arguments {}", launchClassLoader, arguments);
|
||||
super.beforeStart(launchClassLoader);
|
||||
launchClassLoader.addTargetPackageFilter(getPackagePredicate());
|
||||
Thread.currentThread().setContextClassLoader(launchClassLoader.getInstance());
|
||||
Class.forName("net.minecraft.server.MinecraftServer", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(IEnvironment environment)
|
||||
{
|
||||
LOGGER.debug(CORE, "No jar creation necessary. Launch is dev environment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dist getDist()
|
||||
{
|
||||
return Dist.DEDICATED_SERVER;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.api.distmarker.Dist;
|
||||
|
||||
public class FMLEnvironment
|
||||
{
|
||||
public static final Dist dist = FMLLoader.getDist();
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 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.distmarker.Dist;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
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;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
public class FMLLoader
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static ILaunchPluginService accessTransformer;
|
||||
private static ModDiscoverer modDiscoverer;
|
||||
private static ICoreModProvider coreModProvider;
|
||||
private static ILaunchPluginService eventBus;
|
||||
private static LanguageLoadingProvider languageLoadingProvider;
|
||||
private static Dist dist;
|
||||
private static LoadingModList loadingModList;
|
||||
private static ClassLoader launchClassLoader;
|
||||
private static RuntimeDistCleaner runtimeDistCleaner;
|
||||
private static Path gamePath;
|
||||
private static Path forgePath;
|
||||
|
||||
static void onInitialLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
|
||||
{
|
||||
final String version = ForgeVersion.getVersion();
|
||||
LOGGER.debug(CORE,"FML {} loading", version);
|
||||
final Package modLauncherPackage = ITransformationService.class.getPackage();
|
||||
LOGGER.debug(CORE,"FML found ModLauncher version : {}", modLauncherPackage.getImplementationVersion());
|
||||
if (!modLauncherPackage.isCompatibleWith("1.0")) {
|
||||
LOGGER.error(CORE,"Found incompatible ModLauncher specification : {}, version {} from {}", modLauncherPackage.getSpecificationVersion(), modLauncherPackage.getImplementationVersion(), modLauncherPackage.getImplementationVendor());
|
||||
throw new IncompatibleEnvironmentException("Incompatible modlauncher found "+modLauncherPackage.getSpecificationVersion());
|
||||
}
|
||||
LOGGER.debug(CORE, "Initializing modjar URL handler");
|
||||
URL.setURLStreamHandlerFactory(p->p.equals("modjar") ? new ModJarURLHandler() : null);
|
||||
|
||||
accessTransformer = environment.findLaunchPlugin("accesstransformer").orElseThrow(()-> new IncompatibleEnvironmentException("Missing AccessTransformer, cannot run"));
|
||||
|
||||
final Package atPackage = accessTransformer.getClass().getPackage();
|
||||
LOGGER.debug(CORE,"FML found AccessTransformer version : {}", atPackage.getImplementationVersion());
|
||||
if (!atPackage.isCompatibleWith("1.0")) {
|
||||
LOGGER.error(CORE,"Found incompatible AccessTransformer specification : {}, version {} from {}", atPackage.getSpecificationVersion(), atPackage.getImplementationVersion(), atPackage.getImplementationVendor());
|
||||
throw new IncompatibleEnvironmentException("Incompatible accesstransformer found "+atPackage.getSpecificationVersion());
|
||||
}
|
||||
|
||||
eventBus = environment.findLaunchPlugin("eventbus").orElseThrow(()-> new IncompatibleEnvironmentException("Missing EventBus, cannot run"));
|
||||
|
||||
final Package eventBusPackage = eventBus.getClass().getPackage();
|
||||
LOGGER.debug(CORE,"FML found EventBus version : {}", eventBusPackage.getImplementationVersion());
|
||||
if (!eventBusPackage.isCompatibleWith("1.0")) {
|
||||
LOGGER.error(CORE,"Found incompatible EventBus specification : {}, version {} from {}", eventBusPackage.getSpecificationVersion(), eventBusPackage.getImplementationVersion(), eventBusPackage.getImplementationVendor());
|
||||
throw new IncompatibleEnvironmentException("Incompatible eventbus found "+eventBusPackage.getSpecificationVersion());
|
||||
}
|
||||
|
||||
runtimeDistCleaner = (RuntimeDistCleaner)environment.findLaunchPlugin("runtimedistcleaner").orElseThrow(()->new IncompatibleEnvironmentException("Missing RuntimeDistCleaner, cannot run!"));
|
||||
LOGGER.debug(CORE, "Found Runtime Dist Cleaner");
|
||||
|
||||
final ArrayList<ICoreModProvider> coreModProviders = new ArrayList<>();
|
||||
ServiceLoader.load(ICoreModProvider.class).forEach(coreModProviders::add);
|
||||
|
||||
if (coreModProviders.isEmpty()) {
|
||||
LOGGER.error(CORE, "Found no coremod provider. Cannot run");
|
||||
throw new IncompatibleEnvironmentException("No coremod library found");
|
||||
} else if (coreModProviders.size() > 1) {
|
||||
LOGGER.error(CORE, "Found multiple coremod providers : {}. Cannot run", coreModProviders.stream().map(p -> p.getClass().getName()).collect(Collectors.toList()));
|
||||
throw new IncompatibleEnvironmentException("Multiple coremod libraries found");
|
||||
}
|
||||
|
||||
coreModProvider = coreModProviders.get(0);
|
||||
final Package coremodPackage = coreModProvider.getClass().getPackage();
|
||||
LOGGER.debug(CORE,"FML found CoreMod version : {}", coremodPackage.getImplementationVersion());
|
||||
|
||||
languageLoadingProvider = new LanguageLoadingProvider();
|
||||
}
|
||||
|
||||
static void setupLaunchHandler(final IEnvironment environment)
|
||||
{
|
||||
final String launchTarget = environment.getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).orElse("MISSING");
|
||||
final Optional<ILaunchHandlerService> launchHandler = environment.findLaunchHandler(launchTarget);
|
||||
LOGGER.debug(CORE, "Using {} as launch service", launchTarget);
|
||||
if (!launchHandler.isPresent()) {
|
||||
LOGGER.error(CORE,"Missing LaunchHandler {}, cannot continue", launchTarget);
|
||||
throw new RuntimeException("Missing launch handler");
|
||||
}
|
||||
|
||||
if (!(launchHandler.get() instanceof FMLCommonLaunchHandler)) {
|
||||
LOGGER.error(CORE, "Incompatible Launch handler found - type {}, cannot continue", launchHandler.get().getClass().getName());
|
||||
throw new RuntimeException("Incompatible launch handler found");
|
||||
}
|
||||
gamePath = environment.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Paths.get(".").toAbsolutePath());
|
||||
|
||||
FMLCommonLaunchHandler commonLaunchHandler = (FMLCommonLaunchHandler)launchHandler.get();
|
||||
commonLaunchHandler.setup(environment);
|
||||
dist = commonLaunchHandler.getDist();
|
||||
runtimeDistCleaner.getExtension().accept(dist);
|
||||
}
|
||||
public static void beginModScan()
|
||||
{
|
||||
LOGGER.debug(SCAN,"Scanning for Mod Locators");
|
||||
modDiscoverer = new ModDiscoverer();
|
||||
final BackgroundScanHandler backgroundScanHandler = modDiscoverer.discoverMods();
|
||||
loadingModList = backgroundScanHandler.getLoadingModList();
|
||||
}
|
||||
|
||||
public static ICoreModProvider getCoreModProvider() {
|
||||
return coreModProvider;
|
||||
}
|
||||
|
||||
public static LanguageLoadingProvider getLanguageLoadingProvider()
|
||||
{
|
||||
return languageLoadingProvider;
|
||||
}
|
||||
|
||||
public static void loadAccessTransformer()
|
||||
{
|
||||
final URL resource = FMLLoader.class.getClassLoader().getResource("forge_at.cfg");
|
||||
if (resource == null) {
|
||||
throw new RuntimeException("Missing forge_at.cfg file");
|
||||
}
|
||||
try
|
||||
{
|
||||
LOGGER.debug(CORE, "Loading forge_at.cfg into access transformer");
|
||||
accessTransformer.addResource(Paths.get(resource.toURI()), "forge_at.cfg");
|
||||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
LOGGER.error("Error loading forge_at.cfg file", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addAccessTransformer(Path atPath, ModFile modName)
|
||||
{
|
||||
LOGGER.debug(SCAN, "Adding Access Transformer in {}", modName.getFilePath());
|
||||
accessTransformer.addResource(atPath, modName.getFileName());
|
||||
}
|
||||
|
||||
public static Dist getDist()
|
||||
{
|
||||
return dist;
|
||||
}
|
||||
|
||||
public static void beforeStart(ITransformingClassLoader launchClassLoader, Path forgePath)
|
||||
{
|
||||
FMLLoader.launchClassLoader = launchClassLoader.getInstance();
|
||||
FMLLoader.forgePath = forgePath;
|
||||
}
|
||||
|
||||
|
||||
public static LoadingModList getLoadingModList()
|
||||
{
|
||||
return loadingModList;
|
||||
|
||||
}
|
||||
|
||||
public static ClassLoader getLaunchClassLoader()
|
||||
{
|
||||
return launchClassLoader;
|
||||
}
|
||||
|
||||
public static Path getGamePath()
|
||||
{
|
||||
return gamePath;
|
||||
}
|
||||
|
||||
public static Path getForgePath() {
|
||||
return forgePath;
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 cpw.mods.modlauncher.api.IEnvironment;
|
||||
import net.minecraftforge.fml.FileUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public enum FMLPaths
|
||||
{
|
||||
GAMEDIR(),
|
||||
MODSDIR("mods"),
|
||||
CONFIGDIR("config"),
|
||||
FMLCONFIG(false, CONFIGDIR, "fml.toml");
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final Path relativePath;
|
||||
private final boolean isDirectory;
|
||||
private Path absolutePath;
|
||||
|
||||
FMLPaths() {
|
||||
this("");
|
||||
}
|
||||
|
||||
FMLPaths(String... path) {
|
||||
relativePath = computePath(path);
|
||||
this.isDirectory = true;
|
||||
}
|
||||
|
||||
private Path computePath(String... path)
|
||||
{
|
||||
return Paths.get(path[0], Arrays.copyOfRange(path, 1, path.length));
|
||||
}
|
||||
|
||||
FMLPaths(boolean isDir, FMLPaths parent, String... path) {
|
||||
this.relativePath = parent.relativePath.resolve(computePath(path));
|
||||
this.isDirectory = isDir;
|
||||
}
|
||||
|
||||
public static void setup(IEnvironment env) {
|
||||
final Path rootPath = env.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElseThrow(() -> new RuntimeException("No game path found"));
|
||||
|
||||
loadAbsolutePaths(rootPath);
|
||||
}
|
||||
|
||||
public static void loadAbsolutePaths(Path rootPath)
|
||||
{
|
||||
for (FMLPaths path : FMLPaths.values())
|
||||
{
|
||||
path.absolutePath = rootPath.resolve(path.relativePath).toAbsolutePath().normalize();
|
||||
if (path.isDirectory)
|
||||
{
|
||||
FileUtils.getOrCreateDirectory(path.absolutePath, path.name());
|
||||
}
|
||||
LOGGER.debug(CORE,"Path {} is {}", ()-> path, ()-> path.absolutePath);
|
||||
}
|
||||
}
|
||||
|
||||
public Path get() {
|
||||
return absolutePath;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.versions.mcp.MCPVersion;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class FMLServerLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "fmlserver";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path[] identifyTransformationTargets()
|
||||
{
|
||||
Path libsPath = findLibsPath();
|
||||
Path patchedBinariesPath = libsPath.resolve(Paths.get(ForgeVersion.getGroup().replace('.', File.separatorChar), "forge", MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion(), "forge-" + MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion() + "-server.jar"));
|
||||
Path srgMcPath = libsPath.resolve(Paths.get("net","minecraft", "server", MCPVersion.getMCPandMCVersion(), "server-"+MCPVersion.getMCPandMCVersion()+"-srg.jar"));
|
||||
LOGGER.info("SRG MC at {} is {}", srgMcPath.toString(), Files.exists(srgMcPath) ? "present" : "missing");
|
||||
LOGGER.info("Forge patches at {} is {}", patchedBinariesPath.toString(), Files.exists(patchedBinariesPath) ? "present" : "missing");
|
||||
LOGGER.info("Forge at {} is {}", getForgePath().toString(), Files.exists(getForgePath()) ? "present" : "missing");
|
||||
if (!(Files.exists(srgMcPath) && Files.exists(patchedBinariesPath) && Files.exists(getForgePath()))) {
|
||||
throw new RuntimeException("Failed to find patched jars");
|
||||
}
|
||||
return new Path[] {getForgePath(), patchedBinariesPath, srgMcPath};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
return () -> {
|
||||
super.beforeStart(launchClassLoader);
|
||||
launchClassLoader.addTargetPackageFilter(getPackagePredicate());
|
||||
Class.forName("net.minecraft.server.MinecraftServer", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(final IEnvironment environment) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dist getDist()
|
||||
{
|
||||
return Dist.DEDICATED_SERVER;
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ITransformationService;
|
||||
import cpw.mods.modlauncher.api.ITransformer;
|
||||
import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
|
||||
import joptsimple.ArgumentAcceptingOptionSpec;
|
||||
import joptsimple.OptionSpecBuilder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public class FMLServiceProvider implements ITransformationService
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private ArgumentAcceptingOptionSpec<String> modsOption;
|
||||
private ArgumentAcceptingOptionSpec<String> modListsOption;
|
||||
private List<String> modsArgumentList;
|
||||
private List<String> modListsArgumentList;
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "fml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(IEnvironment environment)
|
||||
{
|
||||
LOGGER.debug(CORE,"Setting up basic FML game directories");
|
||||
FMLPaths.setup(environment);
|
||||
LOGGER.debug(CORE,"Loading configuration");
|
||||
FMLConfig.load();
|
||||
LOGGER.debug(CORE, "Preparing launch handler");
|
||||
FMLLoader.setupLaunchHandler(environment);
|
||||
LOGGER.debug(CORE,"Initiating mod scan");
|
||||
FMLLoader.beginModScan();
|
||||
LOGGER.debug(CORE, "Loading access transformers");
|
||||
FMLLoader.loadAccessTransformer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
|
||||
{
|
||||
FMLLoader.onInitialLoad(environment, otherServices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arguments(BiFunction<String, String, OptionSpecBuilder> argumentBuilder)
|
||||
{
|
||||
modsOption = argumentBuilder.apply("mods", "List of mods to add").withRequiredArg().ofType(String.class).withValuesSeparatedBy(",");
|
||||
modListsOption = argumentBuilder.apply("modLists", "JSON modlists").withRequiredArg().ofType(String.class).withValuesSeparatedBy(",");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void argumentValues(OptionResult option)
|
||||
{
|
||||
modsArgumentList = option.values(modsOption);
|
||||
modListsArgumentList = option.values(modListsOption);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<ITransformer> transformers()
|
||||
{
|
||||
LOGGER.debug(CORE, "Loading coremod transformers");
|
||||
return new ArrayList<>(FMLLoader.getCoreModProvider().getCoreModTransformers());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.fml.language.IModLanguageProvider;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public class LanguageLoadingProvider
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final List<IModLanguageProvider> languageProviders = new ArrayList<>();
|
||||
private final ServiceLoader<IModLanguageProvider> serviceLoader;
|
||||
private final Map<String, ModLanguageWrapper> languageProviderMap = new HashMap<>();
|
||||
|
||||
public void forEach(final Consumer<IModLanguageProvider> consumer)
|
||||
{
|
||||
languageProviders.forEach(consumer);
|
||||
}
|
||||
|
||||
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();
|
||||
String implementationVersion = pkg.getImplementationVersion();
|
||||
if (implementationVersion == null) {
|
||||
implementationVersion = ForgeVersion.getSpec();
|
||||
}
|
||||
LOGGER.debug(CORE, "Found system classpath language provider {}, version {}", lp.name(), implementationVersion);
|
||||
languageProviderMap.put(lp.name(), new ModLanguageWrapper(lp, new DefaultArtifactVersion(implementationVersion)));
|
||||
});
|
||||
}
|
||||
|
||||
public void addAdditionalLanguages(List<ModFile> modFiles)
|
||||
{
|
||||
if (modFiles==null) return;
|
||||
Stream<Path> langPaths = modFiles.stream().map(ModFile::getFilePath);
|
||||
serviceLoader.reload();
|
||||
}
|
||||
|
||||
public IModLanguageProvider findLanguage(ModFile mf, String modLoader, VersionRange modLoaderVersion) {
|
||||
final String languageFileName = mf.getLocator() instanceof ExplodedDirectoryLocator ? "in-development" : mf.getFileName();
|
||||
final ModLanguageWrapper mlw = languageProviderMap.get(modLoader);
|
||||
if (mlw == null) {
|
||||
LOGGER.error("Missing language {} version {} wanted by {}", modLoader, modLoaderVersion, languageFileName);
|
||||
throw new EarlyLoadingException("Missing language "+modLoader, null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, "null")));
|
||||
}
|
||||
if (!modLoaderVersion.containsVersion(mlw.getVersion())) {
|
||||
LOGGER.error("Missing language {} version {} wanted by {}, found {}", modLoader, modLoaderVersion, languageFileName, mlw.getVersion());
|
||||
throw new EarlyLoadingException("Missing language "+ modLoader + " matching range "+modLoaderVersion + " found "+mlw.getVersion(), null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, mlw.getVersion())));
|
||||
}
|
||||
|
||||
return mlw.getModLanguageProvider();
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.Streams;
|
||||
import net.minecraftforge.fml.LifecycleEventProvider;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.ModLoadingStage;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Master list of all mods <em>in the loading context. This class cannot refer outside the
|
||||
* loading package</em>
|
||||
*/
|
||||
public class LoadingModList
|
||||
{
|
||||
private static LoadingModList INSTANCE;
|
||||
private final List<ModFileInfo> modFiles;
|
||||
private final List<ModInfo> sortedList;
|
||||
private final Map<String, ModFileInfo> fileById;
|
||||
private BackgroundScanHandler scanner;
|
||||
private final List<EarlyLoadingException> preLoadErrors;
|
||||
|
||||
private LoadingModList(final List<ModFile> modFiles, final List<ModInfo> sortedList)
|
||||
{
|
||||
this.modFiles = modFiles.stream().map(ModFile::getModFileInfo).map(ModFileInfo.class::cast).collect(Collectors.toList());
|
||||
this.sortedList = Streams.concat(DefaultModInfos.getModInfos().stream(), sortedList.stream()).
|
||||
map(ModInfo.class::cast).
|
||||
collect(Collectors.toList());
|
||||
this.fileById = this.modFiles.stream().map(ModFileInfo::getMods).flatMap(Collection::stream).
|
||||
map(ModInfo.class::cast).
|
||||
collect(Collectors.toMap(ModInfo::getModId, ModInfo::getOwningFile));
|
||||
this.preLoadErrors = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static LoadingModList of(List<ModFile> modFiles, List<ModInfo> sortedList, final EarlyLoadingException earlyLoadingException)
|
||||
{
|
||||
INSTANCE = new LoadingModList(modFiles, sortedList);
|
||||
if (earlyLoadingException != null)
|
||||
{
|
||||
INSTANCE.preLoadErrors.add(earlyLoadingException);
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static LoadingModList get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
public void addCoreMods()
|
||||
{
|
||||
modFiles.stream().map(ModFileInfo::getFile).map(ModFile::getCoreMods).flatMap(List::stream).forEach(FMLLoader.getCoreModProvider()::addCoreMod);
|
||||
}
|
||||
|
||||
public void addAccessTransformers()
|
||||
{
|
||||
modFiles.stream().map(ModFileInfo::getFile).forEach(mod -> mod.getAccessTransformer().ifPresent(path -> FMLLoader.addAccessTransformer(path, mod)));
|
||||
}
|
||||
|
||||
public void addForScanning(BackgroundScanHandler backgroundScanHandler)
|
||||
{
|
||||
this.scanner = backgroundScanHandler;
|
||||
backgroundScanHandler.setLoadingModList(this);
|
||||
modFiles.stream().map(ModFileInfo::getFile).forEach(backgroundScanHandler::submitForScanning);
|
||||
}
|
||||
|
||||
public List<ModFileInfo> getModFiles()
|
||||
{
|
||||
return modFiles;
|
||||
}
|
||||
|
||||
public Path findResource(final String className)
|
||||
{
|
||||
for (ModFileInfo mf : modFiles) {
|
||||
final Path resource = mf.getFile().findResource(className);
|
||||
if (Files.exists(resource)) return resource;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ModFileInfo getModFileById(String modid)
|
||||
{
|
||||
return this.fileById.get(modid);
|
||||
}
|
||||
|
||||
public List<ModInfo> getMods()
|
||||
{
|
||||
return this.sortedList;
|
||||
}
|
||||
|
||||
public List<EarlyLoadingException> getErrors() {
|
||||
return preLoadErrors;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 org.apache.logging.log4j.Logger;
|
||||
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public final class MavenVersionAdapter {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private MavenVersionAdapter() {}
|
||||
|
||||
public static VersionRange createFromVersionSpec(final String spec) {
|
||||
try {
|
||||
return VersionRange.createFromVersionSpec(spec);
|
||||
} catch (InvalidVersionSpecificationException e) {
|
||||
LOGGER.error(CORE, "Failed to parse version spec {}", spec, e);
|
||||
throw new RuntimeException("Failed to parse spec", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class ModJarURLHandler extends URLStreamHandler
|
||||
{
|
||||
// modjar:///modid!path/to/file
|
||||
@Override
|
||||
protected URLConnection openConnection(URL url) throws IOException {
|
||||
return new URLConnection(url) {
|
||||
private String modpath;
|
||||
private String modid;
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException
|
||||
{
|
||||
final String path = url.getPath();
|
||||
final String[] parts = path.split("!");
|
||||
if (parts.length!=2) throw new IOException("Illegal URL format "+path);
|
||||
modid = parts[0];
|
||||
modpath = parts[1];
|
||||
}
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException
|
||||
{
|
||||
return Files.newInputStream(FMLLoader.getLoadingModList().getModFileById(modid).getFile().findResource(modpath));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.Java9BackportUtils;
|
||||
import net.minecraftforge.fml.common.toposort.TopologicalSort;
|
||||
import net.minecraftforge.fml.language.IModInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
|
||||
public class ModSorter
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private List<ModFile> modFiles;
|
||||
private List<ModInfo> sortedList;
|
||||
private Map<String, ModInfo> modIdNameLookup;
|
||||
|
||||
private ModSorter(final List<ModFile> modFiles)
|
||||
{
|
||||
this.modFiles = modFiles;
|
||||
}
|
||||
|
||||
public static LoadingModList sort(List<ModFile> mods)
|
||||
{
|
||||
final ModSorter ms = new ModSorter(mods);
|
||||
EarlyLoadingException earlyLoadingException = null;
|
||||
try {
|
||||
ms.findLanguages();
|
||||
ms.buildUniqueList();
|
||||
ms.verifyDependencyVersions();
|
||||
ms.sort();
|
||||
} catch (EarlyLoadingException ele) {
|
||||
earlyLoadingException = ele;
|
||||
ms.sortedList = Collections.emptyList();
|
||||
}
|
||||
return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException);
|
||||
}
|
||||
|
||||
private void findLanguages() {
|
||||
modFiles.stream().forEach(mf->mf.identifyLanguage());
|
||||
}
|
||||
|
||||
private void sort()
|
||||
{
|
||||
final TopologicalSort.DirectedGraph<Supplier<ModFileInfo>> topoGraph = new TopologicalSort.DirectedGraph<>();
|
||||
modFiles.stream().map(ModFile::getModFileInfo).map(ModFileInfo.class::cast).forEach(mi -> topoGraph.addNode(() -> mi));
|
||||
modFiles.stream().map(ModFile::getModInfos).flatMap(Collection::stream).
|
||||
map(IModInfo::getDependencies).flatMap(Collection::stream).
|
||||
forEach(dep -> addDependency(topoGraph, dep));
|
||||
final List<Supplier<ModFileInfo>> sorted;
|
||||
try
|
||||
{
|
||||
sorted = TopologicalSort.topologicalSort(topoGraph);
|
||||
}
|
||||
catch (TopologicalSort.TopoSortException e)
|
||||
{
|
||||
TopologicalSort.TopoSortException.TopoSortExceptionData<Supplier<ModInfo>> data = e.getData();
|
||||
LOGGER.error(LOADING, ()-> data);
|
||||
throw new EarlyLoadingException("Sorting error", e, data.toExceptionData(mi-> mi.get().getModId()));
|
||||
}
|
||||
this.sortedList = sorted.stream().map(Supplier::get).map(ModFileInfo::getMods).
|
||||
flatMap(Collection::stream).map(ModInfo.class::cast).collect(Collectors.toList());
|
||||
this.modFiles = sorted.stream().map(Supplier::get).map(ModFileInfo::getFile).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void addDependency(TopologicalSort.DirectedGraph<Supplier<ModFileInfo>> topoGraph,IModInfo.ModVersion dep)
|
||||
{
|
||||
switch (dep.getOrdering()) {
|
||||
case BEFORE:
|
||||
topoGraph.addEdge(()->(ModFileInfo)dep.getOwner().getOwningFile(), ()->modIdNameLookup.get(dep.getModId()).getOwningFile());
|
||||
break;
|
||||
case AFTER:
|
||||
topoGraph.addEdge(()->modIdNameLookup.get(dep.getModId()).getOwningFile(), ()->(ModFileInfo)dep.getOwner().getOwningFile());
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void buildUniqueList()
|
||||
{
|
||||
final Stream<ModInfo> modInfos = modFiles.stream().map(ModFile::getModInfos).flatMap(Collection::stream).map(ModInfo.class::cast);
|
||||
final Map<String, List<ModInfo>> modIds = modInfos.collect(Collectors.groupingBy(IModInfo::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()) {
|
||||
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods.stream().
|
||||
map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod", dm.getValue().get(0))).
|
||||
collect(Collectors.toList());
|
||||
throw new EarlyLoadingException("Duplicate mods found", null, duplicateModErrors);
|
||||
}
|
||||
|
||||
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), DefaultModInfos.getModInfos().stream()).collect(Collectors.toMap(IModInfo::getModId, IModInfo::getVersion));
|
||||
final Map<IModInfo, List<IModInfo.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<IModInfo.ModVersion> mandatoryModVersions = modVersionDependencies.values().stream().flatMap(Collection::stream).
|
||||
filter(mv -> mv.isMandatory() && mv.getSide().isCorrectSide()).collect(Collectors.toSet());
|
||||
LOGGER.debug(LOADING, "Found {} mandatory requirements", mandatoryModVersions.size());
|
||||
final Set<IModInfo.ModVersion> missingVersions = mandatoryModVersions.stream().filter(mv->this.modVersionMatches(mv, modVersions)).collect(Collectors.toSet());
|
||||
LOGGER.debug(LOADING, "Found {} mandatory mod requirements missing", missingVersions.size());
|
||||
|
||||
if (!missingVersions.isEmpty()) {
|
||||
final List<EarlyLoadingException.ExceptionData> exceptionData = missingVersions.stream().map(mv ->
|
||||
new EarlyLoadingException.ExceptionData("fml.modloading.missingdependency", mv.getModId(),
|
||||
mv.getOwner().getModId(), mv.getVersionRange(), modVersions.getOrDefault(mv.getModId(), new DefaultArtifactVersion("null")))).
|
||||
collect(Collectors.toList());
|
||||
throw new EarlyLoadingException("Missing mods", null, exceptionData);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean modVersionMatches(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
|
||||
{
|
||||
return !modVersions.containsKey(mv.getModId()) || !mv.getVersionRange().containsVersion(modVersions.get(mv.getModId()));
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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 java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.Streams;
|
||||
import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class RuntimeDistCleaner implements ILaunchPluginService
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker DISTXFORM = MarkerManager.getMarker("DISTXFORM");
|
||||
private static String DIST;
|
||||
private static final String ONLYIN = Type.getDescriptor(OnlyIn.class);
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "runtimedistcleaner";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResource(Path resource, String name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassNode processClass(ClassNode classNode, Type classType)
|
||||
{
|
||||
if (remove(classNode.visibleAnnotations, DIST))
|
||||
{
|
||||
LOGGER.debug(DISTXFORM, "Attempted to load class {} for invalid dist {}", classNode.name, DIST);
|
||||
throw new RuntimeException("Attempted to load class "+ classNode.name + " for invalid dist "+ DIST);
|
||||
}
|
||||
|
||||
Iterator<FieldNode> fields = classNode.fields.iterator();
|
||||
while(fields.hasNext())
|
||||
{
|
||||
FieldNode field = fields.next();
|
||||
if (remove(field.visibleAnnotations, DIST))
|
||||
{
|
||||
LOGGER.debug(DISTXFORM,"Removing field: {}.{}", classNode.name, field.name);
|
||||
fields.remove();
|
||||
}
|
||||
}
|
||||
|
||||
LambdaGatherer lambdaGatherer = new LambdaGatherer();
|
||||
Iterator<MethodNode> methods = classNode.methods.iterator();
|
||||
while(methods.hasNext())
|
||||
{
|
||||
MethodNode method = methods.next();
|
||||
if (remove(method.visibleAnnotations, DIST))
|
||||
{
|
||||
LOGGER.debug(DISTXFORM,"Removing method: {}.{}{}", classNode.name, method.name, method.desc);
|
||||
methods.remove();
|
||||
lambdaGatherer.accept(method);
|
||||
}
|
||||
}
|
||||
|
||||
// remove dynamic lambda methods that are inside of removed methods
|
||||
List<Handle> dynamicLambdaHandles = lambdaGatherer.getDynamicLambdaHandles();
|
||||
if (!dynamicLambdaHandles.isEmpty())
|
||||
{
|
||||
methods = classNode.methods.iterator();
|
||||
while (methods.hasNext())
|
||||
{
|
||||
MethodNode method = methods.next();
|
||||
for (Handle dynamicLambdaHandle : dynamicLambdaHandles)
|
||||
{
|
||||
if (method.name.equals(dynamicLambdaHandle.getName()) && method.desc.equals(dynamicLambdaHandle.getDesc()))
|
||||
{
|
||||
LOGGER.debug(DISTXFORM,"Removing lambda method: {}.{}{}", classNode.name, method.name, method.desc);
|
||||
methods.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return classNode;
|
||||
}
|
||||
|
||||
private boolean remove(final List<AnnotationNode> anns, final String side)
|
||||
{
|
||||
return !(anns == null) && anns.stream().
|
||||
filter(ann->Objects.equals(ann.desc, ONLYIN)).
|
||||
anyMatch(ann -> !Objects.equals(((String[])ann.values.get(ann.values.indexOf("value")+1))[1], side));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Consumer<Dist> getExtension()
|
||||
{
|
||||
return (s)-> {
|
||||
DIST = s.name();
|
||||
LOGGER.debug(DISTXFORM, "Configuring for Dist {}", DIST);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlesClass(Type classType, boolean isEmpty)
|
||||
{
|
||||
return !isEmpty;
|
||||
}
|
||||
|
||||
private static class LambdaGatherer extends MethodVisitor {
|
||||
private static final Handle META_FACTORY = new Handle(Opcodes.H_INVOKESTATIC,
|
||||
"java/lang/invoke/LambdaMetafactory", "metafactory",
|
||||
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;",
|
||||
false);
|
||||
private final List<Handle> dynamicLambdaHandles = new ArrayList<>();
|
||||
|
||||
public LambdaGatherer() {
|
||||
super(Opcodes.ASM5);
|
||||
}
|
||||
|
||||
public void accept(MethodNode method) {
|
||||
Streams.stream(method.instructions.iterator()).
|
||||
filter(insnNode->insnNode.getType() == AbstractInsnNode.INVOKE_DYNAMIC_INSN).
|
||||
forEach(insnNode->insnNode.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs)
|
||||
{
|
||||
if (META_FACTORY.equals(bsm))
|
||||
{
|
||||
Handle dynamicLambdaHandle = (Handle) bsmArgs[1];
|
||||
dynamicLambdaHandles.add(dynamicLambdaHandle);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Handle> getDynamicLambdaHandles()
|
||||
{
|
||||
return dynamicLambdaHandles;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.ImmutableMap;
|
||||
import net.minecraftforge.versions.forge.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("."));
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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.commons.lang3.text.StrSubstitutor;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Created by cpw on 05/06/17.
|
||||
*/
|
||||
public class StringUtils
|
||||
{
|
||||
public static String toLowerCase(final String str) {
|
||||
return str.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
public static String toUpperCase(final String str) {
|
||||
return str.toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
public static boolean endsWith(final String search, final String... endings) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import net.minecraftforge.fml.language.ModFileScanData;
|
||||
import net.minecraftforge.fml.loading.LoadingModList;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
public class BackgroundScanHandler
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final ExecutorService modContentScanner;
|
||||
private final List<ModFile> pendingFiles;
|
||||
private final List<ModFile> scannedFiles;
|
||||
private final List<ModFile> allFiles;
|
||||
private LoadingModList loadingModList;
|
||||
|
||||
public BackgroundScanHandler() {
|
||||
modContentScanner = Executors.newSingleThreadExecutor(r -> {
|
||||
final Thread thread = Executors.defaultThreadFactory().newThread(r);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
scannedFiles = new ArrayList<>();
|
||||
pendingFiles = new ArrayList<>();
|
||||
allFiles = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void submitForScanning(final ModFile file) {
|
||||
if (modContentScanner.isShutdown()) {
|
||||
throw new IllegalStateException("Scanner has shutdown");
|
||||
}
|
||||
allFiles.add(file);
|
||||
pendingFiles.add(file);
|
||||
final CompletableFuture<ModFileScanData> future = CompletableFuture.supplyAsync(file::compileContent, modContentScanner)
|
||||
.whenComplete(file::setScanResult)
|
||||
.whenComplete((r,t)-> this.addCompletedFile(file,r,t));
|
||||
file.setFutureScanResult(future);
|
||||
}
|
||||
|
||||
private void addCompletedFile(final ModFile file, final ModFileScanData modFileScanData, final Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
LOGGER.error(SCAN,"An error occurred scanning file {}", file, throwable);
|
||||
}
|
||||
pendingFiles.remove(file);
|
||||
scannedFiles.add(file);
|
||||
}
|
||||
|
||||
public List<ModFile> getScannedFiles() {
|
||||
if (!pendingFiles.isEmpty()) {
|
||||
modContentScanner.shutdown();
|
||||
try {
|
||||
modContentScanner.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
return scannedFiles;
|
||||
}
|
||||
|
||||
public List<ModFile> getAllFiles() {
|
||||
return allFiles;
|
||||
}
|
||||
|
||||
public void setLoadingModList(LoadingModList loadingModList)
|
||||
{
|
||||
this.loadingModList = loadingModList;
|
||||
}
|
||||
|
||||
public LoadingModList getLoadingModList()
|
||||
{
|
||||
return loadingModList;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import net.minecraftforge.forgespi.ICoreModFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class CoreModFile implements ICoreModFile {
|
||||
private final Path internalPath;
|
||||
private final ModFile file;
|
||||
private final String name;
|
||||
|
||||
CoreModFile(final String name, final Path path, final ModFile file) {
|
||||
this.name = name;
|
||||
this.internalPath = path;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader readCoreMod() throws IOException {
|
||||
return Files.newBufferedReader(this.internalPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
return this.internalPath;
|
||||
}
|
||||
}
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
public class ExplodedDirectoryLocator implements IModLocator {
|
||||
private static final String DIR = System.getProperty("fml.explodedDir", "modclasses");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final Path rootDir;
|
||||
|
||||
public ExplodedDirectoryLocator() {
|
||||
this.rootDir = FileSystems.getDefault().getPath(DIR);
|
||||
if (!Files.exists(this.rootDir)) {
|
||||
LOGGER.debug(LOADING,"Creating directory {}" + this.rootDir);
|
||||
try
|
||||
{
|
||||
Files.createDirectory(this.rootDir);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOGGER.error(LOADING,"Error creating {}", this.rootDir, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModFile> scanMods() {
|
||||
return Collections.singletonList(new ModFile(rootDir, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "exploded directory";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path findPath(final ModFile modFile, final String... path) {
|
||||
if (path.length < 1) {
|
||||
throw new IllegalArgumentException("Missing path");
|
||||
}
|
||||
return rootDir.resolve(FileSystems.getDefault().getPath(path[0], Arrays.copyOfRange(path, 1, path.length)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanFile(final ModFile modFile, final Consumer<Path> pathConsumer) {
|
||||
LOGGER.debug(SCAN,"Scanning directory {}", rootDir);
|
||||
try (Stream<Path> files = Files.find(rootDir, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) {
|
||||
files.forEach(pathConsumer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
LOGGER.debug(SCAN,"Directory scan complete {}", rootDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "{ExplodedDir locator at "+this.rootDir+"}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Manifest> findManifest(Path file)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.IModLocator;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.versions.mcp.MCPVersion;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
/*
|
||||
* Locate Forge in the classpath, this works similar to ClasspathLocator.
|
||||
* Forge/Minecraft are in the following formats:
|
||||
* Runtime:
|
||||
* %lib%/net/minecraftforge/forge/{ver}/forge-{ver}.jar or ./forge-{ver}-universal.jar - Client is in libs, Server is in root
|
||||
* %lib%/net/minecraftforge/forge/{ver}/forge-{ver}-{client|server}.jar - Forge, Vanilla classes, Patched
|
||||
* %lib%/net/minecraft/{client|server}/{mcver}/{client|server}-{mcver}-srg.jar - Vanilla classes, SRG, Unpatched
|
||||
*
|
||||
* UserDev:
|
||||
* Forge and vanilla is in a single jar file, patched, on the classpath.
|
||||
*
|
||||
* Eclipse:
|
||||
* bin/{sourceset}/
|
||||
*
|
||||
* Intellij: TODO: Verify, I don't use intellij
|
||||
* out/production/resources/../classes/ - Resources are a separate folder so we have to navigate to classes
|
||||
*
|
||||
* Gradle:
|
||||
* build/classes/{language}/{sourceset}
|
||||
* build/resources/{sourceset}
|
||||
*
|
||||
*/
|
||||
public class ForgeLocator implements IModLocator
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final String FORGE_META = "forgemod.toml";
|
||||
private static final String MAIN_SOURCESET = "main";
|
||||
private static final String LIB_RESOURCE = "org/objectweb/asm/Opcodes.class";
|
||||
private static final String LIB_PATH = "org/ow2/asm/asm".replace('/', File.separatorChar);
|
||||
private List<Path> roots = new ArrayList<>();
|
||||
private boolean filterClasses = false;
|
||||
|
||||
public ForgeLocator() { }
|
||||
|
||||
@Override
|
||||
public List<ModFile> scanMods()
|
||||
{
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
URL url = loader.getResource(FORGE_META);
|
||||
if (url == null)
|
||||
throw new IllegalStateException("Could not locate \"" + FORGE_META + "\", Forge is correupt/not on classpath!");
|
||||
|
||||
File base = getRoot(url, FORGE_META);
|
||||
if (base == null)
|
||||
throw new IllegalStateException("Could not determine root for Forge resource: " + url);
|
||||
|
||||
url = loader.getResource(LIB_RESOURCE);
|
||||
if (url == null)
|
||||
throw new IllegalStateException("Could not locate \"" + LIB_RESOURCE + "\" to locate libraries directory.");
|
||||
File libs = getRoot(url, LIB_RESOURCE);
|
||||
//If In maven style the libraries folder we need to drop the file name, and version folder
|
||||
if (libs != null && libs.getParentFile().getParentFile().getAbsolutePath().endsWith(LIB_PATH))
|
||||
{
|
||||
int count = 2 + LIB_PATH.split(Pattern.quote("" + File.separatorChar)).length;
|
||||
for (int x = 0; x < count; x++)
|
||||
libs = libs.getParentFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
libs = null;
|
||||
}
|
||||
|
||||
LOGGER.info("Forge Locator: ");
|
||||
LOGGER.info(" Forge: " + base);
|
||||
LOGGER.info(" Libraries: " + libs);
|
||||
|
||||
Path path = base.toPath();
|
||||
if (base.isDirectory())
|
||||
{ // Development workspace.
|
||||
int count = path.getNameCount();
|
||||
//Eclipse: /bin/{sourceset}/
|
||||
if (count >= 2 && MAIN_SOURCESET.equals(path.getName(count - 1).toString()) && "bin".equals(path.getName(count - 2).toString()))
|
||||
{
|
||||
roots.add(path);
|
||||
roots.add(path.getParent().resolve("userdev")); //Do I need this?
|
||||
} //Intellij: /out/production/resources/ & /out/production/classes/
|
||||
else if (count >= 1 && "resources".equals(path.getName(count - 1).toString()))
|
||||
{
|
||||
roots.add(path.getParent().resolve("classes"));
|
||||
roots.add(path);
|
||||
} //Gradle: build/resources/{sourceset} & build/classes/{language}/{sourceset}
|
||||
else if (count >= 2 && MAIN_SOURCESET.equals(path.getName(count - 1).toString()) && "resources".equals(path.getName(count - 2).toString()))
|
||||
{
|
||||
Path classes = path.getParent().getParent().resolve("classes");
|
||||
roots.add(classes.resolve(MAIN_SOURCESET));
|
||||
roots.add(classes.resolve("userdev"));
|
||||
roots.add(path);
|
||||
roots.add(path.getParent().resolve("userdev"));
|
||||
}
|
||||
filterClasses = true;
|
||||
}
|
||||
else if (base.isFile())
|
||||
{
|
||||
if (libs == null) //User dev workspace.
|
||||
{
|
||||
roots.add(path);
|
||||
}
|
||||
else //Standard install
|
||||
{
|
||||
String dist = FMLEnvironment.dist == Dist.CLIENT ? "client" : "server";
|
||||
String version = MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion();
|
||||
roots.add(path); // universal
|
||||
roots.add(libs.toPath().resolve(Paths.get(ForgeVersion.getGroup().replace('.', File.separatorChar), "forge", version, "forge-" + version + "-" + dist + ".jar"))); // Patched classes
|
||||
roots.add(libs.toPath().resolve(Paths.get("net", "minecraft", dist, MCPVersion.getMCPandMCVersion(), dist + "-" + MCPVersion.getMCPandMCVersion() + "-srg.jar"))); //Vanilla jar in srg names
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
throw new IllegalStateException("Forge path is neither File or Directory... " + base);
|
||||
|
||||
if (roots.isEmpty())
|
||||
return Collections.emptyList();
|
||||
|
||||
roots.forEach(r -> LOGGER.info(" Root: " + r));
|
||||
return Collections.singletonList(new ModFile(roots.get(0), this));
|
||||
}
|
||||
|
||||
protected File getRoot(URL url, String resource)
|
||||
{
|
||||
String path = url.getPath();
|
||||
if ("jar".equals(url.getProtocol()))
|
||||
{
|
||||
int idx = path.indexOf("!/");
|
||||
path = path.substring(0, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Strip resource path off the end
|
||||
path = path.substring(0, path.length() - resource.length());
|
||||
}
|
||||
|
||||
if (path.startsWith("file:"))
|
||||
path = path.substring(5);
|
||||
|
||||
return new File(path).getAbsoluteFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "forge locator";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path findPath(final ModFile modFile, String... path)
|
||||
{
|
||||
if (path.length < 1)
|
||||
throw new IllegalArgumentException("Missing path");
|
||||
|
||||
if (path.length == 2 && "META-INF".equals(path[0]) && "mods.toml".equals(path[1]))
|
||||
path = FORGE_META.split("/");
|
||||
|
||||
if (filterClasses && path[path.length - 1].endsWith(".class"))
|
||||
path[path.length - 1] = path[path.length - 1] + "THIS_FILE_WILL_NEVER_EXITS_DIRTY_HAX";
|
||||
|
||||
String[] tail = Arrays.copyOfRange(path, 1, path.length);
|
||||
for (Path root : roots)
|
||||
{
|
||||
Path target = root.resolve(root.getFileSystem().getPath(path[0], tail));
|
||||
if (Files.exists(target))
|
||||
return target;
|
||||
}
|
||||
|
||||
return modFile.getFilePath().resolve(modFile.getFilePath().getFileSystem().getPath(path[0], tail));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanFile(final ModFile modFile, final Consumer<Path> pathConsumer)
|
||||
{
|
||||
final Set<String> visited = new HashSet<>();
|
||||
roots.stream().forEach(root ->
|
||||
{
|
||||
LOGGER.debug(SCAN,"Scanning Forge: " + root);
|
||||
try (Stream<Path> files = Files.find(root, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class")))
|
||||
{
|
||||
files.forEach(f -> {
|
||||
String relative = root.relativize(f).toString(); //TODO: Test jared files...
|
||||
if (visited.add(relative))
|
||||
pathConsumer.accept(Paths.get(relative));
|
||||
});
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
LOGGER.debug(SCAN,"Forge scan complete");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "{Forge locator}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Manifest> findManifest(Path file)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* Loaded as a ServiceLoader. Takes mechanisms for locating candidate "mods"
|
||||
* and transforms them into {@link ModFile} objects.
|
||||
*/
|
||||
public interface IModLocator {
|
||||
List<ModFile> scanMods();
|
||||
|
||||
String name();
|
||||
|
||||
Path findPath(ModFile modFile, String... path);
|
||||
|
||||
void scanFile(final ModFile modFile, Consumer<Path> pathConsumer);
|
||||
|
||||
Optional<Manifest> findManifest(Path file);
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import net.minecraftforge.fml.language.IModFileInfo;
|
||||
|
||||
public class InvalidModFileException extends RuntimeException
|
||||
{
|
||||
private final IModFileInfo modFileInfo;
|
||||
|
||||
public InvalidModFileException(String message, IModFileInfo modFileInfo)
|
||||
{
|
||||
super(message);
|
||||
this.modFileInfo = modFileInfo;
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.fml.language.ModFileScanData;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public class ModAnnotation
|
||||
{
|
||||
public static ModFileScanData.AnnotationData fromModAnnotation(final Type clazz, final ModAnnotation annotation) {
|
||||
return new ModFileScanData.AnnotationData(annotation.asmType, clazz, annotation.member, annotation.values);
|
||||
}
|
||||
|
||||
public static class EnumHolder
|
||||
{
|
||||
private final String desc;
|
||||
private final String value;
|
||||
|
||||
public EnumHolder(String desc, String value)
|
||||
{
|
||||
this.desc = desc;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getDesc()
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
ElementType type;
|
||||
Type asmType;
|
||||
String member;
|
||||
Map<String,Object> values = Maps.newHashMap();
|
||||
|
||||
private ArrayList<Object> arrayList;
|
||||
private String arrayName;
|
||||
public ModAnnotation(ElementType type, Type asmType, String member)
|
||||
{
|
||||
this.type = type;
|
||||
this.asmType = asmType;
|
||||
this.member = member;
|
||||
}
|
||||
|
||||
public ModAnnotation(ElementType type, Type asmType, ModAnnotation parent)
|
||||
{
|
||||
this.type = type;
|
||||
this.asmType = asmType;
|
||||
}
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return MoreObjects.toStringHelper("Annotation")
|
||||
.add("type",type)
|
||||
.add("name",asmType.getClassName())
|
||||
.add("member",member)
|
||||
.add("values", values)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public ElementType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
public Type getASMType()
|
||||
{
|
||||
return asmType;
|
||||
}
|
||||
public String getMember()
|
||||
{
|
||||
return member;
|
||||
}
|
||||
public Map<String, Object> getValues()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
public void addArray(String name)
|
||||
{
|
||||
this.arrayList = Lists.newArrayList();
|
||||
this.arrayName = name;
|
||||
}
|
||||
public void addProperty(String key, Object value)
|
||||
{
|
||||
if (this.arrayList != null)
|
||||
{
|
||||
arrayList.add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
values.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void addEnumProperty(String key, String enumName, String value)
|
||||
{
|
||||
addProperty(key, new EnumHolder(enumName, value));
|
||||
}
|
||||
|
||||
public void endArray()
|
||||
{
|
||||
values.put(arrayName, arrayList);
|
||||
arrayList = null;
|
||||
}
|
||||
public ModAnnotation addChildAnnotation(String name, String desc)
|
||||
{
|
||||
ModAnnotation child = new ModAnnotation(ElementType.PARAMETER, Type.getType(desc), this);
|
||||
addProperty(name, child.getValues());
|
||||
return child;
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class ModAnnotationVisitor extends AnnotationVisitor
|
||||
{
|
||||
private final ModAnnotation annotation;
|
||||
private LinkedList<ModAnnotation> annotations;
|
||||
private boolean array;
|
||||
private String name;
|
||||
private boolean isSubAnnotation;
|
||||
|
||||
public ModAnnotationVisitor(LinkedList<ModAnnotation> annotations, ModAnnotation annotation)
|
||||
{
|
||||
super(Opcodes.ASM5);
|
||||
this.annotations = annotations;
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
public ModAnnotationVisitor(LinkedList<ModAnnotation> annotations, ModAnnotation annotation, String name)
|
||||
{
|
||||
this(annotations, annotation);
|
||||
this.array = true;
|
||||
this.name = name;
|
||||
annotation.addArray(name);
|
||||
}
|
||||
|
||||
public ModAnnotationVisitor(LinkedList<ModAnnotation> annotations, ModAnnotation annotation, boolean isSubAnnotation)
|
||||
{
|
||||
this(annotations, annotation);
|
||||
this.isSubAnnotation = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String key, Object value)
|
||||
{
|
||||
annotation.addProperty(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(String name, String desc, String value)
|
||||
{
|
||||
annotation.addEnumProperty(name, desc, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(String name)
|
||||
{
|
||||
return new ModAnnotationVisitor(annotations, annotation, name);
|
||||
}
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc)
|
||||
{
|
||||
ModAnnotation ma = annotations.getFirst();
|
||||
final ModAnnotation childAnnotation = ma.addChildAnnotation(name, desc);
|
||||
annotations.addFirst(childAnnotation);
|
||||
return new ModAnnotationVisitor(annotations, childAnnotation,true);
|
||||
}
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
if (array)
|
||||
{
|
||||
annotation.endArray();
|
||||
}
|
||||
|
||||
if (isSubAnnotation)
|
||||
{
|
||||
ModAnnotation child = annotations.removeFirst();
|
||||
annotations.addLast(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import net.minecraftforge.fml.language.ModFileScanData;
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ModClassVisitor extends ClassVisitor
|
||||
{
|
||||
private Type asmType;
|
||||
private Type asmSuperType;
|
||||
private Set<Type> interfaces;
|
||||
private final LinkedList<ModAnnotation> annotations = new LinkedList<>();
|
||||
public ModClassVisitor()
|
||||
{
|
||||
super(Opcodes.ASM5);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
this.asmType = Type.getObjectType(name);
|
||||
this.asmSuperType = superName != null && superName.length() > 0 ? Type.getObjectType(superName) : null;
|
||||
this.interfaces = Stream.of(interfaces).map(Type::getObjectType).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String annotationName, final boolean runtimeVisible)
|
||||
{
|
||||
ModAnnotation ann = new ModAnnotation(ElementType.TYPE, Type.getType(annotationName), this.asmType.getClassName());
|
||||
annotations.addFirst(ann);
|
||||
return new ModAnnotationVisitor(annotations, ann);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value)
|
||||
{
|
||||
return new ModFieldVisitor(name, annotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
|
||||
{
|
||||
return new ModMethodVisitor(name, desc, annotations);
|
||||
}
|
||||
|
||||
public void buildData(final List<ModFileScanData.ClassData> classes, final List<ModFileScanData.AnnotationData> annotations) {
|
||||
classes.add(new ModFileScanData.ClassData(this.asmType, this.asmSuperType, this.interfaces));
|
||||
final List<ModFileScanData.AnnotationData> collect = this.annotations.stream().
|
||||
filter(ma->ModFileScanData.interestingAnnotations().test(ma.asmType)).
|
||||
map(a -> ModAnnotation.fromModAnnotation(this.asmType, a)).collect(Collectors.toList());
|
||||
annotations.addAll(collect);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import cpw.mods.modlauncher.ServiceLoaderStreamUtils;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.LoadingModList;
|
||||
import net.minecraftforge.fml.loading.ModSorter;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
public class ModDiscoverer {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final ServiceLoader<IModLocator> locators;
|
||||
private final List<IModLocator> locatorList;
|
||||
|
||||
public ModDiscoverer() {
|
||||
locators = ServiceLoader.load(IModLocator.class);
|
||||
locatorList = ServiceLoaderStreamUtils.toList(this.locators);
|
||||
LOGGER.debug(SCAN,"Found Mod Locators : {}", ()->locatorList.stream().map(iModLocator -> "("+iModLocator.name() + ":" + iModLocator.getClass().getPackage().getImplementationVersion()+")").collect(Collectors.joining(",")));
|
||||
}
|
||||
|
||||
ModDiscoverer(List<IModLocator> locatorList) {
|
||||
this.locatorList = locatorList;
|
||||
this.locators = null;
|
||||
}
|
||||
|
||||
public BackgroundScanHandler discoverMods() {
|
||||
LOGGER.debug(SCAN,"Scanning for mods and other resources to load. We know {} ways to find mods", locatorList.size());
|
||||
final Map<ModFile.Type, List<ModFile>> modFiles = locatorList.stream()
|
||||
.peek(loc -> LOGGER.debug(SCAN,"Trying locator {}", loc))
|
||||
.map(IModLocator::scanMods)
|
||||
.flatMap(Collection::stream)
|
||||
.peek(mf -> LOGGER.debug(SCAN,"Found mod file {} of type {} with locator {}", mf.getFileName(), mf.getType(), mf.getLocator()))
|
||||
.collect(Collectors.groupingBy(ModFile::getType));
|
||||
|
||||
FMLLoader.getLanguageLoadingProvider().addAdditionalLanguages(modFiles.get(ModFile.Type.LANGPROVIDER));
|
||||
BackgroundScanHandler backgroundScanHandler = new BackgroundScanHandler();
|
||||
final List<ModFile> mods = modFiles.getOrDefault(ModFile.Type.MOD, Collections.emptyList());
|
||||
for (Iterator<ModFile> iterator = mods.iterator(); iterator.hasNext(); )
|
||||
{
|
||||
ModFile mod = iterator.next();
|
||||
if (!mod.identifyMods()) {
|
||||
LOGGER.debug(SCAN, "Removing file {} from further analysis - it is invalid", mod);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
LOGGER.debug(SCAN,"Found {} mod files with {} mods", mods::size, ()->mods.stream().mapToInt(mf -> mf.getModInfos().size()).sum());
|
||||
final LoadingModList loadingModList = ModSorter.sort(mods);
|
||||
loadingModList.addCoreMods();
|
||||
loadingModList.addAccessTransformers();
|
||||
loadingModList.addForScanning(backgroundScanHandler);
|
||||
return backgroundScanHandler;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class ModFieldVisitor extends FieldVisitor
|
||||
{
|
||||
private final LinkedList<ModAnnotation> annotations;
|
||||
private final String fieldName;
|
||||
|
||||
public ModFieldVisitor(String name, final LinkedList<ModAnnotation> annotations)
|
||||
{
|
||||
super(Opcodes.ASM5);
|
||||
this.fieldName = name;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible)
|
||||
{
|
||||
ModAnnotation ann = new ModAnnotation(ElementType.FIELD, Type.getType(annotationName), fieldName);
|
||||
annotations.addFirst(ann);
|
||||
return new ModAnnotationVisitor(annotations, ann);
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraftforge.fml.language.IModFileInfo;
|
||||
import net.minecraftforge.fml.language.IModInfo;
|
||||
import net.minecraftforge.fml.language.ModFileScanData;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.language.IModLanguageProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
public class ModFile
|
||||
{
|
||||
private static final Manifest DEFAULTMANIFEST;
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
static {
|
||||
DEFAULTMANIFEST = new Manifest();
|
||||
DEFAULTMANIFEST.getMainAttributes().putValue("FMLModType", "MOD");
|
||||
}
|
||||
|
||||
private final String jarVersion;
|
||||
private Map<String, Object> fileProperties;
|
||||
private IModLanguageProvider loader;
|
||||
|
||||
public void setFileProperties(Map<String, Object> fileProperties)
|
||||
{
|
||||
this.fileProperties = fileProperties;
|
||||
}
|
||||
|
||||
public IModLanguageProvider getLoader()
|
||||
{
|
||||
return loader;
|
||||
}
|
||||
|
||||
public Path findResource(String className)
|
||||
{
|
||||
return locator.findPath(this, className);
|
||||
}
|
||||
|
||||
public void identifyLanguage() {
|
||||
this.loader = FMLLoader.getLanguageLoadingProvider().findLanguage(this, this.modFileInfo.getModLoader(), this.modFileInfo.getModLoaderVersion());
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
MOD, LIBRARY, LANGPROVIDER
|
||||
}
|
||||
private final Path filePath;
|
||||
private final Type modFileType;
|
||||
private final Manifest manifest;
|
||||
private final IModLocator locator;
|
||||
private IModFileInfo modFileInfo;
|
||||
private ModFileScanData fileModFileScanData;
|
||||
private CompletableFuture<ModFileScanData> futureScanResult;
|
||||
private List<CoreModFile> coreMods;
|
||||
private Path accessTransformer;
|
||||
|
||||
private static final Attributes.Name TYPE = new Attributes.Name("FMLModType");
|
||||
|
||||
public ModFile(final Path file, final IModLocator locator) {
|
||||
this.locator = locator;
|
||||
this.filePath = file;
|
||||
manifest = locator.findManifest(file).orElse(DEFAULTMANIFEST);
|
||||
if (manifest != DEFAULTMANIFEST) LOGGER.debug(SCAN,"Mod file {} has a manifest", file);
|
||||
else LOGGER.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;
|
||||
}
|
||||
|
||||
public Path getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public List<IModInfo> getModInfos() {
|
||||
return modFileInfo.getMods();
|
||||
}
|
||||
|
||||
public Optional<Path> getAccessTransformer() {
|
||||
return Optional.ofNullable(Files.exists(accessTransformer) ? accessTransformer : null);
|
||||
}
|
||||
public boolean identifyMods() {
|
||||
this.modFileInfo = ModFileParser.readModList(this);
|
||||
if (this.modFileInfo == null) return false;
|
||||
LOGGER.debug(LOADING,"Loading mod file {} with language {}", this.getFilePath(), this.modFileInfo.getModLoader());
|
||||
this.coreMods = ModFileParser.getCoreMods(this);
|
||||
this.coreMods.forEach(mi-> LOGGER.debug(LOADING,"Found coremod {}", mi.getPath()));
|
||||
this.accessTransformer = locator.findPath(this, "META-INF", "accesstransformer.cfg");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public List<CoreModFile> getCoreMods() {
|
||||
return coreMods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run in an executor thread to harvest the class and annotation list
|
||||
*/
|
||||
public ModFileScanData compileContent() {
|
||||
return new Scanner(this).scan();
|
||||
}
|
||||
|
||||
public void scanFile(Consumer<Path> pathConsumer) {
|
||||
locator.scanFile(this, pathConsumer);
|
||||
}
|
||||
public void setFutureScanResult(CompletableFuture<ModFileScanData> future)
|
||||
{
|
||||
this.futureScanResult = future;
|
||||
}
|
||||
|
||||
public ModFileScanData getScanResult() {
|
||||
if (this.futureScanResult != null) {
|
||||
try {
|
||||
this.futureScanResult.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return this.fileModFileScanData;
|
||||
}
|
||||
|
||||
public void setScanResult(final ModFileScanData modFileScanData, final Throwable throwable) {
|
||||
this.futureScanResult = null;
|
||||
this.fileModFileScanData = modFileScanData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Mod File: " + Objects.toString(this.filePath);
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return getFilePath().getFileName().toString();
|
||||
}
|
||||
|
||||
public IModLocator getLocator() {
|
||||
return locator;
|
||||
}
|
||||
|
||||
public IModFileInfo getModFileInfo() {
|
||||
return modFileInfo;
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import net.minecraftforge.fml.loading.MavenVersionAdapter;
|
||||
import net.minecraftforge.fml.language.IModFileInfo;
|
||||
import net.minecraftforge.fml.language.IModInfo;
|
||||
import net.minecraftforge.fml.loading.StringUtils;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ModFileInfo implements IModFileInfo
|
||||
{
|
||||
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<IModInfo> mods;
|
||||
private final Map<String,Object> properties;
|
||||
|
||||
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(MavenVersionAdapter::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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IModInfo> getMods()
|
||||
{
|
||||
return mods;
|
||||
}
|
||||
|
||||
public ModFile getFile()
|
||||
{
|
||||
return this.modFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableConfig getConfig()
|
||||
{
|
||||
return this.config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUpdateURL(IModFileInfo modFileInfo)
|
||||
{
|
||||
return this.updateJSONURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModLoader()
|
||||
{
|
||||
return modLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VersionRange getModLoaderVersion()
|
||||
{
|
||||
return modLoaderVersion;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.minecraftforge.fml.language.IModFileInfo;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
|
||||
public class ModFileParser {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
public static IModFileInfo readModList(final ModFile modFile) {
|
||||
LOGGER.debug(LOADING,"Parsing mod file candidate {}", modFile.getFilePath());
|
||||
final Path modsjson = modFile.getLocator().findPath(modFile, "META-INF", "mods.toml");
|
||||
if (!Files.exists(modsjson)) {
|
||||
LOGGER.warn(LOADING, "Mod file {} is missing mods.toml file", modFile);
|
||||
return null;
|
||||
}
|
||||
return loadModFile(modFile, modsjson);
|
||||
}
|
||||
|
||||
public static IModFileInfo loadModFile(final ModFile file, final Path modsjson)
|
||||
{
|
||||
final FileConfig fileConfig = FileConfig.builder(modsjson).build();
|
||||
fileConfig.load();
|
||||
fileConfig.close();
|
||||
return new ModFileInfo(file, fileConfig);
|
||||
}
|
||||
|
||||
protected static List<CoreModFile> getCoreMods(final ModFile modFile) {
|
||||
Map<String,String> coreModPaths;
|
||||
try {
|
||||
final Path coremodsjson = modFile.getLocator().findPath(modFile, "META-INF", "coremods.json");
|
||||
if (!Files.exists(coremodsjson)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final Type type = new TypeToken<Map<String, String>>() {}.getType();
|
||||
final Gson gson = new Gson();
|
||||
coreModPaths = gson.fromJson(Files.newBufferedReader(coremodsjson), type);
|
||||
} catch (IOException e) {
|
||||
LOGGER.debug(LOADING,"Failed to read coremod list coremods.json", e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return coreModPaths.entrySet().stream().
|
||||
peek(e-> LOGGER.debug(LOADING,"Found coremod {} with Javascript path {}", e.getKey(), e.getValue())).
|
||||
map(e -> new CoreModFile(e.getKey(), modFile.getLocator().findPath(modFile, e.getValue()),modFile)).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import net.minecraftforge.fml.language.IModInfo;
|
||||
import net.minecraftforge.fml.loading.StringSubstitutor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
|
||||
public class ModInfo implements IModInfo
|
||||
{
|
||||
private static final DefaultArtifactVersion DEFAULT_VERSION = new DefaultArtifactVersion("1");
|
||||
private final ModFileInfo owningFile;
|
||||
private final String modId;
|
||||
private final ArtifactVersion version;
|
||||
private final String displayName;
|
||||
private final String description;
|
||||
private final List<IModInfo.ModVersion> dependencies;
|
||||
private final Map<String,Object> properties;
|
||||
private final UnmodifiableConfig modConfig;
|
||||
|
||||
public ModInfo(final ModFileInfo owningFile, final UnmodifiableConfig modConfig)
|
||||
{
|
||||
this.owningFile = owningFile;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModFileInfo getOwningFile() {
|
||||
return owningFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModId() {
|
||||
return modId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName()
|
||||
{
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return this.description;
|
||||
}
|
||||
@Override
|
||||
public ArtifactVersion getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IModInfo.ModVersion> getDependencies() {
|
||||
return this.dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableConfig getModConfig() {
|
||||
return this.modConfig;
|
||||
}
|
||||
|
||||
public Optional<String> getLogoFile()
|
||||
{
|
||||
return this.owningFile != null ? this.owningFile.getConfig().getOptional("logoFile") : this.modConfig.getOptional("logoFile");
|
||||
}
|
||||
|
||||
public boolean hasConfigUI()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class ModMethodVisitor extends MethodVisitor {
|
||||
|
||||
private final LinkedList<ModAnnotation> annotations;
|
||||
private String methodName;
|
||||
private String methodDescriptor;
|
||||
|
||||
public ModMethodVisitor(String name, String desc, final LinkedList<ModAnnotation> annotations)
|
||||
{
|
||||
super(Opcodes.ASM5);
|
||||
this.methodName = name;
|
||||
this.methodDescriptor = desc;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible)
|
||||
{
|
||||
ModAnnotation ann = new ModAnnotation(ElementType.METHOD, Type.getType(annotationName), methodName+methodDescriptor);
|
||||
annotations.addFirst(ann);
|
||||
return new ModAnnotationVisitor(annotations, ann);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import net.minecraftforge.fml.loading.StringUtils;
|
||||
import net.minecraftforge.fml.loading.FMLPaths;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipError;
|
||||
|
||||
import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.uncheck;
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
/**
|
||||
* Support loading mods located in JAR files in the mods folder
|
||||
*/
|
||||
public class ModsFolderLocator implements IModLocator {
|
||||
private static final String SUFFIX = ".jar";
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final Path modFolder;
|
||||
private final Map<ModFile, FileSystem> modJars;
|
||||
public ModsFolderLocator() {
|
||||
this(FMLPaths.MODSDIR.get());
|
||||
}
|
||||
|
||||
ModsFolderLocator(Path modFolder) {
|
||||
this.modFolder = modFolder;
|
||||
this.modJars = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModFile> scanMods() {
|
||||
LOGGER.debug(SCAN,"Scanning mods dir {} for mods", this.modFolder);
|
||||
return uncheck(()-> Files.list(this.modFolder)).
|
||||
sorted(Comparator.comparing(path-> StringUtils.toLowerCase(path.getFileName().toString()))).
|
||||
filter(p->StringUtils.toLowerCase(p.getFileName().toString()).endsWith(SUFFIX)).
|
||||
map(p->new ModFile(p, this)).
|
||||
peek(f->modJars.compute(f, (mf, fs)->createFileSystem(mf))).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "mods folder";
|
||||
}
|
||||
|
||||
private FileSystem createFileSystem(ModFile modFile) {
|
||||
try {
|
||||
return FileSystems.newFileSystem(modFile.getFilePath(), modFile.getClass().getClassLoader());
|
||||
} catch (ZipError | IOException e) {
|
||||
LOGGER.debug(SCAN,"Ignoring invalid JAR file {}", modFile.getFilePath());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path findPath(final ModFile modFile, final String... path) {
|
||||
if (path.length < 1) {
|
||||
throw new IllegalArgumentException("Missing path");
|
||||
}
|
||||
return modJars.get(modFile).getPath(path[0], Arrays.copyOfRange(path, 1, path.length));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanFile(final ModFile file, final Consumer<Path> pathConsumer) {
|
||||
LOGGER.debug(SCAN,"Scan started: {}", file);
|
||||
FileSystem fs = modJars.get(file);
|
||||
fs.getRootDirectories().forEach(path -> {
|
||||
try (Stream<Path> files = Files.find(path, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) {
|
||||
files.forEach(pathConsumer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
LOGGER.debug(SCAN,"Scan finished: {}", file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{ModJarsFolder locator at "+this.modFolder+"}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Manifest> findManifest(final Path file)
|
||||
{
|
||||
try (JarFile jf = new JarFile(file.toFile()))
|
||||
{
|
||||
return Optional.ofNullable(jf.getManifest());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-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;
|
||||
|
||||
import net.minecraftforge.fml.language.IModLanguageProvider;
|
||||
import net.minecraftforge.fml.language.ModFileScanData;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
public class Scanner {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final ModFile fileToScan;
|
||||
|
||||
public Scanner(final ModFile fileToScan) {
|
||||
this.fileToScan = fileToScan;
|
||||
}
|
||||
|
||||
public ModFileScanData scan() {
|
||||
ModFileScanData result = new ModFileScanData();
|
||||
fileToScan.scanFile(p -> fileVisitor(p, result));
|
||||
final IModLanguageProvider loader = fileToScan.getLoader();
|
||||
LOGGER.debug(SCAN, "Scanning {} with language loader {}", fileToScan.getFilePath(), loader.name());
|
||||
loader.getFileVisitor().accept(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void fileVisitor(final Path path, final ModFileScanData result) {
|
||||
try {
|
||||
LOGGER.debug(SCAN,"Scanning {} path {}", fileToScan, path);
|
||||
ModClassVisitor mcv = new ModClassVisitor();
|
||||
ClassReader cr = new ClassReader(Files.newInputStream(path));
|
||||
cr.accept(mcv, 0);
|
||||
mcv.buildData(result.getClasses(), result.getAnnotations());
|
||||
} catch (IOException e) {
|
||||
// mark path bad
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,13 +37,11 @@ import java.util.stream.Collectors;
|
||||
public class ResourcePackLoader
|
||||
{
|
||||
private static Map<ModFile, ModFileResourcePack> modResourcePacks;
|
||||
private static AbstractResourcePack forgePack;
|
||||
private static ResourcePackList<?> resourcePackList;
|
||||
|
||||
public static IResourcePack getResourcePackFor(String modId)
|
||||
{
|
||||
if (modId == "forge") return forgePack;
|
||||
else return modResourcePacks.get(ModList.get().getModFileById(modId).getFile());
|
||||
return modResourcePacks.get(ModList.get().getModFileById(modId).getFile());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -56,9 +54,6 @@ public class ResourcePackLoader
|
||||
modResourcePacks = ModList.get().getModFiles().stream().
|
||||
map(mf -> new ModFileResourcePack(mf.getFile())).
|
||||
collect(Collectors.toMap(ModFileResourcePack::getModFile, Function.identity()));
|
||||
forgePack = Files.isDirectory(FMLLoader.getForgePath()) ?
|
||||
new ForgeFolderPack(FMLLoader.getForgePath().toFile()) :
|
||||
new ForgeFilePack(FMLLoader.getForgePath().toFile());
|
||||
resourcePacks.addPackFinder(new ModPackFinder());
|
||||
}
|
||||
|
||||
@@ -111,8 +106,7 @@ public class ResourcePackLoader
|
||||
@Override
|
||||
public <T extends ResourcePackInfo> void addPackInfosToMap(Map<String, T> packList, ResourcePackInfo.IFactory<T> factory)
|
||||
{
|
||||
packList.put("forge", ResourcePackInfo.func_195793_a("forge", true, ()->forgePack, factory, ResourcePackInfo.Priority.BOTTOM));
|
||||
for (Entry<ModFile, ModFileResourcePack> e : modResourcePacks.entrySet())
|
||||
for (Entry<ModFile, ModFileResourcePack> e : modResourcePacks.entrySet())
|
||||
{
|
||||
String name = "modfile/" + e.getKey().getFileName();
|
||||
packList.put(name, ResourcePackInfo.func_195793_a(name, true, ()->e.getValue(), factory, ResourcePackInfo.Priority.BOTTOM));
|
||||
|
||||
Reference in new issue
Block a user