From c851da4eaf28f18b77ca8ca8a2f40188abef136d Mon Sep 17 00:00:00 2001 From: NotEvil Date: Wed, 15 Apr 2026 11:09:48 +0200 Subject: [PATCH] =?UTF-8?q?refactor:=20split=20BondageSubCommand=201207L?= =?UTF-8?q?=20=E2=86=92=205=20focused=20files=20(UC-01)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - BindCommands.java: tie, untie (156L) - GagCommands.java: gag, ungag (140L) - BlindfoldCommands.java: blindfold, unblind (142L) - CollarCommands.java: collar, takecollar, enslave, free (288L) - AccessoryCommands.java: putearplugs, takeearplugs, putclothes, takeclothes, fullyrestrain, adjust (469L) - BondageSubCommand.java: thin delegator (19L) Zero logic changes — purely mechanical code move. --- .../subcommands/AccessoryCommands.java | 469 +++++++ .../commands/subcommands/BindCommands.java | 156 +++ .../subcommands/BlindfoldCommands.java | 142 ++ .../subcommands/BondageSubCommand.java | 1202 +---------------- .../commands/subcommands/CollarCommands.java | 288 ++++ .../commands/subcommands/GagCommands.java | 140 ++ 6 files changed, 1202 insertions(+), 1195 deletions(-) create mode 100644 src/main/java/com/tiedup/remake/commands/subcommands/AccessoryCommands.java create mode 100644 src/main/java/com/tiedup/remake/commands/subcommands/BindCommands.java create mode 100644 src/main/java/com/tiedup/remake/commands/subcommands/BlindfoldCommands.java create mode 100644 src/main/java/com/tiedup/remake/commands/subcommands/CollarCommands.java create mode 100644 src/main/java/com/tiedup/remake/commands/subcommands/GagCommands.java diff --git a/src/main/java/com/tiedup/remake/commands/subcommands/AccessoryCommands.java b/src/main/java/com/tiedup/remake/commands/subcommands/AccessoryCommands.java new file mode 100644 index 0000000..2f0a851 --- /dev/null +++ b/src/main/java/com/tiedup/remake/commands/subcommands/AccessoryCommands.java @@ -0,0 +1,469 @@ +package com.tiedup.remake.commands.subcommands; + +import com.mojang.brigadier.arguments.FloatArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.tiedup.remake.items.base.AdjustmentHelper; +import com.tiedup.remake.items.ModItems; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.tiedup.remake.commands.CommandHelper; +import com.tiedup.remake.v2.bondage.CollarHelper; +import com.tiedup.remake.core.SystemMessageManager; +import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem; +import net.minecraft.resources.ResourceLocation; +import com.tiedup.remake.state.PlayerBindState; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; + +@SuppressWarnings("null") +public class AccessoryCommands { + + public static void register(LiteralArgumentBuilder root) { + // /tiedup putearplugs + root.then( + Commands.literal("putearplugs") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(AccessoryCommands::putearplugs) + ) + ); + // /tiedup takeearplugs + root.then( + Commands.literal("takeearplugs") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(AccessoryCommands::takeearplugs) + ) + ); + // /tiedup putclothes + root.then( + Commands.literal("putclothes") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(AccessoryCommands::putclothes) + ) + ); + // /tiedup takeclothes + root.then( + Commands.literal("takeclothes") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(AccessoryCommands::takeclothes) + ) + ); + // /tiedup fullyrestrain + root.then( + Commands.literal("fullyrestrain") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(AccessoryCommands::fullyrestrain) + ) + ); + // /tiedup adjust + root.then( + Commands.literal("adjust") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument("player", EntityArgument.player()).then( + Commands.argument("type", StringArgumentType.word()) + .suggests((ctx, builder) -> { + builder.suggest("gag"); + builder.suggest("blindfold"); + builder.suggest("all"); + return builder.buildFuture(); + }) + .then( + Commands.argument( + "value", + FloatArgumentType.floatArg(-4.0f, 4.0f) + ).executes(AccessoryCommands::adjust) + ) + ) + ) + ); + } + + static int putearplugs(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (state.hasEarplugs()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " already has earplugs" + ) + ); + return 0; + } + + ItemStack earplugs = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_earplugs")); + state.putEarplugsOn(earplugs); + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been given earplugs" + ), + true + ); + SystemMessageManager.sendToTarget( + context.getSource().getEntity(), + targetPlayer, + SystemMessageManager.MessageCategory.EARPLUGS_ON + ); + + return 1; + } + + static int takeearplugs(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (!state.hasEarplugs()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " does not have earplugs" + ) + ); + return 0; + } + + state.takeEarplugsOff(); + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + "'s earplugs have been removed" + ), + true + ); + SystemMessageManager.sendToPlayer( + targetPlayer, + SystemMessageManager.MessageCategory.INFO, + "Your earplugs have been removed!" + ); + + return 1; + } + + static int putclothes(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (state.hasClothes()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " already has clothes" + ) + ); + return 0; + } + + ItemStack clothes = new ItemStack(ModItems.CLOTHES.get()); + state.putClothesOn(clothes); + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been given clothes" + ), + true + ); + + return 1; + } + + static int takeclothes(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (!state.hasClothes()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " is not wearing clothes" + ) + ); + return 0; + } + + ItemStack removed = state.takeClothesOff(); + CommandHelper.syncPlayerState(targetPlayer, state); + + if (!removed.isEmpty()) { + targetPlayer.drop(removed, false); + } + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "Removed clothes from " + + targetPlayer.getName().getString() + ), + true + ); + return 1; + } + + static int fullyrestrain(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + int applied = 0; + + if (!state.isTiedUp()) { + ItemStack ropes = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "ropes")); + state.putBindOn(ropes); + applied++; + } + + if (!state.isGagged()) { + ItemStack gag = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "cloth_gag")); + state.putGagOn(gag); + applied++; + } + + if (!state.isBlindfolded()) { + ItemStack blindfold = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_blindfold")); + state.putBlindfoldOn(blindfold); + applied++; + } + + if (!state.hasCollar()) { + ItemStack collar = com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem.createStack(new net.minecraft.resources.ResourceLocation("tiedup", "classic_collar")); + if ( + context.getSource().getEntity() instanceof ServerPlayer executor + ) { + CollarHelper.addOwner(collar, executor); + } + state.putCollarOn(collar); + applied++; + } + + if (!state.hasEarplugs()) { + ItemStack earplugs = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_earplugs")); + state.putEarplugsOn(earplugs); + applied++; + } + + if (applied == 0) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " is already fully restrained" + ) + ); + return 0; + } + + CommandHelper.syncPlayerState(targetPlayer, state); + + int finalApplied = applied; + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been fully restrained (" + + finalApplied + + " items applied)" + ), + true + ); + SystemMessageManager.sendToPlayer( + targetPlayer, + SystemMessageManager.MessageCategory.INFO, + "You have been fully restrained!" + ); + + return 1; + } + + static int adjust(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + String type = StringArgumentType.getString(context, "type"); + float value = FloatArgumentType.getFloat(context, "value"); + + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + boolean adjustedGag = false; + boolean adjustedBlindfold = false; + + if (type.equals("gag") || type.equals("all")) { + ItemStack gag = state.getEquipment( + com.tiedup.remake.v2.BodyRegionV2.MOUTH + ); + if (!gag.isEmpty()) { + AdjustmentHelper.setAdjustment(gag, value); + adjustedGag = true; + } + } + + if (type.equals("blindfold") || type.equals("all")) { + ItemStack blindfold = state.getEquipment( + com.tiedup.remake.v2.BodyRegionV2.EYES + ); + if (!blindfold.isEmpty()) { + AdjustmentHelper.setAdjustment(blindfold, value); + adjustedBlindfold = true; + } + } + + if ( + !type.equals("gag") && + !type.equals("blindfold") && + !type.equals("all") + ) { + context + .getSource() + .sendFailure( + Component.literal( + "Invalid type. Use: gag, blindfold, or all" + ) + ); + return 0; + } + + if (!adjustedGag && !adjustedBlindfold) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " has no " + + type + + " to adjust" + ) + ); + return 0; + } + + CommandHelper.syncPlayerState(targetPlayer, state); + + String items = + adjustedGag && adjustedBlindfold + ? "gag and blindfold" + : adjustedGag + ? "gag" + : "blindfold"; + String valueStr = String.format("%.2f", value); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7aAdjusted " + + items + + " for " + + targetPlayer.getName().getString() + + " to " + + valueStr + + " pixels" + ), + true + ); + + return 1; + } + +} diff --git a/src/main/java/com/tiedup/remake/commands/subcommands/BindCommands.java b/src/main/java/com/tiedup/remake/commands/subcommands/BindCommands.java new file mode 100644 index 0000000..84a82df --- /dev/null +++ b/src/main/java/com/tiedup/remake/commands/subcommands/BindCommands.java @@ -0,0 +1,156 @@ +package com.tiedup.remake.commands.subcommands; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.tiedup.remake.commands.CommandHelper; +import com.tiedup.remake.core.SystemMessageManager; +import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem; +import net.minecraft.resources.ResourceLocation; +import com.tiedup.remake.state.PlayerBindState; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; + +@SuppressWarnings("null") +public class BindCommands { + + public static void register(LiteralArgumentBuilder root) { + // /tiedup untie + root.then( + Commands.literal("untie") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(BindCommands::untie) + ) + ); + } + + static int tie(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (state.isTiedUp()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " is already tied up" + ) + ); + return 0; + } + + ItemStack ropes = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "ropes")); + state.putBindOn(ropes); + + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been tied up" + ), + true + ); + SystemMessageManager.sendTiedUp( + context.getSource().getEntity(), + targetPlayer + ); + + return 1; + } + + static int untie(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if ( + !state.isTiedUp() && + !state.isGagged() && + !state.isBlindfolded() && + !state.hasCollar() + ) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " is not restrained" + ) + ); + return 0; + } + + boolean removed = false; + if (state.isTiedUp()) { + state.takeBindOff(); + removed = true; + } + if (state.isGagged()) { + state.takeGagOff(); + removed = true; + } + if (state.isBlindfolded()) { + state.takeBlindfoldOff(); + removed = true; + } + if (state.hasCollar()) { + state.takeCollarOff(); + removed = true; + } + if (state.hasEarplugs()) { + state.takeEarplugsOff(); + removed = true; + } + + if (removed) { + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been freed from all restraints" + ), + true + ); + SystemMessageManager.sendFreed(targetPlayer); + + return 1; + } + + return 0; + } + +} diff --git a/src/main/java/com/tiedup/remake/commands/subcommands/BlindfoldCommands.java b/src/main/java/com/tiedup/remake/commands/subcommands/BlindfoldCommands.java new file mode 100644 index 0000000..44d297b --- /dev/null +++ b/src/main/java/com/tiedup/remake/commands/subcommands/BlindfoldCommands.java @@ -0,0 +1,142 @@ +package com.tiedup.remake.commands.subcommands; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.tiedup.remake.commands.CommandHelper; +import com.tiedup.remake.core.SystemMessageManager; +import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem; +import net.minecraft.resources.ResourceLocation; +import com.tiedup.remake.state.PlayerBindState; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; + +@SuppressWarnings("null") +public class BlindfoldCommands { + + public static void register(LiteralArgumentBuilder root) { + // /tiedup blindfold + root.then( + Commands.literal("blindfold") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(BlindfoldCommands::blindfold) + ) + ); + // /tiedup unblind + root.then( + Commands.literal("unblind") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(BlindfoldCommands::unblind) + ) + ); + } + + static int blindfold(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (state.isBlindfolded()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " is already blindfolded" + ) + ); + return 0; + } + + ItemStack blindfold = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_blindfold")); + state.putBlindfoldOn(blindfold); + + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been blindfolded" + ), + true + ); + SystemMessageManager.sendToTarget( + context.getSource().getEntity(), + targetPlayer, + SystemMessageManager.MessageCategory.BLINDFOLDED + ); + + return 1; + } + + static int unblind(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (!state.isBlindfolded()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " is not blindfolded" + ) + ); + return 0; + } + + state.takeBlindfoldOff(); + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + "'s blindfold has been removed" + ), + true + ); + SystemMessageManager.sendToTarget( + context.getSource().getEntity(), + targetPlayer, + SystemMessageManager.MessageCategory.UNBLINDFOLDED + ); + + return 1; + } + +} diff --git a/src/main/java/com/tiedup/remake/commands/subcommands/BondageSubCommand.java b/src/main/java/com/tiedup/remake/commands/subcommands/BondageSubCommand.java index 20b8301..e6a5c05 100644 --- a/src/main/java/com/tiedup/remake/commands/subcommands/BondageSubCommand.java +++ b/src/main/java/com/tiedup/remake/commands/subcommands/BondageSubCommand.java @@ -1,1207 +1,19 @@ package com.tiedup.remake.commands.subcommands; -import com.mojang.brigadier.arguments.FloatArgumentType; -import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.tiedup.remake.commands.CommandHelper; -import com.tiedup.remake.core.SystemMessageManager; -import com.tiedup.remake.items.ModItems; -import com.tiedup.remake.items.base.AdjustmentHelper; -import com.tiedup.remake.network.ModNetwork; -import com.tiedup.remake.v2.bondage.CollarHelper; -import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem; -import net.minecraft.resources.ResourceLocation; -import com.tiedup.remake.network.sync.PacketSyncBindState; -import com.tiedup.remake.state.PlayerBindState; import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.item.ItemStack; /** * Bondage-related sub-commands for /tiedup. - * Handles: tie, untie, gag, ungag, blindfold, unblind, collar, takecollar, - * takeearplugs, putearplugs, takeclothes, putclothes, fullyrestrain, enslave, free, adjust + * Delegates to specialized command classes. */ -@SuppressWarnings("null") public class BondageSubCommand { - public static void register( - LiteralArgumentBuilder root - ) { - // /tiedup tie - root.then( - Commands.literal("tie") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::tie) - ) - ); - // /tiedup untie - root.then( - Commands.literal("untie") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::untie) - ) - ); - // /tiedup gag - root.then( - Commands.literal("gag") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::gag) - ) - ); - // /tiedup ungag - root.then( - Commands.literal("ungag") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::ungag) - ) - ); - // /tiedup blindfold - root.then( - Commands.literal("blindfold") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::blindfold) - ) - ); - // /tiedup unblind - root.then( - Commands.literal("unblind") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::unblind) - ) - ); - // /tiedup collar - root.then( - Commands.literal("collar") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::collar) - ) - ); - // /tiedup takecollar - root.then( - Commands.literal("takecollar") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::takecollar) - ) - ); - // /tiedup takeearplugs - root.then( - Commands.literal("takeearplugs") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::takeearplugs) - ) - ); - // /tiedup putearplugs - root.then( - Commands.literal("putearplugs") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::putearplugs) - ) - ); - // /tiedup takeclothes - root.then( - Commands.literal("takeclothes") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::takeclothes) - ) - ); - // /tiedup putclothes - root.then( - Commands.literal("putclothes") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::putclothes) - ) - ); - // /tiedup fullyrestrain - root.then( - Commands.literal("fullyrestrain") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::fullyrestrain) - ) - ); - // /tiedup enslave - root.then( - Commands.literal("enslave") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::enslave) - ) - ); - // /tiedup free - root.then( - Commands.literal("free") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument( - "player", - EntityArgument.player() - ).executes(BondageSubCommand::free) - ) - ); - // /tiedup adjust - root.then( - Commands.literal("adjust") - .requires(CommandHelper.REQUIRES_OP) - .then( - Commands.argument("player", EntityArgument.player()).then( - Commands.argument("type", StringArgumentType.word()) - .suggests((ctx, builder) -> { - builder.suggest("gag"); - builder.suggest("blindfold"); - builder.suggest("all"); - return builder.buildFuture(); - }) - .then( - Commands.argument( - "value", - FloatArgumentType.floatArg(-4.0f, 4.0f) - ).executes(BondageSubCommand::adjust) - ) - ) - ) - ); - } - - // Command Implementations - - /** - * /tiedup tie - * - * Forcefully tie a player with ropes (default bind). - * Uses ItemRopes from ModItems. - */ - private static int tie(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (state.isTiedUp()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " is already tied up" - ) - ); - return 0; - } - - ItemStack ropes = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "ropes")); - state.putBindOn(ropes); - - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been tied up" - ), - true - ); - SystemMessageManager.sendTiedUp( - context.getSource().getEntity(), - targetPlayer - ); - - return 1; - } - - /** - * /tiedup untie - * - * Forcefully untie a player, removing ALL bondage equipment. - */ - private static int untie(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if ( - !state.isTiedUp() && - !state.isGagged() && - !state.isBlindfolded() && - !state.hasCollar() - ) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " is not restrained" - ) - ); - return 0; - } - - boolean removed = false; - if (state.isTiedUp()) { - state.takeBindOff(); - removed = true; - } - if (state.isGagged()) { - state.takeGagOff(); - removed = true; - } - if (state.isBlindfolded()) { - state.takeBlindfoldOff(); - removed = true; - } - if (state.hasCollar()) { - state.takeCollarOff(); - removed = true; - } - if (state.hasEarplugs()) { - state.takeEarplugsOff(); - removed = true; - } - - if (removed) { - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been freed from all restraints" - ), - true - ); - SystemMessageManager.sendFreed(targetPlayer); - - return 1; - } - - return 0; - } - - /** - * /tiedup gag - * - * Forcefully gag a player with cloth gag (default). - */ - private static int gag(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (state.isGagged()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " is already gagged" - ) - ); - return 0; - } - - ItemStack gag = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "cloth_gag")); - state.putGagOn(gag); - - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been gagged" - ), - true - ); - SystemMessageManager.sendGagged( - context.getSource().getEntity(), - targetPlayer - ); - - return 1; - } - - /** - * /tiedup blindfold - * - * Forcefully blindfold a player with classic blindfold (default). - */ - private static int blindfold(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (state.isBlindfolded()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " is already blindfolded" - ) - ); - return 0; - } - - ItemStack blindfold = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_blindfold")); - state.putBlindfoldOn(blindfold); - - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been blindfolded" - ), - true - ); - SystemMessageManager.sendToTarget( - context.getSource().getEntity(), - targetPlayer, - SystemMessageManager.MessageCategory.BLINDFOLDED - ); - - return 1; - } - - /** - * /tiedup collar - * - * Give a collar to a player (forces collar even if not tied). - * The command executor becomes the owner of the collar. - */ - private static int collar(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (state.hasCollar()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " already has a collar" - ) - ); - return 0; - } - - ItemStack collar = com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem.createStack(new net.minecraft.resources.ResourceLocation("tiedup", "classic_collar")); - - if (context.getSource().getEntity() instanceof ServerPlayer executor) { - CollarHelper.addOwner(collar, executor); - } - - state.putCollarOn(collar); - - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been collared" - ), - true - ); - SystemMessageManager.sendToTarget( - context.getSource().getEntity(), - targetPlayer, - SystemMessageManager.MessageCategory.COLLARED - ); - - return 1; - } - - /** - * /tiedup free - * - * Free a player from slavery (removes master relationship). - * Does NOT remove collar or other equipment. - */ - private static int free(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (!state.isCaptive()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + " is not captured" - ) - ); - return 0; - } - - state.free(true); - - PacketSyncBindState statePacket = PacketSyncBindState.fromPlayer( - targetPlayer - ); - if (statePacket != null) { - ModNetwork.sendToPlayer(statePacket, targetPlayer); - } - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been freed from slavery" - ), - true - ); - SystemMessageManager.sendFreed(targetPlayer); - - return 1; - } - - /** - * /tiedup adjust - * - * Adjust the Y position of gags and/or blindfolds on a player. - * Value range: -4.0 to +4.0 (pixels, 1 pixel = 1/16 block) - * - * Types: - * - gag: Adjust only gag - * - blindfold: Adjust only blindfold - * - all: Adjust both gag and blindfold - */ - private static int adjust(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - String type = StringArgumentType.getString(context, "type"); - float value = FloatArgumentType.getFloat(context, "value"); - - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - boolean adjustedGag = false; - boolean adjustedBlindfold = false; - - if (type.equals("gag") || type.equals("all")) { - ItemStack gag = state.getEquipment( - com.tiedup.remake.v2.BodyRegionV2.MOUTH - ); - if (!gag.isEmpty()) { - AdjustmentHelper.setAdjustment(gag, value); - adjustedGag = true; - } - } - - if (type.equals("blindfold") || type.equals("all")) { - ItemStack blindfold = state.getEquipment( - com.tiedup.remake.v2.BodyRegionV2.EYES - ); - if (!blindfold.isEmpty()) { - AdjustmentHelper.setAdjustment(blindfold, value); - adjustedBlindfold = true; - } - } - - if ( - !type.equals("gag") && - !type.equals("blindfold") && - !type.equals("all") - ) { - context - .getSource() - .sendFailure( - Component.literal( - "Invalid type. Use: gag, blindfold, or all" - ) - ); - return 0; - } - - if (!adjustedGag && !adjustedBlindfold) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " has no " + - type + - " to adjust" - ) - ); - return 0; - } - - CommandHelper.syncPlayerState(targetPlayer, state); - - String items = - adjustedGag && adjustedBlindfold - ? "gag and blindfold" - : adjustedGag - ? "gag" - : "blindfold"; - String valueStr = String.format("%.2f", value); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7aAdjusted " + - items + - " for " + - targetPlayer.getName().getString() + - " to " + - valueStr + - " pixels" - ), - true - ); - - return 1; - } - - /** - * /tiedup ungag - * - * Remove gag from a player. - */ - private static int ungag(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (!state.isGagged()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + " is not gagged" - ) - ); - return 0; - } - - state.takeGagOff(); - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - "'s gag has been removed" - ), - true - ); - SystemMessageManager.sendToTarget( - context.getSource().getEntity(), - targetPlayer, - SystemMessageManager.MessageCategory.UNGAGGED - ); - - return 1; - } - - /** - * /tiedup unblind - * - * Remove blindfold from a player. - */ - private static int unblind(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (!state.isBlindfolded()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " is not blindfolded" - ) - ); - return 0; - } - - state.takeBlindfoldOff(); - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - "'s blindfold has been removed" - ), - true - ); - SystemMessageManager.sendToTarget( - context.getSource().getEntity(), - targetPlayer, - SystemMessageManager.MessageCategory.UNBLINDFOLDED - ); - - return 1; - } - - /** - * /tiedup takecollar - * - * Remove collar from a player. - */ - private static int takecollar(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (!state.hasCollar()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " does not have a collar" - ) - ); - return 0; - } - - state.takeCollarOff(); - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - "'s collar has been removed" - ), - true - ); - SystemMessageManager.sendToTarget( - context.getSource().getEntity(), - targetPlayer, - SystemMessageManager.MessageCategory.UNCOLLARED - ); - - return 1; - } - - /** - * /tiedup takeearplugs - * - * Remove earplugs from a player. - */ - private static int takeearplugs(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (!state.hasEarplugs()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " does not have earplugs" - ) - ); - return 0; - } - - state.takeEarplugsOff(); - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - "'s earplugs have been removed" - ), - true - ); - SystemMessageManager.sendToPlayer( - targetPlayer, - SystemMessageManager.MessageCategory.INFO, - "Your earplugs have been removed!" - ); - - return 1; - } - - /** - * /tiedup takeclothes - * - * Remove clothes from a player. - */ - private static int takeclothes(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (!state.hasClothes()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " is not wearing clothes" - ) - ); - return 0; - } - - ItemStack removed = state.takeClothesOff(); - CommandHelper.syncPlayerState(targetPlayer, state); - - if (!removed.isEmpty()) { - targetPlayer.drop(removed, false); - } - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "Removed clothes from " + - targetPlayer.getName().getString() - ), - true - ); - return 1; - } - - /** - * /tiedup putclothes - * - * Put clothes on a player. - */ - private static int putclothes(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (state.hasClothes()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " already has clothes" - ) - ); - return 0; - } - - ItemStack clothes = new ItemStack(ModItems.CLOTHES.get()); - state.putClothesOn(clothes); - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been given clothes" - ), - true - ); - - return 1; - } - - /** - * /tiedup putearplugs - * - * Put earplugs on a player. - */ - private static int putearplugs(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - if (state.hasEarplugs()) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " already has earplugs" - ) - ); - return 0; - } - - ItemStack earplugs = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_earplugs")); - state.putEarplugsOn(earplugs); - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been given earplugs" - ), - true - ); - SystemMessageManager.sendToTarget( - context.getSource().getEntity(), - targetPlayer, - SystemMessageManager.MessageCategory.EARPLUGS_ON - ); - - return 1; - } - - /** - * /tiedup fullyrestrain - * - * Apply full bondage: bind + gag + blindfold + collar + earplugs - */ - private static int fullyrestrain(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - int applied = 0; - - if (!state.isTiedUp()) { - ItemStack ropes = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "ropes")); - state.putBindOn(ropes); - applied++; - } - - if (!state.isGagged()) { - ItemStack gag = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "cloth_gag")); - state.putGagOn(gag); - applied++; - } - - if (!state.isBlindfolded()) { - ItemStack blindfold = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_blindfold")); - state.putBlindfoldOn(blindfold); - applied++; - } - - if (!state.hasCollar()) { - ItemStack collar = com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem.createStack(new net.minecraft.resources.ResourceLocation("tiedup", "classic_collar")); - if ( - context.getSource().getEntity() instanceof ServerPlayer executor - ) { - CollarHelper.addOwner(collar, executor); - } - state.putCollarOn(collar); - applied++; - } - - if (!state.hasEarplugs()) { - ItemStack earplugs = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_earplugs")); - state.putEarplugsOn(earplugs); - applied++; - } - - if (applied == 0) { - context - .getSource() - .sendFailure( - Component.literal( - targetPlayer.getName().getString() + - " is already fully restrained" - ) - ); - return 0; - } - - CommandHelper.syncPlayerState(targetPlayer, state); - - int finalApplied = applied; - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been fully restrained (" + - finalApplied + - " items applied)" - ), - true - ); - SystemMessageManager.sendToPlayer( - targetPlayer, - SystemMessageManager.MessageCategory.INFO, - "You have been fully restrained!" - ); - - return 1; - } - - /** - * /tiedup enslave - * - * Fully restrain and enslave a player. - * The command executor becomes the master. - */ - private static int enslave(CommandContext context) - throws CommandSyntaxException { - ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); - PlayerBindState state = PlayerBindState.getInstance(targetPlayer); - - if (state == null) { - context - .getSource() - .sendFailure(Component.literal("Failed to get player state")); - return 0; - } - - // First fully restrain - if (!state.isTiedUp()) { - ItemStack ropes = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "ropes")); - state.putBindOn(ropes); - } - if (!state.isGagged()) { - ItemStack gag = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "cloth_gag")); - state.putGagOn(gag); - } - if (!state.isBlindfolded()) { - ItemStack blindfold = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_blindfold")); - state.putBlindfoldOn(blindfold); - } - if (!state.hasCollar()) { - ItemStack collar = com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem.createStack(new net.minecraft.resources.ResourceLocation("tiedup", "classic_collar")); - if ( - context.getSource().getEntity() instanceof ServerPlayer executor - ) { - CollarHelper.addOwner(collar, executor); - } - state.putCollarOn(collar); - } - if (!state.hasEarplugs()) { - ItemStack earplugs = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_earplugs")); - state.putEarplugsOn(earplugs); - } - - // Capture target (this makes them a captive) - if (context.getSource().getEntity() instanceof ServerPlayer master) { - PlayerBindState masterState = PlayerBindState.getInstance(master); - if (masterState != null && masterState.getCaptorManager() != null) { - masterState.getCaptorManager().addCaptive(state); - } - } - - CommandHelper.syncPlayerState(targetPlayer, state); - - context - .getSource() - .sendSuccess( - () -> - Component.literal( - "\u00a7a" + - targetPlayer.getName().getString() + - " has been enslaved" - ), - true - ); - SystemMessageManager.sendEnslaved( - context.getSource().getEntity(), - targetPlayer - ); - - return 1; + public static void register(LiteralArgumentBuilder root) { + BindCommands.register(root); + GagCommands.register(root); + BlindfoldCommands.register(root); + CollarCommands.register(root); + AccessoryCommands.register(root); } } diff --git a/src/main/java/com/tiedup/remake/commands/subcommands/CollarCommands.java b/src/main/java/com/tiedup/remake/commands/subcommands/CollarCommands.java new file mode 100644 index 0000000..d83682d --- /dev/null +++ b/src/main/java/com/tiedup/remake/commands/subcommands/CollarCommands.java @@ -0,0 +1,288 @@ +package com.tiedup.remake.commands.subcommands; + +import com.tiedup.remake.network.ModNetwork; +import com.tiedup.remake.network.sync.PacketSyncBindState; +import com.tiedup.remake.v2.bondage.CollarHelper; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.tiedup.remake.commands.CommandHelper; +import com.tiedup.remake.core.SystemMessageManager; +import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem; +import net.minecraft.resources.ResourceLocation; +import com.tiedup.remake.state.PlayerBindState; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; + +@SuppressWarnings("null") +public class CollarCommands { + + public static void register(LiteralArgumentBuilder root) { + // /tiedup collar + root.then( + Commands.literal("collar") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(CollarCommands::collar) + ) + ); + // /tiedup takecollar + root.then( + Commands.literal("takecollar") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(CollarCommands::takecollar) + ) + ); + // /tiedup enslave + root.then( + Commands.literal("enslave") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(CollarCommands::enslave) + ) + ); + // /tiedup free + root.then( + Commands.literal("free") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(CollarCommands::free) + ) + ); + } + + static int collar(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (state.hasCollar()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " already has a collar" + ) + ); + return 0; + } + + ItemStack collar = com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem.createStack(new net.minecraft.resources.ResourceLocation("tiedup", "classic_collar")); + + if (context.getSource().getEntity() instanceof ServerPlayer executor) { + CollarHelper.addOwner(collar, executor); + } + + state.putCollarOn(collar); + + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been collared" + ), + true + ); + SystemMessageManager.sendToTarget( + context.getSource().getEntity(), + targetPlayer, + SystemMessageManager.MessageCategory.COLLARED + ); + + return 1; + } + + static int takecollar(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (!state.hasCollar()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " does not have a collar" + ) + ); + return 0; + } + + state.takeCollarOff(); + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + "'s collar has been removed" + ), + true + ); + SystemMessageManager.sendToTarget( + context.getSource().getEntity(), + targetPlayer, + SystemMessageManager.MessageCategory.UNCOLLARED + ); + + return 1; + } + + static int enslave(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + // First fully restrain + if (!state.isTiedUp()) { + ItemStack ropes = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "ropes")); + state.putBindOn(ropes); + } + if (!state.isGagged()) { + ItemStack gag = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "cloth_gag")); + state.putGagOn(gag); + } + if (!state.isBlindfolded()) { + ItemStack blindfold = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_blindfold")); + state.putBlindfoldOn(blindfold); + } + if (!state.hasCollar()) { + ItemStack collar = com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem.createStack(new net.minecraft.resources.ResourceLocation("tiedup", "classic_collar")); + if ( + context.getSource().getEntity() instanceof ServerPlayer executor + ) { + CollarHelper.addOwner(collar, executor); + } + state.putCollarOn(collar); + } + if (!state.hasEarplugs()) { + ItemStack earplugs = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_earplugs")); + state.putEarplugsOn(earplugs); + } + + // Capture target (this makes them a captive) + if (context.getSource().getEntity() instanceof ServerPlayer master) { + PlayerBindState masterState = PlayerBindState.getInstance(master); + if (masterState != null && masterState.getCaptorManager() != null) { + masterState.getCaptorManager().addCaptive(state); + } + } + + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been enslaved" + ), + true + ); + SystemMessageManager.sendEnslaved( + context.getSource().getEntity(), + targetPlayer + ); + + return 1; + } + + static int free(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (!state.isCaptive()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + " is not captured" + ) + ); + return 0; + } + + state.free(true); + + PacketSyncBindState statePacket = PacketSyncBindState.fromPlayer( + targetPlayer + ); + if (statePacket != null) { + ModNetwork.sendToPlayer(statePacket, targetPlayer); + } + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been freed from slavery" + ), + true + ); + SystemMessageManager.sendFreed(targetPlayer); + + return 1; + } + +} diff --git a/src/main/java/com/tiedup/remake/commands/subcommands/GagCommands.java b/src/main/java/com/tiedup/remake/commands/subcommands/GagCommands.java new file mode 100644 index 0000000..2f3a2ef --- /dev/null +++ b/src/main/java/com/tiedup/remake/commands/subcommands/GagCommands.java @@ -0,0 +1,140 @@ +package com.tiedup.remake.commands.subcommands; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.tiedup.remake.commands.CommandHelper; +import com.tiedup.remake.core.SystemMessageManager; +import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem; +import net.minecraft.resources.ResourceLocation; +import com.tiedup.remake.state.PlayerBindState; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; + +@SuppressWarnings("null") +public class GagCommands { + + public static void register(LiteralArgumentBuilder root) { + // /tiedup gag + root.then( + Commands.literal("gag") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(GagCommands::gag) + ) + ); + // /tiedup ungag + root.then( + Commands.literal("ungag") + .requires(CommandHelper.REQUIRES_OP) + .then( + Commands.argument( + "player", + EntityArgument.player() + ).executes(GagCommands::ungag) + ) + ); + } + + static int gag(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (state.isGagged()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + + " is already gagged" + ) + ); + return 0; + } + + ItemStack gag = DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "cloth_gag")); + state.putGagOn(gag); + + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + " has been gagged" + ), + true + ); + SystemMessageManager.sendGagged( + context.getSource().getEntity(), + targetPlayer + ); + + return 1; + } + + static int ungag(CommandContext context) + throws CommandSyntaxException { + ServerPlayer targetPlayer = EntityArgument.getPlayer(context, "player"); + PlayerBindState state = PlayerBindState.getInstance(targetPlayer); + + if (state == null) { + context + .getSource() + .sendFailure(Component.literal("Failed to get player state")); + return 0; + } + + if (!state.isGagged()) { + context + .getSource() + .sendFailure( + Component.literal( + targetPlayer.getName().getString() + " is not gagged" + ) + ); + return 0; + } + + state.takeGagOff(); + CommandHelper.syncPlayerState(targetPlayer, state); + + context + .getSource() + .sendSuccess( + () -> + Component.literal( + "\u00a7a" + + targetPlayer.getName().getString() + + "'s gag has been removed" + ), + true + ); + SystemMessageManager.sendToTarget( + context.getSource().getEntity(), + targetPlayer, + SystemMessageManager.MessageCategory.UNGAGGED + ); + + return 1; + } + +}