package com.tiedup.remake.util; import com.tiedup.remake.compat.mca.MCACompat; import com.tiedup.remake.v2.BodyRegionV2; import com.tiedup.remake.state.IRestrainable; import com.tiedup.remake.state.PlayerBindState; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import org.jetbrains.annotations.Nullable; /** * Phase 14.1: Helper utility for working with IRestrainable entities. * * Provides convenient methods for obtaining IRestrainable instances from various entity types. * *

Purpose

* This helper abstracts the complexity of determining whether an entity can be kidnapped/restrained * and provides a unified way to access the IRestrainable interface across different entity types. * *

Supported Entity Types

* * *

Usage Example

*
{@code
 * public InteractionResult interactLivingEntity(ItemStack stack, Player user,
 *                                                LivingEntity target, InteractionHand hand) {
 *     IRestrainable state = KidnappedHelper.getKidnappedState(target);
 *     if (state == null) {
 *         return InteractionResult.PASS; // Entity cannot be restrained
 *     }
 *
 *     if (state.isTiedUp()) {
 *         user.sendSystemMessage(Component.literal("Already tied up!"));
 *         return InteractionResult.FAIL;
 *     }
 *
 *     state.equip(BodyRegionV2.ARMS, stack.copy());
 *     return InteractionResult.SUCCESS;
 * }
 * }
*/ public class KidnappedHelper { /** * Get the IRestrainable instance for any living entity. * *

This method determines the appropriate IRestrainable implementation based on entity type: *

* * @param entity The living entity to check * @return The IRestrainable instance, or null if entity cannot be kidnapped */ @Nullable public static IRestrainable getKidnappedState(LivingEntity entity) { if (entity == null) { return null; } // For Players: Use PlayerBindState singleton if (entity instanceof Player player) { return PlayerBindState.getInstance(player); } // For NPCs that implement IRestrainable (EntityDamsel, EntityKidnapper, etc.) if (entity instanceof IRestrainable kidnapped) { return kidnapped; } // MCA Compatibility: Check if entity is an MCA villager if (MCACompat.isMCALoaded() && MCACompat.isMCAVillager(entity)) { IRestrainable mcaState = MCACompat.getKidnappedState(entity); com.tiedup.remake.core.TiedUpMod.LOGGER.debug( "[KidnappedHelper] MCA villager {} -> state: {}", entity.getName().getString(), mcaState != null ? mcaState.getClass().getSimpleName() : "null" ); return mcaState; } // Entity cannot be kidnapped return null; } /** * Check if an entity can be kidnapped/restrained. * * @param entity The living entity to check * @return true if the entity implements IRestrainable or is a Player */ public static boolean canBeKidnapped(LivingEntity entity) { return getKidnappedState(entity) != null; } /** * Check if an entity is currently tied up. * *

Convenience method that combines {@link #getKidnappedState(LivingEntity)} * and {@link IRestrainable#isTiedUp()}. * * @param entity The living entity to check * @return true if the entity is tied up, false otherwise */ public static boolean isTiedUp(LivingEntity entity) { IRestrainable state = getKidnappedState(entity); return state != null && state.isTiedUp(); } /** * Check if an entity is currently gagged. * *

Convenience method that combines {@link #getKidnappedState(LivingEntity)} * and {@link IRestrainable#isGagged()}. * * @param entity The living entity to check * @return true if the entity is gagged, false otherwise */ public static boolean isGagged(LivingEntity entity) { IRestrainable state = getKidnappedState(entity); return state != null && state.isGagged(); } /** * Check if an entity is currently blindfolded. * *

Convenience method that combines {@link #getKidnappedState(LivingEntity)} * and {@link IRestrainable#isBlindfolded()}. * * @param entity The living entity to check * @return true if the entity is blindfolded, false otherwise */ public static boolean isBlindfolded(LivingEntity entity) { IRestrainable state = getKidnappedState(entity); return state != null && state.isBlindfolded(); } /** * Check if an entity has a collar. * *

Convenience method that combines {@link #getKidnappedState(LivingEntity)} * and {@link IRestrainable#hasCollar()}. * * @param entity The living entity to check * @return true if the entity has a collar, false otherwise */ public static boolean hasCollar(LivingEntity entity) { IRestrainable state = getKidnappedState(entity); return state != null && state.hasCollar(); } /** * Check if an entity is enslaved. * *

Convenience method that combines {@link #getKidnappedState(LivingEntity)} * and {@link IRestrainable#isSlave()}. * * @param entity The living entity to check * @return true if the entity is enslaved, false otherwise */ /** * Phase 17: Renamed from isSlave to isCaptive */ public static boolean isCaptive(LivingEntity entity) { IRestrainable state = getKidnappedState(entity); return state != null && state.isCaptive(); } }