Skip to content

Commit

Permalink
Do judge a block by its appearance
Browse files Browse the repository at this point in the history
- Call FabricBlock.getAppearance and use the result where appropriate; Fix #307
- Improve StandardOverlayQuadProcessor
  - Optimize and clean up code
  - Fix "two sides adj" case not checking for adjacent blocks with the same overlay before applying corner overlay
  - Remove explicit dynamic bounds check to improve mod compatibility
- Remove key suffix from fields in ProcessingDataKeys
  • Loading branch information
PepperCode1 committed Jul 5, 2024
1 parent 3dab2d1 commit b055564
Show file tree
Hide file tree
Showing 24 changed files with 307 additions and 286 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import net.minecraft.world.BlockRenderView;

public interface QuadProcessor {
ProcessingResult processQuad(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context);
ProcessingResult processQuad(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context);

interface ProcessingContext extends ProcessingDataProvider {
void addEmitterConsumer(Consumer<QuadEmitter> consumer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;

Expand Down Expand Up @@ -47,7 +48,24 @@ public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos
return;
}

quadTransform.prepare(blockView, state, pos, randomSupplier, ContinuityConfig.INSTANCE.useManualCulling.get(), getSliceFunc(state));
// The correct way to get the appearance of the origin state from within a block model is to (1) call
// getAppearance on the result of blockView.getBlockState(pos) instead of the passed state and (2) pass the
// pos and world state of the adjacent block as the source pos and source state.
// (1) is not followed here because at this point in execution, within this call to
// CtmBakedModel#emitBlockQuads, the state parameter must already contain the world state. Even if this
// CtmBakedModel is wrapped, then the wrapper must pass the same state as it received because not doing so can
// cause crashes when the wrapped model is a vanilla multipart model or delegates to one. Thus, getting the
// world state again is inefficient and unnecessary.
// (2) is not possible here because the appearance state is necessary to get the slice and only the processors
// within the slice actually perform checks on adjacent blocks. Likewise, the processors themselves cannot
// retrieve the appearance state since the correct processors can only be chosen with the initially correct
// appearance state.
// Additionally, the side is chosen to always be the first constant of the enum (DOWN) for simplicity. Querying
// the appearance for all six sides would be more correct, but less efficient. This may be fixed in the future,
// especially if there is an actual use case for it.
BlockState appearanceState = state.getAppearance(blockView, pos, Direction.DOWN, state, pos);

quadTransform.prepare(blockView, appearanceState, state, pos, randomSupplier, ContinuityConfig.INSTANCE.useManualCulling.get(), getSliceFunc(appearanceState));

context.pushTransform(quadTransform);
super.emitBlockQuads(blockView, state, pos, randomSupplier, context);
Expand Down Expand Up @@ -87,6 +105,7 @@ protected static class CtmQuadTransform implements RenderContext.QuadTransform {
protected final CullingCache cullingCache = new CullingCache();

protected BlockRenderView blockView;
protected BlockState appearanceState;
protected BlockState state;
protected BlockPos pos;
protected Supplier<Random> randomSupplier;
Expand Down Expand Up @@ -116,7 +135,7 @@ protected Boolean transformOnce(MutableQuadView quad, int pass) {
QuadProcessors.Slice slice = sliceFunc.apply(sprite);
QuadProcessor[] processors = pass == 0 ? slice.processors() : slice.multipassProcessors();
for (QuadProcessor processor : processors) {
QuadProcessor.ProcessingResult result = processor.processQuad(quad, sprite, blockView, state, pos, randomSupplier, pass, processingContext);
QuadProcessor.ProcessingResult result = processor.processQuad(quad, sprite, blockView, appearanceState, state, pos, randomSupplier, pass, processingContext);
if (result == QuadProcessor.ProcessingResult.NEXT_PROCESSOR) {
continue;
}
Expand All @@ -137,8 +156,9 @@ public boolean isActive() {
return active;
}

public void prepare(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, boolean useManualCulling, Function<Sprite, QuadProcessors.Slice> sliceFunc) {
public void prepare(BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, boolean useManualCulling, Function<Sprite, QuadProcessors.Slice> sliceFunc) {
this.blockView = blockView;
this.appearanceState = appearanceState;
this.state = state;
this.pos = pos;
this.randomSupplier = randomSupplier;
Expand All @@ -153,6 +173,7 @@ public void prepare(BlockRenderView blockView, BlockState state, BlockPos pos, S

public void reset() {
blockView = null;
appearanceState = null;
state = null;
pos = null;
randomSupplier = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ public AbstractQuadProcessor(Sprite[] sprites, ProcessingPredicate processingPre
}

@Override
public ProcessingResult processQuad(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context) {
if (!processingPredicate.shouldProcessQuad(quad, sprite, blockView, state, pos, context)) {
public ProcessingResult processQuad(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context) {
if (!processingPredicate.shouldProcessQuad(quad, sprite, blockView, appearanceState, state, pos, context)) {
return ProcessingResult.NEXT_PROCESSOR;
}
return processQuadInner(quad, sprite, blockView, state, pos, randomSupplier, pass, context);
return processQuadInner(quad, sprite, blockView, appearanceState, state, pos, randomSupplier, pass, context);
}

public abstract ProcessingResult processQuadInner(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context);
public abstract ProcessingResult processQuadInner(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ public BaseProcessingPredicate(@Nullable EnumSet<Direction> faces, @Nullable Pre
}

@Override
public boolean shouldProcessQuad(QuadView quad, Sprite sprite, BlockRenderView blockView, BlockState state, BlockPos pos, ProcessingDataProvider dataProvider) {
public boolean shouldProcessQuad(QuadView quad, Sprite sprite, BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, ProcessingDataProvider dataProvider) {
if (heightPredicate != null) {
if (!heightPredicate.test(pos.getY())) {
return false;
}
}
if (faces != null) {
Direction face = quad.lightFace();
if (state.contains(Properties.AXIS)) {
Direction.Axis axis = state.get(Properties.AXIS);
if (appearanceState.contains(Properties.AXIS)) {
Direction.Axis axis = appearanceState.get(Properties.AXIS);
if (axis == Direction.Axis.X) {
face = face.rotateClockwise(Direction.Axis.Z);
} else if (axis == Direction.Axis.Z) {
Expand All @@ -59,13 +59,13 @@ public boolean shouldProcessQuad(QuadView quad, Sprite sprite, BlockRenderView b
}
}
if (biomePredicate != null) {
Biome biome = dataProvider.getData(ProcessingDataKeys.BIOME_CACHE_KEY).get(blockView, pos);
Biome biome = dataProvider.getData(ProcessingDataKeys.BIOME_CACHE).get(blockView, pos);
if (biome == null || !biomePredicate.test(biome)) {
return false;
}
}
if (blockEntityNamePredicate != null) {
String blockEntityName = dataProvider.getData(ProcessingDataKeys.BLOCK_ENTITY_NAME_CACHE_KEY).get(blockView, pos);
String blockEntityName = dataProvider.getData(ProcessingDataKeys.BLOCK_ENTITY_NAME_CACHE).get(blockView, pos);
if (blockEntityName == null || !blockEntityNamePredicate.test(blockEntityName)) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ public CompactCtmQuadProcessor(Sprite[] sprites, ProcessingPredicate processingP
}

@Override
public ProcessingResult processQuadInner(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context) {
int orientation = orientationMode.getOrientation(quad, state);
public ProcessingResult processQuadInner(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context) {
int orientation = orientationMode.getOrientation(quad, appearanceState);
Direction[] directions = DirectionMaps.getMap(quad.lightFace())[orientation];
BlockPos.Mutable mutablePos = context.getData(ProcessingDataKeys.MUTABLE_POS_KEY);
int connections = CtmSpriteProvider.getConnections(connectionPredicate, innerSeams, directions, mutablePos, blockView, state, pos, quad.lightFace(), sprite);
BlockPos.Mutable mutablePos = context.getData(ProcessingDataKeys.MUTABLE_POS);
int connections = CtmSpriteProvider.getConnections(directions, connectionPredicate, innerSeams, mutablePos, blockView, appearanceState, state, pos, quad.lightFace(), sprite);

//

Expand Down Expand Up @@ -157,7 +157,7 @@ public ProcessingResult processQuadInner(MutableQuadView quad, Sprite sprite, Bl
return ProcessingResult.STOP;
}

VertexContainer vertexContainer = context.getData(ProcessingDataKeys.VERTEX_CONTAINER_KEY);
VertexContainer vertexContainer = context.getData(ProcessingDataKeys.VERTEX_CONTAINER);
vertexContainer.fillBaseVertices(quad);

QuadEmitter extraQuadEmitter = context.getExtraQuadEmitter();
Expand Down Expand Up @@ -385,7 +385,7 @@ public ProcessingResult processQuadInner(MutableQuadView quad, Sprite sprite, Bl
spriteIndexB = temp;
}

VertexContainer vertexContainer = context.getData(ProcessingDataKeys.VERTEX_CONTAINER_KEY);
VertexContainer vertexContainer = context.getData(ProcessingDataKeys.VERTEX_CONTAINER);
vertexContainer.fillBaseVertices(quad);

QuadEmitter extraQuadEmitter = context.getExtraQuadEmitter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@
import net.minecraft.world.BlockRenderView;

public interface ConnectionPredicate {
boolean shouldConnect(BlockRenderView blockView, BlockState state, BlockPos pos, BlockState toState, Direction face, Sprite quadSprite);
boolean shouldConnect(BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, BlockState otherAppearanceState, BlockState otherState, BlockPos otherPos, Direction face, Sprite quadSprite);

default boolean shouldConnect(BlockRenderView blockView, BlockState state, BlockPos pos, BlockPos toPos, Direction face, Sprite quadSprite) {
return shouldConnect(blockView, state, pos, blockView.getBlockState(toPos), face, quadSprite);
default boolean shouldConnect(BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, BlockPos otherPos, Direction face, Sprite quadSprite) {
BlockState otherState = blockView.getBlockState(otherPos);
BlockState otherAppearanceState = otherState.getAppearance(blockView, otherPos, face, state, pos);
return shouldConnect(blockView, appearanceState, state, pos, otherAppearanceState, otherState, otherPos, face, quadSprite);
}

default boolean shouldConnect(BlockRenderView blockView, BlockState state, BlockPos pos, BlockPos.Mutable toPos, Direction face, Sprite quadSprite, boolean innerSeams) {
if (shouldConnect(blockView, state, pos, toPos, face, quadSprite)) {
default boolean shouldConnect(BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, BlockPos.Mutable otherPos, Direction face, Sprite quadSprite, boolean innerSeams) {
if (shouldConnect(blockView, appearanceState, state, pos, otherPos, face, quadSprite)) {
if (innerSeams) {
toPos.move(face);
return !shouldConnect(blockView, state, pos, toPos, face, quadSprite);
otherPos.move(face);
return !shouldConnect(blockView, appearanceState, state, pos, otherPos, face, quadSprite);
} else {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
import net.minecraft.util.math.BlockPos;

public final class ProcessingDataKeys {
public static final ProcessingDataKey<BlockPos.Mutable> MUTABLE_POS_KEY = create("mutable_pos", BlockPos.Mutable::new);
public static final ProcessingDataKey<BaseProcessingPredicate.BiomeCache> BIOME_CACHE_KEY = create("biome_cache", BaseProcessingPredicate.BiomeCache::new, BaseProcessingPredicate.BiomeCache::reset);
public static final ProcessingDataKey<BaseProcessingPredicate.BlockEntityNameCache> BLOCK_ENTITY_NAME_CACHE_KEY = create("block_entity_name_cache", BaseProcessingPredicate.BlockEntityNameCache::new, BaseProcessingPredicate.BlockEntityNameCache::reset);
public static final ProcessingDataKey<CompactCtmQuadProcessor.VertexContainer> VERTEX_CONTAINER_KEY = create("vertex_container", CompactCtmQuadProcessor.VertexContainer::new);
public static final ProcessingDataKey<StandardOverlayQuadProcessor.OverlayEmitterPool> STANDARD_OVERLAY_EMITTER_POOL_KEY = create("standard_overlay_emitter_pool", StandardOverlayQuadProcessor.OverlayEmitterPool::new, StandardOverlayQuadProcessor.OverlayEmitterPool::reset);
public static final ProcessingDataKey<SimpleOverlayQuadProcessor.OverlayEmitterPool> SIMPLE_OVERLAY_EMITTER_POOL_KEY = create("simple_overlay_emitter_pool", SimpleOverlayQuadProcessor.OverlayEmitterPool::new, SimpleOverlayQuadProcessor.OverlayEmitterPool::reset);
public static final ProcessingDataKey<BlockPos.Mutable> MUTABLE_POS = create("mutable_pos", BlockPos.Mutable::new);
public static final ProcessingDataKey<BaseProcessingPredicate.BiomeCache> BIOME_CACHE = create("biome_cache", BaseProcessingPredicate.BiomeCache::new, BaseProcessingPredicate.BiomeCache::reset);
public static final ProcessingDataKey<BaseProcessingPredicate.BlockEntityNameCache> BLOCK_ENTITY_NAME_CACHE = create("block_entity_name_cache", BaseProcessingPredicate.BlockEntityNameCache::new, BaseProcessingPredicate.BlockEntityNameCache::reset);
public static final ProcessingDataKey<CompactCtmQuadProcessor.VertexContainer> VERTEX_CONTAINER = create("vertex_container", CompactCtmQuadProcessor.VertexContainer::new);
public static final ProcessingDataKey<StandardOverlayQuadProcessor.OverlayEmitterPool> STANDARD_OVERLAY_EMITTER_POOL = create("standard_overlay_emitter_pool", StandardOverlayQuadProcessor.OverlayEmitterPool::new, StandardOverlayQuadProcessor.OverlayEmitterPool::reset);
public static final ProcessingDataKey<SimpleOverlayQuadProcessor.OverlayEmitterPool> SIMPLE_OVERLAY_EMITTER_POOL = create("simple_overlay_emitter_pool", SimpleOverlayQuadProcessor.OverlayEmitterPool::new, SimpleOverlayQuadProcessor.OverlayEmitterPool::reset);

private static <T> ProcessingDataKey<T> create(String id, Supplier<T> valueSupplier) {
return ProcessingDataKeyRegistry.get().registerKey(ContinuityClient.asId(id), valueSupplier);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
import net.minecraft.world.BlockRenderView;

public interface ProcessingPredicate {
boolean shouldProcessQuad(QuadView quad, Sprite sprite, BlockRenderView blockView, BlockState state, BlockPos pos, ProcessingDataProvider dataProvider);
boolean shouldProcessQuad(QuadView quad, Sprite sprite, BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, ProcessingDataProvider dataProvider);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ public TopQuadProcessor(Sprite[] sprites, ProcessingPredicate processingPredicat
}

@Override
public ProcessingResult processQuadInner(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context) {
public ProcessingResult processQuadInner(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context) {
Direction lightFace = quad.lightFace();
Direction.Axis axis;
if (state.contains(Properties.AXIS)) {
axis = state.get(Properties.AXIS);
if (appearanceState.contains(Properties.AXIS)) {
axis = appearanceState.get(Properties.AXIS);
} else {
axis = Direction.Axis.Y;
}
if (lightFace.getAxis() != axis) {
Direction up = Direction.from(axis, Direction.AxisDirection.POSITIVE);
BlockPos.Mutable mutablePos = context.getData(ProcessingDataKeys.MUTABLE_POS_KEY).set(pos, up);
if (connectionPredicate.shouldConnect(blockView, state, pos, mutablePos, lightFace, sprite, innerSeams)) {
BlockPos.Mutable mutablePos = context.getData(ProcessingDataKeys.MUTABLE_POS).set(pos, up);
if (connectionPredicate.shouldConnect(blockView, appearanceState, state, pos, mutablePos, lightFace, sprite, innerSeams)) {
return SimpleQuadProcessor.process(quad, sprite, sprites[0]);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public OverlayProcessingPredicate(@Nullable EnumSet<Direction> faces, @Nullable
}

@Override
public boolean shouldProcessQuad(QuadView quad, Sprite sprite, BlockRenderView blockView, BlockState state, BlockPos pos, ProcessingDataProvider dataProvider) {
if (!super.shouldProcessQuad(quad, sprite, blockView, state, pos, dataProvider)) {
public boolean shouldProcessQuad(QuadView quad, Sprite sprite, BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, ProcessingDataProvider dataProvider) {
if (!super.shouldProcessQuad(quad, sprite, blockView, appearanceState, state, pos, dataProvider)) {
return false;
}
return QuadUtil.isQuadUnitSquare(quad);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ public SimpleOverlayQuadProcessor(SpriteProvider spriteProvider, ProcessingPredi
}

@Override
public ProcessingResult processQuad(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context) {
if (processingPredicate.shouldProcessQuad(quad, sprite, blockView, state, pos, context)) {
Sprite newSprite = spriteProvider.getSprite(quad, sprite, blockView, state, pos, randomSupplier, context);
public ProcessingResult processQuad(MutableQuadView quad, Sprite sprite, BlockRenderView blockView, BlockState appearanceState, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, int pass, ProcessingContext context) {
if (processingPredicate.shouldProcessQuad(quad, sprite, blockView, appearanceState, state, pos, context)) {
Sprite newSprite = spriteProvider.getSprite(quad, sprite, blockView, appearanceState, state, pos, randomSupplier, context);
if (newSprite != null && !TextureUtil.isMissingSprite(newSprite)) {
OverlayEmitter emitter = context.getData(ProcessingDataKeys.SIMPLE_OVERLAY_EMITTER_POOL_KEY).get();
OverlayEmitter emitter = context.getData(ProcessingDataKeys.SIMPLE_OVERLAY_EMITTER_POOL).get();
emitter.prepare(quad.lightFace(), newSprite, RenderUtil.getTintColor(tintBlock, blockView, pos, tintIndex), material);
context.addEmitterConsumer(emitter);
}
Expand Down
Loading

0 comments on commit b055564

Please sign in to comment.