Proper armor rendering
- Add CustomRenderedArmorItem - Remove old code in HumanoidArmorLayerMixin - Move HumanoidArmorLayerMixin from common to client
This commit is contained in:
parent
8e936a0096
commit
d3a33896e2
11 changed files with 128 additions and 105 deletions
|
@ -259,7 +259,7 @@ public class AllItems {
|
|||
.tag(AllItemTags.PRESSURIZED_AIR_SOURCES.tag)
|
||||
.register(),
|
||||
|
||||
NETHERITE_BACKTANK = REGISTRATE.item("netherite_backtank", p -> new BacktankItem.MultiLayered(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving"), NETHERITE_BACKTANK_PLACEABLE))
|
||||
NETHERITE_BACKTANK = REGISTRATE.item("netherite_backtank", p -> new BacktankItem.Layered(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving"), NETHERITE_BACKTANK_PLACEABLE))
|
||||
.model(AssetLookup.customGenericItemModel("_", "item"))
|
||||
.tag(AllItemTags.PRESSURIZED_AIR_SOURCES.tag)
|
||||
.register();
|
||||
|
@ -269,7 +269,7 @@ public class AllItems {
|
|||
COPPER_DIVING_HELMET = REGISTRATE.item("copper_diving_helmet", p -> new DivingHelmetItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving")))
|
||||
.register(),
|
||||
|
||||
NETHERITE_DIVING_HELMET = REGISTRATE.item("netherite_diving_helmet", p -> new DivingHelmetItem.MultiLayered(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving")))
|
||||
NETHERITE_DIVING_HELMET = REGISTRATE.item("netherite_diving_helmet", p -> new DivingHelmetItem.Layered(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving")))
|
||||
.register();
|
||||
|
||||
public static final ItemEntry<? extends DivingBootsItem>
|
||||
|
@ -277,7 +277,7 @@ public class AllItems {
|
|||
COPPER_DIVING_BOOTS = REGISTRATE.item("copper_diving_boots", p -> new DivingBootsItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving")))
|
||||
.register(),
|
||||
|
||||
NETHERITE_DIVING_BOOTS = REGISTRATE.item("netherite_diving_boots", p -> new DivingBootsItem.MultiLayered(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving")))
|
||||
NETHERITE_DIVING_BOOTS = REGISTRATE.item("netherite_diving_boots", p -> new DivingBootsItem.Layered(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving")))
|
||||
.register();
|
||||
|
||||
public static final ItemEntry<SandPaperItem> SAND_PAPER = REGISTRATE.item("sand_paper", SandPaperItem::new)
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.util.function.Supplier;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.simibubi.create.content.curiosities.armor.CapacityEnchantment.ICapacityEnchantable;
|
||||
import com.simibubi.create.foundation.item.MultiLayeredArmorItem;
|
||||
import com.simibubi.create.foundation.item.LayeredArmorItem;
|
||||
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -119,14 +119,14 @@ public class BacktankItem extends BaseArmorItem implements ICapacityEnchantable
|
|||
}
|
||||
}
|
||||
|
||||
public static class MultiLayered extends BacktankItem implements MultiLayeredArmorItem {
|
||||
public MultiLayered(ArmorMaterial material, Properties properties, ResourceLocation textureLoc, Supplier<BacktankBlockItem> placeable) {
|
||||
public static class Layered extends BacktankItem implements LayeredArmorItem {
|
||||
public Layered(ArmorMaterial material, Properties properties, ResourceLocation textureLoc, Supplier<BacktankBlockItem> placeable) {
|
||||
super(material, properties, textureLoc, placeable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, String layer) {
|
||||
return String.format(Locale.ROOT, "%s:textures/models/armor/%s_layer_%s.png", textureLoc.getNamespace(), textureLoc.getPath(), layer);
|
||||
public String getArmorTextureLocation(LivingEntity entity, EquipmentSlot slot, ItemStack stack, int layer) {
|
||||
return String.format(Locale.ROOT, "%s:textures/models/armor/%s_layer_%d.png", textureLoc.getNamespace(), textureLoc.getPath(), layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.simibubi.create.content.curiosities.armor;
|
|||
|
||||
import java.util.Locale;
|
||||
|
||||
import com.simibubi.create.foundation.item.MultiLayeredArmorItem;
|
||||
import com.simibubi.create.foundation.item.LayeredArmorItem;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -77,14 +77,14 @@ public class DivingBootsItem extends BaseArmorItem {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static class MultiLayered extends DivingBootsItem implements MultiLayeredArmorItem {
|
||||
public MultiLayered(ArmorMaterial material, Properties properties, ResourceLocation textureLoc) {
|
||||
public static class Layered extends DivingBootsItem implements LayeredArmorItem {
|
||||
public Layered(ArmorMaterial material, Properties properties, ResourceLocation textureLoc) {
|
||||
super(material, properties, textureLoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, String layer) {
|
||||
return String.format(Locale.ROOT, "%s:textures/models/armor/%s_layer_%s.png", textureLoc.getNamespace(), textureLoc.getPath(), layer);
|
||||
public String getArmorTextureLocation(LivingEntity entity, EquipmentSlot slot, ItemStack stack, int layer) {
|
||||
return String.format(Locale.ROOT, "%s:textures/models/armor/%s_layer_%d.png", textureLoc.getNamespace(), textureLoc.getPath(), layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.Locale;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.simibubi.create.foundation.advancement.AllAdvancements;
|
||||
import com.simibubi.create.foundation.item.MultiLayeredArmorItem;
|
||||
import com.simibubi.create.foundation.item.LayeredArmorItem;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
@ -97,14 +97,14 @@ public class DivingHelmetItem extends BaseArmorItem {
|
|||
BacktankUtil.consumeAir(entity, backtank, 1);
|
||||
}
|
||||
|
||||
public static class MultiLayered extends DivingHelmetItem implements MultiLayeredArmorItem {
|
||||
public MultiLayered(ArmorMaterial material, Properties properties, ResourceLocation textureLoc) {
|
||||
public static class Layered extends DivingHelmetItem implements LayeredArmorItem {
|
||||
public Layered(ArmorMaterial material, Properties properties, ResourceLocation textureLoc) {
|
||||
super(material, properties, textureLoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, String layer) {
|
||||
return String.format(Locale.ROOT, "%s:textures/models/armor/%s_layer_%s.png", textureLoc.getNamespace(), textureLoc.getPath(), layer);
|
||||
public String getArmorTextureLocation(LivingEntity entity, EquipmentSlot slot, ItemStack stack, int layer) {
|
||||
return String.format(Locale.ROOT, "%s:textures/models/armor/%s_layer_%d.png", textureLoc.getNamespace(), textureLoc.getPath(), layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package com.simibubi.create.foundation.item;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public interface CustomRenderedArmorItem {
|
||||
void renderArmorPiece(HumanoidArmorLayer<?, ?, ?> layer, PoseStack poseStack, MultiBufferSource bufferSource, LivingEntity entity, EquipmentSlot slot, int light, HumanoidModel<?> originalModel, ItemStack stack);
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.simibubi.create.foundation.item;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.foundation.mixin.accessor.HumanoidArmorLayerAccessor;
|
||||
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public interface LayeredArmorItem extends CustomRenderedArmorItem {
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
default void renderArmorPiece(HumanoidArmorLayer<?, ?, ?> layer, PoseStack poseStack,
|
||||
MultiBufferSource bufferSource, LivingEntity entity, EquipmentSlot slot, int light,
|
||||
HumanoidModel<?> originalModel, ItemStack stack) {
|
||||
if (!(stack.getItem() instanceof ArmorItem item)) {
|
||||
return;
|
||||
}
|
||||
if (item.getSlot() != slot) {
|
||||
return;
|
||||
}
|
||||
|
||||
HumanoidArmorLayerAccessor accessor = (HumanoidArmorLayerAccessor) layer;
|
||||
Map<String, ResourceLocation> locationCache = HumanoidArmorLayerAccessor.create$getArmorLocationCache();
|
||||
boolean glint = stack.hasFoil();
|
||||
|
||||
HumanoidModel<?> innerModel = accessor.create$getInnerModel();
|
||||
layer.getParentModel().copyPropertiesTo((HumanoidModel) innerModel);
|
||||
accessor.create$callSetPartVisibility(innerModel, slot);
|
||||
String locationStr2 = getArmorTextureLocation(entity, slot, stack, 2);
|
||||
ResourceLocation location2 = locationCache.computeIfAbsent(locationStr2, ResourceLocation::new);
|
||||
accessor.create$callRenderModel(poseStack, bufferSource, light, glint, innerModel, 1.0F, 1.0F, 1.0F, location2);
|
||||
|
||||
HumanoidModel<?> outerModel = accessor.create$getOuterModel();
|
||||
layer.getParentModel().copyPropertiesTo((HumanoidModel) outerModel);
|
||||
accessor.create$callSetPartVisibility(outerModel, slot);
|
||||
String locationStr1 = getArmorTextureLocation(entity, slot, stack, 1);
|
||||
ResourceLocation location1 = locationCache.computeIfAbsent(locationStr1, ResourceLocation::new);
|
||||
accessor.create$callRenderModel(poseStack, bufferSource, light, glint, outerModel, 1.0F, 1.0F, 1.0F, location1);
|
||||
}
|
||||
|
||||
String getArmorTextureLocation(LivingEntity entity, EquipmentSlot slot, ItemStack stack, int layer);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package com.simibubi.create.foundation.item;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
import net.minecraft.world.item.DyeableLeatherItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.common.extensions.IForgeItem;
|
||||
|
||||
/**
|
||||
* This interface is meant to be implemented on {@link ArmorItem}s, which will allow them to be rendered on both the inner model and outer model.
|
||||
*
|
||||
* <p>Classes implementing this interface <b>must not</b> also implement {@link DyeableLeatherItem}.
|
||||
*
|
||||
* <p>Classes that implement this interface and override {@link IForgeItem#getArmorTexture(ItemStack, Entity, EquipmentSlot, String) getArmorTexture}
|
||||
* must note that the {@code String} argument will be used for layer context instead of the type.
|
||||
* This string will always be {@code "1"} when querying the location for the outer model or {@code "2"} when querying the location for the inner model.
|
||||
*/
|
||||
public interface MultiLayeredArmorItem {
|
||||
}
|
|
@ -1,87 +1,28 @@
|
|||
package com.simibubi.create.foundation.mixin;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.At.Shift;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.foundation.item.MultiLayeredArmorItem;
|
||||
import com.simibubi.create.foundation.item.CustomRenderedArmorItem;
|
||||
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
@Mixin(HumanoidArmorLayer.class)
|
||||
public class HumanoidArmorLayerMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private HumanoidModel<?> innerModel;
|
||||
@Shadow
|
||||
@Final
|
||||
private HumanoidModel<?> outerModel;
|
||||
|
||||
@Unique
|
||||
private boolean intercepted;
|
||||
@Unique
|
||||
private Boolean useInnerTexture;
|
||||
|
||||
@Shadow
|
||||
private void renderArmorPiece(PoseStack poseStack, MultiBufferSource buffer, LivingEntity livingEntity, EquipmentSlot slot, int packedLight, HumanoidModel<?> model) {
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private boolean usesInnerModel(EquipmentSlot slot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Inject(method = "renderArmorPiece", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;getParentModel()Lnet/minecraft/client/model/EntityModel;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
|
||||
private void onRenderArmorPiece(PoseStack poseStack, MultiBufferSource buffer, LivingEntity livingEntity, EquipmentSlot slot, int packedLight, HumanoidModel<?> model, CallbackInfo ci, ItemStack stack, ArmorItem armorItem) {
|
||||
if (intercepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (armorItem instanceof MultiLayeredArmorItem) {
|
||||
intercepted = true;
|
||||
|
||||
useInnerTexture = true;
|
||||
renderArmorPiece(poseStack, buffer, livingEntity, slot, packedLight, innerModel);
|
||||
useInnerTexture = false;
|
||||
renderArmorPiece(poseStack, buffer, livingEntity, slot, packedLight, outerModel);
|
||||
|
||||
useInnerTexture = null;
|
||||
intercepted = false;
|
||||
@Inject(method = "renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;)V", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/entity/LivingEntity;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
|
||||
private void onRenderArmorPiece(PoseStack poseStack, MultiBufferSource bufferSource, LivingEntity entity, EquipmentSlot slot, int light, HumanoidModel<?> model, CallbackInfo ci, ItemStack stack) {
|
||||
if (stack.getItem() instanceof CustomRenderedArmorItem renderer) {
|
||||
renderer.renderArmorPiece((HumanoidArmorLayer<?, ?, ?>) (Object) this, poseStack, bufferSource, entity, slot, light, model, stack);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "usesInnerModel", at = @At("HEAD"), cancellable = true)
|
||||
private void onUsesInnerModel(EquipmentSlot slot, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (useInnerTexture != null) {
|
||||
cir.setReturnValue(useInnerTexture);
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "getArmorResource", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/client/ForgeHooksClient;getArmorTexture(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/item/ItemStack;Ljava/lang/String;Lnet/minecraft/world/entity/EquipmentSlot;Ljava/lang/String;)Ljava/lang/String;", shift = Shift.BEFORE), ordinal = 0, remap = false)
|
||||
private String modifyType(@Nullable String type, Entity entity, ItemStack stack, EquipmentSlot slot, @Nullable String typeArg) {
|
||||
if (stack.getItem() instanceof MultiLayeredArmorItem) {
|
||||
return usesInnerModel(slot) ? "2" : "1";
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import net.minecraft.client.model.geom.ModelPart;
|
|||
public interface AgeableListModelAccessor {
|
||||
@Invoker("headParts")
|
||||
Iterable<ModelPart> create$callHeadParts();
|
||||
|
||||
@Invoker("bodyParts")
|
||||
Iterable<ModelPart> create$callBodyParts();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package com.simibubi.create.foundation.mixin.accessor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.Model;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
|
||||
@Mixin(HumanoidArmorLayer.class)
|
||||
public interface HumanoidArmorLayerAccessor {
|
||||
@Accessor("ARMOR_LOCATION_CACHE")
|
||||
static Map<String, ResourceLocation> create$getArmorLocationCache() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Accessor("innerModel")
|
||||
HumanoidModel<?> create$getInnerModel();
|
||||
|
||||
@Accessor("outerModel")
|
||||
HumanoidModel<?> create$getOuterModel();
|
||||
|
||||
@Invoker("setPartVisibility")
|
||||
void create$callSetPartVisibility(HumanoidModel<?> model, EquipmentSlot slot);
|
||||
|
||||
@Invoker("renderModel")
|
||||
void create$callRenderModel(PoseStack poseStack, MultiBufferSource bufferSource, int light, boolean glint, Model model, float red, float green, float blue, ResourceLocation armorResource);
|
||||
}
|
|
@ -5,13 +5,12 @@
|
|||
"compatibilityLevel": "JAVA_16",
|
||||
"refmap": "create.refmap.json",
|
||||
"mixins": [
|
||||
"ContraptionDriverInteractMixin",
|
||||
"CustomItemUseEffectsMixin",
|
||||
"EnchantmentHelperMixin",
|
||||
"EnchantmentMixin",
|
||||
"EntityMixin",
|
||||
"HumanoidArmorLayerMixin",
|
||||
"MapItemSavedDataMixin",
|
||||
"ContraptionDriverInteractMixin",
|
||||
"accessor.AbstractProjectileDispenseBehaviorAccessor",
|
||||
"accessor.DispenserBlockAccessor",
|
||||
"accessor.FallingBlockEntityAccessor",
|
||||
|
@ -19,18 +18,20 @@
|
|||
"accessor.ServerLevelAccessor"
|
||||
],
|
||||
"client": [
|
||||
"MapItemSavedDataMixinClient",
|
||||
"CameraMixin",
|
||||
"DestroyProgressMixin",
|
||||
"EntityContraptionInteractionMixin",
|
||||
"FixNormalScalingMixin",
|
||||
"GameRendererMixin",
|
||||
"HeavyBootsOnPlayerMixin",
|
||||
"HumanoidArmorLayerMixin",
|
||||
"MapItemSavedDataMixinClient",
|
||||
"MapRendererMixin",
|
||||
"ModelDataRefreshMixin",
|
||||
"WindowResizeMixin",
|
||||
"accessor.AgeableListModelAccessor",
|
||||
"accessor.GameRendererAccessor",
|
||||
"accessor.HumanoidArmorLayerAccessor",
|
||||
"accessor.ParticleEngineAccessor"
|
||||
],
|
||||
"injectors": {
|
||||
|
|
Loading…
Reference in a new issue