Files
MinecraftForge/src/main/java/net/minecraftforge/resource/ResourcePackLoader.java
T

136 lines
5.7 KiB
Java

/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minecraft.server.packs.repository.Pack.Position;
import net.minecraft.DetectedVersion;
import net.minecraft.network.chat.Component;
import net.minecraft.server.packs.PackLocationInfo;
import net.minecraft.server.packs.PackResources;
import net.minecraft.server.packs.PackSelectionConfig;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.PathPackResources;
import net.minecraft.server.packs.metadata.pack.PackMetadataSection;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.server.packs.repository.PackSource;
import net.minecraftforge.fml.Logging;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.ModLoadingStage;
import net.minecraftforge.fml.ModLoadingWarning;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public class ResourcePackLoader {
private static final Logger LOGGER = LogManager.getLogger();
public static void loadResourcePacks(PackRepository resourcePacks, boolean client) {
resourcePacks.addPackFinder(repo -> findPacks(repo, client));
}
public static List<String> getPackNames() {
return ModList.get().applyForEachModFile(mf->"mod:"+mf.getModInfos().getFirst().getModId()).filter(n->!n.equals("mod:minecraft")).toList();
}
public static <V> Comparator<Map.Entry<String,V>> getSorter() {
List<String> order = new ArrayList<>();
order.add("vanilla");
order.add("mod_resources");
ModList.get().getModFiles().stream()
.filter(mf -> mf.requiredLanguageLoaders().stream().noneMatch(ls->ls.languageName().equals("minecraft")))
.map(e -> e.getMods().getFirst().getModId())
.map(e -> "mod:" + e)
.forEach(order::add);
final Object2IntMap<String> order_f = new Object2IntOpenHashMap<>(order.size());
for (int x = 0; x < order.size(); x++)
order_f.put(order.get(x), x);
return (e1, e2) -> {
final String s1 = e1.getKey();
final String s2 = e2.getKey();
final int i1 = order_f.getOrDefault(s1, -1);
final int i2 = order_f.getOrDefault(s2, -1);
if (i1 == i2 && i1 == -1)
return s1.compareTo(s2);
if (i1 == -1) return 1;
if (i2 == -1) return -1;
return i2 - i1;
};
}
private static void findPacks(Consumer<Pack> packAcceptor, boolean client) {
var type = client ? PackType.CLIENT_RESOURCES : PackType.SERVER_DATA;
var version = DetectedVersion.BUILT_IN.packVersion(type);
var hiddenPacks = new ArrayList<PackResources>();
for (var mod : ModList.get().getModFiles()) {
if (mod.requiredLanguageLoaders().stream().anyMatch(ls -> ls.languageName().equals("minecraft")))
continue;
var file = mod.getFile();
var root = file.findResource("");
var supplier = new PathPackResources.PathResourcesSupplier(root);
var modinfo = file.getModInfos().getFirst();
var name = "mod:" + modinfo.getModId();
var info = new PackLocationInfo(name, Component.literal(file.getFileName()), PackSource.DEFAULT, Optional.empty());
var meta = Pack.readPackMetadata(info, supplier, version, type);
Pack pack = null;
if (meta != null)
pack = new Pack(info, supplier, meta, new PackSelectionConfig(false, Position.BOTTOM, false));
if (pack == null) {
// Vanilla only logs an error, instead of propagating, so handle null and warn that something went wrong
ModLoader.get().addWarning(new ModLoadingWarning(modinfo, ModLoadingStage.ERROR, "fml.modloading.brokenresources", file));
continue;
}
LOGGER.debug(Logging.CORE, "Generating PackInfo named {} for mod file {}", name, file.getFilePath());
if (!client || mod.showAsResourcePack())
packAcceptor.accept(pack);
else
hiddenPacks.add(pack.open());
}
if (!hiddenPacks.isEmpty()) {
var info = new PackLocationInfo("mod_resources", Component.translatable("fml.resources.modresources", hiddenPacks.size()), PackSource.DEFAULT, Optional.empty());
@SuppressWarnings("resource")
var delegating = new DelegatingPackResources(info,
new PackMetadataSection(
Component.translatable("fml.resources.modresources", hiddenPacks.size()),
version.minorRange()
),
hiddenPacks
);
var supplier = delegating.supplier();
// Create a resource pack merging all mod resources that should be hidden
var wrapper = new PackLocationInfo("mod_resources", Component.literal("Mod Resources"), PackSource.DEFAULT, Optional.empty());
var wrapperCfg = new PackSelectionConfig(true, Position.BOTTOM, false);
var modResourcesPack = Pack.readMetaAndCreate(wrapper, supplier, type, wrapperCfg);
packAcceptor.accept(modResourcesPack);
}
}
}