Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/java/dansplugins/wildpets/WildPets.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ private void initializeCommandService() {
new InfoCommand(ephemeralData, configService, petRecordRepository), new ListCommand(petListRepository), new LocateCommand(ephemeralData),
new LockCommand(ephemeralData), new RenameCommand(ephemeralData, petListRepository, petRecordRepository, configService),
new SelectCommand(configService, ephemeralData, petListRepository), new SetFreeCommand(ephemeralData, petListRepository), new StatsCommand(petListRepository),
new TameCommand(ephemeralData), new UnlockCommand(ephemeralData), new WanderCommand(ephemeralData),
new TameCommand(ephemeralData), new TradeCommand(ephemeralData, petListRepository, petRecordRepository), new UnlockCommand(ephemeralData), new WanderCommand(ephemeralData),
new StayCommand(ephemeralData), new GatherCommand(petListRepository)
));
commandService.initialize(commands, "That command wasn't found.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public boolean execute(CommandSender sender) {
player.sendMessage(ChatColor.AQUA + "/wp lock - Lock your pet.");
player.sendMessage(ChatColor.AQUA + "/wp unlock - Unlock your pet.");
player.sendMessage(ChatColor.AQUA + "/wp setfree - Set your pet free.");
player.sendMessage(ChatColor.AQUA + "/wp trade (playerName) - Trade selected pet to another player.");
player.sendMessage(ChatColor.AQUA + "/wp gather - Gather your pets in one place.");
player.sendMessage(ChatColor.AQUA + "/wp config - View or set config options.");
return true;
Expand Down
93 changes: 93 additions & 0 deletions src/main/java/dansplugins/wildpets/commands/TradeCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package dansplugins.wildpets.commands;

import dansplugins.wildpets.data.EphemeralData;
import dansplugins.wildpets.exceptions.PetRecordNotFoundException;
import dansplugins.wildpets.pet.Pet;
import dansplugins.wildpets.pet.list.PetListRepository;
import dansplugins.wildpets.pet.record.PetRecord;
import dansplugins.wildpets.pet.record.PetRecordRepository;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

import java.util.ArrayList;
import java.util.Arrays;

/**
* @author Daniel McCoy Stephenson
* Command to transfer a selected pet to another online player.
*/
public class TradeCommand extends AbstractPluginCommand {
private final EphemeralData ephemeralData;
private final PetListRepository petListRepository;
private final PetRecordRepository petRecordRepository;

public TradeCommand(EphemeralData ephemeralData, PetListRepository petListRepository, PetRecordRepository petRecordRepository) {
super(new ArrayList<>(Arrays.asList("trade")), new ArrayList<>(Arrays.asList("wp.trade")));
this.ephemeralData = ephemeralData;
this.petListRepository = petListRepository;
this.petRecordRepository = petRecordRepository;
}

@Override
public boolean execute(CommandSender sender) {
sender.sendMessage(ChatColor.RED + "Usage: /wp trade (playerName)");
return false;
}

@Override
public boolean execute(CommandSender sender, String[] args) {
if (!(sender instanceof Player)) {
return false;
}

Player player = (Player) sender;

Pet pet = ephemeralData.getPetSelectionForPlayer(player.getUniqueId());
if (pet == null) {
player.sendMessage(ChatColor.RED + "No pet selected. Use /wp select first.");
return false;
}

if (args.length < 1) {
return execute(sender);
}

Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The missing-argument check happens after the selected-pet check, so /wp trade with no args can report "No pet selected" instead of showing usage. For consistency with commands like RenameCommand, validate args.length first (show usage), then validate selection/transfer prerequisites.

Suggested change
Pet pet = ephemeralData.getPetSelectionForPlayer(player.getUniqueId());
if (pet == null) {
player.sendMessage(ChatColor.RED + "No pet selected. Use /wp select first.");
return false;
}
if (args.length < 1) {
return execute(sender);
}
if (args.length < 1) {
return execute(sender);
}
Pet pet = ephemeralData.getPetSelectionForPlayer(player.getUniqueId());
if (pet == null) {
player.sendMessage(ChatColor.RED + "No pet selected. Use /wp select first.");
return false;
}

Copilot uses AI. Check for mistakes.
String targetName = args[0];
Player targetPlayer = Bukkit.getPlayer(targetName);

if (targetPlayer == null) {
player.sendMessage(ChatColor.RED + "That player is not online.");
return false;
Comment on lines +58 to +63
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bukkit.getPlayer(String) performs partial name matching and can return the wrong player if multiple online names share a prefix. For a trade/ownership transfer, use Bukkit.getPlayerExact(targetName) (or otherwise disambiguate) to avoid transferring a pet to an unintended player.

Copilot uses AI. Check for mistakes.
}

if (targetPlayer.getUniqueId().equals(player.getUniqueId())) {
player.sendMessage(ChatColor.RED + "You cannot trade a pet to yourself.");
return false;
}

String petName = pet.getName();

boolean success = petListRepository.transferPet(pet, targetPlayer.getUniqueId());
if (!success) {
player.sendMessage(ChatColor.RED + "Failed to transfer pet.");
return false;
}

// Update pet record
try {
PetRecord petRecord = petRecordRepository.getPetRecord(pet.getUniqueID());
petRecord.setOwnerUUID(targetPlayer.getUniqueId());
} catch (PetRecordNotFoundException e) {
petRecordRepository.addPetRecord(pet);
}

ephemeralData.clearPetSelectionForPlayer(player.getUniqueId());

player.sendMessage(ChatColor.GREEN + petName + " has been traded to " + targetPlayer.getName() + ".");
targetPlayer.sendMessage(ChatColor.GREEN + player.getName() + " has traded " + petName + " to you.");
return true;
}
}
19 changes: 19 additions & 0 deletions src/main/java/dansplugins/wildpets/pet/list/PetListRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,25 @@ public boolean removePet(Pet petToRemove) {
return getPetList(petToRemove.getOwnerUUID()).removePet(petToRemove);
}

public boolean transferPet(Pet pet, UUID newOwnerUUID) {
PetList oldList = getPetList(pet.getOwnerUUID());
if (oldList == null || !oldList.getPets().remove(pet)) {
Comment on lines +53 to +55
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pet exposes getOwnerUUID(), but this new code calls pet.getOwnerUUID() (missing UUID). This won't compile and will prevent the plugin from building. Update the call to use the correct method name.

Copilot uses AI. Check for mistakes.
return false;
}

PetList newList = getPetList(newOwnerUUID);
if (newList == null) {
createPetListForPlayer(newOwnerUUID);
newList = getPetList(newOwnerUUID);
}

pet.setOwnerUUID(newOwnerUUID);
pet.removeFromAccessList(oldList.getOwnerUUID());
pet.addToAccessList(newOwnerUUID);
newList.addPet(pet);
return true;
Comment on lines +59 to +76
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transferPet allows bypassing the configured petLimit (currently only enforced during taming). A player can trade pets to someone who is already at the limit, exceeding the cap. Add a limit check against configService.getInt("petLimit") before adding to the recipient list (and return false with a meaningful failure path).

Copilot uses AI. Check for mistakes.
}

public Pet getPet(Entity entity) {
for (PetList petList : getPetLists()) {
Pet pet = petList.getPet(entity.getUniqueId());
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,7 @@ permissions:
default: true
wp.gather:
default: true
wp.trade:
default: true
wp.config:
default: op