Skip to content

Commit

Permalink
add custom armor render event
Browse files Browse the repository at this point in the history
  • Loading branch information
CammiePone committed Nov 2, 2024
1 parent cc5804d commit 78d430e
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package dev.upcraft.sparkweave.api.client.event;

import dev.upcraft.sparkweave.api.client.render.CustomArmorRenderer;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.ItemLike;
import org.jetbrains.annotations.Nullable;

import java.util.HashMap;
import java.util.Objects;

public class CustomArmorRendererRegistryEvent {
private static final HashMap<Item, CustomArmorRenderer> RENDERERS = new HashMap<>();

public static void register(CustomArmorRenderer renderer, ItemLike... items) {
Objects.requireNonNull(renderer, "Custom armor renderer is null");

if(items.length == 0)
throw new IllegalArgumentException("Custom armor renderer registered, but no items are attached to it");

for(ItemLike item : items) {
Objects.requireNonNull(item.asItem(), "Armor item is null or doesn't exist");

if(RENDERERS.putIfAbsent(item.asItem(), renderer) != null)
throw new IllegalArgumentException("Custom armor renderer already exists for " + BuiltInRegistries.ITEM.getKey(item.asItem()));
}
}

@Nullable
public static CustomArmorRenderer get(Item item) {
return RENDERERS.get(item);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.upcraft.sparkweave.api.client.render;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.Model;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;

@FunctionalInterface
public interface CustomArmorRenderer {
static void renderArmor(PoseStack matrices, MultiBufferSource vertexConsumers, int light, ItemStack stack, Model model, ResourceLocation texture) {
VertexConsumer vertexConsumer = ItemRenderer.getArmorFoilBuffer(vertexConsumers, RenderType.armorCutoutNoCull(texture), stack.hasFoil());

model.renderToBuffer(matrices, vertexConsumer, light, OverlayTexture.NO_OVERLAY);
}

void render(PoseStack matrices, MultiBufferSource bufferSource, ItemStack stack, LivingEntity entity, EquipmentSlot slot, int light, HumanoidModel<LivingEntity> contextModel);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package dev.upcraft.sparkweave.mixin.client;

import com.mojang.blaze3d.vertex.PoseStack;
import dev.upcraft.sparkweave.api.client.event.CustomArmorRendererRegistryEvent;
import dev.upcraft.sparkweave.api.client.render.CustomArmorRenderer;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(HumanoidArmorLayer.class)
public abstract class HumanoidArmorLayerMixin extends RenderLayer<LivingEntity, HumanoidModel<LivingEntity>> {
public HumanoidArmorLayerMixin(RenderLayerParent<LivingEntity, HumanoidModel<LivingEntity>> parent) { super(parent); }

@Inject(method = "renderArmorPiece", at = @At("HEAD"), cancellable = true)
private void disableDefaultArmorRendererForCustomArmor(PoseStack poseStack, MultiBufferSource bufferSource, LivingEntity entity, EquipmentSlot slot, int light, HumanoidModel<LivingEntity> model, CallbackInfo info) {
ItemStack stack = entity.getItemBySlot(slot);
CustomArmorRenderer renderer = CustomArmorRendererRegistryEvent.get(stack.getItem());

if(renderer != null) {
renderer.render(poseStack, bufferSource, stack, entity, slot, light, getParentModel());
info.cancel();
}
}
}
27 changes: 14 additions & 13 deletions Common/src/main/resources/sparkweave.mixins.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
{
"required": true,
"minVersion": "0.8",
"package": "dev.upcraft.sparkweave.mixin",
"plugin": "dev.upcraft.sparkweave.SparkweaveMixinConfigPlugin",
"refmap": "${mod_id}.refmap.json",
"compatibilityLevel": "JAVA_21",
"mixins": [
],
"client": [
"client.MainMixin"
],
"injectors": {
"defaultRequire": 1
"required": true,
"minVersion": "0.8",
"package": "dev.upcraft.sparkweave.mixin",
"plugin": "dev.upcraft.sparkweave.SparkweaveMixinConfigPlugin",
"refmap": "${mod_id}.refmap.json",
"compatibilityLevel": "JAVA_21",
"mixins": [
],
"client": [
"client.HumanoidArmorLayerMixin",
"client.MainMixin"
],
"injectors": {
"defaultRequire": 1
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class SparkweaveTestmodClient implements ClientEntryPoint {

@Override
public void onInitializeClient(ModContainer mod) {
RegisterLayerDefinitionsEvent.EVENT.register(event -> event.registerModelLayers(MageRobesModel.MODEL_LAYER, MageRobesModel::createBodyLayer));
CustomArmorRendererRegistryEvent.register(new MageRobesRenderer(), Items.CHAINMAIL_HELMET, Items.CHAINMAIL_CHESTPLATE, Items.CHAINMAIL_LEGGINGS, Items.CHAINMAIL_BOOTS);
}

public static void onClientTickStart(Minecraft client) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package dev.upcraft.sparkweave.testmod.client.models;

import dev.upcraft.sparkweave.testmod.SparkweaveTestmod;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartNames;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.*;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.entity.LivingEntity;

public class MageRobesModel<T extends LivingEntity> extends HumanoidModel<T> {
public static final ModelLayerLocation MODEL_LAYER = new ModelLayerLocation(SparkweaveTestmod.id("mage_robes"), "main");
public final ModelPart closedHood;
public final ModelPart cloak;
public final ModelPart openHood;
public final ModelPart rightSleeve;
public final ModelPart leftSleeve;
public final ModelPart garb;
public final ModelPart belt;
public final ModelPart rightShoe;
public final ModelPart leftShoe;

public MageRobesModel(ModelPart root) {
super(root, RenderType::armorCutoutNoCull);
closedHood = head.getChild("closedHood");
cloak = body.getChild("cloak");
openHood = cloak.getChild("openHood");
rightSleeve = rightArm.getChild("rightSleeve");
leftSleeve = leftArm.getChild("leftSleeve");
garb = body.getChild("garb");
belt = body.getChild("belt");
rightShoe = rightLeg.getChild("rightShoe");
leftShoe = leftLeg.getChild("leftShoe");
}

public static LayerDefinition createBodyLayer() {
MeshDefinition data = HumanoidModel.createMesh(CubeDeformation.NONE, 0);
PartDefinition head = data.getRoot().getChild(PartNames.HEAD);
PartDefinition body = data.getRoot().getChild(PartNames.BODY);
PartDefinition rightArm = data.getRoot().getChild(PartNames.RIGHT_ARM);
PartDefinition leftArm = data.getRoot().getChild(PartNames.LEFT_ARM);
PartDefinition rightLeg = data.getRoot().getChild(PartNames.RIGHT_LEG);
PartDefinition leftLeg = data.getRoot().getChild(PartNames.LEFT_LEG);

PartDefinition closedHood = head.addOrReplaceChild("closedHood", CubeListBuilder.create().texOffs(0, 64).addBox(-4f, -8f, -4f, 8f, 8f, 8f, new CubeDeformation(0.3f)), PartPose.offset(0f, 0f, 0f));
PartDefinition cube_r1 = closedHood.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(29, 78).addBox(-3f, 0.2f, 0f, 6f, 6f, 3f, new CubeDeformation(0.35f)), PartPose.offsetAndRotation(0f, -8f, -4f, -0.1745f, 0f, 0f));

PartDefinition cloak = body.addOrReplaceChild("cloak", CubeListBuilder.create(), PartPose.offset(0f, 0f, 0f));

PartDefinition cube_r2 = cloak.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(24, 91).addBox(-5f, -1f, 2f, 10f, 16f, 1f, new CubeDeformation(0.29f)), PartPose.offsetAndRotation(0f, 2f, 0f, 0.1745f, 0f, 0f));

PartDefinition openHood = cloak.addOrReplaceChild("openHood", CubeListBuilder.create(), PartPose.offset(0f, 0f, 0f));
PartDefinition cube_r3 = openHood.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(0, 80).addBox(-5f, -4f, 0f, 10f, 4f, 7f, new CubeDeformation(0.3f)), PartPose.offsetAndRotation(0f, 2f, 0f, 0.1745f, 0f, 0f));

PartDefinition garb = body.addOrReplaceChild("garb", CubeListBuilder.create().texOffs(0, 91).addBox(-4f, -12f, -2f, 8f, 11f, 4f, new CubeDeformation(0.3f)), PartPose.offset(0f, 12f, 0f));
PartDefinition belt = body.addOrReplaceChild("belt", CubeListBuilder.create().texOffs(41, 80).addBox(-3f, -3f, -2f, 6f, 3f, 1f, new CubeDeformation(0.2f)), PartPose.offset(0f, 12f, 0f));

PartDefinition backCover = garb.addOrReplaceChild("backCover", CubeListBuilder.create().texOffs(16, 108).addBox(-4f, 0f, 0f, 8f, 8f, 1f, new CubeDeformation(0.29f)), PartPose.offsetAndRotation(0f, -1f, 1f, 0.2618f, 0f, 0f));

PartDefinition rightCover = garb.addOrReplaceChild("rightCover", CubeListBuilder.create(), PartPose.offset(0f, 0f, 0f));
PartDefinition cube_r4 = rightCover.addOrReplaceChild("cube_r4", CubeListBuilder.create().texOffs(50, 110).addBox(-1f, -1f, -2f, 1f, 8f, 4f, new CubeDeformation(0.29f)), PartPose.offsetAndRotation(-3f, 0f, 0f, 0f, 0f, 0.2618f));

PartDefinition leftCover = garb.addOrReplaceChild("leftCover", CubeListBuilder.create(), PartPose.offset(0f, 0f, 0f));
PartDefinition cube_r5 = leftCover.addOrReplaceChild("cube_r5", CubeListBuilder.create().texOffs(48, 64).addBox(0f, -1f, -2f, 1f, 8f, 4f, new CubeDeformation(0.29f)), PartPose.offsetAndRotation(3f, 0f, 0f, 0f, 0f, -0.2618f));

PartDefinition rightSleeve = rightArm.addOrReplaceChild("rightSleeve", CubeListBuilder.create(), PartPose.offset(0f, 0f, 0f));
PartDefinition cube_r6 = rightSleeve.addOrReplaceChild("cube_r6", CubeListBuilder.create().texOffs(0, 106).addBox(-3f, -2f, -2f, 4f, 10f, 4f, new CubeDeformation(0.29f)), PartPose.offsetAndRotation(0f, 0f, 0f, 0f, 0f, 0f));

PartDefinition leftSleeve = leftArm.addOrReplaceChild("leftSleeve", CubeListBuilder.create(), PartPose.offset(2f, 0f, 0f));
PartDefinition cube_r7 = leftSleeve.addOrReplaceChild("cube_r7", CubeListBuilder.create().texOffs(32, 64).addBox(-1f, -2f, -2f, 4f, 10f, 4f, new CubeDeformation(0.29f)), PartPose.offsetAndRotation(-2f, 0f, 0f, 0f, 0f, 0f));

PartDefinition rightShoe = rightLeg.addOrReplaceChild("rightShoe", CubeListBuilder.create().texOffs(34, 110).addBox(-2f, 7f, -2f, 4f, 5f, 4f, new CubeDeformation(0.2f)), PartPose.offset(0f, 0f, 0f));

PartDefinition leftShoe = leftLeg.addOrReplaceChild("leftShoe", CubeListBuilder.create().texOffs(46, 90).addBox(-2f, 7f, -2f, 4f, 5f, 4f, new CubeDeformation(0.199f)), PartPose.offset(0.2f, 0f, 0f));

return LayerDefinition.create(data, 64, 128);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.upcraft.sparkweave.testmod.client.renderers;

import com.mojang.blaze3d.vertex.PoseStack;
import dev.upcraft.sparkweave.api.client.render.CustomArmorRenderer;
import dev.upcraft.sparkweave.testmod.SparkweaveTestmod;
import dev.upcraft.sparkweave.testmod.client.models.MageRobesModel;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;

public class MageRobesRenderer implements CustomArmorRenderer {
private static final ResourceLocation TEXTURE = SparkweaveTestmod.id("textures/entity/armor/mage_robes.png");
private MageRobesModel<LivingEntity> model;

@Override
public void render(PoseStack matrices, MultiBufferSource bufferSource, ItemStack stack, LivingEntity entity, EquipmentSlot slot, int light, HumanoidModel<LivingEntity> contextModel) {
if(model == null)
model = new MageRobesModel<>(Minecraft.getInstance().getEntityModels().bakeLayer(MageRobesModel.MODEL_LAYER));

contextModel.copyPropertiesTo(model);
model.setAllVisible(true);
model.openHood.visible = slot == EquipmentSlot.HEAD;
model.closedHood.visible = false;
model.cloak.visible = slot == EquipmentSlot.HEAD;
model.garb.visible = slot == EquipmentSlot.CHEST;
model.leftSleeve.visible = slot == EquipmentSlot.CHEST;
model.rightSleeve.visible = slot == EquipmentSlot.CHEST;
model.belt.visible = slot == EquipmentSlot.LEGS;
model.leftShoe.visible = slot == EquipmentSlot.FEET;
model.rightShoe.visible = slot == EquipmentSlot.FEET;

CustomArmorRenderer.renderArmor(matrices, bufferSource, light, stack, model, TEXTURE);
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 78d430e

Please sign in to comment.