22
33import java .util .EnumMap ;
44import java .util .List ;
5+ import java .util .Set ;
56import java .util .concurrent .locks .StampedLock ;
67import java .util .function .Supplier ;
78
8- import it .unimi .dsi .fastutil .objects .Reference2ReferenceOpenHashMap ;
9+ import org .apache .commons .lang3 .ArrayUtils ;
10+ import org .jetbrains .annotations .Unmodifiable ;
11+
12+ import it .unimi .dsi .fastutil .objects .Reference2ObjectOpenHashMap ;
13+ import it .unimi .dsi .fastutil .objects .ReferenceArrayList ;
914import net .fabricmc .fabric .api .client .rendering .v1 .InvalidateRenderStateCallback ;
1015import net .minecraft .block .BlockState ;
1116import net .minecraft .client .MinecraftClient ;
1823
1924public final class SpriteCalculator {
2025 private static final BlockModels MODELS = MinecraftClient .getInstance ().getBakedModelManager ().getBlockModels ();
26+ private static final Direction [] CULL_FACES = ArrayUtils .add (Direction .values (), null );
2127
2228 private static final EnumMap <Direction , SpriteCache > SPRITE_CACHES = new EnumMap <>(Direction .class );
2329
@@ -29,31 +35,27 @@ public final class SpriteCalculator {
2935 InvalidateRenderStateCallback .EVENT .register (SpriteCalculator ::clearCache );
3036 }
3137
32- public static Sprite getSprite (BlockState state , Direction face ) {
33- return SPRITE_CACHES .get (face ).getSprite (state );
38+ @ Unmodifiable
39+ public static Set <Sprite > getSprites (BlockState state , Direction face ) {
40+ return SPRITE_CACHES .get (face ).getSprites (state );
3441 }
3542
36- public static Sprite calculateSprite (BlockState state , Direction face , Supplier <Random > randomSupplier ) {
43+ @ Unmodifiable
44+ public static Set <Sprite > calculateSprites (BlockState state , Direction face , Supplier <Random > randomSupplier ) {
45+ List <Sprite > sprites = new ReferenceArrayList <>();
3746 BakedModel model = MODELS .getModel (state );
3847 try {
39- List <BakedQuad > quads = model .getQuads (state , face , randomSupplier .get ());
40- if (!quads .isEmpty ()) {
41- return quads .get (0 ).getSprite ();
42- }
43- quads = model .getQuads (state , null , randomSupplier .get ());
44- if (!quads .isEmpty ()) {
45- int amount = quads .size ();
46- for (int i = 0 ; i < amount ; i ++) {
47- BakedQuad quad = quads .get (i );
48+ for (Direction cullFace : CULL_FACES ) {
49+ for (BakedQuad quad : model .getQuads (state , cullFace , randomSupplier .get ())) {
4850 if (quad .getFace () == face ) {
49- return quad .getSprite ();
51+ sprites . add ( quad .getSprite () );
5052 }
5153 }
5254 }
5355 } catch (Exception e ) {
5456 //
5557 }
56- return model .getParticleSprite ();
58+ return ! sprites . isEmpty () ? Set . copyOf ( sprites ) : Set . of ( model .getParticleSprite () );
5759 }
5860
5961 public static void clearCache () {
@@ -64,7 +66,7 @@ public static void clearCache() {
6466
6567 private static class SpriteCache {
6668 private final Direction face ;
67- private final Reference2ReferenceOpenHashMap <BlockState , Sprite > sprites = new Reference2ReferenceOpenHashMap <>();
69+ private final Reference2ObjectOpenHashMap <BlockState , Set < Sprite >> spritesMap = new Reference2ObjectOpenHashMap <>();
6870 private final Supplier <Random > randomSupplier = new Supplier <>() {
6971 private final Random random = Random .create ();
7072
@@ -81,18 +83,19 @@ public SpriteCache(Direction face) {
8183 this .face = face ;
8284 }
8385
84- public Sprite getSprite (BlockState state ) {
85- Sprite sprite ;
86+ @ Unmodifiable
87+ public Set <Sprite > getSprites (BlockState state ) {
88+ Set <Sprite > sprites ;
8689
8790 long optimisticReadStamp = lock .tryOptimisticRead ();
8891 if (optimisticReadStamp != 0L ) {
8992 try {
9093 // This map read could happen at the same time as a map write, so catch any exceptions.
9194 // This is safe due to the map implementation used, which is guaranteed to not mutate the map during
9295 // a read.
93- sprite = sprites .get (state );
94- if (sprite != null && lock .validate (optimisticReadStamp )) {
95- return sprite ;
96+ sprites = spritesMap .get (state );
97+ if (sprites != null && lock .validate (optimisticReadStamp )) {
98+ return sprites ;
9699 }
97100 } catch (Exception e ) {
98101 //
@@ -101,31 +104,31 @@ public Sprite getSprite(BlockState state) {
101104
102105 long readStamp = lock .readLock ();
103106 try {
104- sprite = sprites .get (state );
107+ sprites = spritesMap .get (state );
105108 } finally {
106109 lock .unlockRead (readStamp );
107110 }
108111
109- if (sprite == null ) {
112+ if (sprites == null ) {
110113 long writeStamp = lock .writeLock ();
111114 try {
112- sprite = sprites .get (state );
113- if (sprite == null ) {
114- sprite = calculateSprite (state , face , randomSupplier );
115- sprites .put (state , sprite );
115+ sprites = spritesMap .get (state );
116+ if (sprites == null ) {
117+ sprites = calculateSprites (state , face , randomSupplier );
118+ spritesMap .put (state , sprites );
116119 }
117120 } finally {
118121 lock .unlockWrite (writeStamp );
119122 }
120123 }
121124
122- return sprite ;
125+ return sprites ;
123126 }
124127
125128 public void clear () {
126129 long writeStamp = lock .writeLock ();
127130 try {
128- sprites .clear ();
131+ spritesMap .clear ();
129132 } finally {
130133 lock .unlockWrite (writeStamp );
131134 }
0 commit comments