Skip to content

Commit

Permalink
Allow mods to not provide pack information (neoforged#400)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matyrobbrt authored Dec 18, 2023
1 parent ee686bb commit ae90c8a
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 18 deletions.
113 changes: 95 additions & 18 deletions src/main/java/net/neoforged/neoforge/resource/ResourcePackLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
package net.neoforged.neoforge.resource;

import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
Expand All @@ -20,14 +23,22 @@
import java.util.stream.Collectors;
import net.minecraft.SharedConstants;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentSerialization;
import net.minecraft.server.packs.FeatureFlagsMetadataSection;
import net.minecraft.server.packs.OverlayMetadataSection;
import net.minecraft.server.packs.PackResources;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.PathPackResources;
import net.minecraft.server.packs.metadata.MetadataSectionType;
import net.minecraft.server.packs.metadata.pack.PackMetadataSection;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.repository.PackCompatibility;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.server.packs.repository.PackSource;
import net.minecraft.server.packs.repository.RepositorySource;
import net.neoforged.fml.Logging;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.InclusiveRange;
import net.minecraft.world.flag.FeatureFlagSet;
import net.neoforged.fml.ModList;
import net.neoforged.fml.ModLoader;
import net.neoforged.fml.ModLoadingStage;
Expand Down Expand Up @@ -76,30 +87,96 @@ private static void packFinder(Map<IModFile, Pack.ResourcesSupplier> modResource
if ("minecraft".equals(mod.getModId())) continue; // skip the minecraft "mod"
final String name = "mod:" + mod.getModId();
final String packName = mod.getOwningFile().getFile().getFileName();
Pack modPack = Pack.readMetaAndCreate(
name,
Component.literal(packName.isEmpty() ? "[unnamed]" : packName),
false,
e.getValue(),
packType,
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

try {
final boolean isRequired = (packType == PackType.CLIENT_RESOURCES && mod.getOwningFile().showAsResourcePack()) || (packType == PackType.SERVER_DATA && mod.getOwningFile().showAsDataPack());
final Pack modPack;
// Packs displayed separately must be valid
if (isRequired) {
modPack = Pack.readMetaAndCreate(
name,
Component.literal(packName.isEmpty() ? "[unnamed]" : packName),
false,
e.getValue(),
packType,
Pack.Position.BOTTOM,
PackSource.DEFAULT);

if (modPack == null) {
ModLoader.get().addWarning(new ModLoadingWarning(mod, ModLoadingStage.ERROR, "fml.modloading.brokenresources", e.getKey()));
continue;
}
} else {
modPack = readWithOptionalMeta(
name,
Component.literal(packName.isEmpty() ? "[unnamed]" : packName),
false,
e.getValue(),
packType,
Pack.Position.BOTTOM,
PackSource.DEFAULT);
}

if (isRequired) {
packAcceptor.accept(modPack);
} else {
hiddenPacks.add(modPack.hidden());
}
} catch (IOException exception) {
LOGGER.error("Failed to read pack.mcmeta file of mod {}", mod.getModId(), exception);
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 ((packType == PackType.CLIENT_RESOURCES && mod.getOwningFile().showAsResourcePack()) || (packType == PackType.SERVER_DATA && mod.getOwningFile().showAsDataPack())) {
packAcceptor.accept(modPack);
} else {
hiddenPacks.add(modPack.hidden());
}
}

packAcceptor.accept(makePack(packType, hiddenPacks));
}

public static final MetadataSectionType<PackMetadataSection> OPTIONAL_FORMAT = MetadataSectionType.fromCodec("pack", RecordCodecBuilder.create(
in -> in.group(
ExtraCodecs.strictOptionalField(ComponentSerialization.CODEC, "description", Component.empty()).forGetter(PackMetadataSection::description),
ExtraCodecs.strictOptionalField(Codec.INT, "pack_format", -1).forGetter(PackMetadataSection::packFormat),
ExtraCodecs.strictOptionalField(InclusiveRange.codec(Codec.INT), "supported_formats").forGetter(PackMetadataSection::supportedFormats))
.apply(in, PackMetadataSection::new)));

public static Pack readWithOptionalMeta(
String id,
Component title,
boolean required,
Pack.ResourcesSupplier resources,
PackType type,
Pack.Position position,
PackSource source) throws IOException {
final Pack.Info packInfo = readInfo(type, resources, id, title);
return Pack.create(id, title, required, resources, packInfo, position, false, source);
}

private static Pack.Info readInfo(PackType type, Pack.ResourcesSupplier resources, String id, Component title) throws IOException {
final int currentVersion = SharedConstants.getCurrentVersion().getPackVersion(type);
try (final PackResources primaryResources = resources.openPrimary(id)) {
final PackMetadataSection metadata = primaryResources.getMetadataSection(OPTIONAL_FORMAT);

final FeatureFlagSet flags = Optional.ofNullable(primaryResources.getMetadataSection(FeatureFlagsMetadataSection.TYPE))
.map(FeatureFlagsMetadataSection::flags)
.orElse(FeatureFlagSet.of());

final List<String> overlays = Optional.ofNullable(primaryResources.getMetadataSection(OverlayMetadataSection.TYPE))
.map(section -> section.overlaysForVersion(currentVersion))
.orElse(List.of());

if (metadata == null) {
return new Pack.Info(title, PackCompatibility.COMPATIBLE, flags, overlays, primaryResources.isHidden());
}

final PackCompatibility compatibility;
if (metadata.packFormat() == -1 && metadata.supportedFormats().isEmpty()) {
compatibility = PackCompatibility.COMPATIBLE;
} else {
compatibility = PackCompatibility.forVersion(Pack.getDeclaredPackVersions(id, metadata), currentVersion);
}
return new Pack.Info(metadata.description(), compatibility, flags, overlays, primaryResources.isHidden());
}
}

private static Pack makePack(PackType packType, ArrayList<Pack> hiddenPacks) {
final String id = packType == PackType.CLIENT_RESOURCES ? MOD_RESOURCES_ID : MOD_DATA_ID;
final String name = packType == PackType.CLIENT_RESOURCES ? "Mod Resources" : "Mod Data";
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/META-INF/accesstransformer.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ public net.minecraft.server.packs.FilePackResources$SharedZipFileAccess
public net.minecraft.server.packs.FilePackResources$SharedZipFileAccess <init>(Ljava/io/File;)V # constructor
public net.minecraft.server.packs.repository.BuiltInPackSource fixedResources(Lnet/minecraft/server/packs/PackResources;)Lnet/minecraft/server/packs/repository/Pack$ResourcesSupplier; # fixedResources
public net.minecraft.server.packs.repository.ServerPacksSource createVanillaPackSource()Lnet/minecraft/server/packs/VanillaPackResources; # createVanillaPackSource
public net.minecraft.server.packs.repository.Pack getDeclaredPackVersions(Ljava/lang/String;Lnet/minecraft/server/packs/metadata/pack/PackMetadataSection;)Lnet/minecraft/util/InclusiveRange; # getDeclaredPackVersions
public net.minecraft.server.packs.resources.FallbackResourceManager fallbacks # fallbacks
public net.minecraft.util.ExtraCodecs$EitherCodec
public net.minecraft.util.datafix.fixes.StructuresBecomeConfiguredFix$Conversion
Expand Down

0 comments on commit ae90c8a

Please sign in to comment.