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.
This commit is contained in:
@@ -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.
|
||||
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.
|
||||
@@ -5,12 +5,38 @@
|
||||
<url>src/tools/MaplePacketCreator.java</url>
|
||||
<bookmark id="1">
|
||||
<name/>
|
||||
<line>5939</line>
|
||||
<line>5941</line>
|
||||
<key/>
|
||||
</bookmark>
|
||||
</file>
|
||||
</editor-bookmarks>
|
||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||
<group/>
|
||||
<group>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/command/Commands.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleStatEffect.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/provider/MapleDataTool.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/PlayerInteractionHandler.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/UseCashItemHandler.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/UseItemHandler.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/MovePetHandler.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/quest/QuestActionManager.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/guild/MapleAlliance.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/Server.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleCharacter.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/PlayerLoggedinHandler.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/LogHelper.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/world0/2010009.js</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/MaplePacketCreator.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleMount.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/guild/MapleGuild.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/TimerManager.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleQuestStatus.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/QuestActionHandler.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleTrade.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/MapleInventoryManipulator.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/CharInfoRequestHandler.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleClient.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/quest/MapleQuest.java</file>
|
||||
</group>
|
||||
</open-files>
|
||||
</project-private>
|
||||
|
||||
@@ -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?");
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -239,7 +239,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
private SavedLocation savedLocations[];
|
||||
private SkillMacro[] skillMacros = new SkillMacro[5];
|
||||
private List<Integer> lastmonthfameids;
|
||||
private Map<Short, MapleQuestStatus> quests;
|
||||
private final Map<Short, MapleQuestStatus> quests;
|
||||
private Set<MapleMonster> controlled = new LinkedHashSet<>();
|
||||
private Map<Integer, String> entered = new LinkedHashMap<>();
|
||||
private Set<MapleMapObject> visibleMapObjects = new LinkedHashSet<>();
|
||||
@@ -2067,13 +2067,16 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
|
||||
public final List<MapleQuestStatus> getCompletedQuests() {
|
||||
List<MapleQuestStatus> ret = new LinkedList<>();
|
||||
for (MapleQuestStatus q : quests.values()) {
|
||||
if (q.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
|
||||
ret.add(q);
|
||||
synchronized (quests) {
|
||||
List<MapleQuestStatus> 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<MapleMonster> 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<MapleQuestStatus> getStartedQuests() {
|
||||
List<MapleQuestStatus> ret = new LinkedList<>();
|
||||
for (MapleQuestStatus q : quests.values()) {
|
||||
if (q.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
|
||||
ret.add(q);
|
||||
synchronized (quests) {
|
||||
List<MapleQuestStatus> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<Item> 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);
|
||||
|
||||
@@ -46,7 +46,7 @@ public class MapleQuest {
|
||||
|
||||
private static Map<Integer, MapleQuest> quests = new HashMap<>();
|
||||
protected short infoNumber, id;
|
||||
protected int timeLimit, timeLimit2;
|
||||
protected int timeLimit;
|
||||
protected String infoex;
|
||||
protected Map<MapleQuestRequirementType, MapleQuestRequirement> startReqs = new EnumMap<>(MapleQuestRequirementType.class);
|
||||
protected Map<MapleQuestRequirementType, MapleQuestRequirement> 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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user