From 8438ecdbd7a5640bf2c9a6a06d96d7e23c645707 Mon Sep 17 00:00:00 2001 From: Ceikry Date: Mon, 2 May 2022 10:22:36 +0000 Subject: [PATCH] Fixed an exception thrown when buying from player stock Fix issue where malformed stock could shift following shop items --- .../java/core/game/container/Container.java | 11 ++++++++ .../rs09/game/content/global/shops/Shop.kt | 4 +-- .../rs09/game/content/global/shops/Shops.kt | 28 +++++++++++-------- Server/src/test/kotlin/ShopTests.kt | 27 ++++++++++++++++++ 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/Server/src/main/java/core/game/container/Container.java b/Server/src/main/java/core/game/container/Container.java index a350db758..237993a61 100644 --- a/Server/src/main/java/core/game/container/Container.java +++ b/Server/src/main/java/core/game/container/Container.java @@ -1025,4 +1025,15 @@ public class Container { return event; } + @Override + public String toString() { + return "Container{" + + "items=" + Arrays.toString(items) + + ", capacity=" + capacity + + ", sortType=" + sortType + + ", type=" + type + + ", event=" + event + + ", listeners=" + listeners + + '}'; + } } \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/content/global/shops/Shop.kt b/Server/src/main/kotlin/rs09/game/content/global/shops/Shop.kt index 32d6402a9..279b5f9ff 100644 --- a/Server/src/main/kotlin/rs09/game/content/global/shops/Shop.kt +++ b/Server/src/main/kotlin/rs09/game/content/global/shops/Shop.kt @@ -246,13 +246,13 @@ class Shop(val title: String, val stock: Array, val general: Boolean = sendDialogue(player, "As an ironman, you cannot buy from player stock in shops.") return TransactionStatus.Failure("Ironman buying from player stock") } - val cont = if (isMainStock) getAttribute(player, "shop-cont", null) ?: return TransactionStatus.Failure("Invalid shop-cont attr") else playerStock + val cont = if (isMainStock) (getAttribute(player, "shop-cont", null) ?: return TransactionStatus.Failure("Invalid shop-cont attr")) else playerStock val inStock = cont[slot] val item = Item(inStock.id, amount) if(inStock.amount < amount) item.amount = inStock.amount - if(inStock.amount > stock[slot].amount && !getServerConfig().getBoolean(Shops.personalizedShops, false) && player.ironmanManager.isIronman) + if(isMainStock && inStock.amount > stock[slot].amount && !getServerConfig().getBoolean(Shops.personalizedShops, false) && player.ironmanManager.isIronman) { sendDialogue(player, "As an ironman, you cannot buy overstocked items from shops.") return TransactionStatus.Failure("Ironman overstock purchase") diff --git a/Server/src/main/kotlin/rs09/game/content/global/shops/Shops.kt b/Server/src/main/kotlin/rs09/game/content/global/shops/Shops.kt index de06090f2..337198163 100644 --- a/Server/src/main/kotlin/rs09/game/content/global/shops/Shops.kt +++ b/Server/src/main/kotlin/rs09/game/content/global/shops/Shops.kt @@ -41,15 +41,6 @@ class Shops : StartupListener, TickListener, InteractionListener, InterfaceListe { SystemLogger.logInfo("[SHOPS] $msg") } - } - - override fun startup() { - val path = ServerConstants.CONFIG_PATH + "shops.json" - var shopCount = 0 - logShop("Using JSON path: $path") - - val reader = FileReader(path) - val data = JSONParser().parse(reader) as JSONArray fun parseStock(stock: String, id: Int): ArrayList{ val items = ArrayList() @@ -63,13 +54,28 @@ class Shops : StartupListener, TickListener, InteractionListener, InterfaceListe if(amount == "inf") amount = "-1" val item = tokens[0].toInt() - if(idsInStock[item] != null) + if(idsInStock[item] != null) { SystemLogger.logWarn("[SHOPS] MALFORMED STOCK IN SHOP ID $id FOR ITEM $item") - else + items.forEach { if(it.itemId == item) { + it.amount += amount.toInt() + return@map + }} + } else { items.add(ShopItem(item, amount.toInt(), tokens.getOrNull(2)?.toIntOrNull() ?: 100)) + idsInStock[item] = true + } } return items } + } + + override fun startup() { + val path = ServerConstants.CONFIG_PATH + "shops.json" + var shopCount = 0 + logShop("Using JSON path: $path") + + val reader = FileReader(path) + val data = JSONParser().parse(reader) as JSONArray for(rawShop in data) { diff --git a/Server/src/test/kotlin/ShopTests.kt b/Server/src/test/kotlin/ShopTests.kt index 97909fdba..e705b05b1 100644 --- a/Server/src/test/kotlin/ShopTests.kt +++ b/Server/src/test/kotlin/ShopTests.kt @@ -4,6 +4,8 @@ import org.junit.Assert import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import rs09.game.content.global.shops.Shop +import rs09.game.content.global.shops.Shops +import rs09.game.system.config.ShopParser class ShopTests { val testPlayer = TestUtils.getMockPlayer("test") @@ -114,4 +116,29 @@ class ShopTests { general.restock() } } + + @Test fun playerStockShouldNeverBeNull() { + Assertions.assertNotNull(general.playerStock) + } + + @Test fun shouldAllowBuyingFromPlayerStockOnMultipleRows() { + for(i in 0 until 100) { + general.playerStock.add(Item(i + 3100, 1)) //make sure we populate several rows of items + } + testPlayer.inventory.add(Item(995, 100000)) + testPlayer.setAttribute("shop-cont", general.getContainer(testPlayer)) + testPlayer.setAttribute("shop-main", false) + var status: Shop.TransactionStatus = Shop.TransactionStatus.Success() + Assertions.assertDoesNotThrow({ + status = general.buy(testPlayer, 36, 1) + }, "Error selling to shop: ${general.playerStock}") + Assertions.assertEquals(true, status is Shop.TransactionStatus.Success) + } + + @Test fun invalidStockJsonShouldNotCauseItemShift() { + val invalidJson = "{1277,10,100}-{1277,10,100}-{1279,10,100}" + val stock = Shops.parseStock(invalidJson, -1) + Assertions.assertEquals(2, stock.size) + Assertions.assertEquals(20, stock[0].amount) + } } \ No newline at end of file