More concurrency fixes + Zombify + BPQ available
Fixed some inconsistencies due to race conditions in the project, added Zombify monster effect, made BPQ available and some minor patches.
This commit is contained in:
@@ -26,6 +26,7 @@ public enum MapleDisease {
|
||||
SLOW(0x1),
|
||||
SEDUCE(0x80),
|
||||
FISHABLE(0x100),
|
||||
ZOMBIFY(0x4000),
|
||||
CONFUSE(0x80000),
|
||||
STUN(0x2000000000000L),
|
||||
POISON(0x4000000000000L),
|
||||
|
||||
@@ -43,9 +43,9 @@ public enum ItemFactory {
|
||||
CASH_CYGNUS(4, false),
|
||||
CASH_ARAN(5, false),
|
||||
MERCHANT(6, false);
|
||||
private int value;
|
||||
private boolean account;
|
||||
private static ReentrantLock lock = new ReentrantLock(true);
|
||||
private final int value;
|
||||
private final boolean account;
|
||||
private static final ReentrantLock lock = new ReentrantLock(true);
|
||||
|
||||
private ItemFactory(int value, boolean account) {
|
||||
this.value = value;
|
||||
|
||||
@@ -26,13 +26,14 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
|
||||
public class PlayerStorage {
|
||||
private final ReentrantReadWriteLock locks = new ReentrantReadWriteLock();
|
||||
private final Lock rlock = locks.readLock();
|
||||
private final Lock wlock = locks.writeLock();
|
||||
private final ReentrantReadWriteLock locks = new ReentrantReadWriteLock(true);
|
||||
private final ReadLock rlock = locks.readLock();
|
||||
private final WriteLock wlock = locks.writeLock();
|
||||
private final Map<Integer, MapleCharacter> storage = new LinkedHashMap<>();
|
||||
|
||||
public void addPlayer(MapleCharacter chr) {
|
||||
@@ -76,7 +77,7 @@ public class PlayerStorage {
|
||||
}
|
||||
|
||||
public Collection<MapleCharacter> getAllCharacters() {
|
||||
rlock.lock();
|
||||
rlock.lock();
|
||||
try {
|
||||
return storage.values();
|
||||
} finally {
|
||||
@@ -98,6 +99,11 @@ public class PlayerStorage {
|
||||
}
|
||||
|
||||
public int getSize(){
|
||||
return storage.size();
|
||||
rlock.lock();
|
||||
try {
|
||||
return storage.size();
|
||||
} finally {
|
||||
rlock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,11 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
|
||||
import net.MapleServerHandler;
|
||||
@@ -71,7 +73,9 @@ public final class Channel {
|
||||
private EventScriptManager eventSM;
|
||||
private Map<Integer, HiredMerchant> hiredMerchants = new HashMap<>();
|
||||
private final Map<Integer, Integer> storedVars = new HashMap<>();
|
||||
private ReentrantReadWriteLock merchant_lock = new ReentrantReadWriteLock(true);
|
||||
private ReentrantReadWriteLock merchant_lock = new ReentrantReadWriteLock(true);
|
||||
private ReadLock merchRlock = merchant_lock.readLock();
|
||||
private WriteLock merchWlock = merchant_lock.writeLock();
|
||||
private List<MapleExpedition> expeditions = new ArrayList<>();
|
||||
private List<MapleExpeditionType> expedType = new ArrayList<>();
|
||||
private MapleEvent event;
|
||||
@@ -130,8 +134,7 @@ public final class Channel {
|
||||
}
|
||||
|
||||
public void closeAllMerchants() {
|
||||
WriteLock wlock = merchant_lock.writeLock();
|
||||
wlock.lock();
|
||||
merchWlock.lock();
|
||||
try {
|
||||
final Iterator<HiredMerchant> hmit = hiredMerchants.values().iterator();
|
||||
while (hmit.hasNext()) {
|
||||
@@ -141,7 +144,7 @@ public final class Channel {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
wlock.unlock();
|
||||
merchWlock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,28 +231,31 @@ public final class Channel {
|
||||
}
|
||||
|
||||
public Map<Integer, HiredMerchant> getHiredMerchants() {
|
||||
return hiredMerchants;
|
||||
merchRlock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableMap(hiredMerchants);
|
||||
} finally {
|
||||
merchRlock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void addHiredMerchant(int chrid, HiredMerchant hm) {
|
||||
WriteLock wlock = merchant_lock.writeLock();
|
||||
wlock.lock();
|
||||
merchWlock.lock();
|
||||
try {
|
||||
hiredMerchants.put(chrid, hm);
|
||||
} finally {
|
||||
wlock.unlock();
|
||||
merchWlock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeHiredMerchant(int chrid) {
|
||||
WriteLock wlock = merchant_lock.writeLock();
|
||||
wlock.lock();
|
||||
merchWlock.lock();
|
||||
try {
|
||||
hiredMerchants.remove(chrid);
|
||||
} finally {
|
||||
wlock.unlock();
|
||||
}
|
||||
merchWlock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int[] multiBuddyFind(int charIdFrom, int[] characterIds) {
|
||||
List<Integer> ret = new ArrayList<>(characterIds.length);
|
||||
|
||||
@@ -30,8 +30,9 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
@@ -64,7 +65,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 rL = mutex.readLock(), wL = mutex.writeLock();
|
||||
private final ReadLock rL = mutex.readLock();
|
||||
private final WriteLock wL = mutex.writeLock();
|
||||
private boolean disposed = false;
|
||||
|
||||
public EventInstanceManager(EventManager em, String name) {
|
||||
@@ -148,11 +150,23 @@ public class EventInstanceManager {
|
||||
}
|
||||
|
||||
public int getPlayerCount() {
|
||||
return chars.size();
|
||||
rL.lock();
|
||||
try {
|
||||
return chars.size();
|
||||
}
|
||||
finally {
|
||||
rL.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public List<MapleCharacter> getPlayers() {
|
||||
return new ArrayList<>(chars);
|
||||
rL.lock();
|
||||
try {
|
||||
return new ArrayList<>(chars);
|
||||
}
|
||||
finally {
|
||||
rL.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerMonster(MapleMonster mob) {
|
||||
@@ -247,7 +261,14 @@ public class EventInstanceManager {
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
chars.clear();
|
||||
|
||||
wL.lock();
|
||||
try {
|
||||
chars.clear();
|
||||
} finally {
|
||||
wL.unlock();
|
||||
}
|
||||
|
||||
mobs.clear();
|
||||
killCount.clear();
|
||||
mapFactory = null;
|
||||
@@ -374,11 +395,10 @@ public class EventInstanceManager {
|
||||
map = this.getMapFactory().getMap(towarp);
|
||||
}
|
||||
|
||||
wL.lock();
|
||||
rL.lock();
|
||||
try {
|
||||
if (chars != null && chars.size() <= size) {
|
||||
final List<MapleCharacter> chrs = new LinkedList<MapleCharacter>(chars);
|
||||
for (MapleCharacter chr : chrs) {
|
||||
for (MapleCharacter chr : chars) {
|
||||
if (chr == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -393,7 +413,7 @@ public class EventInstanceManager {
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
wL.unlock();
|
||||
rL.unlock();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -699,7 +699,8 @@ public class MapleStatEffect {
|
||||
AutobanFactory.MPCON.addPoint(applyfrom.getAutobanManager(), "mpCon hack for skill:" + sourceid + "; Player MP: " + applyto.getMp() + " MP Needed: " + getMpCon());
|
||||
} */
|
||||
if (hpchange != 0) {
|
||||
if (hpchange < 0 && (-hpchange) > applyto.getHp()) {
|
||||
if (hpchange < 0 && (-hpchange) > applyto.getHp() && !applyto.hasDisease(MapleDisease.ZOMBIFY)) {
|
||||
applyto.getClient().announce(MaplePacketCreator.enableActions());
|
||||
return false;
|
||||
}
|
||||
int newHp = applyto.getHp() + hpchange;
|
||||
@@ -712,6 +713,7 @@ public class MapleStatEffect {
|
||||
int newMp = applyto.getMp() + mpchange;
|
||||
if (mpchange != 0) {
|
||||
if (mpchange < 0 && -mpchange > applyto.getMp()) {
|
||||
applyto.getClient().announce(MaplePacketCreator.enableActions());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1037,12 +1039,18 @@ public class MapleStatEffect {
|
||||
} else {
|
||||
hpchange += hp;
|
||||
}
|
||||
} else {
|
||||
if (applyfrom.hasDisease(MapleDisease.ZOMBIFY)) {
|
||||
hpchange /= 2;
|
||||
}
|
||||
} else { // assumption: this is heal
|
||||
hpchange += makeHealHP(hp / 100.0, applyfrom.getTotalMagic(), 3, 5);
|
||||
if (applyfrom.hasDisease(MapleDisease.ZOMBIFY)) {
|
||||
hpchange = -hpchange;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hpR != 0) {
|
||||
hpchange += (int) (applyfrom.getCurrentMaxHp() * hpR);
|
||||
hpchange += (int) (applyfrom.getCurrentMaxHp() * hpR) / (applyfrom.hasDisease(MapleDisease.ZOMBIFY) ? 2 : 1);
|
||||
applyfrom.checkBerserk();
|
||||
}
|
||||
if (primary) {
|
||||
|
||||
108
src/server/events/BalrogPQ.java
Normal file
108
src/server/events/BalrogPQ.java
Normal file
@@ -0,0 +1,108 @@
|
||||
package server.events;
|
||||
import client.MapleCharacter;
|
||||
import java.util.*;
|
||||
import server.life.MapleLifeFactory;
|
||||
import java.awt.Point;
|
||||
import server.maps.MapleMap;
|
||||
import server.TimerManager;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author FateJiki
|
||||
* @Mapid 105100300
|
||||
*/
|
||||
public class BalrogPQ {
|
||||
public static final int[] EasyBalrogParts = {8830002, 8830003, 8830000};
|
||||
public static final int[] HardBalrogParts = {8830000, 8830001, 8830002};
|
||||
public static List<MapleCharacter> candidates = new ArrayList<MapleCharacter>();
|
||||
public static boolean hasStarted = false;
|
||||
public static String partyLeader = "undefined";
|
||||
public static boolean balrogSpawned = false;
|
||||
public static long timeStamp = 0;
|
||||
public static byte channel = 1;
|
||||
|
||||
public static void addCandidate(MapleCharacter chr){
|
||||
synchronized(candidates){
|
||||
candidates.add(chr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void warpAllCandidates(){
|
||||
for(MapleCharacter c : candidates){
|
||||
c.changeMap(105100300);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFull(MapleCharacter chr){
|
||||
return chr.getClient().getChannelServer().getMapFactory().getMap(105100300).getCharacters().size() > 0;
|
||||
}
|
||||
|
||||
public static void warpIn(MapleCharacter chr){
|
||||
if(hasStarted){
|
||||
chr.changeMap(105100300);
|
||||
}
|
||||
}
|
||||
|
||||
public static void scheduleChecks(MapleMap map){
|
||||
final MapleMap fmap = map;
|
||||
TimerManager tMan = TimerManager.getInstance();
|
||||
tMan.schedule(new Runnable(){
|
||||
@Override
|
||||
public void run(){
|
||||
for(MapleCharacter chrs : fmap.getCharacters()){
|
||||
chrs.changeMap(105100100);
|
||||
chrs.message("You did not defeat the balrog in time..");
|
||||
close();
|
||||
}
|
||||
}
|
||||
} , 60 * 60 * 1000);
|
||||
|
||||
tMan.schedule(new Runnable(){
|
||||
@Override
|
||||
public void run(){
|
||||
if(fmap.getCharacters().size() <= 3){
|
||||
if(fmap.getCharacters().size() > 0){
|
||||
for(MapleCharacter chrs : fmap.getCharacters()){
|
||||
chrs.message("[The Order]: What? You're down to that many mercenaries? I need you get you out of there.");
|
||||
chrs.changeMap(105100100);
|
||||
}
|
||||
}
|
||||
fmap.killAllMonsters();
|
||||
close();
|
||||
}
|
||||
}
|
||||
} , 60 * 1000);
|
||||
}
|
||||
|
||||
public static void open(MapleCharacter chr){
|
||||
channel = (byte)chr.getClient().getChannel();
|
||||
hasStarted = true;
|
||||
timeStamp = System.currentTimeMillis();
|
||||
scheduleChecks(chr.getClient().getChannelServer().getMapFactory().getMap(105100300));
|
||||
}
|
||||
|
||||
public static int getSecondsLeft(){ // assuming the thing lasts 60 minutes
|
||||
int hour = 60 * 60; // 3600 seconds = 1hr
|
||||
long elapsed = System.currentTimeMillis() - timeStamp;
|
||||
int secondsLeft = (int)(hour - (elapsed / 1000));
|
||||
return secondsLeft;
|
||||
}
|
||||
|
||||
public static void close(){
|
||||
hasStarted = false;
|
||||
balrogSpawned = false;
|
||||
partyLeader = "undefined";
|
||||
candidates.clear();
|
||||
timeStamp = 0;
|
||||
}
|
||||
public static void spawnBalrog(int mode, MapleCharacter chr){
|
||||
if(!balrogSpawned){
|
||||
for(int i = 0; i < HardBalrogParts.length; i++){
|
||||
chr.getClient().getChannelServer().getMapFactory().getMap(105100300).spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(HardBalrogParts[i]), new Point(412, 258));
|
||||
balrogSpawned = true;
|
||||
}
|
||||
} else {
|
||||
// DO NUFFIN'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,7 +274,7 @@ public class MobSkill {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unhandeled Mob skill: " + skillId);
|
||||
System.out.println("Unhandled Mob skill: " + skillId);
|
||||
break;
|
||||
}
|
||||
if (stats.size() > 0) {
|
||||
|
||||
@@ -28,6 +28,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
@@ -42,20 +44,22 @@ public class MobSkillFactory {
|
||||
private static Map<String, MobSkill> mobSkills = new HashMap<String, MobSkill>();
|
||||
private final static MapleDataProvider dataSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Skill.wz"));
|
||||
private static MapleData skillRoot = dataSource.getData("MobSkill.img");
|
||||
private static ReentrantReadWriteLock dataLock = new ReentrantReadWriteLock();
|
||||
private final static ReentrantReadWriteLock dataLock = new ReentrantReadWriteLock();
|
||||
private final static ReadLock rL = dataLock.readLock();
|
||||
private final static WriteLock wL = dataLock.writeLock();
|
||||
|
||||
public static MobSkill getMobSkill(final int skillId, final int level) {
|
||||
final String key = skillId + "" + level;
|
||||
dataLock.readLock().lock();
|
||||
rL.lock();
|
||||
try {
|
||||
MobSkill ret = mobSkills.get(key);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
} finally {
|
||||
dataLock.readLock().unlock();
|
||||
rL.unlock();
|
||||
}
|
||||
dataLock.writeLock().lock();
|
||||
wL.lock();
|
||||
try {
|
||||
MobSkill ret;
|
||||
ret = mobSkills.get(key);
|
||||
@@ -103,7 +107,7 @@ public class MobSkillFactory {
|
||||
}
|
||||
return ret;
|
||||
} finally {
|
||||
dataLock.writeLock().unlock();
|
||||
wL.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ import tools.Pair;
|
||||
import tools.Randomizer;
|
||||
|
||||
public class MapleMap {
|
||||
|
||||
private static final List<MapleMapObjectType> rangedMapobjectTypes = Arrays.asList(MapleMapObjectType.SHOP, MapleMapObjectType.ITEM, MapleMapObjectType.NPC, MapleMapObjectType.MONSTER, MapleMapObjectType.DOOR, MapleMapObjectType.SUMMON, MapleMapObjectType.REACTOR);
|
||||
private Map<Integer, MapleMapObject> mapobjects = new LinkedHashMap<>();
|
||||
private Collection<SpawnPoint> monsterSpawn = Collections.synchronizedList(new LinkedList<SpawnPoint>());
|
||||
@@ -875,7 +874,13 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
public Collection<MapleMapObject> getMapObjects() {
|
||||
return Collections.unmodifiableCollection(mapobjects.values());
|
||||
objectRLock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableCollection(mapobjects.values());
|
||||
}
|
||||
finally {
|
||||
objectRLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsNPC(int npcid) {
|
||||
@@ -898,7 +903,12 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
public MapleMapObject getMapObject(int oid) {
|
||||
return mapobjects.get(oid);
|
||||
objectRLock.lock();
|
||||
try {
|
||||
return mapobjects.get(oid);
|
||||
} finally {
|
||||
objectRLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1285,11 +1295,9 @@ public class MapleMap {
|
||||
|
||||
public void addPlayer(final MapleCharacter chr) {
|
||||
chrWLock.lock();
|
||||
chrRLock.lock();
|
||||
try {
|
||||
characters.add(chr);
|
||||
} finally {
|
||||
chrRLock.unlock();
|
||||
chrWLock.unlock();
|
||||
}
|
||||
chr.setMapId(mapid);
|
||||
@@ -1528,11 +1536,9 @@ public class MapleMap {
|
||||
|
||||
public void removePlayer(MapleCharacter chr) {
|
||||
chrWLock.lock();
|
||||
chrRLock.lock();
|
||||
try {
|
||||
characters.remove(chr);
|
||||
} finally {
|
||||
chrRLock.unlock();
|
||||
chrWLock.unlock();
|
||||
}
|
||||
removeMapObject(chr.getObjectId());
|
||||
@@ -1841,6 +1847,8 @@ public class MapleMap {
|
||||
player.setPosition(newPosition);
|
||||
Collection<MapleMapObject> visibleObjects = player.getVisibleMapObjects();
|
||||
MapleMapObject[] visibleObjectsNow = visibleObjects.toArray(new MapleMapObject[visibleObjects.size()]);
|
||||
|
||||
objectRLock.lock();
|
||||
try {
|
||||
for (MapleMapObject mo : visibleObjectsNow) {
|
||||
if (mo != null) {
|
||||
@@ -1853,7 +1861,10 @@ public class MapleMap {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
objectRLock.unlock();
|
||||
}
|
||||
|
||||
for (MapleMapObject mo : getMapObjectsInRange(player.getPosition(), 722500, rangedMapobjectTypes)) {
|
||||
if (!player.isMapObjectVisible(mo)) {
|
||||
mo.sendSpawnData(player.getClient());
|
||||
@@ -2399,17 +2410,22 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
public void toggleHiddenNPC(int id) {
|
||||
for (MapleMapObject obj : mapobjects.values()) {
|
||||
if (obj.getType() == MapleMapObjectType.NPC) {
|
||||
MapleNPC npc = (MapleNPC) obj;
|
||||
if (npc.getId() == id) {
|
||||
npc.setHide(!npc.isHidden());
|
||||
if (!npc.isHidden()) //Should only be hidden upon changing maps
|
||||
{
|
||||
broadcastMessage(MaplePacketCreator.spawnNPC(npc));
|
||||
objectRLock.lock();
|
||||
try {
|
||||
for (MapleMapObject obj : mapobjects.values()) {
|
||||
if (obj.getType() == MapleMapObjectType.NPC) {
|
||||
MapleNPC npc = (MapleNPC) obj;
|
||||
if (npc.getId() == id) {
|
||||
npc.setHide(!npc.isHidden());
|
||||
if (!npc.isHidden()) //Should only be hidden upon changing maps
|
||||
{
|
||||
broadcastMessage(MaplePacketCreator.spawnNPC(npc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
objectRLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user