From b79225d6847316611e7cc2c3e546b8947b89c981 Mon Sep 17 00:00:00 2001 From: NotEvil Date: Tue, 14 Apr 2026 15:29:31 +0200 Subject: [PATCH] feat(D-01/A): OwnershipComponent lifecycle hooks (A7) - onEquipped: register collar owners in CollarRegistry (server-side only) - onUnequipped: alert kidnappers + unregister from CollarRegistry - Guards: client-side check, ServerLevel cast, empty owners skip, try-catch - appendTooltip: nickname, owner count, shock/GPS/choke capabilities - Delegates alert suppression to ItemCollar.isRemovalAlertSuppressed() --- .../bondage/component/OwnershipComponent.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/main/java/com/tiedup/remake/v2/bondage/component/OwnershipComponent.java b/src/main/java/com/tiedup/remake/v2/bondage/component/OwnershipComponent.java index b4846cc..2d6e632 100644 --- a/src/main/java/com/tiedup/remake/v2/bondage/component/OwnershipComponent.java +++ b/src/main/java/com/tiedup/remake/v2/bondage/component/OwnershipComponent.java @@ -1,6 +1,21 @@ package com.tiedup.remake.v2.bondage.component; import com.google.gson.JsonObject; +import com.tiedup.remake.core.TiedUpMod; +import com.tiedup.remake.items.base.ItemCollar; +import com.tiedup.remake.state.CollarRegistry; +import com.tiedup.remake.v2.bondage.CollarHelper; +import java.util.HashSet; +import java.util.List; +import java.util.UUID; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; /** * Component: collar ownership behavior for data-driven items. @@ -17,4 +32,88 @@ public class OwnershipComponent implements IItemComponent { public static IItemComponent fromJson(JsonObject config) { return new OwnershipComponent(); } + + @Override + public void onEquipped(ItemStack stack, LivingEntity entity) { + if (entity.level().isClientSide()) return; + if (!(entity.level() instanceof ServerLevel serverLevel)) return; + + List owners = CollarHelper.getOwners(stack); + if (owners.isEmpty()) { + TiedUpMod.LOGGER.debug( + "[OwnershipComponent] Collar equipped on {} with no owners in NBT — skipping registry", + entity.getName().getString() + ); + return; + } + + try { + CollarRegistry registry = CollarRegistry.get(serverLevel); + registry.registerCollar(entity.getUUID(), new HashSet<>(owners)); + TiedUpMod.LOGGER.debug( + "[OwnershipComponent] Registered collar for {} with {} owner(s)", + entity.getName().getString(), owners.size() + ); + } catch (Exception e) { + TiedUpMod.LOGGER.warn( + "[OwnershipComponent] Failed to register collar for {}: {}", + entity.getName().getString(), e.getMessage() + ); + } + } + + @Override + public void onUnequipped(ItemStack stack, LivingEntity entity) { + if (entity.level().isClientSide()) return; + if (!(entity.level() instanceof ServerLevel serverLevel)) return; + + // Alert kidnappers if removal wasn't suppressed + if (!CollarHelper.isRemovalAlertSuppressed()) { + ItemCollar.onCollarRemoved(entity, true); + } + + try { + CollarRegistry registry = CollarRegistry.get(serverLevel); + registry.unregisterWearer(entity.getUUID()); + TiedUpMod.LOGGER.debug( + "[OwnershipComponent] Unregistered collar for {}", + entity.getName().getString() + ); + } catch (Exception e) { + TiedUpMod.LOGGER.warn( + "[OwnershipComponent] Failed to unregister collar for {}: {}", + entity.getName().getString(), e.getMessage() + ); + } + } + + @Override + public void appendTooltip(ItemStack stack, @Nullable Level level, List tooltip, TooltipFlag flag) { + String nickname = CollarHelper.getNickname(stack); + if (nickname != null && !nickname.isEmpty()) { + tooltip.add(Component.translatable("item.tiedup.tooltip.nickname", nickname) + .withStyle(ChatFormatting.LIGHT_PURPLE)); + } + + List owners = CollarHelper.getOwners(stack); + if (!owners.isEmpty()) { + tooltip.add(Component.translatable("item.tiedup.tooltip.owners", owners.size()) + .withStyle(ChatFormatting.GOLD)); + } + + if (CollarHelper.canShock(stack)) { + tooltip.add(Component.translatable("item.tiedup.tooltip.shock_capable") + .withStyle(ChatFormatting.DARK_RED)); + } + + if (CollarHelper.hasGPS(stack)) { + tooltip.add(Component.translatable("item.tiedup.tooltip.gps_capable") + .withStyle(ChatFormatting.AQUA)); + } + + if (CollarHelper.isChokeCollar(stack)) { + tooltip.add(Component.translatable("item.tiedup.tooltip.choke_capable") + .withStyle(ChatFormatting.DARK_PURPLE)); + } + } }