XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

MyDimension-Lord

【我的世界】我的维度附属模组:维度之主

公开
关注 0 Fork 0 Star 0
UTF-8
// Native Minecraft 1.21.11
package com.xfestudio.mydimensionlord.client.builder;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import com.mojang.serialization.MapCodec;
import com.xfestudio.mydimensionlord.builder.BuilderMode;
import com.xfestudio.mydimensionlord.builder.RealmwrightData;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.special.SpecialModelRenderer;
import net.minecraft.resources.Identifier;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import java.util.function.Consumer;

public final class RealmwrightScepterRenderer implements SpecialModelRenderer<RealmwrightScepterRenderer.State> {
    private static final int EXTENSION_MODEL=1, LOWER_RING_MODEL=2, UPPER_RING_MODEL=3, FLOATING_MODEL=4, FLOATING_SECONDARY_MODEL=5;
    private static final String[] PARTS = {"build", "extension", "ring_lower", "ring_upper", "floating", "floating_secondary"};
    public record State(ItemStackRenderState[] parts, long millis) {}
    public record Unbaked() implements SpecialModelRenderer.Unbaked {
        public static final MapCodec<Unbaked> CODEC = MapCodec.unit(new Unbaked());
        @Override public SpecialModelRenderer<?> bake(BakingContext context) { return new RealmwrightScepterRenderer(); }
        @Override public MapCodec<Unbaked> type() { return CODEC; }
    }
    @Override public State extractArgument(ItemStack stack) {
        var minecraft = Minecraft.getInstance();
        var parts = new ItemStackRenderState[PARTS.length];
        for (int i=0; i<parts.length; i++) {
            String part = i == 0 && RealmwrightData.mode(stack) == BuilderMode.DEMOLISH ? "demolish" : PARTS[i];
            parts[i] = new ItemStackRenderState();
            minecraft.getModelManager().getItemModel(Identifier.fromNamespaceAndPath("mydimension", "scepter_parts/" + part))
                    .update(parts[i], stack, minecraft.getItemModelResolver(), ItemDisplayContext.NONE, minecraft.level, minecraft.player, 0);
        }
        return new State(parts, net.minecraft.util.Util.getMillis());
    }
    @Override public void getExtents(Consumer<Vector3fc> consumer) {
        consumer.accept(new Vector3f(-0.3F, -1.0F, -0.3F));
        consumer.accept(new Vector3f(1.3F, 2.2F, 1.3F));
    }
    // Both orbit rings live on the upper shaft so neither is hidden by the hand in first person.
    // The former lower ring is now the higher, slightly smaller orbit.
    private static final float LOWER_RING_PIVOT_Y = 12.5F / 16.0F;
    private static final float UPPER_RING_PIVOT_Y = 8.25F / 16.0F;

    @Override public void submit(State state, ItemDisplayContext context, PoseStack pose, SubmitNodeCollector collector,
                                 int packedLight, int packedOverlay, boolean foil, int outline) {
        if (state == null) return;
        long animationMillis = state.millis();
        float ringTicks = (animationMillis % 3_600_000L) / 50.0F;
        double bobPhase = animationMillis * (0.14D / 50.0D);
        renderModel(state, 0, pose, collector, packedLight, packedOverlay, outline);
        // Vanilla item-model elements are restricted to [-16, 32] on every axis. The requested
        // 1.5x shaft exceeds that span, so its lower section is baked as a second valid model and
        // translated back into the exact continuous position here instead of invalidating the
        // whole body into Minecraft's magenta/black missing-model cube.
        pose.pushPose();
        pose.translate(0.0D, -14.55D / 16.0D, 0.0D);
        renderModel(state, EXTENSION_MODEL, pose, collector, packedLight, packedOverlay, outline);
        pose.popPose();

        pose.pushPose();
        rotateAroundShaft(pose, LOWER_RING_PIVOT_Y, ringTicks * 4.0F, -5.0F);
        renderModel(state, LOWER_RING_MODEL, pose, collector, packedLight, packedOverlay, outline);
        pose.popPose();

        pose.pushPose();
        rotateAroundShaft(pose, UPPER_RING_PIVOT_Y, ringTicks * -5.5F, 7.0F);
        renderModel(state, UPPER_RING_MODEL, pose, collector, packedLight, packedOverlay, outline);
        pose.popPose();

        pose.pushPose();
        pose.translate(0.0D, Math.sin(bobPhase) * 0.08D, 0.0D);
        renderModel(state, FLOATING_MODEL, pose, collector, packedLight, packedOverlay, outline);
        pose.popPose();

        pose.pushPose();
        pose.translate(0.0D, Math.sin(bobPhase + 2.2D) * 0.065D, 0.0D);
        renderModel(state, FLOATING_SECONDARY_MODEL, pose, collector, packedLight, packedOverlay, outline);
        pose.popPose();
    }

    private static void rotateAroundShaft(PoseStack pose, float pivotY, float degrees, float tiltDegrees) {
        pose.translate(0.5D, pivotY, 0.5D);
        pose.mulPose(Axis.YP.rotationDegrees(degrees));
        pose.mulPose(Axis.ZP.rotationDegrees(tiltDegrees));
        pose.translate(-0.5D, -pivotY, -0.5D);
    }

    private static void renderModel(State state, int part, PoseStack pose, SubmitNodeCollector collector, int light, int overlay, int outline) {
        // Each native item layer centers its mesh. The parent special renderer
        // already applied that translation; keep the original model-space pivots.
        pose.pushPose();
        pose.translate(0.5D, 0.5D, 0.5D);
        state.parts()[part].submit(pose, collector, light, overlay, outline);
        pose.popPose();
    }
}