From d0396e4c363f2c68e3f610424c250e9d2ec2a2e0 Mon Sep 17 00:00:00 2001 From: ronancpl Date: Fri, 26 May 2017 23:09:42 -0300 Subject: [PATCH] Protected Trade/Quest system + Expirable quests Added true protection against race conditions on player trades and fixed some situational issues. Character's quest status table also received concurrency treatment. Quests with time limit now expires properly. Increased subtly the performance on the server start-up. --- mychanges_ptbr.txt | 8 +- nbproject/private/private.xml | 30 ++- scripts/npc/world0/2010009.js | 12 ++ scripts/quest/2230.js | 3 +- src/client/MapleCharacter.java | 173 +++++++++++------- src/client/MapleClient.java | 2 +- src/client/MapleMount.java | 25 +-- .../channel/handlers/MovePetHandler.java | 2 +- .../handlers/PlayerLoggedinHandler.java | 12 +- src/net/server/world/World.java | 2 + src/server/MapleStatEffect.java | 5 +- src/server/MapleTrade.java | 42 +++-- src/server/quest/MapleQuest.java | 32 ++-- src/tools/MaplePacketCreator.java | 12 +- todo.txt | 1 - 15 files changed, 229 insertions(+), 132 deletions(-) diff --git a/mychanges_ptbr.txt b/mychanges_ptbr.txt index 4d411b2540..6a7722e40c 100644 --- a/mychanges_ptbr.txt +++ b/mychanges_ptbr.txt @@ -250,4 +250,10 @@ Solu 25 Maio 2017, Solução final ao problema das Guild Alliances. Todas as funcionalidades implementadas. -Registros de objetos MapleGuildCharacter agora esta sincronizado entre MapleCharacter's e MapleGuild's. \ No newline at end of file +Registros de objetos MapleGuildCharacter agora esta sincronizado entre MapleCharacter's e MapleGuild's. + +26 Maio 2017, +Correção e proteção a acessos concorrentes em mecânicas de comercialização entre jogadores. +Quests com limite de tempo agora expiram. Tempo restante também é mostrado na aba da quest. +Estrutura de dados que lida com status de quests do jogador agora foi protegido para acesso concorrente. +Montarias, tanto como pets, não ficam com "fome" com o tempo caso os flags PETS_NEVER_HUNGRY estejam setados. \ No newline at end of file diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml index 6d8d3ad834..83e676f731 100644 --- a/nbproject/private/private.xml +++ b/nbproject/private/private.xml @@ -5,12 +5,38 @@ src/tools/MaplePacketCreator.java - 5939 + 5941 - + + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/command/Commands.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleStatEffect.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/provider/MapleDataTool.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/PlayerInteractionHandler.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/UseCashItemHandler.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/UseItemHandler.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/MovePetHandler.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/quest/QuestActionManager.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/guild/MapleAlliance.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/Server.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleCharacter.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/PlayerLoggedinHandler.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/LogHelper.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/world0/2010009.js + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/MaplePacketCreator.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleMount.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/guild/MapleGuild.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/TimerManager.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleQuestStatus.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/QuestActionHandler.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleTrade.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleInventoryManipulator.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/CharInfoRequestHandler.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleClient.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/quest/MapleQuest.java + diff --git a/scripts/npc/world0/2010009.js b/scripts/npc/world0/2010009.js index 4ba70595bb..03f1b62737 100644 --- a/scripts/npc/world0/2010009.js +++ b/scripts/npc/world0/2010009.js @@ -72,6 +72,12 @@ function action(mode, type, selection) { cm.sendYesNo("Oh, are you interested in forming a Guild Union? The current fee for this operation is #b" + allianceCost + " mesos#k."); } else if (selection == 3) { + if(cm.getPlayer().getMGC() == null) { + cm.sendOk("You can not expand a Guild Union if you don't own one."); + cm.dispose(); + return; + } + var rank = cm.getPlayer().getMGC().getAllianceRank(); if (rank == 1) cm.sendYesNo("Do you want to increase your Alliance by one guild slot? The fee for this procedure is #b" + increaseCost + " mesos#k."); @@ -80,6 +86,12 @@ function action(mode, type, selection) { cm.dispose(); } } else if(selection == 4) { + if(cm.getPlayer().getMGC() == null) { + cm.sendOk("You can not disband a Guild Union if you don't own one."); + cm.dispose(); + return; + } + var rank = cm.getPlayer().getMGC().getAllianceRank(); if (rank == 1) cm.sendYesNo("Are you sure you want to disband your Guild Union?"); diff --git a/scripts/quest/2230.js b/scripts/quest/2230.js index e16da4d081..6a1ea10a21 100644 --- a/scripts/quest/2230.js +++ b/scripts/quest/2230.js @@ -70,7 +70,8 @@ function end(mode, type, selection) { } else if (status == 5) { qm.sendYesNo("Now do you understand? Every action comes with consequences, and pets are no exception. The egg of the snail shall hatch soon."); } else if (status == 6) { - qm.gainItem(5000054, 1); // rune snail * 1 + qm.gainItem(5000054, 1, false, true, 5 * 60 * 60 * 1000); // rune snail (5hrs) + qm.gainItem(4032086, -1); // Mysterious Egg * -1 qm.forceCompleteQuest(); qm.sendNext("This snail will only be alive for #b5 hours#k. Shower it with love. Your love will be reciprocated in the end."); diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index f16b2199d7..e450efa4b0 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -239,7 +239,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { private SavedLocation savedLocations[]; private SkillMacro[] skillMacros = new SkillMacro[5]; private List lastmonthfameids; - private Map quests; + private final Map quests; private Set controlled = new LinkedHashSet<>(); private Map entered = new LinkedHashMap<>(); private Set visibleMapObjects = new LinkedHashSet<>(); @@ -2067,13 +2067,16 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } public final List getCompletedQuests() { - List ret = new LinkedList<>(); - for (MapleQuestStatus q : quests.values()) { - if (q.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) { - ret.add(q); + synchronized (quests) { + List ret = new LinkedList<>(); + for (MapleQuestStatus q : quests.values()) { + if (q.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) { + ret.add(q); + } } + + return Collections.unmodifiableList(ret); } - return Collections.unmodifiableList(ret); } public Collection getControlledMonsters() { @@ -2603,46 +2606,58 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } public final byte getQuestStatus(final int quest) { - for (final MapleQuestStatus q : quests.values()) { - if (q.getQuest().getId() == quest) { - return (byte) q.getStatus().getId(); + synchronized (quests) { + for (final MapleQuestStatus q : quests.values()) { + if (q.getQuest().getId() == quest) { + return (byte) q.getStatus().getId(); + } } + return 0; } - return 0; } public MapleQuestStatus getQuest(MapleQuest quest) { - if (!quests.containsKey(quest.getId())) { - return new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED); + synchronized (quests) { + if (!quests.containsKey(quest.getId())) { + return new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED); + } + return quests.get(quest.getId()); } - return quests.get(quest.getId()); } //---- \/ \/ \/ \/ \/ \/ \/ NOT TESTED \/ \/ \/ \/ \/ \/ \/ \/ \/ ---- public final void setQuestAdd(final MapleQuest quest, final byte status, final String customData) { - if (!quests.containsKey(quest.getId())) { - final MapleQuestStatus stat = new MapleQuestStatus(quest, MapleQuestStatus.Status.getById((int)status)); - stat.setCustomData(customData); - quests.put(quest.getId(), stat); + synchronized (quests) { + if (!quests.containsKey(quest.getId())) { + final MapleQuestStatus stat = new MapleQuestStatus(quest, MapleQuestStatus.Status.getById((int)status)); + stat.setCustomData(customData); + quests.put(quest.getId(), stat); + } } } public final MapleQuestStatus getQuestNAdd(final MapleQuest quest) { - if (!quests.containsKey(quest.getId())) { - final MapleQuestStatus status = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED); - quests.put(quest.getId(), status); - return status; + synchronized (quests) { + if (!quests.containsKey(quest.getId())) { + final MapleQuestStatus status = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED); + quests.put(quest.getId(), status); + return status; + } + return quests.get(quest.getId()); } - return quests.get(quest.getId()); } public final MapleQuestStatus getQuestNoAdd(final MapleQuest quest) { - return quests.get(quest.getId()); + synchronized (quests) { + return quests.get(quest.getId()); + } } public final MapleQuestStatus getQuestRemove(final MapleQuest quest) { - return quests.remove(quest.getId()); + synchronized (quests) { + return quests.remove(quest.getId()); + } } //---- /\ /\ /\ /\ /\ /\ /\ NOT TESTED /\ /\ /\ /\ /\ /\ /\ /\ /\ ---- @@ -2742,26 +2757,30 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } public final List getStartedQuests() { - List ret = new LinkedList<>(); - for (MapleQuestStatus q : quests.values()) { - if (q.getStatus().equals(MapleQuestStatus.Status.STARTED)) { - ret.add(q); + synchronized (quests) { + List ret = new LinkedList<>(); + for (MapleQuestStatus q : quests.values()) { + if (q.getStatus().equals(MapleQuestStatus.Status.STARTED)) { + ret.add(q); + } } + return Collections.unmodifiableList(ret); } - return Collections.unmodifiableList(ret); } public final int getStartedQuestsSize() { - int i = 0; - for (MapleQuestStatus q : quests.values()) { - if (q.getStatus().equals(MapleQuestStatus.Status.STARTED)) { - if (q.getQuest().getInfoNumber() > 0) { + synchronized (quests) { + int i = 0; + for (MapleQuestStatus q : quests.values()) { + if (q.getStatus().equals(MapleQuestStatus.Status.STARTED)) { + if (q.getQuest().getInfoNumber() > 0) { + i++; + } i++; } - i++; } + return i; } - return i; } public MapleStatEffect getStatForBuff(MapleBuffStat effect) { @@ -3698,17 +3717,19 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } int lastQuestProcessed = 0; try { - for (MapleQuestStatus q : quests.values()) { - lastQuestProcessed = q.getQuest().getId(); - if (q.getStatus() == MapleQuestStatus.Status.COMPLETED || q.getQuest().canComplete(this, null)) { - continue; - } - String progress = q.getProgress(id); - if (!progress.isEmpty() && Integer.parseInt(progress) >= q.getQuest().getMobAmountNeeded(id)) { - continue; - } - if (q.progress(id)) { - client.announce(MaplePacketCreator.updateQuest(q, false)); + synchronized (quests) { + for (MapleQuestStatus q : quests.values()) { + lastQuestProcessed = q.getQuest().getId(); + if (q.getStatus() == MapleQuestStatus.Status.COMPLETED || q.getQuest().canComplete(this, null)) { + continue; + } + String progress = q.getProgress(id); + if (!progress.isEmpty() && Integer.parseInt(progress) >= q.getQuest().getMobAmountNeeded(id)) { + continue; + } + if (q.progress(id)) { + client.announce(MaplePacketCreator.updateQuest(q, false)); + } } } } catch (Exception e) { @@ -4536,27 +4557,30 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { try (PreparedStatement pse = con.prepareStatement("INSERT INTO questprogress VALUES (DEFAULT, ?, ?, ?)")) { psf = con.prepareStatement("INSERT INTO medalmaps VALUES (DEFAULT, ?, ?)"); ps.setInt(1, id); - for (MapleQuestStatus q : quests.values()) { - ps.setInt(2, q.getQuest().getId()); - ps.setInt(3, q.getStatus().getId()); - ps.setInt(4, (int) (q.getCompletionTime() / 1000)); - ps.setInt(5, q.getForfeited()); - ps.executeUpdate(); - try (ResultSet rs = ps.getGeneratedKeys()) { - rs.next(); - for (int mob : q.getProgress().keySet()) { - pse.setInt(1, rs.getInt(1)); - pse.setInt(2, mob); - pse.setString(3, q.getProgress(mob)); - pse.addBatch(); + + synchronized (quests) { + for (MapleQuestStatus q : quests.values()) { + ps.setInt(2, q.getQuest().getId()); + ps.setInt(3, q.getStatus().getId()); + ps.setInt(4, (int) (q.getCompletionTime() / 1000)); + ps.setInt(5, q.getForfeited()); + ps.executeUpdate(); + try (ResultSet rs = ps.getGeneratedKeys()) { + rs.next(); + for (int mob : q.getProgress().keySet()) { + pse.setInt(1, rs.getInt(1)); + pse.setInt(2, mob); + pse.setString(3, q.getProgress(mob)); + pse.addBatch(); + } + for (int i = 0; i < q.getMedalMaps().size(); i++) { + psf.setInt(1, rs.getInt(1)); + psf.setInt(2, q.getMedalMaps().get(i)); + psf.addBatch(); + } + pse.executeBatch(); + psf.executeBatch(); } - for (int i = 0; i < q.getMedalMaps().size(); i++) { - psf.setInt(1, rs.getInt(1)); - psf.setInt(2, q.getMedalMaps().get(i)); - psf.addBatch(); - } - pse.executeBatch(); - psf.executeBatch(); } } } @@ -5334,7 +5358,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { MapleQuestStatus qs = getQuest(q); qs.setInfo(info); - quests.put(q.getId(), qs); + synchronized (quests) { + quests.put(q.getId(), qs); + } announce(MaplePacketCreator.updateQuest(qs, false)); if (qs.getQuest().getInfoNumber() > 0) { @@ -5354,7 +5380,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } public void updateQuest(MapleQuestStatus quest) { - quests.put(quest.getQuestID(), quest); + synchronized (quests) { + quests.put(quest.getQuestID(), quest); + } if (quest.getStatus().equals(MapleQuestStatus.Status.STARTED)) { announce(MaplePacketCreator.updateQuest(quest, false)); if (quest.getQuest().getInfoNumber() > 0) { @@ -5375,17 +5403,20 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } } - public void questTimeLimit(final MapleQuest quest, int time) { + public void questTimeLimit(final MapleQuest quest, int seconds) { + final MapleCharacter chr = this; ScheduledFuture sf = TimerManager.getInstance().schedule(new Runnable() { @Override public void run() { + if(chr.getQuestStatus(quest.getId()) == MapleQuestStatus.Status.COMPLETED.getId()) return; + announce(MaplePacketCreator.questExpire(quest.getId())); MapleQuestStatus newStatus = new MapleQuestStatus(quest, MapleQuestStatus.Status.NOT_STARTED); newStatus.setForfeited(getQuest(quest).getForfeited() + 1); updateQuest(newStatus); } - }, time * 60 * 1000); - announce(MaplePacketCreator.addQuestTimeLimit(quest.getId(), time * 60 * 1000)); + }, seconds * 1000); + announce(MaplePacketCreator.addQuestTimeLimit(quest.getId(), seconds * 1000)); timers.add(sf); } diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java index 42b9b45ea6..d8b783f05d 100644 --- a/src/client/MapleClient.java +++ b/src/client/MapleClient.java @@ -786,7 +786,7 @@ public class MapleClient { final MapleGuild guild = player.getGuild(); if (channel == -1 || shutdown) { - chrg.setCharacter(null); + if(chrg != null) chrg.setCharacter(null); removePlayer(); player.saveCooldowns(); diff --git a/src/client/MapleMount.java b/src/client/MapleMount.java index c7f159713c..7038ed53a6 100644 --- a/src/client/MapleMount.java +++ b/src/client/MapleMount.java @@ -97,18 +97,19 @@ public class MapleMount { } private void increaseTiredness() { - if(owner != null) { - this.tiredness++; - owner.getMap().broadcastMessage(MaplePacketCreator.updateMount(owner.getId(), this, false)); - if (tiredness > 99) { - this.tiredness = 99; - owner.dispelSkill(owner.getJobType() * 10000000 + 1004); - } - } else { - if(this.tirednessSchedule != null) { - this.tirednessSchedule.cancel(false); - } - } + if(owner != null) { + this.tiredness++; + owner.getMap().broadcastMessage(MaplePacketCreator.updateMount(owner.getId(), this, false)); + if (tiredness > 99) { + this.tiredness = 99; + owner.dispelSkill(owner.getJobType() * 10000000 + 1004); + owner.dropMessage("Your mount grew tired! Treat it some revitalizer before riding it again!"); + } + } else { + if(this.tirednessSchedule != null) { + this.tirednessSchedule.cancel(false); + } + } } public void setExp(int newexp) { diff --git a/src/net/server/channel/handlers/MovePetHandler.java b/src/net/server/channel/handlers/MovePetHandler.java index 0cf813617d..005f265604 100644 --- a/src/net/server/channel/handlers/MovePetHandler.java +++ b/src/net/server/channel/handlers/MovePetHandler.java @@ -21,7 +21,6 @@ */ package net.server.channel.handlers; -import net.server.channel.handlers.AbstractMovementPacketHandler; import java.util.List; import client.MapleCharacter; import client.MapleClient; @@ -30,6 +29,7 @@ import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; public final class MovePetHandler extends AbstractMovementPacketHandler { + @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { int petId = slea.readInt(); slea.readLong(); diff --git a/src/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/net/server/channel/handlers/PlayerLoggedinHandler.java index 8cf8bf3b72..e5fdaedef7 100644 --- a/src/net/server/channel/handlers/PlayerLoggedinHandler.java +++ b/src/net/server/channel/handlers/PlayerLoggedinHandler.java @@ -191,6 +191,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { } else { playerGuild.getMGC(player.getId()).setCharacter(player); player.setMGC(playerGuild.getMGC(player.getId())); + server.setGuildMemberOnline(player, true, c.getChannel()); c.announce(MaplePacketCreator.showGuildInfo(player)); int allianceId = player.getGuild().getAllianceId(); @@ -204,6 +205,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { player.getGuild().setAllianceId(0); } } + if (newAlliance != null) { c.announce(MaplePacketCreator.updateAllianceInfo(newAlliance, c)); c.announce(MaplePacketCreator.allianceNotice(newAlliance.getId(), newAlliance.getNotice())); @@ -267,11 +269,11 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { if (player.getMap().getHPDec() > 0) { final MapleCharacter mc = player; - ScheduledFuture hpDecreaseTask = TimerManager.getInstance().schedule(new Runnable() { - @Override - public void run() { - mc.doHurtHp(); - } + TimerManager.getInstance().schedule(new Runnable() { + @Override + public void run() { + mc.doHurtHp(); + } }, 10000); } } diff --git a/src/net/server/world/World.java b/src/net/server/world/World.java index f067dfaff6..b8448ab87d 100644 --- a/src/net/server/world/World.java +++ b/src/net/server/world/World.java @@ -194,6 +194,8 @@ public class World { } public MapleGuild getGuild(MapleGuildCharacter mgc) { + if(mgc == null) return null; + int gid = mgc.getGuildId(); MapleGuild g; g = Server.getInstance().getGuild(gid, mgc.getWorld(), mgc.getCharacter()); diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java index 60d2cddffb..4d5a7b3bbd 100644 --- a/src/server/MapleStatEffect.java +++ b/src/server/MapleStatEffect.java @@ -943,7 +943,10 @@ public class MapleStatEffect { if (applyto.getMount() == null) { applyto.mount(ridingLevel, sourceid); } - applyto.getMount().startSchedule(); + + if(!(ServerConstants.PETS_NEVER_HUNGRY || applyto.isGM() && ServerConstants.GM_PETS_NEVER_HUNGRY)) { + applyto.getMount().startSchedule(); + } } if (sourceid == Corsair.BATTLE_SHIP) { givemount = new MapleMount(applyto, 1932000, sourceid); diff --git a/src/server/MapleTrade.java b/src/server/MapleTrade.java index b1e52e6b9b..e0b14e5a87 100644 --- a/src/server/MapleTrade.java +++ b/src/server/MapleTrade.java @@ -26,6 +26,7 @@ import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import tools.LogHelper; import tools.MaplePacketCreator; @@ -33,10 +34,11 @@ import client.MapleCharacter; import client.inventory.Item; import client.inventory.MapleInventoryType; import constants.ItemConstants; +import constants.ServerConstants; /** * - * @author Matze + * @author Matze, Ronan (concurrency safety) */ public class MapleTrade { private MapleTrade partner = null; @@ -44,7 +46,7 @@ public class MapleTrade { private List exchangeItems; private int meso = 0; private int exchangeMeso; - boolean locked = false; + private AtomicBoolean locked = new AtomicBoolean(false); private MapleCharacter chr; private byte number; private boolean fullTrade = false; @@ -73,7 +75,7 @@ public class MapleTrade { } private void lock() { - locked = true; + locked.set(true); partner.getChr().getClient().announce(MaplePacketCreator.getTradeConfirmation()); } @@ -83,16 +85,18 @@ public class MapleTrade { } private void complete2() { + boolean show = ServerConstants.USE_DEBUG; + items.clear(); meso = 0; for (Item item : exchangeItems) { if ((item.getFlag() & ItemConstants.KARMA) == ItemConstants.KARMA) item.setFlag((byte) (item.getFlag() ^ ItemConstants.KARMA)); //items with scissors of karma used on them are reset once traded - MapleInventoryManipulator.addFromDrop(chr.getClient(), item, true); + MapleInventoryManipulator.addFromDrop(chr.getClient(), item, show); } if (exchangeMeso > 0) { - chr.gainMeso(exchangeMeso - getFee(exchangeMeso), true, true, true); + chr.gainMeso(exchangeMeso - getFee(exchangeMeso), show, true, show); } exchangeMeso = 0; if (exchangeItems != null) { @@ -102,11 +106,13 @@ public class MapleTrade { } private void cancel() { + boolean show = ServerConstants.USE_DEBUG; + for (Item item : items) { - MapleInventoryManipulator.addFromDrop(chr.getClient(), item, true); + MapleInventoryManipulator.addFromDrop(chr.getClient(), item, show); } if (meso > 0) { - chr.gainMeso(meso, true, true, true); + chr.gainMeso(meso, show, true, show); } meso = 0; if (items != null) { @@ -120,7 +126,7 @@ public class MapleTrade { } private boolean isLocked() { - return locked; + return locked.get(); } private int getMeso() { @@ -128,7 +134,7 @@ public class MapleTrade { } public void setMeso(int meso) { - if (locked) { + if (locked.get()) { throw new RuntimeException("Trade is locked."); } if (meso < 0) { @@ -166,7 +172,7 @@ public class MapleTrade { } public void setPartner(MapleTrade partner) { - if (locked) { + if (locked.get()) { return; } this.partner = partner; @@ -210,9 +216,15 @@ public class MapleTrade { if (partner.isLocked()) { local.complete1(); partner.complete1(); - if (!local.fitsInInventory() || !partner.fitsInInventory()) { + if (!local.fitsInInventory()) { cancelTrade(c); c.message("There is not enough inventory space to complete the trade."); + partner.getChr().message("Partner does not have enough inventory space to complete the trade."); + return; + } + else if (!partner.fitsInInventory()) { + cancelTrade(c); + c.message("Partner does not have enough inventory space to complete the trade."); partner.getChr().message("There is not enough inventory space to complete the trade."); return; } @@ -224,13 +236,13 @@ public class MapleTrade { } else { local.getChr().addMesosTraded(local.exchangeMeso); } - } else if (c.getTrade().getChr().getLevel() < 15) { - if (c.getMesosTraded() + c.getTrade().exchangeMeso > 1000000) { + } else if (partner.getChr().getLevel() < 15) { + if (partner.getChr().getMesosTraded() + partner.exchangeMeso > 1000000) { cancelTrade(c); - c.getClient().announce(MaplePacketCreator.serverNotice(1, "Characters under level 15 may not trade more than 1 million mesos per day.")); + partner.getChr().getClient().announce(MaplePacketCreator.serverNotice(1, "Characters under level 15 may not trade more than 1 million mesos per day.")); return; } else { - c.addMesosTraded(local.exchangeMeso); + partner.getChr().addMesosTraded(partner.exchangeMeso); } } LogHelper.logTrade(local, partner); diff --git a/src/server/quest/MapleQuest.java b/src/server/quest/MapleQuest.java index 19700bd68c..66ebf72c6d 100644 --- a/src/server/quest/MapleQuest.java +++ b/src/server/quest/MapleQuest.java @@ -46,7 +46,7 @@ public class MapleQuest { private static Map quests = new HashMap<>(); protected short infoNumber, id; - protected int timeLimit, timeLimit2; + protected int timeLimit; protected String infoex; protected Map startReqs = new EnumMap<>(MapleQuestRequirementType.class); protected Map completeReqs = new EnumMap<>(MapleQuestRequirementType.class); @@ -57,20 +57,22 @@ public class MapleQuest { private boolean autoPreComplete, autoComplete; private boolean repeatable = false; private final static MapleDataProvider questData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Quest.wz")); - private static MapleData questInfo; - private static MapleData questAct; - private static MapleData questReq; + private static MapleData questInfo; + private static MapleData questAct; + private static MapleData questReq; private MapleQuest(int id) { this.id = (short) id; - if(questInfo != null) { - timeLimit = MapleDataTool.getInt("timeLimit", questInfo, 0); - timeLimit2 = MapleDataTool.getInt("timeLimit2", questInfo, 0); - autoStart = MapleDataTool.getInt("autoStart", questInfo, 0) == 1; - autoPreComplete = MapleDataTool.getInt("autoPreComplete", questInfo, 0) == 1; - autoComplete = MapleDataTool.getInt("autoComplete", questInfo, 0) == 1; - } + if(questInfo != null) { + MapleData reqData = questInfo.getChildByPath(String.valueOf(id)); + + timeLimit = MapleDataTool.getInt("timeLimit", reqData, 0); + timeLimit = Math.max(timeLimit, MapleDataTool.getInt("timeLimit2", reqData, 0)); // alas, nexon made we deal with 2 timeLimits + autoStart = MapleDataTool.getInt("autoStart", reqData, 0) == 1; + autoPreComplete = MapleDataTool.getInt("autoPreComplete", reqData, 0) == 1; + autoComplete = MapleDataTool.getInt("autoComplete", reqData, 0) == 1; + } MapleData reqData = questReq.getChildByPath(String.valueOf(id)); if (reqData == null) {//most likely infoEx @@ -84,7 +86,7 @@ public class MapleQuest { repeatable = true; } - if (type.equals(MapleQuestRequirementType.INFO_NUMBER)) { + if (type.equals(MapleQuestRequirementType.INFO_NUMBER)) { infoNumber = (short) MapleDataTool.getInt(startReq, 0); } @@ -280,11 +282,9 @@ public class MapleQuest { newStatus.setForfeited(c.getQuest(this).getForfeited()); if (timeLimit > 0) { - c.questTimeLimit(this, 30000);//timeLimit * 1000 - } - if (timeLimit2 > 0) {//=\ - + c.questTimeLimit(this, timeLimit); } + c.updateQuest(newStatus); return true; } diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java index ee284ce2ab..1a08a5fe14 100644 --- a/src/tools/MaplePacketCreator.java +++ b/src/tools/MaplePacketCreator.java @@ -2337,16 +2337,18 @@ public class MaplePacketCreator { mplew.write(chr.getMarriageRing() != null ? 1 : 0); String guildName = ""; String allianceName = ""; - MapleGuildSummary gs = chr.getClient().getWorldServer().getGuildSummary(chr.getGuildId(), chr.getWorld()); - if (chr.getGuildId() > 0 && gs != null) { - guildName = gs.getName(); - MapleAlliance alliance = Server.getInstance().getAlliance(gs.getAllianceId()); + if (chr.getGuildId() > 0) { + MapleGuild mg = Server.getInstance().getGuild(chr.getGuildId()); + guildName = mg.getName(); + + MapleAlliance alliance = Server.getInstance().getAlliance(chr.getGuild().getAllianceId()); if (alliance != null) { allianceName = alliance.getName(); } } mplew.writeMapleAsciiString(guildName); - mplew.writeMapleAsciiString(allianceName); + mplew.writeMapleAsciiString(allianceName); // does not seems to work + mplew.write(0); MaplePet[] pets = chr.getPets(); Item inv = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -114); diff --git a/todo.txt b/todo.txt index 3265476950..5a5d298176 100644 --- a/todo.txt +++ b/todo.txt @@ -1,2 +1 @@ -guild npc PQs \ No newline at end of file