Connect-a-block

- Properly integrate both copycat blocks and the connected texture system with forge's built-in 'facade' api
This commit is contained in:
simibubi 2023-05-09 17:40:55 +02:00
parent f201e26f6b
commit 7b00608744
6 changed files with 179 additions and 126 deletions

View file

@ -48,6 +48,7 @@ import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.model.data.ModelDataManager;
public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEntity>, IWrenchable { public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEntity>, IWrenchable {
@ -161,7 +162,7 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
@Nullable @Nullable
public BlockState getAcceptedBlockState(Level pLevel, BlockPos pPos, ItemStack item, Direction face) { public BlockState getAcceptedBlockState(Level pLevel, BlockPos pPos, ItemStack item, Direction face) {
if (!(item.getItem()instanceof BlockItem bi)) if (!(item.getItem() instanceof BlockItem bi))
return null; return null;
Block block = bi.getBlock(); Block block = bi.getBlock();
@ -244,24 +245,18 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
// Connected Textures // Connected Textures
@Nullable @Override
/** @OnlyIn(Dist.CLIENT)
* The wrapped blockstate at toPos. Wrapper guaranteed to be a block of this public BlockState getAppearance(BlockState state, BlockAndTintGetter level, BlockPos pos, Direction side,
* type <br> BlockState queryState, BlockPos queryPos) {
* Return null if the 'from' state shouldn't connect to this block/face
*
* @param from
* @param reader
* @param targetPos
* @param face
* @return
*/
public abstract BlockState getConnectiveMaterial(BlockAndTintGetter reader, BlockState otherState, Direction face,
BlockPos fromPos, BlockPos toPos);
public boolean isUnblockableConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, if (isIgnoredConnectivitySide(level, state, side, pos, queryPos))
BlockPos fromPos, BlockPos toPos) { return state;
return false;
ModelDataManager modelDataManager = level.getModelDataManager();
if (modelDataManager == null)
return getMaterial(level, pos);
return CopycatModel.getMaterial(modelDataManager.getAt(pos));
} }
public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
@ -269,8 +264,13 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
return false; return false;
} }
public abstract boolean canConnectTexturesToward(BlockAndTintGetter reader, BlockPos fromPos, BlockPos toPos,
BlockState state);
//
public static BlockState getMaterial(BlockGetter reader, BlockPos targetPos) { public static BlockState getMaterial(BlockGetter reader, BlockPos targetPos) {
if (reader.getBlockEntity(targetPos)instanceof CopycatBlockEntity ufte) if (reader.getBlockEntity(targetPos) instanceof CopycatBlockEntity ufte)
return ufte.getMaterial(); return ufte.getMaterial();
return Blocks.AIR.defaultBlockState(); return Blocks.AIR.defaultBlockState();
} }
@ -278,7 +278,7 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
public boolean canFaceBeOccluded(BlockState state, Direction face) { public boolean canFaceBeOccluded(BlockState state, Direction face) {
return false; return false;
} }
public boolean shouldFaceAlwaysRender(BlockState state, Direction face) { public boolean shouldFaceAlwaysRender(BlockState state, Direction face) {
return false; return false;
} }

View file

@ -44,13 +44,17 @@ public abstract class CopycatModel extends BakedModelWrapperWithData {
builder.with(MATERIAL_PROPERTY, material); builder.with(MATERIAL_PROPERTY, material);
OcclusionData occlusionData = new OcclusionData(); if (!(state.getBlock() instanceof CopycatBlock copycatBlock))
if (state.getBlock() instanceof CopycatBlock copycatBlock) { return builder;
gatherOcclusionData(world, pos, state, material, occlusionData, copycatBlock);
builder.with(OCCLUSION_PROPERTY, occlusionData);
}
ModelData wrappedData = getModelOf(material).getModelData(world, pos, material, ModelData.EMPTY); OcclusionData occlusionData = new OcclusionData();
gatherOcclusionData(world, pos, state, material, occlusionData, copycatBlock);
builder.with(OCCLUSION_PROPERTY, occlusionData);
ModelData wrappedData = getModelOf(material).getModelData(
new FilteredBlockAndTintGetter(world,
targetPos -> copycatBlock.canConnectTexturesToward(world, pos, targetPos, state)),
pos, material, ModelData.EMPTY);
return builder.with(WRAPPED_DATA_PROPERTY, wrappedData); return builder.with(WRAPPED_DATA_PROPERTY, wrappedData);
} }

