package com.tiedup.remake.v2.bondage; import com.tiedup.remake.v2.BodyRegionV2; import java.util.Set; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; /** * Core interface for V2 bondage items. * * Implemented by Item classes that can be equipped into V2 body regions. * Provides region occupation, 3D model info, pose/animation data, * and lifecycle hooks. */ public interface IV2BondageItem { // ===== REGIONS ===== /** * Which body regions this item occupies. * Example: Armbinder returns {ARMS, HANDS, TORSO}. */ Set getOccupiedRegions(); /** * Stack-aware variant. Data-driven items override this to read regions from NBT/registry. * Default delegates to the no-arg version (backward compatible for hardcoded items). */ default Set getOccupiedRegions(ItemStack stack) { return getOccupiedRegions(); } /** * Which regions this item blocks from having other items. * Usually same as occupied, but could differ. * Example: Hood occupies HEAD but blocks {HEAD, EYES, EARS, MOUTH}. * Defaults to same as {@link #getOccupiedRegions()}. */ default Set getBlockedRegions() { return getOccupiedRegions(); } /** * Stack-aware variant. Data-driven items override this to read blocked regions from NBT/registry. */ default Set getBlockedRegions(ItemStack stack) { return getBlockedRegions(); } // ===== 3D MODELS ===== /** * Get the glTF model location (.glb file). * Returns null for items without a 3D model (e.g., clothes-only items). */ @Nullable ResourceLocation getModelLocation(); /** * Stack-aware variant. Data-driven items override this to read model from NBT/registry. */ @Nullable default ResourceLocation getModelLocation(ItemStack stack) { return getModelLocation(); } // ===== POSES & ANIMATIONS ===== /** * Priority for pose conflicts. Higher value wins. * Example: Fullbind (100) > Armbinder (50) > Handcuffs (30) > Collar (10) > None (0). */ int getPosePriority(); /** * Stack-aware variant for pose priority. */ default int getPosePriority(ItemStack stack) { return getPosePriority(); } // ===== ITEM STATE ===== /** * Difficulty to escape (for struggle minigame). Higher = harder. */ int getEscapeDifficulty(); /** * Stack-aware variant for escape difficulty. */ default int getEscapeDifficulty(ItemStack stack) { return getEscapeDifficulty(); } // ===== RENDERING ===== /** * Whether this item supports color variants (texture_red.png, etc.). */ boolean supportsColor(); /** * Stack-aware variant for color support. */ default boolean supportsColor(ItemStack stack) { return supportsColor(); } /** * Whether this item supports a slim model variant (Alex-style 3px arms). */ boolean supportsSlimModel(); /** * Stack-aware variant for slim model support. */ default boolean supportsSlimModel(ItemStack stack) { return supportsSlimModel(); } /** * Get the slim model location (.glb) for Alex-style players. * Only meaningful if {@link #supportsSlimModel()} returns true. */ @Nullable default ResourceLocation getSlimModelLocation() { return null; } /** * Stack-aware variant for slim model location. */ @Nullable default ResourceLocation getSlimModelLocation(ItemStack stack) { return getSlimModelLocation(); } // ===== LIFECYCLE HOOKS ===== /** * Called when this item is equipped onto an entity. */ default void onEquipped(ItemStack stack, LivingEntity entity) {} /** * Called when this item is unequipped from an entity. */ default void onUnequipped(ItemStack stack, LivingEntity entity) {} /** * Whether this item can be equipped on the given entity right now. */ default boolean canEquip(ItemStack stack, LivingEntity entity) { return true; } /** * Whether this item can be unequipped from the given entity right now. */ default boolean canUnequip(ItemStack stack, LivingEntity entity) { return true; } }