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.
190 lines
6.2 KiB
Java
190 lines
6.2 KiB
Java
package com.tiedup.remake.client.events;
|
|
|
|
import com.tiedup.remake.network.ModNetwork;
|
|
import com.tiedup.remake.network.selfbondage.PacketSelfBondage;
|
|
import com.tiedup.remake.v2.bondage.BindModeHelper;
|
|
import com.tiedup.remake.v2.bondage.CollarHelper;
|
|
import com.tiedup.remake.v2.bondage.IV2BondageItem;
|
|
import com.tiedup.remake.v2.bondage.component.BlindingComponent;
|
|
import com.tiedup.remake.v2.bondage.component.ComponentType;
|
|
import com.tiedup.remake.v2.bondage.component.GaggingComponent;
|
|
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem;
|
|
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenItemDefinition;
|
|
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenItemRegistry;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.player.LocalPlayer;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraftforge.api.distmarker.Dist;
|
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
import net.minecraftforge.event.TickEvent;
|
|
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
import net.minecraftforge.fml.common.Mod;
|
|
|
|
/**
|
|
* Client-side event handler for self-bondage input.
|
|
*
|
|
* Intercepts left-click when holding bondage items and
|
|
* sends packets continuously to the server to perform self-bondage.
|
|
*
|
|
* Self-bondage items:
|
|
* - Binds (rope, chain, etc.) - Self-tie (requires holding left-click)
|
|
* - Gags - Self-gag (if already tied, instant)
|
|
* - Blindfolds - Self-blindfold (if already tied, instant)
|
|
* - Mittens - Self-mitten (if already tied, instant)
|
|
* - Earplugs - Self-earplug (if already tied, instant)
|
|
* - Collar - NOT ALLOWED (cannot self-collar)
|
|
*/
|
|
@Mod.EventBusSubscriber(
|
|
modid = "tiedup",
|
|
value = Dist.CLIENT,
|
|
bus = Mod.EventBusSubscriber.Bus.FORGE
|
|
)
|
|
@OnlyIn(Dist.CLIENT)
|
|
public class SelfBondageInputHandler {
|
|
|
|
/** Track if we're currently in self-bondage mode */
|
|
private static boolean isSelfBondageActive = false;
|
|
|
|
/** The hand we're using for self-bondage */
|
|
private static InteractionHand activeHand = null;
|
|
|
|
/** Tick counter for packet sending interval */
|
|
private static int tickCounter = 0;
|
|
|
|
/** Send packet every 4 ticks (5 times per second) for smooth progress */
|
|
private static final int PACKET_INTERVAL = 4;
|
|
|
|
/**
|
|
* Handle left-click in empty air - START self-bondage.
|
|
*/
|
|
@SubscribeEvent
|
|
public static void onLeftClickEmpty(
|
|
PlayerInteractEvent.LeftClickEmpty event
|
|
) {
|
|
startSelfBondage();
|
|
}
|
|
|
|
/**
|
|
* Handle left-click on block - START self-bondage (cancel block breaking).
|
|
*/
|
|
@SubscribeEvent
|
|
public static void onLeftClickBlock(
|
|
PlayerInteractEvent.LeftClickBlock event
|
|
) {
|
|
if (!event.getLevel().isClientSide()) return;
|
|
|
|
ItemStack stack = event.getItemStack();
|
|
if (isSelfBondageItem(stack)) {
|
|
event.setCanceled(true);
|
|
startSelfBondage();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start self-bondage mode if holding a bondage item.
|
|
*/
|
|
private static void startSelfBondage() {
|
|
LocalPlayer player = Minecraft.getInstance().player;
|
|
if (player == null) return;
|
|
|
|
// Check main hand first, then off hand
|
|
InteractionHand hand = InteractionHand.MAIN_HAND;
|
|
ItemStack stack = player.getMainHandItem();
|
|
|
|
if (!isSelfBondageItem(stack)) {
|
|
stack = player.getOffhandItem();
|
|
hand = InteractionHand.OFF_HAND;
|
|
|
|
if (!isSelfBondageItem(stack)) {
|
|
return; // No bondage item in either hand
|
|
}
|
|
}
|
|
|
|
// Start self-bondage mode
|
|
isSelfBondageActive = true;
|
|
activeHand = hand;
|
|
tickCounter = 0;
|
|
|
|
// Send initial packet immediately
|
|
ModNetwork.sendToServer(new PacketSelfBondage(hand));
|
|
}
|
|
|
|
/**
|
|
* Client tick - continuously send packets while attack button is held.
|
|
*/
|
|
@SubscribeEvent
|
|
public static void onClientTick(TickEvent.ClientTickEvent event) {
|
|
if (event.phase != TickEvent.Phase.END) return;
|
|
if (!isSelfBondageActive) return;
|
|
|
|
Minecraft mc = Minecraft.getInstance();
|
|
LocalPlayer player = mc.player;
|
|
|
|
// Stop if conditions are no longer valid
|
|
if (player == null || mc.screen != null) {
|
|
stopSelfBondage();
|
|
return;
|
|
}
|
|
|
|
// Check if attack button is still held
|
|
if (!mc.options.keyAttack.isDown()) {
|
|
stopSelfBondage();
|
|
return;
|
|
}
|
|
|
|
// Check if still holding bondage item in the active hand
|
|
ItemStack stack = player.getItemInHand(activeHand);
|
|
if (!isSelfBondageItem(stack)) {
|
|
stopSelfBondage();
|
|
return;
|
|
}
|
|
|
|
// Send packet at interval for continuous progress
|
|
tickCounter++;
|
|
if (tickCounter >= PACKET_INTERVAL) {
|
|
tickCounter = 0;
|
|
ModNetwork.sendToServer(new PacketSelfBondage(activeHand));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stop self-bondage mode.
|
|
*/
|
|
private static void stopSelfBondage() {
|
|
isSelfBondageActive = false;
|
|
activeHand = null;
|
|
tickCounter = 0;
|
|
}
|
|
|
|
/**
|
|
* Check if a stack supports self-bondage.
|
|
* Collar is explicitly excluded.
|
|
*/
|
|
private static boolean isSelfBondageItem(ItemStack stack) {
|
|
if (stack.isEmpty()) return false;
|
|
|
|
// Collar cannot be self-equipped (V2 ownership component)
|
|
if (CollarHelper.isCollar(stack)) {
|
|
return false;
|
|
}
|
|
|
|
// V2 bondage items support self-bondage (left-click hold with tying duration)
|
|
if (stack.getItem() instanceof IV2BondageItem) {
|
|
return true;
|
|
}
|
|
|
|
// V2 data-driven items: check if it occupies any bondage region
|
|
DataDrivenItemDefinition def = DataDrivenItemRegistry.get(stack);
|
|
if (def != null) {
|
|
return true;
|
|
}
|
|
|
|
// V1 fallback: bind items
|
|
return BindModeHelper.isBindItem(stack)
|
|
|| DataDrivenBondageItem.getComponent(stack, ComponentType.GAGGING, GaggingComponent.class) != null
|
|
|| DataDrivenBondageItem.getComponent(stack, ComponentType.BLINDING, BlindingComponent.class) != null;
|
|
}
|
|
}
|