Skip to content

Commit

Permalink
Violently commit crimes against git with the power of copy-paste
Browse files Browse the repository at this point in the history
Basically a manual rebase/merge onto upstream 1.20.2—actually doing either resulted in things breaking horribly because git moment

Also fixed the quilt.mod.json for the resource_loader package—it still had the old name for the ClientLoaderEventsTestMod test (formerly ClientResourceLoaderEventsTestMod)
  • Loading branch information
cocona20xx committed Feb 3, 2024
1 parent 5da1018 commit 2020994
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceType;
import net.minecraft.resource.pack.PackProvider;
import net.minecraft.resource.pack.ResourcePack;
Expand Down Expand Up @@ -50,6 +51,22 @@ public interface ResourceLoader {
return ResourceLoaderImpl.get(type);
}

/**
* Gets the static resource manager for a given type.
* <p>
* Static resources are different from regular resources in that they
* are available as soon as the manager is requested and are (theoretically) immutable.
* <p>
* It is <i>highly</i> recommended for mods to personally cache data they get from the provided manager in order to
* prevent changes to user-space packs modifying data at runtime.
*
* @param type the type of resources expected from this resource manager
* @return the static resource manager instance
*/
static @NotNull ResourceManager getStaticResourceManager(@NotNull ResourceType type) {
return ResourceLoaderImpl.getStaticResourceManager(type);
}

/**
* Register a resource reloader for a given resource manager type.
*
Expand Down Expand Up @@ -116,7 +133,7 @@ public interface ResourceLoader {
* @see #newFileSystemPack(Identifier, ModContainer, Path, PackActivationType, Text)
*/
default @NotNull ResourcePack newFileSystemPack(@NotNull Identifier id, @NotNull Path rootPath,
PackActivationType activationType) {
PackActivationType activationType) {
return this.newFileSystemPack(id, rootPath, activationType, ResourceLoaderImpl.getBuiltinPackDisplayNameFromId(id));
}

