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,198 @@
package com.tiedup.remake.client.animation.render;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.items.base.ItemBind;
import com.tiedup.remake.items.base.PoseType;
import com.tiedup.remake.state.HumanChairHelper;
import com.tiedup.remake.state.PlayerBindState;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
/**
* Handles DOG and HUMAN_CHAIR pose rendering adjustments.
*
* <p>Applies vertical offset and smooth body rotation for DOG/HUMAN_CHAIR poses.
* Runs at HIGH priority to ensure transforms are applied before other Pre handlers.
*
* <p>Extracted from PlayerArmHideEventHandler for single-responsibility.
*/
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(
modid = TiedUpMod.MOD_ID,
bus = Mod.EventBusSubscriber.Bus.FORGE,
value = Dist.CLIENT
)
public class DogPoseRenderHandler {
/**
* DOG pose state tracking per player.
* Stores: [0: smoothedTarget, 1: currentRot, 2: appliedDelta, 3: isMoving (0/1)]
*/
private static final Int2ObjectMap<float[]> dogPoseState =
new Int2ObjectOpenHashMap<>();
// Array indices for dogPoseState
private static final int IDX_TARGET = 0;
private static final int IDX_CURRENT = 1;
private static final int IDX_DELTA = 2;
private static final int IDX_MOVING = 3;
/**
* Get the rotation delta applied to a player's render for DOG pose.
* Used by MixinPlayerModel to compensate head rotation.
*/
public static float getAppliedRotationDelta(int playerId) {
float[] state = dogPoseState.get(playerId);
return state != null ? state[IDX_DELTA] : 0f;
}
/**
* Check if a player is currently moving in DOG pose.
*/
public static boolean isDogPoseMoving(int playerId) {
float[] state = dogPoseState.get(playerId);
return state != null && state[IDX_MOVING] > 0.5f;
}
/**
* Clear all DOG pose state data.
* Called on world unload to prevent memory leaks.
*/
public static void clearState() {
dogPoseState.clear();
}
/**
* Before player render: Apply vertical offset and rotation for DOG/HUMAN_CHAIR poses.
* HIGH priority ensures this runs before arm/item hiding handlers.
*/
@SubscribeEvent(priority = EventPriority.HIGH)
public static void onRenderPlayerPre(RenderPlayerEvent.Pre event) {
Player player = event.getEntity();
if (!(player instanceof AbstractClientPlayer)) {
return;
}
if (player.isRemoved() || !player.isAlive()) {
return;
}
PlayerBindState state = PlayerBindState.getInstance(player);
if (state == null) {
return;
}
ItemStack bindForPose = state.getEquipment(BodyRegionV2.ARMS);
if (
bindForPose.isEmpty() ||
!(bindForPose.getItem() instanceof ItemBind itemBind)
) {
return;
}
PoseType bindPoseType = itemBind.getPoseType();
// Check for humanChairMode NBT override
bindPoseType = HumanChairHelper.resolveEffectivePose(
bindPoseType,
bindForPose
);
if (
bindPoseType != PoseType.DOG && bindPoseType != PoseType.HUMAN_CHAIR
) {
return;
}
// Lower player by 6 model units (6/16 = 0.375 blocks)
event
.getPoseStack()
.translate(0, RenderConstants.DOG_AND_PETBED_Y_OFFSET, 0);
int playerId = player.getId();
net.minecraft.world.phys.Vec3 movement = player.getDeltaMovement();
boolean isMoving = movement.horizontalDistanceSqr() > 0.0001;
// Get or create state - initialize to current body rotation
float[] s = dogPoseState.get(playerId);
if (s == null) {
s = new float[] { player.yBodyRot, player.yBodyRot, 0f, 0f };
dogPoseState.put(playerId, s);
}
// Human chair: lock rotation state — body must not turn
if (bindPoseType == PoseType.HUMAN_CHAIR) {
s[IDX_CURRENT] = player.yBodyRot;
s[IDX_TARGET] = player.yBodyRot;
s[IDX_DELTA] = 0f;
s[IDX_MOVING] = 0f;
} else {
// Determine target rotation
float rawTarget;
if (isMoving) {
// Moving: face movement direction
rawTarget = (float) Math.toDegrees(
Math.atan2(-movement.x, movement.z)
);
} else {
// Stationary: face where head is looking
rawTarget = player.yHeadRot;
}
// Check if head would be clamped (body lagging behind head)
float predictedHeadYaw = net.minecraft.util.Mth.wrapDegrees(
player.yHeadRot - s[IDX_CURRENT]
);
float maxYaw = isMoving
? RenderConstants.HEAD_MAX_YAW_MOVING
: RenderConstants.HEAD_MAX_YAW_STATIONARY;
boolean headAtLimit =
Math.abs(predictedHeadYaw) >
maxYaw * RenderConstants.HEAD_AT_LIMIT_RATIO;
if (headAtLimit && !isMoving) {
// Head at limit while stationary: snap body to release head
float sign = predictedHeadYaw > 0 ? 1f : -1f;
s[IDX_CURRENT] =
player.yHeadRot -
sign * maxYaw * RenderConstants.HEAD_SNAP_RELEASE_RATIO;
s[IDX_TARGET] = s[IDX_CURRENT];
} else {
// Normal smoothing
float targetDelta = net.minecraft.util.Mth.wrapDegrees(
rawTarget - s[IDX_TARGET]
);
float targetSpeed = isMoving
? RenderConstants.DOG_TARGET_SPEED_MOVING
: RenderConstants.DOG_TARGET_SPEED_STATIONARY;
s[IDX_TARGET] += targetDelta * targetSpeed;
float rotDelta = net.minecraft.util.Mth.wrapDegrees(
s[IDX_TARGET] - s[IDX_CURRENT]
);
float speed = isMoving
? RenderConstants.DOG_ROT_SPEED_MOVING
: RenderConstants.DOG_ROT_SPEED_STATIONARY;
s[IDX_CURRENT] += rotDelta * speed;
}
}
// Calculate and store the delta we apply to poseStack
s[IDX_DELTA] = player.yBodyRot - s[IDX_CURRENT];
s[IDX_MOVING] = isMoving ? 1f : 0f;
// Apply rotation to make body face our custom direction
event
.getPoseStack()
.mulPose(com.mojang.math.Axis.YP.rotationDegrees(s[IDX_DELTA]));
}
}

