package com.tiedup.remake.items; import com.tiedup.remake.core.SystemMessageManager; import com.tiedup.remake.items.base.ItemOwnerTarget; import com.tiedup.remake.v2.bondage.CollarHelper; import com.tiedup.remake.state.IBondageState; import com.tiedup.remake.util.KidnappedHelper; import com.tiedup.remake.v2.BodyRegionV2; import java.util.List; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; public class ItemGpsLocator extends ItemOwnerTarget { public ItemGpsLocator() { super(new net.minecraft.world.item.Item.Properties().stacksTo(1)); } @Override public void appendHoverText( ItemStack stack, @Nullable Level level, List tooltip, TooltipFlag flag ) { super.appendHoverText(stack, level, tooltip, flag); appendOwnerTooltip(stack, tooltip, "Right-click a player"); if (hasTarget(stack)) { String displayName = resolveTargetDisplayName(stack, level); tooltip.add( Component.translatable("item.tiedup.gps_locator.target", displayName) .withStyle(ChatFormatting.BLUE) ); } } @Override public InteractionResultHolder use( Level level, Player player, InteractionHand hand ) { ItemStack stack = player.getItemInHand(hand); if (level.isClientSide) return InteractionResultHolder.success(stack); if (!hasOwner(stack)) { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.ERROR, "You must claim this locator first! (Right-click a player)" ); return InteractionResultHolder.fail(stack); } if (!isOwner(stack, player)) { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.LOCATOR_NOT_OWNER ); return InteractionResultHolder.fail(stack); } if (hasTarget(stack)) { // Use server player list for cross-dimension tracking Player target = level .getServer() .getPlayerList() .getPlayer(getTargetId(stack)); if (target != null) { IBondageState targetState = KidnappedHelper.getKidnappedState( target ); if (targetState != null && targetState.hasCollar()) { ItemStack collarStack = targetState.getEquipment( BodyRegionV2.NECK ); if (CollarHelper.hasGPS(collarStack)) { if ( CollarHelper.isOwner(collarStack, player) || CollarHelper.hasPublicTracking(collarStack) ) { // Check if same dimension boolean sameDimension = player .level() .dimension() .equals(target.level().dimension()); if (sameDimension) { double distance = player.distanceTo(target); String direction = getDirection(player, target); SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.LOCATOR_DETECTED, (int) distance + "m [" + direction + "]" ); } else { // Cross-dimension: show dimension name String dimName = getDimensionDisplayName( target .level() .dimension() .location() .getPath() ); SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.LOCATOR_DETECTED, "Target is in [" + dimName + "]" ); } playLocatorSound(player); } else { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.ERROR, "You are not allowed to access this GPS Collar!" ); } } else { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.ERROR, "Target is not wearing a GPS Collar!" ); } } } else { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.ERROR, "Unable to locate target! (Offline)" ); } } else { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.ERROR, "No target connected!" ); } return InteractionResultHolder.success(stack); } /** */ @Override public InteractionResult interactLivingEntity( ItemStack stack, Player player, LivingEntity target, InteractionHand hand ) { if (player.level().isClientSide) return InteractionResult.SUCCESS; IBondageState playerState = KidnappedHelper.getKidnappedState(player); if ( playerState != null && playerState.isTiedUp() ) return InteractionResult.FAIL; if (!hasOwner(stack)) { setOwner(stack, player); SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.LOCATOR_CLAIMED ); } else if (!isOwner(stack, player)) { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.LOCATOR_NOT_OWNER ); return InteractionResult.FAIL; } IBondageState targetState = KidnappedHelper.getKidnappedState(target); if (targetState != null) { setTarget(stack, target); player.setItemInHand(hand, stack); // Force sync SystemMessageManager.sendChatToPlayer( player, "Connected to " + target.getName().getString(), ChatFormatting.GREEN ); return InteractionResult.SUCCESS; } return InteractionResult.PASS; } private String getDirection(Player source, Player target) { double dx = target.getX() - source.getX(); double dz = target.getZ() - source.getZ(); if (Math.abs(dx) > Math.abs(dz)) { return dx > 0 ? "EAST" : "WEST"; } else { return dz > 0 ? "SOUTH" : "NORTH"; } } private void playLocatorSound(Player player) { player .level() .playSound( null, player.blockPosition(), com.tiedup.remake.core.ModSounds.SHOCKER_ACTIVATED.get(), net.minecraft.sounds.SoundSource.PLAYERS, 0.5f, 1.0f ); } /** * Get a user-friendly display name for a dimension. */ private String getDimensionDisplayName(String dimensionPath) { return switch (dimensionPath) { case "overworld" -> "Overworld"; case "the_nether" -> "The Nether"; case "the_end" -> "The End"; default -> dimensionPath.replace("_", " "); }; } }