Shingle all the ways

- Copper roof blocks now have custom CT behaviour on the top faces. Assets pending
This commit is contained in:
simibubi 2025-01-05 19:24:24 +01:00
parent 72d3fa6991
commit 61369923e1
13 changed files with 235 additions and 7 deletions

View file

@ -58,6 +58,7 @@ import com.simibubi.create.content.decoration.CardboardBlock;
import com.simibubi.create.content.decoration.CardboardBlockItem;
import com.simibubi.create.content.decoration.MetalLadderBlock;
import com.simibubi.create.content.decoration.MetalScaffoldingBlock;
import com.simibubi.create.content.decoration.RoofBlockCTBehaviour;
import com.simibubi.create.content.decoration.TrainTrapdoorBlock;
import com.simibubi.create.content.decoration.TrapdoorCTBehaviour;
import com.simibubi.create.content.decoration.bracket.BracketBlock;
@ -2661,13 +2662,15 @@ public class AllBlocks {
"copper_roof_top", CopperBlockSet.DEFAULT_VARIANTS, (c, p) -> {
p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("ingots/copper")), RecipeCategory.BUILDING_BLOCKS,
c::get, 2);
});
}, (ws, block) -> connectedTextures(() -> new RoofBlockCTBehaviour(AllSpriteShifts.COPPER_SHINGLES.get(ws)))
.accept(block));
public static final CopperBlockSet COPPER_TILES =
new CopperBlockSet(REGISTRATE, "copper_tiles", "copper_roof_top", CopperBlockSet.DEFAULT_VARIANTS, (c, p) -> {
p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("ingots/copper")), RecipeCategory.BUILDING_BLOCKS,
c::get, 2);
});
}, (ws, block) -> connectedTextures(() -> new RoofBlockCTBehaviour(AllSpriteShifts.COPPER_TILES.get(ws)))
.accept(block));
// Load this class

View file

