blueprint small fix
This commit is contained in:
@@ -11,6 +11,7 @@ import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
|
||||
public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<BlueprintBlockEntity> {
|
||||
@@ -31,43 +32,19 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
|
||||
BlockState storedState = block.getDefaultState();
|
||||
if (storedState.getRenderType() == BlockRenderType.INVISIBLE) return;
|
||||
|
||||
// Get the shape/state of the blueprint block itself
|
||||
BlockState blueprintState = entity.getCachedState();
|
||||
|
||||
// We want to render the stored block's TEXTURE but on the blueprint block's SHAPE.
|
||||
// The way to do this: find the model for the blueprint block shape,
|
||||
// but swap in the stored block's sprite via a custom render layer.
|
||||
// Simplest approach: render the blueprint block's model with the stored block's
|
||||
// textures by remapping the sprite.
|
||||
|
||||
BlockRenderManager renderer = MinecraftClient.getInstance().getBlockRenderManager();
|
||||
|
||||
matrices.push();
|
||||
|
||||
// Render the blueprint shape using the stored block's texture
|
||||
// by temporarily using the stored block's model sprites on our shape
|
||||
renderWithStoredTexture(entity, blueprintState, storedState, matrices, vertexConsumers, light, overlay, renderer);
|
||||
|
||||
matrices.pop();
|
||||
}
|
||||
|
||||
private void renderWithStoredTexture(BlueprintBlockEntity entity, BlockState blueprintState,
|
||||
BlockState storedState, MatrixStack matrices,
|
||||
VertexConsumerProvider vertexConsumers, int light, int overlay,
|
||||
BlockRenderManager renderer) {
|
||||
// Get the first (main) sprite from the stored block's model
|
||||
var storedModel = renderer.getModel(storedState);
|
||||
var blueprintModel = renderer.getModel(blueprintState);
|
||||
var particleSprite = storedModel.getParticleSprite();
|
||||
|
||||
var sprites = storedModel.getParticleSprite(); // main texture of stored block
|
||||
|
||||
// Render blueprint model quads, replacing its texture with stored block's sprite
|
||||
var random = Random.create();
|
||||
random.setSeed(42L);
|
||||
var layer = net.minecraft.client.render.RenderLayers.getBlockLayer(storedState);
|
||||
var consumer = vertexConsumers.getBuffer(layer);
|
||||
|
||||
var bufferSource = vertexConsumers;
|
||||
var layer = net.minecraft.client.render.RenderLayers.getBlockLayer(blueprintState);
|
||||
var consumer = bufferSource.getBuffer(layer);
|
||||
matrices.push();
|
||||
// No scaling here anymore
|
||||
|
||||
for (var direction : new net.minecraft.util.math.Direction[]{
|
||||
null,
|
||||
@@ -81,22 +58,68 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
|
||||
random.setSeed(42L);
|
||||
var quads = blueprintModel.getQuads(blueprintState, direction, random);
|
||||
for (var quad : quads) {
|
||||
// Emit the quad but with the stored block's sprite UV remapped
|
||||
emitQuadWithSprite(consumer, matrices, quad, sprites, light, overlay);
|
||||
int[] vertexData = quad.getVertexData().clone();
|
||||
remapUVs(vertexData, quad.getSprite(), particleSprite);
|
||||
offsetVertsAlongNormal(vertexData, quad.getFace(), 0.001f);
|
||||
|
||||
consumer.quad(
|
||||
matrices.peek(),
|
||||
new net.minecraft.client.render.model.BakedQuad(
|
||||
vertexData,
|
||||
quad.getColorIndex(),
|
||||
quad.getFace(),
|
||||
particleSprite,
|
||||
quad.hasShade()
|
||||
),
|
||||
1f, 1f, 1f, light, overlay
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
matrices.pop();
|
||||
|
||||
}
|
||||
|
||||
private void remapUVs(int[] vertexData,
|
||||
net.minecraft.client.texture.Sprite fromSprite,
|
||||
net.minecraft.client.texture.Sprite toSprite) {
|
||||
// Vertex format: X, Y, Z, COLOR, U, V, UV2, NORMAL — each vertex is 8 ints
|
||||
int vertexSize = 8;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int uvOffset = i * vertexSize + 4;
|
||||
// Unpack UV floats from int bits
|
||||
float u = Float.intBitsToFloat(vertexData[uvOffset]);
|
||||
float v = Float.intBitsToFloat(vertexData[uvOffset + 1]);
|
||||
|
||||
// Normalize UV from the source sprite's atlas space to 0-1
|
||||
float normalizedU = (u - fromSprite.getMinU()) / (fromSprite.getMaxU() - fromSprite.getMinU());
|
||||
float normalizedV = (v - fromSprite.getMinV()) / (fromSprite.getMaxV() - fromSprite.getMinV());
|
||||
|
||||
// Remap to target sprite's atlas space
|
||||
float newU = toSprite.getMinU() + normalizedU * (toSprite.getMaxU() - toSprite.getMinU());
|
||||
float newV = toSprite.getMinV() + normalizedV * (toSprite.getMaxV() - toSprite.getMinV());
|
||||
|
||||
vertexData[uvOffset] = Float.floatToRawIntBits(newU);
|
||||
vertexData[uvOffset + 1] = Float.floatToRawIntBits(newV);
|
||||
}
|
||||
}
|
||||
|
||||
private void emitQuadWithSprite(net.minecraft.client.render.VertexConsumer consumer,
|
||||
MatrixStack matrices,
|
||||
net.minecraft.client.render.model.BakedQuad quad,
|
||||
net.minecraft.client.texture.Sprite sprite,
|
||||
int light, int overlay) {
|
||||
// Re-emit the quad geometry but remap UVs to the new sprite
|
||||
consumer.quad(matrices.peek(), quad, 1f, 1f, 1f, light, overlay);
|
||||
// Note: this uses the quad's original UVs which point to the blueprint texture.
|
||||
// For full texture remapping you'd need to manually rewrite vertex data.
|
||||
// This gives correct shape with blueprint texture as fallback —
|
||||
// see note below for full UV remapping.
|
||||
private void offsetVertsAlongNormal(int[] vertexData, net.minecraft.util.math.Direction face, float amount) {
|
||||
float dx = face.getOffsetX() * amount;
|
||||
float dy = face.getOffsetY() * amount;
|
||||
float dz = face.getOffsetZ() * amount;
|
||||
|
||||
int vertexSize = 8;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int base = i * vertexSize;
|
||||
float x = Float.intBitsToFloat(vertexData[base]);
|
||||
float y = Float.intBitsToFloat(vertexData[base + 1]);
|
||||
float z = Float.intBitsToFloat(vertexData[base + 2]);
|
||||
|
||||
vertexData[base] = Float.floatToRawIntBits(x + dx);
|
||||
vertexData[base + 1] = Float.floatToRawIntBits(y + dy);
|
||||
vertexData[base + 2] = Float.floatToRawIntBits(z + dz);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,13 +29,12 @@ public class BlueprintBehavior {
|
||||
|
||||
ItemStack held = player.getStackInHand(hand);
|
||||
|
||||
if (held.isEmpty()) {
|
||||
// Clear stored block
|
||||
if (held.isEmpty() && player.isSneaking()) {
|
||||
blueprint.clearStoredBlock();
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (held.getItem() instanceof BlockItem blockItem) {
|
||||
if (!held.isEmpty() && held.getItem() instanceof BlockItem blockItem && !blueprint.hasStoredBlock()) {
|
||||
String id = Registries.BLOCK.getId(blockItem.getBlock()).toString();
|
||||
blueprint.setStoredBlock(id);
|
||||
if (!player.isCreative()) held.decrement(1);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
@@ -16,8 +17,19 @@ public class BlueprintBlockEntity extends BlockEntity {
|
||||
@Nullable
|
||||
private String storedBlockId = null;
|
||||
|
||||
public BlueprintBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
public BlueprintBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(getBEType(state), pos, state);
|
||||
}
|
||||
|
||||
private static BlockEntityType<BlueprintBlockEntity> getBEType(BlockState state) {
|
||||
Block block = state.getBlock();
|
||||
if (block instanceof BlueprintStairsBlock) return BlueprintBlocks.BLUEPRINT_STAIRS_BE_TYPE;
|
||||
if (block instanceof BlueprintSlabBlock) return BlueprintBlocks.BLUEPRINT_SLAB_BE_TYPE;
|
||||
if (block instanceof BlueprintDoorBlock) return BlueprintBlocks.BLUEPRINT_DOOR_BE_TYPE;
|
||||
if (block instanceof BlueprintTrapDoorBlock) return BlueprintBlocks.BLUEPRINT_TRAPDOOR_BE_TYPE;
|
||||
if (block instanceof BlueprintWallBlock) return BlueprintBlocks.BLUEPRINT_WALL_BE_TYPE;
|
||||
if (block instanceof BlueprintFenceBlock) return BlueprintBlocks.BLUEPRINT_FENCE_BE_TYPE;
|
||||
throw new IllegalStateException("Unknown blueprint block: " + block);
|
||||
}
|
||||
|
||||
public boolean hasStoredBlock() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import dev.tggamesyt.szar.Szar;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.MapColor;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.item.BlockItem;
|
||||
@@ -38,47 +39,44 @@ public class BlueprintBlocks {
|
||||
|
||||
public static final BlueprintWallBlock BLUEPRINT_WALL =
|
||||
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_wall"),
|
||||
new BlueprintWallBlock(settings()));
|
||||
new BlueprintWallBlock(AbstractBlock.Settings.copy(Blocks.STONE_BRICK_WALL)));
|
||||
|
||||
public static final BlueprintFenceBlock BLUEPRINT_FENCE =
|
||||
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_fence"),
|
||||
new BlueprintFenceBlock(settings()));
|
||||
new BlueprintFenceBlock(AbstractBlock.Settings.copy(Blocks.OAK_FENCE)));
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_STAIRS_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_stairs_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_STAIRS).build());
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_STAIRS_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_SLAB_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_DOOR_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_TRAPDOOR_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_WALL_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_FENCE_BE_TYPE;
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_SLAB_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_slab_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_SLAB).build());
|
||||
static {
|
||||
BLUEPRINT_STAIRS_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_stairs_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_STAIRS).build());
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_DOOR_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_door_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_DOOR).build());
|
||||
BLUEPRINT_SLAB_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_slab_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_SLAB).build());
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_TRAPDOOR_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_trapdoor_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_TRAPDOOR).build());
|
||||
BLUEPRINT_DOOR_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_door_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_DOOR).build());
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_WALL_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_wall_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_WALL).build());
|
||||
BLUEPRINT_TRAPDOOR_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_trapdoor_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_TRAPDOOR).build());
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_FENCE_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_fence_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_FENCE).build());
|
||||
BLUEPRINT_WALL_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_wall_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_WALL).build());
|
||||
|
||||
BLUEPRINT_FENCE_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_fence_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_FENCE).build());
|
||||
}
|
||||
public static final BlockItem BLUEPRINT_STAIRS_ITEM = Registry.register(Registries.ITEM,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_stairs"),
|
||||
new BlockItem(BLUEPRINT_STAIRS, new Item.Settings()));
|
||||
|
||||
@@ -19,7 +19,7 @@ public class BlueprintDoorBlock extends DoorBlock implements BlockEntityProvider
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_DOOR_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class BlueprintFenceBlock extends FenceBlock implements BlockEntityProvid
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_FENCE_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class BlueprintSlabBlock extends SlabBlock implements BlockEntityProvider
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_SLAB_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class BlueprintStairsBlock extends StairsBlock implements BlockEntityProv
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_STAIRS_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class BlueprintTrapDoorBlock extends TrapdoorBlock implements BlockEntity
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_TRAPDOOR_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class BlueprintWallBlock extends WallBlock implements BlockEntityProvider
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_WALL_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
{
|
||||
"multipart": [
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_post" },
|
||||
"when": { "up": "true" } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side", "uvlock": true },
|
||||
"when": { "north": "low" } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side", "y": 90, "uvlock": true },
|
||||
"when": { "east": "low" } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side", "y": 180, "uvlock": true },
|
||||
"when": { "south": "low" } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side", "y": 270, "uvlock": true },
|
||||
"when": { "west": "low" } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side_tall", "uvlock": true },
|
||||
"when": { "north": "tall" } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side_tall", "y": 90, "uvlock": true },
|
||||
"when": { "east": "tall" } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side_tall", "y": 180, "uvlock": true },
|
||||
"when": { "south": "tall" } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side_tall", "y": 270, "uvlock": true },
|
||||
"when": { "west": "tall" } }
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_post" } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side", "uvlock": true } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side", "y": 90, "uvlock": true } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side", "y": 180, "uvlock": true } },
|
||||
{ "apply": { "model": "szar:block/blueprint_wall_side", "y": 270, "uvlock": true } }
|
||||
]
|
||||
}
|
||||
BIN
src/main/resources/assets/szar/textures/block/blueprint.png
Normal file
BIN
src/main/resources/assets/szar/textures/block/blueprint.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 873 B |
Reference in New Issue
Block a user