diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/modern_resourcepacks/PathResourcePackMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/modern_resourcepacks/PathResourcePackMixin.java index dd64c22d..bcafbfce 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/modern_resourcepacks/PathResourcePackMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/modern_resourcepacks/PathResourcePackMixin.java @@ -1,10 +1,12 @@ package org.embeddedt.modernfix.mixin.perf.modern_resourcepacks; import com.google.common.base.Joiner; +import com.mojang.datafixers.util.Pair; import net.minecraft.server.packs.PackType; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.fml.loading.moddiscovery.ModFile; import net.minecraftforge.resource.PathResourcePack; +import org.embeddedt.modernfix.ModernFix; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -29,9 +31,11 @@ public abstract class PathResourcePackMixin { @Shadow protected abstract Path resolve(String... paths); + @Shadow @Final private String packName; + @Shadow @Final private Path source; private EnumMap> namespacesByType; - private EnumMap>> rootListingByNamespaceAndType; - private boolean hasGeneratedListings = false; + private EnumMap>>> rootListingByNamespaceAndType; + private boolean hasGeneratedListings; private Set containedPaths; private FileSystem resourcePackFS; @@ -42,50 +46,45 @@ public abstract class PathResourcePackMixin { private void cacheResources(String packName, Path source, CallbackInfo ci) { this.resourcePackFS = source.getFileSystem(); this.namespacesByType = new EnumMap<>(PackType.class); + this.hasGeneratedListings = false; } - private boolean generateResourceCache() { - synchronized (this.namespacesByType) { - if(!this.namespacesByType.containsKey(PackType.CLIENT_RESOURCES) || !this.namespacesByType.containsKey(PackType.SERVER_DATA)) - return false; - } - if(hasGeneratedListings) - return true; - EnumMap>> rootListingByNamespaceAndType = new EnumMap<>(PackType.class); - HashSet containedPaths = new HashSet<>(); - for(PackType type : PackType.values()) { - Set namespaces; - synchronized (this.namespacesByType) { - namespaces = this.namespacesByType.get(type); - } - HashMap> rootListingForNamespaces = new HashMap<>(); - for(String namespace : namespaces) { - try { - Path root = this.resolve(type.getDirectory(), namespace).toAbsolutePath(); - try (Stream stream = Files.walk(root)) { - ArrayList rootListingPaths = new ArrayList<>(); - stream - .map(path -> root.relativize(path.toAbsolutePath())) - .filter(this::isValidCachedResourcePath) - .forEach(path -> { - if(!path.toString().endsWith(".mcmeta")) - rootListingPaths.add(path); - String mergedPath = slashJoiner.join(type.getDirectory(), namespace, path); - containedPaths.add(mergedPath); - }); - rootListingPaths.trimToSize(); - rootListingForNamespaces.put(namespace, rootListingPaths); + private void generateResourceCache() { + synchronized (this) { + if(hasGeneratedListings) + return; + EnumMap>>> rootListingByNamespaceAndType = new EnumMap<>(PackType.class); + HashSet containedPaths = new HashSet<>(); + for(PackType type : PackType.values()) { + Set namespaces = this.getNamespaces(type); + HashMap>> rootListingForNamespaces = new HashMap<>(); + for(String namespace : namespaces) { + try { + Path root = this.resolve(type.getDirectory(), namespace).toAbsolutePath(); + try (Stream stream = Files.walk(root)) { + ArrayList> rootListingPaths = new ArrayList<>(); + stream + .map(path -> root.relativize(path.toAbsolutePath())) + .filter(this::isValidCachedResourcePath) + .forEach(path -> { + if(!path.toString().endsWith(".mcmeta")) + rootListingPaths.add(Pair.of(path, slashJoiner.join(path))); + String mergedPath = slashJoiner.join(type.getDirectory(), namespace, path); + containedPaths.add(mergedPath); + }); + rootListingPaths.trimToSize(); + rootListingForNamespaces.put(namespace, rootListingPaths); + } + } catch(IOException e) { + rootListingForNamespaces.put(namespace, Collections.emptyList()); } - } catch(IOException e) { - rootListingForNamespaces.put(namespace, Collections.emptyList()); } + rootListingByNamespaceAndType.put(type, rootListingForNamespaces); } - rootListingByNamespaceAndType.put(type, rootListingForNamespaces); + this.rootListingByNamespaceAndType = rootListingByNamespaceAndType; + this.containedPaths = containedPaths; + this.hasGeneratedListings = true; } - this.rootListingByNamespaceAndType = rootListingByNamespaceAndType; - this.containedPaths = containedPaths; - this.hasGeneratedListings = true; - return true; } private boolean isValidCachedResourcePath(Path path) { @@ -118,9 +117,7 @@ public abstract class PathResourcePackMixin { @Inject(method = "hasResource(Ljava/lang/String;)Z", at = @At(value = "HEAD"), cancellable = true) private void useCacheForExistence(String path, CallbackInfoReturnable cir) { - if(!this.generateResourceCache()) { - return; - } + this.generateResourceCache(); cir.setReturnValue(this.containedPaths.contains(path)); } @@ -131,18 +128,18 @@ public abstract class PathResourcePackMixin { @Inject(method = "getResources", at = @At("HEAD"), cancellable = true) public void getResources(PackType type, String resourceNamespace, String pathIn, int maxDepth, Predicate filter, CallbackInfoReturnable> cir) { - if(!this.generateResourceCache()) { - return; - } - Path inputPath = this.resourcePackFS.getPath(pathIn); + this.generateResourceCache(); + if(!pathIn.endsWith("/")) + pathIn = pathIn + "/"; + final String testPath = pathIn; Collection cachedListing = this.rootListingByNamespaceAndType.get(type).getOrDefault(resourceNamespace, Collections.emptyList()).stream(). - filter(path -> path.getNameCount() <= maxDepth). // Make sure the depth is within bounds - filter(path -> path.startsWith(inputPath)). // Make sure the target path is inside this one - filter(path -> filter.test(path.getFileName().toString())). // Test the file name against the predicate + filter(path -> path.getFirst().getNameCount() <= maxDepth). // Make sure the depth is within bounds + filter(path -> path.getSecond().startsWith(testPath)). // Make sure the target path is inside this one + filter(path -> filter.test(path.getFirst().getFileName().toString())). // Test the file name against the predicate // Finally we need to form the RL, so use the first name as the domain, and the rest as the path // It is VERY IMPORTANT that we do not rely on Path.toString as this is inconsistent between operating systems // Join the path names ourselves to force forward slashes - map(path -> new ResourceLocation(resourceNamespace, slashJoiner.join(path))). + map(path -> new ResourceLocation(resourceNamespace, path.getSecond())). collect(Collectors.toList()); cir.setReturnValue(cachedListing); }