Fix up all the things. Removed SidedProvider because it served no real purpose anymore.

Signed-off-by: cpw <cpw+github@weeksfamily.ca>
This commit is contained in:
cpw committed 2020-08-31 21:00:44 -04:00
1 parent 16b82bb97b
commit 2e42340dfa
20 files changed
+282 -204

No files matched your search

@@ -1,13 +1,18 @@
package net.minecraftforge.event;
import com.google.common.collect.ImmutableList;
import net.minecraft.profiler.IProfiler;
import net.minecraft.resources.DataPackRegistries;
import net.minecraft.resources.IFutureReloadListener;
import net.minecraft.resources.IResourceManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.ModLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
/**
* The main ResourceManager is recreated on each reload, through {@link DataPackRegistries}'s creation.
@@ -30,7 +35,7 @@ public class AddReloadListenerEvent extends Event
*/
public void addListener(IFutureReloadListener listener)
{
listeners.add(listener);
listeners.add(new WrappedStateAwareListener(listener));
}
public List<IFutureReloadListener> getListeners()
@@ -42,4 +47,19 @@ public class AddReloadListenerEvent extends Event
{
return dataPackRegistries;
}
private static class WrappedStateAwareListener implements IFutureReloadListener {
private final IFutureReloadListener wrapped;
private WrappedStateAwareListener(final IFutureReloadListener wrapped) {
this.wrapped = wrapped;
}
@Override
public CompletableFuture<Void> reload(final IStage stage, final IResourceManager resourceManager, final IProfiler preparationsProfiler, final IProfiler reloadProfiler, final Executor backgroundExecutor, final Executor gameExecutor) {
if (ModLoader.isLoadingStateValid())
return wrapped.reload(stage, resourceManager, preparationsProfiler, reloadProfiler, backgroundExecutor, gameExecutor);
else
return CompletableFuture.completedFuture(null);
}
}
}
@@ -0,0 +1,34 @@
package net.minecraftforge.fml;
import net.minecraft.util.registry.Bootstrap;
import net.minecraftforge.client.model.generators.ExistingFileHelper;
import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Set;
public class DatagenModLoader {
private static final Logger LOGGER = LogManager.getLogger();
private static GatherDataEvent.DataGeneratorConfig dataGeneratorConfig;
private static ExistingFileHelper existingFileHelper;
private static boolean runningDataGen;
public static boolean isRunningDataGen() {
return runningDataGen;
}
public static void begin(final Set<String> mods, final Path path, final java.util.Collection<Path> inputs, Collection<Path> existingPacks, final boolean serverGenerators, final boolean clientGenerators, final boolean devToolGenerators, final boolean reportsGenerator, final boolean structureValidator, final boolean flat) {
if (mods.contains("minecraft") && mods.size() == 1) return;
LOGGER.info("Initializing Data Gatherer for mods {}", mods);
runningDataGen = true;
Bootstrap.register();
dataGeneratorConfig = new GatherDataEvent.DataGeneratorConfig(mods, path, inputs, serverGenerators, clientGenerators, devToolGenerators, reportsGenerator, structureValidator, flat);
existingFileHelper = new ExistingFileHelper(existingPacks, structureValidator);
ModLoader.get().gatherAndInitializeMods(ModWorkManager.syncExecutor(), ModWorkManager.parallelExecutor(), ()->{});
ModLoader.get().runEventGenerator(mc->new GatherDataEvent(mc, dataGeneratorConfig.makeGenerator(p->dataGeneratorConfig.isFlat() ? p : p.resolve(mc.getModId()), dataGeneratorConfig.getMods().contains(mc.getModId())), dataGeneratorConfig, existingFileHelper));
dataGeneratorConfig.runAll();
}
}
@@ -21,11 +21,7 @@ package net.minecraftforge.fml;
import static net.minecraftforge.fml.Logging.LOADING;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.Executor;
@@ -33,6 +29,7 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import net.minecraftforge.fml.event.lifecycle.ParallelDispatchEvent;
import net.minecraftforge.fml.javafmlmod.FMLModContainer;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -97,6 +94,20 @@ public class DeferredWorkQueue
return CompletableFuture.supplyAsync(work, r->tasks.add(new TaskInfo(modInfo, r)));
}
/**
* DEPRECATED FOR REMOVAL. Use {@link ParallelDispatchEvent#enqueueWork(Runnable)} or {@link ParallelDispatchEvent#enqueueWork(Supplier)}
*
* @param workToEnqueue Runnable to execute later
* @return a completable future
*/
@Deprecated
public static CompletableFuture<Void> runLater(Runnable workToEnqueue) {
return
Optional.ofNullable(ModLoadingContext.get().getActiveContainer().modLoadingStage.getDeferredWorkQueue())
.map(wq->wq.enqueueWork(ModLoadingContext.get().getActiveContainer().modInfo, workToEnqueue))
.orElseGet(()->CompletableFuture.completedFuture(null));
}
static class TaskInfo
{
public final IModInfo owner;
@@ -19,6 +19,7 @@
package net.minecraftforge.fml;
import com.google.common.base.CharMatcher;
import net.minecraftforge.fml.loading.StringUtils;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import org.apache.commons.lang3.text.ExtendedMessageFormat;
@@ -33,14 +34,22 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import static net.minecraftforge.fml.Logging.CORE;
//TODO, this should be re-evaluated now that ITextComponents are passed everywhere instaed of strings.
public class ForgeI18n {
private static final Logger LOGGER = LogManager.getLogger();
// From FontRenderer.renderCharAtPos
private static final String ALLOWED_CHARS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
private static final CharMatcher DISALLOWED_CHAR_MATCHER = CharMatcher.anyOf(ALLOWED_CHARS).negate();
private static Map<String,String> i18n;
private static Map<String,FormatFactory> customFactories;
// From StringUtils
private static final Pattern PATTERN_CONTROL_CODE = Pattern.compile("(?i)\\u00A7[0-9A-FK-OR]");
static {
customFactories = new HashMap<>();
@@ -102,6 +111,16 @@ public class ForgeI18n {
return extendedMessageFormat.format(args);
}
public static String stripSpecialChars(String message)
{
// We can't handle many unicode points in the splash renderer
return DISALLOWED_CHAR_MATCHER.removeFrom(stripControlCodes(message));
}
public static String stripControlCodes(String text) {
return PATTERN_CONTROL_CODE.matcher(text).replaceAll("");
}
public static class CustomReadOnlyFormat extends Format {
private final BiConsumer<StringBuffer, Object> formatter;
@@ -112,8 +112,7 @@ public class ModLoader
private final List<ModLoadingException> loadingExceptions;
private final List<ModLoadingWarning> loadingWarnings;
private GatherDataEvent.DataGeneratorConfig dataGeneratorConfig;
private ExistingFileHelper existingFileHelper;
private boolean loadingStateValid;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private final Optional<Consumer<String>> statusConsumer = StartupMessageManager.modLoaderConsumer();
@@ -162,6 +161,7 @@ public class ModLoader
* @param periodicTask Optional periodic task to perform on the main thread while other activities run
*/
public void gatherAndInitializeMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask) {
loadingStateValid = true;
statusConsumer.ifPresent(c->c.accept("Waiting for scan to complete"));
FMLLoader.backgroundScanHandler.waitForScanToComplete(periodicTask);
statusConsumer.ifPresent(c->c.accept("Loading mods"));
@@ -174,6 +174,7 @@ public class ModLoader
if (!this.loadingExceptions.isEmpty()) {
LOGGER.fatal(CORE, "Error during pre-loading phase", loadingExceptions.get(0));
modList.setLoadedMods(Collections.emptyList());
loadingStateValid = false;
throw new LoadingFailedException(loadingExceptions);
}
statusConsumer.ifPresent(c->c.accept("Building Mod List"));
@@ -185,6 +186,7 @@ public class ModLoader
if (!loadingExceptions.isEmpty()) {
LOGGER.fatal(CORE, "Failed to initialize mod containers", loadingExceptions.get(0));
modList.setLoadedMods(Collections.emptyList());
loadingStateValid = false;
throw new LoadingFailedException(loadingExceptions);
}
modList.setLoadedMods(modContainers);
@@ -225,21 +227,29 @@ public class ModLoader
}
private void dispatchAndHandleError(ModLoadingStage state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker) {
if (!isLoadingStateValid()) {
LOGGER.error("Cowardly refusing to process mod state change request from {}", state);
return;
}
waitForTransition(state, syncExecutor, ticker, state.buildTransition(syncExecutor, parallelExecutor));
}
private void dispatchAndHandleError(ModLoadingStage state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask) {
if (!isLoadingStateValid()) {
LOGGER.error("Cowardly refusing to process mod state change request from {}", state);
return;
}
waitForTransition(state, syncExecutor, ticker, state.buildTransition(syncExecutor, parallelExecutor, preSyncTask, postSyncTask));
}
private void waitForTransition(final ModLoadingStage state, final ModWorkManager.DrivenExecutor syncExecutor, final Runnable ticker, final CompletableFuture<List<Throwable>> transition) {
while (!transition.isDone()) {
ticker.run();
syncExecutor.drive();
syncExecutor.drive(ticker);
}
try {
transition.join();
} catch (CompletionException e) {
loadingStateValid = false;
Throwable t = e.getCause();
final List<Throwable> notModLoading = Arrays.stream(t.getSuppressed())
.filter(obj -> !(obj instanceof ModLoadingException))
@@ -292,7 +302,27 @@ public class ModLoader
}
}
/**
* @return If the current mod loading state is valid. Use if you interact with vanilla systems directly during loading
* and don't want to cause extraneous crashes due to trying to do things that aren't possible in a "broken load"
*/
public static boolean isLoadingStateValid() {
return get().loadingStateValid;
}
public <T extends Event & IModBusEvent> void runEventGenerator(Function<ModContainer, T> generator) {
if (!loadingStateValid) {
LOGGER.error("Cowardly refusing to send event generator to a broken mod state");
return;
}
ModList.get().forEachModContainer((id, mc) -> mc.acceptEvent(generator.apply(mc)));
}
public <T extends Event & IModBusEvent> void postEvent(T e) {
if (!loadingStateValid) {
LOGGER.error("Cowardly refusing to send event {} to a broken mod state", e.getClass().getName());
return;
}
ModList.get().forEachModContainer((id, mc) -> mc.acceptEvent(e));
}
@@ -311,20 +341,4 @@ public class ModLoader
public static boolean isDataGenRunning () {
return runningDataGen;
}
public void runDataGenerator(final Set<String> mods, final Path path, final Collection<Path> inputs, Collection<Path> existingPacks, final boolean serverGenerators, final boolean clientGenerators, final boolean devToolGenerators, final boolean reportsGenerator, final boolean structureValidator, final boolean flat) {
// if (mods.contains("minecraft") && mods.size() == 1) return;
// LOGGER.info("Initializing Data Gatherer for mods {}", mods);
// runningDataGen = true;
// Bootstrap.register();
// dataGeneratorConfig = new GatherDataEvent.DataGeneratorConfig(mods, path, inputs, serverGenerators, clientGenerators, devToolGenerators, reportsGenerator, structureValidator, flat);
// existingFileHelper = new ExistingFileHelper(existingPacks, structureValidator);
// gatherAndInitializeMods(() -> {});
// dispatchAndHandleError(LifecycleEventProvider.GATHERDATA, Runnable::run, () -> {});
// dataGeneratorConfig.runAll();
}
public Function<ModContainer, ModLifecycleEvent> getDataGeneratorEvent() {
return mc -> new GatherDataEvent(mc, dataGeneratorConfig.makeGenerator(p->dataGeneratorConfig.isFlat() ? p : p.resolve(mc.getModId()), dataGeneratorConfig.getMods().contains(mc.getModId())), dataGeneratorConfig, existingFileHelper);
}
}
@@ -28,6 +28,7 @@ public class ModLoadingContext
{
private static ThreadLocal<ModLoadingContext> context = ThreadLocal.withInitial(ModLoadingContext::new);
private Object languageExtension;
private ModLoadingStage stage;
public static ModLoadingContext get() {
return context.get();
@@ -20,7 +20,9 @@
package net.minecraftforge.fml;
import com.google.common.collect.Streams;
import net.minecraft.util.StringUtils;
import net.minecraftforge.fml.loading.EarlyLoadingException;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.forgespi.language.IModInfo;
import java.util.Arrays;
@@ -79,4 +81,11 @@ public class ModLoadingException extends RuntimeException
public String getMessage() {
return formatToString();
}
public IModInfo getModInfo() {
return modInfo;
}
public String getCleanMessage() {
return ForgeI18n.stripControlCodes(formatToString());
}
}
@@ -57,14 +57,14 @@ public enum ModLoadingStage
ENQUEUE_IMC(InterModEnqueueEvent.class),
PROCESS_IMC(InterModProcessEvent.class),
COMPLETE(FMLLoadCompleteEvent.class),
DONE(),
GATHERDATA();
DONE();
private final Supplier<Stream<EventGenerator<?>>> eventFunctionStream;
private final EventDispatcher<?> eventManager;
private final Optional<Class<? extends ParallelDispatchEvent>> parallelEventClass;
private final ThreadSelector threadSelector;
private final BiFunction<Executor, CompletableFuture<List<Throwable>>, CompletableFuture<List<Throwable>>> finalActivityGenerator;
private DeferredWorkQueue deferredWorkQueue;
ModLoadingStage(Class<? extends ParallelDispatchEvent> parallelClass) {
final EventGenerator<?> event = EventGenerator.fromFunction(LamdbaExceptionUtils.rethrowFunction((ModContainer mc) -> parallelClass.getConstructor(ModContainer.class).newInstance(mc)));
@@ -72,7 +72,7 @@ public enum ModLoadingStage
this.threadSelector = ThreadSelector.PARALLEL;
this.eventManager = EventDispatcher.identity();
this.parallelEventClass = Optional.of(parallelClass);
final DeferredWorkQueue deferredWorkQueue = new DeferredWorkQueue(this, parallelClass);
deferredWorkQueue = new DeferredWorkQueue(this, parallelClass);
this.finalActivityGenerator = (e, prev) -> prev.thenApplyAsync((List<Throwable> t) -> {
deferredWorkQueue.runTasks();
return t;
@@ -145,6 +145,10 @@ public enum ModLoadingStage
}
}
public DeferredWorkQueue getDeferredWorkQueue() {
return deferredWorkQueue;
}
public interface EventGenerator<T extends Event & IModBusEvent> extends Function<ModContainer, T> {
static <FN extends Event & IModBusEvent> EventGenerator<FN> fromFunction(Function<ModContainer, FN> fn) {
return fn::apply;
@@ -17,10 +17,10 @@ public class ModWorkManager {
boolean selfDriven();
boolean driveOne();
default void drive() {
default void drive(Runnable ticker) {
if (!selfDriven()) {
while (driveOne())
;
ticker.run();
}
}
}
@@ -1,78 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml;
import net.minecraft.client.Minecraft;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.client.ClientHooks;
import net.minecraftforge.fml.loading.FMLEnvironment;
import java.util.function.Function;
import java.util.function.Supplier;
public enum SidedProvider
{
// All of these need to be careful not to directly dereference the client and server elements in their signatures
DATAFIXER(
c->c.get().getDataFixer(),
s->s.get().getDataFixer(),
()-> { throw new UnsupportedOperationException(); }),
STRIPCHARS(
(Function<Supplier<Minecraft>, Function<String, String>>)c-> ClientHooks::stripSpecialChars,
s-> str->str,
()-> str->str);
private static Supplier<Minecraft> client;
private static Supplier<DedicatedServer> server;
public static void setClient(Supplier<Minecraft> client)
{
SidedProvider.client = client;
}
public static void setServer(Supplier<DedicatedServer> server)
{
SidedProvider.server = server;
}
private final Function<Supplier<Minecraft>, ?> clientSide;
private final Function<Supplier<DedicatedServer>, ?> serverSide;
private final Supplier<?> testSide;
<T> SidedProvider(Function<Supplier<Minecraft>, T> clientSide, Function<Supplier<DedicatedServer>, T> serverSide, Supplier<T> testSide)
{
this.clientSide = clientSide;
this.serverSide = serverSide;
this.testSide = testSide;
}
@SuppressWarnings("unchecked")
public <T> T get() {
if (FMLEnvironment.dist == Dist.CLIENT) {
return (T)this.clientSide.apply(client);
}
else if (FMLEnvironment.dist == Dist.DEDICATED_SERVER) {
return (T)this.serverSide.apply(server);
}
else {
return (T)this.testSide.get();
}
}
}
@@ -75,9 +75,6 @@ public class ClientHooks
{
private static final Logger LOGGER = LogManager.getLogger();
private static final Marker CLIENTHOOKS = MarkerManager.getMarker("CLIENTHOOKS");
// From FontRenderer.renderCharAtPos
private static final String ALLOWED_CHARS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
private static final CharMatcher DISALLOWED_CHAR_MATCHER = CharMatcher.anyOf(ALLOWED_CHARS).negate();
private static final ResourceLocation iconSheet = new ResourceLocation(ForgeVersion.MOD_ID, "textures/gui/icons.png");
@Nullable
@@ -197,12 +194,6 @@ public class ClientHooks
}
public static String stripSpecialChars(String message)
{
// We can't handle many unicode points in the splash renderer
return DISALLOWED_CHAR_MATCHER.removeFrom(net.minecraft.util.StringUtils.stripControlCodes(message));
}
private static SetMultimap<String,ResourceLocation> missingTextures = HashMultimap.create();
private static Set<String> badTextureDomains = Sets.newHashSet();
private static Table<String, String, Set<ResourceLocation>> brokenTextures = HashBasedTable.create();
@@ -22,32 +22,40 @@ package net.minecraftforge.fml.client;
import static net.minecraftforge.fml.Logging.CORE;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.resources.IFutureReloadListener;
import net.minecraft.resources.IPackNameDecorator;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourceManager;
import net.minecraft.resources.ResourcePackInfo;
import net.minecraft.resources.ResourcePackList;
import net.minecraft.util.datafix.codec.DatapackCodec;
import net.minecraftforge.fml.BrandingControl;
import net.minecraftforge.fml.LoadingFailedException;
import net.minecraftforge.fml.LogicalSidedProvider;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.ModLoadingStage;
import net.minecraftforge.fml.ModLoadingWarning;
import net.minecraftforge.fml.ModWorkManager;
import net.minecraftforge.fml.SidedProvider;
import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -80,22 +88,41 @@ public class ClientModLoader
private static final Logger LOGGER = LogManager.getLogger();
private static boolean loading;
private static Minecraft mc;
private static boolean loadingComplete;
private static LoadingFailedException error;
private static EarlyLoaderGUI earlyLoaderGUI;
private static class SpacedRunnable implements Runnable {
static final long NANO_SLEEP_TIME = TimeUnit.MILLISECONDS.toNanos(50);
private final Runnable wrapped;
private long lastRun;
private SpacedRunnable(final Runnable wrapped) {
this.wrapped = wrapped;
this.lastRun = System.nanoTime() - NANO_SLEEP_TIME;
}
@Override
public void run() {
if (System.nanoTime() - this.lastRun > NANO_SLEEP_TIME) {
wrapped.run();
this.lastRun = System.nanoTime();
}
}
}
public static void begin(final Minecraft minecraft, final ResourcePackList<ClientResourcePackInfo> defaultResourcePacks, final IReloadableResourceManager mcResourceManager, DownloadingPackFinder metadataSerializer)
{
// force log4j to shutdown logging in a shutdown hook. This is because we disable default shutdown hook so the server properly logs it's shutdown
Runtime.getRuntime().addShutdownHook(new Thread(LogManager::shutdown));
loading = true;
ClientModLoader.mc = minecraft;
SidedProvider.setClient(()->minecraft);
LogicalSidedProvider.setClient(()->minecraft);
LanguageHook.loadForgeAndMCLangs();
earlyLoaderGUI = new EarlyLoaderGUI(minecraft.getMainWindow());
createRunnableWithCatch(()->ModLoader.get().gatherAndInitializeMods(ModWorkManager.syncExecutor(), ModWorkManager.parallelExecutor(), earlyLoaderGUI::renderTick)).run();
createRunnableWithCatch(()->ModLoader.get().gatherAndInitializeMods(ModWorkManager.syncExecutor(), ModWorkManager.parallelExecutor(), new SpacedRunnable(earlyLoaderGUI::renderTick))).run();
if (error == null) {
ResourcePackLoader.loadResourcePacks(defaultResourcePacks, ClientModLoader::buildPackFinder);
DatapackCodec.field_234880_a_.addModPacks(ResourcePackLoader.getPackNames());
mcResourceManager.addReloadListener(ClientModLoader::onResourceReload);
mcResourceManager.addReloadListener(BrandingControl.resourceManagerReloadListener());
ModelLoaderRegistry.init();
@@ -110,10 +137,10 @@ public class ClientModLoader
private static Runnable createRunnableWithCatch(Runnable r) {
return ()-> {
if (loadingComplete) return;
try {
r.run();
} catch (LoadingFailedException e) {
MinecraftForge.EVENT_BUS.shutdown();
if (error == null) error = e;
}
};
@@ -121,7 +148,7 @@ public class ClientModLoader
private static void startModLoading(ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor) {
earlyLoaderGUI.handleElsewhere();
createRunnableWithCatch(() -> ModLoader.get().loadMods(syncExecutor, parallelExecutor, executor -> CompletableFuture.runAsync(ClientModLoader::preSidedRunnable, executor), executor -> CompletableFuture.runAsync(ClientModLoader::postSidedRunnable, executor), ()->{})).run();
createRunnableWithCatch(() -> ModLoader.get().loadMods(syncExecutor, parallelExecutor, executor -> CompletableFuture.runAsync(ClientModLoader::preSidedRunnable, executor), executor -> CompletableFuture.runAsync(ClientModLoader::postSidedRunnable, executor), new SpacedRunnable(earlyLoaderGUI::renderTick))).run();
}
private static void postSidedRunnable() {
@@ -135,15 +162,15 @@ public class ClientModLoader
private static void finishModLoading(ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor)
{
createRunnableWithCatch(() -> ModLoader.get().finishMods(syncExecutor, parallelExecutor, ()->{})).run();
createRunnableWithCatch(() -> ModLoader.get().finishMods(syncExecutor, parallelExecutor, new SpacedRunnable(earlyLoaderGUI::renderTick))).run();
loading = false;
loadingComplete = true;
// reload game settings on main thread
syncExecutor.execute(()->mc.gameSettings.loadOptions());
}
public static VersionChecker.Status checkForUpdates()
{
boolean anyOutdated = ModList.get().getMods().stream()
.map(VersionChecker::getResult)
.map(result -> result.status)
@@ -173,6 +200,24 @@ public class ClientModLoader
if (error == null) {
// We can finally start the forge eventbus up
MinecraftForge.EVENT_BUS.start();
} else {
final CrashReport crashReport = CrashReport.makeCrashReport(new Exception("Mod Loading has failed"), "Mod loading error has occurred");
error.getErrors().forEach(mle -> {
final CrashReportCategory category = crashReport.makeCategory(mle.getModInfo().getModId());
category.applyStackTrace(mle.getCause());
category.addDetail("Failure message", mle.getCleanMessage());
category.addDetail("Exception message", mle.getCause().toString());
category.addDetail("Mod Version", mle.getModInfo().getVersion().toString());
category.addDetail("Mod Issue URL", ((ModFileInfo)mle.getModInfo().getOwningFile()).getConfigElement("issueTrackerURL").orElse("NOT PROVIDED"));
});
final File file1 = new File(mc.gameDir, "crash-reports");
final File file2 = new File(file1, "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-client.txt");
if (crashReport.saveToFile(file2)) {
LOGGER.fatal("Crash report saved to {}", crashReport.getFile());
} else {
LOGGER.fatal("Failed to save crash report");
}
System.out.print(crashReport.getCompleteReport());
}
if (error != null || !warnings.isEmpty()) {
mc.displayGuiScreen(new LoadingErrorScreen(error, warnings));
@@ -22,6 +22,7 @@ package net.minecraftforge.fml.event.lifecycle;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import net.minecraft.data.DataGenerator;
import net.minecraftforge.client.model.generators.ExistingFileHelper;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.ModContainer;
import java.nio.file.Path;
@@ -33,19 +34,25 @@ import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
public class GatherDataEvent extends ModLifecycleEvent
public class GatherDataEvent extends Event implements IModBusEvent
{
private final DataGenerator dataGenerator;
private final DataGeneratorConfig config;
private final ExistingFileHelper existingFileHelper;
public GatherDataEvent(final ModContainer modContainer, final DataGenerator dataGenerator, final DataGeneratorConfig dataGeneratorConfig, ExistingFileHelper existingFileHelper)
private final ModContainer modContainer;
public GatherDataEvent(final ModContainer mc, final DataGenerator dataGenerator, final DataGeneratorConfig dataGeneratorConfig, ExistingFileHelper existingFileHelper)
{
super(modContainer);
this.modContainer = mc;
this.dataGenerator = dataGenerator;
this.config = dataGeneratorConfig;
this.existingFileHelper = existingFileHelper;
}
public ModContainer getModContainer() {
return this.modContainer;
}
public DataGenerator getGenerator() { return this.dataGenerator; }
public ExistingFileHelper getExistingFileHelper() { return existingFileHelper; }
public boolean includeServer() { return this.config.server; }
@@ -54,16 +54,16 @@ public class ResourcePackLoader
public static <T extends ResourcePackInfo> void loadResourcePacks(ResourcePackList<T> resourcePacks, BiFunction<Map<ModFile, ? extends ModFileResourcePack>, BiConsumer<? super ModFileResourcePack, T>, IPackInfoFinder> packFinder) {
resourcePackList = resourcePacks;
modResourcePacks = ModList.get().getModFiles().stream().
filter(mf->!Objects.equals(mf.getModLoader(),"minecraft")).
map(mf -> new ModFileResourcePack(mf.getFile())).
collect(Collectors.toMap(ModFileResourcePack::getModFile, Function.identity(), (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }, LinkedHashMap::new));
modResourcePacks = ModList.get().getModFiles().stream()
.filter(mf->!Objects.equals(mf.getModLoader(),"minecraft"))
.map(mf -> new ModFileResourcePack(mf.getFile()))
.collect(Collectors.toMap(ModFileResourcePack::getModFile, Function.identity(), (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }, LinkedHashMap::new));
resourcePacks.addPackFinder(new LambdaFriendlyPackFinder(packFinder.apply(modResourcePacks, ModFileResourcePack::setPackInfo)));
}
public static List<String> getPackNames()
{
return modResourcePacks.values().stream().map(pack -> pack.getPackInfo().getName()).collect(Collectors.toList());
return ModList.get().applyForEachModFile(mf->"mod:"+mf.getModInfos().get(0).getModId()).filter(n->!n.equals("mod:minecraft")).collect(Collectors.toList());
}
public static <V> Comparator<Map.Entry<String,V>> getSorter() {
@@ -31,14 +31,12 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import net.minecraft.resources.IPackNameDecorator;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.storage.FolderName;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.LogicalSidedProvider;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.ModLoadingStage;
import net.minecraftforge.fml.ModLoadingWarning;
import net.minecraftforge.fml.SidedProvider;
import net.minecraftforge.fml.network.ConnectionType;
import net.minecraftforge.fml.network.FMLNetworkConstants;
import net.minecraftforge.fml.network.FMLStatusPing;
@@ -92,7 +90,6 @@ public class ServerLifecycleHooks
currentServer = server;
currentServer.getServerStatusResponse().setForgeData(new FMLStatusPing()); //gathers NetworkRegistry data
// on the dedi server we need to force the stuff to setup properly
DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, ()->()->SidedProvider.setServer(()->(DedicatedServer)server));
LogicalSidedProvider.setServer(()->server);
ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.SERVER, getServerConfigPath(server));
return !MinecraftForge.EVENT_BUS.post(new FMLServerAboutToStartEvent(server));
@@ -185,30 +182,6 @@ public class ServerLifecycleHooks
public static void handleExit(int retVal)
{
/*
CountDownLatch latch = exitLatch;
if (latch != null)
{
try
{
LOGGER.info("Waiting for the server to terminate/save.");
if (!latch.await(10, TimeUnit.SECONDS))
{
LOGGER.warn("The server didn't stop within 10 seconds, exiting anyway.");
}
else
{
LOGGER.info("Server terminated.");
}
}
catch (InterruptedException e)
{
LOGGER.warn("Interrupted wait, exiting.");
}
}
*/
System.exit(retVal);
}
@@ -235,5 +208,4 @@ public class ServerLifecycleHooks
consumer.accept(packInfo);
}
}
}
@@ -19,17 +19,23 @@
package net.minecraftforge.fml.server;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.LoadingFailedException;
import net.minecraftforge.fml.LogicalSidedProvider;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.ModLoadingWarning;
import net.minecraftforge.fml.ModWorkManager;
import net.minecraftforge.fml.SidedProvider;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
@@ -39,20 +45,34 @@ public class ServerModLoader
private static boolean hasErrors = false;
public static void load() {
SidedProvider.setServer(()-> {
throw new IllegalStateException("Unable to access server yet");
});
LogicalSidedProvider.setServer(()-> {
throw new IllegalStateException("Unable to access server yet");
});
LanguageHook.loadForgeAndMCLangs();
try {
ModLoader.get().gatherAndInitializeMods(ModWorkManager.syncExecutor(), ModWorkManager.parallelExecutor(), ()->{});
ModLoader.get().loadMods(ModWorkManager.syncExecutor(), ModWorkManager.parallelExecutor(), null, null, ()->{});
ModLoader.get().loadMods(ModWorkManager.syncExecutor(), ModWorkManager.parallelExecutor(), e-> CompletableFuture.runAsync(()->{}, e), e->CompletableFuture.runAsync(()->{}, e), ()->{});
ModLoader.get().finishMods(ModWorkManager.syncExecutor(), ModWorkManager.parallelExecutor(), ()->{});
} catch (LoadingFailedException e) {
} catch (LoadingFailedException error) {
ServerModLoader.hasErrors = true;
throw e;
final CrashReport crashReport = CrashReport.makeCrashReport(error, "Mod loading error has occurred");
error.getErrors().forEach(mle -> {
final CrashReportCategory category = crashReport.makeCategory(mle.getModInfo().getModId());
category.applyStackTrace(mle.getCause());
category.addDetail("Failure message", mle.getCleanMessage());
category.addDetail("Exception message", mle.getCause().toString());
category.addDetail("Mod Version", mle.getModInfo().getVersion().toString());
category.addDetail("Mod Issue URL", ((ModFileInfo)mle.getModInfo().getOwningFile()).getConfigElement("issueTrackerURL").orElse("NOT PROVIDED"));
});
final File file1 = new File("crash-reports");
final File file2 = new File(file1, "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-server.txt");
if (crashReport.saveToFile(file2)) {
LOGGER.fatal("Crash report saved to {}", file2);
} else {
LOGGER.fatal("Failed to save crash report");
}
System.out.print(crashReport.getCompleteReport());
throw error;
}
List<ModLoadingWarning> warnings = ModLoader.get().getWarnings();
if (!warnings.isEmpty()) {