package com.tiedup.remake.state.components; import com.tiedup.remake.v2.bondage.IV2BondageItem; import com.tiedup.remake.state.hosts.IPlayerBindStateHost; import com.tiedup.remake.v2.BodyRegionV2; import com.tiedup.remake.v2.bondage.IV2BondageEquipment; import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; /** * Component responsible for clothes permission and management. * Handles who can remove/change clothes and manages clothes replacement with network sync. * * Single Responsibility: Clothes permissions and synchronization * Complexity: MEDIUM (network sync coordination) * Risk: MEDIUM (must coordinate SyncManager calls) * * Epic 5F: Uses V2EquipmentHelper/BodyRegionV2. */ public class PlayerClothesPermission { private final IPlayerBindStateHost host; public PlayerClothesPermission(IPlayerBindStateHost host) { this.host = host; } // ========== Permission Checks ========== /** * Check if a specific player can take off this player's clothes. * Currently permissive - anyone can take off clothes. * Future: Could check if 'player' is owner/master when tied up. * * @param player The player attempting to remove clothes * @return true if allowed */ public boolean canTakeOffClothes(Player player) { // Currently permissive - anyone can take off clothes // Future: Could check if 'player' is owner/master when tied up return true; } /** * Check if a specific player can change this player's clothes. * Currently permissive - anyone can change clothes. * Future: Could check if 'player' is owner/master when tied up. * * @param player The player attempting to change clothes * @return true if allowed */ public boolean canChangeClothes(Player player) { // Currently permissive - anyone can change clothes // Future: Could check if 'player' is owner/master when tied up return true; } /** * Check if clothes can be changed (no specific player context). * Checks if no clothes are equipped, or if clothes are not locked. * * @return true if clothes can be changed */ public boolean canChangeClothes() { ItemStack clothes = V2EquipmentHelper.getInRegion(host.getPlayer(), BodyRegionV2.TORSO); if (clothes.isEmpty()) return true; // Check if clothes are locked return !isLocked(clothes, false); } // ========== Clothes Management ========== /** * Replace current clothes with new clothes. * Removes old clothes and equips new ones. * Syncs clothes config to all clients. * * @param newClothes The new clothes to equip * @return The old clothes, or empty if none */ public ItemStack replaceClothes(ItemStack newClothes) { return replaceClothes(newClothes, false); } /** * Replace current clothes with new clothes, with optional force. * If force is true, bypasses lock checks. * Syncs clothes config to all clients. * * @param newClothes The new clothes to equip * @param force true to bypass lock checks * @return The old clothes, or empty if none */ public ItemStack replaceClothes(ItemStack newClothes, boolean force) { Player player = host.getPlayer(); if (player == null || player.level().isClientSide) return ItemStack.EMPTY; IV2BondageEquipment equip = V2EquipmentHelper.getEquipment(player); if (equip == null) return ItemStack.EMPTY; // Take off old clothes ItemStack old = V2EquipmentHelper.unequipFromRegion(player, BodyRegionV2.TORSO); // Equip new clothes if we successfully removed old ones if (!old.isEmpty()) { equip.setInRegion(BodyRegionV2.TORSO, newClothes.copy()); // Fire lifecycle hook for new item if (!newClothes.isEmpty() && newClothes.getItem() instanceof IV2BondageItem newItem) { newItem.onEquipped(newClothes, player); } V2EquipmentHelper.sync(player); // CRITICAL: Sync clothes config to all tracking clients // This ensures dynamic textures and other clothes properties are synced host.syncClothesConfig(); } return old; } // ========== Helper Methods ========== /** * Check if an item is locked. * Helper method for lock checking. * * @param stack The item to check * @param force If true, returns false (bypasses lock) * @return true if locked and not forced */ private boolean isLocked(ItemStack stack, boolean force) { if (force) return false; if (stack.isEmpty()) return false; // Check if item has locked property if ( stack.getItem() instanceof com.tiedup.remake.items.base.ILockable lockable ) { return lockable.isLocked(stack); } return false; } }