Protected Hired Merchant + Buff system patch

Fixed some issues with Fredrick not retrieving the right amount of items
from Hired Merchants. Added concurrency protection for HM. Patched a
minor issue on buff system.
This commit is contained in:
ronancpl
2017-09-26 00:18:14 -03:00
parent 28258530e4
commit de7e686a92
42 changed files with 500 additions and 131 deletions

View File

@@ -39,6 +39,8 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;
import net.MapleServerHandler;
import net.mina.MapleCodecFactory;
@@ -79,6 +81,7 @@ public class Server implements Runnable {
private static Server instance = null;
private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>();
private final Map<Integer, MapleGuild> guilds = new LinkedHashMap<>();
private final Lock shutdownLock = new ReentrantLock();
private final PlayerBuffStorage buffStorage = new PlayerBuffStorage();
private final Map<Integer, MapleAlliance> alliances = new LinkedHashMap<>();
private boolean online = false;
@@ -99,7 +102,8 @@ public class Server implements Runnable {
return worldRecommendedList;
}
public void removeChannel(int worldid, int channel) {
/*
public void removeChannel(int worldid, int channel) { //lol don't!
channels.remove(channel);
World world = worlds.get(worldid);
@@ -107,6 +111,7 @@ public class Server implements Runnable {
world.removeChannel(channel);
}
}
*/
public Channel getChannel(int world, int channel) {
return worlds.get(world).getChannel(channel);
@@ -702,69 +707,75 @@ public class Server implements Runnable {
return worlds;
}
public final Runnable shutdown(final boolean restart) {//only once :D
public final Runnable shutdown(final boolean restart) {//no player should be online when trying to shutdown!
return new Runnable() {
@Override
public void run() {
System.out.println((restart ? "Restarting" : "Shutting down") + " the server!\r\n");
if (getWorlds() == null) return;//already shutdown
for (World w : getWorlds()) {
w.shutdown();
}
/*for (World w : getWorlds()) {
while (w.getPlayerStorage().getAllCharacters().size() > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
System.err.println("FUCK MY LIFE");
shutdownLock.lock();
try {
System.out.println((restart ? "Restarting" : "Shutting down") + " the server!\r\n");
if (getWorlds() == null) return;//already shutdown
for (World w : getWorlds()) {
w.shutdown();
}
/*for (World w : getWorlds()) {
while (w.getPlayerStorage().getAllCharacters().size() > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
System.err.println("FUCK MY LIFE");
}
}
}
}
for (Channel ch : getAllChannels()) {
while (ch.getConnectedClients() > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
System.err.println("FUCK MY LIFE");
for (Channel ch : getAllChannels()) {
while (ch.getConnectedClients() > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
System.err.println("FUCK MY LIFE");
}
}
}*/
TimerManager.getInstance().purge();
TimerManager.getInstance().stop();
for (Channel ch : getAllChannels()) {
while (!ch.finishedShutdown()) {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
System.err.println("FUCK MY LIFE");
}
}
}
}*/
worlds.clear();
worlds = null;
channels.clear();
channels = null;
worldRecommendedList.clear();
worldRecommendedList = null;
TimerManager.getInstance().purge();
TimerManager.getInstance().stop();
for (Channel ch : getAllChannels()) {
while (!ch.finishedShutdown()) {
System.out.println("Worlds + Channels are offline.");
acceptor.unbind();
acceptor = null;
if (!restart) {
System.exit(0);
} else {
System.out.println("\r\nRestarting the server....\r\n");
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
System.err.println("FUCK MY LIFE");
instance.finalize();//FUU I CAN AND IT'S FREE
} catch (Throwable ex) {
ex.printStackTrace();
}
instance = null;
System.gc();
getInstance().run();//DID I DO EVERYTHING?! D:
}
}
worlds.clear();
worlds = null;
channels.clear();
channels = null;
worldRecommendedList.clear();
worldRecommendedList = null;
System.out.println("Worlds + Channels are offline.");
acceptor.unbind();
acceptor = null;
if (!restart) {
System.exit(0);
} else {
System.out.println("\r\nRestarting the server....\r\n");
try {
instance.finalize();//FUU I CAN AND IT'S FREE
} catch (Throwable ex) {
ex.printStackTrace();
}
instance = null;
System.gc();
getInstance().run();//DID I DO EVERYTHING?! D:
} finally {
shutdownLock.unlock();
}
}
};

View File

@@ -72,10 +72,10 @@ public class FredrickHandler extends AbstractMaplePacketHandler {
chr.getHiredMerchant().clearItems();
for (int i = 0; i < items.size(); i++) {
Item item = items.get(i).getLeft();
Item item = items.get(i).getLeft();
MapleInventoryManipulator.addFromDrop(c, item, false);
String itemName = MapleItemInformationProvider.getInstance().getName(item.getItemId());
FilePrinter.printError(FilePrinter.FREDRICK + chr.getName() + ".txt", chr.getName() + " gained " + item.getQuantity() + " " + itemName + " (" + item.getItemId() + ")\r\n");
FilePrinter.printError(FilePrinter.FREDRICK + chr.getName() + ".txt", chr.getName() + " gained " + item.getQuantity() + " " + itemName + " (" + item.getItemId() + ")\r\n");
}
c.announce(MaplePacketCreator.fredrickMessage((byte) 0x1E));

View File

@@ -26,6 +26,7 @@ import client.MapleCharacter;
import java.sql.SQLException;
import java.util.Arrays;
import client.MapleClient;
import constants.ServerConstants;
import net.AbstractMaplePacketHandler;
import server.maps.MapleMapObjectType;
import tools.MaplePacketCreator;
@@ -38,7 +39,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
public final class HiredMerchantRequest extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
if (chr.getMap().getMapObjectsInRange(chr.getPosition(), 23000, Arrays.asList(MapleMapObjectType.HIRED_MERCHANT)).isEmpty() && chr.getMapId() > 910000000 && chr.getMapId() < 910000023) {
if (chr.getMap().getMapObjectsInRange(chr.getPosition(), 23000, Arrays.asList(MapleMapObjectType.HIRED_MERCHANT)).isEmpty() && ((ServerConstants.USE_MERCHANT_ANYWHERE && chr.getMapId() != 910000000) || (chr.getMapId() > 910000000 && chr.getMapId() < 910000023))) {
if (!chr.hasMerchant()) {
try {
if (ItemFactory.MERCHANT.loadItems(chr.getId(), false).isEmpty() && chr.getMerchantMeso() == 0) {

View File

@@ -28,6 +28,7 @@ import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import constants.ItemConstants;
import constants.ServerConstants;
import java.util.Arrays;
@@ -234,7 +235,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
} else if (!merchant.isOpen()) {
chr.dropMessage(1, "This shop is in maintenance, please come by later.");
return;
} else if (merchant.getFreeSlot() == -1) {
} else if (merchant.getFreeSlotThreadsafe() == -1) {
chr.dropMessage(1, "This shop has reached it's maximum capacity, please come by later.");
return;
} else {
@@ -259,10 +260,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
game.chat(c, slea.readMapleAsciiString());
}
} else if (merchant != null) {
String message = chr.getName() + " : " + slea.readMapleAsciiString();
byte slot = (byte) (merchant.getVisitorSlot(c.getPlayer()) + 1);
merchant.getMessages().add(new Pair<>(message, slot));
merchant.broadcastToVisitors(MaplePacketCreator.hiredMerchantChat(message, slot));
merchant.sendMessage(c.getPlayer(), slea.readMapleAsciiString());
}
} else if (mode == Action.EXIT.getCode()) {
if (chr.getTrade() != null) {
@@ -408,7 +406,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
} else if (mode == Action.CONFIRM.getCode()) {
MapleTrade.completeTrade(c.getPlayer());
} else if (mode == Action.ADD_ITEM.getCode() || mode == Action.PUT_ITEM.getCode()) {
MapleInventoryType type = MapleInventoryType.getByType(slea.readByte());
MapleInventoryType type = MapleInventoryType.getByType(slea.readByte());
short slot = slea.readShort();
short bundles = slea.readShort();
if (chr.getInventory(type).getItem(slot) == null || chr.getItemQuantity(chr.getInventory(type).getItem(slot).getItemId(), false) < bundles || chr.getInventory(type).getItem(slot).getFlag() == ItemConstants.UNTRADEABLE) {
@@ -425,6 +423,9 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
Item sellItem = ivItem.copy();
if (chr.getItemQuantity(ivItem.getItemId(), false) < perBundle * bundles) {
return;
} else if (ServerConstants.USE_ENFORCE_UNMERCHABLE_PET && ItemConstants.isPet(ivItem.getItemId())) {
c.announce(MaplePacketCreator.serverNotice(1, "Pets are not allowed to be sold on the Player Shop."));
return;
}
sellItem.setQuantity(perBundle);
MaplePlayerShopItem item = new MaplePlayerShopItem(sellItem, bundles, price);
@@ -521,7 +522,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
shop.broadcast(MaplePacketCreator.getPlayerShopItemUpdate(shop));
} else if (merchant != null) {
merchant.buy(c, item, quantity);
merchant.broadcastToVisitors(MaplePacketCreator.updateHiredMerchant(merchant, c.getPlayer()));
merchant.broadcastToVisitorsThreadsafe(MaplePacketCreator.updateHiredMerchant(merchant, c.getPlayer()));
}
} else if (mode == Action.TAKE_ITEM_BACK.getCode()) {
HiredMerchant merchant = chr.getHiredMerchant();
@@ -555,7 +556,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
chr.setHasMerchant(false);
}
if (merchant != null && merchant.isOwner(c.getPlayer())) {
merchant.getMessages().clear();
merchant.clearMessages();
merchant.setOpen(true);
}
chr.setHiredMerchant(null);

View File

@@ -117,8 +117,14 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
return;
}
} catch(ClassCastException e) {
e.printStackTrace();
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Attacker is not a mob-type, rather is a " + map.getMapObject(oid).getClass().getName() + " entity.");
//this happens due to mob on last map damaging player just before changing maps
if(ServerConstants.USE_DEBUG) {
e.printStackTrace();
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Attacker is not a mob-type, rather is a " + map.getMapObject(oid).getClass().getName() + " entity.");
}
return;
}
direction = slea.readByte();

View File

@@ -86,7 +86,6 @@ public class World {
private long mountUpdate;
private Map<HiredMerchant, Byte> activeMerchants = new LinkedHashMap<>();
private ScheduledFuture<?> MerchantsSchedule;
private long merchantUpdate;
private ScheduledFuture<?> charactersSchedule;