Skip to content

Commit af83af8

Browse files
committed
Switch virtual pack to cache based approach. Hopefully fixes #14.
1 parent 055553c commit af83af8

File tree

4 files changed

+115
-137
lines changed

4 files changed

+115
-137
lines changed

build.gradle

+11-7
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,20 @@ minecraft {
6868

6969
sourceSets.main.resources { srcDir 'src/generated/resources' }
7070

71+
sourceSets.main.java {
72+
exclude 'platinpython/rgbblocks/util/compat/cb/**'
73+
}
74+
7175
repositories {
7276
maven { // TOP
7377
url "https://www.cursemaven.com/"
7478
content {
7579
includeGroup "curse.maven"
7680
}
7781
}
78-
maven { // C&B
79-
url 'https://ldtteam.jfrog.io/ldtteam/modding/'
80-
}
82+
// maven { // C&B
83+
// url 'https://ldtteam.jfrog.io/ldtteam/modding/'
84+
// }
8185
}
8286

8387
dependencies {
@@ -88,10 +92,10 @@ dependencies {
8892
implementation fg.deobf("curse.maven:the-one-probe-245211:4629624")
8993
implementation fg.deobf("curse.maven:framedblocks-441647:4657096")
9094

91-
compileOnly fg.deobf("com.communi-suggestu.scena:scena-core:1.0.98")
92-
compileOnly fg.deobf("com.communi-suggestu.saecularia-caudices:saecularia-caudices-core:1.0.20")
93-
compileOnly fg.deobf("mod.chiselsandbits:chisels-and-bits-api:1.4.148")
94-
runtimeOnly fg.deobf("mod.chiselsandbits:chisels-and-bits-forge:1.4.148")
95+
// compileOnly fg.deobf("com.communi-suggestu.scena:scena-core:1.0.98")
96+
// compileOnly fg.deobf("com.communi-suggestu.saecularia-caudices:saecularia-caudices-core:1.0.20")
97+
// compileOnly fg.deobf("mod.chiselsandbits:chisels-and-bits-api:1.4.148")
98+
// runtimeOnly fg.deobf("mod.chiselsandbits:chisels-and-bits-forge:1.4.148")
9599
}
96100

97101
jar {

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ org.gradle.daemon=false
55

66
#version info
77
minecraft_version=1.20.1
8-
mod_version=1.1.9.1
8+
mod_version=1.1.9.2

src/main/java/platinpython/rgbblocks/util/ClientUtils.java

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package platinpython.rgbblocks.util;
22

3+
import net.minecraft.SharedConstants;
34
import net.minecraft.client.Minecraft;
45
import net.minecraft.client.gui.screens.Screen;
56
import net.minecraft.network.chat.Component;
@@ -11,7 +12,6 @@
1112
import net.minecraftforge.api.distmarker.Dist;
1213
import net.minecraftforge.client.event.EntityRenderersEvent;
1314
import net.minecraftforge.client.event.ModelEvent;
14-
import net.minecraftforge.client.event.RegisterClientReloadListenersEvent;
1515
import net.minecraftforge.client.event.RegisterColorHandlersEvent;
1616
import net.minecraftforge.event.AddPackFindersEvent;
1717
import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -31,27 +31,27 @@
3131

3232
@EventBusSubscriber(modid = RGBBlocks.MOD_ID, bus = Bus.MOD, value = Dist.CLIENT)
3333
public class ClientUtils {
34-
public static final RGBBlocksPack VIRTUAL_PACK = new RGBBlocksPack();
35-
3634
@SubscribeEvent
3735
public static void addPackFinders(AddPackFindersEvent event) {
36+
if (event.getPackType() != PackType.CLIENT_RESOURCES) {
37+
return;
38+
}
3839
event.addRepositorySource(
39-
(infoConsumer) -> infoConsumer.accept(
40+
infoConsumer -> infoConsumer.accept(
4041
Pack.create(
41-
"rgbblocks_textures", Component.translatable("rgbblocks.pack_title"), true, id -> VIRTUAL_PACK,
42+
"rgbblocks_textures", Component.translatable("rgbblocks.pack_title"), true,
43+
id -> new RGBBlocksPack(),
4244
new Pack.Info(
43-
Component.translatable("rgbblocks.pack_description"), 0, 0, FeatureFlagSet.of(), false
44-
), PackType.CLIENT_RESOURCES, Pack.Position.TOP, true, PackSource.BUILT_IN
45+
Component.translatable("rgbblocks.pack_description"),
46+
SharedConstants.getCurrentVersion().getPackVersion(PackType.SERVER_DATA),
47+
SharedConstants.getCurrentVersion().getPackVersion(PackType.CLIENT_RESOURCES),
48+
FeatureFlagSet.of(), false
49+
), PackType.CLIENT_RESOURCES, Pack.Position.TOP, false, PackSource.BUILT_IN
4550
)
4651
)
4752
);
4853
}
4954

50-
@SubscribeEvent
51-
public static void registerReloadListener(RegisterClientReloadListenersEvent event) {
52-
event.registerReloadListener(VIRTUAL_PACK);
53-
}
54-
5555
@SubscribeEvent
5656
public static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderers event) {
5757
event.registerEntityRenderer(EntityRegistry.RGB_FALLING_BLOCK.get(), RGBFallingBlockRenderer::new);

src/main/java/platinpython/rgbblocks/util/pack/RGBBlocksPack.java

+91-117
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package platinpython.rgbblocks.util.pack;
22

3+
import com.google.common.collect.ImmutableMap;
34
import com.google.common.collect.ImmutableSet;
45
import com.google.gson.JsonObject;
56
import com.mojang.blaze3d.platform.NativeImage;
6-
import com.mojang.datafixers.util.Pair;
7+
import net.minecraft.SharedConstants;
78
import net.minecraft.client.Minecraft;
89
import net.minecraft.network.chat.Component;
910
import net.minecraft.resources.ResourceLocation;
@@ -13,11 +14,10 @@
1314
import net.minecraft.server.packs.metadata.pack.PackMetadataSection;
1415
import net.minecraft.server.packs.metadata.pack.PackMetadataSectionSerializer;
1516
import net.minecraft.server.packs.resources.IoSupplier;
16-
import net.minecraft.server.packs.resources.PreparableReloadListener;
1717
import net.minecraft.server.packs.resources.ResourceManager;
1818
import net.minecraft.util.GsonHelper;
19-
import net.minecraft.util.profiling.ProfilerFiller;
20-
import org.apache.commons.io.IOUtils;
19+
import net.minecraftforge.fml.ModList;
20+
import org.jspecify.annotations.Nullable;
2121
import platinpython.rgbblocks.RGBBlocks;
2222
import platinpython.rgbblocks.util.Color;
2323

@@ -29,131 +29,99 @@
2929
import java.nio.charset.StandardCharsets;
3030
import java.util.HashMap;
3131
import java.util.Map;
32-
import java.util.NoSuchElementException;
33-
import java.util.Optional;
3432
import java.util.Set;
35-
import java.util.concurrent.CompletableFuture;
36-
import java.util.concurrent.Executor;
33+
import java.util.stream.Stream;
3734

38-
public class RGBBlocksPack extends AbstractPackResources implements PreparableReloadListener {
35+
public class RGBBlocksPack extends AbstractPackResources {
3936
public static final String TEXTURE_DIRECTORY = "textures/";
4037
public static final String BLOCK_DIRECTORY = "block/";
4138
public static final Set<String> NAMESPACES = ImmutableSet.of(RGBBlocks.MOD_ID);
4239

40+
private static final ImmutableMap<ResourceLocation, ResourceLocation> RESOURCES =
41+
Stream.<Map.Entry<String, String>>builder()
42+
.add(Map.entry("concrete", "white_concrete"))
43+
.add(Map.entry("concrete_powder", "white_concrete_powder"))
44+
.add(Map.entry("wool", "white_wool"))
45+
.add(Map.entry("planks", "birch_planks"))
46+
.add(Map.entry("terracotta", "white_terracotta"))
47+
.add(Map.entry("glass", "white_stained_glass"))
48+
.add(Map.entry("glass_pane_top", "white_stained_glass_pane_top"))
49+
.add(Map.entry("glowstone", "glowstone"))
50+
.add(Map.entry("redstone_lamp", "redstone_lamp"))
51+
.add(Map.entry("redstone_lamp_on", "redstone_lamp_on"))
52+
.add(Map.entry("prismarine", "prismarine"))
53+
.add(Map.entry("prismarine_bricks", "prismarine_bricks"))
54+
.add(Map.entry("dark_prismarine", "dark_prismarine"))
55+
.add(Map.entry("sea_lantern", "sea_lantern"))
56+
.build()
57+
.flatMap(RGBBlocksPack::makeIDs)
58+
.collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
59+
4360
private final PackMetadataSection packInfo;
44-
private Map<ResourceLocation, IoSupplier<InputStream>> resources = new HashMap<>();
45-
private final Map<ResourceLocation, ResourceLocation> textures = new HashMap<>();
61+
private final HashMap<ResourceLocation, IoSupplier<InputStream>> resources = new HashMap<>();
4662

4763
public RGBBlocksPack() {
4864
super("rgbblocks_virtual_pack", true);
49-
this.packInfo = new PackMetadataSection(Component.translatable("rgbblocks.pack_description"), 7);
50-
fillTexturesMap();
51-
}
52-
53-
private void fillTexturesMap() {
54-
Map<String, String> map = new HashMap<>();
55-
56-
map.put("concrete", "white_concrete");
57-
map.put("concrete_powder", "white_concrete_powder");
58-
map.put("wool", "white_wool");
59-
map.put("planks", "birch_planks");
60-
map.put("terracotta", "white_terracotta");
61-
map.put("glass", "white_stained_glass");
62-
map.put("glass_pane_top", "white_stained_glass_pane_top");
63-
map.put("glowstone", "glowstone");
64-
map.put("redstone_lamp", "redstone_lamp");
65-
map.put("redstone_lamp_on", "redstone_lamp_on");
66-
map.put("prismarine", "prismarine");
67-
map.put("prismarine_bricks", "prismarine_bricks");
68-
map.put("dark_prismarine", "dark_prismarine");
69-
map.put("sea_lantern", "sea_lantern");
70-
71-
map.forEach(
72-
(modName, vanillaName) -> textures.put(
73-
new ResourceLocation(RGBBlocks.MOD_ID, BLOCK_DIRECTORY + modName),
74-
new ResourceLocation(BLOCK_DIRECTORY + vanillaName)
75-
)
65+
this.packInfo = new PackMetadataSection(
66+
Component.translatable("rgbblocks.pack_description"),
67+
SharedConstants.getCurrentVersion().getPackVersion(PackType.CLIENT_RESOURCES)
7668
);
7769
}
7870

79-
@Override
80-
public CompletableFuture<Void> reload(
81-
PreparationBarrier stage,
82-
ResourceManager manager,
83-
ProfilerFiller workerProfiler,
84-
ProfilerFiller mainProfiler,
85-
Executor workerExecutor,
86-
Executor mainExecutor
87-
) {
88-
this.gatherTextureData(manager, mainProfiler);
89-
return CompletableFuture.supplyAsync(() -> null, workerExecutor)
90-
.thenCompose(stage::wait)
91-
.thenAcceptAsync((noResult) -> {}, mainExecutor);
92-
}
93-
94-
protected void gatherTextureData(ResourceManager manager, ProfilerFiller profiler) {
95-
Map<ResourceLocation, IoSupplier<InputStream>> resourceStreams = new HashMap<>();
96-
97-
textures.forEach(
98-
(
99-
modLocation,
100-
vanillaLocation
101-
) -> generateImage(modLocation, vanillaLocation, Minecraft.getInstance().getResourceManager())
102-
.ifPresent(pair -> {
103-
NativeImage image = pair.getFirst();
104-
ResourceLocation textureID = makeTextureID(modLocation);
105-
resourceStreams.put(textureID, () -> new ByteArrayInputStream(image.asByteArray()));
106-
pair.getSecond()
107-
.ifPresent(
108-
metadataGetter -> resourceStreams.put(getMetadataLocation(textureID), metadataGetter)
109-
);
110-
})
71+
private static Stream<Map.Entry<ResourceLocation, ResourceLocation>> makeIDs(Map.Entry<String, String> entry) {
72+
Map.Entry<ResourceLocation, ResourceLocation> paths = Map.entry(
73+
new ResourceLocation(RGBBlocks.MOD_ID, BLOCK_DIRECTORY + entry.getKey()),
74+
new ResourceLocation(BLOCK_DIRECTORY + entry.getValue())
11175
);
112-
113-
this.resources = resourceStreams;
76+
Map.Entry<ResourceLocation, ResourceLocation> texture =
77+
Map.entry(makeTextureID(paths.getKey()), makeTextureID(paths.getValue()));
78+
return Stream
79+
.of(texture, Map.entry(getMetadataLocation(texture.getKey()), getMetadataLocation(texture.getValue())));
11480
}
11581

116-
public static ResourceLocation makeTextureID(ResourceLocation id) {
117-
return new ResourceLocation(id.getNamespace(), TEXTURE_DIRECTORY + id.getPath() + ".png");
82+
private static ResourceLocation makeTextureID(ResourceLocation id) {
83+
return id.withPath(path -> TEXTURE_DIRECTORY + path + ".png");
11884
}
11985

120-
public static ResourceLocation getMetadataLocation(ResourceLocation id) {
121-
return new ResourceLocation(id.getNamespace(), id.getPath() + ".mcmeta");
86+
private static ResourceLocation getMetadataLocation(ResourceLocation id) {
87+
return id.withSuffix(".mcmeta");
12288
}
12389

124-
public Optional<Pair<NativeImage, Optional<IoSupplier<InputStream>>>> generateImage(
90+
private @Nullable IoSupplier<InputStream> computeImage(
12591
ResourceLocation modLocation,
12692
ResourceLocation vanillaLocation,
12793
ResourceManager manager
12894
) {
129-
ResourceLocation parentFile = makeTextureID(vanillaLocation);
130-
try (InputStream inputStream = manager.getResource(parentFile).orElseThrow().open()) {
95+
try (InputStream inputStream = manager.getResourceOrThrow(vanillaLocation).open()) {
13196
NativeImage image = NativeImage.read(inputStream);
13297
NativeImage transformedImage = this.transformImage(image);
133-
ResourceLocation metadata = getMetadataLocation(parentFile);
134-
Optional<IoSupplier<InputStream>> metadataLookup = Optional.empty();
135-
BufferedReader bufferedReader = null;
136-
JsonObject metadataJson;
137-
if (manager.getResource(metadata).isPresent()) {
138-
try (InputStream metadataStream = manager.getResource(metadata).get().open()) {
139-
bufferedReader = new BufferedReader(new InputStreamReader(metadataStream, StandardCharsets.UTF_8));
140-
metadataJson = GsonHelper.parse(bufferedReader);
141-
} catch (Exception e) {
142-
return Optional.empty();
143-
} finally {
144-
IOUtils.closeQuietly(bufferedReader);
145-
}
146-
JsonObject metaDataJsonForLambda = metadataJson;
147-
metadataLookup =
148-
Optional.of(() -> new ByteArrayInputStream(metaDataJsonForLambda.toString().getBytes()));
149-
}
150-
return Optional.of(Pair.of(transformedImage, metadataLookup));
151-
} catch (IOException | NoSuchElementException e) {
152-
return Optional.empty();
98+
return () -> new ByteArrayInputStream(transformedImage.asByteArray());
99+
} catch (IOException e) {
100+
RGBBlocks.LOGGER.error("Error while generating {}", modLocation, e);
101+
return null;
153102
}
154103
}
155104

156-
public NativeImage transformImage(NativeImage image) {
105+
private @Nullable IoSupplier<InputStream> computeMetadata(
106+
ResourceLocation modLocation,
107+
ResourceLocation vanillaLocation,
108+
ResourceManager manager
109+
) {
110+
return manager.getResource(vanillaLocation).<IoSupplier<InputStream>>map(resource -> {
111+
try (
112+
BufferedReader bufferedReader =
113+
new BufferedReader(new InputStreamReader(resource.open(), StandardCharsets.UTF_8))
114+
) {
115+
JsonObject metadataJson = GsonHelper.parse(bufferedReader);
116+
return () -> new ByteArrayInputStream(metadataJson.toString().getBytes());
117+
} catch (IOException e) {
118+
RGBBlocks.LOGGER.error("Error while generating {}", modLocation, e);
119+
return null;
120+
}
121+
}).orElse(() -> new ByteArrayInputStream("{}".getBytes()));
122+
}
123+
124+
private NativeImage transformImage(NativeImage image) {
157125
for (int x = 0; x < image.getWidth(); x++) {
158126
for (int y = 0; y < image.getHeight(); y++) {
159127
int oldColor = image.getPixelRGBA(x, y);
@@ -169,19 +137,20 @@ public NativeImage transformImage(NativeImage image) {
169137
return image;
170138
}
171139

172-
@Override
173-
public String getName() {
174-
return Component.translatable("rgbblocks.pack_title").getString();
175-
}
176-
177140
@SuppressWarnings("unchecked")
178141
@Override
179-
public <T> T getMetadataSection(MetadataSectionSerializer<T> serializer) {
142+
public <T> @Nullable T getMetadataSection(MetadataSectionSerializer<T> serializer) {
180143
return serializer instanceof PackMetadataSectionSerializer ? (T) this.packInfo : null;
181144
}
182145

183146
@Override
184-
public IoSupplier<InputStream> getRootResource(String... fileName) {
147+
public @Nullable IoSupplier<InputStream> getRootResource(String... elements) {
148+
for (String name : elements) {
149+
if (!name.equals("pack.png")) {
150+
continue;
151+
}
152+
return IoSupplier.create(ModList.get().getModFileById(RGBBlocks.MOD_ID).getFile().findResource("logo.png"));
153+
}
185154
return null;
186155
}
187156

@@ -194,27 +163,32 @@ public Set<String> getNamespaces(PackType type) {
194163
}
195164

196165
@Override
197-
public IoSupplier<InputStream> getResource(PackType type, ResourceLocation id) {
198-
if (this.resources.containsKey(id)) {
199-
IoSupplier<InputStream> streamGetter = this.resources.get(id);
200-
if (streamGetter == null) {
201-
return null;
166+
public @Nullable IoSupplier<InputStream> getResource(PackType type, ResourceLocation id) {
167+
if (RESOURCES.containsKey(id)) {
168+
ResourceManager manager = Minecraft.getInstance().getResourceManager();
169+
IoSupplier<InputStream> streamSupplier;
170+
if (id.getPath().endsWith(".mcmeta")) {
171+
// noinspection DataFlowIssue
172+
streamSupplier = this.resources
173+
.computeIfAbsent(id, location -> computeMetadata(location, RESOURCES.get(location), manager));
174+
} else {
175+
// noinspection DataFlowIssue
176+
streamSupplier = this.resources
177+
.computeIfAbsent(id, location -> computeImage(location, RESOURCES.get(location), manager));
202178
}
203-
204179
try {
205-
return streamGetter;
180+
return streamSupplier;
206181
} catch (Exception e) {
207182
return null;
208183
}
209-
} else {
210-
return null;
211184
}
185+
return null;
212186
}
213187

214188
@Override
215189
public void listResources(PackType type, String namespace, String id, ResourceOutput output) {
216190
if (namespace.equals(RGBBlocks.MOD_ID)) {
217-
this.resources.forEach((name, supplier) -> {
191+
RESOURCES.forEach((name, ignored) -> {
218192
if (name.getPath().startsWith(id)) {
219193
output.accept(name, getResource(type, name));
220194
}

0 commit comments

Comments
 (0)