22
33import java .util .function .Function ;
44import java .util .function .Predicate ;
5- import java .util .function .Supplier ;
65
76import org .jetbrains .annotations .Nullable ;
87
98import me .pepperbell .continuity .api .client .QuadProcessor ;
109import me .pepperbell .continuity .client .config .ContinuityConfig ;
1110import me .pepperbell .continuity .client .util .RenderUtil ;
1211import me .pepperbell .continuity .impl .client .ProcessingContextImpl ;
12+ import net .fabricmc .fabric .api .client .model .loading .v1 .wrapper .WrapperBlockStateModel ;
1313import net .fabricmc .fabric .api .renderer .v1 .mesh .MutableQuadView ;
1414import net .fabricmc .fabric .api .renderer .v1 .mesh .QuadEmitter ;
1515import net .fabricmc .fabric .api .renderer .v1 .mesh .QuadTransform ;
1616import net .minecraft .block .BlockState ;
17- import net .minecraft .client .render .model .BakedModel ;
18- import net .minecraft .client .render .model .WrapperBakedModel ;
17+ import net .minecraft .client .render .model .BlockStateModel ;
1918import net .minecraft .client .texture .Sprite ;
2019import net .minecraft .util .math .BlockPos ;
2120import net .minecraft .util .math .Direction ;
2221import net .minecraft .util .math .random .Random ;
2322import net .minecraft .world .BlockRenderView ;
2423
25- public class CtmBakedModel extends WrapperBakedModel {
24+ public class CtmBlockStateModel extends WrapperBlockStateModel {
2625 public static final int PASSES = 4 ;
2726
2827 protected final BlockState defaultState ;
2928 protected volatile Function <Sprite , QuadProcessors .Slice > defaultSliceFunc ;
3029
31- public CtmBakedModel ( BakedModel wrapped , BlockState defaultState ) {
30+ public CtmBlockStateModel ( BlockStateModel wrapped , BlockState defaultState ) {
3231 super (wrapped );
3332 this .defaultState = defaultState ;
3433 }
3534
3635 @ Override
37- public void emitBlockQuads (QuadEmitter emitter , BlockRenderView blockView , BlockState state , BlockPos pos , Supplier < Random > randomSupplier , Predicate <@ Nullable Direction > cullTest ) {
36+ public void emitQuads (QuadEmitter emitter , BlockRenderView blockView , BlockPos pos , BlockState state , Random random , Predicate <@ Nullable Direction > cullTest ) {
3837 if (!ContinuityConfig .INSTANCE .connectedTextures .get ()) {
39- super .emitBlockQuads (emitter , blockView , state , pos , randomSupplier , cullTest );
38+ super .emitQuads (emitter , blockView , pos , state , random , cullTest );
4039 return ;
4140 }
4241
4342 ModelObjectsContainer container = ModelObjectsContainer .get ();
4443 if (!container .featureStates .getConnectedTexturesState ().isEnabled ()) {
45- super .emitBlockQuads (emitter , blockView , state , pos , randomSupplier , cullTest );
44+ super .emitQuads (emitter , blockView , pos , state , random , cullTest );
4645 return ;
4746 }
4847
4948 CtmQuadTransform quadTransform = container .ctmQuadTransform ;
5049 if (quadTransform .isActive ()) {
51- super .emitBlockQuads (emitter , blockView , state , pos , randomSupplier , cullTest );
50+ super .emitQuads (emitter , blockView , pos , state , random , cullTest );
5251 return ;
5352 }
5453
55- // The correct way to get the appearance of the origin state from within a block model is to (1) call
56- // getAppearance on the result of blockView.getBlockState(pos) instead of the passed state and (2) pass the
57- // pos and world state of the adjacent block as the source pos and source state.
58- // (1) is not followed here because at this point in execution, within this call to
59- // CtmBakedModel#emitBlockQuads, the state parameter must already contain the world state. Even if this
60- // CtmBakedModel is wrapped, then the wrapper must pass the same state as it received because not doing so can
61- // cause crashes when the wrapped model is a vanilla multipart model or delegates to one. Thus, getting the
62- // world state again is inefficient and unnecessary.
63- // (2) is not possible here because the appearance state is necessary to get the slice and only the processors
64- // within the slice actually perform checks on adjacent blocks. Likewise, the processors themselves cannot
65- // retrieve the appearance state since the correct processors can only be chosen with the initially correct
66- // appearance state.
54+ // The correct way to get the appearance of the origin state from within a block model is to call getAppearance
55+ // on the passed world state and pass the pos and world state of the adjacent block as the source pos and source
56+ // state.
57+ // The latter of these is not possible here because the appearance state is necessary to get the slice and only
58+ // the processors within the slice actually perform checks on adjacent blocks. Likewise, the processors
59+ // themselves cannot retrieve the appearance state since the correct processors can only be chosen with the
60+ // initially correct appearance state.
6761 // Additionally, the side is chosen to always be the first constant of the enum (DOWN) for simplicity. Querying
6862 // the appearance for all six sides would be more correct, but less efficient. This may be fixed in the future,
6963 // especially if there is an actual use case for it.
7064 BlockState appearanceState = state .getAppearance (blockView , pos , Direction .DOWN , state , pos );
7165
72- quadTransform .prepare (blockView , appearanceState , state , pos , randomSupplier .get ().nextLong (), cullTest , getSliceFunc (appearanceState ));
66+ // It would be better to use random.nextLong() as the seed, but that changes the state of the random, which
67+ // cannot happen.
68+ quadTransform .prepare (blockView , pos , appearanceState , state , state .getRenderingSeed (pos ), cullTest , getSliceFunc (appearanceState ));
7369
7470 emitter .pushTransform (quadTransform );
75- super .emitBlockQuads (emitter , blockView , state , pos , randomSupplier , cullTest );
71+ super .emitQuads (emitter , blockView , pos , state , random , cullTest );
7672 emitter .popTransform ();
7773
7874 quadTransform .processingContext .outputTo (emitter );
7975 quadTransform .reset ();
8076 }
8177
8278 @ Override
83- public boolean isVanillaAdapter () {
79+ @ Nullable
80+ public Object createGeometryKey (BlockRenderView blockView , BlockPos pos , BlockState state , Random random ) {
8481 if (!ContinuityConfig .INSTANCE .connectedTextures .get ()) {
85- return super .isVanillaAdapter ( );
82+ return super .createGeometryKey ( blockView , pos , state , random );
8683 }
87- return false ;
84+
85+ ModelObjectsContainer container = ModelObjectsContainer .get ();
86+ if (!container .featureStates .getConnectedTexturesState ().isEnabled ()) {
87+ return super .createGeometryKey (blockView , pos , state , random );
88+ }
89+
90+ CtmQuadTransform quadTransform = container .ctmQuadTransform ;
91+ if (quadTransform .isActive ()) {
92+ return super .createGeometryKey (blockView , pos , state , random );
93+ }
94+
95+ // This would be nice to implement, but it's not as important as for a typical model since this CTM wrapper is
96+ // always supposed to be at the top level, and implementing this is far from trivial.
97+ return null ;
8898 }
8999
90100 protected Function <Sprite , QuadProcessors .Slice > getSliceFunc (BlockState state ) {
@@ -106,20 +116,12 @@ protected Function<Sprite, QuadProcessors.Slice> getSliceFunc(BlockState state)
106116
107117 protected static class CtmQuadTransform implements QuadTransform {
108118 protected final ProcessingContextImpl processingContext = new ProcessingContextImpl ();
109- protected final Supplier <Random > randomSupplier = new Supplier <>() {
110- private final Random random = Random .createLocal ();
111-
112- @ Override
113- public Random get () {
114- random .setSeed (randomSeed );
115- return random ;
116- }
117- };
119+ protected final Random random = Random .createLocal ();
118120
119121 protected BlockRenderView blockView ;
122+ protected BlockPos pos ;
120123 protected BlockState appearanceState ;
121124 protected BlockState state ;
122- protected BlockPos pos ;
123125 protected long randomSeed ;
124126 protected Predicate <@ Nullable Direction > cullTest ;
125127 protected Function <Sprite , QuadProcessors .Slice > sliceFunc ;
@@ -147,7 +149,8 @@ protected Boolean transformOnce(MutableQuadView quad, int pass) {
147149 QuadProcessors .Slice slice = sliceFunc .apply (sprite );
148150 QuadProcessor [] processors = pass == 0 ? slice .processors () : slice .multipassProcessors ();
149151 for (QuadProcessor processor : processors ) {
150- QuadProcessor .ProcessingResult result = processor .processQuad (quad , sprite , blockView , appearanceState , state , pos , randomSupplier , pass , processingContext );
152+ random .setSeed (randomSeed );
153+ QuadProcessor .ProcessingResult result = processor .processQuad (quad , sprite , blockView , pos , appearanceState , state , random , pass , processingContext );
151154 if (result == QuadProcessor .ProcessingResult .NEXT_PROCESSOR ) {
152155 continue ;
153156 }
@@ -168,11 +171,11 @@ public boolean isActive() {
168171 return active ;
169172 }
170173
171- public void prepare (BlockRenderView blockView , BlockState appearanceState , BlockState state , BlockPos pos , long randomSeed , Predicate <@ Nullable Direction > cullTest , Function <Sprite , QuadProcessors .Slice > sliceFunc ) {
174+ public void prepare (BlockRenderView blockView , BlockPos pos , BlockState appearanceState , BlockState state , long randomSeed , Predicate <@ Nullable Direction > cullTest , Function <Sprite , QuadProcessors .Slice > sliceFunc ) {
172175 this .blockView = blockView ;
176+ this .pos = pos ;
173177 this .appearanceState = appearanceState ;
174178 this .state = state ;
175- this .pos = pos ;
176179 this .randomSeed = randomSeed ;
177180 this .cullTest = cullTest ;
178181 this .sliceFunc = sliceFunc ;
@@ -182,9 +185,9 @@ public void prepare(BlockRenderView blockView, BlockState appearanceState, Block
182185
183186 public void reset () {
184187 blockView = null ;
188+ pos = null ;
185189 appearanceState = null ;
186190 state = null ;
187- pos = null ;
188191 cullTest = null ;
189192 sliceFunc = null ;
190193
0 commit comments