1
1
package platinpython .rgbblocks .util .pack ;
2
2
3
+ import com .google .common .collect .ImmutableMap ;
3
4
import com .google .common .collect .ImmutableSet ;
4
5
import com .google .gson .JsonObject ;
5
6
import com .mojang .blaze3d .platform .NativeImage ;
6
- import com . mojang . datafixers . util . Pair ;
7
+ import net . minecraft . SharedConstants ;
7
8
import net .minecraft .client .Minecraft ;
8
9
import net .minecraft .network .chat .Component ;
9
10
import net .minecraft .resources .ResourceLocation ;
13
14
import net .minecraft .server .packs .metadata .pack .PackMetadataSection ;
14
15
import net .minecraft .server .packs .metadata .pack .PackMetadataSectionSerializer ;
15
16
import net .minecraft .server .packs .resources .IoSupplier ;
16
- import net .minecraft .server .packs .resources .PreparableReloadListener ;
17
17
import net .minecraft .server .packs .resources .ResourceManager ;
18
18
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 ;
21
21
import platinpython .rgbblocks .RGBBlocks ;
22
22
import platinpython .rgbblocks .util .Color ;
23
23
29
29
import java .nio .charset .StandardCharsets ;
30
30
import java .util .HashMap ;
31
31
import java .util .Map ;
32
- import java .util .NoSuchElementException ;
33
- import java .util .Optional ;
34
32
import java .util .Set ;
35
- import java .util .concurrent .CompletableFuture ;
36
- import java .util .concurrent .Executor ;
33
+ import java .util .stream .Stream ;
37
34
38
- public class RGBBlocksPack extends AbstractPackResources implements PreparableReloadListener {
35
+ public class RGBBlocksPack extends AbstractPackResources {
39
36
public static final String TEXTURE_DIRECTORY = "textures/" ;
40
37
public static final String BLOCK_DIRECTORY = "block/" ;
41
38
public static final Set <String > NAMESPACES = ImmutableSet .of (RGBBlocks .MOD_ID );
42
39
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
+
43
60
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 <>();
46
62
47
63
public RGBBlocksPack () {
48
64
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 )
76
68
);
77
69
}
78
70
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 ())
111
75
);
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 ())));
114
80
}
115
81
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" );
118
84
}
119
85
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" );
122
88
}
123
89
124
- public Optional < Pair < NativeImage , Optional < IoSupplier <InputStream >>>> generateImage (
90
+ private @ Nullable IoSupplier <InputStream > computeImage (
125
91
ResourceLocation modLocation ,
126
92
ResourceLocation vanillaLocation ,
127
93
ResourceManager manager
128
94
) {
129
- ResourceLocation parentFile = makeTextureID (vanillaLocation );
130
- try (InputStream inputStream = manager .getResource (parentFile ).orElseThrow ().open ()) {
95
+ try (InputStream inputStream = manager .getResourceOrThrow (vanillaLocation ).open ()) {
131
96
NativeImage image = NativeImage .read (inputStream );
132
97
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 ;
153
102
}
154
103
}
155
104
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 ) {
157
125
for (int x = 0 ; x < image .getWidth (); x ++) {
158
126
for (int y = 0 ; y < image .getHeight (); y ++) {
159
127
int oldColor = image .getPixelRGBA (x , y );
@@ -169,19 +137,20 @@ public NativeImage transformImage(NativeImage image) {
169
137
return image ;
170
138
}
171
139
172
- @ Override
173
- public String getName () {
174
- return Component .translatable ("rgbblocks.pack_title" ).getString ();
175
- }
176
-
177
140
@ SuppressWarnings ("unchecked" )
178
141
@ Override
179
- public <T > T getMetadataSection (MetadataSectionSerializer <T > serializer ) {
142
+ public <T > @ Nullable T getMetadataSection (MetadataSectionSerializer <T > serializer ) {
180
143
return serializer instanceof PackMetadataSectionSerializer ? (T ) this .packInfo : null ;
181
144
}
182
145
183
146
@ 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
+ }
185
154
return null ;
186
155
}
187
156
@@ -194,27 +163,32 @@ public Set<String> getNamespaces(PackType type) {
194
163
}
195
164
196
165
@ 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 ));
202
178
}
203
-
204
179
try {
205
- return streamGetter ;
180
+ return streamSupplier ;
206
181
} catch (Exception e ) {
207
182
return null ;
208
183
}
209
- } else {
210
- return null ;
211
184
}
185
+ return null ;
212
186
}
213
187
214
188
@ Override
215
189
public void listResources (PackType type , String namespace , String id , ResourceOutput output ) {
216
190
if (namespace .equals (RGBBlocks .MOD_ID )) {
217
- this . resources . forEach ((name , supplier ) -> {
191
+ RESOURCES . forEach ((name , ignored ) -> {
218
192
if (name .getPath ().startsWith (id )) {
219
193
output .accept (name , getResource (type , name ));
220
194
}
0 commit comments