White scroll & PiratePQ fix + Party for starters + concurrency protection on event scripts

Fixed successful scrolled items not using up an upgrade slot when using white scroll. Fixed some issues with the PiratePQ and added a "clear all boxes to complete a stage"-mode. Added "Party for Starters" feature. Added concurrency protection on event script modules.
This commit is contained in:
ronancpl
2017-10-13 03:31:51 -03:00
parent 6e1442af30
commit 1ec7487bd3
96 changed files with 470 additions and 109 deletions

View File

@@ -147,6 +147,7 @@ import constants.skills.Spearman;
import constants.skills.SuperGM;
import constants.skills.Swordsman;
import constants.skills.ThunderBreaker;
import net.server.channel.handlers.PartyOperationHandler;
import scripting.item.ItemScriptManager;
import server.maps.MapleMapItem;
@@ -1902,7 +1903,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}, healInterval, healInterval);
}
public void disableDoor() {
public void disableDoorSpawn() {
canDoor = false;
TimerManager.getInstance().schedule(new Runnable() {
@Override
@@ -4803,6 +4804,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
recalcLocalStats();
setMPC(new MaplePartyCharacter(this));
silentPartyUpdate();
if(level == 10 && party != null) {
if(this.isPartyLeader()) party.assignNewLeader(client);
PartyOperationHandler.leaveParty(party, mpc, client);
client.announceHint("You have reached #blevel 10#k, therefore you must leave your #rstarter party#k.");
}
if (this.guildid > 0) {
getGuild().broadcast(MaplePacketCreator.levelUpMessage(2, level, name), this.getId());
}

View File

@@ -43,6 +43,7 @@ public class ServerConstants {
public static final boolean USE_ITEM_SORT = true;
public static final boolean USE_ITEM_SORT_BY_NAME = false; //Item sorting based on name rather than id.
public static final boolean USE_PARTY_SEARCH = false;
public static final boolean USE_PARTY_FOR_STARTERS = true; //Players level 10 or below can create/invite other players on the given level range.
public static final boolean USE_AUTOBAN = false; //Commands the server to detect infractors automatically.
public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
@@ -53,7 +54,7 @@ public class ServerConstants {
public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped.
public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll.
public static final boolean USE_BUFF_MOST_SIGNIFICANT = true; //When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats.
public static final boolean USE_UNDERLEVELED_EXP_BLOCK = true; //Players 20 levels below the killed mob will gain no experience from defeating it.
public static final boolean USE_UNDERLEVELED_EXP_BLOCK = true; //Players 20 levels below the killed mob will gain no experience from defeating it.
//Server Rates And Experience
public static final int EXP_RATE = 10;

View File

@@ -30,11 +30,38 @@ import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleCharacter;
import client.MapleClient;
import constants.ServerConstants;
import scripting.event.EventInstanceManager;
import server.maps.MapleMap;
public final class PartyOperationHandler extends AbstractMaplePacketHandler {
public static void leaveParty(MapleParty party, MaplePartyCharacter partyplayer, MapleClient c) {
World world = c.getWorldServer();
MapleCharacter player = c.getPlayer();
if (party != null && partyplayer != null) {
if (partyplayer.getId() == party.getLeaderId()) {
c.getWorldServer().removeMapPartyMembers(party.getId());
world.updateParty(party.getId(), PartyOperation.DISBAND, partyplayer);
if (player.getEventInstance() != null) {
player.getEventInstance().disbandParty();
}
} else {
player.getMap().removePartyMember(player);
world.updateParty(party.getId(), PartyOperation.LEAVE, partyplayer);
if (player.getEventInstance() != null) {
player.getEventInstance().leftParty(player);
}
}
player.setParty(null);
}
}
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int operation = slea.readByte();
MapleCharacter player = c.getPlayer();
@@ -43,46 +70,28 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
MaplePartyCharacter partyplayer = player.getMPC();
switch (operation) {
case 1: { // create
if(player.getLevel() < 10) {
c.announce(MaplePacketCreator.partyStatusMessage(10));
return;
if(player.getLevel() < 10 && !ServerConstants.USE_PARTY_FOR_STARTERS) {
c.announce(MaplePacketCreator.partyStatusMessage(10));
return;
}
if (player.getParty() == null) {
partyplayer = new MaplePartyCharacter(player);
party = world.createParty(partyplayer);
player.setParty(party);
player.setMPC(partyplayer);
player.getMap().addPartyMember(player);
player.silentPartyUpdate();
c.announce(MaplePacketCreator.partyCreated(partyplayer));
partyplayer = new MaplePartyCharacter(player);
party = world.createParty(partyplayer);
player.setParty(party);
player.setMPC(partyplayer);
player.getMap().addPartyMember(player);
player.silentPartyUpdate();
c.announce(MaplePacketCreator.partyCreated(partyplayer));
} else {
c.announce(MaplePacketCreator.serverNotice(5, "You can't create a party as you are already in one."));
}
break;
}
case 2: {
if (party != null && partyplayer != null) {
if (partyplayer.getId() == party.getLeaderId()) {
c.getWorldServer().removeMapPartyMembers(party.getId());
world.updateParty(party.getId(), PartyOperation.DISBAND, partyplayer);
if (player.getEventInstance() != null) {
player.getEventInstance().disbandParty();
}
} else {
player.getMap().removePartyMember(player);
world.updateParty(party.getId(), PartyOperation.LEAVE, partyplayer);
if (player.getEventInstance() != null) {
player.getEventInstance().leftParty(player);
}
}
player.setParty(null);
}
case 2: { // leave/disband
leaveParty(party, partyplayer, c);
break;
}
case 3: {//join
case 3: { // join
int partyid = slea.readInt();
if (c.getPlayer().getParty() == null) {
party = world.getParty(partyid);
@@ -105,16 +114,26 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
}
break;
}
case 4: {//invite
case 4: { // invite
String name = slea.readMapleAsciiString();
MapleCharacter invited = world.getPlayerStorage().getCharacterByName(name);
if (invited != null) {
if(invited.getLevel() < 10) { //min requirement is level 10
c.announce(MaplePacketCreator.serverNotice(5, "The player you have invited does not meet the requirements."));
return;
if(invited.getLevel() < 10 && (!ServerConstants.USE_PARTY_FOR_STARTERS || player.getLevel() >= 10)) { //min requirement is level 10
c.announce(MaplePacketCreator.serverNotice(5, "The player you have invited does not meet the requirements."));
return;
}
if(ServerConstants.USE_PARTY_FOR_STARTERS && invited.getLevel() >= 10 && player.getLevel() < 10) { //trying to invite high level
c.announce(MaplePacketCreator.serverNotice(5, "The player you have invited does not meet the requirements."));
return;
}
if (invited.getParty() == null) {
if (player.getParty() == null) {
if(player.getLevel() < 10 && !ServerConstants.USE_PARTY_FOR_STARTERS) {
c.announce(MaplePacketCreator.partyStatusMessage(10));
return;
}
partyplayer = new MaplePartyCharacter(player);
party = world.createParty(partyplayer);
player.setParty(party);
@@ -158,7 +177,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
}
break;
}
case 6: {
case 6: { // change leader
int newLeader = slea.readInt();
MaplePartyCharacter newLeadr = party.getMemberById(newLeader);
world.updateParty(party.getId(), PartyOperation.CHANGE_LEADER, newLeadr);

View File

@@ -21,6 +21,7 @@
*/
package net.server.world;
import client.MapleClient;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
@@ -195,6 +196,24 @@ public class MapleParty {
return slot;
}
public void assignNewLeader(MapleClient c) {
World world = c.getWorldServer();
MaplePartyCharacter newLeadr = null;
lock.lock();
try {
for(MaplePartyCharacter mpc : members) {
if(mpc.getId() != leaderId && (newLeadr == null || newLeadr.getLevel() < mpc.getLevel())) {
newLeadr = mpc;
}
}
} finally {
lock.unlock();
}
if(newLeadr != null) world.updateParty(this.getId(), PartyOperation.CHANGE_LEADER, newLeadr);
}
@Override
public int hashCode() {
final int prime = 31;

View File

@@ -27,7 +27,6 @@ import java.util.LinkedHashMap;
import java.util.Collection;
import server.maps.MapleDoor;
import server.MapleStatEffect;
import client.MapleCharacter;
import client.MapleJob;
import java.util.Collections;

View File

@@ -400,8 +400,8 @@ public class World {
chr.setParty(null);
chr.setMPC(null);
}
default:
break;
default:
break;
}
}

View File

@@ -34,6 +34,8 @@ import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;
import java.util.Properties;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
@@ -50,6 +52,7 @@ import server.expeditions.MapleExpedition;
import server.life.MapleMonster;
import server.maps.MapleMap;
import server.maps.MapleMapFactory;
import server.maps.MapleReactor;
import tools.DatabaseConnection;
import client.MapleCharacter;
import client.SkillFactory;
@@ -87,6 +90,8 @@ public class EventInstanceManager {
private List<Integer> mapIds = new LinkedList<Integer>();
private List<Boolean> isInstanced = new LinkedList<Boolean>();
private final ReentrantReadWriteLock mutex = new ReentrantReadWriteLock();
private final Lock pL = new ReentrantLock();
private final Lock sL = new ReentrantLock();
private final ReadLock rL = mutex.readLock();
private final WriteLock wL = mutex.writeLock();
private ScheduledFuture<?> event_schedule = null;
@@ -225,7 +230,13 @@ public class EventInstanceManager {
}
chr.setEventInstance(this);
em.getIv().invokeFunction("playerEntry", this, chr);
sL.lock();
try {
em.getIv().invokeFunction("playerEntry", this, chr);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -237,7 +248,13 @@ public class EventInstanceManager {
}
try {
unregisterPlayer(chr);
em.getIv().invokeFunction("playerExit", this, chr);
sL.lock();
try {
em.getIv().invokeFunction("playerExit", this, chr);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -268,7 +285,13 @@ public class EventInstanceManager {
public void run() {
try {
dismissEventTimer();
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
sL.lock();
try {
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
@@ -286,7 +309,13 @@ public class EventInstanceManager {
public void run() {
try {
dismissEventTimer();
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
sL.lock();
try {
em.getIv().invokeFunction("scheduledTimeout", EventInstanceManager.this);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
@@ -354,7 +383,12 @@ public class EventInstanceManager {
public void unregisterPlayer(MapleCharacter chr) {
try {
em.getIv().invokeFunction("playerUnregistered", EventInstanceManager.this, chr);
sL.lock();
try {
em.getIv().invokeFunction("playerUnregistered", EventInstanceManager.this, chr);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
@@ -409,7 +443,12 @@ public class EventInstanceManager {
public void movePlayer(MapleCharacter chr) {
try {
em.getIv().invokeFunction("moveMap", this, chr);
sL.lock();
try {
em.getIv().invokeFunction("moveMap", this, chr);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -417,19 +456,34 @@ public class EventInstanceManager {
public void changedMap(MapleCharacter chr, int mapId) { // optional
try {
em.getIv().invokeFunction("changedMap", this, chr, mapId);
sL.lock();
try {
em.getIv().invokeFunction("changedMap", this, chr, mapId);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {}
}
public void afterChangedMap(MapleCharacter chr, int mapId) { // optional
try {
em.getIv().invokeFunction("afterChangedMap", this, chr, mapId);
sL.lock();
try {
em.getIv().invokeFunction("afterChangedMap", this, chr, mapId);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {}
}
public void changedLeader(MapleCharacter ldr) {
try {
em.getIv().invokeFunction("changedLeader", this, ldr);
sL.lock();
try {
em.getIv().invokeFunction("changedLeader", this, ldr);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -440,13 +494,23 @@ public class EventInstanceManager {
public void monsterKilled(MapleMonster mob) {
mobs.remove(mob);
try {
em.getIv().invokeFunction("monsterKilled", mob, this);
sL.lock();
try {
em.getIv().invokeFunction("monsterKilled", mob, this);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
if (mobs.isEmpty()) {
try {
em.getIv().invokeFunction("allMonstersDead", this);
sL.lock();
try {
em.getIv().invokeFunction("allMonstersDead", this);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -455,7 +519,12 @@ public class EventInstanceManager {
public void friendlyKilled(MapleMonster mob) {
try {
em.getIv().invokeFunction("friendlyKilled", mob, this);
sL.lock();
try {
em.getIv().invokeFunction("friendlyKilled", mob, this);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
//optional
}
@@ -463,7 +532,12 @@ public class EventInstanceManager {
public void playerKilled(MapleCharacter chr) {
try {
em.getIv().invokeFunction("playerDead", this, chr);
sL.lock();
try {
em.getIv().invokeFunction("playerDead", this, chr);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -471,7 +545,15 @@ public class EventInstanceManager {
public boolean revivePlayer(MapleCharacter chr) {
try {
Object b = em.getIv().invokeFunction("playerRevive", this, chr);
Object b;
sL.lock();
try {
b = em.getIv().invokeFunction("playerRevive", this, chr);
} finally {
sL.unlock();
}
if (b instanceof Boolean) {
return (Boolean) b;
}
@@ -483,7 +565,12 @@ public class EventInstanceManager {
public void playerDisconnected(MapleCharacter chr) {
try {
em.getIv().invokeFunction("playerDisconnected", this, chr);
sL.lock();
try {
em.getIv().invokeFunction("playerDisconnected", this, chr);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -497,7 +584,15 @@ public class EventInstanceManager {
public void monsterKilled(MapleCharacter chr, MapleMonster mob) {
try {
Integer kc = killCount.get(chr);
int inc = ((Double) em.getIv().invokeFunction("monsterValue", this, mob.getId())).intValue();
int inc;
sL.lock();
try {
inc = ((Double) em.getIv().invokeFunction("monsterValue", this, mob.getId())).intValue();
} finally {
sL.unlock();
}
if (kc == null) {
kc = inc;
} else {
@@ -526,7 +621,12 @@ public class EventInstanceManager {
public void dispose() {
try {
em.getIv().invokeFunction("dispose", this);
sL.lock();
try {
em.getIv().invokeFunction("dispose", this);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -563,7 +663,12 @@ public class EventInstanceManager {
if(em == null) return;
try {
em.getIv().invokeFunction(methodName, EventInstanceManager.this);
sL.lock();
try {
em.getIv().invokeFunction(methodName, EventInstanceManager.this);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -613,28 +718,49 @@ public class EventInstanceManager {
}
public void setProperty(String key, String value) {
props.setProperty(key, value);
pL.lock();
try {
props.setProperty(key, value);
} finally {
pL.unlock();
}
}
public Object setProperty(String key, String value, boolean prev) {
return props.setProperty(key, value);
pL.lock();
try {
return props.setProperty(key, value);
} finally {
pL.unlock();
}
}
public String getProperty(String key) {
return props.getProperty(key);
pL.lock();
try {
return props.getProperty(key);
} finally {
pL.unlock();
}
}
public Properties getProperties() {
return props;
}
public int getIntProperty(String key) {
return Integer.parseInt(props.getProperty(key));
pL.lock();
try {
return Integer.parseInt(props.getProperty(key));
} finally {
pL.unlock();
}
}
public void leftParty(MapleCharacter chr) {
try {
em.getIv().invokeFunction("leftParty", this, chr);
sL.lock();
try {
em.getIv().invokeFunction("leftParty", this, chr);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -642,7 +768,12 @@ public class EventInstanceManager {
public void disbandParty() {
try {
em.getIv().invokeFunction("disbandParty", this);
sL.lock();
try {
em.getIv().invokeFunction("disbandParty", this);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -650,7 +781,12 @@ public class EventInstanceManager {
public void clearPQ() {
try {
em.getIv().invokeFunction("clearPQ", this);
sL.lock();
try {
em.getIv().invokeFunction("clearPQ", this);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -658,7 +794,12 @@ public class EventInstanceManager {
public void removePlayer(MapleCharacter chr) {
try {
em.getIv().invokeFunction("playerExit", this, chr);
sL.lock();
try {
em.getIv().invokeFunction("playerExit", this, chr);
} finally {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
ex.printStackTrace();
}
@@ -1140,4 +1281,20 @@ public class EventInstanceManager {
wL.unlock();
}
}
public boolean activatedAllReactorsOnMap(int mapId, int minReactorId, int maxReactorId) {
return activatedAllReactorsOnMap(this.getMapInstance(mapId), minReactorId, maxReactorId);
}
public boolean activatedAllReactorsOnMap(MapleMap map, int minReactorId, int maxReactorId) {
if(map == null) return true;
for(MapleReactor mr : map.getReactorsByIdRange(minReactorId, maxReactorId)) {
if(mr.getReactorType() != -1) {
return false;
}
}
return true;
}
}

View File

@@ -879,7 +879,7 @@ public class MapleItemInformationProvider {
break;
}
if (!ItemConstants.isCleanSlate(scrollId)) {
if (!assertGM && !usingWhiteScroll) {
if (!assertGM) {
nEquip.setUpgradeSlots((byte) (nEquip.getUpgradeSlots() - 1));
}
nEquip.setLevel((byte) (nEquip.getLevel() + 1));

View File

@@ -23,13 +23,11 @@ package server;
import java.awt.Point;
import java.awt.Rectangle;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import net.server.world.MaplePartyCharacter;
import provider.MapleData;
@@ -896,7 +894,7 @@ public class MapleStatEffect {
door.getTarget().spawnDoor(door.getAreaDoor());
door.getTown().spawnDoor(door.getTownDoor());
applyto.disableDoor();
applyto.disableDoorSpawn();
} else {
MapleInventoryManipulator.addFromDrop(applyto.getClient(), new Item(4006000, (short) 0, (short) 1), false);

View File

@@ -22,6 +22,7 @@
package server.maps;
import java.awt.Point;
import java.util.List;
import tools.Pair;
import server.MaplePortal;
@@ -49,7 +50,7 @@ public class MapleDoor {
if(target.canDeployDoor(targetPosition)) {
if(ServerConstants.USE_ENFORCE_MDOOR_POSITION) {
posStatus = target.getDoorPositionStatus(targetPosition);
posStatus = target.getDoorPositionStatus(targetPosition);
}
if(posStatus == null) {
@@ -74,11 +75,13 @@ public class MapleDoor {
}
private MaplePortal getDoorPortal(int slot) {
List<MaplePortal> avail = town.getAvailableDoorPortals();
try {
return town.getAvailableDoorPortals().get(slot);
return avail.get(slot);
} catch (IndexOutOfBoundsException e) {
try {
return town.getAvailableDoorPortals().get(0);
return avail.get(0);
} catch (IndexOutOfBoundsException ex) {
return null;
}

View File

@@ -1338,6 +1338,27 @@ public class MapleMap {
objectRLock.unlock();
}
}
public List<MapleReactor> getReactorsByIdRange(final int first, final int last) {
List<MapleReactor> list = new LinkedList<>();
objectRLock.lock();
try {
for (MapleMapObject obj : mapobjects.values()) {
if (obj.getType() == MapleMapObjectType.REACTOR) {
MapleReactor mr = (MapleReactor) obj;
if (mr.getId() >= first && mr.getId() <= last) {
list.add(mr);
}
}
}
return list;
} finally {
objectRLock.unlock();
}
}
public MapleReactor getReactorByName(String name) {
objectRLock.lock();
@@ -1607,7 +1628,7 @@ public class MapleMap {
try {
List<MaplePortal> availablePortals = new ArrayList<>();
for (MaplePortal port : getPortals()) {
for (MaplePortal port : portals.values()) {
if (port.getType() == MaplePortal.DOOR_PORTAL) {
availablePortals.add(port);
}
@@ -2117,9 +2138,11 @@ public class MapleMap {
return null;
}
/*
public Collection<MaplePortal> getPortals() {
return Collections.unmodifiableCollection(portals.values());
}
*/
public void removePlayer(MapleCharacter chr) {
chrWLock.lock();