package com.tiedup.remake.commands; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.tiedup.remake.bounty.Bounty; import com.tiedup.remake.bounty.BountyManager; import com.tiedup.remake.core.SettingsAccessor; import com.tiedup.remake.core.TiedUpMod; import com.tiedup.remake.state.IBondageState; import com.tiedup.remake.util.KidnappedHelper; import java.util.Optional; import net.minecraft.ChatFormatting; 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; /** * Command: /bounty * * * Creates a bounty on a target player using the held item as reward. * * Requirements: * - Must hold an item (the reward) * - Cannot put bounty on yourself * - Respects max bounties limit * - Cannot be tied up when creating bounty */ public class BountyCommand { public static void register( CommandDispatcher dispatcher ) { dispatcher.register(createBountyCommand()); TiedUpMod.LOGGER.info("Registered /bounty command"); } /** * Create the bounty command builder (for use as subcommand of /tiedup). * @return The command builder */ public static com.mojang.brigadier.builder.LiteralArgumentBuilder< CommandSourceStack > createBountyCommand() { return Commands.literal("bounty").then( Commands.argument("target", EntityArgument.player()).executes( BountyCommand::execute ) ); } private static int execute(CommandContext context) throws CommandSyntaxException { CommandSourceStack source = context.getSource(); // Must be a player Optional playerOpt = CommandHelper.getPlayerOrFail( source ); if (playerOpt.isEmpty()) return 0; ServerPlayer player = playerOpt.get(); ServerPlayer target = EntityArgument.getPlayer(context, "target"); // Cannot bounty yourself if (player.getUUID().equals(target.getUUID())) { source.sendFailure( Component.translatable( "command.tiedup.bounty.cannot_self" ).withStyle(ChatFormatting.RED) ); return 0; } // Check if player is tied up IBondageState playerState = KidnappedHelper.getKidnappedState(player); if (playerState != null && playerState.isTiedUp()) { source.sendFailure( Component.translatable( "command.tiedup.bounty.tied_up" ).withStyle(ChatFormatting.RED) ); return 0; } // Get bounty manager BountyManager manager = BountyManager.get(player.serverLevel()); // Check bounty limit if (!manager.canCreateBounty(player, player.serverLevel())) { int max = SettingsAccessor.getMaxBounties( player.serverLevel().getGameRules() ); source.sendFailure( Component.translatable( "command.tiedup.bounty.max_reached", max ).withStyle(ChatFormatting.RED) ); return 0; } // Must hold an item as reward ItemStack heldItem = player.getMainHandItem(); if (heldItem.isEmpty()) { source.sendFailure( Component.translatable( "command.tiedup.bounty.must_hold_item" ).withStyle(ChatFormatting.RED) ); return 0; } // Get bounty duration int duration = SettingsAccessor.getBountyDuration( player.serverLevel().getGameRules() ); // SECURITY FIX: Create reward with count=1 to prevent item duplication // Bug: If player held 64 diamonds, bounty would be 64 diamonds but only cost 1 ItemStack rewardItem = heldItem.copy(); rewardItem.setCount(1); // Create the bounty Bounty bounty = new Bounty( player.getUUID(), player.getName().getString(), target.getUUID(), target.getName().getString(), rewardItem, duration ); // Consume one item from the stack (not the entire stack!) player.getMainHandItem().shrink(1); // Add bounty manager.addBounty(bounty); // Notify player source.sendSuccess( () -> Component.translatable( "command.tiedup.bounty.created", target.getName().getString() ).withStyle(ChatFormatting.GREEN), false ); // Broadcast to all players player.server .getPlayerList() .broadcastSystemMessage( Component.translatable( "command.tiedup.bounty.broadcast", player.getName().getString(), target.getName().getString() ).withStyle(ChatFormatting.GOLD), false ); TiedUpMod.LOGGER.info( "[BOUNTY] {} created bounty on {} with reward {}", player.getName().getString(), target.getName().getString(), bounty.getRewardDescription() ); return 1; } }