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:
@@ -1,4 +1,4 @@
|
||||
#Thu, 07 Sep 2017 21:09:39 -0300
|
||||
#Mon, 11 Sep 2017 16:18:43 -0300
|
||||
|
||||
|
||||
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.
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.
Vendored
BIN
Binary file not shown.
@@ -520,4 +520,11 @@ Corrigido itens saindo para fora do mapa. Nova posi
|
||||
|
||||
07 Setembro 2017,
|
||||
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.
|
||||
@@ -2,6 +2,29 @@
|
||||
<project-private xmlns="http://www.netbeans.org/ns/project-private/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">
|
||||
<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>
|
||||
</project-private>
|
||||
|
||||
@@ -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";
|
||||
for (var i = 0; i < belts.length; i++) {
|
||||
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
|
||||
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().getLevel() > level) {
|
||||
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!");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -22,7 +22,7 @@ function action(mode, type, selection) {
|
||||
else
|
||||
status--;
|
||||
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.dispose();
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -21222,7 +21222,7 @@ INSERT INTO `shopitems` ( `shopid`, `itemid`, `price`, `position`) VALUES
|
||||
(1052116, 2000002, 320, 212),
|
||||
(1052116, 2000001, 160, 216),
|
||||
(1052116, 2000000, 50, 220),
|
||||
(9120002, 2061003, 40, 0, 100);
|
||||
(9120002, 2061003, 40, 100);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `skillmacros` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
@@ -4529,26 +4529,31 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
}
|
||||
|
||||
PreparedStatement ps2;
|
||||
ResultSet rs2;
|
||||
for(byte i = 0; i < 3; i++) {
|
||||
MaplePet pet = ret.getPet(i);
|
||||
if(pet == null) continue;
|
||||
|
||||
int petId = pet.getUniqueId();
|
||||
ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?"); // Get pet details..
|
||||
PreparedStatement ps2, ps3;
|
||||
ResultSet rs2, rs3;
|
||||
|
||||
ps3 = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid > -1");
|
||||
ps3.setInt(1, charid);
|
||||
rs3 = ps3.executeQuery();
|
||||
while(rs3.next()) {
|
||||
int petId = rs3.getInt("petid");
|
||||
|
||||
ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?");
|
||||
ps2.setInt(1, petId);
|
||||
|
||||
|
||||
ret.resetExcluded(petId);
|
||||
|
||||
rs2 = ps2.executeQuery();
|
||||
while(rs2.next()) {
|
||||
ret.addExcluded(petId, rs2.getInt("itemid"));
|
||||
}
|
||||
|
||||
|
||||
ps2.close();
|
||||
rs2.close();
|
||||
}
|
||||
ps3.close();
|
||||
rs3.close();
|
||||
|
||||
ret.commitExcludedItems();
|
||||
|
||||
if (channelserver) {
|
||||
@@ -5525,10 +5530,28 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
}
|
||||
|
||||
// synchronize this call instead of trying to give access all at once (?)
|
||||
public synchronized void saveToDB() {
|
||||
public 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();
|
||||
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;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
@@ -5577,7 +5600,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
ps.setInt(22, meso.get());
|
||||
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);
|
||||
} else {
|
||||
MaplePortal closest = map.findClosestPlayerSpawnpoint(getPosition());
|
||||
@@ -5648,7 +5671,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
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=?")) {
|
||||
ps2.setInt(1, es.getKey());
|
||||
ps2.executeUpdate();
|
||||
@@ -5667,8 +5690,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
deleteWhereCharacterId(con, "DELETE FROM keymap WHERE characterid = ?");
|
||||
ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)");
|
||||
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(4, keybinding.getValue().getAction());
|
||||
ps.addBatch();
|
||||
@@ -5691,14 +5716,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
}
|
||||
ps.executeBatch();
|
||||
|
||||
List<Pair<Item, MapleInventoryType>> itemsWithType = new ArrayList<>();
|
||||
|
||||
for (MapleInventory iv : inventory) {
|
||||
for (Item item : iv.list()) {
|
||||
itemsWithType.add(new Pair<>(item, iv.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
ItemFactory.INVENTORY.saveItems(itemsWithType, id, con);
|
||||
|
||||
deleteWhereCharacterId(con, "DELETE FROM skills WHERE characterid = ?");
|
||||
@@ -6283,7 +6307,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
if (slots <= 96) {
|
||||
inventory[type].setSlotLimit(slots);
|
||||
|
||||
saveToDB();
|
||||
this.saveToDB();
|
||||
if (update) {
|
||||
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);
|
||||
|
||||
removePet(pet, shift_left);
|
||||
commitExcludedItems();
|
||||
|
||||
client.announce(MaplePacketCreator.petStatUpdate(this));
|
||||
client.announce(MaplePacketCreator.enableActions());
|
||||
}
|
||||
|
||||
+99
-40
@@ -25,9 +25,13 @@ import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
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.MaplePacketCreator;
|
||||
|
||||
@@ -36,85 +40,140 @@ public final class MonsterBook {
|
||||
private int normalCard = 0;
|
||||
private int bookLevel = 1;
|
||||
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) {
|
||||
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showForeignCardEffect(c.getPlayer().getId()), false);
|
||||
for (Entry<Integer, Integer> all : cards.entrySet()) {
|
||||
if (all.getKey() == cardid) {
|
||||
if (all.getValue() > 4) {
|
||||
c.announce(MaplePacketCreator.addCard(true, cardid, all.getValue()));
|
||||
|
||||
Integer qty;
|
||||
lock.lock();
|
||||
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 {
|
||||
all.setValue(all.getValue() + 1);
|
||||
c.announce(MaplePacketCreator.addCard(false, cardid, all.getValue()));
|
||||
c.announce(MaplePacketCreator.showGainCard());
|
||||
calculateLevel();
|
||||
normalCard++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
cards.put(cardid, 1);
|
||||
c.announce(MaplePacketCreator.addCard(false, cardid, 1));
|
||||
c.announce(MaplePacketCreator.showGainCard());
|
||||
calculateLevel();
|
||||
|
||||
if (cardid / 1000 >= 2388) {
|
||||
specialCard++;
|
||||
if(qty < 5) {
|
||||
calculateLevel(); // current leveling system only accounts unique cards...
|
||||
|
||||
c.announce(MaplePacketCreator.addCard(false, cardid, qty + 1));
|
||||
c.announce(MaplePacketCreator.showGainCard());
|
||||
} 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() {
|
||||
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() {
|
||||
return bookLevel;
|
||||
lock.lock();
|
||||
try {
|
||||
return bookLevel;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Integer, Integer> getCards() {
|
||||
return cards;
|
||||
lock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableMap(cards);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getTotalCards() {
|
||||
return specialCard + normalCard;
|
||||
lock.lock();
|
||||
try {
|
||||
return specialCard + normalCard;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getNormalCard() {
|
||||
return normalCard;
|
||||
lock.lock();
|
||||
try {
|
||||
return normalCard;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getSpecialCard() {
|
||||
return specialCard;
|
||||
lock.lock();
|
||||
try {
|
||||
return specialCard;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadCards(final int charid) throws SQLException {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (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, level;
|
||||
while (rs.next()) {
|
||||
cardid = rs.getInt("cardid");
|
||||
level = rs.getInt("level");
|
||||
if (cardid / 1000 >= 2388) {
|
||||
specialCard++;
|
||||
} else {
|
||||
normalCard++;
|
||||
lock.lock();
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (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, level;
|
||||
while (rs.next()) {
|
||||
cardid = rs.getInt("cardid");
|
||||
level = rs.getInt("level");
|
||||
if (cardid / 1000 >= 2388) {
|
||||
specialCard++;
|
||||
} else {
|
||||
normalCard++;
|
||||
}
|
||||
cards.put(cardid, level);
|
||||
}
|
||||
cards.put(cardid, level);
|
||||
}
|
||||
}
|
||||
|
||||
con.close();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
con.close();
|
||||
calculateLevel();
|
||||
}
|
||||
|
||||
public void saveCards(final int charid) {
|
||||
if (cards.isEmpty()) {
|
||||
Set<Entry<Integer, Integer>> cardSet = getCardSet();
|
||||
|
||||
if (cardSet.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -125,7 +184,7 @@ public final class MonsterBook {
|
||||
ps.close();
|
||||
boolean first = true;
|
||||
StringBuilder query = new StringBuilder();
|
||||
for (Entry<Integer, Integer> all : cards.entrySet()) {
|
||||
for (Entry<Integer, Integer> all : cardSet) {
|
||||
if (first) {
|
||||
query.append("INSERT INTO monsterbook VALUES (");
|
||||
first = false;
|
||||
|
||||
@@ -141,7 +141,6 @@ public enum ItemFactory {
|
||||
ResultSet rs = null;
|
||||
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("DELETE `inventoryitems`, `inventoryequipment` FROM `inventoryitems` LEFT JOIN `inventoryequipment` USING(`inventoryitemid`) WHERE `type` = ? AND `");
|
||||
|
||||
@@ -29,6 +29,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import tools.Pair;
|
||||
import client.MapleCharacter;
|
||||
@@ -36,6 +38,7 @@ import client.MapleClient;
|
||||
import constants.ItemConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MapleInventoryManipulator;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -47,6 +50,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
private byte slotLimit;
|
||||
private MapleInventoryType type;
|
||||
private boolean checked = false;
|
||||
private Lock lock = new ReentrantLock();
|
||||
|
||||
public MapleInventory(MapleCharacter mc, MapleInventoryType type, byte slotLimit) {
|
||||
this.owner = mc;
|
||||
@@ -64,15 +68,34 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public byte getSlotLimit() {
|
||||
return slotLimit;
|
||||
lock.lock();
|
||||
try {
|
||||
return slotLimit;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
if (item.getItemId() == itemId) {
|
||||
return item;
|
||||
}
|
||||
@@ -81,10 +104,10 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public Item findByName(String name) {
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
String itemName = MapleItemInformationProvider.getInstance().getName(item.getItemId());
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -97,7 +120,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
|
||||
public int countById(int itemId) {
|
||||
int qty = 0;
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
if (item.getItemId() == itemId) {
|
||||
qty += item.getQuantity();
|
||||
}
|
||||
@@ -138,7 +161,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
|
||||
public List<Item> listById(int itemId) {
|
||||
List<Item> ret = new ArrayList<>();
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
if (item.getItemId() == itemId) {
|
||||
ret.add(item);
|
||||
}
|
||||
@@ -149,10 +172,6 @@ public class MapleInventory implements Iterable<Item> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Collection<Item> list() {
|
||||
return inventory.values();
|
||||
}
|
||||
|
||||
public short addItem(Item item) {
|
||||
short slotId = getNextFreeSlot();
|
||||
if (slotId < 0 || item == null) {
|
||||
@@ -171,29 +190,34 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public void move(short sSlot, short dSlot, short slotMax) {
|
||||
Item source = (Item) inventory.get(sSlot);
|
||||
Item target = (Item) inventory.get(dSlot);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
if (target == null) {
|
||||
source.setPosition(dSlot);
|
||||
inventory.put(dSlot, source);
|
||||
inventory.remove(sSlot);
|
||||
} else if (target.getItemId() == source.getItemId() && !ItemConstants.isRechargable(source.getItemId())) {
|
||||
if (type.getType() == MapleInventoryType.EQUIP.getType()) {
|
||||
lock.lock();
|
||||
try {
|
||||
Item source = (Item) inventory.get(sSlot);
|
||||
Item target = (Item) inventory.get(dSlot);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
if (target == null) {
|
||||
source.setPosition(dSlot);
|
||||
inventory.put(dSlot, source);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +232,12 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public Item getItem(short slot) {
|
||||
return inventory.get(slot);
|
||||
lock.lock();
|
||||
try {
|
||||
return inventory.get(slot);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeItem(short slot) {
|
||||
@@ -216,7 +245,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
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?
|
||||
return;
|
||||
}
|
||||
@@ -230,7 +259,12 @@ public class MapleInventory implements Iterable<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())) {
|
||||
owner.updateCouponRates();
|
||||
@@ -238,7 +272,13 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
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())) {
|
||||
owner.updateCouponRates();
|
||||
@@ -246,40 +286,67 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return inventory.size() >= slotLimit;
|
||||
lock.lock();
|
||||
try {
|
||||
return inventory.size() >= slotLimit;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return inventory.size() + margin >= slotLimit - used;
|
||||
lock.lock();
|
||||
try {
|
||||
return inventory.size() + margin >= slotLimit - used;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public short getNextFreeSlot() {
|
||||
if (isFull()) {
|
||||
return -1;
|
||||
}
|
||||
for (short i = 1; i <= slotLimit; i++) {
|
||||
if (!inventory.keySet().contains(i)) {
|
||||
return i;
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
for (short i = 1; i <= slotLimit; i++) {
|
||||
if (!inventory.containsKey(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public short getNumFreeSlot() {
|
||||
if (isFull()) {
|
||||
return 0;
|
||||
}
|
||||
short free = 0;
|
||||
for (short i = 1; i <= slotLimit; i++) {
|
||||
if (!inventory.keySet().contains(i)) {
|
||||
free++;
|
||||
}
|
||||
}
|
||||
return free;
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
short free = 0;
|
||||
for (short i = 1; i <= slotLimit; i++) {
|
||||
if (!inventory.containsKey(i)) {
|
||||
free++;
|
||||
}
|
||||
}
|
||||
return free;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean checkSpot(MapleCharacter chr, Item item) {
|
||||
@@ -394,7 +461,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
|
||||
@Override
|
||||
public Iterator<Item> iterator() {
|
||||
return Collections.unmodifiableCollection(inventory.values()).iterator();
|
||||
return Collections.unmodifiableCollection(list()).iterator();
|
||||
}
|
||||
|
||||
public Collection<MapleInventory> allInventories() {
|
||||
@@ -404,7 +471,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
public Item findByCashId(int cashId) {
|
||||
boolean isRing = false;
|
||||
Equip equip = null;
|
||||
for (Item item : inventory.values()) {
|
||||
for (Item item : list()) {
|
||||
if (item.getType() == MapleInventoryType.EQUIP.getType()) {
|
||||
equip = (Equip) item;
|
||||
isRing = equip.getRingId() > -1;
|
||||
@@ -417,10 +484,20 @@ public class MapleInventory implements Iterable<Item> {
|
||||
}
|
||||
|
||||
public boolean checked() {
|
||||
return checked;
|
||||
lock.lock();
|
||||
try {
|
||||
return checked;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void checked(boolean yes) {
|
||||
checked = yes;
|
||||
lock.lock();
|
||||
try {
|
||||
checked = yes;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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_PARTY_SEARCH = false;
|
||||
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_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)
|
||||
|
||||
@@ -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());
|
||||
chr.cancelExpirationTask();
|
||||
chr.saveToDB();
|
||||
System.out.println("STRANGE SAVE TO DB");
|
||||
chr.getMap().removePlayer(c.getPlayer());
|
||||
try {
|
||||
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);
|
||||
c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer()));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
|
||||
|
||||
chr.commitExcludedItems();
|
||||
chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(pet));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,9 @@ import java.util.HashSet;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import server.TimerManager;
|
||||
import net.server.PetFullnessWorker;
|
||||
import net.server.CharacterAutosaverWorker;
|
||||
import net.server.MountTirednessWorker;
|
||||
import net.server.PetFullnessWorker;
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
@@ -82,7 +83,9 @@ public class World {
|
||||
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> mountsSchedule;
|
||||
private long mountUpdate;
|
||||
|
||||
|
||||
private ScheduledFuture<?> charactersSchedule;
|
||||
|
||||
public World(int world, int flag, String eventmsg, int exprate, int droprate, int mesorate, int bossdroprate) {
|
||||
this.id = world;
|
||||
this.flag = flag;
|
||||
@@ -99,6 +102,7 @@ public class World {
|
||||
|
||||
petsSchedule = TimerManager.getInstance().register(new PetFullnessWorker(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() {
|
||||
|
||||
+33
-12
@@ -30,6 +30,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
@@ -43,6 +45,7 @@ import client.inventory.ItemFactory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import constants.ItemConstants;
|
||||
import java.util.Collections;
|
||||
|
||||
/*
|
||||
* @author Flav
|
||||
@@ -99,12 +102,13 @@ public class CashShop {
|
||||
item = new Item(itemId, (byte) 0, count, petid);
|
||||
}
|
||||
|
||||
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.
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 4));
|
||||
} else {
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * period));
|
||||
}
|
||||
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.
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 4));
|
||||
} else {
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * period));
|
||||
}
|
||||
}
|
||||
item.setSN(sn);
|
||||
return item;
|
||||
}
|
||||
@@ -237,6 +241,7 @@ public class CashShop {
|
||||
private List<Item> inventory = new ArrayList<>();
|
||||
private List<Integer> wishList = new ArrayList<>();
|
||||
private int notes = 0;
|
||||
private Lock lock = new ReentrantLock();
|
||||
|
||||
public CashShop(int accountId, int characterId, int jobType) throws SQLException {
|
||||
this.accountId = accountId;
|
||||
@@ -325,13 +330,18 @@ public class CashShop {
|
||||
}
|
||||
|
||||
public List<Item> getInventory() {
|
||||
return inventory;
|
||||
lock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableList(inventory);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Item findByCashId(int cashId) {
|
||||
boolean isRing = false;
|
||||
Equip equip = null;
|
||||
for (Item item : inventory) {
|
||||
for (Item item : getInventory()) {
|
||||
if (item.getType() == 1) {
|
||||
equip = (Equip) item;
|
||||
isRing = equip.getRingId() > -1;
|
||||
@@ -345,11 +355,21 @@ public class CashShop {
|
||||
}
|
||||
|
||||
public void addToInventory(Item item) {
|
||||
inventory.add(item);
|
||||
lock.lock();
|
||||
try {
|
||||
inventory.add(item);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFromInventory(Item item) {
|
||||
inventory.remove(item);
|
||||
lock.lock();
|
||||
try {
|
||||
inventory.remove(item);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Integer> getWishList() {
|
||||
@@ -458,7 +478,8 @@ public class CashShop {
|
||||
ps.close();
|
||||
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())));
|
||||
}
|
||||
|
||||
@@ -466,7 +487,7 @@ public class CashShop {
|
||||
ps = con.prepareStatement("DELETE FROM `wishlists` WHERE `charid` = ?");
|
||||
ps.setInt(1, characterId);
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
ps.close();
|
||||
ps = con.prepareStatement("INSERT INTO `wishlists` VALUES (DEFAULT, ?, ?)");
|
||||
ps.setInt(1, characterId);
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
@@ -47,10 +49,11 @@ import tools.Pair;
|
||||
public class MapleStorage {
|
||||
|
||||
private int id;
|
||||
private List<Item> items;
|
||||
private int meso;
|
||||
private byte slots;
|
||||
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) {
|
||||
this.id = id;
|
||||
@@ -135,7 +138,8 @@ public class MapleStorage {
|
||||
}
|
||||
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())));
|
||||
}
|
||||
|
||||
@@ -146,30 +150,56 @@ public class MapleStorage {
|
||||
}
|
||||
|
||||
public Item getItem(byte slot) {
|
||||
return items.get(slot);
|
||||
lock.lock();
|
||||
try {
|
||||
return items.get(slot);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
typeItems.put(type, new ArrayList<>(filterItems(type)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void store(Item item) {
|
||||
items.add(item);
|
||||
lock.lock();
|
||||
try {
|
||||
items.add(item);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId());
|
||||
typeItems.put(type, new ArrayList<>(filterItems(type)));
|
||||
}
|
||||
|
||||
public List<Item> getItems() {
|
||||
return Collections.unmodifiableList(items);
|
||||
lock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableList(items);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Item> filterItems(MapleInventoryType type) {
|
||||
List<Item> storageItems = getItems();
|
||||
List<Item> ret = new LinkedList<>();
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
for (Item item : items) {
|
||||
|
||||
for (Item item : storageItems) {
|
||||
if (ii.getInventoryType(item.getItemId()) == type) {
|
||||
ret.add(item);
|
||||
}
|
||||
@@ -179,7 +209,8 @@ public class MapleStorage {
|
||||
|
||||
public byte getSlot(MapleInventoryType type, byte slot) {
|
||||
byte ret = 0;
|
||||
for (Item item : items) {
|
||||
List<Item> storageItems = getItems();
|
||||
for (Item item : storageItems) {
|
||||
if (item == typeItems.get(type).get(slot)) {
|
||||
return ret;
|
||||
}
|
||||
@@ -190,21 +221,29 @@ public class MapleStorage {
|
||||
|
||||
public void sendStorage(MapleClient c, int npcId) {
|
||||
final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
Collections.sort(items, new Comparator<Item>() {
|
||||
@Override
|
||||
public int compare(Item o1, Item o2) {
|
||||
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;
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
Collections.sort(items, new Comparator<Item>() {
|
||||
@Override
|
||||
public int compare(Item o1, Item o2) {
|
||||
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;
|
||||
}
|
||||
});
|
||||
for (MapleInventoryType type : MapleInventoryType.values()) {
|
||||
typeItems.put(type, new ArrayList<>(items));
|
||||
});
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
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) {
|
||||
@@ -231,7 +270,12 @@ public class MapleStorage {
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return items.size() >= slots;
|
||||
lock.lock();
|
||||
try {
|
||||
return items.size() >= slots;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
||||
@@ -55,100 +55,107 @@ public class MapleLifeFactory {
|
||||
}
|
||||
|
||||
public static MapleMonster getMonster(int mid) {
|
||||
MapleMonsterStats stats = monsterStats.get(Integer.valueOf(mid));
|
||||
if (stats == null) {
|
||||
MapleData monsterData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(mid) + ".img", '0', 11));
|
||||
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"))));
|
||||
try {
|
||||
MapleMonsterStats stats = monsterStats.get(Integer.valueOf(mid));
|
||||
if (stats == null) {
|
||||
MapleData monsterData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(mid) + ".img", '0', 11));
|
||||
if (monsterData == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
special = monsterInfoData.getChildByPath("selfDestruction");
|
||||
if (special != null) {
|
||||
stats.setSelfDestruction(new selfDestruction((byte) MapleDataTool.getInt(special.getChildByPath("action")), MapleDataTool.getIntConvert("removeAfter", special, -1), MapleDataTool.getIntConvert("hp", special, -1)));
|
||||
}
|
||||
MapleData firstAttackData = monsterInfoData.getChildByPath("firstAttack");
|
||||
int firstAttack = 0;
|
||||
if (firstAttackData != null) {
|
||||
if (firstAttackData.getType() == MapleDataType.FLOAT) {
|
||||
firstAttack = Math.round(MapleDataTool.getFloat(firstAttackData));
|
||||
} else {
|
||||
firstAttack = MapleDataTool.getInt(firstAttackData);
|
||||
}
|
||||
}
|
||||
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));
|
||||
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);
|
||||
|
||||
for (MapleData idata : monsterData) {
|
||||
if (!idata.getName().equals("info")) {
|
||||
int delay = 0;
|
||||
for (MapleData pic : idata.getChildren()) {
|
||||
delay += MapleDataTool.getIntConvert("delay", pic, 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"))));
|
||||
}
|
||||
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_));
|
||||
special = monsterInfoData.getChildByPath("selfDestruction");
|
||||
if (special != null) {
|
||||
stats.setSelfDestruction(new selfDestruction((byte) MapleDataTool.getInt(special.getChildByPath("action")), MapleDataTool.getIntConvert("removeAfter", special, -1), MapleDataTool.getIntConvert("hp", special, -1)));
|
||||
}
|
||||
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++;
|
||||
MapleData firstAttackData = monsterInfoData.getChildByPath("firstAttack");
|
||||
int firstAttack = 0;
|
||||
if (firstAttackData != null) {
|
||||
if (firstAttackData.getType() == MapleDataType.FLOAT) {
|
||||
firstAttack = Math.round(MapleDataTool.getFloat(firstAttackData));
|
||||
} else {
|
||||
firstAttack = MapleDataTool.getInt(firstAttackData);
|
||||
}
|
||||
}
|
||||
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");
|
||||
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);
|
||||
MapleMonster ret = new MapleMonster(mid, stats);
|
||||
return ret;
|
||||
} catch(NullPointerException npe) {
|
||||
System.out.println("[SEVERE] MOB " + mid + " failed to load. Issue: " + npe.getMessage() + "\n\n");
|
||||
npe.printStackTrace();
|
||||
|
||||
return null;
|
||||
}
|
||||
MapleMonster ret = new MapleMonster(mid, stats);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void decodeElementalString(MapleMonsterStats stats, String elemAttr) {
|
||||
|
||||
@@ -2325,11 +2325,11 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
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) {
|
||||
mapArea.setBounds(vrLeft, vrTop, vrRight - vrLeft, vrBottom - vrTop);
|
||||
mapArea.setBounds(vrLeft + 7, vrTop, vrRight - vrLeft - 14, vrBottom - vrTop);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,6 +41,7 @@ public class FilePrinter {
|
||||
FREDRICK = "fredrick/",
|
||||
NPC_UNCODED = "uncodedNPCs.txt",
|
||||
QUEST_UNCODED = "uncodedQuests.txt",
|
||||
AUTOSAVING_CHARACTER = "saveCharAuto.txt",
|
||||
SAVING_CHARACTER = "saveChar.txt",
|
||||
USED_COMMANDS = "usedCommands.txt";//more to come (maps)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user