View File

@@ -0,0 +1,51 @@
package com.tiedup.remake.client.animation.render;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.state.PlayerBindState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
/**
* Hide first-person hand/item rendering based on bondage state.
*
* Behavior:
* - Tied up: Hide hands completely (hands are behind back)
* - Mittens: Hide hands + items (Forge limitation - can't separate them)
*/
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(
modid = TiedUpMod.MOD_ID,
bus = Mod.EventBusSubscriber.Bus.FORGE,
value = Dist.CLIENT
)
public class FirstPersonHandHideHandler {
@SubscribeEvent
public static void onRenderHand(RenderHandEvent event) {
Minecraft mc = Minecraft.getInstance();
if (mc == null) {
return;
}
LocalPlayer player = mc.player;
if (player == null) {
return;
}
PlayerBindState state = PlayerBindState.getInstance(player);
if (state == null) {
return;
}
// Tied or Mittens: hide hands completely
// (Forge limitation: RenderHandEvent controls hand + item together)
if (state.isTiedUp() || state.hasMittens()) {
event.setCanceled(true);
}
}
}

View File

@@ -0,0 +1,93 @@
package com.tiedup.remake.client.animation.render;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.state.PlayerBindState;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
/**
* Hides held items when player has arms bound or is wearing mittens.
*
* <p>Uses Pre/Post pattern to temporarily replace held items with empty
* stacks for rendering, then restore them after.
*
* <p>Extracted from PlayerArmHideEventHandler for single-responsibility.
*/
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(
modid = TiedUpMod.MOD_ID,
bus = Mod.EventBusSubscriber.Bus.FORGE,
value = Dist.CLIENT
)
public class HeldItemHideHandler {
/**
* Stored items to restore after rendering.
* Key: Player entity ID (int), Value: [mainHand, offHand]
*/
private static final Int2ObjectMap<ItemStack[]> storedItems =
new Int2ObjectOpenHashMap<>();
@SubscribeEvent
public static void onRenderPlayerPre(RenderPlayerEvent.Pre event) {
Player player = event.getEntity();
if (!(player instanceof AbstractClientPlayer)) {
return;
}
if (player.isRemoved() || !player.isAlive()) {
return;
}
PlayerBindState state = PlayerBindState.getInstance(player);
if (state == null) {
return;
}
boolean hasArmsBound = state.hasArmsBound();
boolean hasMittens = state.hasMittens();
if (hasArmsBound || hasMittens) {
ItemStack mainHand = player.getItemInHand(
InteractionHand.MAIN_HAND
);
ItemStack offHand = player.getItemInHand(InteractionHand.OFF_HAND);
if (!mainHand.isEmpty() || !offHand.isEmpty()) {
storedItems.put(
player.getId(),
new ItemStack[] { mainHand.copy(), offHand.copy() }
);
player.setItemInHand(
InteractionHand.MAIN_HAND,
ItemStack.EMPTY
);
player.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY);
}
}
}
@SubscribeEvent
public static void onRenderPlayerPost(RenderPlayerEvent.Post event) {
Player player = event.getEntity();
if (!(player instanceof AbstractClientPlayer)) {
return;
}
ItemStack[] items = storedItems.remove(player.getId());
if (items != null) {
player.setItemInHand(InteractionHand.MAIN_HAND, items[0]);
player.setItemInHand(InteractionHand.OFF_HAND, items[1]);
}
}
}

