Skip to content

Commit

Permalink
Add 3d armor system
Browse files Browse the repository at this point in the history
-All example are in the package exampleCustom3DArmor and textures/example/
-Adaptation needed when model exporter from blockbench so DON'T add the java file just open it and copy paste the code
  • Loading branch information
iglee42 committed Sep 10, 2024
1 parent 88bc716 commit cc7320d
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/main/java/com/portingdeadmods/modjam/ModJam.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.portingdeadmods.modjam.content.items.PrismMonocleItem;
import com.portingdeadmods.modjam.data.MJDataComponents;
import com.portingdeadmods.modjam.exampleCustom3DArmor.ExampleItems;
import com.portingdeadmods.modjam.registries.*;
import net.neoforged.neoforge.registries.NewRegistryEvent;
import org.slf4j.Logger;
Expand All @@ -27,6 +28,7 @@ public ModJam(IEventBus modEventBus, ModContainer modContainer) {
event.register(MJRegistries.AUGMENT);
});

new ExampleItems();
MJItems.ITEMS.register(modEventBus);
MJFluids.FLUIDS.register(modEventBus);
MJBlocks.BLOCKS.register(modEventBus);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.portingdeadmods.modjam.api.client.model;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.HumanoidArmorModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.CubeListBuilder;
import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraft.client.model.geom.builders.MeshDefinition;
import net.minecraft.client.model.geom.builders.PartDefinition;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;

import java.util.function.Consumer;

public class MJArmorModel extends HumanoidArmorModel<LivingEntity> {

private final EquipmentSlot slot;

public MJArmorModel(ModelPart root, EquipmentSlot slot) {
super(root);
this.slot = slot;
}

public static LayerDefinition createLayer(int textureWidth, int textureHeight, Consumer<PartsDefinition> partsConsumer) {
MeshDefinition mesh = new MeshDefinition();
PartDefinition root = mesh.getRoot();

root.addOrReplaceChild("head", CubeListBuilder.create(), PartPose.ZERO);
root.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.ZERO);
root.addOrReplaceChild("body", CubeListBuilder.create(), PartPose.ZERO);
root.addOrReplaceChild("left_arm", CubeListBuilder.create(), PartPose.ZERO);
root.addOrReplaceChild("right_arm", CubeListBuilder.create(), PartPose.ZERO);
root.addOrReplaceChild("left_leg", CubeListBuilder.create(), PartPose.ZERO);
root.addOrReplaceChild("right_leg", CubeListBuilder.create(), PartPose.ZERO);

partsConsumer.accept(new PartsDefinition(root));

return LayerDefinition.create(mesh, textureWidth, textureHeight);
}

@Override
public void setupAnim(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
super.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch);
}

@Override
public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int color) {
setPartVisibility(slot);
super.renderToBuffer(poseStack, buffer, packedLight, packedOverlay, color);
}

protected void setPartVisibility(EquipmentSlot slot) {
setAllVisible(false);
switch (slot) {
case HEAD:
head.visible = true;
hat.visible = true;
break;
case CHEST:
body.visible = true;
rightArm.visible = true;
leftArm.visible = true;
break;
case LEGS:
body.visible = true;
rightLeg.visible = true;
leftLeg.visible = true;
break;
case FEET:
rightLeg.visible = true;
leftLeg.visible = true;
}
}

public record PartsDefinition(PartDefinition root) {

public PartDefinition getHat() {
return root().addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.ZERO);
}

public PartDefinition getHead() {
return root().addOrReplaceChild("head", CubeListBuilder.create(), PartPose.ZERO);
}

public PartDefinition getBody() {
return root().addOrReplaceChild("body", CubeListBuilder.create(), PartPose.ZERO);
}

public PartDefinition getLeftArm() {
return root().addOrReplaceChild("left_arm", CubeListBuilder.create(), PartPose.ZERO);
}

public PartDefinition getRightArm() {
return root().addOrReplaceChild("right_arm", CubeListBuilder.create(), PartPose.ZERO);
}