Expand All @@ -137,8 +154,8 @@ public interface ResourceLoader {
default @NotNull ResourcePack newFileSystemPack(@NotNull Identifier id, @NotNull Path rootPath,
PackActivationType activationType, @NotNull Text displayName) {
var container = QuiltLoader.getModContainer(id.getNamespace())
.orElseThrow(() ->
new IllegalArgumentException("No mod with ID '" + id.getNamespace() + "' could be found"));
.orElseThrow(() ->
new IllegalArgumentException("No mod with ID '" + id.getNamespace() + "' could be found"));
return this.newFileSystemPack(id, container, rootPath, activationType, displayName);
}

Expand All @@ -157,7 +174,7 @@ public interface ResourceLoader {
* @see #newFileSystemPack(Identifier, ModContainer, Path, PackActivationType, Text)
*/
default @NotNull ResourcePack newFileSystemPack(@NotNull Identifier id, @NotNull ModContainer owner, @NotNull Path rootPath,
PackActivationType activationType) {
PackActivationType activationType) {
return this.newFileSystemPack(id, owner, rootPath, activationType, ResourceLoaderImpl.getBuiltinPackDisplayNameFromId(id));
}

Expand Down Expand Up @@ -230,8 +247,8 @@ static boolean registerBuiltinPack(@NotNull Identifier id, @NotNull PackActivati
*/
static boolean registerBuiltinPack(@NotNull Identifier id, @NotNull PackActivationType activationType, Text displayName) {
var container = QuiltLoader.getModContainer(id.getNamespace())
.orElseThrow(() ->
new IllegalArgumentException("No mod with mod id " + id.getNamespace() + " could be found"));
.orElseThrow(() ->
new IllegalArgumentException("No mod with mod id " + id.getNamespace() + " could be found"));
return registerBuiltinPack(id, container, activationType, displayName);
}

Expand All @@ -256,7 +273,7 @@ static boolean registerBuiltinPack(@NotNull Identifier id, @NotNull PackActivati
* @see #registerBuiltinPack(Identifier, ModContainer, PackActivationType, Text)
*/
static boolean registerBuiltinPack(@NotNull Identifier id, @NotNull ModContainer container,
@NotNull PackActivationType activationType) {
@NotNull PackActivationType activationType) {
return registerBuiltinPack(id, container, activationType, ResourceLoaderImpl.getBuiltinPackDisplayNameFromId(id));
}

Expand Down Expand Up @@ -284,6 +301,6 @@ static boolean registerBuiltinPack(@NotNull Identifier id, @NotNull ModContainer
static boolean registerBuiltinPack(@NotNull Identifier id, @NotNull ModContainer container,
@NotNull PackActivationType activationType, Text displayName) {
return ResourceLoaderImpl.registerBuiltinPack(id, "resourcepacks/" + id.getPath(), container,
activationType, displayName);
activationType, displayName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.quiltmc.qsl.resource.loader.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
Expand All @@ -35,6 +36,7 @@
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
Expand All @@ -59,6 +61,8 @@
import net.minecraft.util.JsonHelper;
import net.minecraft.util.Language;
import net.minecraft.util.Pair;
import net.minecraft.resource.pack.NioResourcePack;
import net.minecraft.resource.pack.ZipResourcePack;

import org.quiltmc.loader.api.ModContainer;
import org.quiltmc.loader.api.ModMetadata;
Expand All @@ -81,6 +85,12 @@
*/
@ApiStatus.Internal
public final class ResourceLoaderImpl implements ResourceLoader {
private static final String STATIC_PACK_ROOT = "static";
/**
* Contains the names of various filesystem helper files in <i>all lower-case</i>, used to filter said files out of loose file detection.
*/
private static final Set<String> STATIC_USERSPACE_FILESYSTEM_HELPERS = Set.of(".ds_store", "thumbs.db", "desktop.ini", ".desktop");
private static final Map<ResourceType, StaticResourceManager> STATIC_MANAGER_MAP = new EnumMap<>(ResourceType.class);
private static final Map<ResourceType, ResourceLoaderImpl> IMPL_MAP = new EnumMap<>(ResourceType.class);
/**
* Represents a cache of the client mod resource packs so resource packs that can cache don't lose their cache.
Expand All @@ -95,9 +105,9 @@ public final class ResourceLoaderImpl implements ResourceLoader {
private static final Logger LOGGER = LoggerFactory.getLogger("ResourceLoader");

private static final boolean DEBUG_RELOADERS_IDENTITY = TriState.fromProperty("quilt.resource_loader.debug.reloaders_identity")
.toBooleanOrElse(QuiltLoader.isDevelopmentEnvironment());
.toBooleanOrElse(QuiltLoader.isDevelopmentEnvironment());
private static final boolean DEBUG_RELOADERS_ORDER = TriState.fromProperty("quilt.resource_loader.debug.reloaders_order")
.toBooleanOrElse(false);
.toBooleanOrElse(false);

private final ResourceType type;
private final Set<Identifier> addedReloaderIds = new ObjectOpenHashSet<>();
Expand All @@ -124,6 +134,14 @@ public static ResourceLoaderImpl get(ResourceType type) {
return IMPL_MAP.computeIfAbsent(type, ResourceLoaderImpl::new);
}

public static StaticResourceManager getStaticResourceManager(ResourceType type) {
return STATIC_MANAGER_MAP.computeIfAbsent(type, passedType -> {
List<ResourcePack> packs = findUserStaticPacks();
appendModPacks(packs, passedType, STATIC_PACK_ROOT);
return new StaticResourceManager(passedType, packs);
});
}

public static <T> @Nullable T parseMetadata(ResourceMetadataSectionReader<T> metaSectionReader, ResourcePack pack, InputStream inputStream) {
JsonObject json;

Expand Down Expand Up @@ -157,14 +175,14 @@ public static void sort(ResourceType type, List<ResourceReloader> reloaders) {
public void registerReloader(@NotNull IdentifiableResourceReloader resourceReloader) {
if (!this.addedReloaderIds.add(resourceReloader.getQuiltId())) {
throw new IllegalStateException(
"Tried to register resource reloader " + resourceReloader.getQuiltId() + " twice!"
"Tried to register resource reloader " + resourceReloader.getQuiltId() + " twice!"
);
}

if (!this.addedReloaders.add(resourceReloader)) {
throw new IllegalStateException(
"Resource reloader with previously unknown ID " + resourceReloader.getQuiltId()
+ " already in resource reloader set!"
"Resource reloader with previously unknown ID " + resourceReloader.getQuiltId()
+ " already in resource reloader set!"
);
}
}
Expand All @@ -185,7 +203,7 @@ public void addReloaderOrdering(@NotNull Identifier firstReloader, @NotNull Iden
public void registerPackProfileProvider(@NotNull PackProvider provider) {
if (!this.resourcePackProfileProviders.add(provider)) {
throw new IllegalStateException(
"Tried to register a resource pack profile provider twice!"
"Tried to register a resource pack profile provider twice!"
);
}
}
Expand Down Expand Up @@ -259,16 +277,16 @@ private void sort(List<ResourceReloader> reloaders) {
id = identifiable.getQuiltId();
} else {
id = new Identifier("unknown",
"private/"
+ currentReloader.getClass().getName()
.replace(".", "/")
.replace("$", "_")
.toLowerCase(Locale.ROOT)
"private/"
+ currentReloader.getClass().getName()
.replace(".", "/")
.replace("$", "_")
.toLowerCase(Locale.ROOT)
);

if (DEBUG_RELOADERS_IDENTITY) {
LOGGER.warn("The resource reloader at {} does not implement IdentifiableResourceReloader " +
"making ordering support more difficult for other modders.", currentReloader.getClass().getName());
"making ordering support more difficult for other modders.", currentReloader.getClass().getName());
}
}

Expand Down Expand Up @@ -309,7 +327,7 @@ private void sort(List<ResourceReloader> reloaders) {
if (putAfter == afterVanilla) continue;

if (putAfter.vanillaStatus == ResourceReloaderPhaseData.VanillaStatus.NONE
|| putAfter.vanillaStatus == ResourceReloaderPhaseData.VanillaStatus.AFTER) {
|| putAfter.vanillaStatus == ResourceReloaderPhaseData.VanillaStatus.AFTER) {
PhaseData.link(afterVanilla, putAfter);
}
}
Expand Down Expand Up @@ -351,7 +369,7 @@ private void sort(List<ResourceReloader> reloaders) {
*/
public static void appendModPacks(List<ResourcePack> packs, ResourceType type, @Nullable String subPath) {
var modResourcePacks = type == ResourceType.CLIENT_RESOURCES
? CLIENT_MOD_RESOURCE_PACKS : SERVER_MOD_RESOURCE_PACKS;
? CLIENT_MOD_RESOURCE_PACKS : SERVER_MOD_RESOURCE_PACKS;
var existingList = modResourcePacks.get(subPath);
var byMod = new Reference2ObjectOpenHashMap<ModMetadata, ModNioPack>();

Expand Down Expand Up @@ -386,8 +404,8 @@ public static void appendModPacks(List<ResourcePack> packs, ResourceType type, @
}

List<ModNioPack> packList = byMod.values().stream()
.filter(pack -> !pack.getNamespaces(type).isEmpty())
.toList();
.filter(pack -> !pack.getNamespaces(type).isEmpty())
.toList();

// Cache the pack list for the next reload.
modResourcePacks.put(subPath, packList);
Expand Down Expand Up @@ -439,7 +457,7 @@ public static Text getBuiltinPackDisplayNameFromId(Identifier id) {
* @see ResourceLoader#registerBuiltinPack(Identifier, ModContainer, PackActivationType, Text)
*/
public static boolean registerBuiltinPack(Identifier id, String subPath, ModContainer container,
PackActivationType activationType, Text displayName) {
PackActivationType activationType, Text displayName) {
Path resourcePackPath = container.getPath(subPath).toAbsolutePath().normalize();

if (!Files.exists(resourcePackPath)) {
Expand All @@ -451,12 +469,12 @@ public static boolean registerBuiltinPack(Identifier id, String subPath, ModCont
boolean result = false;
if (MinecraftQuiltLoader.getEnvironmentType() == EnvType.CLIENT) {
result = registerBuiltinPack(ResourceType.CLIENT_RESOURCES,
newBuiltinPack(container, name, displayName, resourcePackPath, ResourceType.CLIENT_RESOURCES, activationType)
newBuiltinPack(container, name, displayName, resourcePackPath, ResourceType.CLIENT_RESOURCES, activationType)
);
}

result |= registerBuiltinPack(ResourceType.SERVER_DATA,
newBuiltinPack(container, name, displayName, resourcePackPath, ResourceType.SERVER_DATA, activationType)
newBuiltinPack(container, name, displayName, resourcePackPath, ResourceType.SERVER_DATA, activationType)
);

return result;
Expand All @@ -465,21 +483,21 @@ public static boolean registerBuiltinPack(Identifier id, String subPath, ModCont
private static boolean registerBuiltinPack(ResourceType type, ModNioPack pack) {
if (QuiltLoader.isDevelopmentEnvironment() || !pack.getNamespaces(type).isEmpty()) {
var builtinResourcePacks = type == ResourceType.CLIENT_RESOURCES
? CLIENT_BUILTIN_RESOURCE_PACKS : SERVER_BUILTIN_RESOURCE_PACKS;
? CLIENT_BUILTIN_RESOURCE_PACKS : SERVER_BUILTIN_RESOURCE_PACKS;
builtinResourcePacks.put(pack.getName(), pack);
return true;
}
return false;
}

private static ModNioPack newBuiltinPack(ModContainer container, String name, Text displayName,
Path resourcePackPath, ResourceType type, PackActivationType activationType) {
Path resourcePackPath, ResourceType type, PackActivationType activationType) {
return new ModNioPack(name, container.metadata(), displayName, activationType, resourcePackPath, type, null);
}

public static void registerBuiltinPacks(ResourceType type, Consumer<PackProfile> profileAdder) {
var builtinPacks = type == ResourceType.CLIENT_RESOURCES
? CLIENT_BUILTIN_RESOURCE_PACKS : SERVER_BUILTIN_RESOURCE_PACKS;
? CLIENT_BUILTIN_RESOURCE_PACKS : SERVER_BUILTIN_RESOURCE_PACKS;

// Loop through each registered built-in resource packs and add them if valid.
for (var entry : builtinPacks.entrySet()) {
Expand All @@ -506,7 +524,7 @@ public static void registerBuiltinPacks(ResourceType type, Consumer<PackProfile>
*/
public static void appendLanguageEntries(@NotNull Map<String, String> map) {
var pack = ResourceLoaderImpl.buildMinecraftPack(ResourceType.CLIENT_RESOURCES,
VanillaDataPackProviderAccessor.invokeDefaultPackBuilder()
VanillaDataPackProviderAccessor.invokeDefaultPackBuilder()
);

try (var manager = new MultiPackResourceManager(ResourceType.CLIENT_RESOURCES, List.of(pack))) {
Expand All @@ -523,4 +541,45 @@ public static void appendLanguageEntries(@NotNull Map<String, String> map) {
}
}
}

/* Static pack stuff */
private static List<ResourcePack> findUserStaticPacks() {
List<ResourcePack> returnList = new ArrayList<>();

try (Stream<Path> walkStream = Files.walk(QuiltLoader.getGameDir().resolve(STATIC_PACK_ROOT), 1)) {
for (Path path : walkStream.toList()) {
File pathAsFile = path.toFile();
String n = calcUserspacePackName(pathAsFile);

if (pathAsFile.isFile()) {
if (pathAsFile.toPath().toString().endsWith(".zip")) {
ZipResourcePack.Factory zipFactory = new ZipResourcePack.Factory(path, false);
returnList.add(zipFactory.openPrimary(n));
} else {
// Implementation detail: ._* and (some) *nix-derivative OSes (macOS, Linux distros, etc.)
// ._* is a rare *nix filesystem helper file created to store file information normally placed in an extended attribute
// on HFS+ (Apple Native, typically found under macOS) or UFS (other *nix OSes) filesystems when interfacing with a filesystem
// that does NOT support such extended attributes (for instance, a FAT32 drive). Since these can have names of arbitrary lengths,
// the only way to detect them is via the shared prefix.
// Source: https://apple.stackexchange.com/a/14981
if (!pathAsFile.getName().startsWith("._") && !STATIC_USERSPACE_FILESYSTEM_HELPERS.contains(pathAsFile.getName().toLowerCase(Locale.ROOT))) {
LOGGER.error("Files outside of packs are not supported by the Quilt Static Resource Manager. Loose file: {}", pathAsFile);
LOGGER.error("If the loose file above is a filesystem helper for the in-use Operating System, please make an issue report on the QSL github: https://github.com/QuiltMC/quilt-standard-libraries/issues");
}
}
} else if (pathAsFile.isDirectory()) {
returnList.add(new NioResourcePack(n, path, false));
}
}
} catch (IOException eio) {
LOGGER.error("IO Exception thrown while loading userspace static packs: {}", eio.toString());
}

return returnList;
}

private static String calcUserspacePackName(File packFile) {
int n = packFile.toPath().getNameCount();
return packFile.toPath().getName(n - 2) + "/" + packFile.toPath().getName(n - 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2023 The Quilt Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.quiltmc.qsl.resource.loader.impl;

import java.util.List;

import org.jetbrains.annotations.ApiStatus;

import net.minecraft.resource.MultiPackResourceManager;
import net.minecraft.resource.ResourceType;
import net.minecraft.resource.pack.ResourcePack;

/**
* Exists primarily for determining whether a manager is involved in static resource loading or regular resource loading,
* and also prevents the MultiPackResourceManager from being closed.
* <p>
* This is used to avoid activating certain mixins when they are not necessary.
*/
@ApiStatus.Internal
public class StaticResourceManager extends MultiPackResourceManager {
public StaticResourceManager(ResourceType type, List<ResourcePack> packs) {
super(type, packs);
}

/**
* Forbids the StaticResourceManager instance from being closed (by throwing a RuntimeException) as a sanity check of sorts.
* <p>
* Ultimately, this method should never be called by consumers of the API,
* as the two StaticResourceManager instances are cast to {@link net.minecraft.resource.ResourceManager} when provided,
* and ResourceManager does <i>not</i> extend {@link AutoCloseable}.
*/
@Override
public void close() {
throw new RuntimeException("StaticResourceManager instances cannot be closed!");
}
}
Loading

0 comments on commit 2020994

Please sign in to comment.