package com.tiedup.remake.v2.bondage; import com.tiedup.remake.core.SettingsAccessor; import com.tiedup.remake.core.TiedUpMod; import com.tiedup.remake.state.IBondageState; import com.tiedup.remake.state.PlayerBindState; import com.tiedup.remake.tasks.TyingTask; import com.tiedup.remake.tasks.V2TyingPlayerTask; import com.tiedup.remake.util.KidnappedHelper; import com.tiedup.remake.v2.BodyRegionV2; import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; /** * Handles the tying interaction flow for V2 data-driven ARMS items. * *
Extracted from {@code ItemBind.interactLivingEntity()} to support * the same tying task flow for data-driven items.
*/ public final class TyingInteractionHelper { private TyingInteractionHelper() {} /** * Handle right-click tying of a target entity with a V2 ARMS item. * Creates/continues a V2TyingPlayerTask. */ public static InteractionResult handleTying( ServerPlayer player, LivingEntity target, ItemStack stack, InteractionHand hand ) { IBondageState targetState = KidnappedHelper.getKidnappedState(target); if (targetState == null) return InteractionResult.PASS; // Kidnapper can't be tied themselves IBondageState kidnapperState = KidnappedHelper.getKidnappedState(player); if (kidnapperState != null && kidnapperState.isTiedUp()) { return InteractionResult.PASS; } // Already tied — try to swap if (targetState.isTiedUp()) { if (stack.isEmpty()) return InteractionResult.PASS; ItemStack oldBind = V2EquipmentHelper.unequipFromRegion(target, BodyRegionV2.ARMS); if (!oldBind.isEmpty()) { V2EquipmentHelper.equipItem(target, stack.copy()); stack.shrink(1); target.spawnAtLocation(oldBind); TiedUpMod.LOGGER.debug("[TyingInteraction] Swapped bind on {}", target.getName().getString()); return InteractionResult.SUCCESS; } return InteractionResult.PASS; } // Distance + line-of-sight (skip for self-tying) boolean isSelfTying = player.equals(target); if (!isSelfTying) { if (player.distanceTo(target) > 4.0 || !player.hasLineOfSight(target)) { return InteractionResult.PASS; } } // Create/continue tying task PlayerBindState playerState = PlayerBindState.getInstance(player); if (playerState == null) return InteractionResult.PASS; int tyingSeconds = SettingsAccessor.getTyingPlayerTime(player.level().getGameRules()); V2TyingPlayerTask newTask = new V2TyingPlayerTask( stack.copy(), stack, targetState, target, tyingSeconds, player.level(), player ); TyingTask currentTask = playerState.getCurrentTyingTask(); if (currentTask == null || !(currentTask instanceof V2TyingPlayerTask) || !currentTask.isSameTarget(target) || currentTask.isOutdated() || !ItemStack.matches(currentTask.getBind(), stack)) { // Start new task (also handles case where existing task is V1 TyingPlayerTask) playerState.setCurrentTyingTask(newTask); newTask.start(); } else { newTask = (V2TyingPlayerTask) currentTask; } newTask.update(); if (newTask.isStopped()) { // Item already consumed by V2TyingPlayerTask.onComplete() — don't shrink again playerState.setCurrentTyingTask(null); TiedUpMod.LOGGER.info("[TyingInteraction] {} tied {}", player.getName().getString(), target.getName().getString()); } return InteractionResult.SUCCESS; } }