@ -13,12 +13,16 @@ import com.simibubi.create.foundation.block.connected.CTType;
import net.createmod.catnip.render.SpriteShiftEntry;
import net.createmod.catnip.render.SpriteShifter;
import net.createmod.catnip.utility.Couple;
import net.createmod.catnip.utility.lang.Lang;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.block.WeatheringCopper.WeatherState;
import net.minecraft.world.level.block.state.properties.WoodType;
public class AllSpriteShifts {
private static final Map<WoodType, CTSpriteShiftEntry> WOODEN_WINDOWS = new IdentityHashMap<>();
public static final Map<WeatherState, CTSpriteShiftEntry> COPPER_SHINGLES = new EnumMap<>(WeatherState.class);
public static final Map<WeatherState, CTSpriteShiftEntry> COPPER_TILES = new EnumMap<>(WeatherState.class);
public static final Map<DyeColor, SpriteShiftEntry> DYED_BELTS = new EnumMap<>(DyeColor.class),
DYED_OFFSET_BELTS = new EnumMap<>(DyeColor.class), DYED_DIAGONAL_BELTS = new EnumMap<>(DyeColor.class);
@ -107,6 +111,12 @@ public class AllSpriteShifts {
DYED_OFFSET_BELTS.put(color, get("block/belt_offset", "block/belt/" + id + "_scroll"));
DYED_DIAGONAL_BELTS.put(color, get("block/belt_diagonal", "block/belt/" + id + "_diagonal_scroll"));
}
for (WeatherState state : WeatherState.values()) {
String pref = "copper/" + (state == WeatherState.UNAFFECTED ? "" : Lang.asId(state.name()) + "_");
COPPER_SHINGLES.put(state, getCT(AllCTTypes.ROOF, pref + "copper_roof_top", pref + "copper_shingles_top"));
COPPER_TILES.put(state, getCT(AllCTTypes.ROOF, pref + "copper_roof_top", pref + "copper_tiles_top"));
}
}
private static Couple<CTSpriteShiftEntry> vault(String name) {
@ -150,5 +160,5 @@ public class AllSpriteShifts {
public static CTSpriteShiftEntry getWoodenWindow(WoodType woodType) {
return WOODEN_WINDOWS.get(woodType);
}
}

View file

@ -0,0 +1,142 @@
package com.simibubi.create.content.decoration;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.foundation.block.connected.AllCTTypes;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.CTType;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour;
import net.createmod.catnip.utility.Iterate;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.util.Mth;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.SlabBlock;
import net.minecraft.world.level.block.StairBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Half;
import net.minecraft.world.level.block.state.properties.SlabType;
import net.minecraft.world.level.block.state.properties.StairsShape;
public class RoofBlockCTBehaviour extends ConnectedTextureBehaviour.Base {
private CTSpriteShiftEntry shift;
public RoofBlockCTBehaviour(CTSpriteShiftEntry shift) {
this.shift = shift;
}
@Override
public @Nullable CTSpriteShiftEntry getShift(BlockState state, Direction direction,
@Nullable TextureAtlasSprite sprite) {
if (direction == Direction.UP)
return shift;
return null;
}
@Override
public boolean buildContextForOccludedDirections() {
return true;
}
@Override
public CTContext buildContext(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face,
ContextRequirement requirement) {
if (isUprightStair(state))
return getStairMapping(state);
return super.buildContext(reader, pos, state, face, requirement);
}
@Override
public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos,
BlockPos otherPos, Direction face, Direction primaryOffset, Direction secondaryOffset) {
if (connects(reader, pos, state, other)
|| connectsHigh(reader, pos, state, other, reader.getBlockState(otherPos.above())))
return true;
if (primaryOffset != null && secondaryOffset != null)
return false;
for (boolean p : Iterate.trueAndFalse) {
Direction offset = p ? primaryOffset : secondaryOffset;
if (offset == null)
continue;
if (offset.getAxis()
.isVertical())
continue;
if (connectsHigh(reader, pos, state, reader.getBlockState(pos.relative(offset.getClockWise())),
reader.getBlockState(pos.relative(offset.getClockWise())
.above()))
|| connectsHigh(reader, pos, state, reader.getBlockState(pos.relative(offset.getCounterClockWise())),
reader.getBlockState(pos.relative(offset.getCounterClockWise())
.above())))
return true;
}
return false;
}
public boolean isUprightStair(BlockState state) {
return state.hasProperty(StairBlock.SHAPE) && state.getOptionalValue(StairBlock.HALF)
.orElse(Half.TOP) == Half.BOTTOM;
}
public CTContext getStairMapping(BlockState state) {
CTContext context = new CTContext();
StairsShape shape = state.getValue(StairBlock.SHAPE);
Direction facing = state.getValue(StairBlock.FACING);
if (shape == StairsShape.OUTER_LEFT)
facing = facing.getCounterClockWise();
if (shape == StairsShape.INNER_LEFT)
facing = facing.getCounterClockWise();
int type = shape == StairsShape.STRAIGHT ? 0
: (shape == StairsShape.INNER_LEFT || shape == StairsShape.INNER_RIGHT) ? 1 : 2;
int rot = facing.get2DDataValue();
context.up = type >= 2;
context.right = type % 2 == 1;
context.left = rot >= 2;
context.down = rot % 2 == 1;
return context;
}
protected boolean connects(BlockAndTintGetter reader, BlockPos pos, BlockState state, BlockState other) {
double top = state.getCollisionShape(reader, pos)
.max(Axis.Y);
double topOther = other.getCollisionShape(reader, pos)
.max(Axis.Y);
return Mth.equal(top, topOther);
}
protected boolean connectsHigh(BlockAndTintGetter reader, BlockPos pos, BlockState state, BlockState other,
BlockState aboveOther) {
if (state.getBlock() instanceof SlabBlock && other.getBlock() instanceof SlabBlock)
if (state.getValue(SlabBlock.TYPE) == SlabType.BOTTOM && other.getValue(SlabBlock.TYPE) != SlabType.BOTTOM)
return true;
if (state.getBlock() instanceof SlabBlock && state.getValue(SlabBlock.TYPE) == SlabType.BOTTOM) {
double top = state.getCollisionShape(reader, pos)
.max(Axis.Y);
double topOther = other.getCollisionShape(reader, pos)
.max(Axis.Y);
return !Mth.equal(top, topOther) && topOther > top;
}
double topAboveOther = aboveOther.getCollisionShape(reader, pos)
.max(Axis.Y);
return topAboveOther > 0;
}
@Override
public @Nullable CTType getDataType(BlockAndTintGetter world, BlockPos pos, BlockState state, Direction direction) {
return isUprightStair(state) ? AllCTTypes.ROOF_STAIR : AllCTTypes.ROOF;
}
}

View file

