Skip to content

Commit 24f31dd

Browse files
committed
Initial version of resource pack caching for 1.19.4+
1 parent 5b2e70c commit 24f31dd

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.embeddedt.modernfix.resources;
2+
3+
import net.minecraft.resources.ResourceLocation;
4+
import net.minecraft.server.packs.PackResources;
5+
import net.minecraft.server.packs.resources.IoSupplier;
6+
7+
import java.io.InputStream;
8+
import java.util.Collection;
9+
import java.util.function.Function;
10+
11+
public class NewResourcePackAdapter {
12+
public static void sendToOutput(Function<ResourceLocation, IoSupplier<InputStream>> streamCreator, PackResources.ResourceOutput output, Collection<ResourceLocation> locations) {
13+
for(ResourceLocation rl : locations) {
14+
output.accept(rl, streamCreator.apply(rl));
15+
}
16+
}
17+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package org.embeddedt.modernfix.forge.mixin.perf.resourcepacks;
2+
3+
import net.minecraft.resources.ResourceLocation;
4+
import net.minecraft.server.packs.PackResources;
5+
import net.minecraft.server.packs.PackType;
6+
import net.minecraftforge.resource.PathPackResources;
7+
import org.embeddedt.modernfix.resources.ICachingResourcePack;
8+
import org.embeddedt.modernfix.resources.NewResourcePackAdapter;
9+
import org.embeddedt.modernfix.resources.PackResourcesCacheEngine;
10+
import org.embeddedt.modernfix.util.PackTypeHelper;
11+
import org.jetbrains.annotations.NotNull;
12+
import org.spongepowered.asm.mixin.Mixin;
13+
import org.spongepowered.asm.mixin.Shadow;
14+
import org.spongepowered.asm.mixin.injection.At;
15+
import org.spongepowered.asm.mixin.injection.Inject;
16+
import org.spongepowered.asm.mixin.injection.Redirect;
17+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
18+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
19+
20+
import java.nio.file.Files;
21+
import java.nio.file.LinkOption;
22+
import java.nio.file.Path;
23+
import java.util.Collection;
24+
import java.util.Set;
25+
26+
@Mixin(PathPackResources.class)
27+
public abstract class ForgePathPackResourcesMixin implements ICachingResourcePack {
28+
@Shadow protected abstract Path resolve(String... paths);
29+
30+
@Shadow @NotNull
31+
protected abstract Set<String> getNamespacesFromDisk(PackType type);
32+
33+
@Shadow private static String[] getPathFromLocation(PackType type, ResourceLocation location) {
34+
throw new AssertionError();
35+
}
36+
37+
private PackResourcesCacheEngine cacheEngine;
38+
39+
@Inject(method = "<init>", at = @At("TAIL"))
40+
private void cacheResources(CallbackInfo ci) {
41+
invalidateCache();
42+
PackResourcesCacheEngine.track(this);
43+
}
44+
45+
private PackResourcesCacheEngine generateResourceCache() {
46+
synchronized (this) {
47+
PackResourcesCacheEngine engine = this.cacheEngine;
48+
if(engine != null)
49+
return engine;
50+
this.cacheEngine = engine = new PackResourcesCacheEngine(this::getNamespacesFromDisk, (type, namespace) -> this.resolve(type.getDirectory(), namespace));
51+
return engine;
52+
}
53+
}
54+
55+
@Override
56+
public void invalidateCache() {
57+
this.cacheEngine = null;
58+
}
59+
60+
@Inject(method = "getNamespaces", at = @At("HEAD"), cancellable = true)
61+
private void useCacheForNamespaces(PackType type, CallbackInfoReturnable<Set<String>> cir) {
62+
PackResourcesCacheEngine engine = cacheEngine;
63+
if(engine != null) {
64+
Set<String> namespaces = engine.getNamespaces(type);
65+
if(namespaces != null)
66+
cir.setReturnValue(namespaces);
67+
}
68+
}
69+
70+
@Redirect(method = "getRootResource", at = @At(value = "INVOKE", target = "Ljava/nio/file/Files;exists(Ljava/nio/file/Path;[Ljava/nio/file/LinkOption;)Z"))
71+
private boolean useCacheForExistence(Path path, LinkOption[] options, String[] originalPaths) {
72+
// the cache only stores things with a namespace and pack type
73+
if(originalPaths.length < 3)
74+
return Files.exists(path, options);
75+
else
76+
return this.generateResourceCache().hasResource(originalPaths);
77+
}
78+
79+
/**
80+
* @author embeddedt
81+
* @reason Use cached listing of mod resources
82+
*/
83+
@Inject(method = "listResources", at = @At("HEAD"), cancellable = true)
84+
private void fastGetResources(PackType type, String namespace, String path, PackResources.ResourceOutput resourceOutput, CallbackInfo ci)
85+
{
86+
if(!PackTypeHelper.isVanillaPackType(type))
87+
return;
88+
ci.cancel();
89+
Collection<ResourceLocation> allPossibleResources = this.generateResourceCache().getResources(type, namespace, path, Integer.MAX_VALUE, p -> true);
90+
NewResourcePackAdapter.sendToOutput(location -> {
91+
Path target = resolve(getPathFromLocation(location.getPath().startsWith("lang/") ? PackType.CLIENT_RESOURCES : type, location));
92+
return () -> Files.newInputStream(target);
93+
}, resourceOutput, allPossibleResources);
94+
}
95+
}

0 commit comments

Comments
 (0)