Autosave feature + Pet Ignore fix

Added experimental autosaver feature. Fixed pet ignore feature not
saving/loading data in some cases. Added concurrency protection for
inventory classes and monster book.
This commit is contained in:
ronancpl
2017-09-11 16:53:40 -03:00
parent e064d5cbfa
commit f387d589b2
55 changed files with 567 additions and 247 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
#Thu, 07 Sep 2017 21:09:39 -0300 #Mon, 11 Sep 2017 16:18:43 -0300
C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2= C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2=
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+8 -1
View File
@@ -520,4 +520,11 @@ Corrigido itens saindo para fora do mapa. Nova posi
07 Setembro 2017, 07 Setembro 2017,
Adicionado Vega's Spell. Adicionado Vega's Spell.
3rd job event agora possui tempo-limite e verifica se há jogadores já enfrentando o desafio. 3rd job event agora possui tempo-limite e verifica se há jogadores já enfrentando o desafio.
10 Setembro 2017,
Protegido contra acesso concorrente classes MonsterBook e MapleInventory.
Nova feature: autosaver.
11 Setembro 2017,
Consertado pet ignore não recuperando dados dos pets em alguns casos.
+24 -1
View File
@@ -2,6 +2,29 @@
<project-private xmlns="http://www.netbeans.org/ns/project-private/1"> <project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="1"/> <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="1"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2"> <open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group/> <group>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/inventory/MaplePet.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/EnterMTSHandler.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/PlayerLoggedinHandler.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MonsterBook.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/ItemConstants.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleStorage.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/world/World.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/ServerConstants.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleItemInformationProvider.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/inventory/MapleInventory.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/MaplePacketCreator.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/PetExcludeItemsHandler.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/inventory/ItemFactory.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/FilePrinter.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/PlayerStorage.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/Server.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/CouponWorker.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleInventoryManipulator.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleCharacter.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/CharacterAutosaverWorker.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/CashShop.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/event/EventManager.java</file>
</group>
</open-files> </open-files>
</project-private> </project-private>
+2 -1
View File
@@ -208,7 +208,7 @@ function action(mode, type, selection) {
var selStr = "You have #b" + cm.getPlayer().getDojoPoints() + "#k training points. Master prefers those with great talent. If you obtain more points than the average, you can receive a belt depending on your score.\r\n"; var selStr = "You have #b" + cm.getPlayer().getDojoPoints() + "#k training points. Master prefers those with great talent. If you obtain more points than the average, you can receive a belt depending on your score.\r\n";
for (var i = 0; i < belts.length; i++) { for (var i = 0; i < belts.length; i++) {
if (cm.getPlayer().getItemQuantity(belts[i], true) > 0) { if (cm.getPlayer().getItemQuantity(belts[i], true) > 0) {
selStr += "\r\n#L" + i + "##i" + belts[i] + "# #t" + belts[i] + "# (Obtained)"; selStr += "\r\n#L" + i + "##i" + belts[i] + "# #t" + belts[i] + "# (Already on inventory)";
} else } else
selStr += "\r\n#L" + i + "##i" + belts[i] + "# #t" + belts[i] + "#"; selStr += "\r\n#L" + i + "##i" + belts[i] + "# #t" + belts[i] + "#";
} }
@@ -220,6 +220,7 @@ function action(mode, type, selection) {
if (cm.getPlayer().getDojoPoints() >= points) { if (cm.getPlayer().getDojoPoints() >= points) {
if (cm.getPlayer().getLevel() > level) { if (cm.getPlayer().getLevel() > level) {
cm.gainItem(belt, 1); cm.gainItem(belt, 1);
cm.getPlayer().setDojoPoints(cm.getPlayer().getDojoPoints() - points);
cm.sendNext("There is the #i" + belt + "# #b#t" + belt + "##k. You have proven your valor to ascend on the Dojo ranks. Well done!"); cm.sendNext("There is the #i" + belt + "# #b#t" + belt + "##k. You have proven your valor to ascend on the Dojo ranks. Well done!");
} }
else else
+1 -1
View File
@@ -22,7 +22,7 @@ function action(mode, type, selection) {
else else
status--; status--;
if (status == 0) { if (status == 0) {
if (cm.getLevel() < 20) { if (cm.getLevel() < 25) {
cm.sendDimensionalMirror("#-1# There is no place for you to transport to from here."); cm.sendDimensionalMirror("#-1# There is no place for you to transport to from here.");
cm.dispose(); cm.dispose();
} else { } else {
+1 -1
View File
@@ -21222,7 +21222,7 @@ INSERT INTO `shopitems` ( `shopid`, `itemid`, `price`, `position`) VALUES
(1052116, 2000002, 320, 212), (1052116, 2000002, 320, 212),
(1052116, 2000001, 160, 216), (1052116, 2000001, 160, 216),
(1052116, 2000000, 50, 220), (1052116, 2000000, 50, 220),
(9120002, 2061003, 40, 0, 100); (9120002, 2061003, 40, 100);
CREATE TABLE IF NOT EXISTS `skillmacros` ( CREATE TABLE IF NOT EXISTS `skillmacros` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
+46 -20
View File
@@ -4529,26 +4529,31 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} }
} }
PreparedStatement ps2; PreparedStatement ps2, ps3;
ResultSet rs2; ResultSet rs2, rs3;
for(byte i = 0; i < 3; i++) {
MaplePet pet = ret.getPet(i); ps3 = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid > -1");
if(pet == null) continue; ps3.setInt(1, charid);
rs3 = ps3.executeQuery();
int petId = pet.getUniqueId(); while(rs3.next()) {
ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?"); // Get pet details.. int petId = rs3.getInt("petid");
ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?");
ps2.setInt(1, petId); ps2.setInt(1, petId);
ret.resetExcluded(petId); ret.resetExcluded(petId);
rs2 = ps2.executeQuery(); rs2 = ps2.executeQuery();
while(rs2.next()) { while(rs2.next()) {
ret.addExcluded(petId, rs2.getInt("itemid")); ret.addExcluded(petId, rs2.getInt("itemid"));
} }
ps2.close(); ps2.close();
rs2.close(); rs2.close();
} }
ps3.close();
rs3.close();
ret.commitExcludedItems(); ret.commitExcludedItems();
if (channelserver) { if (channelserver) {
@@ -5525,10 +5530,28 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} }
} }
// synchronize this call instead of trying to give access all at once (?) public void saveToDB() {
public synchronized void saveToDB() { if(ServerConstants.USE_AUTOSAVE) {
Runnable r = new Runnable() {
@Override
public void run() {
saveToDB(true);
}
};
Thread t = new Thread(r); //spawns a new thread to deal with this
t.start();
} else {
saveToDB(true);
}
}
public synchronized void saveToDB(boolean notAutosave) {
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
FilePrinter.print(FilePrinter.SAVING_CHARACTER, "Attempting to save " + name + " at " + c.getTime().toString());
if(notAutosave) FilePrinter.print(FilePrinter.SAVING_CHARACTER, "Attempting to save " + name + " at " + c.getTime().toString());
else FilePrinter.print(FilePrinter.AUTOSAVING_CHARACTER, "Attempting to autosave " + name + " at " + c.getTime().toString());
Connection con = null; Connection con = null;
try { try {
con = DatabaseConnection.getConnection(); con = DatabaseConnection.getConnection();
@@ -5577,7 +5600,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} }
ps.setInt(22, meso.get()); ps.setInt(22, meso.get());
ps.setInt(23, hpMpApUsed); ps.setInt(23, hpMpApUsed);
if (map == null || map.getId() == 610020000 || map.getId() == 610020001) { if (map == null || map.getId() == 610020000 || map.getId() == 610020001) { // reset to first spawnpoint on those maps
ps.setInt(24, 0); ps.setInt(24, 0);
} else { } else {
MaplePortal closest = map.findClosestPlayerSpawnpoint(getPosition()); MaplePortal closest = map.findClosestPlayerSpawnpoint(getPosition());
@@ -5648,7 +5671,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
petLock.unlock(); petLock.unlock();
} }
for(Entry<Integer, Set<Integer>> es: getExcluded().entrySet()) { for(Entry<Integer, Set<Integer>> es: getExcluded().entrySet()) { // this set is already protected
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM petignores WHERE petid=?")) { try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM petignores WHERE petid=?")) {
ps2.setInt(1, es.getKey()); ps2.setInt(1, es.getKey());
ps2.executeUpdate(); ps2.executeUpdate();
@@ -5667,8 +5690,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
deleteWhereCharacterId(con, "DELETE FROM keymap WHERE characterid = ?"); deleteWhereCharacterId(con, "DELETE FROM keymap WHERE characterid = ?");
ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)"); ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)");
ps.setInt(1, id); ps.setInt(1, id);
for (Entry<Integer, MapleKeyBinding> keybinding : keymap.entrySet()) {
ps.setInt(2, keybinding.getKey().intValue()); Set<Entry<Integer, MapleKeyBinding>> keybindingItems = Collections.unmodifiableSet(keymap.entrySet());
for (Entry<Integer, MapleKeyBinding> keybinding : keybindingItems) {
ps.setInt(2, keybinding.getKey());
ps.setInt(3, keybinding.getValue().getType()); ps.setInt(3, keybinding.getValue().getType());
ps.setInt(4, keybinding.getValue().getAction()); ps.setInt(4, keybinding.getValue().getAction());
ps.addBatch(); ps.addBatch();
@@ -5691,14 +5716,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} }
} }
ps.executeBatch(); ps.executeBatch();
List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>(); List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>();
for (MapleInventory iv : inventory) { for (MapleInventory iv : inventory) {
for (Item item : iv.list()) { for (Item item : iv.list()) {
itemsWithType.add(new Pair<>(item, iv.getType())); itemsWithType.add(new Pair<>(item, iv.getType()));
} }
} }
ItemFactory.INVENTORY.saveItems(itemsWithType, id, con); ItemFactory.INVENTORY.saveItems(itemsWithType, id, con);
deleteWhereCharacterId(con, "DELETE FROM skills WHERE characterid = ?"); deleteWhereCharacterId(con, "DELETE FROM skills WHERE characterid = ?");
@@ -6283,7 +6307,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if (slots <= 96) { if (slots <= 96) {
inventory[type].setSlotLimit(slots); inventory[type].setSlotLimit(slots);
saveToDB(); this.saveToDB();
if (update) { if (update) {
client.announce(MaplePacketCreator.updateInventorySlotLimit(type, slots)); client.announce(MaplePacketCreator.updateInventorySlotLimit(type, slots));
} }
@@ -6552,6 +6576,8 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
getMap().broadcastMessage(this, MaplePacketCreator.showPet(this, pet, true, hunger), true); getMap().broadcastMessage(this, MaplePacketCreator.showPet(this, pet, true, hunger), true);
removePet(pet, shift_left); removePet(pet, shift_left);
commitExcludedItems();
client.announce(MaplePacketCreator.petStatUpdate(this)); client.announce(MaplePacketCreator.petStatUpdate(this));
client.announce(MaplePacketCreator.enableActions()); client.announce(MaplePacketCreator.enableActions());
} }
+99 -40
View File
@@ -25,9 +25,13 @@ import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import tools.DatabaseConnection; import tools.DatabaseConnection;
import tools.MaplePacketCreator; import tools.MaplePacketCreator;
@@ -36,85 +40,140 @@ public final class MonsterBook {
private int normalCard = 0; private int normalCard = 0;
private int bookLevel = 1; private int bookLevel = 1;
private Map<Integer, Integer> cards = new LinkedHashMap<>(); private Map<Integer, Integer> cards = new LinkedHashMap<>();
private Lock lock = new ReentrantLock();
private Set<Entry<Integer, Integer>> getCardSet() {
lock.lock();
try {
return Collections.unmodifiableSet(cards.entrySet());
} finally {
lock.unlock();
}
}
public void addCard(final MapleClient c, final int cardid) { public void addCard(final MapleClient c, final int cardid) {
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showForeignCardEffect(c.getPlayer().getId()), false); c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showForeignCardEffect(c.getPlayer().getId()), false);
for (Entry<Integer, Integer> all : cards.entrySet()) {
if (all.getKey() == cardid) { Integer qty;
if (all.getValue() > 4) { lock.lock();
c.announce(MaplePacketCreator.addCard(true, cardid, all.getValue())); try {
qty = cards.get(cardid);
if(qty != null) {
if(qty < 5) {
cards.put(cardid, qty + 1);
}
} else {
cards.put(cardid, 1);
qty = 0;
if (cardid / 1000 >= 2388) {
specialCard++;
} else { } else {
all.setValue(all.getValue() + 1); normalCard++;
c.announce(MaplePacketCreator.addCard(false, cardid, all.getValue()));
c.announce(MaplePacketCreator.showGainCard());
calculateLevel();
} }
return;
} }
} finally {
lock.unlock();
} }
cards.put(cardid, 1);
c.announce(MaplePacketCreator.addCard(false, cardid, 1));
c.announce(MaplePacketCreator.showGainCard());
calculateLevel();
if (cardid / 1000 >= 2388) { if(qty < 5) {
specialCard++; calculateLevel(); // current leveling system only accounts unique cards...
c.announce(MaplePacketCreator.addCard(false, cardid, qty + 1));
c.announce(MaplePacketCreator.showGainCard());
} else { } else {
normalCard++; c.announce(MaplePacketCreator.addCard(true, cardid, 5));
} }
//c.getPlayer().saveToDB(); //is it REALLY needed to save to DB every new entry?
} }
private void calculateLevel() { private void calculateLevel() {
bookLevel = (int) Math.max(1, Math.sqrt((normalCard + specialCard) / 5)); lock.lock();
try {
bookLevel = (int) Math.max(1, Math.sqrt((normalCard + specialCard) / 5));
} finally {
lock.unlock();
}
} }
public int getBookLevel() { public int getBookLevel() {
return bookLevel; lock.lock();
try {
return bookLevel;
} finally {
lock.unlock();
}
} }
public Map<Integer, Integer> getCards() { public Map<Integer, Integer> getCards() {
return cards; lock.lock();
try {
return Collections.unmodifiableMap(cards);
} finally {
lock.unlock();
}
} }
public int getTotalCards() { public int getTotalCards() {
return specialCard + normalCard; lock.lock();
try {
return specialCard + normalCard;
} finally {
lock.unlock();
}
} }
public int getNormalCard() { public int getNormalCard() {
return normalCard; lock.lock();
try {
return normalCard;
} finally {
lock.unlock();
}
} }
public int getSpecialCard() { public int getSpecialCard() {
return specialCard; lock.lock();
try {
return specialCard;
} finally {
lock.unlock();
}
} }
public void loadCards(final int charid) throws SQLException { public void loadCards(final int charid) throws SQLException {
Connection con = DatabaseConnection.getConnection(); lock.lock();
try (PreparedStatement ps = con.prepareStatement("SELECT cardid, level FROM monsterbook WHERE charid = ? ORDER BY cardid ASC")) { try {
ps.setInt(1, charid); Connection con = DatabaseConnection.getConnection();
try (ResultSet rs = ps.executeQuery()) { try (PreparedStatement ps = con.prepareStatement("SELECT cardid, level FROM monsterbook WHERE charid = ? ORDER BY cardid ASC")) {
int cardid, level; ps.setInt(1, charid);
while (rs.next()) { try (ResultSet rs = ps.executeQuery()) {
cardid = rs.getInt("cardid"); int cardid, level;
level = rs.getInt("level"); while (rs.next()) {
if (cardid / 1000 >= 2388) { cardid = rs.getInt("cardid");
specialCard++; level = rs.getInt("level");
} else { if (cardid / 1000 >= 2388) {
normalCard++; specialCard++;
} else {
normalCard++;
}
cards.put(cardid, level);
} }
cards.put(cardid, level);
} }
} }
con.close();
} finally {
lock.unlock();
} }
con.close();
calculateLevel(); calculateLevel();
} }
public void saveCards(final int charid) { public void saveCards(final int charid) {
if (cards.isEmpty()) { Set<Entry<Integer, Integer>> cardSet = getCardSet();
if (cardSet.isEmpty()) {
return; return;
} }
try { try {
@@ -125,7 +184,7 @@ public final class MonsterBook {
ps.close(); ps.close();
boolean first = true; boolean first = true;
StringBuilder query = new StringBuilder(); StringBuilder query = new StringBuilder();
for (Entry<Integer, Integer> all : cards.entrySet()) { for (Entry<Integer, Integer> all : cardSet) {
if (first) { if (first) {
query.append("INSERT INTO monsterbook VALUES ("); query.append("INSERT INTO monsterbook VALUES (");
first = false; first = false;
-1
View File
@@ -141,7 +141,6 @@ public enum ItemFactory {
ResultSet rs = null; ResultSet rs = null;
lock.lock(); lock.lock();
try { try {
StringBuilder query = new StringBuilder(); StringBuilder query = new StringBuilder();
query.append("DELETE `inventoryitems`, `inventoryequipment` FROM `inventoryitems` LEFT JOIN `inventoryequipment` USING(`inventoryitemid`) WHERE `type` = ? AND `"); query.append("DELETE `inventoryitems`, `inventoryequipment` FROM `inventoryitems` LEFT JOIN `inventoryequipment` USING(`inventoryitemid`) WHERE `type` = ? AND `");
+131 -54
View File
@@ -29,6 +29,8 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Map; import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import tools.Pair; import tools.Pair;
import client.MapleCharacter; import client.MapleCharacter;
@@ -36,6 +38,7 @@ import client.MapleClient;
import constants.ItemConstants; import constants.ItemConstants;
import server.MapleItemInformationProvider; import server.MapleItemInformationProvider;
import server.MapleInventoryManipulator; import server.MapleInventoryManipulator;
import tools.FilePrinter;
/** /**
* *
@@ -47,6 +50,7 @@ public class MapleInventory implements Iterable<Item> {
private byte slotLimit; private byte slotLimit;
private MapleInventoryType type; private MapleInventoryType type;
private boolean checked = false; private boolean checked = false;
private Lock lock = new ReentrantLock();
public MapleInventory(MapleCharacter mc, MapleInventoryType type, byte slotLimit) { public MapleInventory(MapleCharacter mc, MapleInventoryType type, byte slotLimit) {
this.owner = mc; this.owner = mc;
@@ -64,15 +68,34 @@ public class MapleInventory implements Iterable<Item> {
} }
public byte getSlotLimit() { public byte getSlotLimit() {
return slotLimit; lock.lock();
try {
return slotLimit;
} finally {
lock.unlock();
}
} }
public void setSlotLimit(int newLimit) { public void setSlotLimit(int newLimit) {
slotLimit = (byte) newLimit; lock.lock();
try {
slotLimit = (byte) newLimit;
} finally {
lock.unlock();
}
} }
public Collection<Item> list() {
lock.lock();
try {
return Collections.unmodifiableCollection(inventory.values());
} finally {
lock.unlock();
}
}
public Item findById(int itemId) { public Item findById(int itemId) {
for (Item item : inventory.values()) { for (Item item : list()) {
if (item.getItemId() == itemId) { if (item.getItemId() == itemId) {
return item; return item;
} }
@@ -81,10 +104,10 @@ public class MapleInventory implements Iterable<Item> {
} }
public Item findByName(String name) { public Item findByName(String name) {
for (Item item : inventory.values()) { for (Item item : list()) {
String itemName = MapleItemInformationProvider.getInstance().getName(item.getItemId()); String itemName = MapleItemInformationProvider.getInstance().getName(item.getItemId());
if(itemName == null) { if(itemName == null) {
System.out.println("[CRITICAL] Item " + item.getItemId() + " has no name."); FilePrinter.printError(FilePrinter.EXCEPTION, "[CRITICAL] Item " + item.getItemId() + " has no name.");
continue; continue;
} }
@@ -97,7 +120,7 @@ public class MapleInventory implements Iterable<Item> {
public int countById(int itemId) { public int countById(int itemId) {
int qty = 0; int qty = 0;
for (Item item : inventory.values()) { for (Item item : list()) {
if (item.getItemId() == itemId) { if (item.getItemId() == itemId) {
qty += item.getQuantity(); qty += item.getQuantity();
} }
@@ -138,7 +161,7 @@ public class MapleInventory implements Iterable<Item> {
public List<Item> listById(int itemId) { public List<Item> listById(int itemId) {
List<Item> ret = new ArrayList<>(); List<Item> ret = new ArrayList<>();
for (Item item : inventory.values()) { for (Item item : list()) {
if (item.getItemId() == itemId) { if (item.getItemId() == itemId) {
ret.add(item); ret.add(item);
} }
@@ -149,10 +172,6 @@ public class MapleInventory implements Iterable<Item> {
return ret; return ret;
} }
public Collection<Item> list() {
return inventory.values();
}
public short addItem(Item item) { public short addItem(Item item) {
short slotId = getNextFreeSlot(); short slotId = getNextFreeSlot();
if (slotId < 0 || item == null) { if (slotId < 0 || item == null) {
@@ -171,29 +190,34 @@ public class MapleInventory implements Iterable<Item> {
} }
public void move(short sSlot, short dSlot, short slotMax) { public void move(short sSlot, short dSlot, short slotMax) {
Item source = (Item) inventory.get(sSlot); lock.lock();
Item target = (Item) inventory.get(dSlot); try {
if (source == null) { Item source = (Item) inventory.get(sSlot);
return; Item target = (Item) inventory.get(dSlot);
} if (source == null) {
if (target == null) { return;
source.setPosition(dSlot); }
inventory.put(dSlot, source); if (target == null) {
inventory.remove(sSlot); source.setPosition(dSlot);
} else if (target.getItemId() == source.getItemId() && !ItemConstants.isRechargable(source.getItemId())) { inventory.put(dSlot, source);
if (type.getType() == MapleInventoryType.EQUIP.getType()) { inventory.remove(sSlot);
} else if (target.getItemId() == source.getItemId() && !ItemConstants.isRechargable(source.getItemId())) {
if (type.getType() == MapleInventoryType.EQUIP.getType()) {
swap(target, source);
}
if (source.getQuantity() + target.getQuantity() > slotMax) {
short rest = (short) ((source.getQuantity() + target.getQuantity()) - slotMax);
source.setQuantity(rest);
target.setQuantity(slotMax);
} else {
target.setQuantity((short) (source.getQuantity() + target.getQuantity()));
inventory.remove(sSlot);
}
} else {
swap(target, source); swap(target, source);
} }
if (source.getQuantity() + target.getQuantity() > slotMax) { } finally {
short rest = (short) ((source.getQuantity() + target.getQuantity()) - slotMax); lock.unlock();
source.setQuantity(rest);
target.setQuantity(slotMax);
} else {
target.setQuantity((short) (source.getQuantity() + target.getQuantity()));
inventory.remove(sSlot);
}
} else {
swap(target, source);
} }
} }
@@ -208,7 +232,12 @@ public class MapleInventory implements Iterable<Item> {
} }
public Item getItem(short slot) { public Item getItem(short slot) {
return inventory.get(slot); lock.lock();
try {
return inventory.get(slot);
} finally {
lock.unlock();
}
} }
public void removeItem(short slot) { public void removeItem(short slot) {
@@ -216,7 +245,7 @@ public class MapleInventory implements Iterable<Item> {
} }
public void removeItem(short slot, short quantity, boolean allowZero) { public void removeItem(short slot, short quantity, boolean allowZero) {
Item item = inventory.get(slot); Item item = getItem(slot);
if (item == null) {// TODO is it ok not to throw an exception here? if (item == null) {// TODO is it ok not to throw an exception here?
return; return;
} }
@@ -230,7 +259,12 @@ public class MapleInventory implements Iterable<Item> {
} }
public void addSlot(short slot, Item item) { public void addSlot(short slot, Item item) {
inventory.put(slot, item); lock.lock();
try {
inventory.put(slot, item);
} finally {
lock.unlock();
}
if(ItemConstants.isRateCoupon(item.getItemId())) { if(ItemConstants.isRateCoupon(item.getItemId())) {
owner.updateCouponRates(); owner.updateCouponRates();
@@ -238,7 +272,13 @@ public class MapleInventory implements Iterable<Item> {
} }
public void removeSlot(short slot) { public void removeSlot(short slot) {
Item item = inventory.remove(slot); Item item;
lock.lock();
try {
item = inventory.remove(slot);
} finally {
lock.unlock();
}
if(item != null && ItemConstants.isRateCoupon(item.getItemId())) { if(item != null && ItemConstants.isRateCoupon(item.getItemId())) {
owner.updateCouponRates(); owner.updateCouponRates();
@@ -246,40 +286,67 @@ public class MapleInventory implements Iterable<Item> {
} }
public boolean isFull() { public boolean isFull() {
return inventory.size() >= slotLimit; lock.lock();
try {
return inventory.size() >= slotLimit;
} finally {
lock.unlock();
}
} }
public boolean isFull(int margin) { public boolean isFull(int margin) {
return inventory.size() + margin >= slotLimit; lock.lock();
try {
return inventory.size() + margin >= slotLimit;
} finally {
lock.unlock();
}
} }
public boolean isFullAfterSomeItems(int margin, int used) { public boolean isFullAfterSomeItems(int margin, int used) {
return inventory.size() + margin >= slotLimit - used; lock.lock();
try {
return inventory.size() + margin >= slotLimit - used;
} finally {
lock.unlock();
}
} }
public short getNextFreeSlot() { public short getNextFreeSlot() {
if (isFull()) { if (isFull()) {
return -1; return -1;
} }
for (short i = 1; i <= slotLimit; i++) {
if (!inventory.keySet().contains(i)) { lock.lock();
return i; try {
for (short i = 1; i <= slotLimit; i++) {
if (!inventory.containsKey(i)) {
return i;
}
} }
return -1;
} finally {
lock.unlock();
} }
return -1;
} }
public short getNumFreeSlot() { public short getNumFreeSlot() {
if (isFull()) { if (isFull()) {
return 0; return 0;
} }
short free = 0;
for (short i = 1; i <= slotLimit; i++) { lock.lock();
if (!inventory.keySet().contains(i)) { try {
free++; short free = 0;
} for (short i = 1; i <= slotLimit; i++) {
} if (!inventory.containsKey(i)) {
return free; free++;
}
}
return free;
} finally {
lock.unlock();
}
} }
public static boolean checkSpot(MapleCharacter chr, Item item) { public static boolean checkSpot(MapleCharacter chr, Item item) {
@@ -394,7 +461,7 @@ public class MapleInventory implements Iterable<Item> {
@Override @Override
public Iterator<Item> iterator() { public Iterator<Item> iterator() {
return Collections.unmodifiableCollection(inventory.values()).iterator(); return Collections.unmodifiableCollection(list()).iterator();
} }
public Collection<MapleInventory> allInventories() { public Collection<MapleInventory> allInventories() {
@@ -404,7 +471,7 @@ public class MapleInventory implements Iterable<Item> {
public Item findByCashId(int cashId) { public Item findByCashId(int cashId) {
boolean isRing = false; boolean isRing = false;
Equip equip = null; Equip equip = null;
for (Item item : inventory.values()) { for (Item item : list()) {
if (item.getType() == MapleInventoryType.EQUIP.getType()) { if (item.getType() == MapleInventoryType.EQUIP.getType()) {
equip = (Equip) item; equip = (Equip) item;
isRing = equip.getRingId() > -1; isRing = equip.getRingId() > -1;
@@ -417,10 +484,20 @@ public class MapleInventory implements Iterable<Item> {
} }
public boolean checked() { public boolean checked() {
return checked; lock.lock();
try {
return checked;
} finally {
lock.unlock();
}
} }
public void checked(boolean yes) { public void checked(boolean yes) {
checked = yes; lock.lock();
try {
checked = yes;
} finally {
lock.unlock();
}
} }
} }
+1
View File
@@ -44,6 +44,7 @@ public class ServerConstants {
public static final boolean USE_ITEM_SORT_BY_NAME = false; //Item sorting based on name rather than id. public static final boolean USE_ITEM_SORT_BY_NAME = false; //Item sorting based on name rather than id.
public static final boolean USE_PARTY_SEARCH = false; public static final boolean USE_PARTY_SEARCH = false;
public static final boolean USE_AUTOBAN = false; //Commands the server to detect infractors automatically. public static final boolean USE_AUTOBAN = false; //Commands the server to detect infractors automatically.
public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly to required secondary stat on equipments. public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly to required secondary stat on equipments.
public static final boolean USE_REFRESH_RANK_MOVE = true; public static final boolean USE_REFRESH_RANK_MOVE = true;
public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster) public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster)
@@ -0,0 +1,50 @@
/*
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 net.server;
import net.server.world.World;
import client.MapleCharacter;
import constants.ServerConstants;
/**
* @author Ronan
*/
public class CharacterAutosaverWorker implements Runnable {
private World wserv;
@Override
public void run() {
if(!ServerConstants.USE_AUTOSAVE) return;
PlayerStorage ps = wserv.getPlayerStorage();
for(MapleCharacter chr: ps.getAllCharacters()) {
if(chr != null && chr.isLoggedin()) {
chr.saveToDB(false);
}
}
}
public CharacterAutosaverWorker(World world) {
wserv = world;
}
}
@@ -61,7 +61,6 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
Server.getInstance().getPlayerBuffStorage().addBuffsToStorage(chr.getId(), chr.getAllBuffs()); Server.getInstance().getPlayerBuffStorage().addBuffsToStorage(chr.getId(), chr.getAllBuffs());
chr.cancelExpirationTask(); chr.cancelExpirationTask();
chr.saveToDB(); chr.saveToDB();
System.out.println("STRANGE SAVE TO DB");
chr.getMap().removePlayer(c.getPlayer()); chr.getMap().removePlayer(c.getPlayer());
try { try {
c.announce(MaplePacketCreator.openCashShop(c, true)); c.announce(MaplePacketCreator.openCashShop(c, true));
@@ -90,7 +90,8 @@ public final class SpawnPetHandler extends AbstractMaplePacketHandler {
chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), pet, false, false), true); chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), pet, false, false), true);
c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer())); c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer()));
c.announce(MaplePacketCreator.enableActions()); c.announce(MaplePacketCreator.enableActions());
chr.commitExcludedItems();
chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(pet)); chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(pet));
} }
} }
+6 -2
View File
@@ -45,8 +45,9 @@ import java.util.HashSet;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import server.TimerManager; import server.TimerManager;
import net.server.PetFullnessWorker; import net.server.CharacterAutosaverWorker;
import net.server.MountTirednessWorker; import net.server.MountTirednessWorker;
import net.server.PetFullnessWorker;
import net.server.PlayerStorage; import net.server.PlayerStorage;
import net.server.Server; import net.server.Server;
import net.server.channel.Channel; import net.server.channel.Channel;
@@ -82,7 +83,9 @@ public class World {
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>(); private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
private ScheduledFuture<?> mountsSchedule; private ScheduledFuture<?> mountsSchedule;
private long mountUpdate; private long mountUpdate;
private ScheduledFuture<?> charactersSchedule;
public World(int world, int flag, String eventmsg, int exprate, int droprate, int mesorate, int bossdroprate) { public World(int world, int flag, String eventmsg, int exprate, int droprate, int mesorate, int bossdroprate) {
this.id = world; this.id = world;
this.flag = flag; this.flag = flag;
@@ -99,6 +102,7 @@ public class World {
petsSchedule = TimerManager.getInstance().register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000); petsSchedule = TimerManager.getInstance().register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000);
mountsSchedule = TimerManager.getInstance().register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000); mountsSchedule = TimerManager.getInstance().register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000);
charactersSchedule = TimerManager.getInstance().register(new CharacterAutosaverWorker(this), 60 * 60 * 1000, 60 * 60 * 1000);
} }
public List<Channel> getChannels() { public List<Channel> getChannels() {
+33 -12
View File
@@ -30,6 +30,8 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import provider.MapleData; import provider.MapleData;
import provider.MapleDataProvider; import provider.MapleDataProvider;
@@ -43,6 +45,7 @@ import client.inventory.ItemFactory;
import client.inventory.MapleInventoryType; import client.inventory.MapleInventoryType;
import client.inventory.MaplePet; import client.inventory.MaplePet;
import constants.ItemConstants; import constants.ItemConstants;
import java.util.Collections;
/* /*
* @author Flav * @author Flav
@@ -99,12 +102,13 @@ public class CashShop {
item = new Item(itemId, (byte) 0, count, petid); item = new Item(itemId, (byte) 0, count, petid);
} }
if (ItemConstants.EXPIRING_ITEMS) if (ItemConstants.EXPIRING_ITEMS) {
if(itemId == 5211048 || itemId == 5360042) { // 4 Hour 2X coupons, the period is 1, but we don't want them to last a day. if(itemId == 5211048 || itemId == 5360042) { // 4 Hour 2X coupons, the period is 1, but we don't want them to last a day.
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 4)); item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 4));
} else { } else {
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * period)); item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * period));
} }
}
item.setSN(sn); item.setSN(sn);
return item; return item;
} }
@@ -237,6 +241,7 @@ public class CashShop {
private List<Item> inventory = new ArrayList<>(); private List<Item> inventory = new ArrayList<>();
private List<Integer> wishList = new ArrayList<>(); private List<Integer> wishList = new ArrayList<>();
private int notes = 0; private int notes = 0;
private Lock lock = new ReentrantLock();
public CashShop(int accountId, int characterId, int jobType) throws SQLException { public CashShop(int accountId, int characterId, int jobType) throws SQLException {
this.accountId = accountId; this.accountId = accountId;
@@ -325,13 +330,18 @@ public class CashShop {
} }
public List<Item> getInventory() { public List<Item> getInventory() {
return inventory; lock.lock();
try {
return Collections.unmodifiableList(inventory);
} finally {
lock.unlock();
}
} }
public Item findByCashId(int cashId) { public Item findByCashId(int cashId) {
boolean isRing = false; boolean isRing = false;
Equip equip = null; Equip equip = null;
for (Item item : inventory) { for (Item item : getInventory()) {
if (item.getType() == 1) { if (item.getType() == 1) {
equip = (Equip) item; equip = (Equip) item;
isRing = equip.getRingId() > -1; isRing = equip.getRingId() > -1;
@@ -345,11 +355,21 @@ public class CashShop {
} }
public void addToInventory(Item item) { public void addToInventory(Item item) {
inventory.add(item); lock.lock();
try {
inventory.add(item);
} finally {
lock.unlock();
}
} }
public void removeFromInventory(Item item) { public void removeFromInventory(Item item) {
inventory.remove(item); lock.lock();
try {
inventory.remove(item);
} finally {
lock.unlock();
}
} }
public List<Integer> getWishList() { public List<Integer> getWishList() {
@@ -458,7 +478,8 @@ public class CashShop {
ps.close(); ps.close();
List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>(); List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>();
for (Item item : inventory) { List<Item> inv = getInventory();
for (Item item : inv) {
itemsWithType.add(new Pair<>(item, MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId()))); itemsWithType.add(new Pair<>(item, MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId())));
} }
@@ -466,7 +487,7 @@ public class CashShop {
ps = con.prepareStatement("DELETE FROM `wishlists` WHERE `charid` = ?"); ps = con.prepareStatement("DELETE FROM `wishlists` WHERE `charid` = ?");
ps.setInt(1, characterId); ps.setInt(1, characterId);
ps.executeUpdate(); ps.executeUpdate();
ps.close(); ps.close();
ps = con.prepareStatement("INSERT INTO `wishlists` VALUES (DEFAULT, ?, ?)"); ps = con.prepareStatement("INSERT INTO `wishlists` VALUES (DEFAULT, ?, ?)");
ps.setInt(1, characterId); ps.setInt(1, characterId);
+66 -22
View File
@@ -36,6 +36,8 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import tools.DatabaseConnection; import tools.DatabaseConnection;
import tools.MaplePacketCreator; import tools.MaplePacketCreator;
import tools.Pair; import tools.Pair;
@@ -47,10 +49,11 @@ import tools.Pair;
public class MapleStorage { public class MapleStorage {
private int id; private int id;
private List<Item> items;
private int meso; private int meso;
private byte slots; private byte slots;
private Map<MapleInventoryType, List<Item>> typeItems = new HashMap<>(); private Map<MapleInventoryType, List<Item>> typeItems = new HashMap<>();
private List<Item> items;
private Lock lock = new ReentrantLock();
private MapleStorage(int id, byte slots, int meso) { private MapleStorage(int id, byte slots, int meso) {
this.id = id; this.id = id;
@@ -135,7 +138,8 @@ public class MapleStorage {
} }
List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>(); List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>();
for (Item item : items) { List<Item> list = getItems();
for (Item item : list) {
itemsWithType.add(new Pair<>(item, MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId()))); itemsWithType.add(new Pair<>(item, MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId())));
} }
@@ -146,30 +150,56 @@ public class MapleStorage {
} }
public Item getItem(byte slot) { public Item getItem(byte slot) {
return items.get(slot); lock.lock();
try {
return items.get(slot);
} finally {
lock.unlock();
}
} }
public Item takeOut(byte slot) { public Item takeOut(byte slot) {
Item ret = items.remove(slot); Item ret;
lock.lock();
try {
ret = items.remove(slot);
} finally {
lock.unlock();
}
MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(ret.getItemId()); MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(ret.getItemId());
typeItems.put(type, new ArrayList<>(filterItems(type))); typeItems.put(type, new ArrayList<>(filterItems(type)));
return ret; return ret;
} }
public void store(Item item) { public void store(Item item) {
items.add(item); lock.lock();
try {
items.add(item);
} finally {
lock.unlock();
}
MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId()); MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId());
typeItems.put(type, new ArrayList<>(filterItems(type))); typeItems.put(type, new ArrayList<>(filterItems(type)));
} }
public List<Item> getItems() { public List<Item> getItems() {
return Collections.unmodifiableList(items); lock.lock();
try {
return Collections.unmodifiableList(items);
} finally {
lock.unlock();
}
} }
private List<Item> filterItems(MapleInventoryType type) { private List<Item> filterItems(MapleInventoryType type) {
List<Item> storageItems = getItems();
List<Item> ret = new LinkedList<>(); List<Item> ret = new LinkedList<>();
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
for (Item item : items) {
for (Item item : storageItems) {
if (ii.getInventoryType(item.getItemId()) == type) { if (ii.getInventoryType(item.getItemId()) == type) {
ret.add(item); ret.add(item);
} }
@@ -179,7 +209,8 @@ public class MapleStorage {
public byte getSlot(MapleInventoryType type, byte slot) { public byte getSlot(MapleInventoryType type, byte slot) {
byte ret = 0; byte ret = 0;
for (Item item : items) { List<Item> storageItems = getItems();
for (Item item : storageItems) {
if (item == typeItems.get(type).get(slot)) { if (item == typeItems.get(type).get(slot)) {
return ret; return ret;
} }
@@ -190,21 +221,29 @@ public class MapleStorage {
public void sendStorage(MapleClient c, int npcId) { public void sendStorage(MapleClient c, int npcId) {
final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
Collections.sort(items, new Comparator<Item>() {
@Override lock.lock();
public int compare(Item o1, Item o2) { try {
if (ii.getInventoryType(o1.getItemId()).getType() < ii.getInventoryType(o2.getItemId()).getType()) { Collections.sort(items, new Comparator<Item>() {
return -1; @Override
} else if (ii.getInventoryType(o1.getItemId()) == ii.getInventoryType(o2.getItemId())) { public int compare(Item o1, Item o2) {
return 0; if (ii.getInventoryType(o1.getItemId()).getType() < ii.getInventoryType(o2.getItemId()).getType()) {
return -1;
} else if (ii.getInventoryType(o1.getItemId()) == ii.getInventoryType(o2.getItemId())) {
return 0;
}
return 1;
} }
return 1; });
} } finally {
}); lock.unlock();
for (MapleInventoryType type : MapleInventoryType.values()) {
typeItems.put(type, new ArrayList<>(items));
} }
c.announce(MaplePacketCreator.getStorage(npcId, slots, items, meso));
List<Item> storageItems = getItems();
for (MapleInventoryType type : MapleInventoryType.values()) {
typeItems.put(type, new ArrayList<>(storageItems));
}
c.announce(MaplePacketCreator.getStorage(npcId, slots, storageItems, meso));
} }
public void sendStored(MapleClient c, MapleInventoryType type) { public void sendStored(MapleClient c, MapleInventoryType type) {
@@ -231,7 +270,12 @@ public class MapleStorage {
} }
public boolean isFull() { public boolean isFull() {
return items.size() >= slots; lock.lock();
try {
return items.size() >= slots;
} finally {
lock.unlock();
}
} }
public void close() { public void close() {
+93 -86
View File
@@ -55,100 +55,107 @@ public class MapleLifeFactory {
} }
public static MapleMonster getMonster(int mid) { public static MapleMonster getMonster(int mid) {
MapleMonsterStats stats = monsterStats.get(Integer.valueOf(mid)); try {
if (stats == null) { MapleMonsterStats stats = monsterStats.get(Integer.valueOf(mid));
MapleData monsterData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(mid) + ".img", '0', 11)); if (stats == null) {
if (monsterData == null) { MapleData monsterData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(mid) + ".img", '0', 11));
return null; if (monsterData == null) {
} return null;
MapleData monsterInfoData = monsterData.getChildByPath("info");
stats = new MapleMonsterStats();
stats.setHp(MapleDataTool.getIntConvert("maxHP", monsterInfoData));
stats.setFriendly(MapleDataTool.getIntConvert("damagedByMob", monsterInfoData, 0) == 1);
stats.setPADamage(MapleDataTool.getIntConvert("PADamage", monsterInfoData));
stats.setPDDamage(MapleDataTool.getIntConvert("PDDamage", monsterInfoData));
stats.setMADamage(MapleDataTool.getIntConvert("MADamage", monsterInfoData));
stats.setMDDamage(MapleDataTool.getIntConvert("MDDamage", monsterInfoData));
stats.setMp(MapleDataTool.getIntConvert("maxMP", monsterInfoData, 0));
stats.setExp(MapleDataTool.getIntConvert("exp", monsterInfoData, 0));
stats.setLevel(MapleDataTool.getIntConvert("level", monsterInfoData));
stats.setRemoveAfter(MapleDataTool.getIntConvert("removeAfter", monsterInfoData, 0));
stats.setBoss(MapleDataTool.getIntConvert("boss", monsterInfoData, 0) > 0);
stats.setExplosiveReward(MapleDataTool.getIntConvert("explosiveReward", monsterInfoData, 0) > 0);
stats.setFfaLoot(MapleDataTool.getIntConvert("publicReward", monsterInfoData, 0) > 0);
stats.setUndead(MapleDataTool.getIntConvert("undead", monsterInfoData, 0) > 0);
stats.setName(MapleDataTool.getString(mid + "/name", mobStringData, "MISSINGNO"));
stats.setBuffToGive(MapleDataTool.getIntConvert("buff", monsterInfoData, -1));
stats.setCP(MapleDataTool.getIntConvert("getCP", monsterInfoData, 0));
stats.setRemoveOnMiss(MapleDataTool.getIntConvert("removeOnMiss", monsterInfoData, 0) > 0);
MapleData special = monsterInfoData.getChildByPath("coolDamage");
if (special != null) {
int coolDmg = MapleDataTool.getIntConvert("coolDamage", monsterInfoData);
int coolProb = MapleDataTool.getIntConvert("coolDamageProb", monsterInfoData, 0);
stats.setCool(new Pair<>(coolDmg, coolProb));
}
special = monsterInfoData.getChildByPath("loseItem");
if (special != null) {
for (MapleData liData : special.getChildren()) {
stats.addLoseItem(new loseItem(MapleDataTool.getInt(liData.getChildByPath("id")), (byte) MapleDataTool.getInt(liData.getChildByPath("prop")), (byte) MapleDataTool.getInt(liData.getChildByPath("x"))));
} }
} MapleData monsterInfoData = monsterData.getChildByPath("info");
special = monsterInfoData.getChildByPath("selfDestruction"); stats = new MapleMonsterStats();
if (special != null) { stats.setHp(MapleDataTool.getIntConvert("maxHP", monsterInfoData));
stats.setSelfDestruction(new selfDestruction((byte) MapleDataTool.getInt(special.getChildByPath("action")), MapleDataTool.getIntConvert("removeAfter", special, -1), MapleDataTool.getIntConvert("hp", special, -1))); stats.setFriendly(MapleDataTool.getIntConvert("damagedByMob", monsterInfoData, 0) == 1);
} stats.setPADamage(MapleDataTool.getIntConvert("PADamage", monsterInfoData));
MapleData firstAttackData = monsterInfoData.getChildByPath("firstAttack"); stats.setPDDamage(MapleDataTool.getIntConvert("PDDamage", monsterInfoData));
int firstAttack = 0; stats.setMADamage(MapleDataTool.getIntConvert("MADamage", monsterInfoData));
if (firstAttackData != null) { stats.setMDDamage(MapleDataTool.getIntConvert("MDDamage", monsterInfoData));
if (firstAttackData.getType() == MapleDataType.FLOAT) { stats.setMp(MapleDataTool.getIntConvert("maxMP", monsterInfoData, 0));
firstAttack = Math.round(MapleDataTool.getFloat(firstAttackData)); stats.setExp(MapleDataTool.getIntConvert("exp", monsterInfoData, 0));
} else { stats.setLevel(MapleDataTool.getIntConvert("level", monsterInfoData));
firstAttack = MapleDataTool.getInt(firstAttackData); stats.setRemoveAfter(MapleDataTool.getIntConvert("removeAfter", monsterInfoData, 0));
} stats.setBoss(MapleDataTool.getIntConvert("boss", monsterInfoData, 0) > 0);
} stats.setExplosiveReward(MapleDataTool.getIntConvert("explosiveReward", monsterInfoData, 0) > 0);
stats.setFirstAttack(firstAttack > 0); stats.setFfaLoot(MapleDataTool.getIntConvert("publicReward", monsterInfoData, 0) > 0);
stats.setDropPeriod(MapleDataTool.getIntConvert("dropItemPeriod", monsterInfoData, 0) * 10000); stats.setUndead(MapleDataTool.getIntConvert("undead", monsterInfoData, 0) > 0);
stats.setName(MapleDataTool.getString(mid + "/name", mobStringData, "MISSINGNO"));
stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0)); stats.setBuffToGive(MapleDataTool.getIntConvert("buff", monsterInfoData, -1));
stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0)); stats.setCP(MapleDataTool.getIntConvert("getCP", monsterInfoData, 0));
stats.setRemoveOnMiss(MapleDataTool.getIntConvert("removeOnMiss", monsterInfoData, 0) > 0);
for (MapleData idata : monsterData) { MapleData special = monsterInfoData.getChildByPath("coolDamage");
if (!idata.getName().equals("info")) { if (special != null) {
int delay = 0; int coolDmg = MapleDataTool.getIntConvert("coolDamage", monsterInfoData);
for (MapleData pic : idata.getChildren()) { int coolProb = MapleDataTool.getIntConvert("coolDamageProb", monsterInfoData, 0);
delay += MapleDataTool.getIntConvert("delay", pic, 0); stats.setCool(new Pair<>(coolDmg, coolProb));
}
special = monsterInfoData.getChildByPath("loseItem");
if (special != null) {
for (MapleData liData : special.getChildren()) {
stats.addLoseItem(new loseItem(MapleDataTool.getInt(liData.getChildByPath("id")), (byte) MapleDataTool.getInt(liData.getChildByPath("prop")), (byte) MapleDataTool.getInt(liData.getChildByPath("x"))));
} }
stats.setAnimationTime(idata.getName(), delay);
} }
} special = monsterInfoData.getChildByPath("selfDestruction");
MapleData reviveInfo = monsterInfoData.getChildByPath("revive"); if (special != null) {
if (reviveInfo != null) { stats.setSelfDestruction(new selfDestruction((byte) MapleDataTool.getInt(special.getChildByPath("action")), MapleDataTool.getIntConvert("removeAfter", special, -1), MapleDataTool.getIntConvert("hp", special, -1)));
List<Integer> revives = new LinkedList<>();
for (MapleData data_ : reviveInfo) {
revives.add(MapleDataTool.getInt(data_));
} }
stats.setRevives(revives); MapleData firstAttackData = monsterInfoData.getChildByPath("firstAttack");
} int firstAttack = 0;
decodeElementalString(stats, MapleDataTool.getString("elemAttr", monsterInfoData, "")); if (firstAttackData != null) {
MapleData monsterSkillData = monsterInfoData.getChildByPath("skill"); if (firstAttackData.getType() == MapleDataType.FLOAT) {
if (monsterSkillData != null) { firstAttack = Math.round(MapleDataTool.getFloat(firstAttackData));
int i = 0; } else {
List<Pair<Integer, Integer>> skills = new ArrayList<>(); firstAttack = MapleDataTool.getInt(firstAttackData);
while (monsterSkillData.getChildByPath(Integer.toString(i)) != null) { }
skills.add(new Pair<>(Integer.valueOf(MapleDataTool.getInt(i + "/skill", monsterSkillData, 0)), Integer.valueOf(MapleDataTool.getInt(i + "/level", monsterSkillData, 0))));
i++;
} }
stats.setSkills(skills); stats.setFirstAttack(firstAttack > 0);
stats.setDropPeriod(MapleDataTool.getIntConvert("dropItemPeriod", monsterInfoData, 0) * 10000);
stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0));
stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0));
for (MapleData idata : monsterData) {
if (!idata.getName().equals("info")) {
int delay = 0;
for (MapleData pic : idata.getChildren()) {
delay += MapleDataTool.getIntConvert("delay", pic, 0);
}
stats.setAnimationTime(idata.getName(), delay);
}
}
MapleData reviveInfo = monsterInfoData.getChildByPath("revive");
if (reviveInfo != null) {
List<Integer> revives = new LinkedList<>();
for (MapleData data_ : reviveInfo) {
revives.add(MapleDataTool.getInt(data_));
}
stats.setRevives(revives);
}
decodeElementalString(stats, MapleDataTool.getString("elemAttr", monsterInfoData, ""));
MapleData monsterSkillData = monsterInfoData.getChildByPath("skill");
if (monsterSkillData != null) {
int i = 0;
List<Pair<Integer, Integer>> skills = new ArrayList<>();
while (monsterSkillData.getChildByPath(Integer.toString(i)) != null) {
skills.add(new Pair<>(Integer.valueOf(MapleDataTool.getInt(i + "/skill", monsterSkillData, 0)), Integer.valueOf(MapleDataTool.getInt(i + "/level", monsterSkillData, 0))));
i++;
}
stats.setSkills(skills);
}
MapleData banishData = monsterInfoData.getChildByPath("ban");
if (banishData != null) {
stats.setBanishInfo(new BanishInfo(MapleDataTool.getString("banMsg", banishData), MapleDataTool.getInt("banMap/0/field", banishData, -1), MapleDataTool.getString("banMap/0/portal", banishData, "sp")));
}
monsterStats.put(Integer.valueOf(mid), stats);
} }
MapleData banishData = monsterInfoData.getChildByPath("ban"); MapleMonster ret = new MapleMonster(mid, stats);
if (banishData != null) { return ret;
stats.setBanishInfo(new BanishInfo(MapleDataTool.getString("banMsg", banishData), MapleDataTool.getInt("banMap/0/field", banishData, -1), MapleDataTool.getString("banMap/0/portal", banishData, "sp"))); } catch(NullPointerException npe) {
} System.out.println("[SEVERE] MOB " + mid + " failed to load. Issue: " + npe.getMessage() + "\n\n");
monsterStats.put(Integer.valueOf(mid), stats); npe.printStackTrace();
return null;
} }
MapleMonster ret = new MapleMonster(mid, stats);
return ret;
} }
private static void decodeElementalString(MapleMonsterStats stats, String elemAttr) { private static void decodeElementalString(MapleMonsterStats stats, String elemAttr) {
+2 -2
View File
@@ -2325,11 +2325,11 @@ public class MapleMap {
} }
public void setMapPointBoundings(int px, int py, int h, int w) { public void setMapPointBoundings(int px, int py, int h, int w) {
mapArea.setBounds(px, py, w, h); mapArea.setBounds(px + 7, py, w - 14, h);
} }
public void setMapLineBoundings(int vrTop, int vrBottom, int vrLeft, int vrRight) { public void setMapLineBoundings(int vrTop, int vrBottom, int vrLeft, int vrRight) {
mapArea.setBounds(vrLeft, vrTop, vrRight - vrLeft, vrBottom - vrTop); mapArea.setBounds(vrLeft + 7, vrTop, vrRight - vrLeft - 14, vrBottom - vrTop);
} }
/** /**
+1
View File
@@ -41,6 +41,7 @@ public class FilePrinter {
FREDRICK = "fredrick/", FREDRICK = "fredrick/",
NPC_UNCODED = "uncodedNPCs.txt", NPC_UNCODED = "uncodedNPCs.txt",
QUEST_UNCODED = "uncodedQuests.txt", QUEST_UNCODED = "uncodedQuests.txt",
AUTOSAVING_CHARACTER = "saveCharAuto.txt",
SAVING_CHARACTER = "saveChar.txt", SAVING_CHARACTER = "saveChar.txt",
USED_COMMANDS = "usedCommands.txt";//more to come (maps) USED_COMMANDS = "usedCommands.txt";//more to come (maps)