Rewrite MonsterBook, touch up chr loading

Temporarily disabled loading monster cards from db
This commit is contained in:
P0nk
2023-07-25 21:27:10 +02:00
parent b3ec325e95
commit f6aa8ceba6
7 changed files with 165 additions and 259 deletions

View File

@@ -1901,8 +1901,8 @@ public class Character extends AbstractCharacterObject {
ii.getItemEffect(itemId).applyTo(this); ii.getItemEffect(itemId).applyTo(this);
} }
if (itemId / 10000 == 238) { if (ItemId.isMonsterCard(itemId)) {
this.getMonsterBook().addCard(client, itemId); monsterbook.addCard(itemId, client);
} }
return true; return true;
} }
@@ -6743,7 +6743,7 @@ public class Character extends AbstractCharacterObject {
} }
} }
public static Character loadCharacterEntryFromDB(ResultSet rs, List<Item> equipped) { public static Character loadCharacterViewFromDB(ResultSet rs, List<Item> equipped) {
Character ret = new Character(); Character ret = new Character();
try { try {
@@ -6794,7 +6794,7 @@ public class Character extends AbstractCharacterObject {
return ret; return ret;
} }
public Character generateCharacterEntry() { public Character createCharacterView() {
Character ret = new Character(); Character ret = new Character();
ret.accountid = this.getAccountID(); ret.accountid = this.getAccountID();
@@ -6854,10 +6854,16 @@ public class Character extends AbstractCharacterObject {
updateRemainingSp(remainingSp, GameConstants.getSkillBook(job.getId())); updateRemainingSp(remainingSp, GameConstants.getSkillBook(job.getId()));
} }
public static Character loadCharFromDB(final int charid, Client client, boolean channelserver) throws SQLException { @Deprecated
public static Character loadCharFromDB(int chrId, Client client, boolean channelServer) throws SQLException {
return loadCharFromDB(chrId, client, channelServer, new MonsterBook(Collections.emptyList()));
}
public static Character loadCharFromDB(final int chrId, Client client, boolean channelServer,
MonsterBook monsterBook) throws SQLException {
Character ret = new Character(); Character ret = new Character();
ret.client = client; ret.client = client;
ret.id = charid; ret.id = chrId;
try (Connection con = DatabaseConnection.getConnection()) { try (Connection con = DatabaseConnection.getConnection()) {
final int mountexp; final int mountexp;
@@ -6867,7 +6873,7 @@ public class Character extends AbstractCharacterObject {
// Character info // Character info
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM characters WHERE id = ?")) { try (PreparedStatement ps = con.prepareStatement("SELECT * FROM characters WHERE id = ?")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) { if (!rs.next()) {
@@ -6925,8 +6931,7 @@ public class Character extends AbstractCharacterObject {
ret.allianceRank = rs.getInt("allianceRank"); ret.allianceRank = rs.getInt("allianceRank");
ret.familyId = rs.getInt("familyId"); ret.familyId = rs.getInt("familyId");
ret.bookCover = rs.getInt("monsterbookcover"); ret.bookCover = rs.getInt("monsterbookcover");
ret.monsterbook = new MonsterBook(); ret.monsterbook = monsterBook;
ret.monsterbook.loadCards(charid);
ret.vanquisherStage = rs.getInt("vanquisherStage"); ret.vanquisherStage = rs.getInt("vanquisherStage");
ret.ariantPoints = rs.getInt("ariantPoints"); ret.ariantPoints = rs.getInt("ariantPoints");
ret.dojoPoints = rs.getInt("dojoPoints"); ret.dojoPoints = rs.getInt("dojoPoints");
@@ -6946,7 +6951,7 @@ public class Character extends AbstractCharacterObject {
ret.getInventory(InventoryType.ETC).setSlotLimit(rs.getByte("etcslots")); ret.getInventory(InventoryType.ETC).setSlotLimit(rs.getByte("etcslots"));
short sandboxCheck = 0x0; short sandboxCheck = 0x0;
for (Pair<Item, InventoryType> item : ItemFactory.INVENTORY.loadItems(ret.id, !channelserver)) { for (Pair<Item, InventoryType> item : ItemFactory.INVENTORY.loadItems(ret.id, !channelServer)) {
sandboxCheck |= item.getLeft().getFlag(); sandboxCheck |= item.getLeft().getFlag();
ret.getInventory(item.getRight()).addItemFromDB(item.getLeft()); ret.getInventory(item.getRight()).addItemFromDB(item.getLeft());
@@ -6993,7 +6998,7 @@ public class Character extends AbstractCharacterObject {
// Items excluded from pet loot // Items excluded from pet loot
try (PreparedStatement psPet = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid > -1")) { try (PreparedStatement psPet = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid > -1")) {
psPet.setInt(1, charid); psPet.setInt(1, chrId);
try (ResultSet rsPet = psPet.executeQuery()) { try (ResultSet rsPet = psPet.executeQuery()) {
while (rsPet.next()) { while (rsPet.next()) {
@@ -7016,7 +7021,7 @@ public class Character extends AbstractCharacterObject {
ret.commitExcludedItems(); ret.commitExcludedItems();
if (channelserver) { if (channelServer) {
MapManager mapManager = client.getChannelServer().getMapFactory(); MapManager mapManager = client.getChannelServer().getMapFactory();
ret.map = mapManager.getMap(ret.mapid); ret.map = mapManager.getMap(ret.mapid);
@@ -7054,7 +7059,7 @@ public class Character extends AbstractCharacterObject {
// Teleport rocks // Teleport rocks
try (PreparedStatement ps = con.prepareStatement("SELECT mapid,vip FROM trocklocations WHERE characterid = ? LIMIT 15")) { try (PreparedStatement ps = con.prepareStatement("SELECT mapid,vip FROM trocklocations WHERE characterid = ? LIMIT 15")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
byte vip = 0; byte vip = 0;
@@ -7125,7 +7130,7 @@ public class Character extends AbstractCharacterObject {
// Blessing of the Fairy // Blessing of the Fairy
try (PreparedStatement ps = con.prepareStatement("SELECT name, level FROM characters WHERE accountid = ? AND id != ? ORDER BY level DESC limit 1")) { try (PreparedStatement ps = con.prepareStatement("SELECT name, level FROM characters WHERE accountid = ? AND id != ? ORDER BY level DESC limit 1")) {
ps.setInt(1, ret.accountid); ps.setInt(1, ret.accountid);
ps.setInt(2, charid); ps.setInt(2, chrId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) { if (rs.next()) {
@@ -7135,12 +7140,12 @@ public class Character extends AbstractCharacterObject {
} }
} }
if (channelserver) { if (channelServer) {
final Map<Integer, QuestStatus> loadedQuestStatus = new LinkedHashMap<>(); final Map<Integer, QuestStatus> loadedQuestStatus = new LinkedHashMap<>();
// Quest status // Quest status
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM queststatus WHERE characterid = ?")) { try (PreparedStatement ps = con.prepareStatement("SELECT * FROM queststatus WHERE characterid = ?")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {
@@ -7167,7 +7172,7 @@ public class Character extends AbstractCharacterObject {
// Quest progress // Quest progress
// opportunity for improvement on questprogress/medalmaps calls to DB // opportunity for improvement on questprogress/medalmaps calls to DB
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM questprogress WHERE characterid = ?")) { try (PreparedStatement ps = con.prepareStatement("SELECT * FROM questprogress WHERE characterid = ?")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rsProgress = ps.executeQuery()) { try (ResultSet rsProgress = ps.executeQuery()) {
while (rsProgress.next()) { while (rsProgress.next()) {
QuestStatus status = loadedQuestStatus.get(rsProgress.getInt("queststatusid")); QuestStatus status = loadedQuestStatus.get(rsProgress.getInt("queststatusid"));
@@ -7180,7 +7185,7 @@ public class Character extends AbstractCharacterObject {
// Medal map visit progress // Medal map visit progress
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM medalmaps WHERE characterid = ?")) { try (PreparedStatement ps = con.prepareStatement("SELECT * FROM medalmaps WHERE characterid = ?")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rsMedalMaps = ps.executeQuery()) { try (ResultSet rsMedalMaps = ps.executeQuery()) {
while (rsMedalMaps.next()) { while (rsMedalMaps.next()) {
QuestStatus status = loadedQuestStatus.get(rsMedalMaps.getInt("queststatusid")); QuestStatus status = loadedQuestStatus.get(rsMedalMaps.getInt("queststatusid"));
@@ -7195,7 +7200,7 @@ public class Character extends AbstractCharacterObject {
// Skills // Skills
try (PreparedStatement ps = con.prepareStatement("SELECT skillid,skilllevel,masterlevel,expiration FROM skills WHERE characterid = ?")) { try (PreparedStatement ps = con.prepareStatement("SELECT skillid,skilllevel,masterlevel,expiration FROM skills WHERE characterid = ?")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {
@@ -7265,7 +7270,7 @@ public class Character extends AbstractCharacterObject {
// Skill macros // Skill macros
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM skillmacros WHERE characterid = ?")) { try (PreparedStatement ps = con.prepareStatement("SELECT * FROM skillmacros WHERE characterid = ?")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {
@@ -7278,7 +7283,7 @@ public class Character extends AbstractCharacterObject {
// Key config // Key config
try (PreparedStatement ps = con.prepareStatement("SELECT `key`,`type`,`action` FROM keymap WHERE characterid = ?")) { try (PreparedStatement ps = con.prepareStatement("SELECT `key`,`type`,`action` FROM keymap WHERE characterid = ?")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {
@@ -7292,7 +7297,7 @@ public class Character extends AbstractCharacterObject {
// Saved locations // Saved locations
try (PreparedStatement ps = con.prepareStatement("SELECT `locationtype`,`map`,`portal` FROM savedlocations WHERE characterid = ?")) { try (PreparedStatement ps = con.prepareStatement("SELECT `locationtype`,`map`,`portal` FROM savedlocations WHERE characterid = ?")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {
@@ -7303,7 +7308,7 @@ public class Character extends AbstractCharacterObject {
// Fame history // Fame history
try (PreparedStatement ps = con.prepareStatement("SELECT `characterid_to`,`when` FROM famelog WHERE characterid = ? AND DATEDIFF(NOW(),`when`) < 30")) { try (PreparedStatement ps = con.prepareStatement("SELECT `characterid_to`,`when` FROM famelog WHERE characterid = ? AND DATEDIFF(NOW(),`when`) < 30")) {
ps.setInt(1, charid); ps.setInt(1, chrId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
ret.lastfametime = 0; ret.lastfametime = 0;
@@ -7315,7 +7320,7 @@ public class Character extends AbstractCharacterObject {
} }
} }
ret.buddylist.loadFromDb(charid); ret.buddylist.loadFromDb(chrId);
ret.storage = wserv.getAccountStorage(ret.accountid); ret.storage = wserv.getAccountStorage(ret.accountid);
/* Double-check storage incase player is first time on server /* Double-check storage incase player is first time on server

View File

@@ -1,190 +1,106 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package client; package client;
import tools.DatabaseConnection; import database.monsterbook.MonsterCard;
import net.jcip.annotations.ThreadSafe;
import tools.PacketCreator; import tools.PacketCreator;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collections; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.locks.Lock; import java.util.function.Function;
import java.util.concurrent.locks.ReentrantLock; import java.util.function.Predicate;
import java.util.stream.Collectors;
public final class MonsterBook { // TODO: add tests
private int specialCard = 0; @ThreadSafe
private int normalCard = 0; public class MonsterBook {
private int bookLevel = 1; private final Map<Integer, MonsterCard> cards;
private final Map<Integer, Integer> cards = new LinkedHashMap<>(); private int bookLevel;
private final Lock lock = new ReentrantLock();
public void addCard(final Client c, final int cardid) { public MonsterBook(List<MonsterCard> monsterCards) {
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), PacketCreator.showForeignCardEffect(c.getPlayer().getId()), false); this.cards = monsterCards.stream()
.collect(Collectors.toMap(MonsterCard::cardId, Function.identity()));
Integer qty;
lock.lock();
try {
qty = cards.get(cardid);
if (qty != null) {
if (qty < 5) {
cards.put(cardid, qty + 1);
} }
public synchronized List<MonsterCard> getCards() {
return new ArrayList<>(cards.values());
}
public synchronized void addCard(int cardId, Client client) {
var monsterCard = cards.get(cardId);
if (monsterCard != null && monsterCard.isMaxLevel()) {
client.sendPacket(PacketCreator.addMonsterCardAlreadyFull());
return;
}
boolean isNewCard = monsterCard == null;
final MonsterCard card;
if (isNewCard) {
card = new MonsterCard(cardId, (byte) 1);
cards.put(cardId, card);
calculateAndSetLevel();
} else { } else {
cards.put(cardid, 1); card = new MonsterCard(cardId, (byte) (monsterCard.level() + 1));
qty = 0; cards.put(cardId, card);
if (cardid / 1000 >= 2388) {
specialCard++;
} else {
normalCard++;
}
}
} finally {
lock.unlock();
} }
if (qty < 5) { var chr = client.getPlayer();
if (qty == 0) { // leveling system only accounts unique cards chr.sendPacket(PacketCreator.addMonsterCard(card));
calculateLevel(); chr.sendPacket(PacketCreator.showMonsterCardEffect());
chr.getMap().broadcastMessage(chr, PacketCreator.showForeignMonsterCardEffect(chr.getId()), false);
} }
c.sendPacket(PacketCreator.addCard(false, cardid, qty + 1)); private synchronized void calculateAndSetLevel() {
c.sendPacket(PacketCreator.showGainCard()); int collectionExp = getTotalCards();
} else {
c.sendPacket(PacketCreator.addCard(true, cardid, 5));
}
}
private void calculateLevel() { int level = 0;
lock.lock(); int expToNextLevel = 1;
try {
int collectionExp = (normalCard + specialCard);
int level = 0, expToNextlevel = 1;
do { do {
level++; level++;
expToNextlevel += level * 10; expToNextLevel += level * 10;
} while (collectionExp >= expToNextlevel); } while (collectionExp >= expToNextLevel);
bookLevel = level; // thanks IxianMace for noticing book level differing between book UI and character info UI this.bookLevel = level;
} finally {
lock.unlock();
}
} }
public int getBookLevel() { public synchronized int getBookLevel() {
lock.lock();
try {
return bookLevel; return bookLevel;
} finally {
lock.unlock();
}
} }
public Map<Integer, Integer> getCards() { public synchronized int getNormalCards() {
lock.lock(); return (int) cards.values().stream()
try { .filter(Predicate.not(MonsterCard::isSpecial))
return Collections.unmodifiableMap(cards); .count();
} finally {
lock.unlock();
}
} }
public int getTotalCards() { public synchronized int getSpecialCards() {
lock.lock(); return (int) cards.values().stream()
try { .filter(MonsterCard::isSpecial)
return specialCard + normalCard; .count();
} finally {
lock.unlock();
}
} }
public int getNormalCard() { public synchronized int getTotalCards() {
lock.lock(); return cards.size();
try {
return normalCard;
} finally {
lock.unlock();
}
} }
public int getSpecialCard() { public synchronized void saveCards(Connection con, int chrId) throws SQLException {
lock.lock();
try {
return specialCard;
} finally {
lock.unlock();
}
}
public void loadCards(final int charid) throws SQLException {
lock.lock();
try (Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT cardid, level FROM monsterbook WHERE charid = ? ORDER BY cardid ASC")) {
ps.setInt(1, charid);
try (ResultSet rs = ps.executeQuery()) {
int cardid;
int level;
while (rs.next()) {
cardid = rs.getInt("cardid");
level = rs.getInt("level");
if (cardid / 1000 >= 2388) {
specialCard++;
} else {
normalCard++;
}
cards.put(cardid, level);
}
}
} finally {
lock.unlock();
}
calculateLevel();
}
public void saveCards(Connection con, int chrId) throws SQLException {
final String query = """ final String query = """
INSERT INTO monsterbook (charid, cardid, level) INSERT INTO monsterbook (charid, cardid, level)
VALUES (?, ?, ?) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE level = ?; ON DUPLICATE KEY UPDATE level = ?;
"""; """;
try (final PreparedStatement ps = con.prepareStatement(query)) { try (final PreparedStatement ps = con.prepareStatement(query)) {
for (Map.Entry<Integer, Integer> cardAndLevel : cards.entrySet()) { for (MonsterCard card : cards.values()) {
final int card = cardAndLevel.getKey();
final int level = cardAndLevel.getValue();
// insert // insert
ps.setInt(1, chrId); ps.setInt(1, chrId);
ps.setInt(2, card); ps.setInt(2, card.cardId());
ps.setInt(3, level); ps.setInt(3, card.level());
// update // update
ps.setInt(4, level); ps.setInt(4, card.level());
ps.addBatch(); ps.addBatch();
} }

View File

@@ -1,12 +1,15 @@
package database.monsterbook; package database.monsterbook;
import constants.id.ItemId;
public record MonsterCard(int cardId, byte level) { public record MonsterCard(int cardId, byte level) {
private static final int MAX_LEVEL = 5;
public MonsterCard { public MonsterCard {
if (cardId / 10_000 != 238) { if (!ItemId.isMonsterCard(cardId)) {
throw new IllegalArgumentException("Invalid monster card id: %d".formatted(cardId)); throw new IllegalArgumentException("Invalid monster card id: %d".formatted(cardId));
} }
if (level < 0 || level > 5) { if (level < 0 || level > MAX_LEVEL) {
throw new IllegalArgumentException("Invalid monster card level: %d".formatted(level)); throw new IllegalArgumentException("Invalid monster card level: %d".formatted(level));
} }
} }
@@ -14,4 +17,8 @@ public record MonsterCard(int cardId, byte level) {
public boolean isSpecial() { public boolean isSpecial() {
return cardId / 1000 == 2388; return cardId / 1000 == 2388;
} }
public boolean isMaxLevel() {
return level == MAX_LEVEL;
}
} }

View File

@@ -1432,7 +1432,7 @@ public class Server {
} }
public void updateCharacterEntry(Character chr) { public void updateCharacterEntry(Character chr) {
Character chrView = chr.generateCharacterEntry(); Character chrView = chr.createCharacterView();
lgnWLock.lock(); lgnWLock.lock();
try { try {
@@ -1457,7 +1457,7 @@ public class Server {
worldChars.put(chrid, world); worldChars.put(chrid, world);
Character chrView = chr.generateCharacterEntry(); Character chrView = chr.createCharacterView();
World wserv = this.getWorld(chrView.getWorld()); World wserv = this.getWorld(chrView.getWorld());
if (wserv != null) { if (wserv != null) {
@@ -1488,47 +1488,6 @@ public class Server {
} }
} }
public void transferWorldCharacterEntry(Character chr, Integer toWorld) { // used before setting the new worldid on the character object
lgnWLock.lock();
try {
Integer chrid = chr.getId(), accountid = chr.getAccountID(), world = worldChars.get(chr.getId());
if (world != null) {
World wserv = this.getWorld(world);
if (wserv != null) {
wserv.unregisterAccountCharacterView(accountid, chrid);
}
}
worldChars.put(chrid, toWorld);
Character chrView = chr.generateCharacterEntry();
World wserv = this.getWorld(toWorld);
if (wserv != null) {
wserv.registerAccountCharacterView(chrView.getAccountID(), chrView);
}
} finally {
lgnWLock.unlock();
}
}
/*
public void deleteAccountEntry(Integer accountid) { is this even a thing?
lgnWLock.lock();
try {
accountCharacterCount.remove(accountid);
accountChars.remove(accountid);
} finally {
lgnWLock.unlock();
}
for (World wserv : this.getWorlds()) {
wserv.clearAccountCharacterView(accountid);
wserv.unregisterAccountStorage(accountid);
}
}
*/
public SortedMap<Integer, List<Character>> loadAccountCharlist(int accountId, int visibleWorlds) { public SortedMap<Integer, List<Character>> loadAccountCharlist(int accountId, int visibleWorlds) {
List<World> worlds = this.getWorlds(); List<World> worlds = this.getWorlds();
if (worlds.size() > visibleWorlds) { if (worlds.size() > visibleWorlds) {
@@ -1558,11 +1517,11 @@ public class Server {
return worldChrs; return worldChrs;
} }
private static Pair<Short, List<List<Character>>> loadAccountCharactersViewFromDb(int accId, int wlen) { private static Pair<Short, List<List<Character>>> loadAccountCharactersViewFromDb(int accId, int worlds) {
short characterCount = 0; short chrCount = 0;
List<List<Character>> wchars = new ArrayList<>(wlen); List<List<Character>> worldChrs = new ArrayList<>(worlds);
for (int i = 0; i < wlen; i++) { for (int i = 0; i < worlds; i++) {
wchars.add(i, new LinkedList<>()); worldChrs.add(i, new LinkedList<>());
} }
List<Character> chars = new LinkedList<>(); List<Character> chars = new LinkedList<>();
@@ -1587,32 +1546,32 @@ public class Server {
ps.setInt(1, accId); ps.setInt(1, accId);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {
characterCount++; chrCount++;
int cworld = rs.getByte("world"); int cworld = rs.getByte("world");
if (cworld >= wlen) { if (cworld >= worlds) {
continue; continue;
} }
if (cworld > curWorld) { if (cworld > curWorld) {
wchars.add(curWorld, chars); worldChrs.add(curWorld, chars);
curWorld = cworld; curWorld = cworld;
chars = new LinkedList<>(); chars = new LinkedList<>();
} }
Integer cid = rs.getInt("id"); Integer cid = rs.getInt("id");
chars.add(Character.loadCharacterEntryFromDB(rs, accPlayerEquips.get(cid))); chars.add(Character.loadCharacterViewFromDB(rs, accPlayerEquips.get(cid)));
} }
} }
} }
wchars.add(curWorld, chars); worldChrs.add(curWorld, chars);
} catch (SQLException sqle) { } catch (SQLException sqle) {
sqle.printStackTrace(); sqle.printStackTrace();
} }
return new Pair<>(characterCount, wchars); return new Pair<>(chrCount, worldChrs);
} }
public void loadAllAccountsCharactersView() { public void loadAllAccountsCharactersView() {

View File

@@ -451,18 +451,6 @@ public class World {
} }
} }
public void clearAccountCharacterView(Integer accountId) {
accountCharsLock.lock();
try {
SortedMap<Integer, Character> accChars = accountChars.remove(accountId);
if (accChars != null) {
accChars.clear();
}
} finally {
accountCharsLock.unlock();
}
}
public void loadAccountStorage(Integer accountId) { public void loadAccountStorage(Integer accountId) {
if (getAccountStorage(accountId) == null) { if (getAccountStorage(accountId) == null) {
registerAccountStorage(accountId); registerAccountStorage(accountId);

View File

@@ -40,6 +40,7 @@ import constants.inventory.ItemConstants;
import constants.skills.Buccaneer; import constants.skills.Buccaneer;
import constants.skills.Corsair; import constants.skills.Corsair;
import constants.skills.ThunderBreaker; import constants.skills.ThunderBreaker;
import database.monsterbook.MonsterCard;
import net.encryption.InitializationVector; import net.encryption.InitializationVector;
import net.opcodes.SendOpcode; import net.opcodes.SendOpcode;
import net.packet.ByteBufOutPacket; import net.packet.ByteBufOutPacket;
@@ -526,12 +527,12 @@ public class PacketCreator {
private static void addMonsterBookInfo(OutPacket p, Character chr) { private static void addMonsterBookInfo(OutPacket p, Character chr) {
p.writeInt(chr.getMonsterBookCover()); // cover p.writeInt(chr.getMonsterBookCover()); // cover
p.writeByte(0); p.writeByte(0);
Map<Integer, Integer> cards = chr.getMonsterBook().getCards(); List<MonsterCard> cards = chr.getMonsterBook().getCards();
p.writeShort(cards.size()); p.writeShort(cards.size());
for (Entry<Integer, Integer> all : cards.entrySet()) { cards.forEach(card -> {
p.writeShort(all.getKey() % 10000); // Id p.writeShort(card.cardId() % 10000);
p.writeByte(all.getValue()); // Level p.writeByte(card.level());
} });
} }
public static Packet sendGuestTOS() { public static Packet sendGuestTOS() {
@@ -2734,8 +2735,8 @@ public class PacketCreator {
MonsterBook book = chr.getMonsterBook(); MonsterBook book = chr.getMonsterBook();
p.writeInt(book.getBookLevel()); p.writeInt(book.getBookLevel());
p.writeInt(book.getNormalCard()); p.writeInt(book.getNormalCards());
p.writeInt(book.getSpecialCard()); p.writeInt(book.getSpecialCards());
p.writeInt(book.getTotalCards()); p.writeInt(book.getTotalCards());
p.writeInt(chr.getMonsterBookCover() > 0 ? ItemInformationProvider.getInstance().getCardMobId(chr.getMonsterBookCover()) : 0); p.writeInt(chr.getMonsterBookCover() > 0 ? ItemInformationProvider.getInstance().getCardMobId(chr.getMonsterBookCover()) : 0);
Item medal = chr.getInventory(InventoryType.EQUIPPED).getItem((short) -49); Item medal = chr.getInventory(InventoryType.EQUIPPED).getItem((short) -49);
@@ -5978,13 +5979,29 @@ public class PacketCreator {
return p; return p;
} }
public static Packet showGainCard() { public static Packet addMonsterCard(MonsterCard monsterCard) {
OutPacket p = OutPacket.create(SendOpcode.MONSTER_BOOK_SET_CARD);
p.writeBool(true);
p.writeInt(monsterCard.cardId());
p.writeInt(monsterCard.level());
return p;
}
public static Packet addMonsterCardAlreadyFull() {
OutPacket p = OutPacket.create(SendOpcode.MONSTER_BOOK_SET_CARD);
p.writeBool(false);
return p;
}
public static Packet showMonsterCardEffect() {
OutPacket p = OutPacket.create(SendOpcode.SHOW_ITEM_GAIN_INCHAT); OutPacket p = OutPacket.create(SendOpcode.SHOW_ITEM_GAIN_INCHAT);
p.writeByte(0x0D); p.writeByte(0x0D);
return p; return p;
} }
public static Packet showForeignCardEffect(int id) { public static Packet showForeignMonsterCardEffect(int id) {
OutPacket p = OutPacket.create(SendOpcode.SHOW_FOREIGN_EFFECT); OutPacket p = OutPacket.create(SendOpcode.SHOW_FOREIGN_EFFECT);
p.writeInt(id); p.writeInt(id);
p.writeByte(0x0D); p.writeByte(0x0D);

View File

@@ -38,6 +38,20 @@ class MonsterCardTest {
assertFalse(normalCard.isSpecial()); assertFalse(normalCard.isSpecial());
} }
@Test
void notMaxLevel() {
var nonMaxedCard = new MonsterCard(validCardId(), (byte) 4);
assertFalse(nonMaxedCard.isMaxLevel());
}
@Test
void isMaxLevel() {
var maxedCard = new MonsterCard(validCardId(), (byte) 5);
assertTrue(maxedCard.isMaxLevel());
}
private int validCardId() { private int validCardId() {
return 2380000; return 2380000;
} }