public PartDefinition getLeftLeg() {
return root().addOrReplaceChild("left_leg", CubeListBuilder.create(), PartPose.ZERO);
}

public PartDefinition getRightLeg() {
return root().addOrReplaceChild("right_leg", CubeListBuilder.create(), PartPose.ZERO);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.portingdeadmods.modjam.registries.MJBlockEntityTypes;
import com.portingdeadmods.modjam.registries.MJItems;
import com.portingdeadmods.modjam.registries.MJMenuTypes;
import com.portingdeadmods.modjam.utils.ArmorModelsHandler;
import net.minecraft.client.Camera;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
Expand Down Expand Up @@ -114,6 +115,7 @@ public static void registerBERenderers(EntityRenderersEvent.RegisterRenderers ev
public static void registerLayerDefinitions(EntityRenderersEvent.RegisterLayerDefinitions event) {
event.registerLayerDefinition(DrainTopModel.LAYER_LOCATION, DrainTopModel::createBodyLayer);
event.registerLayerDefinition(PrismarineCrystalModel.LAYER_LOCATION, PrismarineCrystalModel::createBodyLayer);
ArmorModelsHandler.registerLayers(event);
}

@SubscribeEvent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.portingdeadmods.modjam.exampleCustom3DArmor;

import com.portingdeadmods.modjam.ModJam;
import com.portingdeadmods.modjam.registries.MJItems;
import com.portingdeadmods.modjam.utils.ArmorModelsHandler;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions;
import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent;

@EventBusSubscriber(modid = ModJam.MODID,value = Dist.CLIENT,bus = EventBusSubscriber.Bus.MOD)
public class ExampleClientEvents {

@SubscribeEvent
public static void registerClientExtensions(RegisterClientExtensionsEvent event) {
event.registerItem(new IClientItemExtensions() {

@Override
public HumanoidModel<?> getHumanoidArmorModel(LivingEntity livingEntity, ItemStack
itemStack, EquipmentSlot equipmentSlot, HumanoidModel<?> original) {
return ArmorModelsHandler.armorModel(ArmorModelsHandler.test, equipmentSlot);
}
}, ExampleItems.TEST);

event.registerItem(new IClientItemExtensions() {

@Override
public HumanoidModel<?> getHumanoidArmorModel(LivingEntity livingEntity, ItemStack
itemStack, EquipmentSlot equipmentSlot, HumanoidModel<?> original) {
return ArmorModelsHandler.armorModel(ArmorModelsHandler.test, equipmentSlot);
}
}, ExampleItems.TEST_CHEST);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.portingdeadmods.modjam.exampleCustom3DArmor;

import net.minecraft.world.item.Item;
import net.neoforged.neoforge.registries.DeferredItem;

import static com.portingdeadmods.modjam.registries.MJItems.registerItem;

public class ExampleItems {

public static final DeferredItem<TestItem> TEST = registerItem("test",
TestItem::new, new Item.Properties());
public static final DeferredItem<TestChestItem> TEST_CHEST = registerItem("test_chest",
TestChestItem::new, new Item.Properties());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.portingdeadmods.modjam.exampleCustom3DArmor;

import com.portingdeadmods.modjam.api.client.model.MJArmorModel;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.CubeDeformation;
import net.minecraft.client.model.geom.builders.CubeListBuilder;
import net.minecraft.client.model.geom.builders.LayerDefinition;

public class TestArmorModel {

public static LayerDefinition createLayerDefinition(){
return MJArmorModel.createLayer(1,1, parts ->{
parts.getHead().addOrReplaceChild("test",
CubeListBuilder.create().texOffs(0, 0).addBox(-1.0F, -9.0F, 0.0F, 1.0F, 1.0F, 1.0F, new CubeDeformation(0.0F))
.texOffs(0, 0).addBox(1.0F, -9.0F, 0.0F, 1.0F, 1.0F, 1.0F, new CubeDeformation(0.0F))
.texOffs(0, 0).addBox(0.0F, -12.0F, 0.0F, 1.0F, 3.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 0.0F, 0.0F));
parts.getHead().addOrReplaceChild("curved", CubeListBuilder.create().texOffs(0, 0).addBox(-1.0F, -3.0F, 0.0F, 1.0F, 3.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(1.0F, -11.25F, 0.25F, 0.6981F, 0.0F, 0.0F));

parts.getBody().addOrReplaceChild("slt",
CubeListBuilder.create().texOffs(0,0)
.addBox(-5,0,-3,10,12,6),
PartPose.ZERO);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.portingdeadmods.modjam.exampleCustom3DArmor;
import com.portingdeadmods.modjam.ModJam;
import com.portingdeadmods.modjam.content.items.tiers.MJArmorMaterials;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.ArmorMaterial;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;

public class TestChestItem extends ArmorItem {
public TestChestItem(Properties properties) {
super(MJArmorMaterials.PRISMARINE,Type.CHESTPLATE,properties);
}

@Override
public @Nullable ResourceLocation getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, ArmorMaterial.Layer layer, boolean innerModel) {
return ResourceLocation.fromNamespaceAndPath(ModJam.MODID,"textures/example/test.png");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.portingdeadmods.modjam.exampleCustom3DArmor;
import com.portingdeadmods.modjam.ModJam;
import com.portingdeadmods.modjam.content.items.tiers.MJArmorMaterials;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.ArmorMaterial;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;

public class TestItem extends ArmorItem {
public TestItem(Properties properties) {
super(MJArmorMaterials.PRISMARINE,Type.HELMET,properties);
}

@Override
public @Nullable ResourceLocation getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, ArmorMaterial.Layer layer, boolean innerModel) {
return ResourceLocation.fromNamespaceAndPath(ModJam.MODID,"textures/example/test.png");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.portingdeadmods.modjam.utils;

import com.portingdeadmods.modjam.ModJam;
import com.portingdeadmods.modjam.api.client.model.MJArmorModel;
import com.portingdeadmods.modjam.exampleCustom3DArmor.TestArmorModel;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
import org.apache.commons.lang3.tuple.Pair;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Supplier;

public class ArmorModelsHandler {

private static final Map<ModelLayerLocation, Layer> layers = new HashMap<>();
private static final Map<Pair<ModelLayerLocation, EquipmentSlot>, MJArmorModel> cachedArmors = new HashMap<>();

public static ModelLayerLocation test;

private static boolean modelsInitted = false;

private static void initModels() {
if(modelsInitted)
return;

test = addArmorModel("test", TestArmorModel::createLayerDefinition);

modelsInitted = true;
}


private static ModelLayerLocation addArmorModel(String name, Supplier<LayerDefinition> supplier) {
return addLayer(name, new Layer(supplier, MJArmorModel::new));
}

private static ModelLayerLocation addLayer(String name, Layer layer) {
ModelLayerLocation loc = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(ModJam.MODID,name), "main");
layers.put(loc, layer);
return loc;
}


public static void registerLayers(EntityRenderersEvent.RegisterLayerDefinitions event){
initModels();
layers.forEach((loc,layer)->event.registerLayerDefinition(loc,layer.definition));
}

public static MJArmorModel armorModel(ModelLayerLocation location, EquipmentSlot slot) {
Pair<ModelLayerLocation, EquipmentSlot> key = Pair.of(location, slot);
if(cachedArmors.containsKey(key))
return cachedArmors.get(key);

initModels();

Layer layer = layers.get(location);
Minecraft mc = Minecraft.getInstance();
MJArmorModel model = layer.armorModelConstructor.apply(mc.getEntityModels().bakeLayer(location), slot);
cachedArmors.put(key, model);

return model;
}

private static class Layer {

final Supplier<LayerDefinition> definition;
final BiFunction<ModelPart, EquipmentSlot, MJArmorModel> armorModelConstructor;

public Layer(Supplier<LayerDefinition> definition, BiFunction<ModelPart, EquipmentSlot, MJArmorModel> armorModelConstructor) {
this.definition = definition;
this.armorModelConstructor = armorModelConstructor;
}

}

}
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 cc7320d

Please sign in to comment.