View file

@ -88,12 +88,6 @@ public class CopycatPanelBlock extends WaterloggedCopycatBlock {
return super.use(state, world, pos, player, hand, ray); return super.use(state, world, pos, player, hand, ray);
} }
@Override
public boolean isUnblockableConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) {
return true;
}
@Override @Override
public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) { BlockPos fromPos, BlockPos toPos) {
@ -112,6 +106,31 @@ public class CopycatPanelBlock extends WaterloggedCopycatBlock {
.getStep()); .getStep());
} }
@Override
public boolean canConnectTexturesToward(BlockAndTintGetter reader, BlockPos fromPos, BlockPos toPos,
BlockState state) {
Direction facing = state.getValue(FACING);
BlockState toState = reader.getBlockState(toPos);
if (toPos.equals(fromPos.relative(facing)))
return false;
BlockPos diff = fromPos.subtract(toPos);
int coord = facing.getAxis()
.choose(diff.getX(), diff.getY(), diff.getZ());
if (!toState.is(this))
return coord != -facing.getAxisDirection()
.getStep();
if (isOccluded(state, toState, facing))
return true;
if (toState.setValue(WATERLOGGED, false) == state.setValue(WATERLOGGED, false) && coord == 0)
return true;
return false;
}
@Override @Override
public boolean canFaceBeOccluded(BlockState state, Direction face) { public boolean canFaceBeOccluded(BlockState state, Direction face) {
return state.getValue(FACING) return state.getValue(FACING)
@ -123,28 +142,6 @@ public class CopycatPanelBlock extends WaterloggedCopycatBlock {
return canFaceBeOccluded(state, face.getOpposite()); return canFaceBeOccluded(state, face.getOpposite());
} }
@Override
public BlockState getConnectiveMaterial(BlockAndTintGetter reader, BlockState otherState, Direction face,
BlockPos fromPos, BlockPos toPos) {
BlockState panelState = reader.getBlockState(toPos);
Direction facing = panelState.getValue(FACING);
if (!otherState.is(this))
return facing == face.getOpposite() ? getMaterial(reader, toPos) : null;
if (isOccluded(panelState, otherState, facing))
return getMaterial(reader, toPos);
BlockPos diff = fromPos.subtract(toPos);
int coord = facing.getAxis()
.choose(diff.getX(), diff.getY(), diff.getZ());
if (otherState.setValue(WATERLOGGED, false) == panelState.setValue(WATERLOGGED, false) && coord == 0)
return getMaterial(reader, toPos);
return null;
}
@Override @Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) { public BlockState getStateForPlacement(BlockPlaceContext pContext) {
BlockState stateForPlacement = super.getStateForPlacement(pContext); BlockState stateForPlacement = super.getStateForPlacement(pContext);

View file

@ -4,7 +4,6 @@ import java.util.function.Predicate;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes; import com.simibubi.create.AllShapes;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VoxelShaper; import com.simibubi.create.foundation.utility.VoxelShaper;
import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
@ -64,54 +63,13 @@ public class CopycatStepBlock extends WaterloggedCopycatBlock {
return super.use(state, world, pos, player, hand, ray); return super.use(state, world, pos, player, hand, ray);
} }
@Override
public BlockState getConnectiveMaterial(BlockAndTintGetter reader, BlockState otherState, Direction face,
BlockPos fromPos, BlockPos toPos) {
if (!otherState.is(this))
return null;
BlockState stepState = reader.getBlockState(toPos);
Direction facing = stepState.getValue(FACING);
BlockPos diff = fromPos.subtract(toPos);
if (diff.getY() != 0) {
if (isOccluded(stepState, otherState, diff.getY() > 0 ? Direction.UP : Direction.DOWN))
return getMaterial(reader, toPos);
return null;
}
if (isOccluded(stepState, otherState, facing))
return getMaterial(reader, toPos);
int coord = facing.getAxis()
.choose(diff.getX(), diff.getY(), diff.getZ());
if (otherState.setValue(WATERLOGGED, false) == stepState.setValue(WATERLOGGED, false) && coord == 0)
return getMaterial(reader, toPos);
return null;
}
@Override
public boolean isUnblockableConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) {
return true;
}
@Override @Override
public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) { BlockPos fromPos, BlockPos toPos) {
BlockState toState = reader.getBlockState(toPos); BlockState toState = reader.getBlockState(toPos);
if (!toState.is(this)) { if (!toState.is(this))
if (!canFaceBeOccluded(state, face.getOpposite())) return true;
return true;
for (Direction d : Iterate.directions)
if (fromPos.relative(d)
.equals(toPos) && !canFaceBeOccluded(state, d))
return true;
return false;
}
Direction facing = state.getValue(FACING); Direction facing = state.getValue(FACING);
BlockPos diff = fromPos.subtract(toPos); BlockPos diff = fromPos.subtract(toPos);
@ -128,13 +86,42 @@ public class CopycatStepBlock extends WaterloggedCopycatBlock {
.getStep()); .getStep());
} }
@Override
public boolean canConnectTexturesToward(BlockAndTintGetter reader, BlockPos fromPos, BlockPos toPos,
BlockState state) {
Direction facing = state.getValue(FACING);
BlockState toState = reader.getBlockState(toPos);
BlockPos diff = fromPos.subtract(toPos);
if (fromPos.equals(toPos.relative(facing)))
return false;
if (!toState.is(this))
return false;
if (diff.getY() != 0) {
if (isOccluded(toState, state, diff.getY() > 0 ? Direction.UP : Direction.DOWN))
return true;
return false;
}
if (isOccluded(state, toState, facing))
return true;
int coord = facing.getAxis()
.choose(diff.getX(), diff.getY(), diff.getZ());
if (state.setValue(WATERLOGGED, false) == toState.setValue(WATERLOGGED, false) && coord == 0)
return true;
return false;
}
@Override @Override
public boolean canFaceBeOccluded(BlockState state, Direction face) { public boolean canFaceBeOccluded(BlockState state, Direction face) {
if (face.getAxis() == Axis.Y) if (face.getAxis() == Axis.Y)
return (state.getValue(HALF) == Half.TOP) == (face == Direction.UP); return (state.getValue(HALF) == Half.TOP) == (face == Direction.UP);
return state.getValue(FACING) == face; return state.getValue(FACING) == face;
} }
@Override @Override
public boolean shouldFaceAlwaysRender(BlockState state, Direction face) { public boolean shouldFaceAlwaysRender(BlockState state, Direction face) {
return canFaceBeOccluded(state, face.getOpposite()); return canFaceBeOccluded(state, face.getOpposite());

View file

@ -0,0 +1,74 @@
package com.simibubi.create.content.curiosities.frames;
import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.client.model.data.ModelDataManager;
public class FilteredBlockAndTintGetter implements BlockAndTintGetter {
private BlockAndTintGetter wrapped;
private Predicate<BlockPos> filter;
public FilteredBlockAndTintGetter(BlockAndTintGetter wrapped, Predicate<BlockPos> filter) {
this.wrapped = wrapped;
this.filter = filter;
}
@Override
public BlockEntity getBlockEntity(BlockPos pPos) {
return filter.test(pPos) ? wrapped.getBlockEntity(pPos) : null;
}
@Override
public BlockState getBlockState(BlockPos pPos) {
return filter.test(pPos) ? wrapped.getBlockState(pPos) : Blocks.AIR.defaultBlockState();
}
@Override
public FluidState getFluidState(BlockPos pPos) {
return filter.test(pPos) ? wrapped.getFluidState(pPos) : Fluids.EMPTY.defaultFluidState();
}
@Override
public int getHeight() {
return wrapped.getHeight();
}
@Override
public int getMinBuildHeight() {
return wrapped.getMinBuildHeight();
}
@Override
public float getShade(Direction pDirection, boolean pShade) {
return wrapped.getShade(pDirection, pShade);
}
@Override
public LevelLightEngine getLightEngine() {
return wrapped.getLightEngine();
}
@Override
public int getBlockTint(BlockPos pBlockPos, ColorResolver pColorResolver) {
return wrapped.getBlockTint(pBlockPos, pColorResolver);
}
@Override
public @Nullable ModelDataManager getModelDataManager() {
return wrapped.getModelDataManager();
}
}

View file

@ -3,14 +3,13 @@ package com.simibubi.create.foundation.block.connected;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.simibubi.create.content.curiosities.frames.CopycatBlock;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection; import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public abstract class ConnectedTextureBehaviour { public abstract class ConnectedTextureBehaviour {
@ -31,17 +30,18 @@ public abstract class ConnectedTextureBehaviour {
Direction face) { Direction face) {
BlockPos blockingPos = otherPos.relative(face); BlockPos blockingPos = otherPos.relative(face);
BlockState blockState = reader.getBlockState(pos); BlockState blockState = reader.getBlockState(pos);
BlockState blockingState = reader.getBlockState(blockingPos);
if (blockState.getBlock() instanceof CopycatBlock ufb if (!Block.isFaceFull(blockingState.getShape(reader, blockingPos), face.getOpposite()))
&& ufb.isUnblockableConnectivitySide(reader, blockState, face, pos, otherPos)) return false;
if (face.getAxis()
.choose(pos.getX(), pos.getY(), pos.getZ()) != face.getAxis()
.choose(otherPos.getX(), otherPos.getY(), otherPos.getZ()))
return false; return false;
return face.getAxis() return connectsTo(state,
.choose(pos.getX(), pos.getY(), pos.getZ()) == face.getAxis() getCTBlockState(reader, blockState, face.getOpposite(), pos.relative(face), blockingPos), reader, pos,
.choose(otherPos.getX(), otherPos.getY(), otherPos.getZ()) blockingPos, face);
&& connectsTo(state,
getCTBlockState(reader, blockState, face.getOpposite(), pos.relative(face), blockingPos), reader, pos,
blockingPos, face);
} }
public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos,
@ -54,17 +54,14 @@ public abstract class ConnectedTextureBehaviour {
return !isBeingBlocked(state, reader, pos, otherPos, face) && state.getBlock() == other.getBlock(); return !isBeingBlocked(state, reader, pos, otherPos, face) && state.getBlock() == other.getBlock();
} }
private boolean testConnection(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face, private boolean testConnection(BlockAndTintGetter reader, BlockPos currentPos, BlockState connectiveCurrentState,
final Direction horizontal, final Direction vertical, int sh, int sv) { Direction textureSide, final Direction horizontal, final Direction vertical, int sh, int sv) {
BlockPos p = pos.relative(horizontal, sh) BlockState trueCurrentState = reader.getBlockState(currentPos);
BlockPos targetPos = currentPos.relative(horizontal, sh)
.relative(vertical, sv); .relative(vertical, sv);
BlockState blockState = reader.getBlockState(pos); BlockState connectiveTargetState =
getCTBlockState(reader, trueCurrentState, textureSide, currentPos, targetPos);
if (blockState.getBlock() instanceof CopycatBlock ufb return connectsTo(connectiveCurrentState, connectiveTargetState, reader, currentPos, targetPos, textureSide,
&& ufb.isIgnoredConnectivitySide(reader, blockState, face, pos, p))
return false;
return connectsTo(state, getCTBlockState(reader, blockState, face, pos, p), reader, pos, p, face,
sh == 0 ? null : sh == -1 ? horizontal.getOpposite() : horizontal, sh == 0 ? null : sh == -1 ? horizontal.getOpposite() : horizontal,
sv == 0 ? null : sv == -1 ? vertical.getOpposite() : vertical); sv == 0 ? null : sv == -1 ? vertical.getOpposite() : vertical);
} }
@ -72,13 +69,7 @@ public abstract class ConnectedTextureBehaviour {
public BlockState getCTBlockState(BlockAndTintGetter reader, BlockState reference, Direction face, BlockPos fromPos, public BlockState getCTBlockState(BlockAndTintGetter reader, BlockState reference, Direction face, BlockPos fromPos,
BlockPos toPos) { BlockPos toPos) {
BlockState blockState = reader.getBlockState(toPos); BlockState blockState = reader.getBlockState(toPos);
return blockState.getAppearance(reader, toPos, face, reference, fromPos);
if (blockState.getBlock() instanceof CopycatBlock ufb) {
BlockState connectiveMaterial = ufb.getConnectiveMaterial(reader, reference, face, fromPos, toPos);
return connectiveMaterial == null ? blockState : connectiveMaterial;
}
return blockState;
} }
protected boolean reverseUVs(BlockState state, Direction face) { protected boolean reverseUVs(BlockState state, Direction face) {