GuildPQ Queue system + revamped Warp mechanic

Added a queue system for waiting guilds outside the GPQ area. Changed
the way players are transported through maps on non-portal passing
cases: if not defined, a spawn point is chosen randomly for each player.
This commit is contained in:
ronancpl
2017-06-13 20:47:58 -03:00
parent 7a8bba98ca
commit 81f9226286
82 changed files with 669 additions and 375 deletions

View File

@@ -528,6 +528,10 @@ public class AbstractPlayerInteraction {
public MapleParty getParty() {
return getPlayer().getParty();
}
public boolean isGuildLeader() {
return getPlayer().isGuildLeader();
}
public boolean isLeader() {
if(getParty() == null)
@@ -535,6 +539,10 @@ public class AbstractPlayerInteraction {
return getParty().getLeaderId() == getPlayer().getId();
}
public boolean isEventLeader() {
return getEventInstance() != null && getPlayer().getId() == getEventInstance().getLeaderId();
}
public void givePartyItems(int id, short quantity, List<MapleCharacter> party) {
for (MapleCharacter chr : party) {

View File

@@ -31,6 +31,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;
import java.util.Properties;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
@@ -69,7 +70,8 @@ import tools.MaplePacketCreator;
* @author Matze, Ronan
*/
public class EventInstanceManager {
private List<MapleCharacter> chars = new ArrayList<>();
private Map<Integer, MapleCharacter> chars = new HashMap<>();
private int leaderId = -1;
private List<MapleMonster> mobs = new LinkedList<>();
private Map<MapleCharacter, Integer> killCount = new HashMap<>();
private EventManager em;
@@ -103,7 +105,7 @@ public class EventInstanceManager {
// registers all opened gates on the event. Will help late characters to encounter next stages gates already opened
private Set<Integer> openedGates = new HashSet<>();
// forces deletion of items not supposed to be holding out of the event, dealt on a player's leave moment.
// forces deletion of items not supposed to be held outside of the event, dealt on a player's leaving moment.
private Set<Integer> exclusiveItems = new HashSet<>();
public EventInstanceManager(EventManager em, String name) {
@@ -209,7 +211,7 @@ public class EventInstanceManager {
try {
wL.lock();
try {
chars.add(chr);
chars.put(chr.getId(), chr);
}
finally {
wL.unlock();
@@ -238,12 +240,15 @@ public class EventInstanceManager {
timeStarted = System.currentTimeMillis();
eventTime = time;
for(MapleCharacter chr: getPlayers()) chr.announce(MaplePacketCreator.getClock((int) (time / 1000)));
for(MapleCharacter chr: getPlayers()) {
chr.announce(MaplePacketCreator.getClock((int) (time / 1000)));
}
event_schedule = TimerManager.getInstance().schedule(new Runnable() {
public void run() {
try {
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
dismissEventTimer();
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
@@ -260,8 +265,8 @@ public class EventInstanceManager {
event_schedule = TimerManager.getInstance().schedule(new Runnable() {
public void run() {
try {
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
dismissEventTimer();
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
@@ -274,14 +279,6 @@ public class EventInstanceManager {
}
}
public void stopEventTimer() {
if(event_schedule != null) {
event_schedule.cancel(false);
event_schedule = null;
}
dismissEventTimer();
}
private void dismissEventTimer() {
for(MapleCharacter chr: getPlayers()) {
chr.getClient().getSession().write(MaplePacketCreator.removeClock());
@@ -292,6 +289,14 @@ public class EventInstanceManager {
timeStarted = 0;
}
public void stopEventTimer() {
if(event_schedule != null) {
event_schedule.cancel(false);
event_schedule = null;
}
dismissEventTimer();
}
public boolean isTimerStarted() {
return eventTime > 0 && timeStarted > 0;
}
@@ -300,6 +305,12 @@ public class EventInstanceManager {
return eventTime - (System.currentTimeMillis() - timeStarted);
}
public void registerParty(MapleCharacter chr) {
if(chr.isPartyLeader()) {
registerParty(chr.getParty(), chr.getMap());
}
}
public void registerParty(MapleParty party, MapleMap map) {
for (MaplePartyCharacter pc : party.getEligibleMembers()) {
MapleCharacter c = map.getCharacterById(pc.getId());
@@ -321,7 +332,7 @@ public class EventInstanceManager {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
chars.remove(chr);
chars.remove(chr.getId());
gridRemove(chr);
dropExclusiveItems(chr);
} finally {
@@ -344,7 +355,7 @@ public class EventInstanceManager {
public List<MapleCharacter> getPlayers() {
rL.lock();
try {
return new ArrayList<>(chars);
return new ArrayList<>(chars.values());
}
finally {
rL.unlock();
@@ -354,7 +365,7 @@ public class EventInstanceManager {
private List<MapleCharacter> getPlayerList() {
rL.lock();
try {
return new LinkedList<>(chars);
return new LinkedList<>(chars.values());
} finally {
rL.unlock();
}
@@ -478,7 +489,7 @@ public class EventInstanceManager {
wL.lock();
try {
for(MapleCharacter chr: chars) chr.setEventInstance(null);
for(MapleCharacter chr: chars.values()) chr.setEventInstance(null);
chars.clear();
mobs.clear();
@@ -612,6 +623,10 @@ public class EventInstanceManager {
return (chr.getParty().getLeaderId() == chr.getId());
}
public boolean isEventLeader(MapleCharacter chr) {
return (chr.getId() == getLeaderId());
}
public final MapleMap getInstanceMap(final int mapid) { //gets instance map from the channelserv
if (disposed) {
return getMapFactory().getMap(mapid);
@@ -829,10 +844,27 @@ public class EventInstanceManager {
return eventCleared;
}
private boolean isEventTeamLeaderOn() {
for(MapleCharacter chr: getPlayers()) {
if(chr.getId() == getLeaderId()) return true;
}
return false;
}
public final boolean checkEventTeamLacking(boolean testLeader, int minPlayers) {
if(eventCleared && getPlayerCount() > 1) return false;
if(!eventCleared && testLeader && !isEventTeamLeaderOn()) return true;
if(getPlayerCount() < minPlayers) return true;
return false;
}
public final boolean isEventTeamLackingNow(boolean testLeader, int minPlayers, MapleCharacter quitter) {
if(eventCleared && getPlayerCount() > 1) return false;
if(!eventCleared && testLeader && getLeader().getId() == quitter.getId()) return true;
if(!eventCleared && testLeader && getLeaderId() == quitter.getId()) return true;
if(getPlayerCount() <= minPlayers) return true;
return false;
@@ -842,12 +874,16 @@ public class EventInstanceManager {
rL.lock();
try {
if(chars.size() <= 1) return true;
int mapId = chars.get(0).getMapId();
for(int i = 1; i < chars.size(); i++) {
if(chars.get(i).getMapId() != mapId) return false;
Iterator<MapleCharacter> iterator = chars.values().iterator();
MapleCharacter mc = iterator.next();
int mapId = mc.getMapId();
for (; iterator.hasNext();) {
mc = iterator.next();
if(mc.getMapId() != mapId) return false;
}
return true;
} finally {
rL.unlock();
@@ -888,19 +924,33 @@ public class EventInstanceManager {
}
}
public final MapleCharacter getLeader() {
public final int getLeaderId() {
rL.lock();
try {
for (MapleCharacter chr : chars) {
if(chr.isPartyLeader()) return chr;
}
return null;
return leaderId;
} finally {
rL.unlock();
}
}
public MapleCharacter getLeader() {
rL.lock();
try {
return chars.get(leaderId);
} finally {
rL.unlock();
}
}
public final void setLeader(MapleCharacter chr) {
wL.lock();
try {
leaderId = chr.getId();
} finally {
wL.unlock();
}
}
public final void showWrongEffect() {
MapleMap map = getMapInstance(getLeader().getMapId());
map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/wrong_kor"));

View File

@@ -33,7 +33,10 @@ import java.util.logging.Logger;
import javax.script.Invocable;
import javax.script.ScriptException;
import net.server.Server;
import net.server.world.World;
import net.server.channel.Channel;
import net.server.guild.MapleGuild;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import server.TimerManager;
@@ -43,10 +46,10 @@ import server.life.MapleMonster;
import server.life.MapleLifeFactory;
import client.MapleCharacter;
import java.util.LinkedList;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Array;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -57,20 +60,26 @@ import java.util.concurrent.locks.ReentrantLock;
public class EventManager {
private Invocable iv;
private Channel cserv;
private World wserv;
private Server server;
private Map<String, EventInstanceManager> instances = new HashMap<String, EventInstanceManager>();
private Map<String, Integer> instanceLocks = new HashMap<String, Integer>();
private final Queue<Integer> queuedGuilds = new LinkedList<>();
private final Map<Integer, Integer> queuedGuildLeaders = new HashMap<>();
private List<Boolean> openedLobbys;
private Properties props = new Properties();
private String name;
private ScheduledFuture<?> schedule = null;
private Lock l = new ReentrantLock();
private static final int limitGuilds = 10; // max numbers of guilds in queue for GPQ.
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
private static final long lobbyDelay = 10; // 10 seconds cooldown before reopening a lobby
public EventManager(Channel cserv, Invocable iv, String name) {
this.server = Server.getInstance();
this.iv = iv;
this.cserv = cserv;
this.wserv = server.getWorld(cserv.getWorld());
this.name = name;
this.openedLobbys = new ArrayList<>();
@@ -92,6 +101,10 @@ public class EventManager {
return intList;
}
public long getLobbyDelay() {
return lobbyDelay;
}
private List<Integer> getLobbyRange() {
try {
return convertToIntegerArray((List<Double>)iv.invokeFunction("setLobbyRange", (Object) null));
@@ -104,12 +117,12 @@ public class EventManager {
}
}
public void schedule(String methodName, long delay) {
schedule(methodName, null, delay);
public ScheduledFuture<?> schedule(String methodName, long delay) {
return schedule(methodName, null, delay);
}
public void schedule(final String methodName, final EventInstanceManager eim, long delay) {
schedule = TimerManager.getInstance().schedule(new Runnable() {
public ScheduledFuture<?> schedule(final String methodName, final EventInstanceManager eim, long delay) {
return TimerManager.getInstance().schedule(new Runnable() {
public void run() {
try {
iv.invokeFunction(methodName, eim);
@@ -120,11 +133,6 @@ public class EventManager {
}, delay);
}
public void cancelSchedule() {
if(schedule != null)
schedule.cancel(false);
}
public ScheduledFuture<?> scheduleAtTimestamp(final String methodName, long timestamp) {
return TimerManager.getInstance().scheduleAtTimestamp(new Runnable() {
public void run() {
@@ -250,9 +258,13 @@ public class EventManager {
public boolean startInstance(MapleExpedition exped) {
return startInstance(-1, exped);
}
public boolean startInstance(int lobbyId, MapleExpedition exped) {
return startInstance(lobbyId, exped, exped.getLeader());
}
//Expedition method: starts an expedition
public boolean startInstance(int lobbyId, MapleExpedition exped) {
public boolean startInstance(int lobbyId, MapleExpedition exped, MapleCharacter leader) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -269,6 +281,7 @@ public class EventManager {
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
eim.registerExpedition(exped);
exped.start();
@@ -286,6 +299,10 @@ public class EventManager {
}
public boolean startInstance(int lobbyId, MapleCharacter chr) {
return startInstance(lobbyId, chr, chr, 1);
}
public boolean startInstance(int lobbyId, MapleCharacter chr, MapleCharacter leader, int difficulty) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -296,12 +313,13 @@ public class EventManager {
startLobbyInstance(lobbyId);
}
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null));
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);
eim.registerPlayer(chr);
iv.invokeFunction("afterSetup", eim);
@@ -318,6 +336,10 @@ public class EventManager {
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map) {
return startInstance(lobbyId, party, map, party.getLeader().getPlayer());
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, MapleCharacter leader) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -334,6 +356,7 @@ public class EventManager {
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
eim.registerParty(party, map);
party.setEligibleMembers(null);
@@ -351,6 +374,10 @@ public class EventManager {
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, int difficulty) {
return startInstance(lobbyId, party, map, difficulty, party.getLeader().getPlayer());
}
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, int difficulty, MapleCharacter leader) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -367,6 +394,7 @@ public class EventManager {
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
eim.registerParty(party, map);
party.setEligibleMembers(null);
@@ -379,11 +407,19 @@ public class EventManager {
}
//non-PQ method for starting instance
public boolean startInstance(EventInstanceManager eim, String leader) {
return startInstance(-1, eim, leader);
public boolean startInstance(EventInstanceManager eim, String ldr) {
return startInstance(-1, eim, ldr);
}
public boolean startInstance(int lobbyId, EventInstanceManager eim, String leader) {
public boolean startInstance(EventInstanceManager eim, MapleCharacter ldr) {
return startInstance(-1, eim, ldr.getName(), ldr);
}
public boolean startInstance(int lobbyId, EventInstanceManager eim, String ldr) {
return startInstance(-1, eim, ldr, eim.getEm().getChannelServer().getPlayerStorage().getCharacterByName(ldr)); // things they make me do...
}
public boolean startInstance(int lobbyId, EventInstanceManager eim, String ldr, MapleCharacter leader) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
@@ -399,9 +435,10 @@ public class EventManager {
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
iv.invokeFunction("setup", eim);
eim.setProperty("leader", leader);
eim.setProperty("leader", ldr);
iv.invokeFunction("afterSetup", eim);
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
@@ -448,4 +485,115 @@ public class EventManager {
public MapleMonster getMonster(int mid) {
return(MapleLifeFactory.getMonster(mid));
}
private static String ordinal(int i) {
String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
switch (i % 100) {
case 11:
case 12:
case 13:
return i + "th";
default:
return i + sufixes[i % 10];
}
}
private void exportReadyGuild(Integer guildId) {
MapleGuild mg = server.getGuild(guildId);
String callout = "Your guild has been registered to attend to the Sharenian Guild Quest at channel " + this.getChannelServer().getId()
+ " and JUST STARTED THE STRATEGY PHASE. After 3 minutes, no more guild members will be allowed to join the effort.";
mg.dropMessage(0, callout);
}
private void exportMovedQueueToGuild(Integer guildId, int place) {
MapleGuild mg = server.getGuild(guildId);
String callout = "Your guild has been registered to attend to the Sharenian Guild Quest at channel " + this.getChannelServer().getId()
+ " and is currently on the " + ordinal(place) + " place on the waiting queue.";
mg.dropMessage(0, callout);
}
private List<Integer> getNextGuildQueue() {
synchronized(queuedGuilds) {
Integer guildId = queuedGuilds.poll();
if(guildId == null) return null;
wserv.removeGuildQueued(guildId);
Integer leaderId = queuedGuildLeaders.remove(guildId);
exportReadyGuild(guildId);
int place = 1;
for(Integer i: queuedGuilds) {
exportMovedQueueToGuild(i, place);
place++;
}
List<Integer> list = new ArrayList<>(2);
list.add(guildId); list.add(leaderId);
return list;
}
}
public boolean isQueueFull() {
synchronized(queuedGuilds) {
return queuedGuilds.size() >= limitGuilds;
}
}
public int getQueueSize() {
synchronized(queuedGuilds) {
return queuedGuilds.size();
}
}
public byte addGuildToQueue(Integer guildId, Integer leaderId) {
if(wserv.isGuildQueued(guildId)) return -1;
if(!isQueueFull()) {
boolean canStartAhead;
synchronized(queuedGuilds) {
canStartAhead = queuedGuilds.isEmpty();
queuedGuilds.add(guildId);
wserv.putGuildQueued(guildId);
queuedGuildLeaders.put(guildId, leaderId);
int place = queuedGuilds.size();
exportMovedQueueToGuild(guildId, place);
}
if(canStartAhead) {
if(!attemptStartGuildInstance()) {
synchronized(queuedGuilds) {
queuedGuilds.add(guildId);
wserv.putGuildQueued(guildId);
queuedGuildLeaders.put(guildId, leaderId);
}
} else {
return 2;
}
}
return 1;
} else {
return 0;
}
}
public boolean attemptStartGuildInstance() {
MapleCharacter chr = null;
while(chr == null) {
List<Integer> guildInstance = getNextGuildQueue();
if(guildInstance == null) {
return false;
}
chr = cserv.getPlayerStorage().getCharacterById(guildInstance.get(1));
}
return startInstance(chr);
}
}