Mystic Doors review + Togglable SrvMessage-BossHP + Map-Event patch

Reviewed Mystic Doors.
Fixed several issues showing up on Duey in uncommon scenarios.
Fixed a concurrency issue with XMLDomMapleData.
Scheduled forward the "lock disposal" action within the source. Now, it's expected that, after a set while, no method should require usage of a disposed lock and, during that while, a supposed "disposed lock" is still available to run (although no new processes is expected to require use of these locks).
Fixed concurrency issues with player's current event instance, generating several inconsistencies when swiftly registering/unregistering from events.
Implemented a mutually exclusive approach for server message - Boss HPbar.
Fixed item-making Kage requiring lv71~80 ETC instead of the expected 81~90.
Removed the possibility to buy cosmetic coupons with mesos through the NPCs.
Sleepywood JQ's no longer gives cash items when they finish the quest repeatedly.
Added Duey trucks in several maps lacking it. Added NPC Duey in New Leaf City.
Fixed scripted quests not calculating QUEST_RATE (if applied) when rewarding experience and meso.
This commit is contained in:
ronancpl
2018-08-07 23:37:24 -03:00
parent cc541f39d5
commit 4c25c07e28
173 changed files with 38064 additions and 37254 deletions

View File

@@ -30,9 +30,11 @@ import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Map;
import java.util.Comparator;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import server.maps.MapleDoor;
public class MapleParty {
private int id;
@@ -44,11 +46,12 @@ public class MapleParty {
private Map<Integer, Integer> histMembers = new HashMap<>();
private int nextEntry = 0;
private Map<Integer, MapleDoor> doors = new HashMap<>();
private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.PARTY, true);
public MapleParty(int id, MaplePartyCharacter chrfor) {
this.leaderId = chrfor.getId();
this.members.add(chrfor);
this.id = id;
}
@@ -169,7 +172,7 @@ public class MapleParty {
}
}
public byte getPartyDoor(int cid) {
public List<Integer> getMembersSortedByHistory() {
List<Entry<Integer, Integer>> histList;
lock.lock();
@@ -187,16 +190,53 @@ public class MapleParty {
return ( o1.getValue() ).compareTo( o2.getValue() );
}
});
List<Integer> histSort = new LinkedList<>();
for(Entry<Integer, Integer> e : histList) {
histSort.add(e.getKey());
}
return histSort;
}
public byte getPartyDoor(int cid) {
List<Integer> histList = getMembersSortedByHistory();
byte slot = 0;
for(Entry<Integer, Integer> e: histList) {
if(e.getKey() == cid) break;
for(Integer e: histList) {
if(e == cid) break;
slot++;
}
return slot;
}
public void addDoor(Integer owner, MapleDoor door) {
lock.lock();
try {
this.doors.put(owner, door);
} finally {
lock.unlock();
}
}
public void removeDoor(Integer owner) {
lock.lock();
try {
this.doors.remove(owner);
} finally {
lock.unlock();
}
}
public Map<Integer, MapleDoor> getDoors() {
lock.lock();
try {
return Collections.unmodifiableMap(doors);
} finally {
lock.unlock();
}
}
public void assignNewLeader(MapleClient c) {
World world = c.getWorldServer();
MaplePartyCharacter newLeadr = null;
@@ -216,6 +256,15 @@ public class MapleParty {
}
public void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
lock = lock.dispose();
}

View File

@@ -21,15 +21,8 @@
*/
package net.server.world;
import java.util.Map;
import java.util.Map.Entry;
import java.util.LinkedHashMap;
import java.util.Collection;
import server.maps.MapleDoor;
import client.MapleCharacter;
import client.MapleJob;
import java.util.Collections;
public class MaplePartyCharacter {
private String name;
@@ -38,7 +31,6 @@ public class MaplePartyCharacter {
private int channel, world;
private int jobid;
private int mapid;
private Map<Integer, MapleDoor> doors = new LinkedHashMap<>();
private boolean online;
private MapleJob job;
private MapleCharacter character;
@@ -54,9 +46,6 @@ public class MaplePartyCharacter {
this.mapid = maplechar.getMapId();
this.online = true;
this.job = maplechar.getJob();
for (Entry<Integer, MapleDoor> entry : maplechar.getDoors().entrySet()) {
doors.put(entry.getKey(), entry.getValue());
}
}
public MaplePartyCharacter() {
@@ -118,18 +107,6 @@ public class MaplePartyCharacter {
public int getGuildId() {
return character.getGuildId();
}
public void addDoor(Integer owner, MapleDoor door) {
this.doors.put(owner, door);
}
public void removeDoor(Integer owner) {
this.doors.remove(owner);
}
public Collection<MapleDoor> getDoors() {
return Collections.unmodifiableCollection(doors.values());
}
@Override
public int hashCode() {

View File

@@ -63,12 +63,15 @@ import server.maps.MaplePlayerShop;
import server.maps.MaplePlayerShopItem;
import server.maps.AbstractMapleMapObject;
import net.server.worker.CharacterAutosaverWorker;
import net.server.worker.HiredMerchantWorker;
import net.server.worker.MountTirednessWorker;
import net.server.worker.PetFullnessWorker;
import net.server.worker.ServerMessageWorker;
import net.server.worker.TimedMapObjectWorker;
import net.server.worker.WeddingReservationWorker;
import net.server.PlayerStorage;
import net.server.Server;
import net.server.audit.LockCollector;
import net.server.channel.Channel;
import net.server.channel.CharacterIdChannelPair;
import net.server.guild.MapleGuild;
@@ -119,15 +122,17 @@ public class World {
private MonitoredReentrantLock partyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PARTY, true);
private Map<Integer, Integer> owlSearched = new LinkedHashMap<>();
private MonitoredReentrantLock owlLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_OWL);
private Map<Integer, Integer> disabledServerMessages = new HashMap<>(); // reuse owl lock
private MonitoredReentrantLock srvMessagesLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_SRVMESSAGES);
private ScheduledFuture<?> srvMessagesSchedule;
private MonitoredReentrantLock activePetsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PETS, true);
private Map<Integer, Byte> activePets = new LinkedHashMap<>();
private Map<Integer, Integer> activePets = new LinkedHashMap<>();
private ScheduledFuture<?> petsSchedule;
private long petUpdate;
private MonitoredReentrantLock activeMountsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MOUNTS, true);
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
private Map<Integer, Integer> activeMounts = new LinkedHashMap<>();
private ScheduledFuture<?> mountsSchedule;
private long mountUpdate;
@@ -135,7 +140,8 @@ public class World {
private Map<Integer, MaplePlayerShop> activePlayerShops = new LinkedHashMap<>();
private MonitoredReentrantLock activeMerchantsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MERCHS, true);
private Map<Integer, Pair<MapleHiredMerchant, Byte>> activeMerchants = new LinkedHashMap<>();
private Map<Integer, Pair<MapleHiredMerchant, Integer>> activeMerchants = new LinkedHashMap<>();
private ScheduledFuture<?> merchantSchedule;
private long merchantUpdate;
private Map<Runnable, Long> registeredTimedMapObjects = new LinkedHashMap<>();
@@ -161,7 +167,9 @@ public class World {
TimerManager tman = TimerManager.getInstance();
petsSchedule = tman.register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000);
srvMessagesSchedule = tman.register(new ServerMessageWorker(this), 10 * 1000, 10 * 1000);
mountsSchedule = tman.register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000);
merchantSchedule = tman.register(new HiredMerchantWorker(this), 10 * 60 * 1000, 10 * 60 * 1000);
timedMapObjectsSchedule = tman.register(new TimedMapObjectWorker(this), 60 * 1000, 60 * 1000);
charactersSchedule = tman.register(new CharacterAutosaverWorker(this), 60 * 60 * 1000, 60 * 60 * 1000);
marriagesSchedule = tman.register(new WeddingReservationWorker(this), ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000, ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000);
@@ -189,7 +197,11 @@ public class World {
public Channel getChannel(int channel) {
chnRLock.lock();
try {
return channels.get(channel - 1);
try {
return channels.get(channel - 1);
} catch (IndexOutOfBoundsException e) {
return null;
}
} finally {
chnRLock.unlock();
}
@@ -731,6 +743,7 @@ public class World {
partyLock.unlock();
}
party.addMember(chrfor);
return party;
}
@@ -784,7 +797,7 @@ public class World {
updateCharacterParty(party, operation, target, partyMembers);
for (MaplePartyCharacter partychar : partyMembers) {
MapleCharacter chr = getPlayerStorage().getCharacterByName(partychar.getName());
MapleCharacter chr = getPlayerStorage().getCharacterById(partychar.getId());
if (chr != null) {
if (operation == PartyOperation.DISBAND) {
chr.setParty(null);
@@ -799,7 +812,7 @@ public class World {
switch (operation) {
case LEAVE:
case EXPEL:
MapleCharacter chr = getPlayerStorage().getCharacterByName(target.getName());
MapleCharacter chr = getPlayerStorage().getCharacterById(target.getId());
if (chr != null) {
chr.getClient().announce(MaplePacketCreator.updateParty(chr.getClient().getChannel(), party, operation, target));
chr.setParty(null);
@@ -1126,7 +1139,7 @@ public class World {
}
public void addOwlItemSearch(Integer itemid) {
owlLock.lock();
srvMessagesLock.lock();
try {
Integer cur = owlSearched.get(itemid);
if(cur != null) {
@@ -1135,7 +1148,7 @@ public class World {
owlSearched.put(itemid, 1);
}
} finally {
owlLock.unlock();
srvMessagesLock.unlock();
}
}
@@ -1144,7 +1157,7 @@ public class World {
return new ArrayList<>(0);
}
owlLock.lock();
srvMessagesLock.lock();
try {
List<Pair<Integer, Integer>> searchCounts = new ArrayList<>(owlSearched.size());
@@ -1154,7 +1167,7 @@ public class World {
return searchCounts;
} finally {
owlLock.unlock();
srvMessagesLock.unlock();
}
}
@@ -1167,7 +1180,7 @@ public class World {
activePetsLock.lock();
try {
byte initProc;
int initProc;
if(System.currentTimeMillis() - petUpdate > 55000) initProc = ServerConstants.PET_EXHAUST_COUNT - 2;
else initProc = ServerConstants.PET_EXHAUST_COUNT - 1;
@@ -1189,7 +1202,7 @@ public class World {
}
public void runPetSchedule() {
Map<Integer, Byte> deployedPets;
Map<Integer, Integer> deployedPets;
activePetsLock.lock();
try {
@@ -1199,11 +1212,11 @@ public class World {
activePetsLock.unlock();
}
for(Map.Entry<Integer, Byte> dp: deployedPets.entrySet()) {
for(Map.Entry<Integer, Integer> dp: deployedPets.entrySet()) {
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey() / 4);
if(chr == null || !chr.isLoggedinWorld()) continue;
Byte dpVal = (byte)(dp.getValue() + 1);
Integer dpVal = dp.getValue() + 1;
if(dpVal == ServerConstants.PET_EXHAUST_COUNT) {
chr.runFullnessSchedule(dp.getKey() % 4);
dpVal = 0;
@@ -1226,7 +1239,7 @@ public class World {
Integer key = chr.getId();
activeMountsLock.lock();
try {
byte initProc;
int initProc;
if(System.currentTimeMillis() - mountUpdate > 45000) initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 2;
else initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 1;
@@ -1248,7 +1261,7 @@ public class World {
}
public void runMountSchedule() {
Map<Integer, Byte> deployedMounts;
Map<Integer, Integer> deployedMounts;
activeMountsLock.lock();
try {
mountUpdate = System.currentTimeMillis();
@@ -1257,11 +1270,11 @@ public class World {
activeMountsLock.unlock();
}
for(Map.Entry<Integer, Byte> dp: deployedMounts.entrySet()) {
for(Map.Entry<Integer, Integer> dp: deployedMounts.entrySet()) {
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey());
if(chr == null || !chr.isLoggedinWorld()) continue;
Byte dpVal = (byte)(dp.getValue() + 1);
int dpVal = dp.getValue() + 1;
if(dpVal == ServerConstants.MOUNT_EXHAUST_COUNT) {
chr.runTirednessSchedule();
dpVal = 0;
@@ -1320,8 +1333,8 @@ public class World {
public void registerHiredMerchant(MapleHiredMerchant hm) {
activeMerchantsLock.lock();
try {
byte initProc;
if(System.currentTimeMillis() - merchantUpdate > 5 * 60 * 1000) initProc = 1;
int initProc;
if(Server.getInstance().getCurrentTime() - merchantUpdate > 5 * 60 * 1000) initProc = 1;
else initProc = 0;
activeMerchants.put(hm.getOwnerId(), new Pair<>(hm, initProc));
@@ -1340,18 +1353,18 @@ public class World {
}
public void runHiredMerchantSchedule() {
Map<Integer, Pair<MapleHiredMerchant, Byte>> deployedMerchants;
Map<Integer, Pair<MapleHiredMerchant, Integer>> deployedMerchants;
activeMerchantsLock.lock();
try {
merchantUpdate = System.currentTimeMillis();
merchantUpdate = Server.getInstance().getCurrentTime();
deployedMerchants = new LinkedHashMap<>(activeMerchants);
for(Map.Entry<Integer, Pair<MapleHiredMerchant, Byte>> dm: deployedMerchants.entrySet()) {
byte timeOn = dm.getValue().getRight();
for(Map.Entry<Integer, Pair<MapleHiredMerchant, Integer>> dm: deployedMerchants.entrySet()) {
int timeOn = dm.getValue().getRight();
MapleHiredMerchant hm = dm.getValue().getLeft();
if(timeOn <= 144) { // 1440 minutes == 24hrs
activeMerchants.put(hm.getOwnerId(), new Pair<>(dm.getValue().getLeft(), (byte)(timeOn + 1)));
activeMerchants.put(hm.getOwnerId(), new Pair<>(dm.getValue().getLeft(), timeOn + 1));
} else {
hm.forceClose();
this.getChannel(hm.getChannel()).removeHiredMerchant(hm.getOwnerId());
@@ -1368,7 +1381,7 @@ public class World {
List<MapleHiredMerchant> hmList = new ArrayList<>();
activeMerchantsLock.lock();
try {
for(Pair<MapleHiredMerchant, Byte> hmp : activeMerchants.values()) {
for(Pair<MapleHiredMerchant, Integer> hmp : activeMerchants.values()) {
MapleHiredMerchant hm = hmp.getLeft();
if(hm.isOpen()) {
hmList.add(hm);
@@ -1397,7 +1410,7 @@ public class World {
public void registerTimedMapObject(Runnable r, long duration) {
timedMapObjectLock.lock();
try {
long expirationTime = System.currentTimeMillis() + duration;
long expirationTime = Server.getInstance().getCurrentTime() + duration;
registeredTimedMapObjects.put(r, expirationTime);
} finally {
timedMapObjectLock.unlock();
@@ -1409,7 +1422,7 @@ public class World {
timedMapObjectLock.lock();
try {
long timeNow = System.currentTimeMillis();
long timeNow = Server.getInstance().getCurrentTime();
for(Entry<Runnable, Long> rtmo : registeredTimedMapObjects.entrySet()) {
if(rtmo.getValue() <= timeNow) {
@@ -1429,6 +1442,68 @@ public class World {
}
}
public void resetDisabledServerMessages() {
srvMessagesLock.lock();
try {
disabledServerMessages.clear();
} finally {
srvMessagesLock.unlock();
}
}
public boolean registerDisabledServerMessage(int chrid) {
srvMessagesLock.lock();
try {
boolean alreadyDisabled = disabledServerMessages.containsKey(chrid);
disabledServerMessages.put(chrid, 0);
return alreadyDisabled;
} finally {
srvMessagesLock.unlock();
}
}
public boolean unregisterDisabledServerMessage(int chrid) {
srvMessagesLock.lock();
try {
return disabledServerMessages.remove(chrid) != null;
} finally {
srvMessagesLock.unlock();
}
}
public void runDisabledServerMessagesSchedule() {
List<Integer> toRemove = new LinkedList<>();
srvMessagesLock.lock();
try {
for(Entry<Integer, Integer> dsm : disabledServerMessages.entrySet()) {
int b = dsm.getValue();
if(b >= 4) { // ~35sec duration, 10sec update
toRemove.add(dsm.getKey());
} else {
disabledServerMessages.put(dsm.getKey(), ++b);
}
}
for(Integer chrid : toRemove) {
disabledServerMessages.remove(chrid);
}
} finally {
srvMessagesLock.unlock();
}
if(!toRemove.isEmpty()) {
for(Integer chrid : toRemove) {
MapleCharacter chr = players.getCharacterById(chrid);
if(chr != null && chr.isLoggedinWorld()) {
chr.announce(MaplePacketCreator.serverMessage(chr.getClient().getChannelServer().getServerMessage()));
}
}
}
}
public void setPlayerNpcMapStep(int mapid, int step) {
setPlayerNpcMapData(mapid, step, -1, false);
}
@@ -1670,7 +1745,7 @@ public class World {
}
}
private void disposeLocks() {
private void clearWorldData() {
List<MapleParty> pList;
partyLock.lock();
try {
@@ -1683,9 +1758,22 @@ public class World {
p.disposeLocks();
}
disposeLocks();
}
private void disposeLocks() {
LockCollector.getInstance().registerDisposeAction(new Runnable() {
@Override
public void run() {
emptyLocks();
}
});
}
private void emptyLocks() {
accountCharsLock = accountCharsLock.dispose();
partyLock = partyLock.dispose();
owlLock = owlLock.dispose();
srvMessagesLock = srvMessagesLock.dispose();
activePetsLock = activePetsLock.dispose();
activeMountsLock = activeMountsLock.dispose();
activePlayerShopsLock = activePlayerShopsLock.dispose();
@@ -1703,11 +1791,21 @@ public class World {
petsSchedule = null;
}
if(srvMessagesSchedule != null) {
srvMessagesSchedule.cancel(false);
srvMessagesSchedule = null;
}
if(mountsSchedule != null) {
mountsSchedule.cancel(false);
mountsSchedule = null;
}
if(merchantSchedule != null) {
merchantSchedule.cancel(false);
merchantSchedule = null;
}
if(timedMapObjectsSchedule != null) {
timedMapObjectsSchedule.cancel(false);
timedMapObjectsSchedule = null;
@@ -1726,6 +1824,6 @@ public class World {
players.disconnectAll();
players = null;
disposeLocks();
clearWorldData();
}
}