Sprites and CT - Except it works

- Added a few new sprites for crafting ingredients
- Reworked the Connected Texture system
- Added Limestone Layers to test custom CT spriteshifts
- Migrated existing CT blocks to use the new system
- Crushing wheel controllers no longer crash when in a schematic
This commit is contained in:
simibubi 2020-01-13 21:59:26 +01:00
parent 7ff524f616
commit 07ef48fefb
25 changed files with 219 additions and 220 deletions

View file

@ -7,6 +7,8 @@ import com.simibubi.create.foundation.block.ProperStairsBlock;
import com.simibubi.create.foundation.block.RenderUtilityAxisBlock;
import com.simibubi.create.foundation.block.RenderUtilityBlock;
import com.simibubi.create.foundation.block.RenderUtilityDirectionalBlock;
import com.simibubi.create.foundation.block.connected.CTSpriteShifter;
import com.simibubi.create.foundation.block.connected.CTSpriteShifter.CTType;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.world.CopperOreBlock;
import com.simibubi.create.modules.IModule;
@ -69,6 +71,7 @@ import com.simibubi.create.modules.logistics.transport.villager.LogisticiansTabl
import com.simibubi.create.modules.logistics.transport.villager.PackageFunnelBlock;
import com.simibubi.create.modules.palettes.CTGlassBlock;
import com.simibubi.create.modules.palettes.GlassPaneBlock;
import com.simibubi.create.modules.palettes.LayeredCTBlock;
import com.simibubi.create.modules.palettes.VolcanicRockBlock;
import com.simibubi.create.modules.schematics.block.CreativeCrateBlock;
import com.simibubi.create.modules.schematics.block.SchematicTableBlock;
@ -222,11 +225,12 @@ public enum AllBlocks {
LIMESTONE_BRICKS(new Block(Properties.from(LIMESTONE.block)), ComesWith.STAIRS, ComesWith.SLAB, ComesWith.WALL),
POLISHED_LIMESTONE(new Block(Properties.from(LIMESTONE.block)), ComesWith.SLAB),
LIMESTONE_PILLAR(new RotatedPillarBlock(Properties.from(LIMESTONE.block))),
LIMESTONE_LAYERS(
new LayeredCTBlock(Properties.from(LIMESTONE.block),
CTSpriteShifter.get(CTType.HORIZONTAL, "limestone_layers"),
CTSpriteShifter.get(CTType.OMNIDIRECTIONAL, "polished_limestone"))),
WEATHERED_LIMESTONE(new Block(Properties.from(Blocks.ANDESITE)), ComesWith.STAIRS, ComesWith.SLAB, ComesWith.WALL),
WEATHERED_LIMESTONE_BRICKS(
new Block(Properties.from(WEATHERED_LIMESTONE.block)),
ComesWith.STAIRS,
ComesWith.SLAB,
WEATHERED_LIMESTONE_BRICKS(new Block(Properties.from(WEATHERED_LIMESTONE.block)), ComesWith.STAIRS, ComesWith.SLAB,
ComesWith.WALL),
POLISHED_WEATHERED_LIMESTONE(new Block(Properties.from(WEATHERED_LIMESTONE.block)), ComesWith.SLAB),
WEATHERED_LIMESTONE_PILLAR(new RotatedPillarBlock(Properties.from(WEATHERED_LIMESTONE.block))),

View file

@ -109,9 +109,10 @@ public class CreateClient {
Block block = allBlocks.get();
if (!(block instanceof IHaveConnectedTextures))
continue;
for (SpriteShiftEntry spriteShiftEntry : ((IHaveConnectedTextures) block).getSpriteShifts())
for (SpriteShiftEntry spriteShiftEntry : ((IHaveConnectedTextures) block).getBehaviour().getAllCTShifts())
event.addSprite(spriteShiftEntry.getTargetResourceLocation());
}
}
@OnlyIn(Dist.CLIENT)

View file

@ -5,7 +5,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Random;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour.CTContext;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@ -24,28 +24,28 @@ import net.minecraftforge.client.model.data.ModelProperty;
public class CTModel extends BakedModelWrapper<IBakedModel> {
private static ModelProperty<CTData> CT_PROPERTY = new ModelProperty<>();
private Iterable<SpriteShiftEntry> textures;
private ConnectedTextureBehaviour behaviour;
private class CTData {
int[] textures;
int[] indices;
public CTData() {
textures = new int[6];
Arrays.fill(textures, -1);
indices = new int[6];
Arrays.fill(indices, -1);
}
void put(Direction face, int texture) {
textures[face.getIndex()] = texture;
indices[face.getIndex()] = texture;
}
int get(Direction face) {
return textures[face.getIndex()];
return indices[face.getIndex()];
}
}
public CTModel(IBakedModel originalModel, IHaveConnectedTextures block) {
super(originalModel);
textures = block.getSpriteShifts();
behaviour = block.getBehaviour();
}
@Override
@ -53,11 +53,15 @@ public class CTModel extends BakedModelWrapper<IBakedModel> {
if (!(state.getBlock() instanceof IHaveConnectedTextures))
return EmptyModelData.INSTANCE;
CTData data = new CTData();
IHaveConnectedTextures texDef = (IHaveConnectedTextures) state.getBlock();
for (Direction face : Direction.values()) {
if (!Block.shouldSideBeRendered(state, world, pos, face))
continue;
data.put(face, texDef.getTextureIndex(world, pos, state, face));
CTSpriteShiftEntry spriteShift = behaviour.get(state, face);
if (spriteShift == null)
continue;
CTContext ctContext = behaviour.buildContext(world, pos, state, face);
data.put(face, spriteShift.getTextureIndex(ctContext));
}
return new ModelDataMap.Builder().withInitial(CT_PROPERTY, data).build();
}
@ -67,40 +71,27 @@ public class CTModel extends BakedModelWrapper<IBakedModel> {
List<BakedQuad> quads = new ArrayList<>(super.getQuads(state, side, rand, extraData));
if (!extraData.hasProperty(CT_PROPERTY))
return quads;
IHaveConnectedTextures texDef = (IHaveConnectedTextures) state.getBlock();
CTData data = extraData.getData(CT_PROPERTY);
for (int i = 0; i < quads.size(); i++) {
BakedQuad quad = quads.get(i);
if (!texDef.appliesTo(quad))
continue;
SpriteShiftEntry texture = null;
for (SpriteShiftEntry entry : textures) {
if (entry.getOriginal() == quad.getSprite()) {
texture = entry;
break;
}
}
if (texture == null)
CTSpriteShiftEntry spriteShift = behaviour.get(state, quad.getFace());
if (spriteShift == null)
continue;
int index = data.get(quad.getFace());
if (index == -1)
continue;
float textureSize = 16f / 128f / 8f;
float uShift = (index % 8) * textureSize;
float vShift = (index / 8) * textureSize * 2;
uShift = texture.getTarget().getInterpolatedU((index % 8) * 2) - texture.getOriginal().getMinU();
vShift = texture.getTarget().getInterpolatedV((index / 8) * 2) - texture.getOriginal().getMinV();
float uShift = spriteShift.getUShift(index);
float vShift = spriteShift.getVShift(index);
BakedQuad newQuad = new BakedQuad(Arrays.copyOf(quad.getVertexData(), quad.getVertexData().length),
quad.getTintIndex(), quad.getFace(), quad.getSprite(), quad.shouldApplyDiffuseLighting(),
quad.getFormat());
VertexFormat format = quad.getFormat();
int[] vertexData = newQuad.getVertexData();
for (int vertex = 0; vertex < vertexData.length; vertex += format.getIntegerSize()) {
int uvOffset = format.getUvOffsetById(0) / 4;
int uIndex = vertex + uvOffset;

View file

@ -11,6 +11,16 @@ public abstract class CTSpriteShiftEntry extends SpriteShiftEntry {
this.textureSheetSize = sheetSize;
}
public float getUShift(int index) {
return getTarget().getInterpolatedU((index % textureSheetSize) * (16 / textureSheetSize))
- getOriginal().getMinU();
}
public float getVShift(int index) {
return getTarget().getInterpolatedV((index / textureSheetSize) * (16 / textureSheetSize))
- getOriginal().getMinV();
}
public abstract int getTextureIndex(CTContext context);
public static class Horizontal extends CTSpriteShiftEntry {
@ -21,7 +31,7 @@ public abstract class CTSpriteShiftEntry extends SpriteShiftEntry {
@Override
public int getTextureIndex(CTContext context) {
return (context.left ? 1 : 0) + (context.right ? 2 : 0);
return (context.right ? 1 : 0) + (context.left ? 2 : 0);
}
}

View file

@ -11,6 +11,10 @@ public class CTSpriteShifter extends SpriteShifter {
OMNIDIRECTIONAL, HORIZONTAL, VERTICAL;
}
public static CTSpriteShiftEntry get(CTType type, String blockTextureName) {
return get(type, blockTextureName, blockTextureName);
}
public static CTSpriteShiftEntry get(CTType type, String blockTextureName, String connectedTextureName) {
String originalLocation = "block/" + blockTextureName;
String targetLocation = "block/connected/" + blockTextureName;

View file

@ -1,22 +1,13 @@
package com.simibubi.create.foundation.block.connected;
import java.util.Map;
import java.util.function.BiPredicate;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.block.render.SpriteShifter;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IEnviromentBlockReader;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public abstract class ConnectedTextureBehaviour {
@ -27,7 +18,9 @@ public abstract class ConnectedTextureBehaviour {
public abstract CTSpriteShiftEntry get(BlockState state, Direction direction);
boolean shouldFlipUVs(BlockState state, Direction face) {
public abstract Iterable<CTSpriteShiftEntry> getAllCTShifts();
protected boolean shouldFlipUVs(BlockState state, Direction face) {
return false;
}

View file

@ -1,160 +1,7 @@
package com.simibubi.create.foundation.block.connected;
import java.util.function.BiPredicate;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.block.render.SpriteShifter;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IEnviromentBlockReader;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public interface IHaveConnectedTextures {
class CTContext {
boolean up, down, left, right;
boolean topLeft, topRight, bottomLeft, bottomRight;
}
@OnlyIn(Dist.CLIENT)
default boolean appliesTo(BakedQuad quad) {
return true;
}
default boolean connectsTo(BlockState state, BlockState other, IEnviromentBlockReader reader, BlockPos pos,
BlockPos otherPos, Direction face) {
BlockPos blockingPos = otherPos.offset(face);
if ((face.getAxis().getCoordinate(pos.getX(), pos.getY(), pos.getZ()) == face.getAxis()
.getCoordinate(otherPos.getX(), otherPos.getY(), otherPos.getZ()))
&& connectsTo(state, reader.getBlockState(blockingPos), reader, pos, blockingPos, face))
return false;
return state.getBlock() == other.getBlock();
}
default Iterable<SpriteShiftEntry> getSpriteShifts() {
return ImmutableList.of(SpriteShifter.getCT(((Block) this).getRegistryName().getPath()));
}
default int getTextureIndex(IEnviromentBlockReader reader, BlockPos pos, BlockState state, Direction face) {
return getTextureIndexForContext(reader, pos, state, face, buildContext(reader, pos, state, face));
}
default CTContext buildContext(IEnviromentBlockReader reader, BlockPos pos, BlockState state, Direction face) {
Axis axis = face.getAxis();
boolean positive = face.getAxisDirection() == AxisDirection.POSITIVE;
Direction h = axis == Axis.X ? Direction.SOUTH : Direction.WEST;
Direction v = axis.isHorizontal() ? Direction.UP : Direction.NORTH;
h = positive ? h.getOpposite() : h;
if (face == Direction.DOWN) {
v = v.getOpposite();
h = h.getOpposite();
}
final Direction horizontal = h;
final Direction vertical = v;
BiPredicate<Integer, Integer> connection = (x, y) -> {
BlockPos p = pos.offset(horizontal, x).offset(vertical, y);
return connectsTo(state, reader.getBlockState(p), reader, pos, p, face);
};
boolean up = connection.test(0, 1);
boolean down = connection.test(0, -1);
boolean left = connection.test(-1, 0);
boolean right = connection.test(1, 0);
boolean topLeft = connection.test(-1, 1);
boolean topRight = connection.test(1, 1);
boolean bottomLeft = connection.test(-1, -1);
boolean bottomRight = connection.test(1, -1);
boolean flip = shouldFlipUVs(state, face);
CTContext context = new CTContext();
context.up = flip ? down : up;
context.down = flip ? up : down;
context.left = flip ? right : left;
context.right = flip ? left : right;
context.topLeft = flip ? bottomRight : topLeft;
context.topRight = flip ? bottomLeft : topRight;
context.bottomLeft = flip ? topRight : bottomLeft;
context.bottomRight = flip ? topLeft : bottomRight;
return context;
}
default boolean shouldFlipUVs(BlockState state, Direction face) {
return false;
}
default int getTextureIndexForContext(IEnviromentBlockReader reader, BlockPos pos, BlockState state, Direction face,
CTContext c) {
int tileX = 0, tileY = 0;
int borders = (!c.up ? 1 : 0) + (!c.down ? 1 : 0) + (!c.left ? 1 : 0) + (!c.right ? 1 : 0);
if (c.up)
tileX++;
if (c.down)
tileX += 2;
if (c.left)
tileY++;
if (c.right)
tileY += 2;
if (borders == 0) {
if (c.topRight)
tileX++;
if (c.topLeft)
tileX += 2;
if (c.bottomRight)
tileY += 2;
if (c.bottomLeft)
tileY++;
}
if (borders == 1) {
if (!c.right) {
if (c.topLeft || c.bottomLeft) {
tileY = 4;
tileX = -1 + (c.bottomLeft ? 1 : 0) + (c.topLeft ? 1 : 0) * 2;
}
}
if (!c.left) {
if (c.topRight || c.bottomRight) {
tileY = 5;
tileX = -1 + (c.bottomRight ? 1 : 0) + (c.topRight ? 1 : 0) * 2;
}
}
if (!c.down) {
if (c.topLeft || c.topRight) {
tileY = 6;
tileX = -1 + (c.topLeft ? 1 : 0) + (c.topRight ? 1 : 0) * 2;
}
}
if (!c.up) {
if (c.bottomLeft || c.bottomRight) {
tileY = 7;
tileX = -1 + (c.bottomLeft ? 1 : 0) + (c.bottomRight ? 1 : 0) * 2;
}
}
}
if (borders == 2) {
if ((c.up && c.left && c.topLeft) || (c.down && c.left && c.bottomLeft) || (c.up && c.right && c.topRight)
|| (c.down && c.right && c.bottomRight))
tileX += 3;
}
return tileX + 8 * tileY;
}
public ConnectedTextureBehaviour getBehaviour();
}

View file

@ -1,7 +1,26 @@
package com.simibubi.create.foundation.block.connected;
import java.util.Arrays;
import net.minecraft.block.BlockState;
import net.minecraft.util.Direction;
public class StandardCTBehaviour extends ConnectedTextureBehaviour {
CTSpriteShiftEntry shift;
public StandardCTBehaviour(CTSpriteShiftEntry shift) {
this.shift = shift;
}
@Override
public CTSpriteShiftEntry get(BlockState state, Direction direction) {
return shift;
}
@Override
public Iterable<CTSpriteShiftEntry> getAllCTShifts() {
return Arrays.asList(shift);
}
}

View file

@ -1,7 +1,9 @@
package com.simibubi.create.foundation.block.render;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.simibubi.create.Create;
@ -27,4 +29,8 @@ public class SpriteShifter {
textures.values().forEach(SpriteShiftEntry::loadTextures);
}
public static List<ResourceLocation> getAllTargetSprites() {
return textures.values().stream().map(SpriteShiftEntry::getTargetResourceLocation).collect(Collectors.toList());
}
}

View file

@ -1,10 +1,13 @@
package com.simibubi.create.modules.contraptions.components.contraptions.chassis;
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.CTSpriteShifter;
import com.simibubi.create.foundation.block.connected.CTSpriteShifter.CTType;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour;
import com.simibubi.create.foundation.block.connected.IHaveConnectedTextures;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.block.render.SpriteShifter;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@ -68,18 +71,36 @@ public class LinearChassisBlock extends AbstractChassisBlock implements IHaveCon
}
@Override
public Iterable<SpriteShiftEntry> getSpriteShifts() {
return ImmutableList.of(
SpriteShifter.get("block/translation_chassis_top", "block/connected/translation_chassis_top"),
SpriteShifter.get("block/translation_chassis_top_sticky",
"block/connected/translation_chassis_top_sticky"));
public ConnectedTextureBehaviour getBehaviour() {
return new ChassisCTBehaviour();
}
private static class ChassisCTBehaviour extends ConnectedTextureBehaviour {
static final CTSpriteShiftEntry regular = CTSpriteShifter.get(CTType.OMNIDIRECTIONAL,
"translation_chassis_top");
static final CTSpriteShiftEntry sticky = CTSpriteShifter.get(CTType.OMNIDIRECTIONAL,
"translation_chassis_top_sticky");
@Override
public CTSpriteShiftEntry get(BlockState state, Direction direction) {
Block block = state.getBlock();
BooleanProperty glueableSide = ((LinearChassisBlock) block).getGlueableSide(state, direction);
if (glueableSide == null)
return null;
return state.get(glueableSide) ? sticky : regular;
}
@Override
public Iterable<CTSpriteShiftEntry> getAllCTShifts() {
return Arrays.asList(regular, sticky);
}
@Override
public boolean shouldFlipUVs(BlockState state, Direction face) {
if (state.get(AXIS).isHorizontal() && face.getAxisDirection() == AxisDirection.POSITIVE)
return true;
return IHaveConnectedTextures.super.shouldFlipUVs(state, face);
return super.shouldFlipUVs(state, face);
}
@Override
@ -89,3 +110,5 @@ public class LinearChassisBlock extends AbstractChassisBlock implements IHaveCon
}
}
}

View file

@ -104,10 +104,11 @@ public class CrushingWheelControllerBlock extends Block implements IHaveNoBlockI
}
public void updateSpeed(BlockState state, World world, BlockPos pos) {
CrushingWheelControllerTileEntity te = (CrushingWheelControllerTileEntity) world.getTileEntity(pos);
if (te == null)
TileEntity tileEntity = world.getTileEntity(pos);
if (tileEntity == null || !(tileEntity instanceof CrushingWheelControllerTileEntity))
return;
CrushingWheelControllerTileEntity te = (CrushingWheelControllerTileEntity) tileEntity;
if (!state.get(VALID) || CrushingWheelControllerTileEntity.isFrozen()) {
if (te.crushingspeed != 0) {
te.crushingspeed = 0;

View file

@ -1,6 +1,10 @@
package com.simibubi.create.modules.palettes;
import com.simibubi.create.foundation.block.connected.CTSpriteShifter;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour;
import com.simibubi.create.foundation.block.connected.IHaveConnectedTextures;
import com.simibubi.create.foundation.block.connected.StandardCTBehaviour;
import com.simibubi.create.foundation.block.connected.CTSpriteShifter.CTType;
import net.minecraft.block.Blocks;
import net.minecraft.block.GlassBlock;
@ -20,4 +24,9 @@ public class CTGlassBlock extends GlassBlock implements IHaveConnectedTextures {
return hasAlpha ? BlockRenderLayer.TRANSLUCENT : super.getRenderLayer();
}
@Override
public ConnectedTextureBehaviour getBehaviour() {
return new StandardCTBehaviour(CTSpriteShifter.get(CTType.OMNIDIRECTIONAL, getRegistryName().getPath()));
}
}

View file

@ -0,0 +1,55 @@
package com.simibubi.create.modules.palettes;
import java.util.Arrays;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour;
import com.simibubi.create.foundation.block.connected.IHaveConnectedTextures;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.Direction;
public class LayeredCTBlock extends Block implements IHaveConnectedTextures {
private LayeredCTBehaviour behaviour;
public LayeredCTBlock(Properties properties, CTSpriteShiftEntry layerShift) {
this(properties, layerShift, null);
}
public LayeredCTBlock(Properties properties, CTSpriteShiftEntry layerShift, CTSpriteShiftEntry topShift) {
super(properties);
behaviour = new LayeredCTBehaviour(layerShift, topShift);
}
@Override
public ConnectedTextureBehaviour getBehaviour() {
return behaviour;
}
private static class LayeredCTBehaviour extends ConnectedTextureBehaviour {
CTSpriteShiftEntry topShift;
CTSpriteShiftEntry layerShift;
public LayeredCTBehaviour(CTSpriteShiftEntry layerShift, CTSpriteShiftEntry topShift) {
this.layerShift = layerShift;
this.topShift = topShift;
}
@Override
public CTSpriteShiftEntry get(BlockState state, Direction direction) {
return direction.getAxis().isHorizontal() ? layerShift : topShift;
}
@Override
public Iterable<CTSpriteShiftEntry> getAllCTShifts() {
if (topShift == null)
return Arrays.asList(layerShift);
return Arrays.asList(layerShift, topShift);
}
}
}

View file

@ -0,0 +1,5 @@
{
"variants": {
"": { "model": "create:block/palettes/limestone_layers" }
}
}

View file

@ -180,6 +180,7 @@
"block.create.polished_limestone": "Polished Limestone",
"block.create.polished_limestone_slab": "Polished Limestone Slab",
"block.create.limestone_pillar": "Limestone Pillar",
"block.create.limestone_layers": "Limestone Layers",
"block.create.schematicannon": "Schematicannon",
"block.create.schematic_table": "Schematic Table",

View file

@ -0,0 +1,7 @@
{
"parent": "block/cube_column",
"textures": {
"end": "create:block/polished_limestone",
"side": "create:block/limestone_layers"
}
}

View file

@ -0,0 +1,3 @@
{
"parent": "create:block/palettes/limestone_layers"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 604 B

View file

@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"name": "create:limestone_layers",
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "create:limestone_layers"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}