Files
TiedUp-/src/main/java/com/tiedup/remake/items/ItemShockerController.java
NotEvil 2504b7d657 feat(D-01/D): V1 cleanup — delete 28 files, ~5400 lines removed
D1: ThreadLocal alert suppression moved from ItemCollar to CollarHelper.
    onCollarRemoved() logic (kidnapper alert) moved to CollarHelper.

D2+D3: Deleted 17 V1 item classes + 4 V1-only interfaces:
  ItemBind, ItemGag, ItemBlindfold, ItemCollar, ItemEarplugs, ItemMittens,
  ItemColor, ItemClassicCollar, ItemShockCollar, ItemShockCollarAuto,
  ItemGpsCollar, ItemChokeCollar, ItemHood, ItemMedicalGag,
  IBondageItem, IHasGaggingEffect, IHasBlindingEffect, IAdjustable

D4: KidnapperTheme/KidnapperItemSelector/DispenserBehaviors migrated
    from variant enums to string-based DataDrivenItemRegistry IDs.

D5: Deleted 11 variant enums + Generic* factories + ItemBallGag3D:
  BindVariant, GagVariant, BlindfoldVariant, EarplugsVariant, MittensVariant,
  GenericBind, GenericGag, GenericBlindfold, GenericEarplugs, GenericMittens

D6: ModItems cleaned — all V1 bondage registrations removed.
D7: ModCreativeTabs rewritten — iterates DataDrivenItemRegistry.
D8+D9: All V2 helpers cleaned (V1 fallbacks removed), orphan imports removed.

Zero V1 bondage code references remain (only Javadoc comments).
All bondage items are now data-driven via 47 JSON definitions.
2026-04-15 01:55:16 +02:00

398 lines
14 KiB
Java

