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:
NotEvil
2026-04-12 00:51:22 +02:00
parent 2e7a1d403b
commit f6466360b6
1947 changed files with 238025 additions and 1 deletions

View File

@@ -0,0 +1,395 @@
package com.tiedup.remake.items;
import com.tiedup.remake.core.ModConfig;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.ILockable;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.jetbrains.annotations.Nullable;
/**
* Lockpick item for picking locks on bondage restraints.
*
* Phase 21: Revamped Lockpick System
*
* Behavior:
* - 25% chance of success per attempt
* - SUCCESS: Instant unlock, padlock PRESERVED (lockable=true)
* - FAIL:
* - 2.5% chance to JAM the lock (blocks future lockpick attempts)
* - 15% chance to break the lockpick
* - If shock collar equipped: SHOCK + notify owners
* - Cannot be used while wearing mittens
* - Durability: 10 uses
*/
public class ItemLockpick extends Item {
private static final Random random = new Random();
public ItemLockpick() {
super(new Item.Properties().durability(5)); // 5 tentatives max
}
@Override
public void appendHoverText(
ItemStack stack,
@Nullable Level level,
List<Component> tooltip,
TooltipFlag flag
) {
super.appendHoverText(stack, level, tooltip, flag);
tooltip.add(
Component.translatable("item.tiedup.lockpick.tooltip").withStyle(
ChatFormatting.GRAY
)
);
int remaining = stack.getMaxDamage() - stack.getDamageValue();
tooltip.add(
Component.literal(
"Uses: " + remaining + "/" + stack.getMaxDamage()
).withStyle(ChatFormatting.DARK_GRAY)
);
// LOW FIX: Removed server config access from client tooltip (desync issue)
// Success/break chances depend on server config, not client config
// Displaying client config values here would be misleading in multiplayer
tooltip.add(
Component.literal("Success/break chances: Check server config")
.withStyle(ChatFormatting.GRAY)
.withStyle(ChatFormatting.ITALIC)
);
}
/**
* v2.5: Right-click with lockpick opens the struggle choice screen.
* This allows the player to choose which locked item to pick.
*/
@Override
public InteractionResultHolder<ItemStack> use(
Level level,
Player player,
InteractionHand hand
) {
ItemStack stack = player.getItemInHand(hand);
PlayerBindState state = PlayerBindState.getInstance(player);
if (state == null) {
return InteractionResultHolder.pass(stack);
}
// Block mittens
if (state.hasMittens()) {
if (!level.isClientSide) {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.CANT_USE_ITEM_MITTENS
);
}
return InteractionResultHolder.fail(stack);
}
// Client side: open the unified bondage screen
if (level.isClientSide) {
openUnifiedBondageScreen();
return InteractionResultHolder.success(stack);
}
return InteractionResultHolder.consume(stack);
}
/**
* Client-only method to open the unified bondage screen.
* Separated to avoid classloading issues on server.
* Uses fully qualified names to prevent class loading on server.
*/
@OnlyIn(Dist.CLIENT)
private void openUnifiedBondageScreen() {
net.minecraft.client.Minecraft.getInstance().setScreen(
new com.tiedup.remake.client.gui.screens.UnifiedBondageScreen()
);
}
/**
* Check if this lockpick can be used (has durability remaining).
*/
public static boolean canUse(ItemStack stack) {
if (stack.isEmpty() || !(stack.getItem() instanceof ItemLockpick)) {
return false;
}
return stack.getDamageValue() < stack.getMaxDamage();
}
/**
* Result of a lockpick attempt.
*/
public enum PickResult {
/** Successfully picked the lock - item unlocked, padlock preserved */
SUCCESS,
/** Failed but lock still pickable */
FAIL,
/** Failed and jammed the lock - lockpick no longer usable on this item */
JAMMED,
/** Lockpick broke during attempt */
BROKE,
/** Cannot attempt - mittens equipped */
BLOCKED_MITTENS,
/** Cannot attempt - lock is jammed */
BLOCKED_JAMMED,
/** Cannot attempt - item not locked */
NOT_LOCKED,
}
/**
* Attempt to pick a lock on a target item.
*
* @param player The player attempting to pick
* @param state The player's bind state
* @param lockpickStack The lockpick being used
* @param targetStack The item to pick
* @param targetRegion The V2 body region of the target item
* @return The result of the pick attempt
*/
public static PickResult attemptPick(
Player player,
PlayerBindState state,
ItemStack lockpickStack,
ItemStack targetStack,
BodyRegionV2 targetRegion
) {
// Check if lockpick is usable
if (!canUse(lockpickStack)) {
return PickResult.BROKE;
}
// Check if wearing mittens
if (state.hasMittens()) {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.CANT_USE_ITEM_MITTENS
);
return PickResult.BLOCKED_MITTENS;
}
// Check if target is lockable and locked
if (!(targetStack.getItem() instanceof ILockable lockable)) {
return PickResult.NOT_LOCKED;
}
if (!lockable.isLocked(targetStack)) {
return PickResult.NOT_LOCKED;
}
// Check if lock is jammed
if (lockable.isJammed(targetStack)) {
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.ERROR,
"This lock is jammed! Use struggle instead."
);
return PickResult.BLOCKED_JAMMED;
}
// Roll for success
boolean success =
random.nextInt(100) < ModConfig.SERVER.lockpickSuccessChance.get();
if (success) {
// SUCCESS: Unlock the item, PRESERVE the padlock
lockable.setLockedByKeyUUID(targetStack, null); // Unlock
lockable.clearLockResistance(targetStack); // Clear struggle progress
// lockable stays true - padlock preserved!
SystemMessageManager.sendToPlayer(
player,
"Lock picked!",
ChatFormatting.GREEN
);
// Damage lockpick
damageLockpick(lockpickStack);
TiedUpMod.LOGGER.info(
"[LOCKPICK] {} successfully picked lock on {} ({})",
player.getName().getString(),
targetStack.getDisplayName().getString(),
targetRegion
);
return PickResult.SUCCESS;
} else {
// FAIL: Various bad things can happen
// 1. Check for shock collar and trigger shock
triggerShockIfCollar(player, state);
// 2. Check for jam
boolean jammed =
random.nextDouble() * 100 <
ModConfig.SERVER.lockpickJamChance.get();
if (jammed) {
lockable.setJammed(targetStack, true);
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.ERROR,
"The lock jammed! Only struggle can open it now."
);
TiedUpMod.LOGGER.info(
"[LOCKPICK] {} jammed the lock on {} ({})",
player.getName().getString(),
targetStack.getDisplayName().getString(),
targetRegion
);
// Damage lockpick
boolean broke = damageLockpick(lockpickStack);
return broke ? PickResult.BROKE : PickResult.JAMMED;
}
// 3. Check for break
boolean broke =
random.nextInt(100) <
ModConfig.SERVER.lockpickBreakChance.get();
if (broke) {
lockpickStack.shrink(1);
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.ERROR,
"Lockpick broke!"
);
TiedUpMod.LOGGER.info(
"[LOCKPICK] {}'s lockpick broke while picking {} ({})",
player.getName().getString(),
targetStack.getDisplayName().getString(),
targetRegion
);
return PickResult.BROKE;
}
// 4. Normal fail - just damage lockpick
damageLockpick(lockpickStack);
SystemMessageManager.sendToPlayer(
player,
SystemMessageManager.MessageCategory.WARNING,
"Lockpick slipped..."
);
TiedUpMod.LOGGER.debug(
"[LOCKPICK] {} failed to pick lock on {} ({})",
player.getName().getString(),
targetStack.getDisplayName().getString(),
targetRegion
);
return PickResult.FAIL;
}
}
/**
* Damage the lockpick by 1 use.
* @return true if the lockpick broke (ran out of durability)
*/
private static boolean damageLockpick(ItemStack stack) {
stack.setDamageValue(stack.getDamageValue() + 1);
if (stack.getDamageValue() >= stack.getMaxDamage()) {
stack.shrink(1);
return true;
}
return false;
}
/**
* Trigger shock collar if player has one equipped.
* Also notifies the collar owners.
*/
private static void triggerShockIfCollar(
Player player,
PlayerBindState state
) {
ItemStack collar = V2EquipmentHelper.getInRegion(
player,
BodyRegionV2.NECK
);
if (collar.isEmpty()) return;
if (
collar.getItem() instanceof
com.tiedup.remake.items.ItemShockCollar shockCollar
) {
// Shock the player
state.shockKidnapped(" (Failed lockpick attempt)", 2.0f);
// Notify owners
notifyOwnersLockpickAttempt(player, collar, shockCollar);
TiedUpMod.LOGGER.info(
"[LOCKPICK] {} was shocked for failed lockpick attempt",
player.getName().getString()
);
}
}
/**
* Notify shock collar owners about the lockpick attempt.
*/
private static void notifyOwnersLockpickAttempt(
Player player,
ItemStack collar,
com.tiedup.remake.items.ItemShockCollar shockCollar
) {
if (player.getServer() == null) return;
Component warning = Component.literal("ALERT: ")
.withStyle(ChatFormatting.RED, ChatFormatting.BOLD)
.append(
Component.literal(
player.getName().getString() + " tried to pick a lock!"
).withStyle(ChatFormatting.GOLD)
);
List<UUID> owners = shockCollar.getOwners(collar);
for (UUID ownerId : owners) {
ServerPlayer owner = player
.getServer()
.getPlayerList()
.getPlayer(ownerId);
if (owner != null) {
owner.sendSystemMessage(warning);
}
}
}
/**
* Find a lockpick in the player's inventory.
* @return The first usable lockpick found, or EMPTY if none
*/
public static ItemStack findLockpickInInventory(Player player) {
for (ItemStack stack : player.getInventory().items) {
if (canUse(stack)) {
return stack;
}
}
return ItemStack.EMPTY;
}
}