445 lines
14 KiB
Java
445 lines
14 KiB
Java
/*
|
|
This file is part of the OdinMS Maple Story Server
|
|
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
|
Matthias Butz <matze@odinms.de>
|
|
Jan Christian Meyer <vimes@odinms.de>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation version 3 as published by
|
|
the Free Software Foundation. You may not use, modify or distribute
|
|
this program under any other version of the GNU Affero General Public
|
|
License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package scripting.event;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Properties;
|
|
import java.util.concurrent.ScheduledFuture;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.script.Invocable;
|
|
import javax.script.ScriptException;
|
|
|
|
import net.server.channel.Channel;
|
|
import net.server.world.MapleParty;
|
|
import net.server.world.MaplePartyCharacter;
|
|
import server.TimerManager;
|
|
import server.expeditions.MapleExpedition;
|
|
import server.maps.MapleMap;
|
|
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.concurrent.locks.Lock;
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
|
|
/**
|
|
*
|
|
* @author Matze
|
|
*/
|
|
public class EventManager {
|
|
private Invocable iv;
|
|
private Channel cserv;
|
|
private Map<String, EventInstanceManager> instances = new HashMap<String, EventInstanceManager>();
|
|
private Map<String, Integer> instanceLocks = new HashMap<String, Integer>();
|
|
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 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.iv = iv;
|
|
this.cserv = cserv;
|
|
this.name = name;
|
|
|
|
this.openedLobbys = new ArrayList<>();
|
|
for(int i = 0; i < maxLobbys; i++) this.openedLobbys.add(false);
|
|
}
|
|
|
|
public void cancel() {
|
|
try {
|
|
iv.invokeFunction("cancelSchedule", (Object) null);
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
|
|
private List<Integer> convertToIntegerArray(List<Double> list) {
|
|
List<Integer> intList = new ArrayList<>();
|
|
for(Double d: list) intList.add(d.intValue());
|
|
|
|
return intList;
|
|
}
|
|
|
|
private List<Integer> getLobbyRange() {
|
|
try {
|
|
return convertToIntegerArray((List<Double>)iv.invokeFunction("setLobbyRange", (Object) null));
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
ex.printStackTrace();
|
|
}
|
|
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
public void schedule(String methodName, long delay) {
|
|
schedule(methodName, null, delay);
|
|
}
|
|
|
|
public void schedule(final String methodName, final EventInstanceManager eim, long delay) {
|
|
schedule = TimerManager.getInstance().schedule(new Runnable() {
|
|
public void run() {
|
|
try {
|
|
iv.invokeFunction(methodName, eim);
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
}, 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() {
|
|
try {
|
|
iv.invokeFunction(methodName, (Object) null);
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
}, timestamp);
|
|
}
|
|
|
|
public Channel getChannelServer() {
|
|
return cserv;
|
|
}
|
|
|
|
public EventInstanceManager getInstance(String name) {
|
|
return instances.get(name);
|
|
}
|
|
|
|
public Collection<EventInstanceManager> getInstances() {
|
|
return Collections.unmodifiableCollection(instances.values());
|
|
}
|
|
|
|
public EventInstanceManager newInstance(String name) {
|
|
EventInstanceManager ret = new EventInstanceManager(this, name);
|
|
instances.put(name, ret);
|
|
return ret;
|
|
}
|
|
|
|
public void disposeInstance(final String name) {
|
|
TimerManager.getInstance().schedule(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
freeLobbyInstance(name);
|
|
instances.remove(name);
|
|
}
|
|
}, lobbyDelay * 1000);
|
|
}
|
|
|
|
public Invocable getIv() {
|
|
return iv;
|
|
}
|
|
|
|
public void setProperty(String key, String value) {
|
|
props.setProperty(key, value);
|
|
}
|
|
|
|
public String getProperty(String key) {
|
|
return props.getProperty(key);
|
|
}
|
|
|
|
public void setProperty(String key, int value) {
|
|
props.setProperty(key, value + "");
|
|
}
|
|
|
|
public int getIntProperty(String key) {
|
|
return Integer.parseInt(props.getProperty(key));
|
|
}
|
|
|
|
private boolean getLockLobby(int lobbyId) {
|
|
l.lock();
|
|
try {
|
|
return openedLobbys.get(lobbyId);
|
|
} finally {
|
|
l.unlock();
|
|
}
|
|
}
|
|
|
|
private void setLockLobby(int lobbyId, boolean lock) {
|
|
l.lock();
|
|
try {
|
|
openedLobbys.set(lobbyId, lock);
|
|
} finally {
|
|
l.unlock();
|
|
}
|
|
}
|
|
|
|
private boolean startLobbyInstance(int lobbyId) {
|
|
l.lock();
|
|
try {
|
|
if(!openedLobbys.get(lobbyId)) {
|
|
openedLobbys.set(lobbyId, true);
|
|
return true;
|
|
}
|
|
} finally {
|
|
l.unlock();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void freeLobbyInstance(String lobbyName) {
|
|
Integer i = instanceLocks.get(lobbyName);
|
|
if(i == null) return;
|
|
|
|
instanceLocks.remove(lobbyName);
|
|
if(i > -1) setLockLobby(i, false);
|
|
}
|
|
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
public int availableLobbyInstance() {
|
|
List<Integer> lr = getLobbyRange();
|
|
int lb = 0, hb = 0;
|
|
|
|
if(lr.size() >= 2) {
|
|
lb = Math.max(lr.get(0), 0);
|
|
hb = Math.min(lr.get(1), maxLobbys - 1);
|
|
}
|
|
|
|
for(int i = lb; i <= hb; i++) {
|
|
if(startLobbyInstance(i)) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public boolean startInstance(MapleExpedition exped) {
|
|
return startInstance(-1, exped);
|
|
}
|
|
|
|
//Expedition method: starts an expedition
|
|
public boolean startInstance(int lobbyId, MapleExpedition exped) {
|
|
try {
|
|
if(lobbyId == -1) {
|
|
lobbyId = availableLobbyInstance();
|
|
if(lobbyId == -1) return false;
|
|
}
|
|
else {
|
|
if(getLockLobby(lobbyId)) return false;
|
|
startLobbyInstance(lobbyId);
|
|
}
|
|
|
|
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.registerExpedition(exped);
|
|
exped.start();
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//Regular method: player
|
|
public boolean startInstance(MapleCharacter chr) {
|
|
return startInstance(-1, chr);
|
|
}
|
|
|
|
public boolean startInstance(int lobbyId, MapleCharacter chr) {
|
|
try {
|
|
if(lobbyId == -1) {
|
|
lobbyId = availableLobbyInstance();
|
|
if(lobbyId == -1) return false;
|
|
}
|
|
else {
|
|
if(getLockLobby(lobbyId)) return false;
|
|
startLobbyInstance(lobbyId);
|
|
}
|
|
|
|
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.registerPlayer(chr);
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//PQ method: starts a PQ
|
|
public boolean startInstance(MapleParty party, MapleMap map) {
|
|
return startInstance(-1, party, map);
|
|
}
|
|
|
|
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map) {
|
|
try {
|
|
if(lobbyId == -1) {
|
|
lobbyId = availableLobbyInstance();
|
|
if(lobbyId == -1) return false;
|
|
}
|
|
else {
|
|
if(getLockLobby(lobbyId)) return false;
|
|
startLobbyInstance(lobbyId);
|
|
}
|
|
|
|
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.registerParty(party, map);
|
|
party.setEligibleMembers(null);
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//PQ method: starts a PQ with a difficulty level, requires function setup(difficulty, leaderid) instead of setup()
|
|
public boolean startInstance(MapleParty party, MapleMap map, int difficulty) {
|
|
return startInstance(-1, party, map, difficulty);
|
|
}
|
|
|
|
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, int difficulty) {
|
|
try {
|
|
if(lobbyId == -1) {
|
|
lobbyId = availableLobbyInstance();
|
|
if(lobbyId == -1) return false;
|
|
}
|
|
else {
|
|
if(getLockLobby(lobbyId)) return false;
|
|
startLobbyInstance(lobbyId);
|
|
}
|
|
|
|
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.registerParty(party, map);
|
|
party.setEligibleMembers(null);
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//non-PQ method for starting instance
|
|
public boolean startInstance(EventInstanceManager eim, String leader) {
|
|
return startInstance(-1, eim, leader);
|
|
}
|
|
|
|
public boolean startInstance(int lobbyId, EventInstanceManager eim, String leader) {
|
|
try {
|
|
if(lobbyId == -1) {
|
|
lobbyId = availableLobbyInstance();
|
|
if(lobbyId == -1) return false;
|
|
}
|
|
else {
|
|
if(getLockLobby(lobbyId)) return false;
|
|
startLobbyInstance(lobbyId);
|
|
}
|
|
|
|
if(eim == null) {
|
|
if(lobbyId > -1) setLockLobby(lobbyId, false);
|
|
return false;
|
|
}
|
|
instanceLocks.put(eim.getName(), lobbyId);
|
|
|
|
iv.invokeFunction("setup", eim);
|
|
eim.setProperty("leader", leader);
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public List<MaplePartyCharacter> getEligibleParty(MapleParty party) {
|
|
if (party == null) {
|
|
return(new ArrayList<>());
|
|
}
|
|
try {
|
|
Object p = iv.invokeFunction("getEligibleParty", party.getPartyMembers());
|
|
|
|
if(p != null) {
|
|
List<MaplePartyCharacter> lmpc = new ArrayList<>((List<MaplePartyCharacter>) p);
|
|
party.setEligibleMembers(lmpc);
|
|
return lmpc;
|
|
}
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
ex.printStackTrace();
|
|
}
|
|
|
|
return(new ArrayList<>());
|
|
}
|
|
|
|
public void clearPQ(EventInstanceManager eim) {
|
|
try {
|
|
iv.invokeFunction("clearPQ", eim);
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
|
|
public void clearPQ(EventInstanceManager eim, MapleMap toMap) {
|
|
try {
|
|
iv.invokeFunction("clearPQ", eim, toMap);
|
|
} catch (ScriptException | NoSuchMethodException ex) {
|
|
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
|
|
public MapleMonster getMonster(int mid) {
|
|
return(MapleLifeFactory.getMonster(mid));
|
|
}
|
|
}
|