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:
NotEvil
2026-04-12 00:51:22 +02:00
parent 2e7a1d403b
commit f6466360b6
1947 changed files with 238025 additions and 1 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}
}