View File

@@ -0,0 +1,111 @@
package com.tiedup.remake.client.animation.render;
import com.tiedup.remake.client.state.PetBedClientState;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.ItemBind;
import com.tiedup.remake.items.base.PoseType;
import com.tiedup.remake.state.HumanChairHelper;
import com.tiedup.remake.state.PlayerBindState;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
/**
* Handles pet bed render adjustments (SIT and SLEEP modes).
*
* <p>Applies vertical offset and forced standing pose for pet bed states.
* Runs at HIGH priority alongside DogPoseRenderHandler.
*
* <p>Extracted from PlayerArmHideEventHandler for single-responsibility.
*/
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(
modid = TiedUpMod.MOD_ID,
bus = Mod.EventBusSubscriber.Bus.FORGE,
value = Dist.CLIENT
)
public class PetBedRenderHandler {
/**
* Before player render: Apply vertical offset and forced pose for pet bed.
*/
@SubscribeEvent(priority = EventPriority.HIGH)
public static void onRenderPlayerPre(RenderPlayerEvent.Pre event) {
Player player = event.getEntity();
if (!(player instanceof AbstractClientPlayer)) {
return;
}
if (player.isRemoved() || !player.isAlive()) {
return;
}
java.util.UUID petBedUuid = player.getUUID();
byte petBedMode = PetBedClientState.get(petBedUuid);
if (petBedMode == 1 || petBedMode == 2) {
// Skip Y-offset if DogPoseRenderHandler already applies it
// (DOG/HUMAN_CHAIR pose uses the same offset amount)
if (!isDogOrChairPose(player)) {
event
.getPoseStack()
.translate(0, RenderConstants.DOG_AND_PETBED_Y_OFFSET, 0);
}
}
if (petBedMode == 2) {
// SLEEP: force STANDING pose to prevent vanilla sleeping rotation
player.setForcedPose(net.minecraft.world.entity.Pose.STANDING);
// Compensate for vanilla sleeping Y offset
player
.getSleepingPos()
.ifPresent(pos -> {
double yOffset = player.getY() - pos.getY();
if (yOffset > 0.01) {
event.getPoseStack().translate(0, -yOffset, 0);
}
});
}
}
/**
* Check if the player is in DOG or HUMAN_CHAIR pose.
* Used to avoid double Y-offset with DogPoseRenderHandler.
*/
private static boolean isDogOrChairPose(Player player) {
PlayerBindState state = PlayerBindState.getInstance(player);
if (state == null) return false;
ItemStack bind = state.getEquipment(BodyRegionV2.ARMS);
if (
bind.isEmpty() || !(bind.getItem() instanceof ItemBind itemBind)
) return false;
PoseType pose = HumanChairHelper.resolveEffectivePose(
itemBind.getPoseType(),
bind
);
return pose == PoseType.DOG || pose == PoseType.HUMAN_CHAIR;
}
/**
* After player render: Restore forced pose for pet bed SLEEP mode.
*/
@SubscribeEvent
public static void onRenderPlayerPost(RenderPlayerEvent.Post event) {
Player player = event.getEntity();
if (!(player instanceof AbstractClientPlayer)) {
return;
}
byte petBedMode = PetBedClientState.get(player.getUUID());
if (petBedMode == 2) {
player.setForcedPose(null);
}
}
}

View File

