From fe9dd75a23103b2500d3bfb5fd4220eb26a367b9 Mon Sep 17 00:00:00 2001 From: P0nk Date: Wed, 29 Mar 2023 21:59:00 +0200 Subject: [PATCH] Instantiate shops in ShopFactory --- src/main/java/constants/id/ItemId.java | 22 +++-- src/main/java/net/server/Server.java | 3 +- .../channel/handlers/NPCTalkHandler.java | 4 +- src/main/java/server/Shop.java | 81 +------------------ src/main/java/server/ShopFactory.java | 78 +++++++++++------- 5 files changed, 70 insertions(+), 118 deletions(-) diff --git a/src/main/java/constants/id/ItemId.java b/src/main/java/constants/id/ItemId.java index 9c9541e61d..ad3811cf8d 100644 --- a/src/main/java/constants/id/ItemId.java +++ b/src/main/java/constants/id/ItemId.java @@ -70,14 +70,16 @@ public class ItemId { // Throwing star public static final int SUBI_THROWING_STARS = 2070000; public static final int HWABI_THROWING_STARS = 2070007; + private static final int ORANGE_THROWING_STARS = 2070013; public static final int BALANCED_FURY = 2070018; public static final int CRYSTAL_ILBI_THROWING_STARS = 2070016; - private static final int THROWING_STAR_MIN = SUBI_THROWING_STARS; - private static final int THROWING_STAR_MAX = 2070016; - public static final int DEVIL_RAIN_THROWING_STAR = 2070014; - public static int[] allThrowingStarIds() { - return IntStream.range(THROWING_STAR_MIN, THROWING_STAR_MAX + 1).toArray(); + public static IntStream allThrowingStarIds() { + // excluding 2070015 - A Beginner Thief's Throwing Stars + return IntStream.concat( + IntStream.range(SUBI_THROWING_STARS, ORANGE_THROWING_STARS + 1), + IntStream.of(CRYSTAL_ILBI_THROWING_STARS, BALANCED_FURY) + ); } // Bullet @@ -87,8 +89,12 @@ public class ItemId { public static final int BLAZE_CAPSULE = 2331000; public static final int GLAZE_CAPSULE = 2332000; - public static int[] allBulletIds() { - return IntStream.range(BULLET_MIN, BULLET_MAX + 1).toArray(); + public static IntStream allBulletIds() { + return IntStream.range(BULLET_MIN, BULLET_MAX + 1); + } + + public static IntStream allBulletCapsuleIds() { + return IntStream.of(BLAZE_CAPSULE, GLAZE_CAPSULE); } // Starter @@ -325,7 +331,7 @@ public class ItemId { public static boolean isWeddingRing(int itemId) { return itemId == WEDDING_RING_MOONSTONE || itemId == WEDDING_RING_STAR || - itemId == WEDDING_RING_GOLDEN || itemId == WEDDING_RING_SILVER; + itemId == WEDDING_RING_GOLDEN || itemId == WEDDING_RING_SILVER; } // Priority buff diff --git a/src/main/java/net/server/Server.java b/src/main/java/net/server/Server.java index 07837600de..dd637a90e5 100644 --- a/src/main/java/net/server/Server.java +++ b/src/main/java/net/server/Server.java @@ -49,6 +49,7 @@ import database.maker.MakerDao; import database.maker.MakerInfoProvider; import database.migration.FlywayRunner; import database.note.NoteDao; +import database.shop.ShopDao; import net.ChannelDependencies; import net.PacketProcessor; import net.netty.LoginServer; @@ -978,7 +979,7 @@ public class Server { MakerProcessor makerProcessor = new MakerProcessor(new MakerInfoProvider(new MakerDao(connection))); FredrickProcessor fredrickProcessor = new FredrickProcessor(noteService); DropProvider dropProvider = new DropProvider(new DropDao(connection)); - ShopFactory shopFactory = new ShopFactory(); + ShopFactory shopFactory = new ShopFactory(new ShopDao(connection)); CommandContext commandContext = new CommandContext(dropProvider, shopFactory); CommandsExecutor commandsExecutor = new CommandsExecutor(commandContext); ChannelDependencies channelDependencies = new ChannelDependencies(noteService, fredrickProcessor, diff --git a/src/main/java/net/server/channel/handlers/NPCTalkHandler.java b/src/main/java/net/server/channel/handlers/NPCTalkHandler.java index 0ead20e467..d66e8144b2 100644 --- a/src/main/java/net/server/channel/handlers/NPCTalkHandler.java +++ b/src/main/java/net/server/channel/handlers/NPCTalkHandler.java @@ -106,11 +106,11 @@ public final class NPCTalkHandler extends AbstractPacketHandler { } private boolean hasShop(NPC npc) { - return shopFactory.getShopForNPC(npc.getId()) != null; + return shopFactory.getShop(npc.getId()) != null; } private void sendShop(NPC npc, Client c) { - Shop shop = shopFactory.getShopForNPC(npc.getId()); + Shop shop = shopFactory.getShop(npc.getId()); if (shop == null) { return; } diff --git a/src/main/java/server/Shop.java b/src/main/java/server/Shop.java index b4045d451a..f017f1af39 100644 --- a/src/main/java/server/Shop.java +++ b/src/main/java/server/Shop.java @@ -30,25 +30,16 @@ import constants.id.ItemId; import constants.inventory.ItemConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import tools.DatabaseConnection; import tools.PacketCreator; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; /** * @author Matze */ public class Shop { private static final Logger log = LoggerFactory.getLogger(Shop.class); - private static final Set rechargeableItems = new LinkedHashSet<>(); - private static final short MAX_QUANTITY_PER_PURCHASE = 1000; // Should really use max stack size for the given item private final int id; private final int npcId; @@ -56,27 +47,10 @@ public class Shop { private final int tokenvalue = 1000000000; private final int token = ItemId.GOLDEN_MAPLE_LEAF; - static { - for (int throwingStarId : ItemId.allThrowingStarIds()) { - rechargeableItems.add(throwingStarId); - } - rechargeableItems.add(ItemId.BLAZE_CAPSULE); - rechargeableItems.add(ItemId.GLAZE_CAPSULE); - rechargeableItems.add(ItemId.BALANCED_FURY); - rechargeableItems.remove(ItemId.DEVIL_RAIN_THROWING_STAR); // doesn't exist - for (int bulletId : ItemId.allBulletIds()) { - rechargeableItems.add(bulletId); - } - } - - private Shop(int id, int npcId) { + public Shop(int id, int npcId, List items) { this.id = id; this.npcId = npcId; - items = new ArrayList<>(); - } - - private void addItem(ShopItem item) { - items.add(item); + this.items = new ArrayList<>(items); } public void sendShop(Client c) { @@ -242,57 +216,6 @@ public class Shop { return items.get(slot); } - public static Shop createFromDB(int id, boolean isShopId) { - Shop ret = null; - int shopId; - try (Connection con = DatabaseConnection.getConnection()) { - final String query; - if (isShopId) { - query = "SELECT * FROM shops WHERE shopid = ?"; - } else { - query = "SELECT * FROM shops WHERE npcid = ?"; - } - - try (PreparedStatement ps = con.prepareStatement(query)) { - ps.setInt(1, id); - - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - shopId = rs.getInt("shopid"); - ret = new Shop(shopId, rs.getInt("npcid")); - } else { - return null; - } - } - } - - try (PreparedStatement ps = con.prepareStatement("SELECT itemid, price, pitch FROM shopitems WHERE shopid = ? ORDER BY position DESC")) { - ps.setInt(1, shopId); - - try (ResultSet rs = ps.executeQuery()) { - List recharges = new ArrayList<>(rechargeableItems); - while (rs.next()) { - if (ItemConstants.isRechargeable(rs.getInt("itemid"))) { - ShopItem starItem = new ShopItem((short) 1, rs.getInt("itemid"), rs.getInt("price"), rs.getInt("pitch")); - ret.addItem(starItem); - if (rechargeableItems.contains(starItem.getItemId())) { - recharges.remove(Integer.valueOf(starItem.getItemId())); - } - } else { - ret.addItem(new ShopItem(MAX_QUANTITY_PER_PURCHASE, rs.getInt("itemid"), rs.getInt("price"), rs.getInt("pitch"))); - } - } - for (Integer recharge : recharges) { - ret.addItem(new ShopItem((short) 0, recharge, 0, 0)); - } - } - } - } catch (SQLException e) { - e.printStackTrace(); - } - return ret; - } - public int getNpcId() { return npcId; } diff --git a/src/main/java/server/ShopFactory.java b/src/main/java/server/ShopFactory.java index 7038f761ad..7e932368fc 100644 --- a/src/main/java/server/ShopFactory.java +++ b/src/main/java/server/ShopFactory.java @@ -1,8 +1,8 @@ /* - This file is part of the OdinMS Maple Story Server + This file is part of the OdinMS Maple Story Server Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer + Matthias Butz + Jan Christian Meyer This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -21,45 +21,67 @@ */ package server; -import java.util.HashMap; -import java.util.Map; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import constants.id.ItemId; +import constants.inventory.ItemConstants; +import database.shop.ShopDao; +import database.shop.ShopItem; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; /** * @author Matze */ public class ShopFactory { - private final Map shops = new HashMap<>(); - private final Map npcShops = new HashMap<>(); + private static final short MAX_QUANTITY_PER_PURCHASE = 1000; // Should really use max stack size for the given item + private static final Set rechargeableItemIds = rechargeableItemIds(); + private final Cache shops = Caffeine.newBuilder().build(); + private final ShopDao shopDao; - private Shop loadShop(int id, boolean isShopId) { - Shop ret = Shop.createFromDB(id, isShopId); - if (ret != null) { - shops.put(ret.getId(), ret); - npcShops.put(ret.getNpcId(), ret); - } else if (isShopId) { - shops.put(id, null); - } else { - npcShops.put(id, null); - } - return ret; + public ShopFactory(ShopDao shopDao) { + this.shopDao = shopDao; + } + + private static Set rechargeableItemIds() { + IntStream stars = ItemId.allThrowingStarIds(); + IntStream ammo = IntStream.concat(ItemId.allBulletIds(), ItemId.allBulletCapsuleIds()); + return IntStream.concat(stars, ammo) + .boxed() + .collect(Collectors.toUnmodifiableSet()); } public Shop getShop(int shopId) { - if (shops.containsKey(shopId)) { - return shops.get(shopId); - } - return loadShop(shopId, true); + return shops.get(shopId, this::loadShop); } - public Shop getShopForNPC(int npcId) { - if (npcShops.containsKey(npcId)) { - return npcShops.get(npcId); + private Shop loadShop(int shopId) { + Optional dbShop = shopDao.getShop(shopId); + if (dbShop.isEmpty()) { + throw new IllegalArgumentException("Shop with id %d does not exist".formatted(shopId)); } - return loadShop(npcId, false); + List items = shopDao.getShopItems(shopId); + return new Shop(dbShop.get().id(), dbShop.get().npcId(), fromDbShopItems(items)); + } + + private List fromDbShopItems(List dbItems) { + Stream purchaseableItems = dbItems.stream() + .map(dbItem -> { + short buyable = ItemConstants.isRechargeable(dbItem.itemId()) ? (short) 1 : MAX_QUANTITY_PER_PURCHASE; + int pitch = dbItem.pitch() == null ? 0 : dbItem.pitch(); + return new server.ShopItem(buyable, dbItem.itemId(), dbItem.price(), pitch); + }); + Stream rechargeableItems = rechargeableItemIds.stream() + .map(rechItem -> new server.ShopItem((short) 0, rechItem, 0, 0)); + return Stream.concat(purchaseableItems, rechargeableItems).toList(); } public void reloadShops() { - shops.clear(); - npcShops.clear(); + shops.invalidateAll(); } }