Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
package com.tiedup.remake.client.animation.util;
|
||||
|
||||
import com.tiedup.remake.items.base.PoseType;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
/**
|
||||
* Utility class for building animation ResourceLocation IDs.
|
||||
*
|
||||
* <p>Centralizes the logic for constructing animation file names.
|
||||
* Used by BondageAnimationManager, NpcAnimationTickHandler, and AnimationTickHandler.
|
||||
*
|
||||
* <p>Animation naming convention:
|
||||
* <pre>
|
||||
* {poseType}_{bindMode}_{variant}.json
|
||||
*
|
||||
* poseType: tied_up_basic | straitjacket | wrap | latex_sack
|
||||
* bindMode: (empty for FULL) | _arms | _legs
|
||||
* variant: _idle | _struggle | (empty for static)
|
||||
* </pre>
|
||||
*
|
||||
* <p>Examples:
|
||||
* <ul>
|
||||
* <li>tiedup:tied_up_basic_idle - STANDARD + FULL + idle</li>
|
||||
* <li>tiedup:straitjacket_arms_struggle - STRAITJACKET + ARMS + struggle</li>
|
||||
* <li>tiedup:wrap_idle - WRAP + FULL + idle</li>
|
||||
* </ul>
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public final class AnimationIdBuilder {
|
||||
|
||||
private static final String NAMESPACE = "tiedup";
|
||||
|
||||
// Bind mode suffixes
|
||||
private static final String SUFFIX_ARMS = "_arms";
|
||||
private static final String SUFFIX_LEGS = "_legs";
|
||||
|
||||
// Variant suffixes
|
||||
private static final String SUFFIX_IDLE = "_idle";
|
||||
private static final String SUFFIX_WALK = "_walk";
|
||||
private static final String SUFFIX_STRUGGLE = "_struggle";
|
||||
private static final String SUFFIX_SNEAK = "_sneak";
|
||||
|
||||
private AnimationIdBuilder() {
|
||||
// Utility class - no instantiation
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base animation name from pose type.
|
||||
* Delegates to {@link PoseType#getAnimationId()}.
|
||||
*
|
||||
* @param poseType Pose type
|
||||
* @return Base name string
|
||||
*/
|
||||
public static String getBaseName(PoseType poseType) {
|
||||
return poseType.getAnimationId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get suffix for bind mode derived from region flags.
|
||||
*
|
||||
* @param armsBound whether ARMS region is occupied
|
||||
* @param legsBound whether LEGS region is occupied
|
||||
* @return Suffix string: "" for FULL (both), "_arms" for arms-only, "_legs" for legs-only
|
||||
*/
|
||||
public static String getModeSuffix(boolean armsBound, boolean legsBound) {
|
||||
if (armsBound && legsBound) return ""; // FULL has no suffix
|
||||
if (armsBound) return SUFFIX_ARMS;
|
||||
if (legsBound) return SUFFIX_LEGS;
|
||||
return ""; // neither bound = no suffix (shouldn't happen in practice)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bind type name for SIT/KNEEL animations.
|
||||
* Delegates to {@link PoseType#getBindTypeName()}.
|
||||
*
|
||||
* @param poseType Pose type
|
||||
* @return Bind type name ("basic", "straitjacket", "wrap", "latex_sack")
|
||||
*/
|
||||
public static String getBindTypeName(PoseType poseType) {
|
||||
return poseType.getBindTypeName();
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Unified Build Method
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Build animation ID string for entities.
|
||||
*
|
||||
* <p>This method handles all cases:
|
||||
* <ul>
|
||||
* <li>Standing poses: tied_up_basic_idle, straitjacket_struggle, etc.</li>
|
||||
* <li>Sitting poses: sit_basic_idle, sit_free_idle, etc.</li>
|
||||
* <li>Kneeling poses: kneel_basic_idle, kneel_wrap_struggle, etc.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param poseType The bind pose type (STANDARD, STRAITJACKET, etc.)
|
||||
* @param armsBound whether ARMS region is occupied
|
||||
* @param legsBound whether LEGS region is occupied
|
||||
* @param positionPrefix Position prefix ("sit", "kneel") or null for standing
|
||||
* @param isStruggling Whether entity is struggling
|
||||
* @param hasBind Whether entity has a bind equipped
|
||||
* @return Animation ID string (without namespace)
|
||||
*/
|
||||
public static String build(
|
||||
PoseType poseType,
|
||||
boolean armsBound,
|
||||
boolean legsBound,
|
||||
String positionPrefix,
|
||||
boolean isStruggling,
|
||||
boolean hasBind
|
||||
) {
|
||||
return build(
|
||||
poseType,
|
||||
armsBound,
|
||||
legsBound,
|
||||
positionPrefix,
|
||||
isStruggling,
|
||||
hasBind,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build animation ID string for entities with sneak support.
|
||||
*
|
||||
* @param poseType The bind pose type (STANDARD, STRAITJACKET, etc.)
|
||||
* @param armsBound whether ARMS region is occupied
|
||||
* @param legsBound whether LEGS region is occupied
|
||||
* @param positionPrefix Position prefix ("sit", "kneel") or null for standing
|
||||
* @param isStruggling Whether entity is struggling
|
||||
* @param hasBind Whether entity has a bind equipped
|
||||
* @param isSneaking Whether entity is sneaking
|
||||
* @return Animation ID string (without namespace)
|
||||
*/
|
||||
public static String build(
|
||||
PoseType poseType,
|
||||
boolean armsBound,
|
||||
boolean legsBound,
|
||||
String positionPrefix,
|
||||
boolean isStruggling,
|
||||
boolean hasBind,
|
||||
boolean isSneaking
|
||||
) {
|
||||
return build(
|
||||
poseType,
|
||||
armsBound,
|
||||
legsBound,
|
||||
positionPrefix,
|
||||
isStruggling,
|
||||
hasBind,
|
||||
isSneaking,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build animation ID string for entities with sneak and movement support.
|
||||
*
|
||||
* @param poseType The bind pose type (STANDARD, STRAITJACKET, etc.)
|
||||
* @param armsBound whether ARMS region is occupied
|
||||
* @param legsBound whether LEGS region is occupied
|
||||
* @param positionPrefix Position prefix ("sit", "kneel") or null for standing
|
||||
* @param isStruggling Whether entity is struggling
|
||||
* @param hasBind Whether entity has a bind equipped
|
||||
* @param isSneaking Whether entity is sneaking
|
||||
* @param isMoving Whether entity is moving
|
||||
* @return Animation ID string (without namespace)
|
||||
*/
|
||||
public static String build(
|
||||
PoseType poseType,
|
||||
boolean armsBound,
|
||||
boolean legsBound,
|
||||
String positionPrefix,
|
||||
boolean isStruggling,
|
||||
boolean hasBind,
|
||||
boolean isSneaking,
|
||||
boolean isMoving
|
||||
) {
|
||||
String sneakSuffix = isSneaking ? SUFFIX_SNEAK : "";
|
||||
|
||||
// Determine variant suffix based on state priority: struggle > walk > idle
|
||||
String variantSuffix;
|
||||
if (isStruggling) {
|
||||
variantSuffix = SUFFIX_STRUGGLE;
|
||||
} else if (isMoving && poseType == PoseType.DOG) {
|
||||
// DOG pose has a walking animation (tied_up_dog_walk.json)
|
||||
variantSuffix = SUFFIX_WALK;
|
||||
} else {
|
||||
variantSuffix = SUFFIX_IDLE;
|
||||
}
|
||||
|
||||
// SIT or KNEEL pose
|
||||
if (positionPrefix != null) {
|
||||
if (!hasBind) {
|
||||
// No bind: free pose (arms natural)
|
||||
return positionPrefix + "_free" + sneakSuffix + variantSuffix;
|
||||
}
|
||||
|
||||
// Has bind
|
||||
String bindTypeName;
|
||||
if (legsBound && !armsBound) {
|
||||
// LEGS-only mode = arms free
|
||||
bindTypeName = "legs";
|
||||
} else {
|
||||
// FULL or ARMS mode
|
||||
bindTypeName = getBindTypeName(poseType);
|
||||
}
|
||||
return (
|
||||
positionPrefix +
|
||||
"_" +
|
||||
bindTypeName +
|
||||
sneakSuffix +
|
||||
variantSuffix
|
||||
);
|
||||
}
|
||||
|
||||
// Standing pose (no position prefix)
|
||||
String baseName = getBaseName(poseType);
|
||||
String modeSuffix = getModeSuffix(armsBound, legsBound);
|
||||
|
||||
// LEGS-only mode: only lock legs, arms are free - no idle/struggle variants needed
|
||||
if (legsBound && !armsBound) {
|
||||
return baseName + modeSuffix;
|
||||
}
|
||||
|
||||
return baseName + modeSuffix + sneakSuffix + variantSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build animation ResourceLocation for SIT or KNEEL pose.
|
||||
*
|
||||
* @param posePrefix "sit" or "kneel"
|
||||
* @param poseType Bind pose type
|
||||
* @param armsBound whether ARMS region is occupied
|
||||
* @param legsBound whether LEGS region is occupied
|
||||
* @param isStruggling Whether entity is struggling
|
||||
* @return Animation ResourceLocation
|
||||
*/
|
||||
public static ResourceLocation buildPositionAnimation(
|
||||
String posePrefix,
|
||||
PoseType poseType,
|
||||
boolean armsBound,
|
||||
boolean legsBound,
|
||||
boolean isStruggling
|
||||
) {
|
||||
String bindTypeName;
|
||||
if (legsBound && !armsBound) {
|
||||
bindTypeName = "legs";
|
||||
} else {
|
||||
bindTypeName = getBindTypeName(poseType);
|
||||
}
|
||||
|
||||
String variantSuffix = isStruggling ? SUFFIX_STRUGGLE : SUFFIX_IDLE;
|
||||
String animationName = posePrefix + "_" + bindTypeName + variantSuffix;
|
||||
return ResourceLocation.fromNamespaceAndPath(NAMESPACE, animationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build animation ResourceLocation for SIT or KNEEL pose when NOT bound.
|
||||
*
|
||||
* @param posePrefix "sit" or "kneel"
|
||||
* @return Animation ResourceLocation for free pose
|
||||
*/
|
||||
public static ResourceLocation buildFreePositionAnimation(
|
||||
String posePrefix
|
||||
) {
|
||||
String animationName = posePrefix + "_free" + SUFFIX_IDLE;
|
||||
return ResourceLocation.fromNamespaceAndPath(NAMESPACE, animationName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.tiedup.remake.client.animation.util;
|
||||
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
/**
|
||||
* Utility class for DOG pose head compensation.
|
||||
*
|
||||
* <h2>Problem</h2>
|
||||
* <p>When in DOG pose, the body is rotated -90° pitch (horizontal, face down).
|
||||
* This makes the head point at the ground. We need to compensate:
|
||||
* <ul>
|
||||
* <li>Head pitch: add -90° offset so head looks forward</li>
|
||||
* <li>Head yaw: convert to zRot (roll) since yRot axis is sideways</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Architecture: Players vs NPCs</h2>
|
||||
* <pre>
|
||||
* ┌─────────────────────────────────────────────────────────────────┐
|
||||
* │ PLAYERS │
|
||||
* ├─────────────────────────────────────────────────────────────────┤
|
||||
* │ 1. PlayerArmHideEventHandler.onRenderPlayerPre() │
|
||||
* │ - Offset vertical (-6 model units) │
|
||||
* │ - Rotation Y lissée (dogPoseState tracking) │
|
||||
* │ │
|
||||
* │ 2. Animation (PlayerAnimator) │
|
||||
* │ - body.pitch = -90° → appliqué au PoseStack automatiquement │
|
||||
* │ │
|
||||
* │ 3. MixinPlayerModel.setupAnim() @TAIL │
|
||||
* │ - Uses DogPoseHelper.applyHeadCompensationClamped() │
|
||||
* └─────────────────────────────────────────────────────────────────┘
|
||||
*
|
||||
* ┌─────────────────────────────────────────────────────────────────┐
|
||||
* │ NPCs │
|
||||
* ├─────────────────────────────────────────────────────────────────┤
|
||||
* │ 1. EntityDamsel.tick() │
|
||||
* │ - Uses RotationSmoother for Y rotation (10% per tick) │
|
||||
* │ │
|
||||
* │ 2. DamselRenderer.setupRotations() │
|
||||
* │ - super.setupRotations() (applique rotation Y) │
|
||||
* │ - Rotation X -90° au PoseStack (APRÈS Y = espace local) │
|
||||
* │ - Offset vertical (-7 model units) │
|
||||
* │ │
|
||||
* │ 3. DamselModel.setupAnim() │
|
||||
* │ - body.xRot = 0 (évite double rotation) │
|
||||
* │ - Uses DogPoseHelper.applyHeadCompensation() │
|
||||
* └─────────────────────────────────────────────────────────────────┘
|
||||
* </pre>
|
||||
*
|
||||
* <h2>Key Differences</h2>
|
||||
* <table>
|
||||
* <tr><th>Aspect</th><th>Players</th><th>NPCs</th></tr>
|
||||
* <tr><td>Rotation X application</td><td>Auto by PlayerAnimator</td><td>Manual in setupRotations()</td></tr>
|
||||
* <tr><td>Rotation Y smoothing</td><td>PlayerArmHideEventHandler</td><td>EntityDamsel.tick() via RotationSmoother</td></tr>
|
||||
* <tr><td>Head compensation</td><td>MixinPlayerModel</td><td>DamselModel.setupAnim()</td></tr>
|
||||
* <tr><td>Reset body.xRot</td><td>Not needed</td><td>Yes (prevents double rotation)</td></tr>
|
||||
* <tr><td>Vertical offset</td><td>-6 model units</td><td>-7 model units</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* <h2>Usage</h2>
|
||||
* <p>Used by:
|
||||
* <ul>
|
||||
* <li>MixinPlayerModel - for player head compensation</li>
|
||||
* <li>DamselModel - for NPC head compensation</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see RotationSmoother for Y rotation smoothing
|
||||
* @see com.tiedup.remake.mixin.client.MixinPlayerModel
|
||||
* @see com.tiedup.remake.client.model.DamselModel
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public final class DogPoseHelper {
|
||||
|
||||
private static final float DEG_TO_RAD = (float) Math.PI / 180F;
|
||||
private static final float HEAD_PITCH_OFFSET = (float) Math.toRadians(-90);
|
||||
|
||||
private DogPoseHelper() {
|
||||
// Utility class - no instantiation
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply head compensation for DOG pose (horizontal body).
|
||||
*
|
||||
* <p>When body is horizontal (-90° pitch), the head needs compensation:
|
||||
* <ul>
|
||||
* <li>xRot: -90° offset + player's up/down look (headPitch)</li>
|
||||
* <li>yRot: 0 (this axis points sideways when body is horizontal)</li>
|
||||
* <li>zRot: -headYaw (left/right look, replaces yaw)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param head The head ModelPart to modify
|
||||
* @param hat The hat ModelPart to sync (can be null)
|
||||
* @param headPitch Player's up/down look angle in degrees
|
||||
* @param headYaw Head yaw relative to body in degrees (netHeadYaw for NPCs,
|
||||
* netHeadYaw + rotationDelta for players)
|
||||
*/
|
||||
public static void applyHeadCompensation(
|
||||
ModelPart head,
|
||||
ModelPart hat,
|
||||
float headPitch,
|
||||
float headYaw
|
||||
) {
|
||||
float pitchRad = headPitch * DEG_TO_RAD;
|
||||
float yawRad = headYaw * DEG_TO_RAD;
|
||||
|
||||
// xRot: base offset (-90° to look forward) + player's up/down look
|
||||
head.xRot = HEAD_PITCH_OFFSET + pitchRad;
|
||||
|
||||
// yRot: stays at 0 (this axis points sideways when body is horizontal)
|
||||
head.yRot = 0;
|
||||
|
||||
// zRot: used for left/right look (replaces yaw since body is horizontal)
|
||||
head.zRot = -yawRad;
|
||||
|
||||
// Sync hat layer if provided
|
||||
if (hat != null) {
|
||||
hat.copyFrom(head);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply head compensation with yaw clamping.
|
||||
*
|
||||
* <p>Same as {@link #applyHeadCompensation} but clamps yaw to a maximum angle.
|
||||
* Used for players where yaw range depends on movement state.
|
||||
*
|
||||
* @param head The head ModelPart to modify
|
||||
* @param hat The hat ModelPart to sync (can be null)
|
||||
* @param headPitch Player's up/down look angle in degrees
|
||||
* @param headYaw Head yaw relative to body in degrees
|
||||
* @param maxYaw Maximum allowed yaw angle in degrees
|
||||
*/
|
||||
public static void applyHeadCompensationClamped(
|
||||
ModelPart head,
|
||||
ModelPart hat,
|
||||
float headPitch,
|
||||
float headYaw,
|
||||
float maxYaw
|
||||
) {
|
||||
// Wrap first so 350° becomes -10° before clamping (fixes full-rotation accumulation)
|
||||
float clampedYaw = net.minecraft.util.Mth.clamp(
|
||||
net.minecraft.util.Mth.wrapDegrees(headYaw),
|
||||
-maxYaw,
|
||||
maxYaw
|
||||
);
|
||||
applyHeadCompensation(head, hat, headPitch, clampedYaw);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user