diff --git a/src/main/java/client/processor/action/MakerProcessor.java b/src/main/java/client/processor/action/MakerProcessor.java index bd8417628e..e6b6e46624 100644 --- a/src/main/java/client/processor/action/MakerProcessor.java +++ b/src/main/java/client/processor/action/MakerProcessor.java @@ -101,7 +101,11 @@ public class MakerProcessor { } else { if (ItemConstants.isEquipment(toCreate)) { // only equips uses stimulant and reagents if (p.readByte() != 0) { // stimulant - stimulantid = ii.getMakerStimulant(toCreate); + Optional makerStimulant = infoProvider.getStimulant(toCreate); + if (makerStimulant.isEmpty()) { + throw new IllegalArgumentException("Maker item %d has no stimulator".formatted(toCreate)); + } + stimulantid = makerStimulant.get(); if (!c.getAbstractPlayerInteraction().haveItem(stimulantid)) { stimulantid = -1; } diff --git a/src/main/java/database/JdbiConfig.java b/src/main/java/database/JdbiConfig.java new file mode 100644 index 0000000000..02dc9f9088 --- /dev/null +++ b/src/main/java/database/JdbiConfig.java @@ -0,0 +1,19 @@ +package database; + +import database.maker.MakerReagentRowMapper; +import database.maker.MakerRecipeRowMapper; +import database.note.NoteRowMapper; +import org.jdbi.v3.core.Jdbi; + +import javax.sql.DataSource; + +public final class JdbiConfig { + private JdbiConfig() {} + + public static Jdbi createConfigured(DataSource dataSource) { + return Jdbi.create(dataSource) + .registerRowMapper(new NoteRowMapper()) + .registerRowMapper(new MakerReagentRowMapper()) + .registerRowMapper(new MakerRecipeRowMapper()); + } +} diff --git a/src/main/java/database/PgDatabaseConnection.java b/src/main/java/database/PgDatabaseConnection.java index f52f29426e..4a66d0c96d 100644 --- a/src/main/java/database/PgDatabaseConnection.java +++ b/src/main/java/database/PgDatabaseConnection.java @@ -1,7 +1,5 @@ package database; -import database.maker.MakerReagentRowMapper; -import database.note.NoteRowMapper; import org.jdbi.v3.core.Handle; import org.jdbi.v3.core.Jdbi; @@ -15,14 +13,7 @@ public class PgDatabaseConnection { public PgDatabaseConnection(DataSource dataSource) { this.dataSource = dataSource; - this.jdbi = Jdbi.create(dataSource); - registerRowMappers(); - // TODO: configure jdbi elsewhere - } - - private void registerRowMappers() { - jdbi.registerRowMapper(new NoteRowMapper()) - .registerRowMapper(new MakerReagentRowMapper()); + this.jdbi = JdbiConfig.createConfigured(dataSource); } public Connection getConnection() throws SQLException { diff --git a/src/main/java/database/maker/MakerDao.java b/src/main/java/database/maker/MakerDao.java index 0a08df913e..6b87109ae6 100644 --- a/src/main/java/database/maker/MakerDao.java +++ b/src/main/java/database/maker/MakerDao.java @@ -27,4 +27,18 @@ public class MakerDao { throw new DaoException("Failed to get maker reagent with item id: %d".formatted(itemId), e); } } + + public Optional getRecipe(int itemId) { + try (Handle handle = connection.getHandle()) { + return handle.createQuery(""" + SELECT * + FROM maker_recipe + WHERE item_id = ?;""") + .bind(0, itemId) + .mapTo(MakerRecipe.class) + .findOne(); + } catch (JdbiException e) { + throw new DaoException("Failed to get maker recipe with item id: %d".formatted(itemId), e); + } + } } diff --git a/src/main/java/database/maker/MakerInfoProvider.java b/src/main/java/database/maker/MakerInfoProvider.java index b733aa6315..3a0092c217 100644 --- a/src/main/java/database/maker/MakerInfoProvider.java +++ b/src/main/java/database/maker/MakerInfoProvider.java @@ -1,19 +1,23 @@ package database.maker; +import net.jcip.annotations.ThreadSafe; + import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +@ThreadSafe public class MakerInfoProvider { private final MakerDao makerDao; - private final Map reagents = new ConcurrentHashMap<>(); + private final Map reagentCache = new ConcurrentHashMap<>(); + private final Map recipeCache = new ConcurrentHashMap<>(); public MakerInfoProvider(MakerDao makerDao) { this.makerDao = makerDao; } public Optional getMakerReagent(int itemId) { - final MakerReagent cachedReagent = reagents.get(itemId); + final MakerReagent cachedReagent = reagentCache.get(itemId); if (cachedReagent != null) { return Optional.of(cachedReagent); } @@ -22,7 +26,25 @@ public class MakerInfoProvider { if (reagentFromDb.isEmpty()) { return Optional.empty(); } - reagents.put(itemId, reagentFromDb.get()); + reagentCache.put(itemId, reagentFromDb.get()); return reagentFromDb; } + + public Optional getMakerRecipe(int itemId) { + final MakerRecipe cachedRecipe = recipeCache.get(itemId); + if (cachedRecipe != null) { + return Optional.of(cachedRecipe); + } + + final Optional recipeFromDb = makerDao.getRecipe(itemId); + if (recipeFromDb.isEmpty()) { + return Optional.empty(); + } + recipeCache.put(itemId, recipeFromDb.get()); + return recipeFromDb; + } + + public Optional getStimulant(int itemId) { + return getMakerRecipe(itemId).map(MakerRecipe::catalyst); + } } diff --git a/src/main/java/database/maker/MakerRecipe.java b/src/main/java/database/maker/MakerRecipe.java new file mode 100644 index 0000000000..892173bee8 --- /dev/null +++ b/src/main/java/database/maker/MakerRecipe.java @@ -0,0 +1,5 @@ +package database.maker; + +public record MakerRecipe(int itemId, short jobCategory, short requiredLevel, short requiredMakerLevel, int mesoCost, + Integer requiredItem, Integer requiredEquip, Integer catalyst, short quantity, + short reagentSlots) {} diff --git a/src/main/java/database/maker/MakerRecipeRowMapper.java b/src/main/java/database/maker/MakerRecipeRowMapper.java new file mode 100644 index 0000000000..bebc4031d4 --- /dev/null +++ b/src/main/java/database/maker/MakerRecipeRowMapper.java @@ -0,0 +1,26 @@ +package database.maker; + +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class MakerRecipeRowMapper implements RowMapper { + + @Override + public MakerRecipe map(ResultSet rs, StatementContext ctx) throws SQLException { + int itemId = rs.getInt("item_id"); + short jobCategory = rs.getShort("job_category"); + short requiredLevel = rs.getShort("required_level"); + short requiredMakerLevel = rs.getShort("required_maker_level"); + int mesoCost = rs.getInt("meso_cost"); + Integer requiredItem = rs.getObject("required_item", Integer.class); + Integer requiredEquip = rs.getObject("required_equip", Integer.class); + Integer catalyst = rs.getObject("catalyst", Integer.class); + short quantity = rs.getShort("quantity"); + short reagentSlots = rs.getShort("reagent_slots"); + return new MakerRecipe(itemId, jobCategory, requiredLevel, requiredMakerLevel, mesoCost, requiredItem, + requiredEquip, catalyst, quantity, reagentSlots); + } +} diff --git a/src/main/java/server/ItemInformationProvider.java b/src/main/java/server/ItemInformationProvider.java index 82bed494d9..cfba281f5a 100644 --- a/src/main/java/server/ItemInformationProvider.java +++ b/src/main/java/server/ItemInformationProvider.java @@ -40,7 +40,10 @@ import provider.wz.WZFiles; import server.MakerItemFactory.MakerItemCreateEntry; import server.life.LifeFactory; import server.life.MonsterInformationProvider; -import tools.*; +import tools.DatabaseConnection; +import tools.PacketCreator; +import tools.Pair; +import tools.Randomizer; import java.sql.Connection; import java.sql.PreparedStatement; @@ -111,7 +114,6 @@ public class ItemInformationProvider { protected Map mobCrystalMakerCache = new HashMap<>(); protected Map> statUpgradeMakerCache = new HashMap<>(); protected Map makerItemCache = new HashMap<>(); - protected Map makerCatalystCache = new HashMap<>(); protected Map> skillUpgradeCache = new HashMap<>(); protected Map skillUpgradeInfoCache = new HashMap<>(); protected Map>> cashPetFoodCache = new HashMap<>(); @@ -2119,26 +2121,6 @@ public class ItemInformationProvider { return fee; } - public int getMakerStimulant(int itemId) { // thanks to Arnah - Integer itemid = makerCatalystCache.get(itemId); - if (itemid != null) { - return itemid; - } - - itemid = -1; - for (Data md : etcData.getData("ItemMake.img").getChildren()) { - Data me = md.getChildByPath(StringUtil.getLeftPaddedStr(Integer.toString(itemId), '0', 8)); - - if (me != null) { - itemid = DataTool.getInt(me.getChildByPath("catalyst"), -1); - break; - } - } - - makerCatalystCache.put(itemId, itemid); - return itemid; - } - public Set getWhoDrops(Integer itemId) { Set list = new HashSet<>(); try (Connection con = DatabaseConnection.getConnection();