diff --git a/gradle.properties b/gradle.properties index 2c62248..eed3948 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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.1 +mod_version=26.3.25.2 maven_group=dev.tggamesyt archives_base_name=szar # Dependencies diff --git a/src/client/java/dev/tggamesyt/szar/client/BlueprintBlockEntityRenderer.java b/src/client/java/dev/tggamesyt/szar/client/BlueprintBlockEntityRenderer.java index ef43a74..d0146e5 100644 --- a/src/client/java/dev/tggamesyt/szar/client/BlueprintBlockEntityRenderer.java +++ b/src/client/java/dev/tggamesyt/szar/client/BlueprintBlockEntityRenderer.java @@ -4,10 +4,13 @@ import dev.tggamesyt.szar.BlueprintBlockEntity; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.LightmapTextureManager; import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.render.block.BlockRenderManager; import net.minecraft.client.render.block.entity.BlockEntityRenderer; import net.minecraft.client.render.block.entity.BlockEntityRendererFactory; +import net.minecraft.client.render.model.BakedQuad; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; @@ -21,6 +24,7 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer getQuads(BlockState state, Direction face, Random random) { + List original = blueprint.getQuads(blueprintState, face, random); + List result = new ArrayList<>(original.size()); + + for (BakedQuad quad : original) { + int[] data = quad.getVertexData().clone(); + + Direction quadFace = quad.getFace(); + Sprite target = getSpriteForFace(stored, storedState, quadFace); + + remapUVs(data, quad.getSprite(), target); + + BlockPos pos = entity.getPos(); + Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera(); + Vec3d camPos = camera.getPos(); + double dx = pos.getX() + 0.5 - camPos.x; + double dy = pos.getY() + 0.5 - camPos.y; + double dz = pos.getZ() + 0.5 - camPos.z; + double distance = Math.sqrt(dx*dx + dy*dy + dz*dz); + float offsetAmount = 0.0001f + (float)distance * 1e-5f; + offsetAmount = Math.min(offsetAmount, 0.001f); // clamp max + offsetVertsAlongNormal(data, quad.getFace(), offsetAmount); + + result.add(new BakedQuad( + data, + quad.getColorIndex(), + quadFace, + target, + quad.hasShade() + )); + } + + return result; + } + + // --- IMPORTANT: delegate everything else properly --- + + @Override + public boolean useAmbientOcclusion() { + return stored.useAmbientOcclusion(); // important for lighting + } + + @Override + public boolean hasDepth() { + return stored.hasDepth(); + } + + @Override + public boolean isSideLit() { + return stored.isSideLit(); + } + + @Override + public boolean isBuiltin() { + return false; + } + + @Override + public Sprite getParticleSprite() { + return stored.getParticleSprite(); + } + + @Override + public ModelTransformation getTransformation() { + return stored.getTransformation(); + } + + @Override + public ModelOverrideList getOverrides() { + return stored.getOverrides(); + } + + // --- helpers --- + + private Sprite getSpriteForFace(BakedModel model, BlockState state, Direction face) { + Random rand = Random.create(42L); + + List quads = model.getQuads(state, face, rand); + if (!quads.isEmpty()) return quads.get(0).getSprite(); + + quads = model.getQuads(state, null, rand); + for (BakedQuad q : quads) { + if (q.getFace() == face) return q.getSprite(); + } + + return model.getParticleSprite(); + } + + private void remapUVs(int[] vertexData, Sprite from, Sprite to) { + int stride = 8; + + for (int i = 0; i < 4; i++) { + int uvIndex = i * stride + 4; + + float u = Float.intBitsToFloat(vertexData[uvIndex]); + float v = Float.intBitsToFloat(vertexData[uvIndex + 1]); + + float nu = (u - from.getMinU()) / (from.getMaxU() - from.getMinU()); + float nv = (v - from.getMinV()) / (from.getMaxV() - from.getMinV()); + + float newU = to.getMinU() + nu * (to.getMaxU() - to.getMinU()); + float newV = to.getMinV() + nv * (to.getMaxV() - to.getMinV()); + + vertexData[uvIndex] = Float.floatToRawIntBits(newU); + vertexData[uvIndex + 1] = Float.floatToRawIntBits(newV); + } + } + + private void offsetVertsAlongNormal(int[] vertexData, Direction face, float amount) { + if (face == null) return; // skip general quads + + float dx = face.getOffsetX() * amount; + float dy = face.getOffsetY() * amount; + float dz = face.getOffsetZ() * amount; + + int vertexSize = 8; // X,Y,Z,COLOR,U,V,UV2,NORMAL + 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); + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/szar/textures/block/blueprint.png b/src/main/resources/assets/szar/textures/block/blueprint.png index e05ab79..a21f211 100644 Binary files a/src/main/resources/assets/szar/textures/block/blueprint.png and b/src/main/resources/assets/szar/textures/block/blueprint.png differ diff --git a/src/main/resources/szar.accesswidener b/src/main/resources/szar.accesswidener index e1ec0a4..a7d420d 100644 --- a/src/main/resources/szar.accesswidener +++ b/src/main/resources/szar.accesswidener @@ -6,4 +6,5 @@ accessible class net/minecraft/client/gui/hud/InGameHud$HeartType accessible field net/minecraft/server/network/ServerPlayerInteractionManager player Lnet/minecraft/server/network/ServerPlayerEntity; accessible method net/minecraft/client/render/entity/LivingEntityRenderer addFeature (Lnet/minecraft/client/render/entity/feature/FeatureRenderer;)Z accessible field net/minecraft/client/render/entity/EntityRenderDispatcher renderers Ljava/util/Map; -accessible method net/minecraft/world/GameRules$BooleanRule create (ZLjava/util/function/BiConsumer;)Lnet/minecraft/world/GameRules$Type; \ No newline at end of file +accessible method net/minecraft/world/GameRules$BooleanRule create (ZLjava/util/function/BiConsumer;)Lnet/minecraft/world/GameRules$Type; +accessible method net/minecraft/client/render/block/BlockModelRenderer renderQuad (Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/render/VertexConsumer;Lnet/minecraft/client/util/math/MatrixStack$Entry;Lnet/minecraft/client/render/model/BakedQuad;FFFFIIIII)V \ No newline at end of file