diff --git a/src/main/java/com/tiedup/remake/network/selfbondage/PacketSelfBondage.java b/src/main/java/com/tiedup/remake/network/selfbondage/PacketSelfBondage.java index 1eb0fed..e65c9d3 100644 --- a/src/main/java/com/tiedup/remake/network/selfbondage/PacketSelfBondage.java +++ b/src/main/java/com/tiedup/remake/network/selfbondage/PacketSelfBondage.java @@ -14,8 +14,10 @@ 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.BindModeHelper; import com.tiedup.remake.v2.bondage.IV2BondageItem; import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper; +import com.tiedup.remake.v2.bondage.V2EquipResult; import java.util.function.Supplier; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; @@ -222,71 +224,112 @@ public class PacketSelfBondage { IV2BondageItem v2Item, IBondageState state ) { + java.util.Set regions = v2Item.getOccupiedRegions(stack); + + // Cannot self-collar + if (regions.contains(BodyRegionV2.NECK)) { + TiedUpMod.LOGGER.debug("[SelfBondage] {} tried to self-collar — blocked", player.getName().getString()); + return; + } + + // ARMS: tying task with progress bar + if (regions.contains(BodyRegionV2.ARMS)) { + handleV2SelfBind(player, stack, v2Item, state); + return; + } + + // Accessories (MOUTH, EYES, EARS, HANDS): instant equip + handleV2SelfAccessory(player, stack, v2Item, state); + } + + private static void handleV2SelfBind( + ServerPlayer player, + ItemStack stack, + IV2BondageItem v2Item, + IBondageState state + ) { + // Can't self-tie if already tied + if (state.isTiedUp()) { + TiedUpMod.LOGGER.debug("[SelfBondage] {} tried V2 self-tie but already tied", player.getName().getString()); + return; + } + // Check if all target regions are already occupied or blocked boolean allBlocked = true; for (BodyRegionV2 region : v2Item.getOccupiedRegions(stack)) { - if ( - !V2EquipmentHelper.isRegionOccupied(player, region) && - !V2EquipmentHelper.isRegionBlocked(player, region) - ) { + if (!V2EquipmentHelper.isRegionOccupied(player, region) + && !V2EquipmentHelper.isRegionBlocked(player, region)) { allBlocked = false; break; } } if (allBlocked) { - TiedUpMod.LOGGER.debug( - "[SelfBondage] {} tried V2 self-equip but all regions occupied", - player.getName().getString() - ); + TiedUpMod.LOGGER.debug("[SelfBondage] {} tried V2 self-equip but all regions occupied", player.getName().getString()); return; } PlayerBindState playerState = PlayerBindState.getInstance(player); if (playerState == null) return; - int tyingSeconds = SettingsAccessor.getTyingPlayerTime( - player.level().getGameRules() - ); + int tyingSeconds = SettingsAccessor.getTyingPlayerTime(player.level().getGameRules()); - // Create V2 tying task (uses V2EquipmentHelper on completion, NOT putBindOn) V2TyingPlayerTask newTask = new V2TyingPlayerTask( - stack.copy(), // copy for display/matching - stack, // live reference for consumption - state, - player, // target is self - tyingSeconds, - player.level(), - player // kidnapper is also self + stack.copy(), stack, state, player, tyingSeconds, player.level(), player ); TyingTask currentTask = playerState.getCurrentTyingTask(); - - if ( - currentTask == null || - !currentTask.isSameTarget(player) || - currentTask.isOutdated() || - !ItemStack.matches(currentTask.getBind(), stack) - ) { - // Start new task + if (currentTask == null + || !currentTask.isSameTarget(player) + || currentTask.isOutdated() + || !ItemStack.matches(currentTask.getBind(), stack)) { playerState.setCurrentTyingTask(newTask); newTask.start(); - - TiedUpMod.LOGGER.debug( - "[SelfBondage] {} started V2 self-tying ({} seconds)", - player.getName().getString(), - tyingSeconds - ); } else { - // Continue existing task — just mark active currentTask.update(); } - // If we started a new task, mark it active too if (playerState.getCurrentTyingTask() == newTask) { newTask.update(); } } + private static void handleV2SelfAccessory( + ServerPlayer player, + ItemStack stack, + IV2BondageItem v2Item, + IBondageState state + ) { + // Can't equip accessories if arms are fully bound + ItemStack currentBind = V2EquipmentHelper.getInRegion(player, BodyRegionV2.ARMS); + if (!currentBind.isEmpty() && BindModeHelper.hasArmsBound(currentBind)) { + TiedUpMod.LOGGER.debug("[SelfBondage] {} can't self-accessory — arms bound", player.getName().getString()); + return; + } + + // Check if region is occupied — try to swap + for (BodyRegionV2 region : v2Item.getOccupiedRegions(stack)) { + if (V2EquipmentHelper.isRegionOccupied(player, region)) { + ItemStack existing = V2EquipmentHelper.getInRegion(player, region); + // Can't swap if locked + if (existing.getItem() instanceof ILockable lockable && lockable.isLocked(existing)) { + TiedUpMod.LOGGER.debug("[SelfBondage] {} can't swap — current is locked", player.getName().getString()); + return; + } + } + } + + // Equip via V2EquipmentHelper (handles conflict resolution, displaced items) + V2EquipResult result = V2EquipmentHelper.equipItem(player, stack.copy()); + if (result.isSuccess()) { + for (ItemStack displaced : result.displaced()) { + player.spawnAtLocation(displaced); + } + stack.shrink(1); + SyncManager.syncInventory(player); + TiedUpMod.LOGGER.info("[SelfBondage] {} self-equipped V2 accessory", player.getName().getString()); + } + } + /** * Handle self-equipping an accessory (gag, blindfold, mittens, earplugs). * Can be used anytime (no need to be tied).