Files
TiedUp-/src/main/java/com/tiedup/remake/util/RestraintApplicator.java
NotEvil 449178f57b feat(D-01/C): consumer migration — 85 files migrated to V2 helpers
Phase 1 (state): PlayerBindState, PlayerCaptorManager, PlayerEquipment,
  PlayerDataRetrieval, PlayerLifecycle, PlayerShockCollar, StruggleAccessory
Phase 2 (client): AnimationTickHandler, NpcAnimationTickHandler, 5 render
  handlers, DamselModel, 3 client mixins, SelfBondageInputHandler,
  SlaveManagementScreen, ActionPanel, SlaveEntryWidget, ModKeybindings
Phase 3 (entities): 28 entity/AI files migrated to CollarHelper,
  BindModeHelper, PoseTypeHelper, createStack()
Phase 4 (network): PacketSlaveAction, PacketMasterEquip,
  PacketAssignCellToCollar, PacketNpcCommand, PacketFurnitureForcemount
Phase 5 (events): RestraintTaskTickHandler, PetPlayRestrictionHandler,
  PlayerEnslavementHandler, ChatEventHandler, LaborAttackPunishmentHandler
Phase 6 (commands): BondageSubCommand, CollarCommand, NPCCommand,
  KidnapSetCommand
Phase 7 (compat): MCAKidnappedAdapter, MCA mixins
Phase 8 (misc): GagTalkManager, PetRequestManager, HangingCagePiece,
  BondageItemBlockEntity, TrappedChestBlockEntity, DispenserBehaviors,
  BondageItemLoaderUtility, RestraintApplicator, StruggleSessionManager,
  MovementStyleResolver, CampLifecycleManager

Some files retain dual V1/V2 checks (instanceof V1 || V2Helper) for
coexistence — V1-only branches removed in Branch D.
2026-04-15 00:16:50 +02:00

345 lines
10 KiB
Java

