Make DEFAULT_ENABLED work with client resource pack

This commit is contained in:
deirn 2022-07-22 18:33:27 +07:00 committed by modmuss50
parent f60060dfe3
commit e5c0910538
7 changed files with 101 additions and 22 deletions
fabric-resource-loader-v0/src
client/java/net/fabricmc/fabric/mixin/resource/loader/client
main/java/net/fabricmc/fabric
testmod
java/net/fabricmc/fabric/test/resource/loader
resources/resourcepacks/test

View file

@ -16,9 +16,16 @@
package net.fabricmc.fabric.mixin.resource.loader.client;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -26,32 +33,99 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.option.GameOptions;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.NbtString;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourcePackProfile;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.impl.resource.loader.ModNioResourcePack;
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackCreator;
import net.fabricmc.loader.api.FabricLoader;
@Mixin(GameOptions.class)
public class GameOptionsMixin {
@Shadow
public List<String> resourcePacks;
@Shadow
@Final
static Logger LOGGER;
@Inject(method = "load", at = @At("RETURN"))
private void onLoad(CallbackInfo ci) {
// Add built-in resource packs if they are enabled by default only if the options file is blank.
if (this.resourcePacks.isEmpty()) {
List<ResourcePackProfile> profiles = new ArrayList<>();
ModResourcePackCreator.CLIENT_RESOURCE_PACK_PROVIDER.register(profiles::add);
this.resourcePacks = new ArrayList<>();
// Track built-in resource packs if they are enabled by default.
// - If there is NO value with matching resource pack id, add it to the enabled packs and the tracker file.
// - If there is a matching value and pack id, do not add it to the enabled packs and let
// the options value decides if it is enabled or not.
// - If there is a value without matching pack id (e.g. because the mod is removed),
// remove it from the tracker file so that it would be enabled again if added back later.
for (ResourcePackProfile profile : profiles) {
ResourcePack pack = profile.createResourcePack();
if (profile.getSource() == ModResourcePackCreator.RESOURCE_PACK_SOURCE
|| (pack instanceof ModNioResourcePack && ((ModNioResourcePack) pack).getActivationType().isEnabledByDefault())) {
this.resourcePacks.add(profile.getName());
File dataDir = FabricLoader.getInstance().getGameDir().resolve("data").toFile();
if (!dataDir.exists() && !dataDir.mkdirs()) {
LOGGER.warn("[Fabric Resource Loader] Could not create data directory: " + dataDir.getAbsolutePath());
}
File trackerFile = new File(dataDir, "fabricDefaultResourcePacks.dat");
Set<Identifier> trackedPacks = new HashSet<>();
if (trackerFile.exists()) {
try {
NbtCompound data = NbtIo.readCompressed(trackerFile);
NbtList values = data.getList("values", NbtElement.STRING_TYPE);
for (int i = 0; i < values.size(); i++) {
trackedPacks.add(new Identifier(values.getString(i)));
}
} catch (IOException e) {
LOGGER.warn("[Fabric Resource Loader] Could not read " + trackerFile.getAbsolutePath(), e);
}
}
Set<Identifier> removedPacks = new HashSet<>(trackedPacks);
Set<String> resourcePacks = new LinkedHashSet<>(this.resourcePacks);
List<ResourcePackProfile> profiles = new ArrayList<>();
ModResourcePackCreator.CLIENT_RESOURCE_PACK_PROVIDER.register(profiles::add);
for (ResourcePackProfile profile : profiles) {
// Always add "Fabric Mods" pack to enabled resource packs.
if (profile.getSource() == ModResourcePackCreator.RESOURCE_PACK_SOURCE) {
resourcePacks.add(profile.getName());
continue;
}
ResourcePack pack = profile.createResourcePack();
if (pack instanceof ModNioResourcePack builtinPack && builtinPack.getActivationType().isEnabledByDefault()) {
if (trackedPacks.add(builtinPack.getId())) {
resourcePacks.add(profile.getName());
} else {
removedPacks.remove(builtinPack.getId());
}
}
}
try {
NbtList values = new NbtList();
for (Identifier id : trackedPacks) {
if (!removedPacks.contains(id)) {
values.add(NbtString.of(id.toString()));
}
}
NbtCompound nbt = new NbtCompound();
nbt.put("values", values);
NbtIo.writeCompressed(nbt, trackerFile);
} catch (IOException e) {
LOGGER.warn("[Fabric Resource Loader] Could not write to " + trackerFile.getAbsolutePath(), e);
}
this.resourcePacks = new ArrayList<>(resourcePacks);
}
}

View file

@ -26,8 +26,6 @@ public enum ResourcePackActivationType {
NORMAL,
/**
* Enabled by default. The user has still full control over the activation of the resource pack.
*
* <p>Note: this setting can only be satisfied on data packs, client resource packs cannot be by default enabled.
*/
DEFAULT_ENABLED,
/**

View file

@ -56,6 +56,7 @@ public class ModNioResourcePack extends AbstractFileResourcePack implements ModR
private static final Pattern RESOURCE_PACK_PATH = Pattern.compile("[a-z0-9-_.]+");
private static final FileSystem DEFAULT_FS = FileSystems.getDefault();
private final Identifier id;
private final String name;
private final ModMetadata modInfo;
private final List<Path> basePaths;
@ -64,7 +65,7 @@ public class ModNioResourcePack extends AbstractFileResourcePack implements ModR
private final ResourcePackActivationType activationType;
private final Map<ResourceType, Set<String>> namespaces;
public static ModNioResourcePack create(String name, ModContainer mod, String subPath, ResourceType type, ResourcePackActivationType activationType) {
public static ModNioResourcePack create(Identifier id, String name, ModContainer mod, String subPath, ResourceType type, ResourcePackActivationType activationType) {
List<Path> rootPaths = mod.getRootPaths();
List<Path> paths;
@ -87,14 +88,15 @@ public class ModNioResourcePack extends AbstractFileResourcePack implements ModR
if (paths.isEmpty()) return null;
ModNioResourcePack ret = new ModNioResourcePack(name, mod.getMetadata(), paths, type, null, activationType);
ModNioResourcePack ret = new ModNioResourcePack(id, name, mod.getMetadata(), paths, type, null, activationType);
return ret.getNamespaces(type).isEmpty() ? null : ret;
}
private ModNioResourcePack(String name, ModMetadata modInfo, List<Path> paths, ResourceType type, AutoCloseable closer, ResourcePackActivationType activationType) {
private ModNioResourcePack(Identifier id, String name, ModMetadata modInfo, List<Path> paths, ResourceType type, AutoCloseable closer, ResourcePackActivationType activationType) {
super(null);
this.id = id;
this.name = name;
this.modInfo = modInfo;
this.basePaths = paths;
@ -158,8 +160,8 @@ public class ModNioResourcePack extends AbstractFileResourcePack implements ModR
return null;
}
private static final String resPrefix = ResourceType.CLIENT_RESOURCES.getDirectory()+"/";
private static final String dataPrefix = ResourceType.SERVER_DATA.getDirectory()+"/";
private static final String resPrefix = ResourceType.CLIENT_RESOURCES.getDirectory() + "/";
private static final String dataPrefix = ResourceType.SERVER_DATA.getDirectory() + "/";
private boolean hasAbsentNs(String filename) {
int prefixLen;
@ -280,6 +282,10 @@ public class ModNioResourcePack extends AbstractFileResourcePack implements ModR
return name;
}
public Identifier getId() {
return id;
}
private static boolean exists(Path path) {
// NIO Files.exists is notoriously slow when checking the file system
return path.getFileSystem() == DEFAULT_FS ? path.toFile().exists() : Files.exists(path);

View file

@ -32,6 +32,7 @@ import net.minecraft.resource.DataPackSettings;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourcePackProfile;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.resource.ModResourcePack;
import net.fabricmc.fabric.api.resource.ResourcePackActivationType;
@ -61,7 +62,7 @@ public final class ModResourcePackUtil {
continue;
}
ModResourcePack pack = ModNioResourcePack.create(getName(container.getMetadata()), container, null, type, ResourcePackActivationType.ALWAYS_ENABLED);
ModResourcePack pack = ModNioResourcePack.create(new Identifier("fabric", container.getMetadata().getId()), getName(container.getMetadata()), container, null, type, ResourcePackActivationType.ALWAYS_ENABLED);
if (pack != null) {
packs.add(pack);

View file

@ -71,8 +71,8 @@ public class ResourceManagerHelperImpl implements ResourceManagerHelper {
String separator = container.getRootPath().getFileSystem().getSeparator();
subPath = subPath.replace("/", separator);
String name = displayName;
ModNioResourcePack resourcePack = ModNioResourcePack.create(name, container, subPath, ResourceType.CLIENT_RESOURCES, activationType);
ModNioResourcePack dataPack = ModNioResourcePack.create(name, container, subPath, ResourceType.SERVER_DATA, activationType);
ModNioResourcePack resourcePack = ModNioResourcePack.create(id, name, container, subPath, ResourceType.CLIENT_RESOURCES, activationType);
ModNioResourcePack dataPack = ModNioResourcePack.create(id, name, container, subPath, ResourceType.SERVER_DATA, activationType);
if (resourcePack == null && dataPack == null) return false;
if (resourcePack != null) {

View file

@ -42,7 +42,7 @@ public class BuiltinResourcePackTestMod implements ModInitializer {
// Should always be present as it's **this** mod.
FabricLoader.getInstance().getModContainer(MODID)
.map(container -> ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MODID, "test"),
container, "Fabric Resource Loader Test Pack", ResourcePackActivationType.NORMAL))
container, "Fabric Resource Loader Test Pack", ResourcePackActivationType.DEFAULT_ENABLED))
.filter(success -> !success).ifPresent(success -> LOGGER.warn("Could not register built-in resource pack with custom name."));
FabricLoader.getInstance().getModContainer(MODID)
.map(container -> ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MODID, "test2"),

View file

@ -1,6 +1,6 @@
{
"pack": {
"pack_format": 8,
"pack_format": 9,
"description": "Fabric Resource Loader Test Builtin Pack."
}
}