diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/bots/BotManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/bots/BotManager.java index 7fd3ee93..7d5ea500 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/bots/BotManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/bots/BotManager.java @@ -179,9 +179,13 @@ public class BotManager { } public void pickUpBot(Bot bot, Habbo habbo) { - HabboInfo receiverInfo = habbo == null ? Emulator.getGameEnvironment().getHabboManager().getHabboInfo(bot.getOwnerId()) : habbo.getHabboInfo(); - if (bot != null) { + HabboInfo receiverInfo = resolvePickupReceiver(bot, habbo); + Room botRoom = bot.getRoom(); + if (receiverInfo == null || botRoom == null) { + return; + } + BotPickUpEvent pickedUpEvent = new BotPickUpEvent(bot, habbo); Emulator.getPluginManager().fireEvent(pickedUpEvent); @@ -198,8 +202,8 @@ public class BotManager { return; } - bot.onPickUp(habbo, receiverInfo.getCurrentRoom()); - receiverInfo.getCurrentRoom().removeBot(bot); + bot.onPickUp(habbo, botRoom); + botRoom.removeBot(bot); bot.stopFollowingHabbo(); bot.setOwnerId(receiverInfo.getId()); bot.setOwnerName(receiverInfo.getUsername()); @@ -215,6 +219,14 @@ public class BotManager { } } + private HabboInfo resolvePickupReceiver(Bot bot, Habbo picker) { + if (picker != null && bot.getOwnerId() == picker.getHabboInfo().getId()) { + return picker.getHabboInfo(); + } + + return Emulator.getGameEnvironment().getHabboManager().getHabboInfo(bot.getOwnerId()); + } + public Bot loadBot(ResultSet set) { try { String type = set.getString("type"); diff --git a/Emulator/src/test/java/com/eu/habbo/habbohotel/bots/BotPickupOwnershipContractTest.java b/Emulator/src/test/java/com/eu/habbo/habbohotel/bots/BotPickupOwnershipContractTest.java new file mode 100644 index 00000000..43295c39 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/habbohotel/bots/BotPickupOwnershipContractTest.java @@ -0,0 +1,30 @@ +package com.eu.habbo.habbohotel.bots; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; + +class BotPickupOwnershipContractTest { + private static String source() throws Exception { + return Files.readString(Path.of("src/main/java/com/eu/habbo/habbohotel/bots/BotManager.java")); + } + + @Test + void roomOwnerPickupReturnsBotToOriginalOwner() throws Exception { + String source = source(); + + assertTrue(source.contains("HabboInfo receiverInfo = resolvePickupReceiver(bot, habbo);"), + "bot pickup should resolve the receiver without blindly using the picker"); + assertTrue(source.contains("private HabboInfo resolvePickupReceiver(Bot bot, Habbo picker)"), + "bot pickup receiver logic should be centralized"); + assertTrue(source.contains("return Emulator.getGameEnvironment().getHabboManager().getHabboInfo(bot.getOwnerId());"), + "when a room owner picks up someone else's bot, it should return to the original bot owner"); + assertTrue(source.contains("Room botRoom = bot.getRoom();"), + "pickup should remove the bot from the bot's current room, not the receiver's current room"); + assertTrue(source.contains("botRoom.removeBot(bot);"), + "bot removal should work even when the original owner is offline"); + } +}