mirror of
https://github.com/MinecraftForge/MinecraftForge
synced 2026-08-22 04:26:10 -04:00
[1.21.1] ModLoading cleanup and optimisations (#10052)
This commit is contained in:
parent
f106ff0c21
commit
9714512c31
101 changed files with 837 additions and 841 deletions
|
|
@ -57,7 +57,9 @@ public class DeferredWorkQueue
|
|||
LOGGER.debug(LOADING, "Dispatching synchronous work for work queue {}: {} jobs", modLoadingStage, tasks.size());
|
||||
RuntimeException aggregate = new RuntimeException();
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
tasks.forEach(t -> makeRunnable(t, Runnable::run, aggregate));
|
||||
for (TaskInfo t : tasks) {
|
||||
makeRunnable(t, Runnable::run, aggregate);
|
||||
}
|
||||
timer.stop();
|
||||
if (aggregate.getSuppressed().length > 0) {
|
||||
LOGGER.fatal(
|
||||
|
|
@ -114,7 +116,7 @@ public class DeferredWorkQueue
|
|||
return future;
|
||||
}
|
||||
|
||||
private static class TaskInfo {
|
||||
private static final class TaskInfo {
|
||||
private final ModContainer owner;
|
||||
private Runnable task;
|
||||
private CompletableFuture<?> future;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public class InterModComms
|
|||
}
|
||||
}
|
||||
|
||||
private static ConcurrentMap<String, ConcurrentLinkedQueue<IMCMessage>> containerQueues = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentMap<String, ConcurrentLinkedQueue<IMCMessage>> containerQueues = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Send IMC to remote. Sender will default to the active modcontainer, or minecraft if not.
|
||||
|
|
@ -115,16 +115,14 @@ public class InterModComms
|
|||
return getMessages(modId, s->Boolean.TRUE);
|
||||
}
|
||||
|
||||
private static class QueueFilteringSpliterator implements Spliterator<IMCMessage>
|
||||
{
|
||||
private final ConcurrentLinkedQueue<IMCMessage> queue;
|
||||
private final Predicate<String> methodFilter;
|
||||
private final Iterator<IMCMessage> iterator;
|
||||
private record QueueFilteringSpliterator(
|
||||
ConcurrentLinkedQueue<IMCMessage> queue,
|
||||
Predicate<String> methodFilter,
|
||||
Iterator<IMCMessage> iterator
|
||||
) implements Spliterator<IMCMessage> {
|
||||
|
||||
public QueueFilteringSpliterator(final ConcurrentLinkedQueue<IMCMessage> queue, final Predicate<String> methodFilter) {
|
||||
this.queue = queue;
|
||||
this.iterator = queue.iterator();
|
||||
this.methodFilter = methodFilter;
|
||||
this(queue, methodFilter, queue.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public abstract class ModContainer
|
|||
protected final IModInfo modInfo;
|
||||
protected ModLoadingStage modLoadingStage;
|
||||
protected Supplier<?> contextExtension;
|
||||
protected final Map<ModLoadingStage, Runnable> activityMap = new HashMap<>();
|
||||
protected final Map<ModLoadingStage, Runnable> activityMap = new EnumMap<>(ModLoadingStage.class);
|
||||
protected final Map<Class<? extends IExtensionPoint<?>>, Supplier<?>> extensionPoints = new IdentityHashMap<>();
|
||||
protected final EnumMap<ModConfig.Type, ModConfig> configs = new EnumMap<>(ModConfig.Type.class);
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
|
|
@ -168,7 +168,10 @@ public abstract class ModContainer
|
|||
}
|
||||
|
||||
public void dispatchConfigEvent(IConfigEvent event) {
|
||||
configHandler.ifPresent(configHandler->configHandler.accept(event));
|
||||
var handler = configHandler.orElse(null);
|
||||
if (handler != null) {
|
||||
handler.accept(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -74,11 +74,12 @@ public class ModList
|
|||
}
|
||||
|
||||
private String fileToLine(IModFile mf) {
|
||||
var mainMod = mf.getModInfos().getFirst();
|
||||
return String.format(Locale.ENGLISH, "%-50.50s|%-30.30s|%-30.30s|%-20.20s|%-10.10s|Manifest: %s", mf.getFileName(),
|
||||
mf.getModInfos().get(0).getDisplayName(),
|
||||
mf.getModInfos().get(0).getModId(),
|
||||
mf.getModInfos().get(0).getVersion(),
|
||||
getModContainerState(mf.getModInfos().get(0).getModId()),
|
||||
mainMod.getDisplayName(),
|
||||
mainMod.getModId(),
|
||||
mainMod.getVersion(),
|
||||
getModContainerState(mainMod.getModId()),
|
||||
((ModFileInfo)mf.getModFileInfo()).getCodeSigningFingerprint().orElse("NOSIGNATURE"));
|
||||
}
|
||||
private String crashReport() {
|
||||
|
|
@ -95,14 +96,6 @@ public class ModList
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static ForkJoinWorkerThread newForkJoinWorkerThread(ForkJoinPool pool) {
|
||||
ForkJoinWorkerThread thread = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
|
||||
thread.setName("modloading-worker-" + thread.getPoolIndex());
|
||||
// The default sets it to the SystemClassloader, so copy the current one.
|
||||
thread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
return thread;
|
||||
}
|
||||
|
||||
public List<IModFileInfo> getModFiles()
|
||||
{
|
||||
return modFiles;
|
||||
|
|
@ -131,16 +124,18 @@ public class ModList
|
|||
CompletableFuture<Void> cf = new CompletableFuture<>();
|
||||
final RuntimeException accumulator = new RuntimeException();
|
||||
cf.completeExceptionally(accumulator);
|
||||
throwables.forEach(exception -> {
|
||||
for (Throwable exception : throwables) {
|
||||
if (exception instanceof CompletionException) {
|
||||
exception = exception.getCause();
|
||||
}
|
||||
if (exception.getSuppressed().length!=0) {
|
||||
Arrays.stream(exception.getSuppressed()).forEach(accumulator::addSuppressed);
|
||||
if (exception.getSuppressed().length != 0) {
|
||||
for (Throwable throwable : exception.getSuppressed()) {
|
||||
accumulator.addSuppressed(throwable);
|
||||
}
|
||||
} else {
|
||||
accumulator.addSuppressed(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
return cf;
|
||||
}
|
||||
}
|
||||
|
|
@ -148,11 +143,11 @@ public class ModList
|
|||
static <V> CompletableFuture<List<Map.Entry<V, Throwable>>> gather(List<? extends CompletableFuture<? extends V>> futures) {
|
||||
List<Map.Entry<V, Throwable>> list = new ArrayList<>(futures.size());
|
||||
CompletableFuture<?>[] results = new CompletableFuture[futures.size()];
|
||||
futures.forEach(future -> {
|
||||
for (var future : futures) {
|
||||
int i = list.size();
|
||||
list.add(null);
|
||||
results[i] = future.whenComplete((result, exception) -> list.set(i, new AbstractMap.SimpleImmutableEntry<>(result, exception)));
|
||||
});
|
||||
}
|
||||
return CompletableFuture.allOf(results).handle((r, th)->null).thenApply(res -> list);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,13 +77,13 @@ import static net.minecraftforge.fml.Logging.LOADING;
|
|||
public class ModLoader
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static ModLoader INSTANCE;
|
||||
private final LoadingModList loadingModList;
|
||||
|
||||
private final List<ModLoadingException> loadingExceptions;
|
||||
private final Set<IModInfo> erroredModInfos;
|
||||
private final List<ModLoadingWarning> loadingWarnings;
|
||||
private final ModStateManager stateManager;
|
||||
private boolean loadingStateValid;
|
||||
private static boolean loadingStateValid;
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
private final Optional<Consumer<String>> statusConsumer = StartupNotificationManager.modLoaderConsumer();
|
||||
private final Set<IModLoadingState> completedStates = new HashSet<>();
|
||||
|
|
@ -91,7 +91,6 @@ public class ModLoader
|
|||
|
||||
private ModLoader()
|
||||
{
|
||||
INSTANCE = this;
|
||||
this.loadingModList = FMLLoader.getLoadingModList();
|
||||
this.loadingExceptions = this.loadingModList.getErrors().stream()
|
||||
.flatMap(ModLoadingException::fromEarlyException)
|
||||
|
|
@ -99,24 +98,32 @@ public class ModLoader
|
|||
this.loadingWarnings = this.loadingModList.getBrokenFiles().stream()
|
||||
.map(file -> new ModLoadingWarning(null, ModLoadingStage.VALIDATE, InvalidModIdentifier.identifyJarProblem(file.getFilePath()).orElse("fml.modloading.brokenfile"), file.getFileName()))
|
||||
.collect(Collectors.toList());
|
||||
if (this.loadingExceptions.isEmpty()) {
|
||||
this.erroredModInfos = Collections.emptySet();
|
||||
} else {
|
||||
this.erroredModInfos = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
this.erroredModInfos.addAll(this.loadingExceptions.stream().map(ModLoadingException::getModInfo).toList());
|
||||
}
|
||||
this.loadingModList.getModFiles().stream()
|
||||
.filter(ModFileInfo::missingLicense)
|
||||
.filter(modFileInfo -> modFileInfo.getMods().stream().noneMatch(thisModInfo -> this.loadingExceptions.stream().map(ModLoadingException::getModInfo).anyMatch(otherInfo -> otherInfo == thisModInfo))) //Ignore files where any other mod already encountered an error
|
||||
.filter(modFileInfo -> modFileInfo.getMods().stream().noneMatch(this.erroredModInfos::contains)) //Ignore files where any other mod already encountered an error
|
||||
.map(modFileInfo -> new ModLoadingException(null, ModLoadingStage.VALIDATE, "fml.modloading.missinglicense", null, modFileInfo.getFile()))
|
||||
.forEach(this.loadingExceptions::add);
|
||||
this.stateManager = new ModStateManager();
|
||||
CrashReportCallables.registerCrashCallable("ModLauncher", FMLLoader::getLauncherInfo);
|
||||
CrashReportCallables.registerCrashCallable("ModLauncher launch target", FMLLoader::launcherHandlerName);
|
||||
CrashReportCallables.registerCrashCallable("ModLauncher naming", FMLLoader::getNaming);
|
||||
CrashReportCallables.registerCrashCallable("ModLauncher services", this::computeModLauncherServiceList);
|
||||
CrashReportCallables.registerCrashCallable("FML Language Providers", this::computeLanguageList);
|
||||
CrashReportCallables.registerCrashCallable("ModLauncher services", ModLoader::computeModLauncherServiceList);
|
||||
CrashReportCallables.registerCrashCallable("FML Language Providers", ModLoader::computeLanguageList);
|
||||
}
|
||||
|
||||
private String computeLanguageList() {
|
||||
return "\n"+FMLLoader.getLanguageLoadingProvider().applyForEach(lp->lp.name() +"@"+ lp.getClass().getPackage().getImplementationVersion()).collect(Collectors.joining("\n\t\t", "\t\t", ""));
|
||||
private static String computeLanguageList() {
|
||||
return "\n" + FMLLoader.getLanguageLoadingProvider()
|
||||
.applyForEach(lp -> lp.name() + "@" + lp.getClass().getPackage().getImplementationVersion())
|
||||
.collect(Collectors.joining("\n\t\t", "\t\t", ""));
|
||||
}
|
||||
|
||||
private String computeModLauncherServiceList() {
|
||||
private static String computeModLauncherServiceList() {
|
||||
final List<Map<String, String>> mods = FMLLoader.modLauncherModList();
|
||||
return "\n"+mods.stream().map(mod->mod.getOrDefault("file","nofile")+
|
||||
" "+mod.getOrDefault("name", "missing")+
|
||||
|
|
@ -125,9 +132,13 @@ public class ModLoader
|
|||
collect(Collectors.joining("\n\t\t","\t\t",""));
|
||||
}
|
||||
|
||||
public static ModLoader get()
|
||||
{
|
||||
return INSTANCE == null ? INSTANCE = new ModLoader() : INSTANCE;
|
||||
public static ModLoader get() {
|
||||
return LazyInit.INSTANCE;
|
||||
}
|
||||
|
||||
private static final class LazyInit {
|
||||
private static final ModLoader INSTANCE = new ModLoader();
|
||||
private LazyInit() {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,7 +155,7 @@ public class ModLoader
|
|||
final ModList modList = ModList.of(loadingModList.getModFiles().stream().map(ModFileInfo::getFile).toList(),
|
||||
loadingModList.getMods());
|
||||
if (!this.loadingExceptions.isEmpty()) {
|
||||
LOGGER.fatal(CORE, "Error during pre-loading phase", loadingExceptions.get(0));
|
||||
LOGGER.fatal(CORE, "Error during pre-loading phase", loadingExceptions.getFirst());
|
||||
statusConsumer.ifPresent(c->c.accept("ERROR DURING MOD LOADING"));
|
||||
modList.setLoadedMods(Collections.emptyList());
|
||||
loadingStateValid = false;
|
||||
|
|
@ -152,7 +163,7 @@ public class ModLoader
|
|||
}
|
||||
List<? extends ForgeFeature.Bound> failedBounds = loadingModList.getMods().stream()
|
||||
.map(ModInfo::getForgeFeatures)
|
||||
.flatMap(Collection::stream)
|
||||
.flatMap(List::stream)
|
||||
.filter(bound -> !ForgeFeature.testFeature(FMLEnvironment.dist, bound))
|
||||
.toList();
|
||||
|
||||
|
|
@ -169,10 +180,10 @@ public class ModLoader
|
|||
final List<ModContainer> modContainers = loadingModList.getModFiles().stream()
|
||||
.map(ModFileInfo::getFile)
|
||||
.map(this::buildMods)
|
||||
.<ModContainer>mapMulti(Iterable::forEach)
|
||||
.flatMap(List::stream)
|
||||
.toList();
|
||||
if (!loadingExceptions.isEmpty()) {
|
||||
LOGGER.fatal(CORE, "Failed to initialize mod containers", loadingExceptions.get(0));
|
||||
LOGGER.fatal(CORE, "Failed to initialize mod containers", loadingExceptions.getFirst());
|
||||
statusConsumer.ifPresent(c->c.accept("ERROR DURING MOD LOADING"));
|
||||
modList.setLoadedMods(Collections.emptyList());
|
||||
loadingStateValid = false;
|
||||
|
|
@ -181,22 +192,28 @@ public class ModLoader
|
|||
modList.setLoadedMods(modContainers);
|
||||
this.modList = modList;
|
||||
var stateList = stateManager.getStates(ModLoadingPhase.GATHER);
|
||||
var progress = StartupMessageManager.addProgressBar("Mod Gather", stateList.stream().mapToInt(mls -> mls.size().applyAsInt(modList)).sum());
|
||||
stateList.forEach(mls->dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask, progress));
|
||||
var progress = StartupMessageManager.addProgressBar("Mod Gather", stateList.stream().mapToInt(mls -> mls.size().applyAsInt(this.modList)).sum());
|
||||
for (IModLoadingState mls : stateList) {
|
||||
dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask, progress);
|
||||
}
|
||||
progress.complete();
|
||||
}
|
||||
|
||||
public void loadMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask) {
|
||||
var stateList = stateManager.getStates(ModLoadingPhase.LOAD);
|
||||
var progress = StartupMessageManager.addProgressBar("Mod Loading", stateList.stream().mapToInt(mls -> mls.size().applyAsInt(modList)).sum());
|
||||
stateList.forEach(mls->dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask, progress));
|
||||
for (IModLoadingState mls : stateList) {
|
||||
dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask, progress);
|
||||
}
|
||||
progress.complete();
|
||||
}
|
||||
|
||||
public void finishMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask) {
|
||||
var stateList = stateManager.getStates(ModLoadingPhase.COMPLETE);
|
||||
var progress = StartupMessageManager.addProgressBar("Mod Complete", stateList.stream().mapToInt(mls -> mls.size().applyAsInt(modList)).sum());
|
||||
stateList.forEach(mls->dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask, progress));
|
||||
for (IModLoadingState mls : stateList) {
|
||||
dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask, progress);
|
||||
}
|
||||
statusConsumer.ifPresent(c->c.accept(String.format("Mod loading complete - %d mods loaded", this.modList.size())));
|
||||
progress.complete();
|
||||
}
|
||||
|
|
@ -206,10 +223,15 @@ public class ModLoader
|
|||
LOGGER.error("Cowardly refusing to process mod state change request from {}", state);
|
||||
return;
|
||||
}
|
||||
progressBar.label(progressBar.name()+ " working");
|
||||
progressBar.label(progressBar.name() + " working");
|
||||
syncExecutor.drive(ticker);
|
||||
state.inlineRunnable().ifPresent(a->this.handleInlineTransition(a, state, syncExecutor, ticker));
|
||||
state.buildTransition(syncExecutor, parallelExecutor, progressBar).ifPresent(t->waitForTransition(state, syncExecutor, ticker, t));
|
||||
|
||||
var inlineRunnable = state.inlineRunnable().orElse(null);
|
||||
if (inlineRunnable != null) handleInlineTransition(inlineRunnable, state, syncExecutor, ticker);
|
||||
|
||||
var transition = state.buildTransition(syncExecutor, parallelExecutor, progressBar).orElse(null);
|
||||
if (transition != null) waitForTransition(state, syncExecutor, ticker, transition);
|
||||
|
||||
completedStates.add(state);
|
||||
}
|
||||
|
||||
|
|
@ -286,9 +308,12 @@ public class ModLoader
|
|||
try {
|
||||
final String modId = idToProviderEntry.getKey();
|
||||
final IModLanguageProvider.IModLanguageLoader languageLoader = idToProviderEntry.getValue();
|
||||
IModInfo info = Optional.ofNullable(modInfoMap.get(modId)).
|
||||
// throw a missing metadata error if there is no matching modid in the modInfoMap from the mods.toml file
|
||||
orElseThrow(()->new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingmetadata", null, modId));
|
||||
|
||||
IModInfo info = modInfoMap.get(modId);
|
||||
// throw a missing metadata error if there is no matching modid in the modInfoMap from the mods.toml file
|
||||
if (info == null)
|
||||
throw new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingmetadata", null, modId);
|
||||
|
||||
return languageLoader.loadMod(info, modFile.getScanResult(), FMLLoader.getGameLayer());
|
||||
} catch (ModLoadingException mle) {
|
||||
// exceptions are caught and added to the error list for later handling
|
||||
|
|
@ -303,7 +328,7 @@ public class ModLoader
|
|||
* 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;
|
||||
return loadingStateValid;
|
||||
}
|
||||
|
||||
public boolean hasCompletedState(final String stateName) {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,10 @@ public record ModLoadingState(String name, String previous,
|
|||
final ProgressMeter progressBar,
|
||||
final Function<Executor, CompletableFuture<Void>> preSyncTask,
|
||||
final Function<Executor, CompletableFuture<Void>> postSyncTask) {
|
||||
return transition.map(t -> t.build(name, syncExecutor, parallelExecutor, progressBar, preSyncTask, postSyncTask));
|
||||
var transition = this.transition.orElse(null);
|
||||
return transition == null
|
||||
? Optional.empty()
|
||||
: Optional.ofNullable(transition.build(name, syncExecutor, parallelExecutor, progressBar, preSyncTask, postSyncTask));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,15 +16,13 @@ import java.util.stream.Collectors;
|
|||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class ModStateManager {
|
||||
static ModStateManager INSTANCE;
|
||||
private final EnumMap<ModLoadingPhase, List<IModLoadingState>> stateMap;
|
||||
|
||||
public ModStateManager() {
|
||||
INSTANCE = this;
|
||||
final var sp = ServiceLoader.load(FMLLoader.getGameLayer(), IModStateProvider.class);
|
||||
this.stateMap = ServiceLoaderUtils.streamWithErrorHandling(sp, sce->{})
|
||||
.map(IModStateProvider::getAllStates)
|
||||
.<IModLoadingState>mapMulti(Iterable::forEach)
|
||||
.flatMap(List::stream)
|
||||
.collect(Collectors.groupingBy(IModLoadingState::phase, ()->new EnumMap<>(ModLoadingPhase.class), Collectors.toUnmodifiableList()));
|
||||
}
|
||||
|
||||
|
|
@ -36,14 +34,16 @@ public class ModStateManager {
|
|||
var dummy = ModLoadingState.empty("", "", phase);
|
||||
nodes.forEach(graph::addNode);
|
||||
graph.addNode(dummy);
|
||||
nodes.forEach(n->graph.putEdge(lookup.getOrDefault(n.previous(), dummy), n));
|
||||
for (IModLoadingState node : nodes) {
|
||||
graph.putEdge(lookup.getOrDefault(node.previous(), dummy), node);
|
||||
}
|
||||
return TopologicalSort.topologicalSort(graph, Comparator.comparingInt(nodes::indexOf)).stream().filter(st->st!=dummy).toList();
|
||||
}
|
||||
|
||||
public IModLoadingState findState(final String stateName) {
|
||||
return stateMap.values()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.flatMap(List::stream)
|
||||
.filter(mls -> mls.name().equals(stateName))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Unknown IModLoadingState: " + stateName));
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import static net.minecraftforge.fml.Logging.LOADING;
|
|||
public class ModWorkManager {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final long PARK_TIME = TimeUnit.MILLISECONDS.toNanos(1);
|
||||
|
||||
public interface DrivenExecutor extends Executor {
|
||||
boolean selfDriven();
|
||||
boolean driveOne();
|
||||
|
|
@ -33,8 +34,11 @@ public class ModWorkManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
private static class SyncExecutor implements DrivenExecutor {
|
||||
private ConcurrentLinkedDeque<Runnable> tasks = new ConcurrentLinkedDeque<>();
|
||||
|
||||
private record SyncExecutor(ConcurrentLinkedDeque<Runnable> tasks) implements DrivenExecutor {
|
||||
public SyncExecutor() {
|
||||
this(new ConcurrentLinkedDeque<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean driveOne() {
|
||||
|
|
@ -56,13 +60,7 @@ public class ModWorkManager {
|
|||
}
|
||||
}
|
||||
|
||||
private static class WrappingExecutor implements DrivenExecutor {
|
||||
private final Executor wrapped;
|
||||
|
||||
public WrappingExecutor(final Executor executor) {
|
||||
this.wrapped = executor;
|
||||
}
|
||||
|
||||
private record WrappingExecutor(Executor wrapped) implements DrivenExecutor {
|
||||
@Override
|
||||
public boolean selfDriven() {
|
||||
return true;
|
||||
|
|
@ -79,11 +77,9 @@ public class ModWorkManager {
|
|||
}
|
||||
}
|
||||
|
||||
private static SyncExecutor syncExecutor;
|
||||
private static final SyncExecutor syncExecutor = new SyncExecutor();
|
||||
|
||||
public static DrivenExecutor syncExecutor() {
|
||||
if (syncExecutor == null)
|
||||
syncExecutor = new SyncExecutor();
|
||||
return syncExecutor;
|
||||
}
|
||||
|
||||
|
|
@ -91,14 +87,8 @@ public class ModWorkManager {
|
|||
return new WrappingExecutor(executor);
|
||||
}
|
||||
|
||||
private static ForkJoinPool parallelThreadPool;
|
||||
public static Executor parallelExecutor() {
|
||||
if (parallelThreadPool == null) {
|
||||
final int loadingThreadCount = FMLConfig.getIntConfigValue(FMLConfig.ConfigValue.MAX_THREADS);
|
||||
LOGGER.debug(LOADING, "Using {} threads for parallel mod-loading", loadingThreadCount);
|
||||
parallelThreadPool = new ForkJoinPool(loadingThreadCount, ModWorkManager::newForkJoinWorkerThread, null, false);
|
||||
}
|
||||
return parallelThreadPool;
|
||||
return LazyInit.PARALLEL_EXECUTOR;
|
||||
}
|
||||
|
||||
private static ForkJoinWorkerThread newForkJoinWorkerThread(ForkJoinPool pool) {
|
||||
|
|
@ -109,4 +99,14 @@ public class ModWorkManager {
|
|||
return thread;
|
||||
}
|
||||
|
||||
private static final class LazyInit {
|
||||
private LazyInit() {}
|
||||
private static final ForkJoinPool PARALLEL_EXECUTOR;
|
||||
|
||||
static {
|
||||
final int loadingThreadCount = FMLConfig.getIntConfigValue(FMLConfig.ConfigValue.MAX_THREADS);
|
||||
LOGGER.debug(LOADING, "Using {} threads for parallel mod-loading", loadingThreadCount);
|
||||
PARALLEL_EXECUTOR = new ForkJoinPool(loadingThreadCount, ModWorkManager::newForkJoinWorkerThread, null, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public final class OptionalMod<T>
|
|||
return new OptionalMod<>(modId);
|
||||
}
|
||||
|
||||
private static OptionalMod<?> EMPTY = new OptionalMod<>(true);
|
||||
private static final OptionalMod<?> EMPTY = new OptionalMod<>(true);
|
||||
private static <T> OptionalMod<T> empty() {
|
||||
@SuppressWarnings("unchecked")
|
||||
OptionalMod<T> t = (OptionalMod<T>) EMPTY;
|
||||
|
|
@ -213,8 +213,8 @@ public final class OptionalMod<T>
|
|||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) return true;
|
||||
if (obj instanceof OptionalMod) {
|
||||
return Objects.equals(((OptionalMod)obj).modId, modId);
|
||||
if (obj instanceof OptionalMod<?> optionalMod) {
|
||||
return Objects.equals(optionalMod.modId, modId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import static net.minecraftforge.fml.config.ConfigTracker.CONFIG;
|
|||
|
||||
public class ConfigFileTypeHandler {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
static ConfigFileTypeHandler TOML = new ConfigFileTypeHandler();
|
||||
static final ConfigFileTypeHandler TOML = new ConfigFileTypeHandler();
|
||||
private static final Path defaultConfigPath = FMLPaths.GAMEDIR.get().resolve(FMLConfig.getConfigValue(FMLConfig.ConfigValue.DEFAULT_CONFIG_PATH));
|
||||
|
||||
public Function<ModConfig, CommentedFileConfig> reader(Path configBasePath) {
|
||||
|
|
@ -62,7 +62,7 @@ public class ConfigFileTypeHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean setupConfigFile(final ModConfig modConfig, final Path file, final ConfigFormat<?> conf) throws IOException {
|
||||
private static boolean setupConfigFile(final ModConfig modConfig, final Path file, final ConfigFormat<?> conf) throws IOException {
|
||||
if (!Files.isDirectory(file.getParent())) {
|
||||
Files.createDirectories(file.getParent());
|
||||
}
|
||||
|
|
@ -109,17 +109,11 @@ public class ConfigFileTypeHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private static class ConfigWatcher implements Runnable {
|
||||
private final ModConfig modConfig;
|
||||
private final CommentedFileConfig commentedFileConfig;
|
||||
private final ClassLoader realClassLoader;
|
||||
|
||||
ConfigWatcher(final ModConfig modConfig, final CommentedFileConfig commentedFileConfig, final ClassLoader classLoader) {
|
||||
this.modConfig = modConfig;
|
||||
this.commentedFileConfig = commentedFileConfig;
|
||||
this.realClassLoader = classLoader;
|
||||
}
|
||||
|
||||
private record ConfigWatcher(
|
||||
ModConfig modConfig,
|
||||
CommentedFileConfig commentedFileConfig,
|
||||
ClassLoader realClassLoader
|
||||
) implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
// Force the regular classloader onto the special thread
|
||||
|
|
|
|||
|
|
@ -47,15 +47,19 @@ public class ConfigTracker {
|
|||
|
||||
public void loadConfigs(ModConfig.Type type, Path configBasePath) {
|
||||
LOGGER.debug(CONFIG, "Loading configs type {}", type);
|
||||
this.configSets.get(type).forEach(config -> openConfig(config, configBasePath));
|
||||
for (ModConfig config : this.configSets.get(type)) {
|
||||
openConfig(config, configBasePath);
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadConfigs(ModConfig.Type type, Path configBasePath) {
|
||||
LOGGER.debug(CONFIG, "Unloading configs type {}", type);
|
||||
this.configSets.get(type).forEach(config -> closeConfig(config, configBasePath));
|
||||
for (ModConfig config : this.configSets.get(type)) {
|
||||
closeConfig(config, configBasePath);
|
||||
}
|
||||
}
|
||||
|
||||
private void openConfig(final ModConfig config, final Path configBasePath) {
|
||||
private static void openConfig(final ModConfig config, final Path configBasePath) {
|
||||
LOGGER.trace(CONFIG, "Loading config file type {} at {} for {}", config.getType(), config.getFileName(), config.getModId());
|
||||
final CommentedFileConfig configData = config.getHandler().reader(configBasePath).apply(config);
|
||||
config.setConfigData(configData);
|
||||
|
|
@ -63,7 +67,7 @@ public class ConfigTracker {
|
|||
config.save();
|
||||
}
|
||||
|
||||
private void closeConfig(final ModConfig config, final Path configBasePath) {
|
||||
private static void closeConfig(final ModConfig config, final Path configBasePath) {
|
||||
if (config.getConfigData() != null) {
|
||||
LOGGER.trace(CONFIG, "Closing config file type {} at {} for {}", config.getType(), config.getFileName(), config.getModId());
|
||||
// stop the filewatcher before we save the file and close it, so reload doesn't fire
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ public class ModConfig
|
|||
private final ModContainer container;
|
||||
private final ConfigFileTypeHandler configHandler;
|
||||
private CommentedConfig configData;
|
||||
private Callable<Void> saveHandler;
|
||||
|
||||
public ModConfig(final Type type, final IConfigSpec<?> spec, final ModContainer container, final String fileName) {
|
||||
this.type = type;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public class SimpleFont {
|
|||
private final int lineSpacing;
|
||||
private final int descent;
|
||||
private final int GLYPH_COUNT = 127-32;
|
||||
private Glyph[] glyphs;
|
||||
private final Glyph[] glyphs;
|
||||
|
||||
private record Glyph(char c, int charwidth, int[] pos, float[] uv) {
|
||||
Pos loadQuad(Pos pos, int colour, SimpleBufferBuilder bb) {
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
|
|||
*/
|
||||
public class CapabilityTokenSubclass implements ILaunchPluginService {
|
||||
|
||||
private final String FUNC_NAME = "getType";
|
||||
private final String FUNC_DESC = "()Ljava/lang/String;";
|
||||
private final String CAP_INJECT = "net/minecraftforge/common/capabilities/CapabilityToken"; //Don't directly reference this to prevent class loading.
|
||||
private static final String FUNC_NAME = "getType";
|
||||
private static final String FUNC_DESC = "()Ljava/lang/String;";
|
||||
private static final String CAP_INJECT = "net/minecraftforge/common/capabilities/CapabilityToken"; //Don't directly reference this to prevent class loading.
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
|
|
@ -67,7 +67,7 @@ public class CapabilityTokenSubclass implements ILaunchPluginService {
|
|||
|
||||
SignatureReader reader = new SignatureReader(classNode.signature); // Having a node version of this would probably be useful.
|
||||
reader.accept(new SignatureVisitor(Opcodes.ASM9) {
|
||||
Deque<String> stack = new ArrayDeque<>();
|
||||
final Deque<String> stack = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public void visitClassType(final String name) {
|
||||
|
|
@ -100,7 +100,7 @@ public class CapabilityTokenSubclass implements ILaunchPluginService {
|
|||
}
|
||||
}
|
||||
|
||||
private static class Holder {
|
||||
private static final class Holder {
|
||||
String value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ public class ObjectHolderDefinalize implements ILaunchPluginService {
|
|||
new VanillaObjectHolderData("net.minecraft.world.effect.MobEffects", "mob_effect", "net.minecraft.world.effect.MobEffect"),
|
||||
new VanillaObjectHolderData("net.minecraft.core.particles.ParticleTypes", "particle_type", "net.minecraft.core.particles.ParticleType"),
|
||||
new VanillaObjectHolderData("net.minecraft.sounds.SoundEvents", "sound_event", "net.minecraft.sounds.SoundEvent")
|
||||
).collect(Collectors.toMap(VanillaObjectHolderData::holderClass, Function.identity()));
|
||||
private final String OBJECT_HOLDER = "Lnet/minecraftforge/registries/ObjectHolder;"; //Don't directly reference this to prevent class loading.
|
||||
).collect(Collectors.toUnmodifiableMap(VanillaObjectHolderData::holderClass, Function.identity()));
|
||||
private static final String OBJECT_HOLDER = "Lnet/minecraftforge/registries/ObjectHolder;"; //Don't directly reference this to prevent class loading.
|
||||
private static final int PUBLIC_STATIC_FINAL_FLAGS = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
|
|
@ -51,8 +52,7 @@ public class ObjectHolderDefinalize implements ILaunchPluginService {
|
|||
return isEmpty ? NAY : YAY;
|
||||
}
|
||||
|
||||
private boolean hasHolder(List<AnnotationNode> lst)
|
||||
{
|
||||
private static boolean hasHolder(List<AnnotationNode> lst) {
|
||||
return lst != null && lst.stream().anyMatch(n -> n.desc.equals(OBJECT_HOLDER));
|
||||
}
|
||||
|
||||
|
|
@ -76,10 +76,9 @@ public class ObjectHolderDefinalize implements ILaunchPluginService {
|
|||
{
|
||||
final AtomicBoolean changes = new AtomicBoolean();
|
||||
//Must be public static finals, and non-array objects
|
||||
final int flags = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
|
||||
|
||||
//Fix Annotated Fields before injecting from class level
|
||||
classNode.fields.stream().filter(f -> ((f.access & flags) == flags) && f.desc.startsWith("L") && hasHolder(f.visibleAnnotations)).forEach(f ->
|
||||
classNode.fields.stream().filter(f -> ((f.access & PUBLIC_STATIC_FINAL_FLAGS) == PUBLIC_STATIC_FINAL_FLAGS) && f.desc.startsWith("L") && hasHolder(f.visibleAnnotations)).forEach(f ->
|
||||
{
|
||||
int prev = f.access;
|
||||
f.access &= ~Opcodes.ACC_FINAL; //Strip final
|
||||
|
|
@ -89,7 +88,7 @@ public class ObjectHolderDefinalize implements ILaunchPluginService {
|
|||
|
||||
if (VANILLA_OBJECT_HOLDERS.containsKey(classType.getClassName())) //Class level, de-finalize all fields and add @ObjectHolder to them!
|
||||
{
|
||||
classNode.fields.stream().filter(f -> ((f.access & flags) == flags) && f.desc.startsWith("L")).forEach(f ->
|
||||
classNode.fields.stream().filter(f -> ((f.access & PUBLIC_STATIC_FINAL_FLAGS) == PUBLIC_STATIC_FINAL_FLAGS) && f.desc.startsWith("L")).forEach(f ->
|
||||
{
|
||||
int prev = f.access;
|
||||
f.access &= ~Opcodes.ACC_FINAL;
|
||||
|
|
|
|||
|
|
@ -28,15 +28,16 @@ import org.slf4j.Logger;
|
|||
public class RuntimeEnumExtender implements ILaunchPluginService {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final Type STRING = Type.getType(String.class);
|
||||
private final Type ENUM = Type.getType(Enum.class);
|
||||
private final Type MARKER_IFACE = Type.getType("Lnet/minecraftforge/common/IExtensibleEnum;");
|
||||
private final Type ARRAY_UTILS = Type.getType("Lorg/apache/commons/lang3/ArrayUtils;"); //Don't directly reference this to prevent class loading.
|
||||
private final String ADD_DESC = Type.getMethodDescriptor(Type.getType(Object[].class), Type.getType(Object[].class), Type.getType(Object.class));
|
||||
private final Type UNSAFE_HACKS = Type.getType("Lnet/minecraftforge/fml/unsafe/UnsafeHacks;"); //Again, not direct reference to prevent class loading.
|
||||
private final String CLEAN_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Class.class));
|
||||
private final String NAME_DESC = Type.getMethodDescriptor(STRING);
|
||||
private final String EQUALS_DESC = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, STRING);
|
||||
private static final Type STRING = Type.getType(String.class);
|
||||
private static final Type ENUM = Type.getType(Enum.class);
|
||||
private static final Type MARKER_IFACE = Type.getType("Lnet/minecraftforge/common/IExtensibleEnum;");
|
||||
private static final Type ARRAY_UTILS = Type.getType("Lorg/apache/commons/lang3/ArrayUtils;"); //Don't directly reference this to prevent class loading.
|
||||
private static final String ADD_DESC = Type.getMethodDescriptor(Type.getType(Object[].class), Type.getType(Object[].class), Type.getType(Object.class));
|
||||
private static final Type UNSAFE_HACKS = Type.getType("Lnet/minecraftforge/fml/unsafe/UnsafeHacks;"); //Again, not direct reference to prevent class loading.
|
||||
private static final String CLEAN_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Class.class));
|
||||
private static final String NAME_DESC = Type.getMethodDescriptor(STRING);
|
||||
private static final String EQUALS_DESC = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, STRING);
|
||||
private static final int FLAGS = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC;
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
|
|
@ -59,9 +60,9 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
|
|||
return ComputeFlags.NO_REWRITE;
|
||||
|
||||
Type array = Type.getType("[" + classType.getDescriptor());
|
||||
final int flags = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC;
|
||||
String arrayDesc = array.getDescriptor();
|
||||
|
||||
FieldNode values = classNode.fields.stream().filter(f -> f.desc.contentEquals(array.getDescriptor()) && ((f.access & flags) == flags)).findFirst().orElse(null);
|
||||
FieldNode values = classNode.fields.stream().filter(f -> f.desc.equals(arrayDesc) && ((f.access & FLAGS) == FLAGS)).findFirst().orElse(null);
|
||||
|
||||
if (!classNode.interfaces.contains(MARKER_IFACE.getInternalName())) {
|
||||
return ComputeFlags.NO_REWRITE;
|
||||
|
|
@ -70,13 +71,13 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
|
|||
//Static methods named "create" with first argument as a string
|
||||
List<MethodNode> candidates = classNode.methods.stream()
|
||||
.filter(m -> ((m.access & Opcodes.ACC_STATIC) != 0) && m.name.equals("create"))
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
|
||||
if (candidates.isEmpty()) {
|
||||
throw new IllegalStateException("IExtensibleEnum has no candidate factory methods: " + classType.getClassName());
|
||||
}
|
||||
|
||||
candidates.forEach(mtd ->
|
||||
for (var mtd : candidates)
|
||||
{
|
||||
Type[] args = Type.getArgumentTypes(mtd.desc);
|
||||
if (args.length == 0 || !args[0].equals(STRING)) {
|
||||
|
|
@ -108,8 +109,7 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
|
|||
Type[] ctrArgs = new Type[args.length + 1];
|
||||
ctrArgs[0] = STRING;
|
||||
ctrArgs[1] = Type.INT_TYPE;
|
||||
for (int x = 1; x < args.length; x++)
|
||||
ctrArgs[1 + x] = args[x];
|
||||
System.arraycopy(args, 1, ctrArgs, 2, args.length - 1);
|
||||
|
||||
String desc = Type.getMethodDescriptor(Type.VOID_TYPE, ctrArgs);
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
|
|||
ins.load(vars, classType);
|
||||
ins.areturn(classType);
|
||||
}
|
||||
});
|
||||
}
|
||||
return ComputeFlags.COMPUTE_FRAMES;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,11 +17,9 @@ import net.minecraftforge.api.distmarker.Dist;
|
|||
import net.minecraftforge.fml.loading.targets.CommonLaunchHandler;
|
||||
import net.minecraftforge.forgespi.Environment;
|
||||
import net.minecraftforge.forgespi.coremod.ICoreModProvider;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -36,7 +34,6 @@ import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
|
|||
public class FMLLoader {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static AccessTransformerService accessTransformer;
|
||||
private static ModDiscoverer modDiscoverer;
|
||||
private static ICoreModProvider coreModProvider;
|
||||
private static LanguageLoadingProvider languageLoadingProvider;
|
||||
private static Dist dist;
|
||||
|
|
@ -62,7 +59,7 @@ public class FMLLoader {
|
|||
/*eventBus =*/ getPlugin(env, "eventbus", "1.0", "EventBus");
|
||||
runtimeDistCleaner = getPlugin(env, "runtimedistcleaner", "1.0", "RuntimeDistCleaner");
|
||||
coreModProvider = getSingleService(ICoreModProvider.class, "CoreMod");
|
||||
LOGGER.debug(CORE,"FML found CoreMod version : {}", JarVersionLookupHandler.getInfo(coreModProvider.getClass()).impl().version().orElse("MISSING"));
|
||||
LOGGER.debug(CORE, "FML found CoreMod version : {}", JarVersionLookupHandler.getInfo(coreModProvider.getClass()).impl().version().orElse("MISSING"));
|
||||
checkPackage(Environment.class, "2.0", "ForgeSPI");
|
||||
|
||||
try {
|
||||
|
|
@ -74,14 +71,15 @@ public class FMLLoader {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T getPlugin(IEnvironment env, String id, String version, String name) throws IncompatibleEnvironmentException {
|
||||
@SuppressWarnings("unchecked")
|
||||
var plugin = (T)env.findLaunchPlugin(id).orElseThrow(() -> {
|
||||
var plugin = env.findLaunchPlugin(id).orElse(null);
|
||||
if (plugin == null) {
|
||||
LOGGER.error(CORE, "{} library is missing, we need this to run", name);
|
||||
return new IncompatibleEnvironmentException("Missing " + name + ", cannot run");
|
||||
});
|
||||
throw new IncompatibleEnvironmentException("Missing " + name + ", cannot run");
|
||||
}
|
||||
checkPackage(plugin.getClass(), version, name);
|
||||
return plugin;
|
||||
return (T) plugin;
|
||||
}
|
||||
|
||||
private static void checkPackage(Class<?> cls, String version, String name) throws IncompatibleEnvironmentException {
|
||||
|
|
@ -137,20 +135,20 @@ public class FMLLoader {
|
|||
}
|
||||
commonLaunchHandler = (CommonLaunchHandler)launchHandler.get();
|
||||
launchHandlerName = launchHandler.get().name();
|
||||
gamePath = environment.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Paths.get(".").toAbsolutePath());
|
||||
gamePath = environment.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Path.of(".").toAbsolutePath());
|
||||
|
||||
naming = commonLaunchHandler.getNaming();
|
||||
dist = commonLaunchHandler.getDist();
|
||||
production = commonLaunchHandler.isProduction();
|
||||
|
||||
accessTransformer.getExtension().accept(Pair.of(naming, "srg"));
|
||||
accessTransformer.getExtension().accept(Map.entry(naming, "srg"));
|
||||
|
||||
runtimeDistCleaner.getExtension().accept(dist);
|
||||
}
|
||||
|
||||
public static List<ITransformationService.Resource> beginModScan(final Map<String,?> arguments) {
|
||||
LOGGER.debug(SCAN,"Scanning for Mod Locators");
|
||||
modDiscoverer = new ModDiscoverer(arguments);
|
||||
var modDiscoverer = new ModDiscoverer(arguments);
|
||||
modValidator = modDiscoverer.discoverMods();
|
||||
var pluginResources = modValidator.getPluginResources();
|
||||
return List.of(pluginResources);
|
||||
|
|
@ -172,10 +170,6 @@ public class FMLLoader {
|
|||
return languageLoadingProvider;
|
||||
}
|
||||
|
||||
static ModDiscoverer getModDiscoverer() {
|
||||
return modDiscoverer;
|
||||
}
|
||||
|
||||
public static CommonLaunchHandler getLaunchHandler() {
|
||||
return commonLaunchHandler;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
|||
|
||||
public class FMLServiceProvider implements ITransformationService {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private Map<String, Object> arguments;
|
||||
private final Map<String, Object> arguments = new HashMap<>();
|
||||
|
||||
public FMLServiceProvider() {
|
||||
var markers = System.getProperty("forge.logging.markers", "").split(",");
|
||||
|
|
@ -45,7 +45,6 @@ public class FMLServiceProvider implements ITransformationService {
|
|||
FMLConfig.load();
|
||||
LOGGER.debug(CORE, "Preparing ModFile");
|
||||
environment.computePropertyIfAbsent(Environment.Keys.MODFILEFACTORY.get(), k->ModFile::new);
|
||||
arguments = new HashMap<>();
|
||||
LOGGER.debug(CORE, "Preparing launch handler");
|
||||
FMLLoader.setupLaunchHandler(environment, arguments);
|
||||
FMLEnvironment.setupInteropEnvironment(environment);
|
||||
|
|
@ -68,14 +67,6 @@ public class FMLServiceProvider implements ITransformationService {
|
|||
FMLLoader.onInitialLoad(environment, otherServices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arguments(BiFunction<String, String, OptionSpecBuilder> argumentBuilder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void argumentValues(OptionResult option) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public @NotNull List<ITransformer> transformers() {
|
||||
|
|
|
|||
|
|
@ -78,9 +78,13 @@ public class LoadingModList
|
|||
|
||||
public void addAccessTransformers()
|
||||
{
|
||||
modFiles.stream()
|
||||
.map(ModFileInfo::getFile)
|
||||
.forEach(mod -> mod.getAccessTransformer().ifPresent(path -> FMLLoader.addAccessTransformer(path, mod)));
|
||||
for (ModFileInfo modFile : modFiles) {
|
||||
ModFile mod = modFile.getFile();
|
||||
var at = mod.getAccessTransformer().orElse(null);
|
||||
if (at != null) {
|
||||
FMLLoader.addAccessTransformer(at, mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addForScanning(BackgroundScanHandler backgroundScanHandler)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public class MCPNamingService implements INameMappingService {
|
|||
|
||||
@Override
|
||||
public Map.Entry<String, String> understanding() {
|
||||
return Pair.of("srg", "mcp");
|
||||
return Map.entry("srg", "mcp");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class MavenCoordinateResolver {
|
|||
(!extension.isEmpty() ? "." + extension : ".jar");
|
||||
|
||||
String[] groups = groupId.split("\\.");
|
||||
Path result = Paths.get(groups[0]);
|
||||
Path result = Path.of(groups[0]);
|
||||
for (int i = 1; i < groups.length; i++) {
|
||||
result = result.resolve(groups[i]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,13 +57,13 @@ public class ModSorter
|
|||
// Note this will never actually throw an error because the duplicate checks are done in ModDiscovererer before we get to this phase
|
||||
// So all this is really doing is wasting time.
|
||||
// But i'm leaving it here until I rewrite all of cpw's mod loading code because its such a clusterfuck.
|
||||
return LoadingModList.of(ms.systemMods, ms.systemMods.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(toList()), e);
|
||||
return LoadingModList.of(ms.systemMods, ms.systemMods.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).toList(), e);
|
||||
}
|
||||
// try and validate dependencies
|
||||
final List<ExceptionData> failedList = Stream.concat(ms.verifyDependencyVersions().stream(), errors.stream()).toList();
|
||||
// if we miss one or the other, we abort now
|
||||
if (!failedList.isEmpty()) {
|
||||
return LoadingModList.of(ms.systemMods, ms.systemMods.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(toList()), new EarlyLoadingException("failure to validate mod list", null, failedList));
|
||||
return LoadingModList.of(ms.systemMods, ms.systemMods.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).toList(), new EarlyLoadingException("failure to validate mod list", null, failedList));
|
||||
} else {
|
||||
// Otherwise, lets try and sort the modlist and proceed
|
||||
EarlyLoadingException earlyLoadingException = null;
|
||||
|
|
@ -89,9 +89,9 @@ public class ModSorter
|
|||
infos.keySet().forEach(graph::addNode);
|
||||
modFiles.stream()
|
||||
.map(ModFile::getModInfos)
|
||||
.<IModInfo>mapMulti(Iterable::forEach)
|
||||
.flatMap(List::stream)
|
||||
.map(IModInfo::getDependencies)
|
||||
.<IModInfo.ModVersion>mapMulti(Iterable::forEach)
|
||||
.<IModInfo.ModVersion>flatMap(List::stream)
|
||||
.forEach(dep -> addDependency(graph, dep));
|
||||
|
||||
final List<ModFileInfo> sorted;
|
||||
|
|
@ -107,7 +107,7 @@ public class ModSorter
|
|||
LOGGER.error(LOADING, "Mod Sorting failed.\nDetected Cycles: {}\n", cycles);
|
||||
}
|
||||
var dataList = cycles.stream()
|
||||
.<ModFileInfo>mapMulti(Iterable::forEach)
|
||||
.flatMap(Set::stream)
|
||||
.<IModInfo>mapMulti((mf,c)->mf.getMods().forEach(c))
|
||||
.map(IModInfo::getModId)
|
||||
.map(list -> new ExceptionData("fml.modloading.cycle", list))
|
||||
|
|
@ -116,7 +116,7 @@ public class ModSorter
|
|||
}
|
||||
this.sortedList = sorted.stream()
|
||||
.map(ModFileInfo::getMods)
|
||||
.<IModInfo>mapMulti(Iterable::forEach)
|
||||
.flatMap(List::stream)
|
||||
.map(ModInfo.class::cast)
|
||||
.collect(toList());
|
||||
this.modFiles = sorted.stream()
|
||||
|
|
@ -126,12 +126,14 @@ public class ModSorter
|
|||
|
||||
private void addDependency(MutableGraph<ModFileInfo> topoGraph, IModInfo.ModVersion dep)
|
||||
{
|
||||
final ModFileInfo self = (ModFileInfo)dep.getOwner().getOwningFile();
|
||||
final IModInfo targetModInfo = modIdNameLookup.get(dep.getModId());
|
||||
// soft dep that doesn't exist. Just return. No edge required.
|
||||
if (targetModInfo == null || !(targetModInfo.getOwningFile() instanceof final ModFileInfo target)) return;
|
||||
|
||||
final ModFileInfo self = (ModFileInfo)dep.getOwner().getOwningFile();
|
||||
if (self == target)
|
||||
return; // in case a jar has two mods that have dependencies between
|
||||
|
||||
switch (dep.getOrdering()) {
|
||||
case BEFORE -> topoGraph.putEdge(self, target);
|
||||
case AFTER -> topoGraph.putEdge(target, self);
|
||||
|
|
@ -165,7 +167,7 @@ public class ModSorter
|
|||
var container = modFilesByFirstId.get(systemMod);
|
||||
if (container != null && !container.isEmpty()) {
|
||||
LOGGER.debug("Found system mod: {}", systemMod);
|
||||
this.systemMods.add((ModFile) container.get(0));
|
||||
this.systemMods.add(container.getFirst());
|
||||
} else {
|
||||
throw new IllegalStateException("Failed to find system mod: " + systemMod);
|
||||
}
|
||||
|
|
@ -176,23 +178,23 @@ public class ModSorter
|
|||
{
|
||||
final var modVersions = modFiles.stream()
|
||||
.map(ModFile::getModInfos)
|
||||
.<IModInfo>mapMulti(Iterable::forEach)
|
||||
.flatMap(List::stream)
|
||||
.collect(toMap(IModInfo::getModId, IModInfo::getVersion));
|
||||
|
||||
final var modVersionDependencies = modFiles.stream()
|
||||
.map(ModFile::getModInfos)
|
||||
.<IModInfo>mapMulti(Iterable::forEach)
|
||||
.flatMap(List::stream)
|
||||
.collect(groupingBy(Function.identity(), flatMapping(e -> e.getDependencies().stream(), toList())));
|
||||
|
||||
final var modRequirements = modVersionDependencies.values().stream()
|
||||
.<IModInfo.ModVersion>mapMulti(Iterable::forEach)
|
||||
.<IModInfo.ModVersion>flatMap(List::stream)
|
||||
.filter(mv -> mv.getSide().isCorrectSide())
|
||||
.collect(toSet());
|
||||
|
||||
final long mandatoryRequired = modRequirements.stream().filter(IModInfo.ModVersion::isMandatory).count();
|
||||
LOGGER.debug(LOADING, "Found {} mod requirements ({} mandatory, {} optional)", modRequirements.size(), mandatoryRequired, modRequirements.size() - mandatoryRequired);
|
||||
final var missingVersions = modRequirements.stream()
|
||||
.filter(mv -> (mv.isMandatory() || modVersions.containsKey(mv.getModId())) && this.modVersionNotContained(mv, modVersions))
|
||||
.filter(mv -> (mv.isMandatory() || modVersions.containsKey(mv.getModId())) && !modVersionContained(mv, modVersions))
|
||||
.collect(toSet());
|
||||
final long mandatoryMissing = missingVersions.stream().filter(IModInfo.ModVersion::isMandatory).count();
|
||||
LOGGER.debug(LOADING, "Found {} mod requirements missing ({} mandatory, {} optional)", missingVersions.size(), mandatoryMissing, missingVersions.size() - mandatoryMissing);
|
||||
|
|
@ -240,9 +242,13 @@ public class ModSorter
|
|||
);
|
||||
}
|
||||
|
||||
private boolean modVersionNotContained(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
|
||||
{
|
||||
return !(VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod", (modId, range) -> modVersions.containsKey(modId) &&
|
||||
(range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("0.0NONE"))));
|
||||
private static boolean modVersionContained(IModInfo.ModVersion mv, Map<String, ArtifactVersion> modVersions) {
|
||||
var modId = mv.getModId();
|
||||
var range = mv.getVersionRange();
|
||||
if (modVersions.containsKey(modId)
|
||||
&& (range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("0.0NONE")))
|
||||
return true;
|
||||
|
||||
return VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ public class RuntimeDistCleaner implements ILaunchPluginService
|
|||
return unpacked;
|
||||
}
|
||||
|
||||
private boolean remove(final List<AnnotationNode> anns, final String side)
|
||||
private static boolean remove(final List<AnnotationNode> anns, final String side)
|
||||
{
|
||||
var onlyIns = unpack(anns);
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ public class RuntimeDistCleaner implements ILaunchPluginService
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean hasOnlyInWithModAnnotation(final List<AnnotationNode> anns)
|
||||
private static boolean hasOnlyInWithModAnnotation(final List<AnnotationNode> anns)
|
||||
{
|
||||
if (anns == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,16 +14,17 @@ import org.apache.commons.lang3.text.StrSubstitutor;
|
|||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class StringSubstitutor {
|
||||
private static final Map<String, String> GLOBALS = Map.of(
|
||||
"mcVersion", FMLLoader.versionInfo().mcVersion(),
|
||||
"forgeVersion", FMLLoader.versionInfo().forgeVersion()
|
||||
);
|
||||
|
||||
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) {
|
||||
var globals = Map.of(
|
||||
"mcVersion", FMLLoader.versionInfo().mcVersion(),
|
||||
"forgeVersion", FMLLoader.versionInfo().forgeVersion()
|
||||
);
|
||||
return new StrLookup<String>() {
|
||||
return new StrLookup<>() {
|
||||
@Override
|
||||
public String lookup(String key) {
|
||||
var parts = key.split("\\.");
|
||||
|
|
@ -32,7 +33,7 @@ public class StringSubstitutor {
|
|||
var pfx = parts[0];
|
||||
|
||||
if ("global".equals(pfx))
|
||||
return globals.get(parts[1]);
|
||||
return GLOBALS.get(parts[1]);
|
||||
else if ("file".equals(pfx) && file != null)
|
||||
return String.valueOf(file.getSubstitutionMap().get().get(parts[1]));
|
||||
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@ public class UniqueModListBuilder
|
|||
|
||||
// Select the newest by artifact version sorting of non-unique files thus identified
|
||||
uniqueModList = modFilesByFirstId.entrySet().stream()
|
||||
.map(this::selectNewestModInfo)
|
||||
.map(UniqueModListBuilder::selectNewestModInfo)
|
||||
.toList();
|
||||
|
||||
// Select the newest by artifact version sorting of non-unique files thus identified
|
||||
uniqueLibListWithVersion = libFilesWithVersionByModuleName.entrySet().stream()
|
||||
.map(this::selectNewestModInfo)
|
||||
.map(UniqueModListBuilder::selectNewestModInfo)
|
||||
.toList();
|
||||
|
||||
// Transform to the full mod id list
|
||||
|
|
@ -75,7 +75,7 @@ public class UniqueModListBuilder
|
|||
final List<String> dupedModErrors = modIds.values().stream()
|
||||
.filter(modInfos -> modInfos.size() > 1)
|
||||
.map(mods -> String.format("\tMod ID: '%s' from mod files: %s",
|
||||
mods.get(0).getModId(),
|
||||
mods.getFirst().getModId(),
|
||||
mods.stream()
|
||||
.map(modInfo -> modInfo.getOwningFile().getFile().getFileName()).collect(joining(", "))
|
||||
)).toList();
|
||||
|
|
@ -91,9 +91,8 @@ public class UniqueModListBuilder
|
|||
final List<String> dupedLibErrors = versionedLibIds.values().stream()
|
||||
.filter(modFiles -> modFiles.size() > 1)
|
||||
.map(mods -> String.format("\tLibrary: '%s' from files: %s",
|
||||
getModId(mods.get(0)),
|
||||
mods.stream()
|
||||
.map(modFile -> modFile.getFileName()).collect(joining(", "))
|
||||
getModId(mods.getFirst()),
|
||||
mods.stream().map(ModFile::getFileName).collect(joining(", "))
|
||||
)).toList();
|
||||
|
||||
if (!dupedLibErrors.isEmpty()) {
|
||||
|
|
@ -107,25 +106,23 @@ public class UniqueModListBuilder
|
|||
final Map<String, List<ModFile>> uniqueModFilesByFirstId = uniqueModList.stream()
|
||||
.collect(groupingBy(UniqueModListBuilder::getModId));
|
||||
|
||||
final List<ModFile> loadedList = new ArrayList<>();
|
||||
loadedList.addAll(uniqueModList);
|
||||
final List<ModFile> loadedList = new ArrayList<>(uniqueModList);
|
||||
loadedList.addAll(uniqueLibListWithVersion);
|
||||
|
||||
return new UniqueModListData(loadedList, uniqueModFilesByFirstId);
|
||||
}
|
||||
|
||||
private ModFile selectNewestModInfo(Map.Entry<String, List<ModFile>> fullList) {
|
||||
private static ModFile selectNewestModInfo(Map.Entry<String, List<ModFile>> fullList) {
|
||||
List<ModFile> modInfoList = fullList.getValue();
|
||||
if (modInfoList.size() > 1) {
|
||||
LOGGER.debug("Found {} mods for first modid {}, selecting most recent based on version data", modInfoList.size(), fullList.getKey());
|
||||
modInfoList.sort(Comparator.comparing(this::getVersion).reversed());
|
||||
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.get(0).getFileName(), fullList.getKey(), this.getVersion(modInfoList.get(0)));
|
||||
modInfoList.sort(Comparator.comparing(UniqueModListBuilder::getVersion).reversed());
|
||||
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.getFirst().getFileName(), fullList.getKey(), getVersion(modInfoList.getFirst()));
|
||||
}
|
||||
return modInfoList.get(0);
|
||||
}
|
||||
|
||||
private ArtifactVersion getVersion(final ModFile mf)
|
||||
{
|
||||
private static ArtifactVersion getVersion(final ModFile mf) {
|
||||
if (mf.getModFileInfo() == null || mf.getModInfos() == null || mf.getModInfos().isEmpty()) {
|
||||
return mf.getJarVersion();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,33 +5,53 @@
|
|||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import net.minecraftforge.forgespi.language.MavenVersionAdapter;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
@ApiStatus.Internal // since 1.21.1, will be made non-public in a later MC version
|
||||
public class VersionSupportMatrix {
|
||||
private static final HashMap<String, List<ArtifactVersion>> overrideVersions = new HashMap<>();
|
||||
private static final Map<String, List<ArtifactVersion>> OVERRIDE_VERSIONS;
|
||||
|
||||
static {
|
||||
final ArtifactVersion version = new DefaultArtifactVersion(FMLLoader.versionInfo().mcVersion());
|
||||
if (MavenVersionAdapter.createFromVersionSpec("[1.21.1]").containsVersion(version)) {
|
||||
// 1.21.1 is Compatible with 1.21
|
||||
add("languageloader.javafml", "51");
|
||||
add("mod.minecraft", "1.21");
|
||||
add("mod.forge", "51.0.33");
|
||||
if ("1.21.1".equals(FMLLoader.versionInfo().mcVersion())) {
|
||||
OVERRIDE_VERSIONS = Map.ofEntries(
|
||||
// 1.21.1 is compatible with 1.21
|
||||
entry("languageloader.javafml", "51"),
|
||||
entry("mod.minecraft", "1.21"),
|
||||
entry("mod.forge", "51.0.33")
|
||||
);
|
||||
} else {
|
||||
OVERRIDE_VERSIONS = Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
private static void add(String key, String value) {
|
||||
overrideVersions.computeIfAbsent(key, k -> new ArrayList<>()).add(new DefaultArtifactVersion(value));
|
||||
}
|
||||
public static <T> boolean testVersionSupportMatrix(VersionRange declaredRange, String lookupId, String type, BiPredicate<String, VersionRange> standardLookup) {
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #testVersionSupportMatrix(VersionRange, String, String)} instead, unwrapping your BiPredicate.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "1.21.1")
|
||||
public static boolean testVersionSupportMatrix(VersionRange declaredRange, String lookupId, String type, BiPredicate<String, VersionRange> standardLookup) {
|
||||
if (standardLookup.test(lookupId, declaredRange)) return true;
|
||||
List<ArtifactVersion> custom = overrideVersions.get(type + "." + lookupId);
|
||||
return custom == null ? false : custom.stream().anyMatch(declaredRange::containsVersion);
|
||||
return testVersionSupportMatrix(declaredRange, lookupId, type);
|
||||
}
|
||||
|
||||
public static boolean testVersionSupportMatrix(VersionRange declaredRange, String lookupId, String type) {
|
||||
if (OVERRIDE_VERSIONS.isEmpty()) return false;
|
||||
List<ArtifactVersion> custom = OVERRIDE_VERSIONS.get(type + "." + lookupId);
|
||||
return custom != null && custom.stream().anyMatch(declaredRange::containsVersion);
|
||||
}
|
||||
|
||||
private static Map.Entry<String, List<ArtifactVersion>> entry(String typeAndLookupId, String declaredRange) {
|
||||
return Map.entry(typeAndLookupId, List.of(new DefaultArtifactVersion(declaredRange)));
|
||||
}
|
||||
|
||||
private static Map.Entry<String, List<ArtifactVersion>> entry(String typeAndLookupId, List<String> declaredRanges) {
|
||||
return Map.entry(typeAndLookupId, declaredRanges.stream().map(DefaultArtifactVersion::new).map(it -> (ArtifactVersion) it).toList());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,10 +49,7 @@ public class ForgeHighlight {
|
|||
LOGGER.warn("Failed to invoke initializeTerminal on TCA", e);
|
||||
}
|
||||
if (!TerminalConsoleAppender.isAnsiSupported() && Arrays.stream(options).noneMatch(s -> s.equals("disableAnsi=true"))) {
|
||||
List<String> optionList = new ArrayList<>();
|
||||
optionList.add(options[0]);
|
||||
optionList.add("disableAnsi=true");
|
||||
options = optionList.toArray(new String[0]);
|
||||
options = new String[] { options[0], "disableAnsi=true" };
|
||||
}
|
||||
return HighlightConverter.newInstance(config, options);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,11 @@ public abstract class AbstractModProvider implements IModProvider {
|
|||
var mf = mod.getSecureJar().moduleDataProvider().getManifest().getMainAttributes();
|
||||
var license = mf.getValue("LICENSE");
|
||||
var dummy = new IConfigurable() {
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(String key) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(String... key) {
|
||||
return Optional.empty();
|
||||
|
|
@ -140,10 +145,11 @@ public abstract class AbstractModProvider implements IModProvider {
|
|||
}
|
||||
|
||||
private static final class Holder<T> {
|
||||
T value;
|
||||
private T value;
|
||||
}
|
||||
|
||||
private record DefaultModFileInfo(IModFile mod, String license, IConfigurable configurable) implements IModFileInfo, IConfigurable {
|
||||
@Override public <T> Optional<T> getConfigElement(final String string) { return Optional.empty(); }
|
||||
@Override public <T> Optional<T> getConfigElement(final String... strings) { return Optional.empty(); }
|
||||
@Override public List<? extends IConfigurable> getConfigList(final String... strings) { return null; }
|
||||
@Override public List<IModInfo> getMods() { return Collections.emptyList(); }
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public class BackgroundScanHandler
|
|||
}
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final boolean DEBUG = LOGGER.isErrorEnabled(LogMarkers.SCAN);
|
||||
private final ExecutorService modContentScanner;
|
||||
private final List<ModFile> modFiles;
|
||||
private ScanStatus status;
|
||||
|
|
@ -55,16 +56,16 @@ public class BackgroundScanHandler
|
|||
}
|
||||
status = ScanStatus.RUNNING;
|
||||
ImmediateWindowHandler.updateProgress("Scanning mod candidates");
|
||||
final CompletableFuture<ModFileScanData> future = CompletableFuture.supplyAsync(file::compileContent, modContentScanner)
|
||||
.whenComplete(file::setScanResult)
|
||||
.whenComplete((r,t)-> this.addCompletedFile(file,r,t));
|
||||
CompletableFuture<ModFileScanData> future = CompletableFuture.supplyAsync(file::compileContent, modContentScanner)
|
||||
.whenComplete(file::setScanResult);
|
||||
if (DEBUG) future = future.whenComplete((r, t) -> addCompletedFile(file, t));
|
||||
file.setFutureScanResult(future);
|
||||
}
|
||||
|
||||
private void addCompletedFile(final ModFile file, final ModFileScanData modFileScanData, final Throwable throwable) {
|
||||
private void addCompletedFile(final ModFile file, final Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
status = ScanStatus.ERRORED;
|
||||
LOGGER.error(LogMarkers.SCAN,"An error occurred scanning file {}", file, throwable);
|
||||
LOGGER.error(LogMarkers.SCAN, "An error occurred scanning file {}", file, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
|
|
@ -28,7 +28,7 @@ import java.util.jar.JarFile;
|
|||
import java.util.jar.Manifest;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class ClasspathLocator extends AbstractModProvider implements IModLocator {
|
||||
public final class ClasspathLocator extends AbstractModProvider implements IModLocator {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final Attributes.Name MOD_TYPE = new Attributes.Name("FMLModType");
|
||||
|
||||
|
|
@ -80,11 +80,11 @@ public class ClasspathLocator extends AbstractModProvider implements IModLocator
|
|||
return ret;
|
||||
}
|
||||
|
||||
private List<URL> getUrls(ClassLoader cl, String resource) {
|
||||
private static List<URL> getUrls(ClassLoader cl, String resource) {
|
||||
try {
|
||||
var lst = Collections.list(cl.getResources(resource));
|
||||
if (LOGGER.isDebugEnabled(LogMarkers.SCAN)) {
|
||||
Collections.sort(lst, (a, b) -> a.toString().compareTo(b.toString()));
|
||||
lst.sort(Comparator.comparing(URL::toString));
|
||||
LOGGER.debug(LogMarkers.SCAN, "Scanning Classloader: {} for {}", cl, resource);
|
||||
for (var url : lst)
|
||||
LOGGER.debug(LogMarkers.SCAN, "\t{}", url);
|
||||
|
|
@ -104,8 +104,7 @@ public class ClasspathLocator extends AbstractModProvider implements IModLocator
|
|||
len += 2;
|
||||
}
|
||||
str = str.substring(0, str.length() - len);
|
||||
var path = Paths.get(URI.create(str));
|
||||
return path;
|
||||
return Path.of(URI.create(str));
|
||||
}
|
||||
|
||||
private static Path getPathFromResource(ClassLoader cl, String resource) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import java.nio.file.Path;
|
|||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class CoreModFile implements ICoreModFile {
|
||||
public final class CoreModFile implements ICoreModFile {
|
||||
private final Path internalPath;
|
||||
private final ModFile file;
|
||||
private final String name;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraftforge.fml.loading.EarlyLoadingException;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
|
|
@ -26,6 +25,7 @@ import java.nio.file.FileSystem;
|
|||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -51,7 +51,7 @@ public class JarInJarDependencyLocator extends AbstractModProvider implements ID
|
|||
|
||||
@Override
|
||||
public List<IModFile> scanMods(Iterable<IModFile> loadedMods) {
|
||||
final List<IModFile> sources = Lists.newArrayList();
|
||||
final List<IModFile> sources = new ArrayList<>();
|
||||
loadedMods.forEach(sources::add);
|
||||
|
||||
var dependenciesToLoad = JarSelector.detectAndSelect(
|
||||
|
|
@ -102,34 +102,34 @@ public class JarInJarDependencyLocator extends AbstractModProvider implements ID
|
|||
protected EarlyLoadingException exception(Collection<JarSelector.ResolutionFailureInformation<IModFile>> failedDependencies) {
|
||||
final List<EarlyLoadingException.ExceptionData> errors = failedDependencies.stream()
|
||||
.filter(entry -> !entry.sources().isEmpty()) //Should never be the case, but just to be sure
|
||||
.map(this::buildExceptionData)
|
||||
.map(JarInJarDependencyLocator::buildExceptionData)
|
||||
.toList();
|
||||
|
||||
return new EarlyLoadingException(failedDependencies.size() + " Dependency restrictions were not met.", null, errors);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private EarlyLoadingException.ExceptionData buildExceptionData(JarSelector.ResolutionFailureInformation<IModFile> entry) {
|
||||
private static EarlyLoadingException.ExceptionData buildExceptionData(JarSelector.ResolutionFailureInformation<IModFile> entry) {
|
||||
return new EarlyLoadingException.ExceptionData(
|
||||
getErrorTranslationKey(entry),
|
||||
entry.identifier().group() + ":" + entry.identifier().artifact(),
|
||||
entry.sources()
|
||||
.stream()
|
||||
.flatMap(this::getModWithVersionRangeStream)
|
||||
.map(this::formatError)
|
||||
.flatMap(JarInJarDependencyLocator::getModWithVersionRangeStream)
|
||||
.map(JarInJarDependencyLocator::formatError)
|
||||
.collect(Collectors.joining(", "))
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getErrorTranslationKey(JarSelector.ResolutionFailureInformation<IModFile> entry) {
|
||||
private static String getErrorTranslationKey(JarSelector.ResolutionFailureInformation<IModFile> entry) {
|
||||
return entry.failureReason() == JarSelector.FailureReason.VERSION_RESOLUTION_FAILED ?
|
||||
"fml.dependencyloading.conflictingdependencies" :
|
||||
"fml.dependencyloading.mismatchedcontaineddependencies";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Stream<ModWithVersionRange> getModWithVersionRangeStream(JarSelector.SourceWithRequestedVersionRange<IModFile> file) {
|
||||
private static Stream<ModWithVersionRange> getModWithVersionRangeStream(JarSelector.SourceWithRequestedVersionRange<IModFile> file) {
|
||||
return file.sources()
|
||||
.stream()
|
||||
.map(IModFile::getModFileInfo)
|
||||
|
|
@ -152,7 +152,7 @@ public class JarInJarDependencyLocator extends AbstractModProvider implements ID
|
|||
}
|
||||
|
||||
@NotNull
|
||||
private String formatError(ModWithVersionRange modWithVersionRange){
|
||||
private static String formatError(ModWithVersionRange modWithVersionRange){
|
||||
return YELLOW + modWithVersionRange.modInfo().getModId() + RESET + " - " +
|
||||
RED + modWithVersionRange.versionRange().toString() + RESET + " - " +
|
||||
GREEN + modWithVersionRange.artifactVersion().toString() + RESET;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import java.util.List;
|
|||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class MinecraftLocator extends AbstractModProvider implements IModLocator {
|
||||
public final class MinecraftLocator extends AbstractModProvider implements IModLocator {
|
||||
@Override
|
||||
public List<IModLocator.ModFileOrException> scanMods() {
|
||||
var minecraft = FMLLoader.getLaunchHandler().getMinecraftPaths();
|
||||
|
|
@ -29,13 +29,13 @@ public class MinecraftLocator extends AbstractModProvider implements IModLocator
|
|||
jar -> meta,
|
||||
minecraft.toArray(Path[]::new)
|
||||
);
|
||||
var mc = ModFileFactory.FACTORY.build(mcjar, this, this::buildMinecraftTOML);
|
||||
var mc = ModFileFactory.FACTORY.build(mcjar, this, MinecraftLocator::buildMinecraftTOML);
|
||||
meta.setModFile(mc);
|
||||
|
||||
return List.of(new ModFileOrException(mc, null));
|
||||
}
|
||||
|
||||
private IModFileInfo buildMinecraftTOML(final IModFile iModFile) {
|
||||
private static IModFileInfo buildMinecraftTOML(final IModFile iModFile) {
|
||||
// We haven't changed this in years, and I can't be asked right now to special case this one file in the path.
|
||||
final var conf = Config.inMemory();
|
||||
conf.set("modLoader", "minecraft");
|
||||
|
|
@ -52,7 +52,7 @@ public class MinecraftLocator extends AbstractModProvider implements IModLocator
|
|||
conf.set("mods", List.of(mods));
|
||||
|
||||
var configWrapper = new NightConfigWrapper(conf);
|
||||
return new ModFileInfo((ModFile)iModFile, configWrapper, configWrapper::setFile, List.of());
|
||||
return new ModFileInfo((ModFile) iModFile, configWrapper, configWrapper::setFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.modlauncher.Launcher;
|
||||
import cpw.mods.modlauncher.api.IModuleLayerManager;
|
||||
|
|
@ -28,6 +27,7 @@ import org.jetbrains.annotations.ApiStatus;
|
|||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
|
@ -49,17 +49,19 @@ public class ModDiscoverer {
|
|||
modLocators = ServiceLoader.load(moduleLayerManager.getLayer(IModuleLayerManager.Layer.SERVICE).orElseThrow(), IModLocator.class);
|
||||
dependencyLocators = ServiceLoader.load(moduleLayerManager.getLayer(IModuleLayerManager.Layer.SERVICE).orElseThrow(), IDependencyLocator.class);
|
||||
modLocatorList = ServiceLoaderUtils.streamServiceLoader(()-> modLocators, sce->LOGGER.error("Failed to load mod locator list", sce)).collect(Collectors.toList());
|
||||
modLocatorList.forEach(l->l.initArguments(arguments));
|
||||
for (IModLocator iModLocator : modLocatorList) {
|
||||
iModLocator.initArguments(arguments);
|
||||
}
|
||||
dependencyLocatorList = ServiceLoaderUtils.streamServiceLoader(()-> dependencyLocators, sce->LOGGER.error("Failed to load dependency locator list", sce)).collect(Collectors.toList());
|
||||
dependencyLocatorList.forEach(l->l.initArguments(arguments));
|
||||
for (IDependencyLocator l : dependencyLocatorList) {
|
||||
l.initArguments(arguments);
|
||||
}
|
||||
if (LOGGER.isDebugEnabled(LogMarkers.CORE))
|
||||
{
|
||||
LOGGER.debug(LogMarkers.CORE, "Found Mod Locators : {}", modLocatorList.stream()
|
||||
.map(modLocator -> "(%s:%s)".formatted(modLocator.name(),
|
||||
modLocator.getClass().getPackage().getImplementationVersion())).collect(Collectors.joining(",")));
|
||||
}
|
||||
if (LOGGER.isDebugEnabled(LogMarkers.CORE))
|
||||
{
|
||||
|
||||
LOGGER.debug(LogMarkers.CORE, "Found Dependency Locators : {}", dependencyLocatorList.stream()
|
||||
.map(dependencyLocator -> "(%s:%s)".formatted(dependencyLocator.name(),
|
||||
dependencyLocator.getClass().getPackage().getImplementationVersion())).collect(Collectors.joining(",")));
|
||||
|
|
@ -126,7 +128,7 @@ public class ModDiscoverer {
|
|||
}
|
||||
|
||||
//First processing run of the mod list. Any duplicates will cause resolution failure and dependency loading will be skipped.
|
||||
Map<IModFile.Type, List<ModFile>> modFilesMap = Maps.newHashMap();
|
||||
Map<IModFile.Type, List<ModFile>> modFilesMap = new EnumMap<>(IModFile.Type.class);
|
||||
try {
|
||||
final UniqueModListBuilder modsUniqueListBuilder = new UniqueModListBuilder(loadedFiles);
|
||||
final UniqueModListBuilder.UniqueModListData uniqueModsData = modsUniqueListBuilder.buildUniqueList();
|
||||
|
|
@ -134,7 +136,7 @@ public class ModDiscoverer {
|
|||
//Grab the temporary results.
|
||||
//This allows loading to continue to a base state, in case dependency loading fails.
|
||||
modFilesMap = uniqueModsData.modFiles().stream()
|
||||
.collect(Collectors.groupingBy(IModFile::getType));
|
||||
.collect(Collectors.groupingBy(IModFile::getType, () -> new EnumMap<>(IModFile.Type.class), Collectors.toList()));
|
||||
loadedFiles = uniqueModsData.modFiles();
|
||||
}
|
||||
catch (EarlyLoadingException exception) {
|
||||
|
|
@ -171,11 +173,11 @@ public class ModDiscoverer {
|
|||
|
||||
//We now only need the mod files map, not the list.
|
||||
modFilesMap = uniqueModsAndDependenciesData.modFiles().stream()
|
||||
.collect(Collectors.groupingBy(IModFile::getType));
|
||||
.collect(Collectors.groupingBy(IModFile::getType, () -> new EnumMap<>(IModFile.Type.class), Collectors.toList()));
|
||||
} catch (EarlyLoadingException exception) {
|
||||
LOGGER.error(LogMarkers.SCAN, "Failed to build unique mod list after dependency discovery.", exception);
|
||||
discoveryErrorData.addAll(exception.getAllData());
|
||||
modFilesMap = loadedFiles.stream().collect(Collectors.groupingBy(IModFile::getType));
|
||||
modFilesMap = loadedFiles.stream().collect(Collectors.groupingBy(IModFile::getType, () -> new EnumMap<>(IModFile.Type.class), Collectors.toList()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -190,8 +192,7 @@ public class ModDiscoverer {
|
|||
return validator;
|
||||
}
|
||||
|
||||
private void handleLocatedFiles(final List<ModFile> loadedFiles, final List<IModFile> locatedFiles)
|
||||
{
|
||||
private static void handleLocatedFiles(final List<ModFile> loadedFiles, final List<IModFile> locatedFiles) {
|
||||
var locatedModFiles = locatedFiles.stream().filter(ModFile.class::isInstance).map(ModFile.class::cast).toList();
|
||||
for (IModFile mf : locatedModFiles) {
|
||||
LOGGER.info(LogMarkers.SCAN, "Found mod file {} of type {} with provider {}", mf.getFileName(), mf.getType(), mf.getProvider());
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ public class ModFile implements IModFile {
|
|||
private Throwable scanError;
|
||||
private final SecureJar jar;
|
||||
private final Type modFileType;
|
||||
private final Manifest manifest;
|
||||
private final IModProvider provider;
|
||||
private IModFileInfo modFileInfo;
|
||||
private ModFileScanData fileModFileScanData;
|
||||
|
|
@ -65,7 +64,7 @@ public class ModFile implements IModFile {
|
|||
this.jar = jar;
|
||||
this.parser = parser;
|
||||
|
||||
manifest = this.jar.moduleDataProvider().getManifest();
|
||||
var manifest = this.jar.moduleDataProvider().getManifest();
|
||||
modFileType = Type.valueOf(type);
|
||||
jarVersion = Optional.ofNullable(manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION)).orElse("0.0NONE");
|
||||
this.modFileInfo = ModFileParser.readModList(this, this.parser);
|
||||
|
|
|
|||
|
|
@ -104,11 +104,11 @@ public class ModFileInfo implements IModFileInfo, IConfigurable {
|
|||
this.modFile.setFileProperties(this.properties);
|
||||
|
||||
final List<? extends IConfigurable> modConfigs = config.getConfigList("mods");
|
||||
if (modConfigs.isEmpty())
|
||||
if (modConfigs == null || modConfigs.isEmpty())
|
||||
throw new InvalidModFileException("Missing mods list", this);
|
||||
|
||||
this.mods = modConfigs.stream()
|
||||
.map(mi-> (IModInfo)new ModInfo(this, mi))
|
||||
.map(mi -> (IModInfo) ModInfo.of(this, mi))
|
||||
.toList();
|
||||
|
||||
if (LOGGER.isDebugEnabled(LogMarkers.LOADING)) {
|
||||
|
|
@ -158,6 +158,11 @@ public class ModFileInfo implements IModFileInfo, IConfigurable {
|
|||
return this.showAsDataPack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(final String key) {
|
||||
return this.config.getConfigElement(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(final String... key) {
|
||||
return this.config.getConfigElement(key);
|
||||
|
|
@ -186,7 +191,7 @@ public class ModFileInfo implements IModFileInfo, IConfigurable {
|
|||
return Strings.isNullOrEmpty(license);
|
||||
}
|
||||
|
||||
private final char[] HEX = "0123456789ABCDEF".toCharArray();
|
||||
private static final char[] HEX = "0123456789ABCDEF".toCharArray();
|
||||
public Optional<String> getCodeSigningFingerprint() {
|
||||
var signers = this.modFile.getSecureJar().getManifestSigners();
|
||||
if (signers == null)
|
||||
|
|
|
|||
|
|
@ -27,211 +27,181 @@ import java.util.Optional;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class ModInfo implements IModInfo, IConfigurable {
|
||||
public record ModInfo(
|
||||
ModFileInfo getOwningFile,
|
||||
IConfigurable getConfig,
|
||||
|
||||
String getModId,
|
||||
String getNamespace,
|
||||
ArtifactVersion getVersion,
|
||||
|
||||
String getDisplayName,
|
||||
String getDescription,
|
||||
Optional<String> getLogoFile,
|
||||
boolean getLogoBlur,
|
||||
Optional<URL> getUpdateURL,
|
||||
Optional<URL> getModURL,
|
||||
|
||||
Holder<List<? extends ModVersion>> dependencies,
|
||||
Holder<List<ForgeFeature.Bound>> forgeFeatures,
|
||||
Map<String, Object> getModProperties
|
||||
) implements IModInfo, IConfigurable {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final DefaultArtifactVersion DEFAULT_VERSION = new DefaultArtifactVersion("1");
|
||||
private static final Pattern VALID_MODID = Pattern.compile("^[a-z][a-z0-9_]{1,63}$");
|
||||
private static final Pattern VALID_NAMESPACE = Pattern.compile("^[a-z][a-z0-9_.-]{1,63}$");
|
||||
private static final Pattern VALID_VERSION = Pattern.compile("^\\d+.*");
|
||||
|
||||
private final ModFileInfo owningFile;
|
||||
private final String modId;
|
||||
private final String namespace;
|
||||
private final ArtifactVersion version;
|
||||
private final String displayName;
|
||||
private final String description;
|
||||
private final Optional<String> logoFile;
|
||||
private final boolean logoBlur;
|
||||
private final Optional<URL> updateJSONURL;
|
||||
private final List<? extends IModInfo.ModVersion> dependencies;
|
||||
|
||||
private final List<ForgeFeature.Bound> features;
|
||||
private final Map<String,Object> properties;
|
||||
private final IConfigurable config;
|
||||
private final Optional<URL> modUrl;
|
||||
|
||||
public ModInfo(final ModFileInfo owningFile, final IConfigurable config) {
|
||||
Optional<ModFileInfo> ownFile = Optional.ofNullable(owningFile);
|
||||
this.owningFile = owningFile;
|
||||
this.config = config;
|
||||
|
||||
public static ModInfo of(ModFileInfo owningFile, IConfigurable config) {
|
||||
// These are sourced from the mod specific [[mod]] entry
|
||||
this.modId = config.<String>getConfigElement("modId")
|
||||
.orElseThrow(() -> new InvalidModFileException("Missing modId", owningFile));
|
||||
String modId = config.<String>getConfigElement("modId").orElse(null);
|
||||
if (modId == null)
|
||||
throw new InvalidModFileException("Missing modId", owningFile);
|
||||
|
||||
// verify we have a valid modid
|
||||
if (!VALID_MODID.matcher(this.modId).matches()) {
|
||||
LOGGER.error(LogUtils.FATAL_MARKER, "Invalid modId found in file {} - {} does not match the standard: {}", this.owningFile.getFile().getFilePath(), this.modId, VALID_MODID.pattern());
|
||||
throw new InvalidModFileException("Invalid modId found : " + this.modId, owningFile);
|
||||
if (!VALID_MODID.matcher(modId).matches()) {
|
||||
LOGGER.error(LogUtils.FATAL_MARKER, "Invalid modId found in file {} - {} does not match the standard: {}", owningFile.getFile().getFilePath(), modId, VALID_MODID.pattern());
|
||||
throw new InvalidModFileException("Invalid modId found : " + modId, owningFile);
|
||||
}
|
||||
|
||||
this.namespace = config.<String>getConfigElement("namespace")
|
||||
.orElse(this.modId);
|
||||
String namespace = config.<String>getConfigElement("namespace")
|
||||
.orElse(modId);
|
||||
|
||||
// verify our namespace is valid
|
||||
if (!VALID_NAMESPACE.matcher(this.namespace).matches()) {
|
||||
LOGGER.error(LogUtils.FATAL_MARKER, "Invalid override namespace found in file {} - {} does not match the standard: {}", this.owningFile.getFile().getFilePath(), this.namespace, VALID_NAMESPACE.pattern());
|
||||
throw new InvalidModFileException("Invalid override namespace found : " + this.namespace, owningFile);
|
||||
if (!VALID_NAMESPACE.matcher(namespace).matches()) {
|
||||
LOGGER.error(LogUtils.FATAL_MARKER, "Invalid override namespace found in file {} - {} does not match the standard: {}", owningFile.getFile().getFilePath(), namespace, VALID_NAMESPACE.pattern());
|
||||
throw new InvalidModFileException("Invalid override namespace found : " + namespace, owningFile);
|
||||
}
|
||||
|
||||
this.version = config.<String>getConfigElement("version")
|
||||
.map(s -> StringSubstitutor.replace(s, ownFile.map(ModFileInfo::getFile).orElse(null)))
|
||||
ArtifactVersion version = config.<String>getConfigElement("version")
|
||||
.map(s -> StringSubstitutor.replace(s, owningFile.getFile()))
|
||||
.map(DefaultArtifactVersion::new)
|
||||
.orElse(DEFAULT_VERSION);
|
||||
|
||||
// verify we have a valid mod version
|
||||
if (!VALID_VERSION.matcher(this.version.toString()).matches())
|
||||
throw new InvalidModFileException("Illegal version number specified " + this.version, this.getOwningFile());
|
||||
if (!VALID_VERSION.matcher(version.toString()).matches())
|
||||
throw new InvalidModFileException("Illegal version number specified " + version, owningFile);
|
||||
|
||||
// The remaining properties all default to sensible values and are not essential
|
||||
this.displayName = config.<String>getConfigElement("displayName")
|
||||
.orElse(this.modId);
|
||||
this.description = config.<String>getConfigElement("description")
|
||||
String displayName = config.<String>getConfigElement("displayName")
|
||||
.orElse(modId);
|
||||
|
||||
String description = config.<String>getConfigElement("description")
|
||||
.orElse("MISSING DESCRIPTION")
|
||||
.replace("\r\n", "\n").stripIndent();
|
||||
this.logoFile = Optional.ofNullable(config.<String>getConfigElement("logoFile")
|
||||
.orElseGet(() -> ownFile.flatMap(mf -> mf.<String>getConfigElement("logoFile"))
|
||||
.orElse(null)));
|
||||
this.logoBlur = config.<Boolean>getConfigElement("logoBlur")
|
||||
.orElseGet(() -> ownFile.flatMap(mf -> mf.<Boolean>getConfigElement("logoBlur"))
|
||||
.orElse(true));
|
||||
this.updateJSONURL = config.<String>getConfigElement("updateJSONURL")
|
||||
.map(StringUtils::toURL);
|
||||
this.modUrl = config.<String>getConfigElement("modUrl")
|
||||
|
||||
Optional<String> logoFile = Optional.ofNullable(
|
||||
config.<String>getConfigElement("logoFile")
|
||||
.orElseGet(() -> owningFile.<String>getConfigElement("logoFile").orElse(null))
|
||||
);
|
||||
|
||||
Boolean logoBlur = config.<Boolean>getConfigElement("logoBlur").orElse(null);
|
||||
if (logoBlur == null)
|
||||
logoBlur = owningFile.<Boolean>getConfigElement("logoBlur").orElse(true);
|
||||
|
||||
Optional<URL> updateJSONURL = config.<String>getConfigElement("updateJSONURL")
|
||||
.map(StringUtils::toURL);
|
||||
|
||||
// These are sourced from the file rather than the mod-specific block, but with a modid tag
|
||||
if (ownFile.isEmpty()) {
|
||||
this.dependencies = Collections.emptyList();
|
||||
this.features = Collections.emptyList();
|
||||
this.properties = Collections.emptyMap();
|
||||
} else {
|
||||
var deps = this.owningFile.getConfigList("dependencies", this.modId);
|
||||
if (deps == null || deps.isEmpty()) {
|
||||
this.dependencies = Collections.emptyList();
|
||||
} else {
|
||||
var tmp = new ArrayList<ModVersion>();
|
||||
for (var dep : deps)
|
||||
tmp.add(new ModVersion(this, dep));
|
||||
this.dependencies = Collections.unmodifiableList(tmp);
|
||||
}
|
||||
Optional<URL> modUrl = config.<String>getConfigElement("modUrl")
|
||||
.map(StringUtils::toURL);
|
||||
|
||||
var feats = this.owningFile.<Map<String, Object>>getConfigElement("features", this.modId).orElse(null);
|
||||
if (feats == null) {
|
||||
this.features = Collections.emptyList();
|
||||
} else {
|
||||
var tmp = new ArrayList<ForgeFeature.Bound>();
|
||||
for (var entry : feats.entrySet()) {
|
||||
if (!(entry.getValue() instanceof String val))
|
||||
throw new InvalidModFileException("Invalid feature bound {" + entry.getValue() + "} for key {" + entry.getKey() + "} only strings are accepted", this.owningFile);
|
||||
tmp.add(new ForgeFeature.Bound(entry.getKey(), val, this));
|
||||
}
|
||||
this.features = Collections.unmodifiableList(tmp);
|
||||
}
|
||||
// dependencies and features are done after the constructor as they need to reference the ModInfo we are creating
|
||||
List<? extends ModVersion> dependencies = Collections.emptyList();
|
||||
List<ForgeFeature.Bound> forgeFeatures = Collections.emptyList();
|
||||
|
||||
var props = this.owningFile.<Map<String, Object>>getConfigElement("modproperties", this.modId).orElse(null);
|
||||
if (props == null)
|
||||
this.properties = Collections.emptyMap();
|
||||
else
|
||||
this.properties = Collections.unmodifiableMap(props);
|
||||
Map<String, Object> modProperties = owningFile.<Map<String, Object>>getConfigElement("modproperties", modId)
|
||||
.map(Collections::unmodifiableMap)
|
||||
.orElse(Collections.emptyMap());
|
||||
|
||||
return new ModInfo(
|
||||
owningFile, config,
|
||||
modId, namespace, version,
|
||||
displayName, description, logoFile, logoBlur, updateJSONURL, modUrl,
|
||||
new Holder<>(dependencies), new Holder<>(forgeFeatures), modProperties
|
||||
).setupDependencies().setupForgeFeatures();
|
||||
}
|
||||
|
||||
private ModInfo setupDependencies() {
|
||||
var deps = getOwningFile.getConfigList("dependencies", getModId);
|
||||
if (deps == null || deps.isEmpty()) {
|
||||
dependencies.value = Collections.emptyList();
|
||||
return this;
|
||||
}
|
||||
|
||||
var tmp = new ModVersion[deps.size()];
|
||||
for (int i = 0; i < deps.size(); i++) {
|
||||
tmp[i] = ModVersion.of(this, deps.get(i));
|
||||
}
|
||||
dependencies.value = List.of(tmp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModFileInfo getOwningFile() {
|
||||
return owningFile;
|
||||
}
|
||||
private ModInfo setupForgeFeatures() {
|
||||
var feats = getOwningFile.<Map<String, Object>>getConfigElement("features", getModId).orElse(null);
|
||||
if (feats == null) {
|
||||
forgeFeatures.value = Collections.emptyList();
|
||||
return this;
|
||||
}
|
||||
|
||||
@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<? extends IModInfo.ModVersion> getDependencies() {
|
||||
return this.dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getModProperties() {
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URL> getUpdateURL() {
|
||||
return this.updateJSONURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getLogoFile() {
|
||||
return this.logoFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getLogoBlur() {
|
||||
return this.logoBlur;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IConfigurable getConfig() {
|
||||
var tmp = new ArrayList<ForgeFeature.Bound>();
|
||||
for (var entry : feats.entrySet()) {
|
||||
if (!(entry.getValue() instanceof String val))
|
||||
throw new InvalidModFileException("Invalid feature bound {" + entry.getValue() + "} for key {" + entry.getKey() + "} only strings are accepted", getOwningFile);
|
||||
tmp.add(new ForgeFeature.Bound(entry.getKey(), val, this));
|
||||
}
|
||||
forgeFeatures.value = List.copyOf(tmp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends ForgeFeature.Bound> getForgeFeatures() {
|
||||
return this.features;
|
||||
public <T> Optional<T> getConfigElement(String key) {
|
||||
return getConfig.getConfigElement(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(final String... key) {
|
||||
return this.config.getConfigElement(key);
|
||||
public <T> Optional<T> getConfigElement(String... key) {
|
||||
return getConfig.getConfigElement(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IConfigurable> getConfigList(final String... key) {
|
||||
public List<? extends IConfigurable> getConfigList(String... key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URL> getModURL() {
|
||||
return modUrl;
|
||||
public List<? extends IModInfo.ModVersion> getDependencies() {
|
||||
return dependencies.value;
|
||||
}
|
||||
|
||||
class ModVersion implements net.minecraftforge.forgespi.language.IModInfo.ModVersion {
|
||||
private IModInfo owner;
|
||||
private final String modId;
|
||||
private final VersionRange versionRange;
|
||||
private final boolean mandatory;
|
||||
private final Ordering ordering;
|
||||
private final DependencySide side;
|
||||
private final Optional<URL> referralUrl;
|
||||
@Override
|
||||
public List<? extends ForgeFeature.Bound> getForgeFeatures() {
|
||||
return forgeFeatures.value;
|
||||
}
|
||||
|
||||
public ModVersion(final IModInfo owner, final IConfigurable config) {
|
||||
this.owner = owner;
|
||||
this.modId = config.<String>getConfigElement("modId")
|
||||
.orElseThrow(()->new InvalidModFileException("Missing required field modid in dependency", getOwningFile()));
|
||||
private static final class Holder<T> {
|
||||
private T value;
|
||||
|
||||
if (this.modId.equals("forge")) {
|
||||
public Holder(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private record ModVersion(
|
||||
Holder<IModInfo> owner,
|
||||
|
||||
String getModId,
|
||||
VersionRange getVersionRange,
|
||||
boolean isMandatory,
|
||||
Ordering getOrdering,
|
||||
DependencySide getSide,
|
||||
Optional<URL> getReferralURL
|
||||
) implements IModInfo.ModVersion {
|
||||
public static ModVersion of(IModInfo owner, IConfigurable config) {
|
||||
var modId = config.<String>getConfigElement("modId").orElse(null);
|
||||
if (modId == null)
|
||||
throw new InvalidModFileException("Missing required field modid in dependency", owner.getOwningFile());
|
||||
|
||||
if (modId.equals("forge")) {
|
||||
var fileProps = owner.getOwningFile().getFileProperties();
|
||||
// Checking containsKey to avoid a possible exception if the property is not present (due to Collections.emptyMap())
|
||||
if (!fileProps.isEmpty() && fileProps.containsKey(ModFileInfo.NOT_A_FORGE_MOD_PROP)) {
|
||||
|
|
@ -241,65 +211,41 @@ public class ModInfo implements IModInfo, IConfigurable {
|
|||
}
|
||||
}
|
||||
|
||||
var mandatory = config.<Boolean>getConfigElement("mandatory");
|
||||
if (mandatory.isPresent())
|
||||
this.mandatory = mandatory.get();
|
||||
boolean mandatory;
|
||||
var mandatoryValue = config.<Boolean>getConfigElement("mandatory");
|
||||
if (mandatoryValue.isPresent())
|
||||
mandatory = mandatoryValue.get();
|
||||
else if (owner.getOwningFile().getFileProperties().containsKey(ModFileInfo.NOT_A_FORGE_MOD_PROP))
|
||||
this.mandatory = true;
|
||||
mandatory = true;
|
||||
else
|
||||
throw new InvalidModFileException("Missing required field mandatory in dependency", getOwningFile());
|
||||
throw new InvalidModFileException("Missing required field mandatory in dependency", owner.getOwningFile());
|
||||
|
||||
this.versionRange = config.<String>getConfigElement("versionRange")
|
||||
var versionRange = config.<String>getConfigElement("versionRange")
|
||||
.map(MavenVersionAdapter::createFromVersionSpec)
|
||||
.orElse(UNBOUNDED);
|
||||
this.ordering = config.<String>getConfigElement("ordering")
|
||||
var ordering = config.<String>getConfigElement("ordering")
|
||||
.map(Ordering::valueOf)
|
||||
.orElse(Ordering.NONE);
|
||||
this.side = config.<String>getConfigElement("side")
|
||||
var side = config.<String>getConfigElement("side")
|
||||
.map(DependencySide::valueOf)
|
||||
.orElse(DependencySide.BOTH);
|
||||
this.referralUrl = config.<String>getConfigElement("referralUrl")
|
||||
var referralUrl = config.<String>getConfigElement("referralUrl")
|
||||
.map(StringUtils::toURL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModId() {
|
||||
return modId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VersionRange getVersionRange() {
|
||||
return versionRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMandatory() {
|
||||
return mandatory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ordering getOrdering() {
|
||||
return ordering;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencySide getSide() {
|
||||
return side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwner(final IModInfo owner) {
|
||||
this.owner = owner;
|
||||
return new ModVersion(
|
||||
new Holder<>(owner),
|
||||
modId, versionRange, mandatory, ordering, side, referralUrl
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModInfo getOwner() {
|
||||
return owner;
|
||||
return owner.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URL> getReferralURL() {
|
||||
return referralUrl;
|
||||
public void setOwner(IModInfo newOwner) {
|
||||
owner.value = newOwner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public class ModValidator {
|
|||
}
|
||||
|
||||
@NotNull
|
||||
private List<ModFile> validateFiles(final List<ModFile> mods) {
|
||||
private static List<ModFile> validateFiles(final List<ModFile> mods) {
|
||||
final List<ModFile> brokenFiles = new ArrayList<>();
|
||||
for (Iterator<ModFile> iterator = mods.iterator(); iterator.hasNext();) {
|
||||
ModFile modFile = iterator.next();
|
||||
|
|
@ -106,8 +106,8 @@ public class ModValidator {
|
|||
|
||||
private List<EarlyLoadingException.ExceptionData> validateLanguages() {
|
||||
List<EarlyLoadingException.ExceptionData> errorData = new ArrayList<>();
|
||||
for (Iterator<ModFile> iterator = this.candidateMods.iterator(); iterator.hasNext(); ) {
|
||||
final ModFile modFile = iterator.next();
|
||||
for (Iterator<ModFile> iterator = this.candidateMods.iterator(); iterator.hasNext();) {
|
||||
var modFile = iterator.next();
|
||||
try {
|
||||
modFile.identifyLanguage();
|
||||
} catch (EarlyLoadingException e) {
|
||||
|
|
|
|||
|
|
@ -18,11 +18,12 @@ import java.util.Optional;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
@ApiStatus.Internal
|
||||
class NightConfigWrapper implements IConfigurable {
|
||||
final class NightConfigWrapper implements IConfigurable {
|
||||
private final UnmodifiableConfig config;
|
||||
private IModFileInfo file;
|
||||
|
||||
|
|
@ -30,39 +31,51 @@ class NightConfigWrapper implements IConfigurable {
|
|||
this.config = config;
|
||||
}
|
||||
|
||||
NightConfigWrapper setFile(IModFileInfo file) {
|
||||
private NightConfigWrapper(UnmodifiableConfig config, IModFileInfo file) {
|
||||
this.config = config;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
void setFile(IModFileInfo file) {
|
||||
this.file = file;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Optional<T> getConfigElement(String key) {
|
||||
var path = List.of(key);
|
||||
return Optional.ofNullable(validate(this.config.get(path), path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(final String... key) {
|
||||
var path = asList(key);
|
||||
return this.config.getOptional(path).map(value -> {
|
||||
if (value instanceof UnmodifiableConfig cfg) {
|
||||
// New Night config doesn't implement valueMap(), so do a copy.
|
||||
var builder = ImmutableMap.builder();
|
||||
for (var e: cfg.entrySet())
|
||||
builder.put(e.getKey(), e.getValue());
|
||||
return (T)builder.build();
|
||||
} else if (value instanceof ArrayList<?> al && al.size() > 0 && al.get(0) instanceof UnmodifiableConfig) {
|
||||
throw new InvalidModFileException("The configuration path " + path + " is invalid. I wasn't expecting a multi-object list - remove one of the [[ ]]", file);
|
||||
}
|
||||
return (T) value;
|
||||
});
|
||||
return Optional.ofNullable(validate(this.config.get(path), path));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T validate(@Nullable T value, List<String> path) {
|
||||
if (value instanceof UnmodifiableConfig cfg) {
|
||||
// New Night config doesn't implement valueMap(), so do a copy.
|
||||
var entries = cfg.entrySet();
|
||||
var builder = ImmutableMap.builderWithExpectedSize(entries.size());
|
||||
for (var e : entries)
|
||||
builder.put(e.getKey(), e.getValue());
|
||||
return (T) builder.build();
|
||||
} else if (value instanceof ArrayList<?> al && !al.isEmpty() && al.getFirst() instanceof UnmodifiableConfig) {
|
||||
throw new InvalidModFileException("The configuration path " + path + " is invalid. I wasn't expecting a multi-object list - remove one of the [[ ]]", file);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IConfigurable> getConfigList(final String... key) {
|
||||
final List<String> path = asList(key);
|
||||
if (this.config.contains(path) && !(this.config.get(path) instanceof Collection)) {
|
||||
throw new InvalidModFileException("The configuration path "+path+" is invalid. Expecting a collection!", file);
|
||||
throw new InvalidModFileException("The configuration path " + path + " is invalid. Expecting a collection!", file);
|
||||
}
|
||||
final Collection<UnmodifiableConfig> nestedConfigs = this.config.getOrElse(path, ArrayList::new);
|
||||
return nestedConfigs.stream()
|
||||
.map(NightConfigWrapper::new)
|
||||
.map(cw->cw.setFile(file))
|
||||
.map(conf -> new NightConfigWrapper(conf, file))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,37 +21,36 @@ import java.nio.file.Path;
|
|||
import java.util.List;
|
||||
|
||||
@ApiStatus.Internal
|
||||
class Scanner {
|
||||
record Scanner(ModFile fileToScan, ModFileScanData result) {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final ModFile fileToScan;
|
||||
private static final boolean DEBUG = LOGGER.isDebugEnabled(LogMarkers.SCAN);
|
||||
|
||||
public Scanner(final ModFile fileToScan) {
|
||||
this.fileToScan = fileToScan;
|
||||
public Scanner(ModFile fileToScan) {
|
||||
this(fileToScan, new ModFileScanData());
|
||||
}
|
||||
|
||||
public ModFileScanData scan() {
|
||||
ModFileScanData result = new ModFileScanData();
|
||||
result.addModFileInfo(fileToScan.getModFileInfo());
|
||||
fileToScan.scanFile(p -> fileVisitor(p, result));
|
||||
fileToScan.scanFile(this::fileVisitor);
|
||||
final List<IModLanguageProvider> loaders = fileToScan.getLoaders();
|
||||
if (loaders != null) {
|
||||
loaders.forEach(loader -> {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Scanning {} with language loader {}", fileToScan.getFilePath(), loader.name());
|
||||
for (IModLanguageProvider loader : loaders) {
|
||||
if (DEBUG) LOGGER.debug("Scanning {} with language loader {}", fileToScan.getFilePath(), loader.name());
|
||||
loader.getFileVisitor().accept(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void fileVisitor(final Path path, final ModFileScanData result) {
|
||||
LOGGER.debug(LogMarkers.SCAN,"Scanning {} path {}", fileToScan, path);
|
||||
try (InputStream in = Files.newInputStream(path)){
|
||||
private void fileVisitor(final Path path) {
|
||||
try (InputStream in = Files.newInputStream(path)) {
|
||||
ModClassVisitor mcv = new ModClassVisitor();
|
||||
ClassReader cr = new ClassReader(in);
|
||||
cr.accept(mcv, 0);
|
||||
mcv.buildData(result.getClasses(), result.getAnnotations());
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
// mark path bad
|
||||
if (DEBUG) LOGGER.warn("Failed scanning {} path {}", fileToScan, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import java.util.function.Supplier;
|
|||
@ApiStatus.Internal
|
||||
class ArgumentList {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private List<Supplier<String[]>> entries = new ArrayList<>();
|
||||
private Map<String, EntryValue> values = new HashMap<>();
|
||||
private final List<Supplier<String[]>> entries = new ArrayList<>();
|
||||
private final Map<String, EntryValue> values = new HashMap<>();
|
||||
|
||||
public static ArgumentList from(String... args) {
|
||||
ArgumentList ret = new ArgumentList();
|
||||
|
|
@ -77,8 +77,8 @@ class ArgumentList {
|
|||
|
||||
public String[] getArguments() {
|
||||
return entries.stream()
|
||||
.flatMap(e -> Arrays.asList(e.get()).stream())
|
||||
.toArray(size -> new String[size]);
|
||||
.flatMap(e -> Arrays.stream(e.get()))
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public boolean hasValue(String key) {
|
||||
|
|
@ -122,7 +122,7 @@ class ArgumentList {
|
|||
return ent.getValue();
|
||||
}
|
||||
|
||||
private class EntryValue implements Supplier<String[]> {
|
||||
private static final class EntryValue implements Supplier<String[]> {
|
||||
private final String prefix;
|
||||
private final String key;
|
||||
private final boolean split;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
|
|||
String username = args.get("username");
|
||||
if (username != null) { // Replace '#' placeholders with random numbers
|
||||
Matcher m = Pattern.compile("#+").matcher(username);
|
||||
StringBuffer replaced = new StringBuffer();
|
||||
StringBuilder replaced = new StringBuilder();
|
||||
while (m.find()) {
|
||||
m.appendReplacement(replaced, getRandomNumbers(m.group().length()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ package net.minecraftforge.fml.loading.targets;
|
|||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoaderBuilder;
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
|
@ -19,7 +18,6 @@ import org.slf4j.Logger;
|
|||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -47,10 +45,6 @@ public abstract class CommonLaunchHandler implements ILaunchHandlerService {
|
|||
|
||||
public abstract List<Path> getMinecraftPaths();
|
||||
|
||||
@Override
|
||||
public void configureTransformationClassLoader(final ITransformingClassLoaderBuilder builder) {
|
||||
}
|
||||
|
||||
protected String[] preLaunch(String[] arguments, ModuleLayer layer) {
|
||||
URI uri;
|
||||
try (var reader = layer.configuration().findModule("net.minecraftforge.fmlloader").orElseThrow().reference().open()) {
|
||||
|
|
@ -107,7 +101,7 @@ public abstract class CommonLaunchHandler implements ILaunchHandlerService {
|
|||
len += 2;
|
||||
}
|
||||
str = str.substring(0, str.length() - len);
|
||||
var path = Paths.get(URI.create(str));
|
||||
var path = Path.of(URI.create(str));
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
sealed abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
private ForgeDevLaunchHandler(LaunchType type) {
|
||||
super(type, "forge_dev_");
|
||||
}
|
||||
|
|
@ -33,25 +33,25 @@ abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
|
|||
return List.of(filtered);
|
||||
}
|
||||
|
||||
public static class Client extends ForgeDevLaunchHandler {
|
||||
public static final class Client extends ForgeDevLaunchHandler {
|
||||
public Client() {
|
||||
super(CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Data extends ForgeDevLaunchHandler {
|
||||
public static final class Data extends ForgeDevLaunchHandler {
|
||||
public Data() {
|
||||
super(DATA);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Server extends ForgeDevLaunchHandler {
|
||||
public static final class Server extends ForgeDevLaunchHandler {
|
||||
public Server() {
|
||||
super(SERVER);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServerGameTest extends ForgeDevLaunchHandler {
|
||||
public static final class ServerGameTest extends ForgeDevLaunchHandler {
|
||||
public ServerGameTest() {
|
||||
super(SERVER_GAMETEST);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import net.minecraftforge.fml.loading.moddiscovery.AbstractModProvider;
|
|||
import net.minecraftforge.forgespi.locating.IModLocator;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class ForgeDevLocator extends AbstractModProvider implements IModLocator {
|
||||
public final class ForgeDevLocator extends AbstractModProvider implements IModLocator {
|
||||
private static final String PACK_META = "pack.mcmeta";
|
||||
|
||||
@Override
|
||||
|
|
@ -60,7 +60,7 @@ public class ForgeDevLocator extends AbstractModProvider implements IModLocator
|
|||
return ret;
|
||||
}
|
||||
|
||||
private List<Path> getMods() {
|
||||
private static List<Path> getMods() {
|
||||
// Forge is an exploded directory as well
|
||||
var minecraft = ForgeDevLaunchHandler.getPathFromResource("net/minecraft/client/Minecraft.class");
|
||||
var forge = ForgeDevLaunchHandler.getPathFromResource("net/minecraftforge/common/MinecraftForge.class");
|
||||
|
|
@ -84,7 +84,7 @@ public class ForgeDevLocator extends AbstractModProvider implements IModLocator
|
|||
return ret;
|
||||
}
|
||||
|
||||
private List<Path> explodeTestMods(Path path) {
|
||||
private static List<Path> explodeTestMods(Path path) {
|
||||
var mod = new ArrayList<Path>();
|
||||
var memory = Jimfs.newFileSystem();
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ public class ForgeDevLocator extends AbstractModProvider implements IModLocator
|
|||
|
||||
// Find all the @Mods so we can generate tomls, and so we can pick packages. Right now it doesn't allow mods in parent directories,
|
||||
// I could make it merge all the way up, but I think this would be fine.
|
||||
private Map<String, Set<String>> findTestModPackages(Path path) {
|
||||
private static Map<String, Set<String>> findTestModPackages(Path path) {
|
||||
var mods = new HashMap<String, Set<String>>();
|
||||
try (var files = Files.walk(path)) {
|
||||
var classes = files
|
||||
|
|
@ -190,7 +190,7 @@ public class ForgeDevLocator extends AbstractModProvider implements IModLocator
|
|||
}
|
||||
|
||||
// Builds or update the mods.toml file for all @Mods in this package
|
||||
private void buildModsToml(Set<Path> resources, Set<String> modids, Path root) {
|
||||
private static void buildModsToml(Set<Path> resources, Set<String> modids, Path root) {
|
||||
var toml = resources.stream()
|
||||
.map(p -> p.resolve(MODS_TOML))
|
||||
.filter(Files::exists)
|
||||
|
|
@ -226,7 +226,7 @@ public class ForgeDevLocator extends AbstractModProvider implements IModLocator
|
|||
}
|
||||
|
||||
for (var modid : modids) {
|
||||
if (!modlist.stream().anyMatch(c -> modid.equals(c.get("modId")))) {
|
||||
if (modlist.stream().noneMatch(c -> modid.equals(c.get("modId")))) {
|
||||
modified = true;
|
||||
var tmp = Config.inMemory();
|
||||
tmp.set("modId", modid);
|
||||
|
|
@ -248,7 +248,7 @@ public class ForgeDevLocator extends AbstractModProvider implements IModLocator
|
|||
}
|
||||
|
||||
// This is optional, it just hides a warning screen when starting up. I should probably remove this once I restructure how data gen for test mods work and make it generate there.
|
||||
private void buildPackMeta(Set<Path> paths, Path root) {
|
||||
private static void buildPackMeta(Set<Path> paths, Path root) {
|
||||
var existing = paths.stream()
|
||||
.map(p -> p.resolve(PACK_META))
|
||||
.filter(Files::exists)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import java.util.List;
|
|||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
abstract class ForgeProdLaunchHandler extends CommonLaunchHandler {
|
||||
sealed abstract class ForgeProdLaunchHandler extends CommonLaunchHandler {
|
||||
protected ForgeProdLaunchHandler(LaunchType type) {
|
||||
super(type, "forge_");
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ abstract class ForgeProdLaunchHandler extends CommonLaunchHandler {
|
|||
@Override public String getNaming() { return "mcp"; }
|
||||
@Override public boolean isProduction() { return true; }
|
||||
|
||||
public static class Client extends ForgeProdLaunchHandler {
|
||||
public static final class Client extends ForgeProdLaunchHandler {
|
||||
public Client() {
|
||||
super(CLIENT);
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ abstract class ForgeProdLaunchHandler extends CommonLaunchHandler {
|
|||
}
|
||||
}
|
||||
|
||||
public static class Server extends ForgeProdLaunchHandler {
|
||||
public static final class Server extends ForgeProdLaunchHandler {
|
||||
public Server() {
|
||||
super(SERVER);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import org.jetbrains.annotations.ApiStatus;
|
|||
import cpw.mods.jarhandling.SecureJar;
|
||||
|
||||
@ApiStatus.Internal
|
||||
abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
|
||||
sealed abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
|
||||
private ForgeUserdevLaunchHandler(LaunchType type) {
|
||||
super(type, "forge_userdev_");
|
||||
}
|
||||
|
|
@ -33,25 +33,25 @@ abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
|
|||
return List.of(minecraft);
|
||||
}
|
||||
|
||||
public static class Client extends ForgeUserdevLaunchHandler {
|
||||
public static final class Client extends ForgeUserdevLaunchHandler {
|
||||
public Client() {
|
||||
super(CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Data extends ForgeUserdevLaunchHandler {
|
||||
public static final class Data extends ForgeUserdevLaunchHandler {
|
||||
public Data() {
|
||||
super(DATA);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Server extends ForgeUserdevLaunchHandler {
|
||||
public static final class Server extends ForgeUserdevLaunchHandler {
|
||||
public Server() {
|
||||
super(SERVER);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServerGameTest extends ForgeUserdevLaunchHandler {
|
||||
public static final class ServerGameTest extends ForgeUserdevLaunchHandler {
|
||||
public ServerGameTest() {
|
||||
super(SERVER_GAMETEST);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import net.minecraftforge.fml.loading.moddiscovery.AbstractModProvider;
|
|||
import net.minecraftforge.forgespi.locating.IModLocator;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class ForgeUserdevLocator extends AbstractModProvider implements IModLocator {
|
||||
public final class ForgeUserdevLocator extends AbstractModProvider implements IModLocator {
|
||||
@Override
|
||||
public String name() {
|
||||
return "forge_userdev_locator";
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import java.util.Set;
|
|||
*/
|
||||
public class StronglyConnectedComponentDetector<T> {
|
||||
private final Graph<T> graph;
|
||||
private Map<T, Integer> ids;
|
||||
private final Map<T, Integer> ids = new HashMap<>();
|
||||
private T[] elements;
|
||||
private int[] dfn;
|
||||
private int[] low;
|
||||
|
|
@ -49,7 +49,6 @@ public class StronglyConnectedComponentDetector<T> {
|
|||
private void calculate() {
|
||||
components = new HashSet<>();
|
||||
int t = 0;
|
||||
ids = new HashMap<>();
|
||||
Set<T> nodes = graph.nodes();
|
||||
elements = (T[]) new Object[nodes.size()];
|
||||
for (T node : nodes) {
|
||||
|
|
|
|||
|
|
@ -31,21 +31,8 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
|||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
private static class FMLModTarget implements IModLanguageProvider.IModLanguageLoader {
|
||||
private record FMLModTarget(String className, String modId) implements IModLanguageProvider.IModLanguageLoader {
|
||||
private static final Logger LOGGER = FMLJavaModLanguageProvider.LOGGER;
|
||||
private final String className;
|
||||
private final String modId;
|
||||
|
||||
private FMLModTarget(String className, String modId)
|
||||
{
|
||||
this.className = className;
|
||||
this.modId = modId;
|
||||
}
|
||||
|
||||
public String getModId()
|
||||
{
|
||||
return modId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
|
|
@ -94,7 +81,7 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
|||
.filter(ad -> ad.annotationType().equals(MODANNOTATION))
|
||||
.peek(ad -> LOGGER.debug(SCAN, "Found @Mod class {} with id {}", ad.clazz().getClassName(), ad.annotationData().get("value")))
|
||||
.map(ad -> new FMLModTarget(ad.clazz().getClassName(), (String)ad.annotationData().get("value")))
|
||||
.collect(Collectors.toMap(FMLModTarget::getModId, Function.identity(), (a,b)->a));
|
||||
.collect(Collectors.toMap(FMLModTarget::modId, Function.identity(), (a,b)->a));
|
||||
scanResult.addLanguageLoader(modTargetMap);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public class FMLModContainer extends ModContainer {
|
|||
LOGGER.debug(LOADING,"Creating FMLModContainer instance for {}", className);
|
||||
this.scanResults = modFileScanResults;
|
||||
activityMap.put(ModLoadingStage.CONSTRUCT, this::constructMod);
|
||||
this.eventBus = BusBuilder.builder().setExceptionHandler(this::onEventFailed).setTrackPhases(false).markerType(IModBusEvent.class).useModLauncher().build();
|
||||
this.eventBus = BusBuilder.builder().setExceptionHandler(FMLModContainer::onEventFailed).setTrackPhases(false).markerType(IModBusEvent.class).useModLauncher().build();
|
||||
this.configHandler = Optional.of(ce->this.eventBus.post(ce.self()));
|
||||
final FMLJavaModLoadingContext contextExtension = new FMLJavaModLoadingContext(this);
|
||||
this.contextExtension = () -> contextExtension;
|
||||
|
|
@ -56,7 +56,7 @@ public class FMLModContainer extends ModContainer {
|
|||
}
|
||||
}
|
||||
|
||||
private void onEventFailed(IEventBus iEventBus, Event event, IEventListener[] iEventListeners, int i, Throwable throwable) {
|
||||
private static void onEventFailed(IEventBus iEventBus, Event event, IEventListener[] iEventListeners, int i, Throwable throwable) {
|
||||
LOGGER.error(new EventBusErrorMessage(event, i, iEventListeners, throwable));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,14 +21,12 @@ import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
|
|||
public class LowCodeModContainer extends ModContainer
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final ModFileScanData scanResults;
|
||||
private Object modInstance;
|
||||
private final Object modInstance;
|
||||
|
||||
public LowCodeModContainer(IModInfo info, ModFileScanData modFileScanResults, ModuleLayer gameLayer)
|
||||
{
|
||||
super(info);
|
||||
LOGGER.debug(LOADING, "Creating LowCodeModContainer for {}", info.getModId());
|
||||
this.scanResults = modFileScanResults;
|
||||
this.modInstance = new Object();
|
||||
this.contextExtension = () -> null;
|
||||
this.extensionPoints.remove(IExtensionPoint.DisplayTest.class);
|
||||
|
|
@ -45,9 +43,4 @@ public class LowCodeModContainer extends ModContainer
|
|||
{
|
||||
return modInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends Event & IModBusEvent> void acceptEvent(final T e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
package net.minecraftforge.fml.mclanguageprovider;
|
||||
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.forgespi.language.ILifecycleEvent;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.forgespi.language.IModLanguageProvider;
|
||||
|
|
@ -15,14 +14,11 @@ import org.apache.logging.log4j.Logger;
|
|||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
|
||||
import net.minecraftforge.forgespi.language.IModLanguageProvider.IModLanguageLoader;
|
||||
|
||||
public class MinecraftModLanguageProvider implements IModLanguageProvider {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@
|
|||
@DontObfuscate
|
||||
public static String getClientModName() {
|
||||
- return "vanilla";
|
||||
+ return net.minecraftforge.internal.BrandingControl.getClientBranding();
|
||||
+ return net.minecraftforge.internal.BrandingControl.getBranding();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,11 +46,11 @@
|
|||
}
|
||||
|
||||
- p_282860_.drawString(this.font, s, 2, this.height - 10, 16777215 | i);
|
||||
+ net.minecraftforge.internal.BrandingControl.forEachLine(true, true, (brdline, brd) ->
|
||||
+ net.minecraftforge.internal.BrandingControl.forEachLine(true, true, (brd, brdline) ->
|
||||
+ p_282860_.drawString(this.font, brd, 2, this.height - ( 10 + brdline * (this.font.lineHeight + 1)), 16777215 | i)
|
||||
+ );
|
||||
+
|
||||
+ net.minecraftforge.internal.BrandingControl.forEachAboveCopyrightLine((brdline, brd) ->
|
||||
+ net.minecraftforge.internal.BrandingControl.forEachAboveCopyrightLine((brd, brdline) ->
|
||||
+ p_282860_.drawString(this.font, brd, this.width - font.width(brd), this.height - (10 + (brdline + 1) * ( this.font.lineHeight + 1)), 16777215 | i)
|
||||
+ );
|
||||
+
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@
|
|||
@DontObfuscate
|
||||
public String getServerModName() {
|
||||
- return "vanilla";
|
||||
+ return net.minecraftforge.internal.BrandingControl.getServerBranding();
|
||||
+ return net.minecraftforge.internal.BrandingControl.getBranding();
|
||||
}
|
||||
|
||||
public SystemReport fillSystemReport(SystemReport p_177936_) {
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ plugins {
|
|||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
libs {
|
||||
library('forgespi', 'net.minecraftforge:forgespi:7.1.4') // Needs modlauncher
|
||||
library('forgespi', 'net.minecraftforge:forgespi:7.1.5') // Needs modlauncher
|
||||
library('modlauncher', 'net.minecraftforge:modlauncher:10.2.1') // Needs securemodules
|
||||
library('securemodules', 'net.minecraftforge:securemodules:2.2.19') // Needs unsafe
|
||||
library('securemodules', 'net.minecraftforge:securemodules:2.2.20') // Needs unsafe
|
||||
library('unsafe', 'net.minecraftforge:unsafe:0.9.2')
|
||||
library('accesstransformers', 'net.minecraftforge:accesstransformers:8.2.0')
|
||||
library('coremods', 'net.minecraftforge:coremods:5.1.6')
|
||||
|
|
|
|||
|
|
@ -141,7 +141,6 @@ import net.minecraftforge.common.ForgeConfig;
|
|||
import net.minecraftforge.common.ForgeI18n;
|
||||
import net.minecraftforge.common.ForgeMod;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.IExtensionPoint;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
|
|
@ -202,7 +201,7 @@ public class ForgeHooksClient {
|
|||
}
|
||||
|
||||
public static void clearGuiLayers(Minecraft minecraft) {
|
||||
while(guiLayers.size() > 0)
|
||||
while (!guiLayers.isEmpty())
|
||||
popGuiLayerInternal(minecraft);
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +220,7 @@ public class ForgeHooksClient {
|
|||
}
|
||||
|
||||
public static void popGuiLayer(Minecraft minecraft) {
|
||||
if (guiLayers.size() == 0) {
|
||||
if (guiLayers.isEmpty()) {
|
||||
minecraft.setScreen(null);
|
||||
return;
|
||||
}
|
||||
|
|
@ -310,7 +309,7 @@ public class ForgeHooksClient {
|
|||
if (idx == -1)
|
||||
return base + complex;
|
||||
|
||||
String name = complex.substring(idx + 1, complex.length());
|
||||
String name = complex.substring(idx + 1);
|
||||
if (idx > 1) {
|
||||
String domain = complex.substring(0, idx);
|
||||
return domain + ':' + base + name;
|
||||
|
|
@ -320,9 +319,7 @@ public class ForgeHooksClient {
|
|||
}
|
||||
|
||||
public static float getFieldOfViewModifier(Player entity, float fovModifier) {
|
||||
ComputeFovModifierEvent fovModifierEvent = new ComputeFovModifierEvent(entity, fovModifier);
|
||||
MinecraftForge.EVENT_BUS.post(fovModifierEvent);
|
||||
return fovModifierEvent.getNewFovModifier();
|
||||
return MinecraftForge.EVENT_BUS.fire(new ComputeFovModifierEvent(entity, fovModifier)).getNewFovModifier();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -333,41 +330,52 @@ public class ForgeHooksClient {
|
|||
//RenderingRegistry.registerBlockHandler(RenderBlockFluid.instance);
|
||||
}
|
||||
|
||||
private static VersionChecker.Status getForgeVersionStatus() {
|
||||
final class LazyInit {
|
||||
private static final VersionChecker.Status INSTANCE = ForgeVersion.getStatus();
|
||||
|
||||
static {
|
||||
forgeStatusLine = switch (INSTANCE) {
|
||||
// case FAILED -> " Version check failed";
|
||||
// case UP_TO_DATE -> "Forge up to date";
|
||||
// case AHEAD -> "Using non-recommended Forge build, issues may arise.";
|
||||
case OUTDATED, BETA_OUTDATED -> I18n.get("forge.update.newversion", ForgeVersion.getTarget());
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private LazyInit() {}
|
||||
}
|
||||
|
||||
return LazyInit.INSTANCE;
|
||||
}
|
||||
|
||||
public static void renderMainMenu(TitleScreen gui, GuiGraphics graphics, Font font, int width, int height, int alpha) {
|
||||
VersionChecker.Status status = ForgeVersion.getStatus();
|
||||
VersionChecker.Status status = getForgeVersionStatus();
|
||||
|
||||
if (status == VersionChecker.Status.BETA || status == VersionChecker.Status.BETA_OUTDATED) {
|
||||
// Render a warning at the top of the screen
|
||||
Component line = Component.translatable("forge.update.beta.1", ChatFormatting.RED, ChatFormatting.RESET).withStyle(ChatFormatting.RED);
|
||||
graphics.drawCenteredString(font, line, width / 2, 4 + (0 * (font.lineHeight + 1)), 0xFFFFFF | alpha);
|
||||
graphics.drawCenteredString(font, line, width / 2, 4, 0xFFFFFF | alpha);
|
||||
line = Component.translatable("forge.update.beta.2");
|
||||
graphics.drawCenteredString(font, line, width / 2, 4 + (1 * (font.lineHeight + 1)), 0xFFFFFF | alpha);
|
||||
graphics.drawCenteredString(font, line, width / 2, 4 + (font.lineHeight + 1), 0xFFFFFF | alpha);
|
||||
}
|
||||
|
||||
forgeStatusLine = switch(status) {
|
||||
// case FAILED -> " Version check failed";
|
||||
// case UP_TO_DATE -> "Forge up to date";
|
||||
// case AHEAD -> "Using non-recommended Forge build, issues may arise.";
|
||||
case OUTDATED, BETA_OUTDATED -> I18n.get("forge.update.newversion", ForgeVersion.getTarget());
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
public static String forgeStatusLine;
|
||||
|
||||
@Nullable
|
||||
public static SoundInstance playSound(SoundEngine manager, SoundInstance sound) {
|
||||
PlaySoundEvent e = new PlaySoundEvent(manager, sound);
|
||||
MinecraftForge.EVENT_BUS.post(e);
|
||||
return e.getSound();
|
||||
return MinecraftForge.EVENT_BUS.fire(new PlaySoundEvent(manager, sound)).getSound();
|
||||
}
|
||||
|
||||
public static void drawScreen(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
|
||||
guiGraphics.pose().pushPose();
|
||||
guiLayers.forEach(layer -> {
|
||||
for (Screen layer : guiLayers) {
|
||||
// Prevent the background layers from thinking the mouse is over their controls and showing them as highlighted.
|
||||
drawScreenInternal(layer, guiGraphics, Integer.MAX_VALUE, Integer.MAX_VALUE, partialTick);
|
||||
guiGraphics.pose().translate(0, 0, 10000);
|
||||
});
|
||||
}
|
||||
drawScreenInternal(screen, guiGraphics, mouseX, mouseY, partialTick);
|
||||
guiGraphics.pose().popPose();
|
||||
}
|
||||
|
|
@ -535,8 +543,7 @@ public class ForgeHooksClient {
|
|||
|
||||
public static void onClientChangeGameType(PlayerInfo info, GameType currentGameMode, GameType newGameMode) {
|
||||
if (currentGameMode != newGameMode) {
|
||||
ClientPlayerChangeGameTypeEvent evt = new ClientPlayerChangeGameTypeEvent(info, currentGameMode, newGameMode);
|
||||
MinecraftForge.EVENT_BUS.post(evt);
|
||||
MinecraftForge.EVENT_BUS.post(new ClientPlayerChangeGameTypeEvent(info, currentGameMode, newGameMode));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -563,8 +570,7 @@ public class ForgeHooksClient {
|
|||
}
|
||||
|
||||
public static void onRecipesUpdated(RecipeManager mgr) {
|
||||
Event event = new RecipesUpdatedEvent(mgr);
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
MinecraftForge.EVENT_BUS.post(new RecipesUpdatedEvent(mgr));
|
||||
}
|
||||
|
||||
public static void onKeyInput(int key, int scanCode, int action, int modifiers) {
|
||||
|
|
@ -589,7 +595,7 @@ public class ForgeHooksClient {
|
|||
public static SpriteContents loadSpriteContents(ResourceLocation name, Resource resource, FrameSize frameSize, NativeImage image, ResourceMetadata animationMeta) {
|
||||
try {
|
||||
ForgeTextureMetadata forgeMeta = ForgeTextureMetadata.forResource(resource);
|
||||
return forgeMeta.getLoader() == null ? null : forgeMeta.getLoader().loadContents(name, resource, frameSize, image, animationMeta, forgeMeta);
|
||||
return forgeMeta.loader() == null ? null : forgeMeta.loader().loadContents(name, resource, frameSize, image, animationMeta, forgeMeta);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Unable to get Forge metadata for {}, falling back to vanilla loading", name);
|
||||
e.printStackTrace();
|
||||
|
|
@ -599,10 +605,10 @@ public class ForgeHooksClient {
|
|||
|
||||
@Nullable
|
||||
public static TextureAtlasSprite loadTextureAtlasSprite(ResourceLocation atlasName, SpriteContents contents, int atlasWidth, int atlasHeight, int spriteX, int spriteY, int mipmapLevel) {
|
||||
if (contents.forgeMeta == null || contents.forgeMeta.getLoader() == null)
|
||||
if (contents.forgeMeta == null || contents.forgeMeta.loader() == null)
|
||||
return null;
|
||||
|
||||
return contents.forgeMeta.getLoader().makeSprite(atlasName, contents, atlasWidth, atlasHeight, spriteX, spriteY, mipmapLevel);
|
||||
return contents.forgeMeta.loader().makeSprite(atlasName, contents, atlasWidth, atlasHeight, spriteX, spriteY, mipmapLevel);
|
||||
}
|
||||
|
||||
private static final Map<ModelLayerLocation, Supplier<LayerDefinition>> layerDefinitions = new HashMap<>();
|
||||
|
|
@ -612,7 +618,9 @@ public class ForgeHooksClient {
|
|||
}
|
||||
|
||||
public static void loadLayerDefinitions(ImmutableMap.Builder<ModelLayerLocation, LayerDefinition> builder) {
|
||||
layerDefinitions.forEach((k, v) -> builder.put(k, v.get()));
|
||||
for (var entry : layerDefinitions.entrySet()) {
|
||||
builder.put(entry.getKey(), entry.getValue().get());
|
||||
}
|
||||
}
|
||||
|
||||
public static void processForgeListPingData(ServerStatus packet, ServerData target) {
|
||||
|
|
@ -716,7 +724,7 @@ public class ForgeHooksClient {
|
|||
}
|
||||
|
||||
private static Connection getClientConnection() {
|
||||
return Minecraft.getInstance().getConnection()!=null ? Minecraft.getInstance().getConnection().getConnection() : null;
|
||||
return Minecraft.getInstance().getConnection() != null ? Minecraft.getInstance().getConnection().getConnection() : null;
|
||||
}
|
||||
|
||||
public static void handleClientLevelClosing(ClientLevel level) {
|
||||
|
|
@ -825,8 +833,7 @@ public class ForgeHooksClient {
|
|||
Font font = getTooltipFont(stack, fallbackFont);
|
||||
|
||||
var event = new RenderTooltipEvent.GatherComponents(stack, screenWidth, screenHeight, elements, -1);
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
if (event.isCanceled()) return List.of();
|
||||
if (MinecraftForge.EVENT_BUS.post(event)) return List.of();
|
||||
|
||||
// text wrapping
|
||||
int tooltipTextWidth = event.getTooltipElements().stream()
|
||||
|
|
@ -891,9 +898,7 @@ public class ForgeHooksClient {
|
|||
}
|
||||
|
||||
public static ScreenEvent.RenderInventoryMobEffects onScreenPotionSize(Screen screen, int availableSpace, boolean compact, int horizontalOffset) {
|
||||
final ScreenEvent.RenderInventoryMobEffects event = new ScreenEvent.RenderInventoryMobEffects(screen, availableSpace, compact, horizontalOffset);
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
return event;
|
||||
return MinecraftForge.EVENT_BUS.fire(new ScreenEvent.RenderInventoryMobEffects(screen, availableSpace, compact, horizontalOffset));
|
||||
}
|
||||
|
||||
public static boolean onToastAdd(Toast toast) {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,10 @@ public final class ItemDecoratorHandler
|
|||
var event = new RegisterItemDecorationsEvent(decorators);
|
||||
ModLoader.get().postEventWrapContainerInModOrder(event);
|
||||
var builder = new ImmutableMap.Builder<Item, ItemDecoratorHandler>();
|
||||
decorators.forEach((item, itemDecorators) -> builder.put(item, new ItemDecoratorHandler(itemDecorators)));
|
||||
for (var entry : decorators.entrySet()) {
|
||||
Item item = entry.getKey();
|
||||
builder.put(item, new ItemDecoratorHandler(entry.getValue()));
|
||||
}
|
||||
DECORATOR_LOOKUP = builder.build();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package net.minecraftforge.client;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
|
@ -31,7 +32,12 @@ public final class PresetEditorManager
|
|||
Map<ResourceKey<WorldPreset>, PresetEditor> gatheredEditors = new HashMap<>();
|
||||
// Vanilla's map uses Optional<ResourceKey>s as its keys.
|
||||
// As far as we can tell there's no good reason for this, so we'll just use regular keys.
|
||||
PresetEditor.EDITORS.forEach((k, v) -> k.ifPresent(key -> gatheredEditors.put(key, v)));
|
||||
for (var entry : PresetEditor.EDITORS.entrySet()) {
|
||||
var key = entry.getKey().orElse(null);
|
||||
if (key != null) {
|
||||
gatheredEditors.put(key, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Gather mods' entries
|
||||
RegisterPresetEditorsEvent event = new RegisterPresetEditorsEvent(gatheredEditors);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
package net.minecraftforge.client;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
|
|
@ -57,14 +55,14 @@ public final class RecipeBookManager {
|
|||
@ApiStatus.Internal
|
||||
public static void init() {
|
||||
// The ImmutableMap is the patched out value of AGGREGATE_CATEGORIES
|
||||
var aggregateCategories = new HashMap<>(ImmutableMap.of(
|
||||
RecipeBookCategories.CRAFTING_SEARCH, ImmutableList.of(RecipeBookCategories.CRAFTING_EQUIPMENT, RecipeBookCategories.CRAFTING_BUILDING_BLOCKS, RecipeBookCategories.CRAFTING_MISC, RecipeBookCategories.CRAFTING_REDSTONE),
|
||||
RecipeBookCategories.FURNACE_SEARCH, ImmutableList.of(RecipeBookCategories.FURNACE_FOOD, RecipeBookCategories.FURNACE_BLOCKS, RecipeBookCategories.FURNACE_MISC),
|
||||
RecipeBookCategories.BLAST_FURNACE_SEARCH, ImmutableList.of(RecipeBookCategories.BLAST_FURNACE_BLOCKS, RecipeBookCategories.BLAST_FURNACE_MISC),
|
||||
RecipeBookCategories.SMOKER_SEARCH, ImmutableList.of(RecipeBookCategories.SMOKER_FOOD)
|
||||
var aggregateCategories = new HashMap<>(Map.of(
|
||||
RecipeBookCategories.CRAFTING_SEARCH, List.of(RecipeBookCategories.CRAFTING_EQUIPMENT, RecipeBookCategories.CRAFTING_BUILDING_BLOCKS, RecipeBookCategories.CRAFTING_MISC, RecipeBookCategories.CRAFTING_REDSTONE),
|
||||
RecipeBookCategories.FURNACE_SEARCH, List.of(RecipeBookCategories.FURNACE_FOOD, RecipeBookCategories.FURNACE_BLOCKS, RecipeBookCategories.FURNACE_MISC),
|
||||
RecipeBookCategories.BLAST_FURNACE_SEARCH, List.of(RecipeBookCategories.BLAST_FURNACE_BLOCKS, RecipeBookCategories.BLAST_FURNACE_MISC),
|
||||
RecipeBookCategories.SMOKER_SEARCH, List.of(RecipeBookCategories.SMOKER_FOOD)
|
||||
));
|
||||
|
||||
var typeCategories = new HashMap<RecipeBookType, ImmutableList<RecipeBookCategories>>();
|
||||
var typeCategories = new HashMap<RecipeBookType, List<RecipeBookCategories>>();
|
||||
var recipeCategoryLookups = new HashMap<RecipeType<?>, Function<Recipe<?>, RecipeBookCategories>>();
|
||||
var event = new RegisterRecipeBookCategoriesEvent(aggregateCategories, typeCategories, recipeCategoryLookups);
|
||||
ModLoader.get().postEventWrapContainerInModOrder(event);
|
||||
|
|
|
|||
|
|
@ -78,8 +78,7 @@ public final class ForgeEventFactoryClient {
|
|||
* @return the event object passed in and possibly modified by listeners
|
||||
*/
|
||||
private static <E extends Event> E fire(E e) {
|
||||
post(e);
|
||||
return e;
|
||||
return MinecraftForge.EVENT_BUS.fire(e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
package net.minecraftforge.client.event;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
|
|
@ -31,14 +30,14 @@ import java.util.function.Function;
|
|||
*/
|
||||
public class RegisterRecipeBookCategoriesEvent extends Event implements IModBusEvent
|
||||
{
|
||||
private final Map<RecipeBookCategories, ImmutableList<RecipeBookCategories>> aggregateCategories;
|
||||
private final Map<RecipeBookType, ImmutableList<RecipeBookCategories>> typeCategories;
|
||||
private final Map<RecipeBookCategories, List<RecipeBookCategories>> aggregateCategories;
|
||||
private final Map<RecipeBookType, List<RecipeBookCategories>> typeCategories;
|
||||
private final Map<RecipeType<?>, Function<Recipe<?>, RecipeBookCategories>> recipeCategoryLookups;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public RegisterRecipeBookCategoriesEvent(
|
||||
Map<RecipeBookCategories, ImmutableList<RecipeBookCategories>> aggregateCategories,
|
||||
Map<RecipeBookType, ImmutableList<RecipeBookCategories>> typeCategories,
|
||||
Map<RecipeBookCategories, List<RecipeBookCategories>> aggregateCategories,
|
||||
Map<RecipeBookType, List<RecipeBookCategories>> typeCategories,
|
||||
Map<RecipeType<?>, Function<Recipe<?>, RecipeBookCategories>> recipeCategoryLookups)
|
||||
{
|
||||
this.aggregateCategories = aggregateCategories;
|
||||
|
|
@ -51,7 +50,7 @@ public class RegisterRecipeBookCategoriesEvent extends Event implements IModBusE
|
|||
*/
|
||||
public void registerAggregateCategory(RecipeBookCategories category, List<RecipeBookCategories> others)
|
||||
{
|
||||
aggregateCategories.put(category, ImmutableList.copyOf(others));
|
||||
aggregateCategories.put(category, List.copyOf(others));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -59,7 +58,7 @@ public class RegisterRecipeBookCategoriesEvent extends Event implements IModBusE
|
|||
*/
|
||||
public void registerBookCategories(RecipeBookType type, List<RecipeBookCategories> categories)
|
||||
{
|
||||
typeCategories.put(type, ImmutableList.copyOf(categories));
|
||||
typeCategories.put(type, List.copyOf(categories));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,60 +21,44 @@ import java.util.Optional;
|
|||
/**
|
||||
* The "forge" section of texture metadata files (.mcmeta). Currently used only to specify custom
|
||||
* TextureAtlasSprite loaders.
|
||||
*
|
||||
* @see ITextureAtlasSpriteLoader
|
||||
*/
|
||||
public final class ForgeTextureMetadata
|
||||
{
|
||||
public record ForgeTextureMetadata(@Nullable ITextureAtlasSpriteLoader loader) {
|
||||
|
||||
public static final ForgeTextureMetadata EMPTY = new ForgeTextureMetadata(null);
|
||||
public static final MetadataSectionSerializer<ForgeTextureMetadata> SERIALIZER = new Serializer();
|
||||
|
||||
public static ForgeTextureMetadata forResource(Resource resource) throws IOException {
|
||||
Optional<ForgeTextureMetadata> metadata = resource.metadata().getSection(SERIALIZER);
|
||||
return metadata.isEmpty() ? EMPTY : metadata.get();
|
||||
return metadata.orElse(EMPTY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private final ITextureAtlasSpriteLoader loader;
|
||||
|
||||
public ForgeTextureMetadata(@Nullable ITextureAtlasSpriteLoader loader)
|
||||
{
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ITextureAtlasSpriteLoader getLoader()
|
||||
{
|
||||
public ITextureAtlasSpriteLoader getLoader() {
|
||||
return loader;
|
||||
}
|
||||
|
||||
private static final class Serializer implements MetadataSectionSerializer<ForgeTextureMetadata>
|
||||
{
|
||||
private static final class Serializer implements MetadataSectionSerializer<ForgeTextureMetadata> {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getMetadataSectionName()
|
||||
{
|
||||
public String getMetadataSectionName() {
|
||||
return "forge";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ForgeTextureMetadata fromJson(JsonObject json)
|
||||
{
|
||||
public ForgeTextureMetadata fromJson(JsonObject json) {
|
||||
@Nullable
|
||||
ITextureAtlasSpriteLoader loader;
|
||||
if (json.has("loader"))
|
||||
{
|
||||
if (json.has("loader")) {
|
||||
ResourceLocation loaderName = ResourceLocation.parse(GsonHelper.getAsString(json, "loader"));
|
||||
loader = TextureAtlasSpriteLoaderManager.get(loaderName);
|
||||
if (loader == null)
|
||||
{
|
||||
if (loader == null) {
|
||||
throw new JsonSyntaxException("Unknown TextureAtlasSpriteLoader " + loaderName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
loader = null;
|
||||
}
|
||||
return new ForgeTextureMetadata(loader);
|
||||
|
|
|
|||
|
|
@ -13,35 +13,31 @@ import org.jetbrains.annotations.ApiStatus;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Manager for {@link ITextureAtlasSpriteLoader} instances.
|
||||
* <p>
|
||||
* Provides a lookup.
|
||||
*/
|
||||
public final class TextureAtlasSpriteLoaderManager
|
||||
{
|
||||
private static ImmutableMap<ResourceLocation, ITextureAtlasSpriteLoader> LOADERS;
|
||||
public final class TextureAtlasSpriteLoaderManager {
|
||||
private static Map<ResourceLocation, ITextureAtlasSpriteLoader> LOADERS;
|
||||
|
||||
/**
|
||||
* Finds the loader with the given name, or null if none is registered.
|
||||
*/
|
||||
@Nullable
|
||||
public static ITextureAtlasSpriteLoader get(ResourceLocation name)
|
||||
{
|
||||
public static ITextureAtlasSpriteLoader get(ResourceLocation name) {
|
||||
return LOADERS.get(name);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void init()
|
||||
{
|
||||
public static void init() {
|
||||
var loaders = new HashMap<ResourceLocation, ITextureAtlasSpriteLoader>();
|
||||
var event = new RegisterTextureAtlasSpriteLoadersEvent(loaders);
|
||||
ModLoader.get().postEventWrapContainerInModOrder(event);
|
||||
LOADERS = ImmutableMap.copyOf(loaders);
|
||||
}
|
||||
|
||||
private TextureAtlasSpriteLoaderManager()
|
||||
{
|
||||
}
|
||||
private TextureAtlasSpriteLoaderManager() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import net.minecraft.world.level.biome.Biome;
|
|||
|
||||
public class BiomeManager
|
||||
{
|
||||
private static TrackedList<BiomeEntry>[] biomes = setupBiomes();
|
||||
private static final TrackedList<BiomeEntry>[] biomes = setupBiomes();
|
||||
private static final List<ResourceKey<Biome>> additionalOverworldBiomes = new ArrayList<>();
|
||||
private static final List<ResourceKey<Biome>> additionalOverworldBiomesView = Collections.unmodifiableList(additionalOverworldBiomes);
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ public final class CreativeModeTabRegistry {
|
|||
@Override
|
||||
protected void apply(@NotNull JsonObject data, @NotNull ResourceManager resourceManager, ProfilerFiller p) {
|
||||
try {
|
||||
if (data.size() > 0) {
|
||||
if (!data.isEmpty()) {
|
||||
JsonArray order = GsonHelper.getAsJsonArray(data, "order");
|
||||
List<CreativeModeTab> customOrder = new ArrayList<>();
|
||||
for (JsonElement entry : order) {
|
||||
|
|
@ -183,8 +183,9 @@ public final class CreativeModeTabRegistry {
|
|||
DEFAULT_TABS.add(BuiltInRegistries.CREATIVE_MODE_TAB.get(CreativeModeTabs.OP_BLOCKS));
|
||||
DEFAULT_TABS.add(BuiltInRegistries.CREATIVE_MODE_TAB.get(CreativeModeTabs.INVENTORY));
|
||||
|
||||
final List<Holder<CreativeModeTab>> indexed = new ArrayList<>();
|
||||
BuiltInRegistries.CREATIVE_MODE_TAB.holders().filter(c -> !DEFAULT_TABS.contains(c.get())).forEach(indexed::add);
|
||||
final List<Holder<CreativeModeTab>> indexed = BuiltInRegistries.CREATIVE_MODE_TAB.holders()
|
||||
.filter(c -> !DEFAULT_TABS.contains(c.get()))
|
||||
.collect(Collectors.toList());
|
||||
int vanillaTabs = 10;
|
||||
|
||||
for (int i = 0; i < vanillaTabs; i++) { // Vanilla ordering
|
||||
|
|
|
|||
|
|
@ -632,7 +632,7 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
|
|||
if (count > currentPath.size())
|
||||
throw new IllegalArgumentException("Attempted to pop " + count + " elements when we only had: " + currentPath);
|
||||
for (int x = 0; x < count; x++)
|
||||
currentPath.remove(currentPath.size() - 1);
|
||||
currentPath.removeLast();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -644,10 +644,14 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper<UnmodifiableConfi
|
|||
public ForgeConfigSpec build() {
|
||||
context.ensureEmpty();
|
||||
Config valueCfg = Config.of(Config.getDefaultMapCreator(true, true), InMemoryFormat.withSupport(ConfigValue.class::isAssignableFrom));
|
||||
values.forEach(v -> valueCfg.set(v.getPath(), v));
|
||||
for (ConfigValue<?> value : values) {
|
||||
valueCfg.set(value.getPath(), value);
|
||||
}
|
||||
|
||||
ForgeConfigSpec ret = new ForgeConfigSpec(storage, valueCfg, levelComments, levelTranslationKeys);
|
||||
values.forEach(v -> v.spec = ret);
|
||||
for (ConfigValue<?> v : values) {
|
||||
v.spec = ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ public class ForgeI18n {
|
|||
// 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;
|
||||
private static Map<String, String> i18n;
|
||||
private static final Map<String, FormatFactory> customFactories;
|
||||
// From StringUtils
|
||||
private static final Pattern PATTERN_CONTROL_CODE = Pattern.compile("(?i)\\u00A7[0-9A-FK-OR]");
|
||||
|
||||
|
|
|
|||
|
|
@ -60,11 +60,11 @@ public class ForgeInternalHandler {
|
|||
WorldWorkerManager.tick(false);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void checkSettings(ClientTickEvent event) {
|
||||
//if (event.phase == Phase.END)
|
||||
// CloudRenderer.updateCloudSettings();
|
||||
}
|
||||
// @SubscribeEvent
|
||||
// public void checkSettings(ClientTickEvent event) {
|
||||
// if (event.phase == Phase.END)
|
||||
// CloudRenderer.updateCloudSettings();
|
||||
// }
|
||||
|
||||
@SubscribeEvent
|
||||
public void onChunkUnload(ChunkEvent.Unload event) {
|
||||
|
|
|
|||
|
|
@ -399,7 +399,9 @@ public class ForgeMod {
|
|||
modEventBus.addListener(this::registerFluids);
|
||||
modEventBus.addListener(this::registerVanillaDisplayContexts);
|
||||
modEventBus.register(this);
|
||||
registries.forEach(r -> r.register(modEventBus));
|
||||
for (DeferredRegister<?> r : registries) {
|
||||
r.register(modEventBus);
|
||||
}
|
||||
|
||||
MinecraftForge.EVENT_BUS.addListener(this::serverStopping);
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ForgeConfig.clientSpec);
|
||||
|
|
|
|||
|
|
@ -92,14 +92,14 @@ public class ForgeSpawnEggItem extends SpawnEggItem {
|
|||
private static class ColorRegisterHandler {
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
public static void registerSpawnEggColors(RegisterColorHandlersEvent.Item event) {
|
||||
MOD_EGGS.forEach(egg -> {
|
||||
for (ForgeSpawnEggItem egg : MOD_EGGS) {
|
||||
event.register((stack, layer) -> {
|
||||
int color = egg.getColor(layer);
|
||||
if (FastColor.ARGB32.alpha(color) == 0)
|
||||
color = FastColor.ARGB32.opaque(color);
|
||||
return color;
|
||||
}, egg);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,11 +29,12 @@ public class VillagerTradingManager
|
|||
|
||||
static
|
||||
{
|
||||
VillagerTrades.TRADES.entrySet().forEach(e ->
|
||||
{
|
||||
VillagerTrades.TRADES.forEach((key, value) -> {
|
||||
Int2ObjectMap<ItemListing[]> copy = new Int2ObjectOpenHashMap<>();
|
||||
e.getValue().int2ObjectEntrySet().forEach(ent -> copy.put(ent.getIntKey(), Arrays.copyOf(ent.getValue(), ent.getValue().length)));
|
||||
VANILLA_TRADES.put(e.getKey(), copy);
|
||||
for (var ent : value.int2ObjectEntrySet()) {
|
||||
copy.put(ent.getIntKey(), Arrays.copyOf(ent.getValue(), ent.getValue().length));
|
||||
}
|
||||
VANILLA_TRADES.put(key, copy);
|
||||
});
|
||||
VillagerTrades.WANDERING_TRADER_TRADES.int2ObjectEntrySet().forEach(e -> WANDERER_TRADES.put(e.getIntKey(), Arrays.copyOf(e.getValue(), e.getValue().length)));
|
||||
}
|
||||
|
|
@ -71,13 +72,14 @@ public class VillagerTradingManager
|
|||
{
|
||||
mutableTrades.put(i, NonNullList.create());
|
||||
}
|
||||
trades.int2ObjectEntrySet().forEach(e ->
|
||||
{
|
||||
Arrays.stream(e.getValue()).forEach(mutableTrades.get(e.getIntKey())::add);
|
||||
});
|
||||
for (var entry : trades.int2ObjectEntrySet()) {
|
||||
Arrays.stream(entry.getValue()).forEach(mutableTrades.get(entry.getIntKey())::add);
|
||||
}
|
||||
MinecraftForge.EVENT_BUS.post(new VillagerTradesEvent(mutableTrades, prof));
|
||||
Int2ObjectMap<ItemListing[]> newTrades = new Int2ObjectOpenHashMap<>();
|
||||
mutableTrades.int2ObjectEntrySet().forEach(e -> newTrades.put(e.getIntKey(), e.getValue().toArray(new ItemListing[0])));
|
||||
for (var entry : mutableTrades.int2ObjectEntrySet()) {
|
||||
newTrades.put(entry.getIntKey(), entry.getValue().toArray(new ItemListing[0]));
|
||||
}
|
||||
VillagerTrades.TRADES.put(prof, newTrades);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import java.util.List;
|
|||
|
||||
public class WorldWorkerManager
|
||||
{
|
||||
private static List<IWorker> workers = new ArrayList<IWorker>();
|
||||
private static final List<IWorker> workers = new ArrayList<>();
|
||||
private static long startTime = -1;
|
||||
private static int index = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import net.minecraft.commands.arguments.selector.EntitySelectorParser;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Allows modders to register custom entity selectors by assigning an {@link IEntitySelectorType} to a String token. <br>
|
||||
|
|
@ -21,6 +23,7 @@ import java.util.HashMap;
|
|||
public class EntitySelectorManager
|
||||
{
|
||||
private static final HashMap<String, IEntitySelectorType> REGISTRY = new HashMap<>();
|
||||
private static final List<String> RESERVED_TOKENS = List.of("p", "a", "r", "s", "e");
|
||||
|
||||
/**
|
||||
* Registers a new {@link IEntitySelectorType} for the given {@code token}.<br>
|
||||
|
|
@ -34,7 +37,7 @@ public class EntitySelectorManager
|
|||
throw new IllegalArgumentException("Token must not be empty");
|
||||
}
|
||||
|
||||
if (Arrays.asList("p", "a", "r", "s", "e").contains(token))
|
||||
if (RESERVED_TOKENS.contains(token))
|
||||
{
|
||||
throw new IllegalArgumentException("Token clashes with vanilla @" + token);
|
||||
}
|
||||
|
|
@ -78,6 +81,10 @@ public class EntitySelectorManager
|
|||
*/
|
||||
public static void fillSelectorSuggestions(SuggestionsBuilder suggestionBuilder)
|
||||
{
|
||||
REGISTRY.forEach((token, type) -> suggestionBuilder.suggest("@" + token, type.getSuggestionTooltip()));
|
||||
for (var entry : REGISTRY.entrySet()) {
|
||||
String token = entry.getKey();
|
||||
IEntitySelectorType type = entry.getValue();
|
||||
suggestionBuilder.suggest("@" + token, type.getSuggestionTooltip());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package net.minecraftforge.common.crafting;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
|
@ -61,10 +62,10 @@ public class ConditionalRecipe {
|
|||
}
|
||||
|
||||
public static class Builder {
|
||||
private List<InnerRecipe> recipes = new ArrayList<>();
|
||||
private List<InnerAdvancement> advancements = new ArrayList<>();
|
||||
private final List<InnerRecipe> recipes = new ArrayList<>();
|
||||
private final List<InnerAdvancement> advancements = new ArrayList<>();
|
||||
|
||||
private RecipeOutput bouncer = new RecipeOutput() {
|
||||
private final RecipeOutput bouncer = new RecipeOutput() {
|
||||
@Override
|
||||
public void accept(ResourceLocation id, Recipe<?> value, @Nullable AdvancementHolder advancement) {
|
||||
recipe(id, value, advancement);
|
||||
|
|
@ -221,7 +222,7 @@ public class ConditionalRecipe {
|
|||
var count = new Holder<Integer>();
|
||||
count.value = -1;
|
||||
var ret = stream.map(entry -> accept(context, ops, count, entry))
|
||||
.filter(entry -> entry != null)
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
|
|
@ -273,7 +274,7 @@ public class ConditionalRecipe {
|
|||
}
|
||||
};
|
||||
|
||||
private static class Holder<T> {
|
||||
private static final class Holder<T> {
|
||||
private T value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public class SimpleCraftingContainer {
|
|||
int height = this.rows.size();
|
||||
if (height == 0)
|
||||
throw new IllegalStateException("Invalid builder, empty inventory");
|
||||
int width = this.rows.get(0).length();
|
||||
int width = this.rows.getFirst().length();
|
||||
var items = NonNullList.withSize(width * height, ItemStack.EMPTY);
|
||||
|
||||
int idx = 0;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public class CompoundIngredient extends AbstractIngredient {
|
|||
return new CompoundIngredient(Arrays.asList(children));
|
||||
}
|
||||
|
||||
private List<Ingredient> children;
|
||||
private final List<Ingredient> children;
|
||||
private ItemStack[] stacks;
|
||||
private IntList itemIds;
|
||||
private final boolean isSimple;
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ public class PartialNBTIngredient extends AbstractIngredient {
|
|||
};
|
||||
|
||||
public static class Builder {
|
||||
private List<ItemLike> items = new ArrayList<>();
|
||||
private final List<ItemLike> items = new ArrayList<>();
|
||||
private CompoundTag nbt;
|
||||
|
||||
public Builder nbt(CompoundTag value) {
|
||||
|
|
|
|||
|
|
@ -253,10 +253,10 @@ public abstract class SoundDefinitionsProvider implements DataProvider
|
|||
|
||||
private CompletableFuture<?> save(final CachedOutput cache, final Path targetFile)
|
||||
{
|
||||
return DataProvider.saveStable(cache, this.mapToJson(this.sounds), targetFile);
|
||||
return DataProvider.saveStable(cache, mapToJson(this.sounds), targetFile);
|
||||
}
|
||||
|
||||
private JsonObject mapToJson(final Map<String, SoundDefinition> map)
|
||||
private static JsonObject mapToJson(final Map<String, SoundDefinition> map)
|
||||
{
|
||||
final JsonObject obj = new JsonObject();
|
||||
// namespaces are ignored when serializing
|
||||
|
|
|
|||
|
|
@ -49,7 +49,11 @@ public abstract class SpriteSourceProvider extends JsonCodecProvider<List<Sprite
|
|||
protected final void gather(BiConsumer<ResourceLocation, List<SpriteSource>> consumer)
|
||||
{
|
||||
addSources();
|
||||
atlases.forEach((atlas, srcList) -> consumer.accept(atlas, srcList.sources));
|
||||
for (var entry : atlases.entrySet()) {
|
||||
ResourceLocation atlas = entry.getKey();
|
||||
SourceList srcList = entry.getValue();
|
||||
consumer.accept(atlas, srcList.sources);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void addSources();
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import net.minecraft.world.level.ChunkPos;
|
|||
// Sorter to load nearby chunks first
|
||||
public class CenterChunkPosComparator implements java.util.Comparator<ChunkPos>
|
||||
{
|
||||
private int x;
|
||||
private int z;
|
||||
private final int x;
|
||||
private final int z;
|
||||
|
||||
public CenterChunkPosComparator(ServerPlayer entityplayer)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class ConcatenatedListView<T> implements List<T>
|
|||
{
|
||||
return switch (members.size()) {
|
||||
case 0 -> List.of();
|
||||
case 1 -> Collections.unmodifiableList(members.get(0));
|
||||
case 1 -> Collections.unmodifiableList(members.getFirst());
|
||||
default -> new ConcatenatedListView<>(members);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public class HexDumper {
|
|||
private static final String HEX = "0123456789ABCDEF";
|
||||
private final int marked;
|
||||
private final StringBuilder buf;
|
||||
private char[] ascii = new char[16];
|
||||
private final char[] ascii = new char[16];
|
||||
private int index = 0;
|
||||
|
||||
private Instance(int marked, int size) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
public class LevelCapabilityData extends SavedData {
|
||||
public static final String ID = "capabilities";
|
||||
|
||||
private INBTSerializable<CompoundTag> serializable;
|
||||
private final INBTSerializable<CompoundTag> serializable;
|
||||
private CompoundTag capNBT = null;
|
||||
|
||||
public LevelCapabilityData(@Nullable INBTSerializable<CompoundTag> serializable) {
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ public class MutableHashedLinkedMap<K, V> implements Iterable<Map.Entry<K, V>>
|
|||
Value apply(Key key, Value left, Value right);
|
||||
}
|
||||
|
||||
private class Entry implements Map.Entry<K, V>
|
||||
private final class Entry implements Map.Entry<K, V>
|
||||
{
|
||||
private final K key;
|
||||
private V value;
|
||||
|
|
@ -374,7 +374,7 @@ public class MutableHashedLinkedMap<K, V> implements Iterable<Map.Entry<K, V>>
|
|||
}
|
||||
}
|
||||
|
||||
private static class BasicStrategy implements Strategy<Object> {
|
||||
private static final class BasicStrategy implements Strategy<Object> {
|
||||
@Override
|
||||
public int hashCode(Object o) {
|
||||
return Objects.hashCode(o);
|
||||
|
|
@ -386,7 +386,7 @@ public class MutableHashedLinkedMap<K, V> implements Iterable<Map.Entry<K, V>>
|
|||
}
|
||||
}
|
||||
|
||||
private static class IdentityStrategy implements Strategy<Object> {
|
||||
private static final class IdentityStrategy implements Strategy<Object> {
|
||||
@Override
|
||||
public int hashCode(Object o) {
|
||||
return System.identityHashCode(o);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ package net.minecraftforge.common.util;
|
|||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
|
@ -25,7 +26,7 @@ public class SortedProperties extends Properties {
|
|||
|
||||
@Override
|
||||
public Set<Map.Entry<Object, Object>> entrySet() {
|
||||
Set<Map.Entry<Object, Object>> ret = new TreeSet<>((left, right) -> left.getKey().toString().compareTo(right.getKey().toString()));
|
||||
Set<Map.Entry<Object, Object>> ret = new TreeSet<>(Comparator.comparing(entry -> entry.getKey().toString()));
|
||||
ret.addAll(super.entrySet());
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,9 +125,9 @@ public class TextTable
|
|||
|
||||
public static class Column
|
||||
{
|
||||
private String header;
|
||||
private final String header;
|
||||
private int width;
|
||||
private Alignment alignment;
|
||||
private final Alignment alignment;
|
||||
|
||||
public Column(String header)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -302,19 +302,12 @@ public final class TransformationHelper
|
|||
Quaternionf ret;
|
||||
try
|
||||
{
|
||||
if (entry.getKey().equals("x"))
|
||||
{
|
||||
ret = Axis.XP.rotationDegrees(entry.getValue().getAsNumber().floatValue());
|
||||
}
|
||||
else if (entry.getKey().equals("y"))
|
||||
{
|
||||
ret = Axis.YP.rotationDegrees(entry.getValue().getAsNumber().floatValue());
|
||||
}
|
||||
else if (entry.getKey().equals("z"))
|
||||
{
|
||||
ret = Axis.ZP.rotationDegrees(entry.getValue().getAsNumber().floatValue());
|
||||
}
|
||||
else throw new JsonParseException("Axis rotation: expected single axis key, got: " + entry.getKey());
|
||||
ret = switch (entry.getKey()) {
|
||||
case "x" -> Axis.XP.rotationDegrees(entry.getValue().getAsNumber().floatValue());
|
||||
case "y" -> Axis.YP.rotationDegrees(entry.getValue().getAsNumber().floatValue());
|
||||
case "z" -> Axis.ZP.rotationDegrees(entry.getValue().getAsNumber().floatValue());
|
||||
default -> throw new JsonParseException("Axis rotation: expected single axis key, got: " + entry.getKey());
|
||||
};
|
||||
}
|
||||
catch(ClassCastException ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@ public class BiomeGenerationSettingsBuilder extends BiomeGenerationSettings.Plai
|
|||
{
|
||||
public BiomeGenerationSettingsBuilder(BiomeGenerationSettings orig)
|
||||
{
|
||||
orig.getCarvingStages().forEach(k -> {
|
||||
for (GenerationStep.Carving k : orig.getCarvingStages()) {
|
||||
carvers.put(k, new ArrayList<>());
|
||||
orig.getCarvers(k).forEach(v -> carvers.get(k).add(v));
|
||||
});
|
||||
for (Holder<ConfiguredWorldCarver<?>> v : orig.getCarvers(k)) {
|
||||
carvers.get(k).add(v);
|
||||
}
|
||||
}
|
||||
orig.features().forEach(l -> {
|
||||
final ArrayList<Holder<PlacedFeature>> featureList = new ArrayList<>();
|
||||
l.forEach(featureList::add);
|
||||
|
|
|
|||
|
|
@ -5,11 +5,9 @@
|
|||
|
||||
package net.minecraftforge.internal;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.function.ObjIntConsumer;
|
||||
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
|
||||
|
|
@ -19,20 +17,20 @@ import net.minecraftforge.fml.ModList;
|
|||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.versions.mcp.MCPVersion;
|
||||
|
||||
public class BrandingControl {
|
||||
public final class BrandingControl {
|
||||
private BrandingControl() {}
|
||||
|
||||
private static List<String> brandings;
|
||||
private static List<String> brandingsNoMC;
|
||||
private static List<String> overCopyrightBrandings;
|
||||
|
||||
private static void computeBranding() {
|
||||
if (brandings == null) {
|
||||
ImmutableList.Builder<String> brd = ImmutableList.builder();
|
||||
brd.add("Forge " + ForgeVersion.getVersion());
|
||||
brd.add("Minecraft " + MCPVersion.getMCVersion());
|
||||
brd.add("MCP " + MCPVersion.getMCPVersion());
|
||||
int tModCount = ModList.get().size();
|
||||
brd.add(ForgeI18n.parseMessage("fml.menu.loadingmods", tModCount));
|
||||
brandings = brd.build();
|
||||
brandings = List.of(
|
||||
"Forge " + ForgeVersion.getVersion(),
|
||||
"Minecraft " + MCPVersion.getMCVersion(),
|
||||
"MCP " + MCPVersion.getMCPVersion(),
|
||||
ForgeI18n.parseMessage("fml.menu.loadingmods", ModList.get().size())
|
||||
);
|
||||
brandingsNoMC = brandings.subList(1, brandings.size());
|
||||
}
|
||||
}
|
||||
|
|
@ -40,34 +38,36 @@ public class BrandingControl {
|
|||
private static List<String> getBrandings(boolean includeMC, boolean reverse) {
|
||||
computeBranding();
|
||||
if (includeMC)
|
||||
return reverse ? Lists.reverse(brandings) : brandings;
|
||||
return reverse ? brandings.reversed() : brandings;
|
||||
else
|
||||
return reverse ? Lists.reverse(brandingsNoMC) : brandingsNoMC;
|
||||
return reverse ? brandingsNoMC.reversed() : brandingsNoMC;
|
||||
}
|
||||
|
||||
private static void computeOverCopyrightBrandings() {
|
||||
if (overCopyrightBrandings == null) {
|
||||
ImmutableList.Builder<String> brd = ImmutableList.builder();
|
||||
if (ForgeHooksClient.forgeStatusLine != null) brd.add(ForgeHooksClient.forgeStatusLine);
|
||||
overCopyrightBrandings = brd.build();
|
||||
public static List<String> getOverCopyrightBrandings() {
|
||||
final class LazyInit {
|
||||
private static final List<String> INSTANCE = ForgeHooksClient.forgeStatusLine == null
|
||||
? Collections.emptyList()
|
||||
: List.of(ForgeHooksClient.forgeStatusLine);
|
||||
|
||||
private LazyInit() {}
|
||||
}
|
||||
|
||||
return LazyInit.INSTANCE;
|
||||
}
|
||||
|
||||
public static void forEachLine(boolean includeMC, boolean reverse, BiConsumer<Integer, String> lineConsumer) {
|
||||
final List<String> brandings = getBrandings(includeMC, reverse);
|
||||
IntStream.range(0, brandings.size()).boxed().forEachOrdered(idx -> lineConsumer.accept(idx, brandings.get(idx)));
|
||||
public static void forEachLine(boolean includeMC, boolean reverse, ObjIntConsumer<String> lineConsumer) {
|
||||
var brandings = getBrandings(includeMC, reverse);
|
||||
for (int idx = 0; idx < brandings.size(); idx++)
|
||||
lineConsumer.accept(brandings.get(idx), idx);
|
||||
}
|
||||
|
||||
public static void forEachAboveCopyrightLine(BiConsumer<Integer, String> lineConsumer) {
|
||||
computeOverCopyrightBrandings();
|
||||
IntStream.range(0, overCopyrightBrandings.size()).boxed().forEachOrdered(idx->lineConsumer.accept(idx, overCopyrightBrandings.get(idx)));
|
||||
public static void forEachAboveCopyrightLine(ObjIntConsumer<String> lineConsumer) {
|
||||
var overCopyrightBrandings = getOverCopyrightBrandings();
|
||||
for (int idx = 0; idx < overCopyrightBrandings.size(); idx++)
|
||||
lineConsumer.accept(overCopyrightBrandings.get(idx), idx);
|
||||
}
|
||||
|
||||
public static String getClientBranding() {
|
||||
return "forge";
|
||||
}
|
||||
|
||||
public static String getServerBranding() {
|
||||
public static String getBranding() {
|
||||
return "forge";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,15 +15,9 @@ import net.minecraftforge.fml.event.config.ModConfigEvent;
|
|||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ForgeBindings implements IBindingsProvider {
|
||||
@Override
|
||||
public Supplier<IEventBus> getForgeBusSupplier() {
|
||||
return ()-> MinecraftForge.EVENT_BUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<I18NParser> getMessageParser() {
|
||||
return ()->new I18NParser() {
|
||||
public final class ForgeBindings implements IBindingsProvider {
|
||||
private static final class LazyInit {
|
||||
private static final Supplier<I18NParser> INSTANCE = () -> new I18NParser() {
|
||||
@Override
|
||||
public String parseMessage(final String i18nMessage, final Object... args) {
|
||||
return ForgeI18n.parseMessage(i18nMessage, args);
|
||||
|
|
@ -34,10 +28,22 @@ public class ForgeBindings implements IBindingsProvider {
|
|||
return ForgeI18n.stripControlCodes(toStrip);
|
||||
}
|
||||
};
|
||||
|
||||
private LazyInit() {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<IEventBus> getForgeBusSupplier() {
|
||||
return () -> MinecraftForge.EVENT_BUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<I18NParser> getMessageParser() {
|
||||
return LazyInit.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<IConfigEvent.ConfigConfig> getConfigConfiguration() {
|
||||
return ()->new IConfigEvent.ConfigConfig(ModConfigEvent.Loading::new, ModConfigEvent.Reloading::new, ModConfigEvent.Unloading::new);
|
||||
return () -> new IConfigEvent.ConfigConfig(ModConfigEvent.Loading::new, ModConfigEvent.Reloading::new, ModConfigEvent.Unloading::new);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import java.text.SimpleDateFormat;
|
|||
import java.util.*;
|
||||
|
||||
public class CrashReportExtender {
|
||||
private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
|
||||
private static final String LINE_SEPARATOR = System.lineSeparator();
|
||||
public static void extendSystemReport(final SystemReport systemReport) {
|
||||
for (final ISystemReportExtender call : CrashReportCallables.allCrashCallables()) {
|
||||
if (call.isActive())
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ public class ChannelListManager {
|
|||
.build();
|
||||
|
||||
private record Register(List<String> channels) implements CustomPacketPayload {
|
||||
private static Type<Register> TYPE = CustomPacketPayload.createType("register");
|
||||
private static StreamCodec<FriendlyByteBuf, Register> CODEC = StreamCodec.of(
|
||||
private static final Type<Register> TYPE = CustomPacketPayload.createType("register");
|
||||
private static final StreamCodec<FriendlyByteBuf, Register> CODEC = StreamCodec.of(
|
||||
(buf, v) -> encode(buf, v.channels),
|
||||
buf -> new Register(decode(buf))
|
||||
);
|
||||
|
|
@ -57,8 +57,8 @@ public class ChannelListManager {
|
|||
}
|
||||
|
||||
private record Unregister(List<String> channels) implements CustomPacketPayload {
|
||||
private static Type<Unregister> TYPE = CustomPacketPayload.createType("unregister");
|
||||
private static StreamCodec<FriendlyByteBuf, Unregister> CODEC = StreamCodec.of(
|
||||
private static final Type<Unregister> TYPE = CustomPacketPayload.createType("unregister");
|
||||
private static final StreamCodec<FriendlyByteBuf, Unregister> CODEC = StreamCodec.of(
|
||||
(buf, v) -> encode(buf, v.channels),
|
||||
buf -> new Unregister(decode(buf))
|
||||
);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|||
import it.unimi.dsi.fastutil.objects.Object2IntRBTreeMap;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraftforge.common.util.LogMessageAdapter;
|
||||
import net.minecraftforge.fml.ModLoadingContext;
|
||||
|
|
@ -794,7 +795,11 @@ public class ForgeRegistry<V> implements IForgeRegistryInternal<V>, IForgeRegist
|
|||
//Public for tests
|
||||
public Snapshot makeSnapshot() {
|
||||
Snapshot ret = new Snapshot();
|
||||
this.ids.forEach((id, value) -> ret.ids.put(getKey(value), id));
|
||||
for (Entry<Integer, V> entry : this.ids.entrySet()) {
|
||||
Integer id = entry.getKey();
|
||||
V value = entry.getValue();
|
||||
ret.ids.put(getKey(value), id.intValue());
|
||||
}
|
||||
ret.aliases.putAll(this.aliases);
|
||||
ret.blocked.addAll(this.blocked);
|
||||
ret.overrides.putAll(getOverrideOwners());
|
||||
|
|
@ -862,19 +867,19 @@ public class ForgeRegistry<V> implements IForgeRegistryInternal<V>, IForgeRegist
|
|||
data.put("ids", ids);
|
||||
|
||||
ListTag aliases = new ListTag();
|
||||
this.aliases.entrySet().forEach(e -> {
|
||||
this.aliases.forEach((k, v) -> {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putString("K", e.getKey().toString());
|
||||
tag.putString("V", e.getValue().toString());
|
||||
tag.putString("K", k.toString());
|
||||
tag.putString("V", v.toString());
|
||||
aliases.add(tag);
|
||||
});
|
||||
data.put("aliases", aliases);
|
||||
|
||||
ListTag overrides = new ListTag();
|
||||
this.overrides.entrySet().forEach(e -> {
|
||||
this.overrides.forEach((k, v) -> {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putString("K", e.getKey().toString());
|
||||
tag.putString("V", e.getValue());
|
||||
tag.putString("K", k.toString());
|
||||
tag.putString("V", v);
|
||||
overrides.add(tag);
|
||||
});
|
||||
data.put("overrides", overrides);
|
||||
|
|
@ -891,22 +896,22 @@ public class ForgeRegistry<V> implements IForgeRegistryInternal<V>, IForgeRegist
|
|||
return ret;
|
||||
|
||||
ListTag list = nbt.getList("ids", 10);
|
||||
list.forEach(e -> {
|
||||
CompoundTag comp = (CompoundTag)e;
|
||||
for (Tag tag : list) {
|
||||
CompoundTag comp = (CompoundTag) tag;
|
||||
ret.ids.put(ResourceLocation.parse(comp.getString("K")), comp.getInt("V"));
|
||||
});
|
||||
}
|
||||
|
||||
list = nbt.getList("aliases", 10);
|
||||
list.forEach(e -> {
|
||||
CompoundTag comp = (CompoundTag)e;
|
||||
for (Tag tag : list) {
|
||||
CompoundTag comp = (CompoundTag) tag;
|
||||
ret.aliases.put(ResourceLocation.parse(comp.getString("K")), ResourceLocation.parse(comp.getString("V")));
|
||||
});
|
||||
}
|
||||
|
||||
list = nbt.getList("overrides", 10);
|
||||
list.forEach(e -> {
|
||||
CompoundTag comp = (CompoundTag)e;
|
||||
for (Tag tag : list) {
|
||||
CompoundTag comp = (CompoundTag) tag;
|
||||
ret.overrides.put(ResourceLocation.parse(comp.getString("K")), comp.getString("V"));
|
||||
});
|
||||
}
|
||||
|
||||
int[] blocked = nbt.getIntArray("blocked");
|
||||
for (int i : blocked)
|
||||
|
|
@ -976,20 +981,24 @@ public class ForgeRegistry<V> implements IForgeRegistryInternal<V>, IForgeRegist
|
|||
}
|
||||
} else {
|
||||
// block item missing, warn as requested and block the id
|
||||
if (action == MissingMappingsEvent.Action.DEFAULT) {
|
||||
V m = this.missing == null ? null : this.missing.createMissing(remap.key, injectNetworkDummies);
|
||||
if (m == null)
|
||||
defaulted.add(remap.key);
|
||||
else
|
||||
this.add(remap.id, remap.key, m, remap.key.getNamespace());
|
||||
} else if (action == MissingMappingsEvent.Action.IGNORE) {
|
||||
LOGGER.debug(REGISTRIES,"Ignoring {}", remap.key);
|
||||
ignored++;
|
||||
} else if (action == MissingMappingsEvent.Action.FAIL) {
|
||||
LOGGER.debug(REGISTRIES,"Failing {}!", remap.key);
|
||||
failed.add(remap.key);
|
||||
} else if (action == MissingMappingsEvent.Action.WARN) {
|
||||
LOGGER.warn(REGISTRIES,"{} may cause world breakage!", remap.key);
|
||||
switch (action) {
|
||||
case DEFAULT -> {
|
||||
V m = this.missing == null ? null : this.missing.createMissing(remap.key, injectNetworkDummies);
|
||||
if (m == null)
|
||||
defaulted.add(remap.key);
|
||||
else
|
||||
this.add(remap.id, remap.key, m, remap.key.getNamespace());
|
||||
}
|
||||
case IGNORE -> {
|
||||
LOGGER.debug(REGISTRIES, "Ignoring {}", remap.key);
|
||||
ignored++;
|
||||
}
|
||||
case FAIL -> {
|
||||
LOGGER.debug(REGISTRIES, "Failing {}!", remap.key);
|
||||
failed.add(remap.key);
|
||||
}
|
||||
case WARN -> LOGGER.warn(REGISTRIES, "{} may cause world breakage!", remap.key);
|
||||
case null, default -> {}
|
||||
}
|
||||
this.block(remap.id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -514,12 +514,12 @@ public class GameData {
|
|||
throw new IllegalStateException("Could not get holder for " + key + " " + obj);
|
||||
}
|
||||
|
||||
obj.matchingStates().forEach((state) -> {
|
||||
for (BlockState state : obj.matchingStates()) {
|
||||
var oldType = map.put(state, holder);
|
||||
if (oldType != null) {
|
||||
throw new IllegalStateException(String.format(Locale.ENGLISH, "Point of interest types %s and %s both list %s in their blockstates, this is not allowed. Blockstates can only have one point of interest type each.", oldType, obj, state));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -53,10 +53,10 @@ class NamespacedWrapper<T> extends MappedRegistry<T> implements ILockableRegistr
|
|||
Lifecycle registryLifecycle = Lifecycle.stable();
|
||||
private boolean frozen = false; // Frozen is vanilla's variant of locked, but it can be unfrozen
|
||||
private List<Holder.Reference<T>> holdersSorted;
|
||||
private ObjectList<Holder.Reference<T>> holdersById = new ObjectArrayList<>(256);
|
||||
private Map<ResourceLocation, Holder.Reference<T>> holdersByName = new HashMap<>();
|
||||
private Map<T, Holder.Reference<T>> holders = new IdentityHashMap<>();
|
||||
private RegistryManager stage;
|
||||
private final ObjectList<Holder.Reference<T>> holdersById = new ObjectArrayList<>(256);
|
||||
private final Map<ResourceLocation, Holder.Reference<T>> holdersByName = new HashMap<>();
|
||||
private final Map<T, Holder.Reference<T>> holders = new IdentityHashMap<>();
|
||||
private final RegistryManager stage;
|
||||
private volatile Map<TagKey<T>, HolderSet.Named<T>> tags = new IdentityHashMap<>();
|
||||
private final Map<ResourceKey<T>, RegistrationInfo> registrationInfos = new IdentityHashMap<>();
|
||||
|
||||
|
|
@ -323,7 +323,9 @@ class NamespacedWrapper<T> extends MappedRegistry<T> implements ILockableRegistr
|
|||
@Override
|
||||
public void bindTags(Map<TagKey<T>, List<Holder<T>>> newTags) {
|
||||
Map<Holder.Reference<T>, List<TagKey<T>>> holderToTag = new IdentityHashMap<>();
|
||||
this.holdersByName.values().forEach(v -> holderToTag.put(v, new ArrayList<>()));
|
||||
for (Holder.Reference<T> tReference : this.holdersByName.values()) {
|
||||
holderToTag.put(tReference, new ArrayList<>());
|
||||
}
|
||||
newTags.forEach((name, values) -> values.forEach(holder -> addTagToHolder(holderToTag, name, holder)));
|
||||
|
||||
Set<TagKey<T>> set = new HashSet<>(Sets.difference(this.tags.keySet(), newTags.keySet()));
|
||||
|
|
@ -336,15 +338,17 @@ class NamespacedWrapper<T> extends MappedRegistry<T> implements ILockableRegistr
|
|||
newTags.forEach((k, v) -> tmpTags.computeIfAbsent(k, this::createTag).bind(v));
|
||||
|
||||
Set<TagKey<T>> defaultedTags = Sets.difference(this.optionalTags.keySet(), newTags.keySet());
|
||||
defaultedTags.forEach(name -> {
|
||||
for (TagKey<T> name : defaultedTags) {
|
||||
List<Holder<T>> defaults = this.optionalTags.get(name).stream()
|
||||
.map(valueSupplier -> getHolder(valueSupplier.get()).orElse(null))
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
defaults.forEach(holder -> addTagToHolder(holderToTag, name, holder));
|
||||
for (Holder<T> holder : defaults) {
|
||||
addTagToHolder(holderToTag, name, holder);
|
||||
}
|
||||
tmpTags.computeIfAbsent(name, this::createTag).bind(defaults);
|
||||
});
|
||||
}
|
||||
|
||||
holderToTag.forEach(Holder.Reference::bindTags);
|
||||
this.tags = tmpTags;
|
||||
|
|
|
|||
|
|
@ -221,16 +221,13 @@ public class ObjectHolderRegistry
|
|||
public static void applyObjectHolders(Predicate<ResourceLocation> filter)
|
||||
{
|
||||
RuntimeException aggregate = new RuntimeException("Failed to apply some object holders, see suppressed exceptions for details");
|
||||
objectHolders.forEach(objectHolder -> {
|
||||
try
|
||||
{
|
||||
for (Consumer<Predicate<ResourceLocation>> objectHolder : objectHolders) {
|
||||
try {
|
||||
objectHolder.accept(filter);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
aggregate.addSuppressed(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (aggregate.getSuppressed().length > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
package net.minecraftforge.registries;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.registries.IForgeRegistry.AddCallback;
|
||||
|
|
@ -15,6 +14,8 @@ import net.minecraftforge.registries.IForgeRegistry.CreateCallback;
|
|||
import net.minecraftforge.registries.IForgeRegistry.MissingFactory;
|
||||
import net.minecraftforge.registries.IForgeRegistry.ValidateCallback;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
|
@ -39,18 +40,18 @@ public class RegistryBuilder<T> {
|
|||
private ResourceLocation optionalDefaultKey;
|
||||
private int minId = 0;
|
||||
private int maxId = MAX_ID;
|
||||
private List<AddCallback<T>> addCallback = Lists.newArrayList();
|
||||
private List<ClearCallback<T>> clearCallback = Lists.newArrayList();
|
||||
private List<CreateCallback<T>> createCallback = Lists.newArrayList();
|
||||
private List<ValidateCallback<T>> validateCallback = Lists.newArrayList();
|
||||
private List<BakeCallback<T>> bakeCallback = Lists.newArrayList();
|
||||
private final List<AddCallback<T>> addCallback = new ArrayList<>();
|
||||
private final List<ClearCallback<T>> clearCallback = new ArrayList<>();
|
||||
private final List<CreateCallback<T>> createCallback = new ArrayList<>();
|
||||
private final List<ValidateCallback<T>> validateCallback = new ArrayList<>();
|
||||
private final List<BakeCallback<T>> bakeCallback = new ArrayList<>();
|
||||
private boolean saveToDisc = true;
|
||||
private boolean sync = true;
|
||||
private boolean allowOverrides = true;
|
||||
private boolean allowModifications = false;
|
||||
private boolean hasWrapper = false;
|
||||
private MissingFactory<T> missingFactory;
|
||||
private Set<ResourceLocation> legacyNames = new HashSet<>();
|
||||
private final Set<ResourceLocation> legacyNames = new HashSet<>();
|
||||
@Nullable
|
||||
private Function<T, Holder.Reference<T>> intrusiveHolderCallback = null;
|
||||
|
||||
|
|
@ -206,8 +207,8 @@ public class RegistryBuilder<T> {
|
|||
IForgeRegistry<T> create() {
|
||||
if (hasWrapper) {
|
||||
GameData.WrapperFactory<T> wrapper = GameData.createWrapperFactory(getDefault() != null);
|
||||
this.addCallback.add(0, wrapper);
|
||||
this.createCallback.add(0, wrapper);
|
||||
this.addCallback.addFirst(wrapper);
|
||||
this.createCallback.addFirst(wrapper);
|
||||
}
|
||||
return RegistryManager.ACTIVE.createRegistry(registryName, this);
|
||||
}
|
||||
|
|
@ -217,7 +218,7 @@ public class RegistryBuilder<T> {
|
|||
if (addCallback.isEmpty())
|
||||
return null;
|
||||
if (addCallback.size() == 1)
|
||||
return addCallback.get(0);
|
||||
return addCallback.getFirst();
|
||||
|
||||
var tmp = this.addCallback;
|
||||
return (owner, stage, id, key, obj, old) -> {
|
||||
|
|
@ -231,7 +232,7 @@ public class RegistryBuilder<T> {
|
|||
if (clearCallback.isEmpty())
|
||||
return null;
|
||||
if (clearCallback.size() == 1)
|
||||
return clearCallback.get(0);
|
||||
return clearCallback.getFirst();
|
||||
|
||||
var tmp = this.clearCallback;
|
||||
return (owner, stage) -> {
|
||||
|
|
@ -245,7 +246,7 @@ public class RegistryBuilder<T> {
|
|||
if (createCallback.isEmpty())
|
||||
return null;
|
||||
if (createCallback.size() == 1)
|
||||
return createCallback.get(0);
|
||||
return createCallback.getFirst();
|
||||
|
||||
var tmp = this.createCallback;
|
||||
return (owner, stage) -> {
|
||||
|
|
@ -259,7 +260,7 @@ public class RegistryBuilder<T> {
|
|||
if (validateCallback.isEmpty())
|
||||
return null;
|
||||
if (validateCallback.size() == 1)
|
||||
return validateCallback.get(0);
|
||||
return validateCallback.getFirst();
|
||||
|
||||
var tmp = this.validateCallback;
|
||||
return (owner, stage, id, key, obj) -> {
|
||||
|
|
@ -273,7 +274,7 @@ public class RegistryBuilder<T> {
|
|||
if (bakeCallback.isEmpty())
|
||||
return null;
|
||||
if (bakeCallback.size() == 1)
|
||||
return bakeCallback.get(0);
|
||||
return bakeCallback.getFirst();
|
||||
|
||||
var tmp = this.bakeCallback;
|
||||
return (owner, stage) -> {
|
||||
|
|
|
|||
|
|
@ -7,14 +7,13 @@ package net.minecraftforge.registries;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import net.minecraft.core.RegistrationInfo;
|
||||
import net.minecraft.core.WritableRegistry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
|
|
@ -35,10 +34,10 @@ public class RegistryManager {
|
|||
private static Set<ResourceLocation> vanillaRegistryKeys = Set.of();
|
||||
|
||||
BiMap<ResourceLocation, ForgeRegistry<?>> registries = HashBiMap.create();
|
||||
private Map<ResourceLocation, ? extends IForgeRegistry<?>> registryView = Collections.unmodifiableMap(registries);
|
||||
private Set<ResourceLocation> persisted = Sets.newHashSet();
|
||||
private Set<ResourceLocation> synced = Sets.newHashSet();
|
||||
private Map<ResourceLocation, ResourceLocation> legacyNames = new HashMap<>();
|
||||
private final Map<ResourceLocation, ? extends IForgeRegistry<?>> registryView = Collections.unmodifiableMap(registries);
|
||||
private final Set<ResourceLocation> persisted = new HashSet<>();
|
||||
private final Set<ResourceLocation> synced = new HashSet<>();
|
||||
private final Map<ResourceLocation, ResourceLocation> legacyNames = new HashMap<>();
|
||||
private final String name;
|
||||
|
||||
RegistryManager() {
|
||||
|
|
@ -152,7 +151,9 @@ public class RegistryManager {
|
|||
public Map<ResourceLocation, Snapshot> takeSnapshot(boolean savingToDisc) {
|
||||
Map<ResourceLocation, Snapshot> ret = new HashMap<>();
|
||||
var keys = savingToDisc ? this.persisted : this.synced;
|
||||
keys.forEach(name -> ret.put(name, getRegistry(name).makeSnapshot()));
|
||||
for (ResourceLocation key : keys) {
|
||||
ret.put(key, getRegistry(key).makeSnapshot());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue