From b55129a8cada0aaee4b1b012078fb0cfdcebe00a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 7 May 2023 18:08:00 -0400 Subject: [PATCH] Generate resource cache using resource reload workers --- .../resources/PackResourcesCacheEngine.java | 73 +++++++++++++------ 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java index 8e2ced85..6c0d2235 100644 --- a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java +++ b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java @@ -1,16 +1,19 @@ package org.embeddedt.modernfix.resources; +import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; +import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.util.PackTypeHelper; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; @@ -26,6 +29,7 @@ public class PackResourcesCacheEngine { private final Map> namespacesByType; private final Set containedPaths; private final EnumMap>> resourceListings; + private CompletableFuture cacheFuture; public PackResourcesCacheEngine(Function> namespacesRetriever, BiFunction basePathRetriever) { this.namespacesByType = new EnumMap<>(PackType.class); @@ -36,32 +40,50 @@ public class PackResourcesCacheEngine { } this.containedPaths = new ObjectOpenHashSet<>(); this.resourceListings = new EnumMap<>(PackType.class); + CompletableFuture future = CompletableFuture.completedFuture(null); + Stopwatch watch = Stopwatch.createStarted(); + // used for log message + Path debugPath = basePathRetriever.apply(PackType.CLIENT_RESOURCES, "minecraft").toAbsolutePath(); for(PackType type : PackType.values()) { Collection namespaces = PackTypeHelper.isVanillaPackType(type) ? this.namespacesByType.get(type) : namespacesRetriever.apply(type); - ImmutableMap.Builder> packTypedMap = ImmutableMap.builder(); - for(String namespace : namespaces) { - try { - ImmutableList.Builder namespacedList = ImmutableList.builder(); - Path root = basePathRetriever.apply(type, namespace).toAbsolutePath(); - String[] prefix = new String[] { type.getDirectory(), namespace }; - try (Stream stream = Files.walk(root)) { - stream - .map(path -> root.relativize(path.toAbsolutePath())) - .filter(PackResourcesCacheEngine::isValidCachedResourcePath) - .forEach(path -> { - CachedResourcePath cachedPath = new CachedResourcePath(prefix, path); - this.containedPaths.add(cachedPath); - if(!cachedPath.getFileName().endsWith(".mcmeta")) - namespacedList.add(cachedPath); - }); + future = future.thenRunAsync(() -> { + ImmutableMap.Builder> packTypedMap = ImmutableMap.builder(); + for(String namespace : namespaces) { + try { + ImmutableList.Builder namespacedList = ImmutableList.builder(); + Path root = basePathRetriever.apply(type, namespace).toAbsolutePath(); + String[] prefix = new String[] { type.getDirectory(), namespace }; + try (Stream stream = Files.walk(root)) { + stream + .map(path -> root.relativize(path.toAbsolutePath())) + .filter(PackResourcesCacheEngine::isValidCachedResourcePath) + .forEach(path -> { + CachedResourcePath cachedPath = new CachedResourcePath(prefix, path); + synchronized (this.containedPaths) { + this.containedPaths.add(cachedPath); + } + if(!cachedPath.getFileName().endsWith(".mcmeta")) + namespacedList.add(cachedPath); + }); + } + packTypedMap.put(namespace, namespacedList.build()); + } catch(IOException ignored) { } - packTypedMap.put(namespace, namespacedList.build()); - } catch(IOException ignored) { } - } - this.resourceListings.put(type, packTypedMap.build()); + synchronized (this.resourceListings) { + this.resourceListings.put(type, packTypedMap.build()); + } + }, ModernFix.resourceReloadExecutor()); } - ((ObjectOpenHashSet)this.containedPaths).trim(); + future = future.thenRunAsync(() -> { + ((ObjectOpenHashSet)this.containedPaths).trim(); + watch.stop(); + }, ModernFix.resourceReloadExecutor()); + this.cacheFuture = future; + // print debug message in separate task to prevent slowing down rest of load + future.thenRunAsync(() -> { + ModernFix.LOGGER.debug("Generated cache for {} in {}", debugPath, watch); + }, ModernFix.resourceReloadExecutor()); } private static boolean isValidCachedResourcePath(Path path) { @@ -86,13 +108,22 @@ public class PackResourcesCacheEngine { return null; } + private void awaitLoad() { + if(this.cacheFuture != null) { + this.cacheFuture.join(); + this.cacheFuture = null; + } + } + public boolean hasResource(String path) { + awaitLoad(); return this.containedPaths.contains(new CachedResourcePath(path)); } public Collection getResources(PackType type, String resourceNamespace, String pathIn, int maxDepth, Predicate filter) { if(!PackTypeHelper.isVanillaPackType(type)) throw new IllegalArgumentException("Only vanilla PackTypes are supported"); + awaitLoad(); List paths = resourceListings.get(type).getOrDefault(resourceNamespace, Collections.emptyList()); if(paths.isEmpty()) return Collections.emptyList();