package com.tiedup.remake.util;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.IHasResistance;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.v2.bondage.CollarHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.UUID;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
/**
* Utility class for applying restraints to entities.
*
*
* This class provides methods for applying various restraints (binds, gags,
* blindfolds, etc.) to targets with consistent validation. Used by:
* - KidnapperCaptureGoal
* - KidnapperPunishGoal
* - EntityRopeArrow
* - Other capture/restraint mechanics
*/
public final class RestraintApplicator {
private RestraintApplicator() {
// Utility class - no instantiation
}
// ==================== BIND ====================
/**
* Apply a bind or tighten existing binds.
*
* @param target The target entity
* @param bind The bind item to apply if needed
* @return true if bind was applied or tightened
*/
public static boolean applyOrTightenBind(
LivingEntity target,
ItemStack bind
) {
IBondageState state = KidnappedHelper.getKidnappedState(target);
if (state == null) {
return false;
}
ItemStack currentBind = state.getEquipment(BodyRegionV2.ARMS);
if (currentBind.isEmpty()) {
// No bind - apply new one
if (bind != null && !bind.isEmpty()) {
state.equip(BodyRegionV2.ARMS, bind.copy());
return true;
}
return false;
}
// Tighten existing bind - reset resistance to max
if (currentBind.getItem() instanceof IHasResistance bindItem) {
int maxResistance = bindItem.getBaseResistance(target);
state.setCurrentBindResistance(maxResistance);
return true;
}
return false;
}
/**
* Tighten an entity's binds, resetting resistance to max.
* This happens when a guard catches someone struggling.
*
* <p>Consolidated from EntityKidnapper, EntityMaid, EntitySlaveTrader, KidnapperPunishGoal.</p>
*
* @param state The prisoner's kidnapped state
* @param prisoner The prisoner entity
* @return true if binds were tightened, false if no binds equipped
*/
public static boolean tightenBind(
IBondageState state,
LivingEntity prisoner
) {
if (state == null) return false;
ItemStack bind = state.getEquipment(BodyRegionV2.ARMS);
if (bind.isEmpty()) {
return false;
}
if (bind.getItem() instanceof IHasResistance resistItem) {
int baseResistance = resistItem.getBaseResistance(prisoner);
resistItem.setCurrentResistance(bind, baseResistance);
// Notify the prisoner
if (prisoner instanceof ServerPlayer serverPlayer) {
serverPlayer.sendSystemMessage(
Component.literal(
"Your restraints have been tightened!"
).withStyle(ChatFormatting.RED)
);
}
TiedUpMod.LOGGER.debug(
"[RestraintApplicator] Tightened {}'s binds (resistance reset to {})",
prisoner.getName().getString(),
baseResistance
);
return true;
}
return false;
}
// ==================== GAG ====================
/**
* Apply a gag to the target.
*
* @param target The target entity
* @param gag The gag item to apply
* @return true if successfully applied, false if already gagged or invalid
*/
public static boolean applyGag(LivingEntity target, ItemStack gag) {
IBondageState state = KidnappedHelper.getKidnappedState(target);
if (state == null || gag == null || gag.isEmpty()) {
return false;
}
if (state.isGagged()) {
return false; // Already gagged
}
state.equip(BodyRegionV2.MOUTH, gag.copy());
return true;
}
/**
* Apply a gag only if the target doesn't have one.
*
* @param target The target entity
* @param gag The gag item to apply
* @return true if gag was applied
*/
public static boolean applyGagIfMissing(
LivingEntity target,
ItemStack gag
) {
IBondageState state = KidnappedHelper.getKidnappedState(target);
if (state == null || gag == null || gag.isEmpty()) {
return false;
}
ItemStack currentGag = state.getEquipment(BodyRegionV2.MOUTH);
if (!currentGag.isEmpty()) {
return false; // Already has gag
}
state.equip(BodyRegionV2.MOUTH, gag.copy());
return true;
}
// ==================== BLINDFOLD ====================
/**
* Apply a blindfold to the target.
*
* @param target The target entity
* @param blindfold The blindfold item to apply
* @return true if successfully applied, false if already blindfolded or invalid
*/
public static boolean applyBlindfold(
LivingEntity target,
ItemStack blindfold
) {
IBondageState state = KidnappedHelper.getKidnappedState(target);
if (state == null || blindfold == null || blindfold.isEmpty()) {
return false;
}
if (state.isBlindfolded()) {
return false; // Already blindfolded
}
state.equip(BodyRegionV2.EYES, blindfold.copy());
return true;
}
/**
* Apply a blindfold only if the target doesn't have one.
*
* @param target The target entity
* @param blindfold The blindfold item to apply
* @return true if blindfold was applied
*/
public static boolean applyBlindfoldIfMissing(
LivingEntity target,
ItemStack blindfold
) {
IBondageState state = KidnappedHelper.getKidnappedState(target);
if (state == null || blindfold == null || blindfold.isEmpty()) {
return false;
}
ItemStack currentBlindfold = state.getEquipment(BodyRegionV2.EYES);
if (!currentBlindfold.isEmpty()) {
return false; // Already has blindfold
}
state.equip(BodyRegionV2.EYES, blindfold.copy());
return true;
}
// ==================== MITTENS ====================
/**
* Apply mittens to the target.
*
* @param target The target entity
* @param mittens The mittens item to apply
* @return true if successfully applied, false if already has mittens or invalid
*/
public static boolean applyMittens(LivingEntity target, ItemStack mittens) {
IBondageState state = KidnappedHelper.getKidnappedState(target);
if (state == null || mittens == null || mittens.isEmpty()) {
return false;
}
if (state.hasMittens()) {
return false; // Already has mittens
}
state.equip(BodyRegionV2.HANDS, mittens.copy());
return true;
}
// ==================== EARPLUGS ====================
/**
* Apply earplugs to the target.
*
* @param target The target entity
* @param earplugs The earplugs item to apply
* @return true if successfully applied, false if already has earplugs or invalid
*/
public static boolean applyEarplugs(
LivingEntity target,
ItemStack earplugs
) {
IBondageState state = KidnappedHelper.getKidnappedState(target);
if (state == null || earplugs == null || earplugs.isEmpty()) {
return false;
}
if (state.hasEarplugs()) {
return false; // Already has earplugs
}
state.equip(BodyRegionV2.EARS, earplugs.copy());
return true;
}
// ==================== COLLAR ====================
/**
* Apply a collar to the target with owner information.
*
* @param target The target entity
* @param collar The collar item to apply
* @param ownerUUID The owner's UUID (can be null)
* @param ownerName The owner's name (can be null)
* @return true if successfully applied, false if already has collar or invalid
*/
public static boolean applyCollar(
LivingEntity target,
ItemStack collar,
@Nullable UUID ownerUUID,
@Nullable String ownerName
) {
IBondageState state = KidnappedHelper.getKidnappedState(target);
if (state == null || collar == null || collar.isEmpty()) {
return false;
}
if (state.hasCollar()) {
return false; // Already has collar
}
ItemStack collarCopy = collar.copy();
// Add owner if provided
if (ownerUUID != null && CollarHelper.isCollar(collarCopy)) {
CollarHelper.addOwner(
collarCopy,
ownerUUID,
ownerName != null ? ownerName : "Unknown"
);
}
state.equip(BodyRegionV2.NECK, collarCopy);
return true;
}
/**
* Apply a collar without owner information.
*
* @param target The target entity
* @param collar The collar item to apply
* @return true if successfully applied
*/
public static boolean applyCollar(LivingEntity target, ItemStack collar) {
return applyCollar(target, collar, null, null);
}
// ==================== BULK OPERATIONS ====================
/**
* Check if target has any restraints.
*
* @param target The target entity
* @return true if target has any restraints
*/
public static boolean hasAnyRestraint(LivingEntity target) {
IBondageState state = KidnappedHelper.getKidnappedState(target);
if (state == null) {
return false;
}
return (
state.isTiedUp() ||
state.isGagged() ||
state.isBlindfolded() ||
state.hasMittens() ||
state.hasEarplugs() ||
state.hasCollar()
);
}
/**
* Get the kidnapped state for an entity.
*
* @param target The target entity
* @return The IBondageState state, or null if not available
*/
@Nullable
public static IBondageState getState(LivingEntity target) {
return KidnappedHelper.getKidnappedState(target);
}
}