Phase 1 (state): PlayerBindState, PlayerCaptorManager, PlayerEquipment, PlayerDataRetrieval, PlayerLifecycle, PlayerShockCollar, StruggleAccessory Phase 2 (client): AnimationTickHandler, NpcAnimationTickHandler, 5 render handlers, DamselModel, 3 client mixins, SelfBondageInputHandler, SlaveManagementScreen, ActionPanel, SlaveEntryWidget, ModKeybindings Phase 3 (entities): 28 entity/AI files migrated to CollarHelper, BindModeHelper, PoseTypeHelper, createStack() Phase 4 (network): PacketSlaveAction, PacketMasterEquip, PacketAssignCellToCollar, PacketNpcCommand, PacketFurnitureForcemount Phase 5 (events): RestraintTaskTickHandler, PetPlayRestrictionHandler, PlayerEnslavementHandler, ChatEventHandler, LaborAttackPunishmentHandler Phase 6 (commands): BondageSubCommand, CollarCommand, NPCCommand, KidnapSetCommand Phase 7 (compat): MCAKidnappedAdapter, MCA mixins Phase 8 (misc): GagTalkManager, PetRequestManager, HangingCagePiece, BondageItemBlockEntity, TrappedChestBlockEntity, DispenserBehaviors, BondageItemLoaderUtility, RestraintApplicator, StruggleSessionManager, MovementStyleResolver, CampLifecycleManager Some files retain dual V1/V2 checks (instanceof V1 || V2Helper) for coexistence — V1-only branches removed in Branch D.
1208 lines
38 KiB
Java
1208 lines
38 KiB
Java
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
|
|
*/
|
|
@SuppressWarnings("null")
|
|
public class BondageSubCommand {
|
|
|
|
public static void register(
|
|
LiteralArgumentBuilder<CommandSourceStack> root
|
|
) {
|
|
// /tiedup tie <player>
|
|
root.then(
|
|
Commands.literal("tie")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::tie)
|
|
)
|
|
);
|
|
// /tiedup untie <player>
|
|
root.then(
|
|
Commands.literal("untie")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::untie)
|
|
)
|
|
);
|
|
// /tiedup gag <player>
|
|
root.then(
|
|
Commands.literal("gag")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::gag)
|
|
)
|
|
);
|
|
// /tiedup ungag <player>
|
|
root.then(
|
|
Commands.literal("ungag")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::ungag)
|
|
)
|
|
);
|
|
// /tiedup blindfold <player>
|
|
root.then(
|
|
Commands.literal("blindfold")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::blindfold)
|
|
)
|
|
);
|
|
// /tiedup unblind <player>
|
|
root.then(
|
|
Commands.literal("unblind")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::unblind)
|
|
)
|
|
);
|
|
// /tiedup collar <player>
|
|
root.then(
|
|
Commands.literal("collar")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::collar)
|
|
)
|
|
);
|
|
// /tiedup takecollar <player>
|
|
root.then(
|
|
Commands.literal("takecollar")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::takecollar)
|
|
)
|
|
);
|
|
// /tiedup takeearplugs <player>
|
|
root.then(
|
|
Commands.literal("takeearplugs")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::takeearplugs)
|
|
)
|
|
);
|
|
// /tiedup putearplugs <player>
|
|
root.then(
|
|
Commands.literal("putearplugs")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::putearplugs)
|
|
)
|
|
);
|
|
// /tiedup takeclothes <player>
|
|
root.then(
|
|
Commands.literal("takeclothes")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::takeclothes)
|
|
)
|
|
);
|
|
// /tiedup putclothes <player>
|
|
root.then(
|
|
Commands.literal("putclothes")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::putclothes)
|
|
)
|
|
);
|
|
// /tiedup fullyrestrain <player>
|
|
root.then(
|
|
Commands.literal("fullyrestrain")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::fullyrestrain)
|
|
)
|
|
);
|
|
// /tiedup enslave <player>
|
|
root.then(
|
|
Commands.literal("enslave")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::enslave)
|
|
)
|
|
);
|
|
// /tiedup free <player>
|
|
root.then(
|
|
Commands.literal("free")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(BondageSubCommand::free)
|
|
)
|
|
);
|
|
// /tiedup adjust <player> <type:gag|blindfold|all> <value>
|
|
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 <player>
|
|
*
|
|
* Forcefully tie a player with ropes (default bind).
|
|
* Uses ItemRopes from ModItems.
|
|
*/
|
|
private static int tie(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Forcefully untie a player, removing ALL bondage equipment.
|
|
*/
|
|
private static int untie(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Forcefully gag a player with cloth gag (default).
|
|
*/
|
|
private static int gag(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Forcefully blindfold a player with classic blindfold (default).
|
|
*/
|
|
private static int blindfold(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* 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<CommandSourceStack> 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 = new ItemStack(ModItems.CLASSIC_COLLAR.get());
|
|
|
|
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 <player>
|
|
*
|
|
* Free a player from slavery (removes master relationship).
|
|
* Does NOT remove collar or other equipment.
|
|
*/
|
|
private static int free(CommandContext<CommandSourceStack> 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 <player> <type> <value>
|
|
*
|
|
* 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<CommandSourceStack> 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 <player>
|
|
*
|
|
* Remove gag from a player.
|
|
*/
|
|
private static int ungag(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Remove blindfold from a player.
|
|
*/
|
|
private static int unblind(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Remove collar from a player.
|
|
*/
|
|
private static int takecollar(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Remove earplugs from a player.
|
|
*/
|
|
private static int takeearplugs(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Remove clothes from a player.
|
|
*/
|
|
private static int takeclothes(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Put clothes on a player.
|
|
*/
|
|
private static int putclothes(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Put earplugs on a player.
|
|
*/
|
|
private static int putearplugs(CommandContext<CommandSourceStack> 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 <player>
|
|
*
|
|
* Apply full bondage: bind + gag + blindfold + collar + earplugs
|
|
*/
|
|
private static int fullyrestrain(CommandContext<CommandSourceStack> 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 = new ItemStack(ModItems.CLASSIC_COLLAR.get());
|
|
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 <player>
|
|
*
|
|
* Fully restrain and enslave a player.
|
|
* The command executor becomes the master.
|
|
*/
|
|
private static int enslave(CommandContext<CommandSourceStack> 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 = new ItemStack(ModItems.CLASSIC_COLLAR.get());
|
|
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;
|
|
}
|
|
}
|