@ -63,26 +63,33 @@ public class CopperBlockSet {
protected final Map<Variant<?>, BlockEntry<?>[]> entries = new HashMap<>();
protected final NonNullBiConsumer<DataGenContext<Block, ?>, RegistrateRecipeProvider> mainBlockRecipe;
protected final String endTextureName;
protected final NonNullBiConsumer<WeatherState, Block> onRegister;
public CopperBlockSet(AbstractRegistrate<?> registrate, String name, String endTextureName, Variant<?>[] variants) {
this(registrate, name, endTextureName, variants, NonNullBiConsumer.noop(), "copper/");
this(registrate, name, endTextureName, variants, NonNullBiConsumer.noop(), "copper/", NonNullBiConsumer.noop());
}
public CopperBlockSet(AbstractRegistrate<?> registrate, String name, String endTextureName, Variant<?>[] variants, String generalDirectory) {
this(registrate, name, endTextureName, variants, NonNullBiConsumer.noop(), generalDirectory);
this(registrate, name, endTextureName, variants, NonNullBiConsumer.noop(), generalDirectory, NonNullBiConsumer.noop());
}
public CopperBlockSet(AbstractRegistrate<?> registrate, String name, String endTextureName, Variant<?>[] variants, NonNullBiConsumer<DataGenContext<Block, ?>, RegistrateRecipeProvider> mainBlockRecipe) {
this(registrate, name, endTextureName, variants, mainBlockRecipe, "copper/");
this(registrate, name, endTextureName, variants, mainBlockRecipe, "copper/", NonNullBiConsumer.noop());
}
public CopperBlockSet(AbstractRegistrate<?> registrate, String name, String endTextureName, Variant<?>[] variants, NonNullBiConsumer<DataGenContext<Block, ?>, RegistrateRecipeProvider> mainBlockRecipe, NonNullBiConsumer<WeatherState, Block> onRegister) {
this(registrate, name, endTextureName, variants, mainBlockRecipe, "copper/", onRegister);
}
public CopperBlockSet(AbstractRegistrate<?> registrate, String name, String endTextureName, Variant<?>[] variants,
NonNullBiConsumer<DataGenContext<Block, ?>, RegistrateRecipeProvider> mainBlockRecipe, String generalDirectory) {
NonNullBiConsumer<DataGenContext<Block, ?>, RegistrateRecipeProvider> mainBlockRecipe, String generalDirectory, NonNullBiConsumer<WeatherState, Block> onRegister) {
this.name = name;
this.generalDirectory = generalDirectory;
this.endTextureName = endTextureName;
this.variants = variants;
this.mainBlockRecipe = mainBlockRecipe;
this.onRegister = onRegister;
for (boolean waxed : Iterate.falseAndTrue) {
for (Variant<?> variant : this.variants) {
BlockEntry<?>[] entries =
@ -128,6 +135,7 @@ public class CopperBlockSet {
.blockstate((ctx, prov) -> variant.generateBlockState(ctx, prov, this, state, waxed))
.recipe((c, p) -> variant.generateRecipes(entries.get(BlockVariant.INSTANCE)[state.ordinal()], c, p))
.transform(TagGen.pickaxeOnly())
.onRegister(block -> onRegister.accept(state, block))
.tag(BlockTags.NEEDS_STONE_TOOL)
.simpleItem();

View file

@ -89,6 +89,71 @@ public enum AllCTTypes implements CTType {
return tileX + 8 * tileY;
}
},
ROOF(4, ContextRequirement.builder().all().build()) {
@Override
public int getTextureIndex(CTContext context) {
boolean upDrops = context.down && !context.up && (context.left || context.right);
boolean downDrops = !context.down && context.up && (context.left || context.right);
boolean leftDrops = !context.left && context.right && (context.up || context.down);
boolean rightDrops = context.left && !context.right && (context.up || context.down);
if (upDrops) {
if (leftDrops)
return context.bottomRight ? 0 : 5;
if (rightDrops)
return context.bottomLeft ? 2 : 5;
return 1;
}
if (downDrops) {
if (leftDrops)
return context.topRight ? 8 : 5;
if (rightDrops)
return context.topLeft ? 10 : 5;
return 9;
}
if (leftDrops)
return 4;
if (rightDrops)
return 6;
if (!context.up || !context.down || !context.left || !context.right)
return 5;
if (context.bottomLeft && context.topRight) {
if (context.topLeft && !context.bottomRight)
return 12;
if (context.bottomRight && !context.topLeft)
return 15;
if (!context.bottomRight && !context.topLeft)
return 7;
}
if (context.bottomRight && context.topLeft) {
if (context.topRight && !context.bottomLeft)
return 13;
if (context.bottomLeft && !context.topRight)
return 14;
if (!context.bottomLeft && !context.topRight)
return 11;
}
return 5;
}
},
ROOF_STAIR(4, ContextRequirement.builder()
.axisAligned()
.build()) {
private static final int[][] MAPPING = { { 1, 6, 9, 4 }, { 14, 12, 13, 15 }, { 2, 10, 8, 0 }, { 5, 5, 5, 5 } };
@Override
public int getTextureIndex(CTContext context) {
int type = (context.up ? 2 : 0) + (context.right ? 1 : 0);
int rot = (context.left ? 2 : 0) + (context.down ? 1 : 0);
return MAPPING[type][rot];
}
},
CROSS(4, ContextRequirement.builder().axisAligned().build()) {
@Override
public int getTextureIndex(CTContext context) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB