blueprint small fix

This commit is contained in:
2026-03-25 15:34:18 +01:00
parent a678f3dd02
commit d44fb3ca9a
13 changed files with 123 additions and 104 deletions

View File

@@ -6,7 +6,7 @@ minecraft_version=1.20.1
yarn_mappings=1.20.1+build.10
loader_version=0.18.3
# Mod Properties
mod_version=26.3.25
mod_version=26.3.25.1
maven_group=dev.tggamesyt
archives_base_name=szar
# Dependencies

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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() {

View File

@@ -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()));

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 } }
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B