package com.tiedup.remake.items;
import com.tiedup.remake.core.ModSounds;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.ItemOwnerTarget;
import com.tiedup.remake.v2.bondage.CollarHelper;
import com.tiedup.remake.state.IRestrainable;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import net.minecraft.ChatFormatting;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
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 ItemShockerController extends ItemOwnerTarget {
private static final String NBT_BROADCAST = "broadcast";
private static final String NBT_RADIUS = "radius";
public ItemShockerController() {
super(new net.minecraft.world.item.Item.Properties().stacksTo(1));
}
@Override
public void appendHoverText(
ItemStack stack,
@Nullable Level level,
List<Component> tooltip,
TooltipFlag flag
) {
super.appendHoverText(stack, level, tooltip, flag);
appendOwnerTooltip(stack, tooltip, "Right-click a player");
if (isBroadcastEnabled(stack)) {
tooltip.add(
Component.literal("MODE: BROADCAST").withStyle(
ChatFormatting.DARK_RED
)
);
tooltip.add(
Component.literal("(Affects ALL your slaves in radius)")
.withStyle(ChatFormatting.GRAY)
.withStyle(ChatFormatting.ITALIC)
);
} else {
tooltip.add(
Component.literal("MODE: TARGETED").withStyle(
ChatFormatting.BLUE
)
);
if (hasTarget(stack)) {
String displayName = getTargetName(stack);
boolean isDisconnected = true;
if (level != null) {
Player target = level.getPlayerByUUID(getTargetId(stack));
if (target != null) {
IRestrainable targetState =
KidnappedHelper.getKidnappedState(target);
if (targetState != null && targetState.hasCollar()) {
isDisconnected = false;
ItemStack collar = targetState.getEquipment(
BodyRegionV2.NECK
);
if (
CollarHelper.isCollar(collar) &&
CollarHelper.hasNickname(collar)
) {
displayName =
CollarHelper.getNickname(collar) +
" (" +
displayName +
")";
}
}
}
}
MutableComponent targetComp = Component.literal(" > ")
.withStyle(ChatFormatting.BLUE)
.append(
Component.literal(displayName).withStyle(
isDisconnected
? ChatFormatting.STRIKETHROUGH
: ChatFormatting.WHITE
)
);
if (isDisconnected) {
targetComp.append(
Component.literal(" [FREED]")
.withStyle(ChatFormatting.RED)
.withStyle(ChatFormatting.BOLD)
);
}
tooltip.add(targetComp);
} else {
tooltip.add(
Component.literal(" > No target connected").withStyle(
ChatFormatting.GRAY
)
);
}
}
tooltip.add(
Component.literal("Radius: " + getRadius(stack) + "m").withStyle(
ChatFormatting.GREEN
)
);
tooltip.add(
Component.literal("Shift + Right-click to toggle Broadcast mode")
.withStyle(ChatFormatting.DARK_GRAY)
.withStyle(ChatFormatting.ITALIC)
);
}
@Override
public InteractionResultHolder<ItemStack> use(
Level level,
Player player,
InteractionHand hand
) {
ItemStack stack = player.getItemInHand(hand);
if (player.isShiftKeyDown()) {
if (!level.isClientSide) {
if (hasOwner(stack) && !isOwner(stack, player)) {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.SHOCKER_NOT_OWNER
);
return InteractionResultHolder.fail(stack);
}
boolean newState = !isBroadcastEnabled(stack);
setBroadcastEnabled(stack, newState);
player.setItemInHand(hand, stack);
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.SHOCKER_MODE_SET,
(newState ? "BROADCAST" : "TARGETED")
);
}
return InteractionResultHolder.sidedSuccess(
stack,
level.isClientSide()
);
}
if (level.isClientSide) return InteractionResultHolder.success(stack);
IRestrainable playerState = KidnappedHelper.getKidnappedState(player);
if (
playerState != null && playerState.isTiedUp()
) return InteractionResultHolder.fail(stack);
if (!hasOwner(stack)) {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.ERROR,
"You must claim this shocker first! (Right-click a player)"
);
return InteractionResultHolder.fail(stack);
}
if (!isOwner(stack, player)) {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.SHOCKER_NOT_OWNER
);
return InteractionResultHolder.fail(stack);
}
List<LivingEntity> nearbyTargets = getNearbyKidnappedTargets(
level,
player,
stack
);
if (isBroadcastEnabled(stack)) {
for (LivingEntity target : nearbyTargets) {
IRestrainable targetState = KidnappedHelper.getKidnappedState(
target
);
if (targetState != null) targetState.shockKidnapped();
}
if (nearbyTargets.isEmpty()) {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.ERROR,
"No valid targets in range!"
);
} else {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.INFO,
"Broadcast shock triggered! (" +
nearbyTargets.size() +
" targets)"
);
playTriggerSound(player);
}
} else if (hasTarget(stack)) {
Player target = level.getPlayerByUUID(getTargetId(stack));
IRestrainable targetState =
target != null
? KidnappedHelper.getKidnappedState(target)
: null;
if (
target != null &&
targetState != null &&
targetState.hasCollar() &&
nearbyTargets.contains(target)
) {
targetState.shockKidnapped();
String name = target.getName().getString();
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.SHOCKER_TRIGGERED,
name
);
playTriggerSound(player);
} else {
String error = (target == null)
? "Target is out of range or in another dimension!"
: (!targetState.hasCollar()
? "Target is no longer wearing a collar!"
: "Target is out of range!");
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.ERROR,
error
);
}
} else {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.ERROR,
"No target set and broadcast is disabled!"
);
}
return InteractionResultHolder.success(stack);
}
/**
*/
@Override
public InteractionResult interactLivingEntity(
ItemStack stack,
Player player,
LivingEntity target,
InteractionHand hand
) {
if (player.level().isClientSide) return InteractionResult.SUCCESS;
IRestrainable playerState = KidnappedHelper.getKidnappedState(player);
if (
playerState != null && playerState.isTiedUp()
) return InteractionResult.FAIL;
// Claim shocker if unclaimed
if (!hasOwner(stack)) {
setOwner(stack, player);
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.SHOCKER_CLAIMED
);
} else if (!isOwner(stack, player)) {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.SHOCKER_NOT_OWNER
);
return InteractionResult.FAIL;
}
// Connect to target (works with any LivingEntity that can be kidnapped)
IRestrainable targetState = KidnappedHelper.getKidnappedState(target);
if (targetState != null) {
setTarget(stack, target);
player.setItemInHand(hand, stack);
SystemMessageManager.sendChatToPlayer(
player,
"Connected to " + target.getName().getString(),
ChatFormatting.GREEN
);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
/**
* Returns all kidnappable entities in range wearing shock collars owned by the shocker owner or in public mode.
*/
private List<LivingEntity> getNearbyKidnappedTargets(
Level level,
Player source,
ItemStack stack
) {
double radius = getRadius(stack);
UUID ownerId = getOwnerId(stack);
List<LivingEntity> targets = new ArrayList<>();
// Check all living entities in range
for (LivingEntity entity : level.getEntitiesOfClass(
LivingEntity.class,
source.getBoundingBox().inflate(radius)
)) {
if (entity == source) continue;
IRestrainable state = KidnappedHelper.getKidnappedState(entity);
if (state != null && state.hasCollar()) {
ItemStack collarStack = state.getEquipment(BodyRegionV2.NECK);
if (CollarHelper.canShock(collarStack)) {
if (
CollarHelper.isOwner(collarStack, ownerId) ||
CollarHelper.isPublicShock(collarStack)
) {
targets.add(entity);
}
}
}
}
return targets;
}
private void playTriggerSound(Player player) {
player
.level()
.playSound(
null,
player.blockPosition(),
ModSounds.SHOCKER_ACTIVATED.get(),
net.minecraft.sounds.SoundSource.PLAYERS,
0.5f,
1.0f
);
}
public boolean isBroadcastEnabled(ItemStack stack) {
CompoundTag tag = stack.getTag();
return tag != null && tag.getBoolean(NBT_BROADCAST);
}
public void setBroadcastEnabled(ItemStack stack, boolean enabled) {
stack.getOrCreateTag().putBoolean(NBT_BROADCAST, enabled);
}
public int getRadius(ItemStack stack) {
CompoundTag tag = stack.getTag();
return (tag != null && tag.contains(NBT_RADIUS))
? tag.getInt(NBT_RADIUS)
: com.tiedup.remake.core.SettingsAccessor.getShockerControllerRadius(
null
);
}
public void setRadius(ItemStack stack, int radius) {
stack.getOrCreateTag().putInt(NBT_RADIUS, radius);
}
public static ItemStack mergeShockers(List<ItemStack> stacks) {
if (stacks == null || stacks.size() <= 1) return ItemStack.EMPTY;
int totalRadius = 0;
for (ItemStack s : stacks) {
if (s.getItem() instanceof ItemShockerController sc) {
totalRadius += sc.getRadius(s);
}
}
ItemStack result = new ItemStack(stacks.get(0).getItem());
((ItemShockerController) result.getItem()).setRadius(
result,
totalRadius
);
return result;
}
}