From ca980a56bc4abc540567894ea59ec8cbd24b246f Mon Sep 17 00:00:00 2001 From: tterrag Date: Fri, 4 Oct 2019 17:16:36 -0400 Subject: [PATCH] Combine all hidden mod resource packs into a single sortable pack Fix mod datapacks sorting under vanilla --- .../fml/client/ClientModLoader.java | 62 +++++--- .../fml/packs/DelegatableResourcePack.java | 21 +++ .../fml/packs/DelegatingResourcePack.java | 133 ++++++++++++++++++ .../fml/packs/ModFileResourcePack.java | 12 +- .../fml/packs/ResourcePackLoader.java | 3 +- .../fml/server/ServerLifecycleHooks.java | 40 +++--- .../resources/assets/forge/lang/en_us.json | 1 + 7 files changed, 220 insertions(+), 52 deletions(-) create mode 100644 src/main/java/net/minecraftforge/fml/packs/DelegatableResourcePack.java create mode 100644 src/main/java/net/minecraftforge/fml/packs/DelegatingResourcePack.java diff --git a/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java b/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java index fa3f3a5fa..d057f5b66 100644 --- a/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java +++ b/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java @@ -19,15 +19,37 @@ package net.minecraftforge.fml.client; +import static net.minecraftforge.fml.Logging.CORE; +import static net.minecraftforge.fml.loading.LogMarkers.LOADING; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.mojang.blaze3d.platform.GlStateManager; + import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.DownloadingPackFinder; import net.minecraft.client.resources.ClientResourcePackInfo; +import net.minecraft.client.resources.DownloadingPackFinder; import net.minecraft.profiler.IProfiler; import net.minecraft.resources.IFutureReloadListener; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.resources.IResourceManager; import net.minecraft.resources.ResourcePackInfo; import net.minecraft.resources.ResourcePackList; +import net.minecraft.resources.data.PackMetadataSection; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.ModelRegistryEvent; @@ -46,27 +68,12 @@ import net.minecraftforge.fml.VersionChecker; import net.minecraftforge.fml.client.gui.LoadingErrorScreen; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.loading.moddiscovery.ModFile; +import net.minecraftforge.fml.packs.DelegatableResourcePack; +import net.minecraftforge.fml.packs.DelegatingResourcePack; import net.minecraftforge.fml.packs.ModFileResourcePack; import net.minecraftforge.fml.packs.ResourcePackLoader; import net.minecraftforge.fml.server.LanguageHook; import net.minecraftforge.forgespi.language.IModInfo; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import com.mojang.blaze3d.platform.GlStateManager; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import static net.minecraftforge.fml.Logging.CORE; -import static net.minecraftforge.fml.loading.LogMarkers.LOADING; @OnlyIn(Dist.CLIENT) public class ClientModLoader @@ -173,17 +180,18 @@ public class ClientModLoader return loading; } - private static ResourcePackLoader.IPackInfoFinder buildPackFinder(Map modResourcePacks, BiConsumer packSetter) { + private static ResourcePackLoader.IPackInfoFinder buildPackFinder(Map modResourcePacks, BiConsumer packSetter) { return (packList, factory) -> clientPackFinder(modResourcePacks, packSetter, packList, factory); } - private static void clientPackFinder(Map modResourcePacks, BiConsumer packSetter, Map packList, ResourcePackInfo.IFactory factory) { - for (Map.Entry e : modResourcePacks.entrySet()) + private static void clientPackFinder(Map modResourcePacks, BiConsumer packSetter, Map packList, ResourcePackInfo.IFactory factory) { + List hiddenPacks = new ArrayList<>(); + for (Entry e : modResourcePacks.entrySet()) { IModInfo mod = e.getKey().getModInfos().get(0); if (Objects.equals(mod.getModId(), "minecraft")) continue; // skip the minecraft "mod" final String name = "mod:" + mod.getModId(); - final T packInfo = ResourcePackInfo.createResourcePack(name, true, e::getValue, factory, ResourcePackInfo.Priority.BOTTOM); + final T packInfo = ResourcePackInfo.createResourcePack(name, false, e::getValue, factory, ResourcePackInfo.Priority.BOTTOM); if (packInfo == null) { // Vanilla only logs an error, instead of propagating, so handle null and warn that something went wrong ModLoader.get().addWarning(new ModLoadingWarning(mod, ModLoadingStage.ERROR, "fml.modloading.brokenresources", e.getKey())); @@ -191,7 +199,15 @@ public class ClientModLoader } packSetter.accept(e.getValue(), packInfo); LOGGER.debug(CORE, "Generating PackInfo named {} for mod file {}", name, e.getKey().getFilePath()); - packList.put(name, packInfo); + if (mod.getOwningFile().showAsResourcePack()) { + packList.put(name, packInfo); + } else { + hiddenPacks.add(e.getValue()); + } } + final T packInfo = ResourcePackInfo.createResourcePack("mod_resources", true, () -> new DelegatingResourcePack("mod_resources", "Mod Resources", + new PackMetadataSection(new TranslationTextComponent("fml.resources.modresources", hiddenPacks.size()), 4), + hiddenPacks), factory, ResourcePackInfo.Priority.BOTTOM); + packList.put("mod_resources", packInfo); } } diff --git a/src/main/java/net/minecraftforge/fml/packs/DelegatableResourcePack.java b/src/main/java/net/minecraftforge/fml/packs/DelegatableResourcePack.java new file mode 100644 index 000000000..9afa8fbbf --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/packs/DelegatableResourcePack.java @@ -0,0 +1,21 @@ +package net.minecraftforge.fml.packs; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import net.minecraft.resources.ResourcePack; + +public abstract class DelegatableResourcePack extends ResourcePack +{ + protected DelegatableResourcePack(File resourcePackFileIn) + { + super(resourcePackFileIn); + } + + @Override + public abstract InputStream getInputStream(String resourcePath) throws IOException; + + @Override + public abstract boolean resourceExists(String resourcePath); +} diff --git a/src/main/java/net/minecraftforge/fml/packs/DelegatingResourcePack.java b/src/main/java/net/minecraftforge/fml/packs/DelegatingResourcePack.java new file mode 100644 index 000000000..04cfbdb4c --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/packs/DelegatingResourcePack.java @@ -0,0 +1,133 @@ +package net.minecraftforge.fml.packs; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import net.minecraft.resources.ResourcePack; +import net.minecraft.resources.ResourcePackFileNotFoundException; +import net.minecraft.resources.ResourcePackType; +import net.minecraft.resources.data.IMetadataSectionSerializer; +import net.minecraft.resources.data.PackMetadataSection; +import net.minecraft.util.ResourceLocation; + +public class DelegatingResourcePack extends ResourcePack +{ + private final List delegates = new ArrayList<>(); + private final String name; + private final PackMetadataSection packInfo; + + public DelegatingResourcePack(String id, String name, PackMetadataSection packInfo) + { + this(id, name, packInfo, Collections.emptyList()); + } + + public DelegatingResourcePack(String id, String name, PackMetadataSection packInfo, List packs) + { + super(new File(id)); + this.name = name; + this.packInfo = packInfo; + packs.forEach(this::addDelegate); + } + + public void addDelegate(DelegatableResourcePack pack) + { + synchronized(delegates) + { + this.delegates.add(pack); + } + } + + @Override + public String getName() + { + return name; + } + + @SuppressWarnings("unchecked") + @Override + public T getMetadata(IMetadataSectionSerializer deserializer) throws IOException + { + if (deserializer.getSectionName().equals("pack")) + { + return (T) packInfo; + } + return null; + } + + @Override + public Collection getAllResourceLocations(ResourcePackType type, String pathIn, int maxDepth, Predicate filter) + { + synchronized(delegates) + { + return delegates.stream() + .flatMap(r -> r.getAllResourceLocations(type, pathIn, maxDepth, filter).stream()) + .collect(Collectors.toList()); + } + } + + @Override + public Set getResourceNamespaces(ResourcePackType type) + { + synchronized (delegates) + { + return delegates.stream() + .flatMap(r -> r.getResourceNamespaces(type).stream()) + .collect(Collectors.toSet()); + } + } + + @Override + public void close() throws IOException + { + synchronized(delegates) + { + for (ResourcePack pack : delegates) + { + pack.close(); + } + } + } + + @Override + protected InputStream getInputStream(String resourcePath) throws IOException + { + if (!resourcePath.equals("pack.png")) // Mods shouldn't be able to mess with the pack icon + { + synchronized (delegates) + { + for (DelegatableResourcePack pack : delegates) + { + if (pack.resourceExists(resourcePath)) + { + return pack.getInputStream(resourcePath); + } + } + } + } + throw new ResourcePackFileNotFoundException(this.file, resourcePath); + } + + @Override + protected boolean resourceExists(String resourcePath) + { + synchronized (delegates) + { + for (DelegatableResourcePack pack : delegates) + { + if (pack.resourceExists(resourcePath)) + { + return true; + } + } + } + return false; + } +} diff --git a/src/main/java/net/minecraftforge/fml/packs/ModFileResourcePack.java b/src/main/java/net/minecraftforge/fml/packs/ModFileResourcePack.java index f2d4f71e5..785d93a1f 100644 --- a/src/main/java/net/minecraftforge/fml/packs/ModFileResourcePack.java +++ b/src/main/java/net/minecraftforge/fml/packs/ModFileResourcePack.java @@ -52,7 +52,7 @@ import org.apache.logging.log4j.Logger; import static net.minecraftforge.fml.Logging.CORE; -public class ModFileResourcePack extends ResourcePack +public class ModFileResourcePack extends DelegatableResourcePack { private final ModFile modFile; private ResourcePackInfo packInfo; @@ -74,14 +74,14 @@ public class ModFileResourcePack extends ResourcePack } @Override - protected InputStream getInputStream(String name) throws IOException + public InputStream getInputStream(String name) throws IOException { final Path path = modFile.getLocator().findPath(modFile, name); return Files.newInputStream(path, StandardOpenOption.READ); } @Override - protected boolean resourceExists(String name) + public boolean resourceExists(String name) { return Files.exists(modFile.getLocator().findPath(modFile, name)); } @@ -146,7 +146,6 @@ public class ModFileResourcePack extends ResourcePack } } - @Override public void close() throws IOException { @@ -160,9 +159,4 @@ public class ModFileResourcePack extends ResourcePack T getPackInfo() { return (T)this.packInfo; } - - @Override - public boolean isHidden() { - return !modFile.getModFileInfo().showAsResourcePack(); - } } diff --git a/src/main/java/net/minecraftforge/fml/packs/ResourcePackLoader.java b/src/main/java/net/minecraftforge/fml/packs/ResourcePackLoader.java index 5eca5f7ba..e855ee8e8 100644 --- a/src/main/java/net/minecraftforge/fml/packs/ResourcePackLoader.java +++ b/src/main/java/net/minecraftforge/fml/packs/ResourcePackLoader.java @@ -32,6 +32,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import net.minecraft.resources.IPackFinder; +import net.minecraft.resources.ResourcePack; import net.minecraft.resources.ResourcePackInfo; import net.minecraft.resources.ResourcePackList; import net.minecraftforge.fml.ModList; @@ -49,7 +50,7 @@ public class ResourcePackLoader map(ModFileInfo::getFile).map(mf->modResourcePacks.get(mf)); } - public static void loadResourcePacks(ResourcePackList resourcePacks, BiFunction, BiConsumer, IPackInfoFinder> packFinder) { + public static void loadResourcePacks(ResourcePackList resourcePacks, BiFunction, BiConsumer, IPackInfoFinder> packFinder) { resourcePackList = resourcePacks; modResourcePacks = ModList.get().getModFiles().stream(). filter(mf->!Objects.equals(mf.getModLoader(),"minecraft")). diff --git a/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java b/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java index 23c2fe10a..567a57dbf 100644 --- a/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java +++ b/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java @@ -19,8 +19,23 @@ package net.minecraftforge.fml.server; -import net.minecraft.network.ProtocolType; +import static net.minecraftforge.fml.Logging.CORE; + +import java.nio.file.Path; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BiConsumer; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.MarkerManager; + import net.minecraft.network.NetworkManager; +import net.minecraft.network.ProtocolType; import net.minecraft.network.handshake.client.CHandshakePacket; import net.minecraft.network.login.server.SDisconnectLoginPacket; import net.minecraft.resources.ResourcePackInfo; @@ -36,8 +51,8 @@ import net.minecraftforge.fml.ModLoadingWarning; import net.minecraftforge.fml.config.ConfigTracker; import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; -import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; +import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.loading.FileUtils; @@ -49,19 +64,6 @@ import net.minecraftforge.fml.network.NetworkRegistry; import net.minecraftforge.fml.packs.ModFileResourcePack; import net.minecraftforge.fml.packs.ResourcePackLoader; import net.minecraftforge.forgespi.language.IModInfo; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.MarkerManager; - -import java.nio.file.Path; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.BiConsumer; - -import static net.minecraftforge.fml.Logging.CORE; public class ServerLifecycleHooks { @@ -193,17 +195,17 @@ public class ServerLifecycleHooks System.exit(retVal); } - private static ResourcePackLoader.IPackInfoFinder buildPackFinder(Map modResourcePacks, BiConsumer packSetter) { + private static ResourcePackLoader.IPackInfoFinder buildPackFinder(Map modResourcePacks, BiConsumer packSetter) { return (packList, factory) -> serverPackFinder(modResourcePacks, packSetter, packList, factory); } - private static void serverPackFinder(Map modResourcePacks, BiConsumer packSetter, Map packList, ResourcePackInfo.IFactory factory) { - for (Map.Entry e : modResourcePacks.entrySet()) + private static void serverPackFinder(Map modResourcePacks, BiConsumer packSetter, Map packList, ResourcePackInfo.IFactory factory) { + for (Entry e : modResourcePacks.entrySet()) { IModInfo mod = e.getKey().getModInfos().get(0); if (Objects.equals(mod.getModId(), "minecraft")) continue; // skip the minecraft "mod" final String name = "mod:" + mod.getModId(); - final T packInfo = ResourcePackInfo.createResourcePack(name, true, e::getValue, factory, ResourcePackInfo.Priority.BOTTOM); + final T packInfo = ResourcePackInfo.createResourcePack(name, true, e::getValue, factory, ResourcePackInfo.Priority.TOP); if (packInfo == null) { // Vanilla only logs an error, instead of propagating, so handle null and warn that something went wrong ModLoader.get().addWarning(new ModLoadingWarning(mod, ModLoadingStage.ERROR, "fml.modloading.brokenresources", e.getKey())); diff --git a/src/main/resources/assets/forge/lang/en_us.json b/src/main/resources/assets/forge/lang/en_us.json index 134964afa..f32379c61 100644 --- a/src/main/resources/assets/forge/lang/en_us.json +++ b/src/main/resources/assets/forge/lang/en_us.json @@ -57,6 +57,7 @@ "fml.modloading.brokenfile.optifine": "File {2} is an incompatible version of OptiFine", "fml.modloading.brokenfile.invalidzip": "File {2} is not a jar file", "fml.modloading.brokenresources": "File {2} failed to load a valid ResourcePackInfo", + "fml.resources.modresources": "Resources for {0} mod files", "fml.messages.artifactversion.ornotinstalled":"{0,ornull,fml.messages.artifactversion.notinstalled}", "fml.messages.artifactversion":"{0,ornull,fml.messages.artifactversion.none}",