diff --git a/fmlcore/src/main/java/net/minecraftforge/fml/ModLoadingWarning.java b/fmlcore/src/main/java/net/minecraftforge/fml/ModLoadingWarning.java index 09852fd1e9..27fe31da27 100644 --- a/fmlcore/src/main/java/net/minecraftforge/fml/ModLoadingWarning.java +++ b/fmlcore/src/main/java/net/minecraftforge/fml/ModLoadingWarning.java @@ -12,8 +12,7 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Stream; -public class ModLoadingWarning -{ +public class ModLoadingWarning { /** * Mod Info for mod with warning */ diff --git a/patches/minecraft/net/minecraft/client/gui/screens/worldselection/CreateWorldScreen.java.patch b/patches/minecraft/net/minecraft/client/gui/screens/worldselection/CreateWorldScreen.java.patch index d2445ef544..36e988ffbe 100644 --- a/patches/minecraft/net/minecraft/client/gui/screens/worldselection/CreateWorldScreen.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/screens/worldselection/CreateWorldScreen.java.patch @@ -21,7 +21,7 @@ if (path != null) { if (this.tempDataPackRepository == null) { this.tempDataPackRepository = ServerPacksSource.createPackRepository(path, this.packValidator); -+ net.minecraftforge.resource.ResourcePackLoader.loadResourcePacks(this.tempDataPackRepository, net.minecraftforge.server.ServerLifecycleHooks::buildPackFinder); ++ net.minecraftforge.resource.ResourcePackLoader.loadResourcePacks(this.tempDataPackRepository, false); this.tempDataPackRepository.reload(); } diff --git a/patches/minecraft/net/minecraft/resources/RegistryDataLoader.java.patch b/patches/minecraft/net/minecraft/resources/RegistryDataLoader.java.patch index f7b58e554a..ce0ad31a67 100644 --- a/patches/minecraft/net/minecraft/resources/RegistryDataLoader.java.patch +++ b/patches/minecraft/net/minecraft/resources/RegistryDataLoader.java.patch @@ -1,5 +1,16 @@ --- a/net/minecraft/resources/RegistryDataLoader.java +++ b/net/minecraft/resources/RegistryDataLoader.java +@@ -75,7 +_,9 @@ + }); + if (!map.isEmpty()) { + logErrors(map); +- throw new IllegalStateException("Failed to load registries due to above errors"); ++ var buf = new StringBuilder("Failed to load registries, see debug.log for more details:"); ++ map.forEach((k,v) -> buf.append("\n\t").append(k.toString()).append(": ").append(v.getMessage())); ++ throw new IllegalStateException(buf.toString()); + } else { + return (new RegistryAccess.ImmutableRegistryAccess(list.stream().map(Pair::getFirst).toList())).freeze(); + } @@ -124,13 +_,16 @@ } diff --git a/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch b/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch index 5785af2e37..38f7c9353e 100644 --- a/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch +++ b/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch @@ -187,7 +187,7 @@ } public static WorldDataConfiguration configurePackRepository(PackRepository p_248681_, DataPackConfig p_248920_, boolean p_249869_, FeatureFlagSet p_251243_) { -+ net.minecraftforge.resource.ResourcePackLoader.loadResourcePacks(p_248681_, net.minecraftforge.server.ServerLifecycleHooks::buildPackFinder); ++ net.minecraftforge.resource.ResourcePackLoader.loadResourcePacks(p_248681_, false); p_248681_.reload(); + DataPackConfig.DEFAULT.addModPacks(net.minecraftforge.common.ForgeHooks.getModPacks()); + p_248920_.addModPacks(net.minecraftforge.common.ForgeHooks.getModPacks()); diff --git a/patches/minecraft/net/minecraft/world/level/Explosion.java.patch b/patches/minecraft/net/minecraft/world/level/Explosion.java.patch index 882c61e034..d675e5fba7 100644 --- a/patches/minecraft/net/minecraft/world/level/Explosion.java.patch +++ b/patches/minecraft/net/minecraft/world/level/Explosion.java.patch @@ -1,21 +1,5 @@ --- a/net/minecraft/world/level/Explosion.java +++ b/net/minecraft/world/level/Explosion.java -@@ -57,6 +_,7 @@ - private final SoundEvent explosionSound; - private final ObjectArrayList toBlow = new ObjectArrayList<>(); - private final Map hitPlayers = Maps.newHashMap(); -+ private final Vec3 position; - - public static DamageSource getDefaultDamageSource(Level p_309890_, @Nullable Entity p_311046_) { - return p_309890_.damageSources().explosion(p_311046_, getIndirectSourceEntityInternal(p_311046_)); -@@ -90,6 +_,7 @@ - this.smallExplosionParticles = p_312175_; - this.largeExplosionParticles = p_310459_; - this.explosionSound = p_311795_; -+ this.position = new Vec3(this.x, this.y, this.z); - } - - private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity p_46063_) { @@ -193,6 +_,7 @@ int j2 = Mth.floor(this.z - (double)f2 - 1.0D); int j1 = Mth.floor(this.z + (double)f2 + 1.0D); @@ -24,14 +8,15 @@ Vec3 vec3 = new Vec3(this.x, this.y, this.z); for(Entity entity : list) { -@@ -345,6 +_,15 @@ +@@ -345,6 +_,16 @@ public List getToBlow() { return this.toBlow; + } + ++ @Deprecated(forRemoval = true, since = "1.20.4") + public Vec3 getPosition() { -+ return this.position; ++ return this.center(); + } + + @Nullable diff --git a/src/main/java/net/minecraftforge/client/gui/ModListScreen.java b/src/main/java/net/minecraftforge/client/gui/ModListScreen.java index e8b0986aab..0835202a8f 100644 --- a/src/main/java/net/minecraftforge/client/gui/ModListScreen.java +++ b/src/main/java/net/minecraftforge/client/gui/ModListScreen.java @@ -6,7 +6,7 @@ package net.minecraftforge.client.gui; import java.io.IOException; -import java.io.InputStream; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -17,12 +17,10 @@ import java.util.function.Function; import java.util.stream.Collectors; import net.minecraft.client.gui.narration.NarrationElementOutput; -import net.minecraft.server.packs.resources.IoSupplier; import net.minecraftforge.client.ConfigScreenHandler; import net.minecraftforge.client.gui.widget.ModListWidget; import net.minecraftforge.client.gui.widget.ScrollPanel; import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo; -import net.minecraftforge.resource.PathPackResources; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -53,19 +51,16 @@ import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.VersionChecker; import net.minecraftforge.fml.loading.FMLPaths; import net.minecraftforge.fml.loading.StringUtils; -import net.minecraftforge.resource.ResourcePackLoader; import net.minecraftforge.forgespi.language.IModInfo; import net.minecraft.locale.Language; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Style; -public class ModListScreen extends Screen -{ +public class ModListScreen extends Screen { private static String stripControlCodes(String value) { return net.minecraft.util.StringUtil.stripColor(value); } private static final Logger LOGGER = LogManager.getLogger(); - private enum SortType implements Comparator - { + private enum SortType implements Comparator { NORMAL, A_TO_Z{ @Override protected int compare(String name1, String name2){ return name1.compareTo(name2); }}, Z_TO_A{ @Override protected int compare(String name1, String name2){ return name2.compareTo(name1); }}; @@ -105,8 +100,7 @@ public class ModListScreen extends Screen private boolean sorted = false; private SortType sortType = SortType.NORMAL; - public ModListScreen(Screen parentScreen) - { + public ModListScreen(Screen parentScreen) { super(Component.translatable("fml.menu.mods.title")); this.parentScreen = parentScreen; this.mods = Collections.unmodifiableList(ModList.get().getMods()); @@ -118,32 +112,26 @@ public class ModListScreen extends Screen private Size2i logoDims = new Size2i(0, 0); private List lines = Collections.emptyList(); - InfoPanel(Minecraft mcIn, int widthIn, int heightIn, int topIn) - { + InfoPanel(Minecraft mcIn, int widthIn, int heightIn, int topIn) { super(mcIn, widthIn, heightIn, topIn, modList.getRight() + PADDING); } - void setInfo(List lines, ResourceLocation logoPath, Size2i logoDims) - { + void setInfo(List lines, ResourceLocation logoPath, Size2i logoDims) { this.logoPath = logoPath; this.logoDims = logoDims; this.lines = resizeContent(lines); } - void clearInfo() - { + void clearInfo() { this.logoPath = null; this.logoDims = new Size2i(0, 0); this.lines = Collections.emptyList(); } - private List resizeContent(List lines) - { + private List resizeContent(List lines) { List ret = new ArrayList<>(); - for (String line : lines) - { - if (line == null) - { + for (String line : lines) { + if (line == null) { ret.add(null); continue; } @@ -151,16 +139,13 @@ public class ModListScreen extends Screen Component chat = ForgeHooks.newChatWithLinks(line, false); int maxTextLength = this.width - 12; if (maxTextLength >= 0) - { ret.addAll(Language.getInstance().getVisualOrder(font.getSplitter().splitLines(chat, maxTextLength, Style.EMPTY))); - } } return ret; } @Override - public int getContentHeight() - { + public int getContentHeight() { int height = 50; height += (lines.size() * font.lineHeight); if (height < this.bottom - this.top - 8) @@ -169,14 +154,12 @@ public class ModListScreen extends Screen } @Override - protected int getScrollAmount() - { + protected int getScrollAmount() { return font.lineHeight * 3; } @Override - protected void drawPanel(GuiGraphics guiGraphics, int entryRight, int relativeY, Tesselator tess, int mouseX, int mouseY) - { + protected void drawPanel(GuiGraphics guiGraphics, int entryRight, int relativeY, Tesselator tess, int mouseX, int mouseY) { if (logoPath != null) { RenderSystem.enableBlend(); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); @@ -186,10 +169,8 @@ public class ModListScreen extends Screen relativeY += headerHeight + PADDING; } - for (FormattedCharSequence line : lines) - { - if (line != null) - { + for (FormattedCharSequence line : lines) { + if (line != null) { RenderSystem.enableBlend(); guiGraphics.drawString(ModListScreen.this.font, line, left + PADDING, relativeY, 0xFFFFFF); RenderSystem.disableBlend(); @@ -198,9 +179,8 @@ public class ModListScreen extends Screen } final Style component = findTextLine(mouseX, mouseY); - if (component!=null) { + if (component!=null) guiGraphics.renderComponentHoverEffect(ModListScreen.this.font, component, mouseX, mouseY); - } } private Style findTextLine(final int mouseX, final int mouseY) { @@ -208,9 +188,8 @@ public class ModListScreen extends Screen return null; double offset = (mouseY - top) + border + scrollDistance + 1; - if (logoPath != null) { + if (logoPath != null) offset -= 50; - } if (offset <= 0) return null; @@ -220,9 +199,7 @@ public class ModListScreen extends Screen FormattedCharSequence line = lines.get(lineIdx-1); if (line != null) - { return font.getSplitter().componentStyleAtWidth(line, mouseX - left - border); - } return null; } @@ -247,10 +224,8 @@ public class ModListScreen extends Screen } @Override - public void init() - { - for (IModInfo mod : mods) - { + public void init() { + for (IModInfo mod : mods) { listWidth = Math.max(listWidth,getFontRenderer().width(mod.getDisplayName()) + 10); listWidth = Math.max(listWidth,getFontRenderer().width(MavenVersionStringHelper.artifactVersionToString(mod.getVersion())) + 5); } @@ -295,37 +270,31 @@ public class ModListScreen extends Screen updateCache(); } - private void displayModConfig() - { - if (selected == null) return; - try - { + private void displayModConfig() { + if (selected == null) + return; + + try { ConfigScreenHandler.getScreenFactoryFor(selected.getInfo()).map(f->f.apply(this.minecraft, this)).ifPresent(newScreen -> this.minecraft.setScreen(newScreen)); - } - catch (final Exception e) - { + } catch (final Exception e) { LOGGER.error("There was a critical issue trying to build the config GUI for {}", selected.getInfo().getModId(), e); } } @Override - public void tick() - { + public void tick() { modList.setSelected(selected); - if (!search.getValue().equals(lastFilterText)) - { + if (!search.getValue().equals(lastFilterText)) { reloadMods(); sorted = false; } - if (!sorted) - { + if (!sorted) { reloadMods(); mods.sort(sortType); modList.refreshList(); - if (selected != null) - { + if (selected != null) { selected = modList.children().stream().filter(e -> e.getInfo() == selected.getInfo()).findFirst().orElse(null); updateCache(); } @@ -333,33 +302,33 @@ public class ModListScreen extends Screen } } - public > void buildModList(Consumer modListViewConsumer, Function newEntry) - { + public > void buildModList(Consumer modListViewConsumer, Function newEntry) { mods.forEach(mod->modListViewConsumer.accept(newEntry.apply(mod))); } - private void reloadMods() - { - this.mods = this.unsortedMods.stream(). - filter(mi->StringUtils.toLowerCase(stripControlCodes(mi.getDisplayName())).contains(StringUtils.toLowerCase(search.getValue()))).collect(Collectors.toList()); + private void reloadMods() { + this.mods = this.unsortedMods + .stream() + .filter(mi -> + StringUtils.toLowerCase(stripControlCodes(mi.getDisplayName())) + .contains(StringUtils.toLowerCase(search.getValue())) + ).collect(Collectors.toList()); lastFilterText = search.getValue(); } - private void resortMods(SortType newSort) - { + private void resortMods(SortType newSort) { this.sortType = newSort; - for (SortType sort : SortType.values()) - { + for (SortType sort : SortType.values()) { if (sort.button != null) sort.button.active = sortType != sort; } + sorted = false; } @Override - public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) - { + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { this.modList.render(guiGraphics, mouseX, mouseY, partialTick); if (this.modInfo != null) this.modInfo.render(guiGraphics, mouseX, mouseY, partialTick); @@ -371,52 +340,46 @@ public class ModListScreen extends Screen guiGraphics.drawString(getFontRenderer(), text.getVisualOrderText(), x, search.getY() - getFontRenderer().lineHeight, 0xFFFFFF, false); } - public Minecraft getMinecraftInstance() - { + public Minecraft getMinecraftInstance() { return minecraft; } - public Font getFontRenderer() - { + public Font getFontRenderer() { return font; } - public void setSelected(ModListWidget.ModEntry entry) - { + public void setSelected(ModListWidget.ModEntry entry) { this.selected = entry == this.selected ? null : entry; updateCache(); } - private void updateCache() - { + private void updateCache() { if (selected == null) { this.configButton.active = false; this.modInfo.clearInfo(); return; } + IModInfo selectedMod = selected.getInfo(); this.configButton.active = ConfigScreenHandler.getScreenFactoryFor(selectedMod).isPresent(); List lines = new ArrayList<>(); VersionChecker.CheckResult vercheck = VersionChecker.getResult(selectedMod); @SuppressWarnings("resource") - Pair logoData = selectedMod.getLogoFile().map(logoFile-> - { + Pair logoData = selectedMod.getLogoFile().map(logoFile -> { TextureManager tm = this.minecraft.getTextureManager(); - final PathPackResources resourcePack = ResourcePackLoader.getPackFor(selectedMod.getModId()) - .orElse(ResourcePackLoader.getPackFor("forge"). - orElseThrow(()->new RuntimeException("Can't find forge, WHAT!"))); - try - { + + try { NativeImage logo = null; - IoSupplier logoResource = resourcePack.getRootResource(logoFile); - if (logoResource != null) - logo = NativeImage.read(logoResource.get()); - if (logo != null) - { + var modfile = ModList.get().getModFileById(selectedMod.getModId()); + if (modfile != null) { + var path = modfile.getFile().findResource(logoFile); + if (Files.exists(path)) + logo = NativeImage.read(Files.newInputStream(path)); + } + if (logo != null) { return Pair.of(tm.register("modlogo", new DynamicTexture(logo) { - @Override public void upload() { this.bind(); @@ -426,8 +389,8 @@ public class ModListScreen extends Screen } }), new Size2i(logo.getWidth(), logo.getHeight())); } - } - catch (IOException e) { } + } catch (IOException e) { } + return Pair.of(null, new Size2i(0, 0)); }).orElse(Pair.of(null, new Size2i(0, 0))); @@ -463,12 +426,10 @@ public class ModListScreen extends Screen } */ - if ((vercheck.status() == VersionChecker.Status.OUTDATED || vercheck.status() == VersionChecker.Status.BETA_OUTDATED) && vercheck.changes().size() > 0) - { + if ((vercheck.status() == VersionChecker.Status.OUTDATED || vercheck.status() == VersionChecker.Status.BETA_OUTDATED) && vercheck.changes().size() > 0) { lines.add(null); lines.add(ForgeI18n.parseMessage("fml.menu.mods.info.changelogheader")); - for (Entry entry : vercheck.changes().entrySet()) - { + for (Entry entry : vercheck.changes().entrySet()) { lines.add(" " + entry.getKey() + ":"); lines.add(entry.getValue()); lines.add(null); @@ -479,24 +440,25 @@ public class ModListScreen extends Screen } @Override - public void resize(Minecraft mc, int width, int height) - { + public void resize(Minecraft mc, int width, int height) { String s = this.search.getValue(); SortType sort = this.sortType; ModListWidget.ModEntry selected = this.selected; this.init(mc, width, height); this.search.setValue(s); this.selected = selected; + if (!this.search.getValue().isEmpty()) reloadMods(); + if (sort != SortType.NORMAL) resortMods(sort); + updateCache(); } @Override - public void onClose() - { + public void onClose() { this.minecraft.setScreen(this.parentScreen); } } diff --git a/src/main/java/net/minecraftforge/client/loading/ClientModLoader.java b/src/main/java/net/minecraftforge/client/loading/ClientModLoader.java index a9b81cbe5a..c02abc7701 100644 --- a/src/main/java/net/minecraftforge/client/loading/ClientModLoader.java +++ b/src/main/java/net/minecraftforge/client/loading/ClientModLoader.java @@ -53,16 +53,14 @@ import net.minecraftforge.server.LanguageHook; import net.minecraftforge.forgespi.language.IModInfo; @OnlyIn(Dist.CLIENT) -public class ClientModLoader -{ +public class ClientModLoader { private static final Logger LOGGER = LogManager.getLogger(); private static boolean loading; private static Minecraft mc; private static boolean loadingComplete; private static LoadingFailedException error; - public static void begin(final Minecraft minecraft, final PackRepository defaultResourcePacks, final ReloadableResourceManager mcResourceManager) - { + public static void begin(final Minecraft minecraft, final PackRepository defaultResourcePacks, final ReloadableResourceManager mcResourceManager) { // force log4j to shutdown logging in a shutdown hook. This is because we disable default shutdown hook so the server properly logs it's shutdown Runtime.getRuntime().addShutdownHook(new Thread(LogManager::shutdown)); ImmediateWindowHandler.updateProgress("Loading mods"); @@ -72,7 +70,7 @@ public class ClientModLoader LanguageHook.loadForgeAndMCLangs(); createRunnableWithCatch(()->ModLoader.get().gatherAndInitializeMods(ModWorkManager.syncExecutor(), ModWorkManager.parallelExecutor(), ImmediateWindowHandler::renderTick)).run(); if (error == null) { - ResourcePackLoader.loadResourcePacks(defaultResourcePacks, ClientModLoader::buildPackFinder); + ResourcePackLoader.loadResourcePacks(defaultResourcePacks, true); ModLoader.get().postEvent(new AddPackFindersEvent(PackType.CLIENT_RESOURCES, defaultResourcePacks::addPackFinder)); DataPackConfig.DEFAULT.addModPacks(ResourcePackLoader.getPackNames()); mcResourceManager.registerReloadListener(ClientModLoader::onResourceReload); @@ -101,8 +99,7 @@ public class ClientModLoader createRunnableWithCatch(() -> ModLoader.get().loadMods(syncExecutor, parallelExecutor, ImmediateWindowHandler::renderTick)).run(); } - private static void finishModLoading(ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor) - { + private static void finishModLoading(ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor) { createRunnableWithCatch(() -> ModLoader.get().finishMods(syncExecutor, parallelExecutor, ImmediateWindowHandler::renderTick)).run(); loading = false; loadingComplete = true; @@ -110,8 +107,7 @@ public class ClientModLoader syncExecutor.execute(()->mc.options.load(true)); } - public static VersionChecker.Status checkForUpdates() - { + public static VersionChecker.Status checkForUpdates() { boolean anyOutdated = ModList.get().getMods().stream() .map(VersionChecker::getResult) .map(result -> result.status()) @@ -119,8 +115,7 @@ public class ClientModLoader return anyOutdated ? VersionChecker.Status.OUTDATED : null; } - public static boolean completeModLoading() - { + public static boolean completeModLoading() { var warnings = ModLoader.get().getWarnings(); boolean showWarnings = true; try { @@ -128,6 +123,7 @@ public class ClientModLoader } catch (NullPointerException | IllegalStateException e) { // We're in an early error state, config is not available. Assume true. } + if (!showWarnings) { //User disabled warning screen, as least log them if (!warnings.isEmpty()) { @@ -136,6 +132,7 @@ public class ClientModLoader } warnings = Collections.emptyList(); //Clear warnings, as the user does not want to see them } + File dumpedLocation = null; if (error == null) { // We can finally start the forge eventbus up @@ -145,81 +142,16 @@ public class ClientModLoader LanguageHook.loadForgeAndMCLangs(); dumpedLocation = CrashReportExtender.dumpModLoadingCrashReport(LOGGER, error, mc.gameDirectory); } + if (error != null || !warnings.isEmpty()) { mc.setScreen(new LoadingErrorScreen(error, warnings, dumpedLocation)); return true; - } else { - return false; } + + return false; } - public static boolean isLoading() - { + public static boolean isLoading() { return loading; } - - private static RepositorySource buildPackFinder(Map modResourcePacks) { - return packAcceptor -> clientPackFinder(modResourcePacks, packAcceptor); - } - - private static void clientPackFinder(Map modResourcePacks, Consumer packAcceptor) { - var hiddenPacks = new ArrayList(); - for (Entry e : modResourcePacks.entrySet()) - { - - var supplier = new Pack.ResourcesSupplier() { - @Override - public PackResources openPrimary(String path) { - return e.getValue(); - } - - @Override - public PackResources openFull(String path, Info info) { - return e.getValue(); // TODO: composite - } - - }; - - IModInfo mod = e.getKey().getModInfos().get(0); - final String name = "mod:" + mod.getModId(); - final Pack modPack = Pack.readMetaAndCreate(name, Component.literal(e.getValue().packId()), false, supplier, PackType.CLIENT_RESOURCES, Pack.Position.BOTTOM, PackSource.DEFAULT); - if (modPack == 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())); - continue; - } - LOGGER.debug(Logging.CORE, "Generating PackInfo named {} for mod file {}", name, e.getKey().getFilePath()); - if (mod.getOwningFile().showAsResourcePack()) { - packAcceptor.accept(modPack); - } else { - hiddenPacks.add(e.getValue()); - } - } - var delegating = new DelegatingPackResources("mod_resources", false, - new PackMetadataSection( - Component.translatable("fml.resources.modresources", hiddenPacks.size()), - SharedConstants.getCurrentVersion().getPackVersion(PackType.CLIENT_RESOURCES), - Optional.empty() - ), - hiddenPacks - ); - - var supplier = new Pack.ResourcesSupplier() { - @Override - public PackResources openPrimary(String path) { - return delegating; - } - - @Override - public PackResources openFull(String path, Info info) { - return delegating; // TODO: composite - } - - }; - - // Create a resource pack merging all mod resources that should be hidden - final Pack modResourcesPack = Pack.readMetaAndCreate("mod_resources", Component.literal("Mod Resources"), true, supplier, - PackType.CLIENT_RESOURCES, Pack.Position.BOTTOM, PackSource.DEFAULT); - packAcceptor.accept(modResourcesPack); - } } diff --git a/src/main/java/net/minecraftforge/resource/DelegatingPackResources.java b/src/main/java/net/minecraftforge/resource/DelegatingPackResources.java index 9e2a771ce3..3500b6dd9e 100644 --- a/src/main/java/net/minecraftforge/resource/DelegatingPackResources.java +++ b/src/main/java/net/minecraftforge/resource/DelegatingPackResources.java @@ -22,18 +22,21 @@ import net.minecraft.server.packs.PackResources; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.metadata.MetadataSectionSerializer; import net.minecraft.server.packs.metadata.pack.PackMetadataSection; +import net.minecraft.server.packs.repository.Pack; +import net.minecraft.server.packs.repository.Pack.Info; import net.minecraft.server.packs.resources.IoSupplier; + +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -public class DelegatingPackResources extends AbstractPackResources -{ +@ApiStatus.Internal +public class DelegatingPackResources extends AbstractPackResources { private final PackMetadataSection packMeta; private final List delegates; private final Map> namespacesAssets; private final Map> namespacesData; - public DelegatingPackResources(String packId, boolean isBuiltin, PackMetadataSection packMeta, List packs) - { + public DelegatingPackResources(String packId, boolean isBuiltin, PackMetadataSection packMeta, List packs) { super(packId, isBuiltin); this.packMeta = packMeta; this.delegates = ImmutableList.copyOf(packs); @@ -41,15 +44,11 @@ public class DelegatingPackResources extends AbstractPackResources this.namespacesData = this.buildNamespaceMap(PackType.SERVER_DATA, delegates); } - private Map> buildNamespaceMap(PackType type, List packList) - { + private Map> buildNamespaceMap(PackType type, List packList) { Map> map = new HashMap<>(); - for (PackResources pack : packList) - { + for (PackResources pack : packList) { for (String namespace : pack.getNamespaces(type)) - { map.computeIfAbsent(namespace, k -> new ArrayList<>()).add(pack); - } } map.replaceAll((k, list) -> ImmutableList.copyOf(list)); return ImmutableMap.copyOf(map); @@ -58,49 +57,38 @@ public class DelegatingPackResources extends AbstractPackResources @SuppressWarnings("unchecked") @Nullable @Override - public T getMetadataSection(MetadataSectionSerializer deserializer) throws IOException - { + public T getMetadataSection(MetadataSectionSerializer deserializer) throws IOException { return deserializer.getMetadataSectionName().equals("pack") ? (T) this.packMeta : null; } @Override - public void listResources(PackType type, String resourceNamespace, String paths, ResourceOutput resourceOutput) - { + public void listResources(PackType type, String resourceNamespace, String paths, ResourceOutput resourceOutput) { for (PackResources delegate : this.delegates) - { delegate.listResources(type, resourceNamespace, paths, resourceOutput); - } } @Override - public Set getNamespaces(PackType type) - { + public Set getNamespaces(PackType type) { return type == PackType.CLIENT_RESOURCES ? namespacesAssets.keySet() : namespacesData.keySet(); } @Override - public void close() - { + public void close() { for (PackResources pack : delegates) - { pack.close(); - } } @Nullable @Override - public IoSupplier getRootResource(String... paths) - { + public IoSupplier getRootResource(String... paths) { // Root resources do not make sense here return null; } @Nullable @Override - public IoSupplier getResource(PackType type, ResourceLocation location) - { - for (PackResources pack : getCandidatePacks(type, location)) - { + public IoSupplier getResource(PackType type, ResourceLocation location) { + for (PackResources pack : getCandidatePacks(type, location)) { IoSupplier ioSupplier = pack.getResource(type, location); if (ioSupplier != null) return ioSupplier; @@ -110,15 +98,29 @@ public class DelegatingPackResources extends AbstractPackResources } @Nullable - public Collection getChildren() - { + public Collection getChildren() { return delegates; } - private List getCandidatePacks(PackType type, ResourceLocation location) - { + private List getCandidatePacks(PackType type, ResourceLocation location) { Map> map = type == PackType.CLIENT_RESOURCES ? namespacesAssets : namespacesData; List packsWithNamespace = map.get(location.getNamespace()); return packsWithNamespace == null ? Collections.emptyList() : packsWithNamespace; } + + public Pack.ResourcesSupplier supplier() { + return new Supplier(); + } + + private class Supplier implements Pack.ResourcesSupplier { + @Override + public PackResources openPrimary(String path) { + return DelegatingPackResources.this; + } + + @Override + public PackResources openFull(String path, Info info) { + return DelegatingPackResources.this; + } + } } diff --git a/src/main/java/net/minecraftforge/resource/PathPackResources.java b/src/main/java/net/minecraftforge/resource/PathPackResources.java index 8909661ab0..4d6c92658d 100644 --- a/src/main/java/net/minecraftforge/resource/PathPackResources.java +++ b/src/main/java/net/minecraftforge/resource/PathPackResources.java @@ -5,14 +5,12 @@ package net.minecraftforge.resource; -import com.google.common.base.Joiner; import com.mojang.logging.LogUtils; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; -import java.util.List; import java.util.Locale; import java.util.Set; import java.util.stream.Collectors; @@ -31,10 +29,9 @@ import org.slf4j.Logger; *

* This is primarily intended to support including optional resource packs inside a mod, * such as to have alternative textures to use along with Programmer Art, or optional - * alternative recipes for compatibility ot to replace vanilla recipes. + * alternative recipes for compatibility to to replace vanilla recipes. */ -public class PathPackResources extends AbstractPackResources -{ +public class PathPackResources extends AbstractPackResources { private static final Logger LOGGER = LogUtils.getLogger(); private final Path source; @@ -46,8 +43,7 @@ public class PathPackResources extends AbstractPackResources * @param isBuiltin whether this pack resources should be considered builtin * @param source the root path of the pack. This needs to point to the folder that contains "assets" and/or "data", not the asset folder itself! */ - public PathPackResources(String packId, boolean isBuiltin, final Path source) - { + public PathPackResources(String packId, boolean isBuiltin, final Path source) { super(packId, isBuiltin); this.source = source; } @@ -58,8 +54,7 @@ public class PathPackResources extends AbstractPackResources * * @return the root path of the resources. */ - public Path getSource() - { + public Path getSource() { return this.source; } @@ -69,8 +64,7 @@ public class PathPackResources extends AbstractPackResources * @param paths One or more path strings to resolve. Can include slash-separated paths. * @return the resulting path, which may not exist. */ - protected Path resolve(String... paths) - { + protected Path resolve(String... paths) { Path path = getSource(); for (String name : paths) path = path.resolve(name); @@ -79,8 +73,7 @@ public class PathPackResources extends AbstractPackResources @Nullable @Override - public IoSupplier getRootResource(String... paths) - { + public IoSupplier getRootResource(String... paths) { final Path path = resolve(paths); if (!Files.exists(path)) return null; @@ -89,27 +82,22 @@ public class PathPackResources extends AbstractPackResources } @Override - public void listResources(PackType type, String namespace, String path, ResourceOutput resourceOutput) - { + public void listResources(PackType type, String namespace, String path, ResourceOutput resourceOutput) { FileUtil.decomposePath(path).get() .ifLeft(parts -> net.minecraft.server.packs.PathPackResources.listPath(namespace, resolve(type.getDirectory(), namespace).toAbsolutePath(), parts, resourceOutput)) .ifRight(dataResult -> LOGGER.error("Invalid path {}: {}", path, dataResult.message())); } @Override - public Set getNamespaces(PackType type) - { + public Set getNamespaces(PackType type) { return getNamespacesFromDisk(type); } @NotNull - private Set getNamespacesFromDisk(final PackType type) - { - try - { + private Set getNamespacesFromDisk(final PackType type) { + try { Path root = resolve(type.getDirectory()); - try (Stream walker = Files.walk(root, 1)) - { + try (Stream walker = Files.walk(root, 1)) { return walker .filter(Files::isDirectory) .map(root::relativize) @@ -118,28 +106,20 @@ public class PathPackResources extends AbstractPackResources .filter(s -> !s.isEmpty()) // Filter empty strings, otherwise empty strings default to minecraft namespace in ResourceLocations .collect(Collectors.toSet()); } - } - catch (IOException e) - { + } catch (IOException e) { if (type == PackType.SERVER_DATA) // We still have to add the resource namespace if client resources exist, as we load langs (which are in assets) on server - { return this.getNamespaces(PackType.CLIENT_RESOURCES); - } else - { return Collections.emptySet(); - } } } @Override - public IoSupplier getResource(PackType type, ResourceLocation location) - { + public IoSupplier getResource(PackType type, ResourceLocation location) { return this.getRootResource(getPathFromLocation(location.getPath().startsWith("lang/") ? PackType.CLIENT_RESOURCES : type, location)); } - private static String[] getPathFromLocation(PackType type, ResourceLocation location) - { + private static String[] getPathFromLocation(PackType type, ResourceLocation location) { String[] parts = location.getPath().split("/"); String[] result = new String[parts.length + 2]; result[0] = type.getDirectory(); @@ -149,13 +129,10 @@ public class PathPackResources extends AbstractPackResources } @Override - public void close() - { - } + public void close() { } @Override - public String toString() - { + public String toString() { return String.format(Locale.ROOT, "%s: %s (%s)", getClass().getName(), this.packId(), getSource()); } } diff --git a/src/main/java/net/minecraftforge/resource/ResourcePackLoader.java b/src/main/java/net/minecraftforge/resource/ResourcePackLoader.java index 128b75fdb4..c97822701a 100644 --- a/src/main/java/net/minecraftforge/resource/ResourcePackLoader.java +++ b/src/main/java/net/minecraftforge/resource/ResourcePackLoader.java @@ -8,62 +8,97 @@ package net.minecraftforge.resource; import java.nio.file.Path; import java.util.ArrayList; import java.util.Comparator; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Optional; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Function; +import java.util.function.Consumer; import java.util.stream.Collectors; -import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import net.minecraft.server.packs.repository.RepositorySource; +import net.minecraft.server.packs.repository.Pack.Info; +import net.minecraft.SharedConstants; +import net.minecraft.network.chat.Component; +import net.minecraft.server.packs.CompositePackResources; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.PackType; +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 net.minecraftforge.forgespi.language.IModFileInfo; import net.minecraftforge.forgespi.locating.IModFile; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +@ApiStatus.Internal public class ResourcePackLoader { - private static Map modResourcePacks; + private static final Logger LOGGER = LogManager.getLogger(); - public static Optional getPackFor(String modId) { - return Optional.ofNullable(ModList.get().getModFileById(modId)). - map(IModFileInfo::getFile).map(mf->modResourcePacks.get(mf)); - } - - @Deprecated - public static void loadResourcePacks(PackRepository resourcePacks, BiFunction, BiConsumer, ? extends RepositorySource> packFinder) { - loadResourcePacks(resourcePacks, (map) -> packFinder.apply(map, (rp,p) -> {})); - } - - public static void loadResourcePacks(PackRepository resourcePacks, Function, ? extends RepositorySource> packFinder) { - modResourcePacks = ModList.get().getModFiles().stream() - .filter(mf->mf.requiredLanguageLoaders().stream().noneMatch(ls->ls.languageName().equals("minecraft"))) - .map(mf -> Pair.of(mf, createPackForMod(mf))) - .collect(Collectors.toMap(p -> p.getFirst().getFile(), Pair::getSecond, (u,v) -> { throw new IllegalStateException(String.format(Locale.ENGLISH, "Duplicate key %s", u)); }, LinkedHashMap::new)); - resourcePacks.addPackFinder(packFinder.apply(modResourcePacks)); + public static void loadResourcePacks(PackRepository resourcePacks, boolean client) { + resourcePacks.addPackFinder(repo -> findPacks(repo, client)); } @NotNull - public static PathPackResources createPackForMod(IModFileInfo mf) - { - return new PathPackResources(mf.getFile().getFileName(), true, mf.getFile().getFilePath()) - { - private final IModFile modFile = mf.getFile(); + public static PathPackResources createPackForMod(IModFileInfo mf) { + return new ModPathPackResources(mf.getFile()); + } - @NotNull - @Override - protected Path resolve(@NotNull String... paths) - { - return this.modFile.findResource(paths); + private static class ModPathPackResources extends PathPackResources { + private final IModFile mod; + private final String[] prefix; + + private ModPathPackResources(IModFile mod, String... prefix) { + super(mod.getFileName(), true, mod.getFilePath()); + this.mod = mod; + this.prefix = prefix; + } + + @NotNull + @Override + protected Path resolve(@NotNull String... paths) { + if (prefix != null && prefix.length > 0) { + var tmp = new String[prefix.length + paths.length]; + System.arraycopy(prefix, 0, tmp, 0, prefix.length); + System.arraycopy(paths, 0, tmp, prefix.length, paths.length); + return this.mod.findResource(tmp); } - }; + return this.mod.findResource(paths); + } + + private static class Supplier implements Pack.ResourcesSupplier { + private final IModFile mod; + + private Supplier(IModFile mod) { + this.mod = mod; + } + + @Override + public PackResources openPrimary(String packId) { + return new ModPathPackResources(mod); + } + + @Override + public PackResources openFull(String packId, Info info) { + var primary = openPrimary(packId); + if (info.overlays().isEmpty()) + return primary; + + var lst = new ArrayList(info.overlays().size()); + for (var overlay : info.overlays()) + lst.add(new ModPathPackResources(mod, overlay)); + + return new CompositePackResources(primary, lst); + } + } } public static List getPackNames() { @@ -99,4 +134,55 @@ public class ResourcePackLoader { }; } + private static void findPacks(Consumer packAcceptor, boolean client) { + var type = client ? PackType.CLIENT_RESOURCES : PackType.SERVER_DATA; + var version = SharedConstants.getCurrentVersion().getPackVersion(type); + var hiddenPacks = new ArrayList(); + + for (var mod : ModList.get().getModFiles()) { + if (mod.requiredLanguageLoaders().stream().anyMatch(ls -> ls.languageName().equals("minecraft"))) + continue; + + var file = mod.getFile(); + + var supplier = new ModPathPackResources.Supplier(file); + + var modinfo = file.getModInfos().get(0); + var name = "mod:" + modinfo.getModId(); + var meta = Pack.readPackInfo(name, supplier, version); + Pack pack = null; + if (meta != null) + pack = Pack.create(name, Component.literal(file.getFileName()), false, supplier, meta, Pack.Position.BOTTOM, false, PackSource.DEFAULT); + + 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()) { + @SuppressWarnings("resource") + var delegating = new DelegatingPackResources("mod_resources", false, + new PackMetadataSection( + Component.translatable("fml.resources.modresources", hiddenPacks.size()), + version, + Optional.empty() + ), + hiddenPacks + ); + + var supplier = delegating.supplier(); + + // Create a resource pack merging all mod resources that should be hidden + var modResourcesPack = Pack.readMetaAndCreate("mod_resources", Component.literal("Mod Resources"), true, supplier, type, Pack.Position.BOTTOM, PackSource.DEFAULT); + packAcceptor.accept(modResourcesPack); + } + } } diff --git a/src/main/java/net/minecraftforge/server/ServerLifecycleHooks.java b/src/main/java/net/minecraftforge/server/ServerLifecycleHooks.java index ae793a88bf..174f858c99 100644 --- a/src/main/java/net/minecraftforge/server/ServerLifecycleHooks.java +++ b/src/main/java/net/minecraftforge/server/ServerLifecycleHooks.java @@ -9,13 +9,8 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; -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.Consumer; - import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; @@ -23,37 +18,24 @@ import net.minecraft.gametest.framework.GameTestServer; import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.handshake.ClientIntent; import net.minecraft.network.protocol.handshake.ClientIntentionPacket; import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; -import net.minecraft.server.packs.PackResources; -import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.repository.PackSource; -import net.minecraft.server.packs.repository.RepositorySource; import net.minecraft.world.level.storage.LevelResource; import net.minecraftforge.common.world.StructureModifier; import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.Logging; import net.minecraftforge.common.util.LogicalSidedProvider; import net.minecraftforge.common.world.BiomeModifier; -import net.minecraftforge.fml.ModLoader; -import net.minecraftforge.fml.ModLoadingStage; -import net.minecraftforge.fml.ModLoadingWarning; -import net.minecraftforge.forgespi.locating.IModFile; import net.minecraftforge.network.ConnectionType; import net.minecraftforge.network.NetworkContext; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.registries.ForgeRegistries.Keys; -import net.minecraftforge.resource.PathPackResources; import net.minecraftforge.server.permission.PermissionAPI; 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.server.packs.repository.Pack; -import net.minecraft.server.packs.repository.Pack.Info; import net.minecraft.server.MinecraftServer; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; @@ -64,7 +46,6 @@ import net.minecraftforge.event.server.ServerStartedEvent; import net.minecraftforge.event.server.ServerStartingEvent; import net.minecraftforge.event.server.ServerStoppedEvent; import net.minecraftforge.event.server.ServerStoppingEvent; -import net.minecraftforge.forgespi.language.IModInfo; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.GameData; import org.jetbrains.annotations.ApiStatus; @@ -134,41 +115,6 @@ public class ServerLifecycleHooks { return currentServer; } - @ApiStatus.Internal - public static RepositorySource buildPackFinder(Map modResourcePacks) { - return packAcceptor -> serverPackFinder(modResourcePacks, packAcceptor); - } - - private static void serverPackFinder(Map modResourcePacks, Consumer packAcceptor) { - 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(); - - var supplier = new Pack.ResourcesSupplier() { - @Override - public PackResources openPrimary(String path) { - return e.getValue(); - } - - @Override - public PackResources openFull(String path, Info info) { - return e.getValue(); // TODO: composite - } - - }; - - final Pack modPack = Pack.readMetaAndCreate(name, Component.literal(e.getValue().packId()), false, supplier, PackType.SERVER_DATA, Pack.Position.BOTTOM, PackSource.DEFAULT); - if (modPack == 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())); - continue; - } - LOGGER.debug(Logging.CORE, "Generating PackInfo named {} for mod file {}", name, e.getKey().getFilePath()); - packAcceptor.accept(modPack); - } - } - private static void runModifiers(final MinecraftServer server) { final RegistryAccess registries = server.registryAccess();