RyanHub – file viewer
filename: common/src/main/java/rearth/oritech/client/renderers/ItemPipeTransferRenderer.java
branch: 1.21
back to repo
package rearth.oritech.client.renderers;

import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.Vec3d;
import rearth.oritech.block.entity.pipes.ItemPipeInterfaceEntity;

import java.util.HashSet;

public class ItemPipeTransferRenderer implements BlockEntityRenderer<ItemPipeInterfaceEntity> {
    
    @Override
    public void render(ItemPipeInterfaceEntity entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
        
        if (entity.activeStacks == null || entity.activeStacks.isEmpty()) return;
        
        var time = entity.getWorld().getTime() + tickDelta;
        var removedStacks = new HashSet<ItemPipeInterfaceEntity.RenderStackData>();
        
        for (var renderedStack : entity.activeStacks) {
            var age = time - renderedStack.startedAt();
            var neededTime = ItemPipeInterfaceEntity.calculatePathLength(renderedStack.pathLength());    // about 2 blocks/s, but much faster on longer paths
            var progress = age / neededTime;
            if (progress > 1) {
                removedStacks.add(renderedStack);
                continue;
            }
            
            progress = sigmoidFitted(progress);
            
            // get position in path at current progress (traverse path to current progress)
            var targetPathProgress = renderedStack.pathLength() * progress;
            var pathProgress = 0;
            var pathPosition = renderedStack.path().getFirst();
            Vec3d targetPos = Vec3d.ZERO;
            
            for (var segment : renderedStack.path()) {
                var segmentDist = segment.getManhattanDistance(pathPosition);
                
                if (pathProgress + segmentDist < targetPathProgress) {
                    pathProgress += segmentDist;
                    pathPosition = segment;
                } else {    // reaching or overshooting target
                    var remainingDist = targetPathProgress - pathProgress;
                    var targetOffset = Vec3d.of(segment.subtract(pathPosition)).normalize().multiply(remainingDist);
                    targetPos = Vec3d.of(pathPosition).add(targetOffset);
                    break;
                }
                
            }
            
            var offset = targetPos.subtract(Vec3d.of(entity.getPos()));
            
            matrices.push();
            matrices.translate(offset.x + 0.5, offset.y + 0.5, offset.z + 0.5);
            matrices.scale(0.4f, 0.4f, 0.4f);
            matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-140));
            matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-30));
            
            var renderedItem = renderedStack.rendered();
            
            MinecraftClient.getInstance().getItemRenderer().renderItem(
              renderedItem,
              ModelTransformationMode.GUI,
              light,
              OverlayTexture.DEFAULT_UV,
              matrices,
              vertexConsumers,
              entity.getWorld(),
              0
            );
            
            matrices.pop();
            
        }
        
        entity.activeStacks.removeAll(removedStacks);
        
    }
    
    private static double sigmoidFitted(double x) {
        return sigmoid((x - 0.5) * 2) + 0.5f;
    }
    
    private static double sigmoid(double x) {
        return x / (1 + Math.abs(x));
    }
}