@@ -0,0 +1,135 @@
package com.tiedup.remake.client.animation.render;
import com.tiedup.remake.client.renderer.layers.ClothesRenderHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.ItemBind;
import com.tiedup.remake.items.base.PoseType;
import com.tiedup.remake.items.clothes.ClothesProperties;
import com.tiedup.remake.state.PlayerBindState;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
/**
* Hide player arms and outer layers based on bondage/clothes state.
*
* <p>Responsibilities (after extraction of dog pose, pet bed, and held items):
* <ul>
* <li>Hide arms for wrap/latex_sack poses</li>
* <li>Hide outer layers (hat, jacket, sleeves, pants) based on clothes settings</li>
* </ul>
*
* <p>Uses Pre/Post pattern to temporarily modify and restore state.
*/
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(
modid = TiedUpMod.MOD_ID,
bus = Mod.EventBusSubscriber.Bus.FORGE,
value = Dist.CLIENT
)
public class PlayerArmHideEventHandler {
/**
* Stored layer visibility to restore after rendering.
* Key: Player entity ID (int), Value: [hat, jacket, leftSleeve, rightSleeve, leftPants, rightPants]
*/
private static final Int2ObjectMap<boolean[]> storedLayers =
new Int2ObjectOpenHashMap<>();
/**
* Before player render:
* - Hide arms for wrap/latex_sack poses
* - Hide outer layers based on clothes settings (Phase 19)
*/
@SubscribeEvent
public static void onRenderPlayerPre(RenderPlayerEvent.Pre event) {
Player player = event.getEntity();
if (!(player instanceof AbstractClientPlayer clientPlayer)) {
return;
}
if (player.isRemoved() || !player.isAlive()) {
return;
}
PlayerBindState state = PlayerBindState.getInstance(player);
if (state == null) {
return;
}
PlayerModel<?> model = event.getRenderer().getModel();
// === HIDE ARMS (wrap/latex_sack poses) ===
if (state.hasArmsBound()) {
ItemStack bind = state.getEquipment(BodyRegionV2.ARMS);
if (
!bind.isEmpty() && bind.getItem() instanceof ItemBind itemBind
) {
PoseType poseType = itemBind.getPoseType();
// Only hide arms for wrap/sack poses (arms are covered by the item)
if (
poseType == PoseType.WRAP || poseType == PoseType.LATEX_SACK
) {
model.leftArm.visible = false;
model.rightArm.visible = false;
model.leftSleeve.visible = false;
model.rightSleeve.visible = false;
}
}
}
// === HIDE WEARER LAYERS (clothes settings) - Phase 19 ===
ItemStack clothes = state.getEquipment(BodyRegionV2.TORSO);
if (!clothes.isEmpty()) {
ClothesProperties props =
ClothesRenderHelper.getPropsForLayerHiding(
clothes,
clientPlayer
);
if (props != null) {
boolean[] savedLayers = ClothesRenderHelper.hideWearerLayers(
model,
props
);
if (savedLayers != null) {
storedLayers.put(player.getId(), savedLayers);
}
}
}
}
/**
* After player render: Restore arm visibility and layer visibility.
*/
@SubscribeEvent
public static void onRenderPlayerPost(RenderPlayerEvent.Post event) {
Player player = event.getEntity();
if (!(player instanceof AbstractClientPlayer)) {
return;
}
PlayerModel<?> model = event.getRenderer().getModel();
// === RESTORE ARM VISIBILITY ===
model.leftArm.visible = true;
model.rightArm.visible = true;
model.leftSleeve.visible = true;
model.rightSleeve.visible = true;
// === RESTORE WEARER LAYERS - Phase 19 ===
boolean[] savedLayers = storedLayers.remove(player.getId());
if (savedLayers != null) {
ClothesRenderHelper.restoreWearerLayers(model, savedLayers);
}
}
}

View File

@@ -0,0 +1,58 @@
package com.tiedup.remake.client.animation.render;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
/**
* Centralizes magic numbers used across render handlers.
*
* <p>DOG pose rotation smoothing, head clamp limits, and vertical offsets
* that were previously scattered as unnamed literals.
*/
@OnlyIn(Dist.CLIENT)
public final class RenderConstants {
private RenderConstants() {}
// === DOG pose rotation smoothing speeds ===
/** Speed for smoothing body rotation toward target while moving */
public static final float DOG_ROT_SPEED_MOVING = 0.15f;
/** Speed for smoothing body rotation toward target while stationary */
public static final float DOG_ROT_SPEED_STATIONARY = 0.12f;
/** Speed for smoothing target rotation while moving */
public static final float DOG_TARGET_SPEED_MOVING = 0.2f;
/** Speed for smoothing target rotation while stationary */
public static final float DOG_TARGET_SPEED_STATIONARY = 0.3f;
// === Head clamp limits ===
/** Maximum head yaw relative to body while moving (degrees) */
public static final float HEAD_MAX_YAW_MOVING = 60f;
/** Maximum head yaw relative to body while stationary (degrees) */
public static final float HEAD_MAX_YAW_STATIONARY = 90f;
/** Threshold ratio for detecting head-at-limit (triggers body snap) */
public static final float HEAD_AT_LIMIT_RATIO = 0.85f;
/** Ratio of max yaw to snap body to when releasing head */
public static final float HEAD_SNAP_RELEASE_RATIO = 0.7f;
// === Vertical offsets (model units, 16 = 1 block) ===
/** Y offset for DOG and PET BED poses (6/16 = 0.375 blocks) */
public static final double DOG_AND_PETBED_Y_OFFSET = -6.0 / 16.0;
/** Y offset for Damsel sitting pose (model units) */
public static final float DAMSEL_SIT_OFFSET = -10.0f;
/** Y offset for Damsel kneeling pose (model units) */
public static final float DAMSEL_KNEEL_OFFSET = -5.0f;
/** Y offset for Damsel dog pose (model units) */
public static final float DAMSEL_DOG_OFFSET = -7.0f;
}