package com.tiedup.remake.client;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.PoseType;
import com.tiedup.remake.v2.bondage.PoseTypeHelper;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderArmEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
/**
* Renders mittens on the player's arms in first-person view.
*
* Uses RenderArmEvent which fires specifically when a player's arm
* is being rendered in first person. This is more targeted than RenderHandEvent.
*
* @see RenderArmEvent Documentation
*/
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(
modid = TiedUpMod.MOD_ID,
bus = Mod.EventBusSubscriber.Bus.FORGE,
value = Dist.CLIENT
)
public class FirstPersonMittensRenderer {
private static final ResourceLocation MITTENS_TEXTURE =
ResourceLocation.fromNamespaceAndPath(
TiedUpMod.MOD_ID,
"textures/models/bondage/mittens/mittens.png"
);
/**
* Render mittens overlay on the player's arm in first-person view.
*
* This event fires after the arm is set up for rendering but we can add
* our own rendering on top of it.
*/
@SubscribeEvent
public static void onRenderArm(RenderArmEvent event) {
AbstractClientPlayer player = event.getPlayer();
// Get player's bind state
PlayerBindState state = PlayerBindState.getInstance(player);
if (state == null) return;
// If tied up, arms are hidden by FirstPersonHandHideHandler - don't render mittens
if (state.isTiedUp()) return;
// Check if player has mittens
if (!state.hasMittens()) return;
// Hide mittens when player is in a wrap or latex sack (hands are covered)
if (isBindHidingMittens(player)) return;
// Render mittens on this arm
renderMittensOnArm(event);
}
/**
* Render the mittens overlay on the arm.
*/
private static void renderMittensOnArm(RenderArmEvent event) {
PoseStack poseStack = event.getPoseStack();
MultiBufferSource buffer = event.getMultiBufferSource();
int packedLight = event.getPackedLight();
AbstractClientPlayer player = event.getPlayer();
HumanoidArm arm = event.getArm();
// Get the player's model to access the arm ModelPart
Minecraft mc = Minecraft.getInstance();
var renderer = mc.getEntityRenderDispatcher().getRenderer(player);
if (!(renderer instanceof PlayerRenderer playerRenderer)) return;
PlayerModel playerModel =
playerRenderer.getModel();
poseStack.pushPose();
// Get the appropriate arm from the player model
ModelPart armPart = (arm == HumanoidArm.RIGHT)
? playerModel.rightArm
: playerModel.leftArm;
ModelPart sleevePart = (arm == HumanoidArm.RIGHT)
? playerModel.rightSleeve
: playerModel.leftSleeve;
// The arm is already positioned by the game's first-person renderer
// We just need to render our mittens texture on top
// Use a slightly scaled version to appear on top (avoid z-fighting)
poseStack.scale(1.001F, 1.001F, 1.001F);
// Render the arm with mittens texture
VertexConsumer vertexConsumer = buffer.getBuffer(
RenderType.entitySolid(MITTENS_TEXTURE)
);
// Render the arm part with mittens texture
armPart.render(
poseStack,
vertexConsumer,
packedLight,
OverlayTexture.NO_OVERLAY
);
// Also render the sleeve part if visible
if (sleevePart.visible) {
sleevePart.render(
poseStack,
vertexConsumer,
packedLight,
OverlayTexture.NO_OVERLAY
);
}
poseStack.popPose();
}
/**
* Check if the player's current bind variant hides mittens.
* WRAP and LATEX_SACK cover the entire body including hands.
*/
private static boolean isBindHidingMittens(AbstractClientPlayer player) {
net.minecraft.world.item.ItemStack bindStack =
V2EquipmentHelper.getInRegion(player, BodyRegionV2.ARMS);
if (bindStack.isEmpty()) return false;
PoseType poseType = PoseTypeHelper.getPoseType(bindStack);
return poseType == PoseType.WRAP || poseType == PoseType.LATEX_SACK;
}
}