Persistent diseases + PQ request system + GuildPQ fix
Implemented persistent diseases. Players now keep their disease status when logging out the game. Solved several concurrent access issues in MapleMap and MapleMonster. Implemented an option where an account's character slots can be accounted either by each world or all-server range. Fixed some issues with character slot count when entering/exiting Cash Shop. Fixed an exploit with Papulatus, on where players could create cracks of dimension infinitely. Solved an issue with the "reach" command not working properly when the targeted player is on an event instance. Devised an advanced and secure "PQ request" system. The service revolves around expecting massive number of players requesting a "pass" simultaneously, and fairly & swiftly responsing as much people as possible. Improved overall Whisper handler performance. Fixed GPQ Stage 1 statues not working as expected, which rendered the instance unplayable until now. Added commands for start, complete and reset quests.
This commit is contained in:
@@ -224,14 +224,18 @@ public class EventInstanceManager {
|
||||
|
||||
}
|
||||
|
||||
public void registerPlayer(MapleCharacter chr) {
|
||||
if (chr == null || !chr.isLoggedin()){
|
||||
public synchronized void registerPlayer(MapleCharacter chr) {
|
||||
if (chr == null || !chr.isLoggedinWorld() || disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
wL.lock();
|
||||
try {
|
||||
if(chars.containsKey(chr.getId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
chars.put(chr.getId(), chr);
|
||||
chr.setEventInstance(this);
|
||||
} finally {
|
||||
@@ -249,7 +253,7 @@ public class EventInstanceManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void exitPlayer(MapleCharacter chr) { //unused
|
||||
public void exitPlayer(MapleCharacter chr) {
|
||||
if (chr == null || !chr.isLoggedin()){
|
||||
return;
|
||||
}
|
||||
@@ -299,7 +303,7 @@ public class EventInstanceManager {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement scheduledTimeout function.", ex);
|
||||
}
|
||||
}
|
||||
}, time);
|
||||
@@ -324,7 +328,7 @@ public class EventInstanceManager {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement scheduledTimeout function.", ex);
|
||||
}
|
||||
}
|
||||
}, nextTime);
|
||||
@@ -397,7 +401,7 @@ public class EventInstanceManager {
|
||||
sL.unlock();
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement playerUnregistered function.", ex);
|
||||
}
|
||||
|
||||
wL.lock();
|
||||
|
||||
@@ -48,10 +48,14 @@ import server.life.MapleMonster;
|
||||
import server.life.MapleLifeFactory;
|
||||
import server.quest.MapleQuest;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
@@ -74,12 +78,16 @@ public class EventManager {
|
||||
private final Map<Integer, Integer> queuedGuildLeaders = new HashMap<>();
|
||||
private List<Boolean> openedLobbys;
|
||||
private List<EventInstanceManager> readyInstances = new LinkedList<>();
|
||||
private Integer readyId = 0;
|
||||
private Integer readyId = 0, onLoadInstances = 0;
|
||||
private Properties props = new Properties();
|
||||
private String name;
|
||||
private MonitoredReentrantLock lobbyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_LOBBY);
|
||||
private MonitoredReentrantLock queueLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_QUEUE);
|
||||
|
||||
private MonitoredReentrantLock startLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_START);
|
||||
|
||||
private Set<Integer> playerPermit = new HashSet<>();
|
||||
private Semaphore startSemaphore = new Semaphore(7);
|
||||
|
||||
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
|
||||
|
||||
public EventManager(Channel cserv, Invocable iv, String name) {
|
||||
@@ -114,6 +122,7 @@ public class EventManager {
|
||||
try {
|
||||
readyEims = new ArrayList<>(readyInstances);
|
||||
readyInstances.clear();
|
||||
onLoadInstances = Integer.MIN_VALUE / 2;
|
||||
} finally {
|
||||
queueLock.unlock();
|
||||
}
|
||||
@@ -143,6 +152,7 @@ public class EventManager {
|
||||
private void emptyLocks() {
|
||||
lobbyLock = lobbyLock.dispose();
|
||||
queueLock = queueLock.dispose();
|
||||
startLock = startLock.dispose();
|
||||
}
|
||||
|
||||
private static List<Integer> convertToIntegerArray(List<Double> list) {
|
||||
@@ -333,33 +343,50 @@ public class EventManager {
|
||||
//Expedition method: starts an expedition
|
||||
public boolean startInstance(int lobbyId, MapleExpedition exped, MapleCharacter leader) {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) return false;
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) return false;
|
||||
}
|
||||
|
||||
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", leader.getClient().getChannel()));
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
|
||||
playerPermit.add(leader.getId());
|
||||
|
||||
startLock.lock();
|
||||
try {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) return false;
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) return false;
|
||||
}
|
||||
|
||||
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", leader.getClient().getChannel()));
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
exped.start();
|
||||
eim.registerExpedition(exped);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
startLock.unlock();
|
||||
playerPermit.remove(leader.getId());
|
||||
startSemaphore.release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
exped.start();
|
||||
eim.registerExpedition(exped);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch(InterruptedException ie) {
|
||||
playerPermit.remove(leader.getId());
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//Regular method: player
|
||||
@@ -373,36 +400,53 @@ public class EventManager {
|
||||
|
||||
public boolean startInstance(int lobbyId, MapleCharacter chr, MapleCharacter leader, int difficulty) {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) {
|
||||
return false;
|
||||
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
|
||||
playerPermit.add(leader.getId());
|
||||
|
||||
startLock.lock();
|
||||
try {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : leader.getId()));
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
if(chr != null) eim.registerPlayer(chr);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
startLock.unlock();
|
||||
playerPermit.remove(leader.getId());
|
||||
startSemaphore.release();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : leader.getId()));
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
if(chr != null) eim.registerPlayer(chr);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch(InterruptedException ie) {
|
||||
playerPermit.remove(leader.getId());
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//PQ method: starts a PQ
|
||||
@@ -416,33 +460,50 @@ public class EventManager {
|
||||
|
||||
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, MapleCharacter leader) {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) return false;
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) return false;
|
||||
}
|
||||
|
||||
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null));
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
|
||||
playerPermit.add(leader.getId());
|
||||
|
||||
startLock.lock();
|
||||
try {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) return false;
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) return false;
|
||||
}
|
||||
|
||||
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null));
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
eim.registerParty(party, map);
|
||||
party.setEligibleMembers(null);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
startLock.unlock();
|
||||
playerPermit.remove(leader.getId());
|
||||
startSemaphore.release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
eim.registerParty(party, map);
|
||||
party.setEligibleMembers(null);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch(InterruptedException ie) {
|
||||
playerPermit.remove(leader.getId());
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//PQ method: starts a PQ with a difficulty level, requires function setup(difficulty, leaderid) instead of setup()
|
||||
@@ -456,33 +517,50 @@ public class EventManager {
|
||||
|
||||
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, int difficulty, MapleCharacter leader) {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) return false;
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) return false;
|
||||
}
|
||||
|
||||
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : party.getLeaderId()));
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
|
||||
playerPermit.add(leader.getId());
|
||||
|
||||
startLock.lock();
|
||||
try {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) return false;
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) return false;
|
||||
}
|
||||
|
||||
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : party.getLeaderId()));
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
eim.registerParty(party, map);
|
||||
party.setEligibleMembers(null);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
startLock.unlock();
|
||||
playerPermit.remove(leader.getId());
|
||||
startSemaphore.release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
eim.registerParty(party, map);
|
||||
party.setEligibleMembers(null);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch(InterruptedException ie) {
|
||||
playerPermit.remove(leader.getId());
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//non-PQ method for starting instance
|
||||
@@ -500,32 +578,49 @@ public class EventManager {
|
||||
|
||||
public boolean startInstance(int lobbyId, EventInstanceManager eim, String ldr, MapleCharacter leader) {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) return false;
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) return false;
|
||||
}
|
||||
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
|
||||
playerPermit.add(leader.getId());
|
||||
|
||||
startLock.lock();
|
||||
try {
|
||||
try {
|
||||
if(lobbyId == -1) {
|
||||
lobbyId = availableLobbyInstance();
|
||||
if(lobbyId == -1) return false;
|
||||
}
|
||||
else {
|
||||
if(!startLobbyInstance(lobbyId)) return false;
|
||||
}
|
||||
|
||||
if(eim == null) {
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
iv.invokeFunction("setup", eim);
|
||||
eim.setProperty("leader", ldr);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
startLock.unlock();
|
||||
playerPermit.remove(leader.getId());
|
||||
startSemaphore.release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
iv.invokeFunction("setup", eim);
|
||||
eim.setProperty("leader", ldr);
|
||||
|
||||
eim.startEvent();
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch(InterruptedException ie) {
|
||||
playerPermit.remove(leader.getId());
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<MaplePartyCharacter> getEligibleParty(MapleParty party) {
|
||||
@@ -713,16 +808,31 @@ public class EventManager {
|
||||
}
|
||||
|
||||
private void instantiateQueuedInstance() {
|
||||
int nextEventId;
|
||||
queueLock.lock();
|
||||
try {
|
||||
if(readyInstances.size() >= Math.ceil((double)maxLobbys / 3.0)) return;
|
||||
if(onLoadInstances <= -1000 || readyInstances.size() + onLoadInstances >= Math.ceil((double)maxLobbys / 3.0)) return;
|
||||
|
||||
readyInstances.add(new EventInstanceManager(this, "sampleName" + readyId));
|
||||
onLoadInstances++;
|
||||
nextEventId = readyId;
|
||||
readyId++;
|
||||
} finally {
|
||||
queueLock.unlock();
|
||||
}
|
||||
|
||||
EventInstanceManager eim = new EventInstanceManager(this, "sampleName" + nextEventId);
|
||||
queueLock.lock();
|
||||
try {
|
||||
if(onLoadInstances <= -1000) { // EM already disposed
|
||||
return;
|
||||
}
|
||||
|
||||
readyInstances.add(eim);
|
||||
onLoadInstances--;
|
||||
} finally {
|
||||
queueLock.unlock();
|
||||
}
|
||||
|
||||
instantiateQueuedInstance(); // keep filling the queue until reach threshold.
|
||||
}
|
||||
|
||||
|
||||
@@ -344,7 +344,9 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
|
||||
|
||||
public void gainCloseness(int closeness) {
|
||||
for (MaplePet pet : getPlayer().getPets()) {
|
||||
if(pet != null) pet.gainClosenessFullness(getPlayer(), closeness, 0, 0);
|
||||
if(pet != null) {
|
||||
pet.gainClosenessFullness(getPlayer(), closeness, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user