Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
This commit is contained in:
446
src/main/java/com/tiedup/remake/client/ModKeybindings.java
Normal file
446
src/main/java/com/tiedup/remake/client/ModKeybindings.java
Normal file
@@ -0,0 +1,446 @@
|
||||
package com.tiedup.remake.client;
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
|
||||
import com.tiedup.remake.client.gui.screens.AdjustmentScreen;
|
||||
import com.tiedup.remake.client.gui.screens.UnifiedBondageScreen;
|
||||
import com.tiedup.remake.items.base.ItemCollar;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.tiedup.remake.core.ModConfig;
|
||||
import com.tiedup.remake.core.TiedUpMod;
|
||||
import com.tiedup.remake.items.base.ILockable;
|
||||
import com.tiedup.remake.network.ModNetwork;
|
||||
import com.tiedup.remake.network.action.PacketForceSeatModifier;
|
||||
import com.tiedup.remake.network.action.PacketStruggle;
|
||||
import com.tiedup.remake.network.action.PacketTighten;
|
||||
import com.tiedup.remake.network.bounty.PacketRequestBounties;
|
||||
import com.tiedup.remake.v2.BodyRegionV2;
|
||||
import com.tiedup.remake.v2.bondage.network.PacketV2StruggleStart;
|
||||
import com.tiedup.remake.state.PlayerBindState;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
/**
|
||||
* Phase 7: Client-side keybindings for TiedUp mod.
|
||||
*
|
||||
* Manages key mappings and sends packets to server when keys are pressed.
|
||||
*
|
||||
* Based on original KeyBindings from 1.12.2
|
||||
*/
|
||||
@Mod.EventBusSubscriber(
|
||||
modid = TiedUpMod.MOD_ID,
|
||||
bus = Mod.EventBusSubscriber.Bus.FORGE,
|
||||
value = Dist.CLIENT
|
||||
)
|
||||
public class ModKeybindings {
|
||||
|
||||
/**
|
||||
* Key category for TiedUp keybindings
|
||||
*/
|
||||
private static final String CATEGORY = "key.categories.tiedup";
|
||||
|
||||
/**
|
||||
* Struggle keybinding - Press to struggle against binds
|
||||
* Default: R key
|
||||
*/
|
||||
public static final KeyMapping STRUGGLE_KEY = new KeyMapping(
|
||||
"key.tiedup.struggle", // Translation key
|
||||
InputConstants.Type.KEYSYM,
|
||||
InputConstants.KEY_R, // Default key: R
|
||||
CATEGORY
|
||||
);
|
||||
|
||||
/**
|
||||
* Adjustment screen keybinding - Open item adjustment screen
|
||||
* Default: K key
|
||||
*/
|
||||
public static final KeyMapping ADJUSTMENT_KEY = new KeyMapping(
|
||||
"key.tiedup.adjustment_screen",
|
||||
InputConstants.Type.KEYSYM,
|
||||
InputConstants.KEY_K, // Default key: K
|
||||
CATEGORY
|
||||
);
|
||||
|
||||
/**
|
||||
* Bondage inventory keybinding - Open bondage inventory screen
|
||||
* Default: J key
|
||||
*/
|
||||
public static final KeyMapping INVENTORY_KEY = new KeyMapping(
|
||||
"key.tiedup.bondage_inventory",
|
||||
InputConstants.Type.KEYSYM,
|
||||
InputConstants.KEY_J, // Default key: J
|
||||
CATEGORY
|
||||
);
|
||||
|
||||
/**
|
||||
* Slave management keybinding - Open slave management dashboard
|
||||
* Default: L key
|
||||
*/
|
||||
public static final KeyMapping SLAVE_MANAGEMENT_KEY = new KeyMapping(
|
||||
"key.tiedup.slave_management",
|
||||
InputConstants.Type.KEYSYM,
|
||||
InputConstants.KEY_L, // Default key: L
|
||||
CATEGORY
|
||||
);
|
||||
|
||||
/**
|
||||
* Bounty list keybinding - Open bounty list screen
|
||||
* Default: B key
|
||||
*/
|
||||
public static final KeyMapping BOUNTY_KEY = new KeyMapping(
|
||||
"key.tiedup.bounties",
|
||||
InputConstants.Type.KEYSYM,
|
||||
InputConstants.KEY_B, // Default key: B
|
||||
CATEGORY
|
||||
);
|
||||
|
||||
/**
|
||||
* Force seat keybinding - Hold to force captive on/off vehicles
|
||||
* Default: Left ALT key
|
||||
*/
|
||||
public static final KeyMapping FORCE_SEAT_KEY = new KeyMapping(
|
||||
"key.tiedup.force_seat",
|
||||
InputConstants.Type.KEYSYM,
|
||||
InputConstants.KEY_LALT, // Default key: Left ALT
|
||||
CATEGORY
|
||||
);
|
||||
|
||||
/**
|
||||
* Tighten bind keybinding - Tighten binds on looked-at target
|
||||
* Default: T key
|
||||
*/
|
||||
public static final KeyMapping TIGHTEN_KEY = new KeyMapping(
|
||||
"key.tiedup.tighten",
|
||||
InputConstants.Type.KEYSYM,
|
||||
InputConstants.KEY_T, // Default key: T
|
||||
CATEGORY
|
||||
);
|
||||
|
||||
/** Track last sent state to avoid spamming packets */
|
||||
private static boolean lastForceSeatState = false;
|
||||
|
||||
/**
|
||||
* Check if Force Seat key is currently pressed.
|
||||
*/
|
||||
public static boolean isForceSeatPressed() {
|
||||
return FORCE_SEAT_KEY.isDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register keybindings.
|
||||
* Called during mod initialization (MOD bus).
|
||||
*
|
||||
* @param event The registration event
|
||||
*/
|
||||
public static void register(RegisterKeyMappingsEvent event) {
|
||||
event.register(STRUGGLE_KEY);
|
||||
event.register(ADJUSTMENT_KEY);
|
||||
event.register(INVENTORY_KEY);
|
||||
event.register(SLAVE_MANAGEMENT_KEY);
|
||||
event.register(BOUNTY_KEY);
|
||||
event.register(FORCE_SEAT_KEY);
|
||||
event.register(TIGHTEN_KEY);
|
||||
TiedUpMod.LOGGER.info("Registered {} keybindings", 7);
|
||||
}
|
||||
|
||||
// ==================== STRUGGLE MINI-GAME (uses vanilla movement keys) ====================
|
||||
|
||||
/**
|
||||
* Get the vanilla movement keybind for a given direction index.
|
||||
* Uses Minecraft's movement keys so AZERTY/QWERTY is already configured.
|
||||
* @param index 0=FORWARD, 1=LEFT, 2=BACK, 3=RIGHT
|
||||
* @return The keybind or null if invalid index
|
||||
*/
|
||||
public static KeyMapping getStruggleDirectionKey(int index) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.options == null) return null;
|
||||
return switch (index) {
|
||||
case 0 -> mc.options.keyUp; // Forward (W/Z)
|
||||
case 1 -> mc.options.keyLeft; // Strafe Left (A/Q)
|
||||
case 2 -> mc.options.keyDown; // Back (S)
|
||||
case 3 -> mc.options.keyRight; // Strafe Right (D)
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a keycode matches any vanilla movement keybind.
|
||||
* @param keyCode The GLFW key code
|
||||
* @return The direction index (0-3) or -1 if not a movement key
|
||||
*/
|
||||
public static int getStruggleDirectionFromKeyCode(int keyCode) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.options == null) return -1;
|
||||
if (mc.options.keyUp.matches(keyCode, 0)) return 0;
|
||||
if (mc.options.keyLeft.matches(keyCode, 0)) return 1;
|
||||
if (mc.options.keyDown.matches(keyCode, 0)) return 2;
|
||||
if (mc.options.keyRight.matches(keyCode, 0)) return 3;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display name of a vanilla movement key.
|
||||
* Shows the actual bound key (W for QWERTY, Z for AZERTY, etc.)
|
||||
* @param index 0=FORWARD, 1=LEFT, 2=BACK, 3=RIGHT
|
||||
* @return The key's display name
|
||||
*/
|
||||
public static String getStruggleDirectionKeyName(int index) {
|
||||
KeyMapping key = getStruggleDirectionKey(index);
|
||||
if (key == null) return "?";
|
||||
return key.getTranslatedKeyMessage().getString().toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle key presses on client tick.
|
||||
* Called every client tick (FORGE bus).
|
||||
*
|
||||
* @param event The tick event
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onClientTick(TickEvent.ClientTickEvent event) {
|
||||
// Only run at end of tick
|
||||
if (event.phase != TickEvent.Phase.END) {
|
||||
return;
|
||||
}
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.player == null || mc.level == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync Force Seat keybind state to server (only send on change)
|
||||
boolean currentForceSeatState = isForceSeatPressed();
|
||||
if (currentForceSeatState != lastForceSeatState) {
|
||||
lastForceSeatState = currentForceSeatState;
|
||||
ModNetwork.sendToServer(
|
||||
new PacketForceSeatModifier(currentForceSeatState)
|
||||
);
|
||||
}
|
||||
|
||||
// Check struggle key - Phase 21: Flow based on bind/accessories
|
||||
while (STRUGGLE_KEY.consumeClick()) {
|
||||
handleStruggleKey();
|
||||
}
|
||||
|
||||
// Check adjustment screen key
|
||||
while (ADJUSTMENT_KEY.consumeClick()) {
|
||||
// Only open if not already in a screen and player has adjustable items
|
||||
if (mc.screen == null && AdjustmentScreen.canOpen()) {
|
||||
mc.setScreen(new AdjustmentScreen());
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[CLIENT] Adjustment key pressed - opening screen"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check bondage inventory key - opens UnifiedBondageScreen in SELF or MASTER mode
|
||||
while (INVENTORY_KEY.consumeClick()) {
|
||||
if (mc.screen == null) {
|
||||
LivingEntity masterTarget = findOwnedCollarTarget(mc.player);
|
||||
if (masterTarget != null) {
|
||||
mc.setScreen(new UnifiedBondageScreen(masterTarget));
|
||||
} else {
|
||||
mc.setScreen(new UnifiedBondageScreen());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SLAVE_MANAGEMENT_KEY: now handled by [J] with master mode detection (see above)
|
||||
while (SLAVE_MANAGEMENT_KEY.consumeClick()) {
|
||||
// consumed but no-op — kept registered to avoid key conflict during transition
|
||||
}
|
||||
|
||||
// Check bounty list key
|
||||
while (BOUNTY_KEY.consumeClick()) {
|
||||
// Request bounty list from server (server will open the screen)
|
||||
if (mc.screen == null) {
|
||||
ModNetwork.sendToServer(new PacketRequestBounties());
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[CLIENT] Bounty key pressed - requesting bounty list"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check tighten key
|
||||
while (TIGHTEN_KEY.consumeClick()) {
|
||||
// Send tighten packet to server (server finds target)
|
||||
if (mc.screen == null) {
|
||||
ModNetwork.sendToServer(new PacketTighten());
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[CLIENT] Tighten key pressed - sending tighten request"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase 21: Handle struggle key press with new flow.
|
||||
*
|
||||
* Flow:
|
||||
* 1. If bind equipped: Send PacketStruggle to server (struggle against bind)
|
||||
* 2. If no bind: Check for locked accessories
|
||||
* - If locked accessories exist: Open StruggleChoiceScreen
|
||||
* - If no locked accessories: Show "Nothing to struggle" message
|
||||
*/
|
||||
private static void handleStruggleKey() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
Player player = mc.player;
|
||||
if (player == null || mc.screen != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// V2 path: check if player has V2 equipment to struggle against
|
||||
if (com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper.hasAnyEquipment(player)) {
|
||||
handleV2Struggle(player);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerBindState state = PlayerBindState.getInstance(player);
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if player has bind equipped
|
||||
if (state.isTiedUp()) {
|
||||
// Has bind - struggle against it
|
||||
// Phase 2.5: Check if mini-game is enabled
|
||||
if (ModConfig.SERVER.struggleMiniGameEnabled.get()) {
|
||||
// New: Start struggle mini-game
|
||||
ModNetwork.sendToServer(new PacketV2StruggleStart(BodyRegionV2.ARMS));
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[CLIENT] Struggle key pressed - starting V2 struggle mini-game"
|
||||
);
|
||||
} else {
|
||||
// Legacy: Probability-based struggle
|
||||
ModNetwork.sendToServer(new PacketStruggle());
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[CLIENT] Struggle key pressed - legacy struggle against bind"
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// No bind - check for locked accessories
|
||||
boolean hasLockedAccessories = hasAnyLockedAccessory(player);
|
||||
|
||||
if (hasLockedAccessories) {
|
||||
// Open UnifiedBondageScreen in self mode
|
||||
mc.setScreen(new UnifiedBondageScreen());
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[CLIENT] Struggle key pressed - opening unified bondage screen"
|
||||
);
|
||||
} else {
|
||||
// No locked accessories - show message
|
||||
player.displayClientMessage(
|
||||
Component.translatable("tiedup.struggle.nothing").withStyle(
|
||||
ChatFormatting.GRAY
|
||||
),
|
||||
true
|
||||
);
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[CLIENT] Struggle key pressed - nothing to struggle"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle struggle key for V2 equipment.
|
||||
* Auto-targets the highest posePriority item.
|
||||
*/
|
||||
private static void handleV2Struggle(Player player) {
|
||||
java.util.Map<com.tiedup.remake.v2.BodyRegionV2, ItemStack> equipped =
|
||||
com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper.getAllEquipped(player);
|
||||
|
||||
if (equipped.isEmpty()) return;
|
||||
|
||||
// Auto-target: find highest posePriority item
|
||||
com.tiedup.remake.v2.BodyRegionV2 bestRegion = null;
|
||||
int bestPriority = Integer.MIN_VALUE;
|
||||
|
||||
for (java.util.Map.Entry<com.tiedup.remake.v2.BodyRegionV2, ItemStack> entry : equipped.entrySet()) {
|
||||
ItemStack stack = entry.getValue();
|
||||
if (stack.getItem() instanceof com.tiedup.remake.v2.bondage.IV2BondageItem item) {
|
||||
if (item.getPosePriority(stack) > bestPriority) {
|
||||
bestPriority = item.getPosePriority(stack);
|
||||
bestRegion = entry.getKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestRegion != null) {
|
||||
ModNetwork.sendToServer(
|
||||
new com.tiedup.remake.v2.bondage.network.PacketV2StruggleStart(bestRegion)
|
||||
);
|
||||
TiedUpMod.LOGGER.debug(
|
||||
"[CLIENT] V2 Struggle key pressed - targeting region {}",
|
||||
bestRegion.name()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the crosshair entity: if it is a LivingEntity wearing a collar owned by the player,
|
||||
* return it as the MASTER mode target. Returns null if no valid target.
|
||||
*/
|
||||
@Nullable
|
||||
private static LivingEntity findOwnedCollarTarget(Player player) {
|
||||
if (player == null) return null;
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
net.minecraft.world.entity.Entity crosshair = mc.crosshairPickEntity;
|
||||
if (crosshair instanceof LivingEntity living) {
|
||||
return checkCollarOwnership(living, player) ? living : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given entity has a collar in the NECK region that lists the player as an owner.
|
||||
*/
|
||||
private static boolean checkCollarOwnership(LivingEntity target, Player player) {
|
||||
ItemStack collarStack = com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper.getInRegion(
|
||||
target, BodyRegionV2.NECK
|
||||
);
|
||||
if (!collarStack.isEmpty() && collarStack.getItem() instanceof ItemCollar collar) {
|
||||
return collar.isOwner(collarStack, player);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if player has any locked accessories.
|
||||
*/
|
||||
private static boolean hasAnyLockedAccessory(Player player) {
|
||||
BodyRegionV2[] accessoryRegions = {
|
||||
BodyRegionV2.MOUTH,
|
||||
BodyRegionV2.EYES,
|
||||
BodyRegionV2.EARS,
|
||||
BodyRegionV2.NECK,
|
||||
BodyRegionV2.TORSO,
|
||||
BodyRegionV2.HANDS,
|
||||
};
|
||||
|
||||
for (BodyRegionV2 region : accessoryRegions) {
|
||||
ItemStack stack = V2EquipmentHelper.getInRegion(player, region);
|
||||
if (
|
||||
!stack.isEmpty() &&
|
||||
stack.getItem() instanceof ILockable lockable
|
||||
) {
|
||||
if (lockable.isLocked(stack)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user