diff --git a/pom.xml b/pom.xml index 1c7ac8da10..ea27a32ed1 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 cosmic-maplestory @@ -52,7 +53,8 @@ 3.2.5 3.4.1 - 3.7.1 + 3.7.1 + 2.0.13 @@ -180,6 +182,12 @@ ${mockito.version} test + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + diff --git a/src/main/java/client/Character.java b/src/main/java/client/Character.java index c90d31480c..0bc5926a02 100644 --- a/src/main/java/client/Character.java +++ b/src/main/java/client/Character.java @@ -2068,7 +2068,7 @@ public class Character extends AbstractCharacterObject { this.getCashShop().gainCash(1, nxGain); if (YamlConfig.config.server.USE_ANNOUNCE_NX_COUPON_LOOT) { - showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(1) + " NX)", 300); + showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(CashShop.NX_CREDIT) + " NX)", 300); } this.getMap().pickItemDrop(pickupPacket, mapitem); @@ -2120,7 +2120,7 @@ public class Character extends AbstractCharacterObject { this.getCashShop().gainCash(1, nxGain); if (YamlConfig.config.server.USE_ANNOUNCE_NX_COUPON_LOOT) { - showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(1) + " NX)", 300); + showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(CashShop.NX_CREDIT) + " NX)", 300); } } else if (applyConsumeOnPickup(mItem.getItemId())) { } else if (InventoryManipulator.addFromDrop(client, mItem, true)) { diff --git a/src/main/java/net/packet/ByteBufInPacket.java b/src/main/java/net/packet/ByteBufInPacket.java index e79326f7c6..25b139629c 100644 --- a/src/main/java/net/packet/ByteBufInPacket.java +++ b/src/main/java/net/packet/ByteBufInPacket.java @@ -82,6 +82,11 @@ public class ByteBufInPacket implements InPacket { return byteBuf.readerIndex(); } + @Override + public boolean equals(Object o) { + return o instanceof ByteBufInPacket other && byteBuf.equals(other.byteBuf); + } + @Override public String toString() { final int readerIndex = byteBuf.readerIndex(); diff --git a/src/main/java/net/packet/ByteBufOutPacket.java b/src/main/java/net/packet/ByteBufOutPacket.java index ce289603be..376253d280 100644 --- a/src/main/java/net/packet/ByteBufOutPacket.java +++ b/src/main/java/net/packet/ByteBufOutPacket.java @@ -91,4 +91,9 @@ public class ByteBufOutPacket implements OutPacket { public void skip(int numberOfBytes) { writeBytes(new byte[numberOfBytes]); } + + @Override + public boolean equals(Object o) { + return o instanceof ByteBufOutPacket other && byteBuf.equals(other.byteBuf); + } } diff --git a/src/main/java/net/server/channel/handlers/CashOperationHandler.java b/src/main/java/net/server/channel/handlers/CashOperationHandler.java index 077c654a5c..86efa554b0 100644 --- a/src/main/java/net/server/channel/handlers/CashOperationHandler.java +++ b/src/main/java/net/server/channel/handlers/CashOperationHandler.java @@ -116,7 +116,7 @@ public final class CashOperationHandler extends AbstractPacketHandler { CashItem cItem = CashItemFactory.getItem(p.readInt()); Map recipient = Character.getCharacterFromDatabase(p.readString()); String message = p.readString(); - if (!canBuy(chr, cItem, cs.getCash(4)) || message.length() < 1 || message.length() > 73) { + if (!canBuy(chr, cItem, cs.getCash(CashShop.NX_PREPAID)) || message.isEmpty() || message.length() > 73) { c.enableCSActions(); return; } @@ -405,7 +405,7 @@ public final class CashOperationHandler extends AbstractPacketHandler { c.sendPacket(PacketCreator.showCash(c.getPlayer())); } else if (action == 0x2E) { //name change CashItem cItem = CashItemFactory.getItem(p.readInt()); - if (cItem == null || !canBuy(chr, cItem, cs.getCash(4))) { + if (cItem == null || !canBuy(chr, cItem, cs.getCash(CashShop.NX_PREPAID))) { c.sendPacket(PacketCreator.showCashShopMessage((byte) 0)); c.enableCSActions(); return; @@ -434,7 +434,7 @@ public final class CashOperationHandler extends AbstractPacketHandler { c.enableCSActions(); } else if (action == 0x31) { //world transfer CashItem cItem = CashItemFactory.getItem(p.readInt()); - if (cItem == null || !canBuy(chr, cItem, cs.getCash(4))) { + if (cItem == null || !canBuy(chr, cItem, cs.getCash(CashShop.NX_PREPAID))) { c.sendPacket(PacketCreator.showCashShopMessage((byte) 0)); c.enableCSActions(); return; diff --git a/src/main/java/net/server/channel/handlers/CashShopSurpriseHandler.java b/src/main/java/net/server/channel/handlers/CashShopSurpriseHandler.java index 618c3f7d31..9fff47092f 100644 --- a/src/main/java/net/server/channel/handlers/CashShopSurpriseHandler.java +++ b/src/main/java/net/server/channel/handlers/CashShopSurpriseHandler.java @@ -24,26 +24,34 @@ import client.inventory.Item; import net.AbstractPacketHandler; import net.packet.InPacket; import server.CashShop; +import server.CashShop.CashShopSurpriseResult; import tools.PacketCreator; -import tools.Pair; + +import java.util.Optional; /** * @author RonanLana + * @author Ponk */ public class CashShopSurpriseHandler extends AbstractPacketHandler { + @Override public final void handlePacket(InPacket p, Client c) { CashShop cs = c.getPlayer().getCashShop(); - - if (cs.isOpened()) { - Pair cssResult = cs.openCashShopSurprise(); - - if (cssResult != null) { - Item cssItem = cssResult.getLeft(), cssBox = cssResult.getRight(); - c.sendPacket(PacketCreator.onCashGachaponOpenSuccess(c.getAccID(), cssBox.getCashId(), cssBox.getQuantity(), cssItem, cssItem.getItemId(), cssItem.getQuantity(), true)); - } else { - c.sendPacket(PacketCreator.onCashItemGachaponOpenFailed()); - } + if (!cs.isOpened()) { + return; } + + long cashId = p.readLong(); + Optional result = cs.openCashShopSurprise(cashId); + if (result.isEmpty()) { + c.sendPacket(PacketCreator.onCashItemGachaponOpenFailed()); + return; + } + + Item usedCashShopSurprise = result.get().usedCashShopSurprise(); + Item reward = result.get().reward(); + c.sendPacket(PacketCreator.onCashGachaponOpenSuccess(c.getAccID(), usedCashShopSurprise.getCashId(), + usedCashShopSurprise.getQuantity(), reward, reward.getItemId(), reward.getQuantity(), true)); } } diff --git a/src/main/java/net/server/channel/handlers/MTSHandler.java b/src/main/java/net/server/channel/handlers/MTSHandler.java index bc5d3dac74..4634c2bef3 100644 --- a/src/main/java/net/server/channel/handlers/MTSHandler.java +++ b/src/main/java/net/server/channel/handlers/MTSHandler.java @@ -35,6 +35,7 @@ import net.server.Server; import net.server.channel.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import server.CashShop; import server.ItemInformationProvider; import server.MTSItemInfo; import tools.DatabaseConnection; @@ -402,7 +403,7 @@ public final class MTSHandler extends AbstractPacketHandler { ResultSet rs = ps.executeQuery(); if (rs.next()) { int price = rs.getInt("price") + 100 + (int) (rs.getInt("price") * 0.1); // taxes - if (c.getPlayer().getCashShop().getCash(4) >= price) { // FIX + if (c.getPlayer().getCashShop().getCash(CashShop.NX_PREPAID) >= price) { // FIX boolean alwaysnull = true; for (Channel cserv : Server.getInstance().getAllChannels()) { Character victim = cserv.getPlayerStorage().getCharacterById(rs.getInt("seller")); @@ -459,11 +460,11 @@ public final class MTSHandler extends AbstractPacketHandler { ResultSet rs = ps.executeQuery(); if (rs.next()) { int price = rs.getInt("price") + 100 + (int) (rs.getInt("price") * 0.1); - if (c.getPlayer().getCashShop().getCash(4) >= price) { + if (c.getPlayer().getCashShop().getCash(CashShop.NX_PREPAID) >= price) { for (Channel cserv : Server.getInstance().getAllChannels()) { Character victim = cserv.getPlayerStorage().getCharacterById(rs.getInt("seller")); if (victim != null) { - victim.getCashShop().gainCash(4, rs.getInt("price")); + victim.getCashShop().gainCash(CashShop.NX_PREPAID, rs.getInt("price")); } else { try (PreparedStatement pse = con.prepareStatement("SELECT accountid FROM characters WHERE id = ?")) { pse.setInt(1, rs.getInt("seller")); diff --git a/src/main/java/server/CashShop.java b/src/main/java/server/CashShop.java index d7e0ec1e28..498fe12fdc 100644 --- a/src/main/java/server/CashShop.java +++ b/src/main/java/server/CashShop.java @@ -29,6 +29,7 @@ import client.inventory.Pet; import config.YamlConfig; import constants.id.ItemId; import constants.inventory.ItemConstants; +import net.jcip.annotations.GuardedBy; import net.server.Server; import provider.Data; import provider.DataProvider; @@ -36,7 +37,6 @@ import provider.DataProviderFactory; import provider.DataTool; import provider.wz.WZFiles; import tools.DatabaseConnection; -import tools.PacketCreator; import tools.Pair; import java.sql.Connection; @@ -48,6 +48,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -56,8 +57,74 @@ import static java.util.concurrent.TimeUnit.HOURS; /* * @author Flav + * @author Ponk */ public class CashShop { + public static final int NX_CREDIT = 1; + public static final int MAPLE_POINT = 2; + public static final int NX_PREPAID = 4; + + private final int accountId; + private final int characterId; + private int nxCredit; + private int maplePoint; + private int nxPrepaid; + private boolean opened; + private ItemFactory factory; + private final List inventory = new ArrayList<>(); + private final List wishList = new ArrayList<>(); + private int notes = 0; + private final Lock lock = new ReentrantLock(); + + public CashShop(int accountId, int characterId, int jobType) throws SQLException { + this.accountId = accountId; + this.characterId = characterId; + + if (!YamlConfig.config.server.USE_JOINT_CASHSHOP_INVENTORY) { + switch (jobType) { + case 0: + factory = ItemFactory.CASH_EXPLORER; + break; + case 1: + factory = ItemFactory.CASH_CYGNUS; + break; + case 2: + factory = ItemFactory.CASH_ARAN; + break; + } + } else { + factory = ItemFactory.CASH_OVERALL; + } + + try (Connection con = DatabaseConnection.getConnection()) { + try (PreparedStatement ps = con.prepareStatement("SELECT `nxCredit`, `maplePoint`, `nxPrepaid` FROM `accounts` WHERE `id` = ?")) { + ps.setInt(1, accountId); + + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + this.nxCredit = rs.getInt("nxCredit"); + this.maplePoint = rs.getInt("maplePoint"); + this.nxPrepaid = rs.getInt("nxPrepaid"); + } + } + } + + for (Pair item : factory.loadItems(accountId, false)) { + inventory.add(item.getLeft()); + } + + try (PreparedStatement ps = con.prepareStatement("SELECT `sn` FROM `wishlists` WHERE `charid` = ?")) { + ps.setInt(1, characterId); + + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + wishList.add(rs.getInt("sn")); + } + } + } + } + } + public static class CashItem { private final int sn; @@ -113,19 +180,20 @@ public class CashShop { if (ItemConstants.EXPIRING_ITEMS) { if (period == 1) { switch (itemId) { - case ItemId.DROP_COUPON_2X_4H, ItemId.EXP_COUPON_2X_4H: // 4 Hour 2X coupons, the period is 1, but we don't want them to last a day. - item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(4)); + case ItemId.DROP_COUPON_2X_4H, + ItemId.EXP_COUPON_2X_4H: // 4 Hour 2X coupons, the period is 1, but we don't want them to last a day. + item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(4)); /* } else if(itemId == 5211047 || itemId == 5360014) { // 3 Hour 2X coupons, unused as of now item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(3)); */ - break; - case ItemId.EXP_COUPON_3X_2H: - item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(2)); - break; - default: - item.setExpiration(Server.getInstance().getCurrentTime() + DAYS.toMillis(1)); - break; + break; + case ItemId.EXP_COUPON_3X_2H: + item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(2)); + break; + default: + item.setExpiration(Server.getInstance().getCurrentTime() + DAYS.toMillis(1)); + break; } } else { item.setExpiration(Server.getInstance().getCurrentTime() + DAYS.toMillis(period)); @@ -259,91 +327,24 @@ public class CashShop { } } - private final int accountId; - private final int characterId; - private int nxCredit; - private int maplePoint; - private int nxPrepaid; - private boolean opened; - private ItemFactory factory; - private final List inventory = new ArrayList<>(); - private final List wishList = new ArrayList<>(); - private int notes = 0; - private final Lock lock = new ReentrantLock(); - - public CashShop(int accountId, int characterId, int jobType) throws SQLException { - this.accountId = accountId; - this.characterId = characterId; - - if (!YamlConfig.config.server.USE_JOINT_CASHSHOP_INVENTORY) { - switch (jobType) { - case 0: - factory = ItemFactory.CASH_EXPLORER; - break; - case 1: - factory = ItemFactory.CASH_CYGNUS; - break; - case 2: - factory = ItemFactory.CASH_ARAN; - break; - } - } else { - factory = ItemFactory.CASH_OVERALL; - } - - try (Connection con = DatabaseConnection.getConnection()) { - try (PreparedStatement ps = con.prepareStatement("SELECT `nxCredit`, `maplePoint`, `nxPrepaid` FROM `accounts` WHERE `id` = ?")) { - ps.setInt(1, accountId); - - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - this.nxCredit = rs.getInt("nxCredit"); - this.maplePoint = rs.getInt("maplePoint"); - this.nxPrepaid = rs.getInt("nxPrepaid"); - } - } - } - - for (Pair item : factory.loadItems(accountId, false)) { - inventory.add(item.getLeft()); - } - - try (PreparedStatement ps = con.prepareStatement("SELECT `sn` FROM `wishlists` WHERE `charid` = ?")) { - ps.setInt(1, characterId); - - try (ResultSet rs = ps.executeQuery()) { - while (rs.next()) { - wishList.add(rs.getInt("sn")); - } - } - } - } + public record CashShopSurpriseResult(Item usedCashShopSurprise, Item reward) { } public int getCash(int type) { - switch (type) { - case 1: - return nxCredit; - case 2: - return maplePoint; - case 4: - return nxPrepaid; - } + return switch (type) { + case NX_CREDIT -> nxCredit; + case MAPLE_POINT -> maplePoint; + case NX_PREPAID -> nxPrepaid; + default -> 0; + }; - return 0; } public void gainCash(int type, int cash) { switch (type) { - case 1: - nxCredit += cash; - break; - case 2: - maplePoint += cash; - break; - case 4: - nxPrepaid += cash; - break; + case NX_CREDIT -> nxCredit += cash; + case MAPLE_POINT -> maplePoint += cash; + case NX_PREPAID -> nxPrepaid += cash; } } @@ -408,17 +409,6 @@ public class CashShop { } } - public int getItemsSize() { - int size = 0; - lock.lock(); - try { - size = inventory.size(); - } finally { - lock.unlock(); - } - return size; - } - public List getWishList() { return wishList; } @@ -537,47 +527,57 @@ public class CashShop { } } - private Item getCashShopItemByItemid(int itemid) { + public Optional openCashShopSurprise(long cashId) { lock.lock(); try { - for (Item it : inventory) { - if (it.getItemId() == itemid) { - return it; - } + Optional maybeCashShopSurprise = getItemByCashId(cashId); + if (maybeCashShopSurprise.isEmpty() || + maybeCashShopSurprise.get().getItemId() != ItemId.CASH_SHOP_SURPRISE) { + return Optional.empty(); } + + Item cashShopSurprise = maybeCashShopSurprise.get(); + if (cashShopSurprise.getQuantity() <= 0) { + return Optional.empty(); + } + + if (getItemsSize() >= 100) { + return Optional.empty(); + } + + CashItem cashItemReward = CashItemFactory.getRandomCashItem(); + if (cashItemReward == null) { + return Optional.empty(); + } + + short newQuantity = (short) (cashShopSurprise.getQuantity() - 1); + cashShopSurprise.setQuantity(newQuantity); + if (newQuantity <= 0) { + removeFromInventory(cashShopSurprise); + } + + Item itemReward = cashItemReward.toItem(); + addToInventory(itemReward); + + return Optional.of(new CashShopSurpriseResult(cashShopSurprise, itemReward)); } finally { lock.unlock(); } - - return null; } - public synchronized Pair openCashShopSurprise() { - Item css = getCashShopItemByItemid(ItemId.CASH_SHOP_SURPRISE); + @GuardedBy("lock") + private Optional getItemByCashId(long cashId) { + return inventory.stream() + .filter(item -> item.getCashId() == cashId) + .findAny(); + } - if (css != null) { - if (getItemsSize() >= 100) { - return null; - } - - CashItem cItem = CashItemFactory.getRandomCashItem(); - - if (cItem != null) { - if (css.getQuantity() > 1) { - css.setQuantity((short) (css.getQuantity() - 1)); - } else { - removeFromInventory(css); - } - - Item item = cItem.toItem(); - addToInventory(item); - - return new Pair<>(item, css); - } else { - return null; - } - } else { - return null; + public int getItemsSize() { + lock.lock(); + try { + return inventory.size(); + } finally { + lock.unlock(); } } diff --git a/src/main/java/tools/PacketCreator.java b/src/main/java/tools/PacketCreator.java index 7471e903b7..a6cf3cf6eb 100644 --- a/src/main/java/tools/PacketCreator.java +++ b/src/main/java/tools/PacketCreator.java @@ -77,6 +77,7 @@ import net.server.world.Party; import net.server.world.PartyCharacter; import net.server.world.PartyOperation; import net.server.world.World; +import server.CashShop; import server.CashShop.CashItem; import server.CashShop.CashItemFactory; import server.CashShop.SpecialCashItem; @@ -5580,8 +5581,8 @@ public class PacketCreator { public static Packet showMTSCash(Character chr) { final OutPacket p = OutPacket.create(SendOpcode.MTS_OPERATION2); - p.writeInt(chr.getCashShop().getCash(4)); - p.writeInt(chr.getCashShop().getCash(2)); + p.writeInt(chr.getCashShop().getCash(CashShop.NX_PREPAID)); + p.writeInt(chr.getCashShop().getCash(CashShop.MAPLE_POINT)); return p; } @@ -5689,9 +5690,9 @@ public class PacketCreator { public static Packet showCash(Character mc) { final OutPacket p = OutPacket.create(SendOpcode.QUERY_CASH_RESULT); - p.writeInt(mc.getCashShop().getCash(1)); - p.writeInt(mc.getCashShop().getCash(2)); - p.writeInt(mc.getCashShop().getCash(4)); + p.writeInt(mc.getCashShop().getCash(CashShop.NX_CREDIT)); + p.writeInt(mc.getCashShop().getCash(CashShop.MAPLE_POINT)); + p.writeInt(mc.getCashShop().getCash(CashShop.NX_PREPAID)); return p; } @@ -6479,14 +6480,15 @@ public class PacketCreator { return p; } - public static Packet onCashGachaponOpenSuccess(int accountid, long sn, int remainingBoxes, Item item, int itemid, int nSelectedItemCount, boolean bJackpot) { + public static Packet onCashGachaponOpenSuccess(int accountid, long boxCashId, int remainingBoxes, Item reward, + int rewardItemId, int rewardQuantity, boolean bJackpot) { OutPacket p = OutPacket.create(SendOpcode.CASHSHOP_CASH_ITEM_GACHAPON_RESULT); p.writeByte(0xE5); // subopcode thanks to Ubaware - p.writeLong(sn);// sn of the box used + p.writeLong(boxCashId); p.writeInt(remainingBoxes); - addCashItemInformation(p, item, accountid); - p.writeInt(itemid);// the itemid of the liSN? - p.writeByte(nSelectedItemCount);// the total count now? o.O + addCashItemInformation(p, reward, accountid); + p.writeInt(rewardItemId); + p.writeByte(rewardQuantity); // nSelectedItemCount p.writeBool(bJackpot);// "CashGachaponJackpot" return p; } diff --git a/src/test/java/net/packet/ByteBufInPacketTest.java b/src/test/java/net/packet/ByteBufInPacketTest.java index 6837ecfe1c..34b87e89b8 100644 --- a/src/test/java/net/packet/ByteBufInPacketTest.java +++ b/src/test/java/net/packet/ByteBufInPacketTest.java @@ -235,4 +235,12 @@ class ByteBufInPacketTest { assertEquals(initial.length(), afterReadingOpcode.length()); } -} \ No newline at end of file + + @Test + void equalsShouldCompareBytes() { + ByteBufInPacket packet1 = new ByteBufInPacket(Unpooled.wrappedBuffer(new byte[]{ 11, 22, 33, 44 })); + ByteBufInPacket packet2 = new ByteBufInPacket(Unpooled.wrappedBuffer(new byte[]{ 11, 22, 33, 44 })); + + assertEquals(packet1, packet2); + } +} diff --git a/src/test/java/net/packet/ByteBufOutPacketTest.java b/src/test/java/net/packet/ByteBufOutPacketTest.java index d3f2892f99..1b54a5c32d 100644 --- a/src/test/java/net/packet/ByteBufOutPacketTest.java +++ b/src/test/java/net/packet/ByteBufOutPacketTest.java @@ -203,4 +203,14 @@ class ByteBufOutPacketTest { assertEquals(0, wrapped.readByte()); assertEquals(secondWrittenByte, wrapped.readByte()); } -} \ No newline at end of file + + @Test + void equalsShouldCompareBytes() { + ByteBufOutPacket packet1 = new ByteBufOutPacket(); + packet1.writeBytes(new byte[] { 55, 66, 77, 88 }); + ByteBufOutPacket packet2 = new ByteBufOutPacket(); + packet2.writeBytes(new byte[] { 55, 66, 77, 88 }); + + assertEquals(packet1, packet2); + } +} diff --git a/src/test/java/net/server/channel/handlers/CashShopSurpriseHandlerTest.java b/src/test/java/net/server/channel/handlers/CashShopSurpriseHandlerTest.java new file mode 100644 index 0000000000..71d0246ab1 --- /dev/null +++ b/src/test/java/net/server/channel/handlers/CashShopSurpriseHandlerTest.java @@ -0,0 +1,72 @@ +package net.server.channel.handlers; + +import client.inventory.Item; +import constants.id.ItemId; +import net.packet.InPacket; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import server.CashShop; +import testutil.HandlerTest; +import testutil.Items; +import testutil.Packets; +import tools.PacketCreator; + +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class CashShopSurpriseHandlerTest extends HandlerTest { + private final CashShopSurpriseHandler handler = new CashShopSurpriseHandler(); + + @Mock + private CashShop cashShop; + + @BeforeEach + void prepareCashShop() { + when(chr.getCashShop()).thenReturn(cashShop); + } + + private InPacket useCashShopSurprisePacket(long cashId) { + return Packets.buildInPacket(out -> out.writeLong(cashId)); + } + + @Test + void shouldDoNothingWhenCsIsNotOpened() { + when(cashShop.isOpened()).thenReturn(false); + + handler.handlePacket(useCashShopSurprisePacket(123), client); + + verify(cashShop, never()).openCashShopSurprise(anyLong()); + } + + @Test + void shouldSendFailurePacketWhenFailToOpen() { + when(cashShop.isOpened()).thenReturn(true); + when(cashShop.openCashShopSurprise(anyLong())).thenReturn(Optional.empty()); + + handler.handlePacket(useCashShopSurprisePacket(456), client); + + verify(client).sendPacket(PacketCreator.onCashItemGachaponOpenFailed()); + } + + @Test + void shouldSendSuccessPacketWhenSuccessfullyOpen() { + when(cashShop.isOpened()).thenReturn(true); + Item cashShopSurprise = Items.itemWithQuantity(ItemId.CASH_SHOP_SURPRISE, 3); + Item reward = Items.itemWithQuantity(5000012, 1); + when(cashShop.openCashShopSurprise(789)).thenReturn(Optional.of(new CashShop.CashShopSurpriseResult( + cashShopSurprise, reward))); + + handler.handlePacket(useCashShopSurprisePacket(789), client); + + verify(client).sendPacket(PacketCreator.onCashGachaponOpenSuccess(ACCOUNT_ID, cashShopSurprise.getCashId(), 3, + reward, 5000012, 1, true)); + } +} diff --git a/src/test/java/testutil/AnyValues.java b/src/test/java/testutil/AnyValues.java index ccf9c0abbf..8c58a8c08b 100644 --- a/src/test/java/testutil/AnyValues.java +++ b/src/test/java/testutil/AnyValues.java @@ -8,6 +8,10 @@ public class AnyValues { return "string"; } + public static short anyShort() { + return 4; + } + public static DaoException daoException() { return new DaoException(string(), new RuntimeException()); } diff --git a/src/test/java/testutil/HandlerTest.java b/src/test/java/testutil/HandlerTest.java new file mode 100644 index 0000000000..32fcaa5299 --- /dev/null +++ b/src/test/java/testutil/HandlerTest.java @@ -0,0 +1,24 @@ +package testutil; + +import client.Character; +import client.Client; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mock; + +import static org.mockito.Mockito.lenient; + +public abstract class HandlerTest { + protected static final int ACCOUNT_ID = 1702; + + @Mock + protected Client client; + + @Mock + protected Character chr; + + @BeforeEach + void prepareClient() { + lenient().when(client.getAccID()).thenReturn(ACCOUNT_ID); + lenient().when(client.getPlayer()).thenReturn(chr); + } +} diff --git a/src/test/java/testutil/Items.java b/src/test/java/testutil/Items.java new file mode 100644 index 0000000000..aba37686f1 --- /dev/null +++ b/src/test/java/testutil/Items.java @@ -0,0 +1,10 @@ +package testutil; + +import client.inventory.Item; + +public class Items { + + public static Item itemWithQuantity(int itemId, int quantity) { + return new Item(itemId, AnyValues.anyShort(), (short) quantity); + } +} diff --git a/src/test/java/testutil/Packets.java b/src/test/java/testutil/Packets.java new file mode 100644 index 0000000000..6bd9db8a9c --- /dev/null +++ b/src/test/java/testutil/Packets.java @@ -0,0 +1,18 @@ +package testutil; + +import io.netty.buffer.Unpooled; +import net.packet.ByteBufInPacket; +import net.packet.ByteBufOutPacket; +import net.packet.InPacket; +import net.packet.OutPacket; + +import java.util.function.Consumer; + +public class Packets { + + public static InPacket buildInPacket(Consumer contentProvider) { + OutPacket builderInput = new ByteBufOutPacket(); + contentProvider.accept(builderInput); + return new ByteBufInPacket(Unpooled.wrappedBuffer(builderInput.getBytes())); + } +}