Strip all Phase references, TODO/FUTURE roadmap notes, and internal planning comments from the codebase. Run Prettier for consistent formatting across all Java files.
225 lines
7.4 KiB
Java
225 lines
7.4 KiB
Java
package com.tiedup.remake.client.renderer;
|
|
|
|
import com.mojang.blaze3d.vertex.PoseStack;
|
|
import com.mojang.math.Axis;
|
|
import com.tiedup.remake.client.animation.render.RenderConstants;
|
|
import com.tiedup.remake.client.model.DamselModel;
|
|
import com.tiedup.remake.compat.wildfire.WildfireCompat;
|
|
import com.tiedup.remake.compat.wildfire.render.WildfireDamselLayer;
|
|
import com.tiedup.remake.entities.AbstractTiedUpNpc;
|
|
import net.minecraft.client.model.HumanoidArmorModel;
|
|
import net.minecraft.client.model.geom.ModelLayers;
|
|
import net.minecraft.client.renderer.MultiBufferSource;
|
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
|
import net.minecraft.client.renderer.entity.HumanoidMobRenderer;
|
|
import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer;
|
|
import net.minecraft.client.renderer.entity.layers.ItemInHandLayer;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraftforge.api.distmarker.Dist;
|
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
|
|
/**
|
|
* Renderer for AbstractTiedUpNpc and all subtypes (Kidnapper, Elite, Archer, Merchant, Shiny).
|
|
*
|
|
* <p>Uses ISkinnedEntity interface for polymorphic texture lookup.
|
|
* Each entity subclass overrides getSkinTexture() to return the appropriate texture.
|
|
*
|
|
* <p><b>Issue #19 fix:</b> Replaced 6+ instanceof checks with single interface call.
|
|
*/
|
|
@OnlyIn(Dist.CLIENT)
|
|
public class DamselRenderer
|
|
extends HumanoidMobRenderer<AbstractTiedUpNpc, DamselModel>
|
|
{
|
|
|
|
/**
|
|
* Normal arms model (4px wide - Steve model).
|
|
*/
|
|
private final DamselModel normalModel;
|
|
|
|
/**
|
|
* Slim arms model (3px wide - Alex model).
|
|
*/
|
|
private final DamselModel slimModel;
|
|
|
|
/**
|
|
* Create renderer.
|
|
*
|
|
*/
|
|
public DamselRenderer(EntityRendererProvider.Context context) {
|
|
super(
|
|
context,
|
|
new DamselModel(context.bakeLayer(ModelLayers.PLAYER), false),
|
|
0.5f // Shadow radius
|
|
);
|
|
// Store both models for runtime swapping
|
|
this.normalModel = this.getModel();
|
|
this.slimModel = new DamselModel(
|
|
context.bakeLayer(ModelLayers.PLAYER_SLIM),
|
|
true
|
|
);
|
|
|
|
// Add armor render layer (renders equipped armor)
|
|
this.addLayer(
|
|
new HumanoidArmorLayer<>(
|
|
this,
|
|
new HumanoidArmorModel<>(
|
|
context.bakeLayer(ModelLayers.PLAYER_INNER_ARMOR)
|
|
),
|
|
new HumanoidArmorModel<>(
|
|
context.bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR)
|
|
),
|
|
context.getModelManager()
|
|
)
|
|
);
|
|
|
|
// Add item in hand layer (renders held items)
|
|
this.addLayer(
|
|
new ItemInHandLayer<>(this, context.getItemInHandRenderer())
|
|
);
|
|
|
|
// Add Wildfire breast layer BEFORE bondage (so bondage renders on top of breasts)
|
|
if (WildfireCompat.isLoaded()) {
|
|
this.addLayer(
|
|
new WildfireDamselLayer<>(this, context.getModelSet())
|
|
);
|
|
}
|
|
|
|
// Add V2 bondage render layer (GLB-based V2 equipment rendering)
|
|
this.addLayer(
|
|
new com.tiedup.remake.v2.bondage.client.V2BondageRenderLayer<>(this)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Render the entity.
|
|
* Uses entity's hasSlimArms() for model selection.
|
|
*
|
|
* to ensure it happens after visibility resets.
|
|
*
|
|
* DOG pose: X rotation is applied in setupRotations() AFTER Y rotation,
|
|
* so the "belly down" direction follows entity facing.
|
|
* Head compensation is applied in DamselModel.setupAnim().
|
|
* Body rotation smoothing is handled in AbstractTiedUpNpc.tick().
|
|
*/
|
|
@Override
|
|
public void render(
|
|
AbstractTiedUpNpc entity,
|
|
float entityYaw,
|
|
float partialTicks,
|
|
PoseStack poseStack,
|
|
MultiBufferSource buffer,
|
|
int packedLight
|
|
) {
|
|
// Use entity's hasSlimArms() - each entity type overrides this appropriately
|
|
boolean useSlim = entity.hasSlimArms();
|
|
|
|
// Swap to appropriate model
|
|
this.model = useSlim ? this.slimModel : this.normalModel;
|
|
|
|
// Apply vertical offset for sitting/kneeling/dog poses
|
|
// This ensures the model AND all layers (gag, blindfold, etc.) move together
|
|
float verticalOffset = getVerticalOffset(entity);
|
|
boolean pushedPose = false;
|
|
if (verticalOffset != 0) {
|
|
poseStack.pushPose();
|
|
pushedPose = true;
|
|
// Convert from model units (16 = 1 block) to render units
|
|
poseStack.translate(0, verticalOffset / 16.0, 0);
|
|
}
|
|
|
|
// Call parent render
|
|
// Note: Wearer layer hiding happens in DamselModel.setupAnim()
|
|
super.render(
|
|
entity,
|
|
entityYaw,
|
|
partialTicks,
|
|
poseStack,
|
|
buffer,
|
|
packedLight
|
|
);
|
|
|
|
if (pushedPose) {
|
|
poseStack.popPose();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get vertical offset for sitting/kneeling/dog poses.
|
|
* Returns offset in model units (16 units = 1 block).
|
|
*
|
|
* @param entity The entity to check
|
|
* @return Vertical offset (negative = down)
|
|
*/
|
|
private float getVerticalOffset(AbstractTiedUpNpc entity) {
|
|
if (entity.isSitting()) {
|
|
return RenderConstants.DAMSEL_SIT_OFFSET;
|
|
} else if (entity.isKneeling()) {
|
|
return RenderConstants.DAMSEL_KNEEL_OFFSET;
|
|
} else if (entity.isDogPose()) {
|
|
return RenderConstants.DAMSEL_DOG_OFFSET;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Get the texture location based on entity type.
|
|
*
|
|
* <p>Issue #19 fix: Uses ISkinnedEntity interface instead of instanceof cascade.
|
|
* Each entity subclass implements getSkinTexture() to return appropriate texture.
|
|
*/
|
|
@Override
|
|
public ResourceLocation getTextureLocation(AbstractTiedUpNpc entity) {
|
|
// ISkinnedEntity provides polymorphic skin texture lookup
|
|
// Each entity type (Damsel, Kidnapper, Elite, Archer, Merchant, Shiny)
|
|
// overrides getSkinTexture() to return the correct texture
|
|
return entity.getSkinTexture();
|
|
}
|
|
|
|
/**
|
|
* Apply scale transformation.
|
|
*/
|
|
@Override
|
|
protected void scale(
|
|
AbstractTiedUpNpc entity,
|
|
PoseStack poseStack,
|
|
float partialTick
|
|
) {
|
|
poseStack.scale(0.9375f, 0.9375f, 0.9375f);
|
|
}
|
|
|
|
/**
|
|
* Setup rotations for the entity.
|
|
*
|
|
* DOG pose: After Y rotation is applied by parent, add X rotation
|
|
* to make the body horizontal. This is applied in entity-local space,
|
|
* so the "belly down" direction follows the entity's facing.
|
|
*/
|
|
@Override
|
|
protected void setupRotations(
|
|
AbstractTiedUpNpc entity,
|
|
PoseStack poseStack,
|
|
float ageInTicks,
|
|
float rotationYaw,
|
|
float partialTicks
|
|
) {
|
|
// Call parent to apply Y rotation (body facing)
|
|
super.setupRotations(
|
|
entity,
|
|
poseStack,
|
|
ageInTicks,
|
|
rotationYaw,
|
|
partialTicks
|
|
);
|
|
|
|
// DOG pose: Apply X rotation to make body horizontal
|
|
// This happens AFTER Y rotation, so it's in entity-local space
|
|
if (entity.isDogPose()) {
|
|
// Rotate -90° on X axis around the model's pivot point
|
|
// Pivot at waist height (12 model units = 0.75 blocks up from feet)
|
|
poseStack.translate(0, 0.75, 0);
|
|
poseStack.mulPose(Axis.XP.rotationDegrees(-90));
|
|
poseStack.translate(0, -0.75, 0);
|
|
}
|
|
}
|
|
}
|