Buff System & Map skipping fix + properly disposing Storage + Fairness to locks
Fixed buff system behaving oddly if a buff has value zero, that would render some skills "broken". Fixed players skipping maps when trying to access portals while under a poor Internet connection. Fixed storage not disposing players properly in cases where the players does not meet the storage conditions. Set some locks to use fairness strategy when dealing with atomic code, in order to make the calls to it properly synchronized. Fixed Aran introductory questline stucking players when certain conditions were met. Added drop data for some mob versions of Fairy, Yeti and Pepe.
This commit is contained in:
@@ -31,6 +31,8 @@ import java.util.List;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import net.SendOpcode;
|
||||
import server.maps.AbstractMapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
@@ -53,6 +55,7 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
|
||||
private List<String> bannedList = new ArrayList<>();
|
||||
private List<Pair<MapleCharacter, String>> chatLog = new LinkedList<>();
|
||||
private Map<Integer, Byte> chatSlot = new LinkedHashMap<>();
|
||||
private Lock visitorLock = new ReentrantLock(true);
|
||||
|
||||
public MaplePlayerShop(MapleCharacter owner, String description) {
|
||||
this.setPosition(owner.getPosition());
|
||||
@@ -322,8 +325,11 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
public void sendShop(MapleClient c) {
|
||||
synchronized(visitors) {
|
||||
visitorLock.lock();
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getPlayerShop(this, isOwner(c.getPlayer())));
|
||||
} finally {
|
||||
visitorLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,11 +338,14 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
public MapleCharacter[] getVisitors() {
|
||||
synchronized(visitors) {
|
||||
visitorLock.lock();
|
||||
try {
|
||||
MapleCharacter[] copy = new MapleCharacter[3];
|
||||
for(int i = 0; i < visitors.length; i++) copy[i] = visitors[i];
|
||||
|
||||
return copy;
|
||||
} finally {
|
||||
visitorLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,13 +379,16 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
MapleCharacter target = null;
|
||||
synchronized(visitors) {
|
||||
visitorLock.lock();
|
||||
try {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (visitors[i] != null && visitors[i].getName().equals(name)) {
|
||||
target = visitors[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
visitorLock.unlock();
|
||||
}
|
||||
|
||||
if(target != null) {
|
||||
@@ -400,15 +412,17 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.hasFreeSlot() && !this.isVisitor(chr)) {
|
||||
this.addVisitor(chr);
|
||||
chr.setPlayerShop(this);
|
||||
this.sendShop(chr.getClient());
|
||||
synchronized (visitors) {
|
||||
if (this.hasFreeSlot() && !this.isVisitor(chr)) {
|
||||
this.addVisitor(chr);
|
||||
chr.setPlayerShop(this);
|
||||
this.sendShop(chr.getClient());
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<MaplePlayerShopItem> sendAvailableBundles(int itemid) {
|
||||
|
||||
@@ -191,6 +191,7 @@ public class MapleStatEffect {
|
||||
ret.duration *= 1000; // items have their times stored in ms, of course
|
||||
ret.overTime = overTime;
|
||||
}
|
||||
|
||||
ArrayList<Pair<MapleBuffStat, Integer>> statups = new ArrayList<>();
|
||||
ret.watk = (short) MapleDataTool.getInt("pad", source, 0);
|
||||
ret.wdef = (short) MapleDataTool.getInt("pdd", source, 0);
|
||||
@@ -206,15 +207,6 @@ public class MapleStatEffect {
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MAP_PROTECTION, Integer.valueOf(ret.mapProtection));
|
||||
|
||||
if (ret.overTime && ret.getSummonMovementType() == null) {
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.WATK, Integer.valueOf(ret.watk));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.WDEF, Integer.valueOf(ret.wdef));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MATK, Integer.valueOf(ret.matk));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MDEF, Integer.valueOf(ret.mdef));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.ACC, Integer.valueOf(ret.acc));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.AVOID, Integer.valueOf(ret.avoid));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.SPEED, Integer.valueOf(ret.speed));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.JUMP, Integer.valueOf(ret.jump));
|
||||
|
||||
if(!skill) {
|
||||
if(isPyramidBuff(sourceid)) {
|
||||
ret.berserk = MapleDataTool.getInt("berserk", source, 0);
|
||||
@@ -273,7 +265,17 @@ public class MapleStatEffect {
|
||||
ret.speed *= 15;
|
||||
}
|
||||
}
|
||||
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.WATK, Integer.valueOf(ret.watk));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.WDEF, Integer.valueOf(ret.wdef));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MATK, Integer.valueOf(ret.matk));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MDEF, Integer.valueOf(ret.mdef));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.ACC, Integer.valueOf(ret.acc));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.AVOID, Integer.valueOf(ret.avoid));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.SPEED, Integer.valueOf(ret.speed));
|
||||
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.JUMP, Integer.valueOf(ret.jump));
|
||||
}
|
||||
|
||||
MapleData ltd = source.getChildByPath("lt");
|
||||
if (ltd != null) {
|
||||
ret.lt = (Point) ltd.getData();
|
||||
@@ -730,6 +732,7 @@ public class MapleStatEffect {
|
||||
applyto.toggleHide(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
int hpchange = calcHPChange(applyfrom, primary);
|
||||
int mpchange = calcMPChange(applyfrom, primary);
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
@@ -51,7 +50,7 @@ public class MapleStorage {
|
||||
private byte slots;
|
||||
private Map<MapleInventoryType, List<Item>> typeItems = new HashMap<>();
|
||||
private List<Item> items;
|
||||
private Lock lock = new ReentrantLock();
|
||||
private Lock lock = new ReentrantLock(true);
|
||||
|
||||
private MapleStorage(int id, byte slots, int meso) {
|
||||
this.id = id;
|
||||
@@ -224,6 +223,14 @@ public class MapleStorage {
|
||||
}
|
||||
|
||||
public void sendStorage(MapleClient c, int npcId) {
|
||||
/*
|
||||
if (c.getPlayer().getLevel() < 15){
|
||||
c.getPlayer().message("You may only use the storage once you have reached level 15.");
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
|
||||
lock.lock();
|
||||
|
||||
@@ -14,7 +14,7 @@ import server.TimerManager;
|
||||
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 List<MapleCharacter> candidates = new ArrayList<>();
|
||||
public static boolean hasStarted = false;
|
||||
public static String partyLeader = "undefined";
|
||||
public static boolean balrogSpawned = false;
|
||||
@@ -28,8 +28,10 @@ public class BalrogPQ {
|
||||
}
|
||||
|
||||
public static void warpAllCandidates(){
|
||||
for(MapleCharacter c : candidates){
|
||||
c.changeMap(105100300);
|
||||
synchronized(candidates){
|
||||
for(MapleCharacter c : candidates){
|
||||
c.changeMap(105100300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +50,7 @@ public class BalrogPQ {
|
||||
TimerManager tMan = TimerManager.getInstance();
|
||||
tMan.schedule(new Runnable(){
|
||||
@Override
|
||||
public void run(){
|
||||
public void run(){
|
||||
for(MapleCharacter chrs : fmap.getCharacters()){
|
||||
chrs.changeMap(105100100);
|
||||
chrs.message("You did not defeat the balrog in time..");
|
||||
@@ -57,9 +59,9 @@ public class BalrogPQ {
|
||||
}
|
||||
} , 60 * 60 * 1000);
|
||||
|
||||
tMan.schedule(new Runnable(){
|
||||
tMan.schedule(new Runnable(){
|
||||
@Override
|
||||
public void run(){
|
||||
public void run(){
|
||||
if(fmap.getCharacters().size() <= 3){
|
||||
if(fmap.getCharacters().size() > 0){
|
||||
for(MapleCharacter chrs : fmap.getCharacters()){
|
||||
@@ -92,7 +94,9 @@ public class BalrogPQ {
|
||||
hasStarted = false;
|
||||
balrogSpawned = false;
|
||||
partyLeader = "undefined";
|
||||
candidates.clear();
|
||||
synchronized(candidates){
|
||||
candidates.clear();
|
||||
}
|
||||
timeStamp = 0;
|
||||
}
|
||||
public static void spawnBalrog(int mode, MapleCharacter chr){
|
||||
|
||||
@@ -85,7 +85,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
private final HashMap<Integer, AtomicInteger> takenDamage = new HashMap<>();
|
||||
|
||||
private ReentrantLock externalLock = new ReentrantLock();
|
||||
private ReentrantLock monsterLock = new ReentrantLock();
|
||||
private ReentrantLock monsterLock = new ReentrantLock(true);
|
||||
private ReentrantLock statiLock = new ReentrantLock();
|
||||
|
||||
public MapleMonster(int id, MapleMonsterStats stats) {
|
||||
|
||||
@@ -36,6 +36,8 @@ import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import net.server.Server;
|
||||
import server.MapleInventoryManipulator;
|
||||
import server.MapleItemInformationProvider;
|
||||
@@ -50,7 +52,6 @@ import tools.Pair;
|
||||
* @author Ronan (concurrency protection)
|
||||
*/
|
||||
public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
|
||||
private int ownerId, itemId, mesos = 0;
|
||||
private int channel, world;
|
||||
private long start;
|
||||
@@ -62,6 +63,7 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
private List<SoldItem> sold = new LinkedList<>();
|
||||
private AtomicBoolean open = new AtomicBoolean();
|
||||
private MapleMap map;
|
||||
private Lock visitorLock = new ReentrantLock(true);
|
||||
|
||||
public MapleHiredMerchant(final MapleCharacter owner, int itemId, String desc) {
|
||||
this.setPosition(owner.getPosition());
|
||||
@@ -76,8 +78,11 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
public void broadcastToVisitorsThreadsafe(final byte[] packet) {
|
||||
synchronized(visitors) {
|
||||
visitorLock.lock();
|
||||
try {
|
||||
broadcastToVisitors(packet);
|
||||
} finally {
|
||||
visitorLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +95,8 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
public boolean addVisitor(MapleCharacter visitor) {
|
||||
synchronized(visitors) {
|
||||
visitorLock.lock();
|
||||
try {
|
||||
int i = this.getFreeSlot();
|
||||
if (i > -1) {
|
||||
visitors[i] = visitor;
|
||||
@@ -100,25 +106,33 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
return false;
|
||||
} finally {
|
||||
visitorLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeVisitor(MapleCharacter visitor) {
|
||||
synchronized(visitors) {
|
||||
visitorLock.lock();
|
||||
try {
|
||||
int slot = getVisitorSlot(visitor);
|
||||
if (slot < 0){ //Not found
|
||||
return;
|
||||
if (slot < 0) { //Not found
|
||||
return;
|
||||
}
|
||||
if (visitors[slot] != null && visitors[slot].getId() == visitor.getId()) {
|
||||
visitors[slot] = null;
|
||||
broadcastToVisitors(MaplePacketCreator.hiredMerchantVisitorLeave(slot + 1));
|
||||
}
|
||||
} finally {
|
||||
visitorLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getVisitorSlotThreadsafe(MapleCharacter visitor) {
|
||||
synchronized(visitors) {
|
||||
visitorLock.lock();
|
||||
try {
|
||||
return getVisitorSlot(visitor);
|
||||
} finally {
|
||||
visitorLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +146,8 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
public void removeAllVisitors() {
|
||||
synchronized(visitors) {
|
||||
visitorLock.lock();
|
||||
try {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (visitors[i] != null) {
|
||||
visitors[i].setHiredMerchant(null);
|
||||
@@ -143,6 +158,8 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
visitors[i] = null;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
visitorLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,11 +331,14 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
}
|
||||
|
||||
public MapleCharacter[] getVisitors() {
|
||||
synchronized(visitors) {
|
||||
visitorLock.lock();
|
||||
try {
|
||||
MapleCharacter[] copy = new MapleCharacter[3];
|
||||
for(int i = 0; i < visitors.length; i++) copy[i] = visitors[i];
|
||||
|
||||
return copy;
|
||||
} finally {
|
||||
visitorLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,12 +382,6 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
}
|
||||
}
|
||||
|
||||
public int getFreeSlotThreadsafe() {
|
||||
synchronized(visitors) {
|
||||
return getFreeSlot();
|
||||
}
|
||||
}
|
||||
|
||||
private int getFreeSlot() {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (visitors[i] == null) {
|
||||
|
||||
@@ -2724,7 +2724,6 @@ public class MapleMap {
|
||||
if (reactor.getShouldCollect() == true && mapitem != null && mapitem == getMapObject(mapitem.getObjectId())) {
|
||||
mapitem.lockItem();
|
||||
try {
|
||||
TimerManager tMan = TimerManager.getInstance();
|
||||
if (mapitem.isPickedUp()) {
|
||||
return;
|
||||
}
|
||||
@@ -2735,6 +2734,7 @@ public class MapleMap {
|
||||
reactor.hitReactor(c);
|
||||
|
||||
if (reactor.getDelay() > 0) {
|
||||
TimerManager tMan = TimerManager.getInstance();
|
||||
tMan.schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
@@ -22,7 +22,7 @@ import tools.MaplePacketCreator;
|
||||
public class MapleMiniDungeon {
|
||||
List<MapleCharacter> players = new ArrayList<>();
|
||||
ScheduledFuture<?> timeoutTask = null;
|
||||
Lock lock = new ReentrantLock();
|
||||
Lock lock = new ReentrantLock(true);
|
||||
|
||||
int baseMap;
|
||||
long expireTime;
|
||||
|
||||
@@ -59,7 +59,7 @@ public class MapleReactor extends AbstractMapleMapObject {
|
||||
this.evstate = (byte)0;
|
||||
this.stats = stats;
|
||||
this.rid = rid;
|
||||
alive = true;
|
||||
this.alive = true;
|
||||
}
|
||||
|
||||
public void setShouldCollect(boolean collect) {
|
||||
|
||||
Reference in New Issue
Block a user