Persistent diseases + PQ request system + GuildPQ fix

Implemented persistent diseases. Players now keep their disease status when logging out the game.
Solved several concurrent access issues in MapleMap and MapleMonster.
Implemented an option where an account's character slots can be accounted either by each world or all-server range.
Fixed some issues with character slot count when entering/exiting Cash Shop.
Fixed an exploit with Papulatus, on where players could create cracks of dimension infinitely.
Solved an issue with the "reach" command not working properly when the targeted player is on an event instance.
Devised an advanced and secure "PQ request" system. The service revolves around expecting massive number of players requesting a "pass" simultaneously, and fairly & swiftly responsing as much people as possible.
Improved overall Whisper handler performance.
Fixed GPQ Stage 1 statues not working as expected, which rendered the instance unplayable until now.
Added commands for start, complete and reset quests.
This commit is contained in:
ronancpl
2018-08-18 11:38:55 -03:00
parent cda4433d99
commit 0d47edf1a7
116 changed files with 1596 additions and 703 deletions
+111 -24
View File
@@ -155,6 +155,7 @@ import constants.skills.Swordsman;
import constants.skills.ThunderBreaker;
import net.server.channel.handlers.PartyOperationHandler;
import scripting.item.ItemScriptManager;
import server.life.MobSkillFactory;
import server.maps.MapleMapItem;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
@@ -1370,6 +1371,35 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
eventAfterChangedMap(this.getMapId());
}
public void forceChangeMap(final MapleMap target, final MaplePortal pto) {
// will actually enter the map given as parameter, regardless of being an eventmap or whatnot
canWarpCounter++;
eventChangedMap(999999999);
EventInstanceManager mapEim = target.getEventInstance();
if(mapEim != null) {
EventInstanceManager playerEim = this.getEventInstance();
if(playerEim != null) {
playerEim.exitPlayer(this);
if(playerEim.getPlayerCount() == 0) {
playerEim.dispose();
}
}
mapEim.registerPlayer(this);
}
MapleMap to = getWarpMap(target.getId());
changeMapInternal(to, pto.getPosition(), MaplePacketCreator.getWarpToMap(to, pto.getId(), this));
canWarpMap = false;
canWarpCounter--;
if(canWarpCounter == 0) canWarpMap = true;
eventAfterChangedMap(this.getMapId());
}
private boolean buffMapProtection() {
effLock.lock();
chrLock.lock();
@@ -2073,6 +2103,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ps.setInt(1, cid);
ps.executeUpdate();
}
try (PreparedStatement ps = con.prepareStatement("DELETE FROM playerdiseases WHERE charid = ?")) {
ps.setInt(1, cid);
ps.executeUpdate();
}
try (PreparedStatement ps = con.prepareStatement("DELETE FROM area_info WHERE charid = ?")) {
ps.setInt(1, cid);
ps.executeUpdate();
@@ -2359,31 +2393,34 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
long expTime = curTime + di.getValue().getLeft();
diseaseExpires.put(di.getKey(), expTime);
diseases.put(di.getKey(), new Pair<>(new MapleDiseaseValueHolder(curTime, expTime), di.getValue().getRight()));
diseases.put(di.getKey(), new Pair<>(new MapleDiseaseValueHolder(curTime, di.getValue().getLeft()), di.getValue().getRight()));
}
} finally {
chrLock.unlock();
}
}
public void announceDiseases(MapleClient c) {
public void announceDiseases() {
Set<Entry<MapleDisease, Pair<MapleDiseaseValueHolder, MobSkill>>> chrDiseases;
chrLock.lock();
try {
// Poison damage visibility and diseases status visibility, extended through map transitions thanks to Ronan
if(!this.isLoggedinWorld()) return;
for(Entry<MapleDisease, Pair<MapleDiseaseValueHolder, MobSkill>> di : diseases.entrySet()) {
MapleDisease disease = di.getKey();
MobSkill skill = di.getValue().getRight();
final List<Pair<MapleDisease, Integer>> debuff = Collections.singletonList(new Pair<>(disease, Integer.valueOf(skill.getX())));
if(disease != MapleDisease.SLOW) c.announce(MaplePacketCreator.giveForeignDebuff(id, debuff, skill));
else c.announce(MaplePacketCreator.giveForeignSlowDebuff(id, debuff, skill));
}
chrDiseases = new LinkedHashSet<>(diseases.entrySet());
} finally {
chrLock.unlock();
}
for(Entry<MapleDisease, Pair<MapleDiseaseValueHolder, MobSkill>> di : chrDiseases) {
MapleDisease disease = di.getKey();
MobSkill skill = di.getValue().getRight();
final List<Pair<MapleDisease, Integer>> debuff = Collections.singletonList(new Pair<>(disease, Integer.valueOf(skill.getX())));
if(disease != MapleDisease.SLOW) map.broadcastMessage(MaplePacketCreator.giveForeignDebuff(id, debuff, skill));
else map.broadcastMessage(MaplePacketCreator.giveForeignSlowDebuff(id, debuff, skill));
}
}
public void giveDebuff(final MapleDisease disease, MobSkill skill) {
@@ -6276,11 +6313,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
rs.close();
ps.close();
ps = con.prepareStatement("SELECT name FROM accounts WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
ps = con.prepareStatement("SELECT name, characterslots FROM accounts WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, ret.accountid);
rs = ps.executeQuery();
if (rs.next()) {
ret.getClient().setAccountName(rs.getString("name"));
MapleClient retClient = ret.getClient();
retClient.setAccountName(rs.getString("name"));
retClient.setCharacterSlots(rs.getByte("characterslots"));
}
rs.close();
ps.close();
@@ -6348,7 +6388,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
try (ResultSet rsProgress = pse.executeQuery()) {
while(rsProgress.next()) {
MapleQuestStatus status = loadedQuestStatus.get(rsProgress.getInt("queststatusid"));
status.setProgress(rsProgress.getInt("progressid"), rsProgress.getString("progress"));
if(status != null) {
status.setProgress(rsProgress.getInt("progressid"), rsProgress.getString("progress"));
}
}
}
}
@@ -6358,7 +6400,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
try (ResultSet rsMedalMaps = pse.executeQuery()) {
while(rsMedalMaps.next()) {
MapleQuestStatus status = loadedQuestStatus.get(rsMedalMaps.getInt("queststatusid"));
status.addMedalMap(rsMedalMaps.getInt("mapid"));
if(status != null) {
status.addMedalMap(rsMedalMaps.getInt("mapid"));
}
}
}
}
@@ -6391,6 +6435,29 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ps.setInt(1, ret.getId());
ps.executeUpdate();
ps.close();
Map<MapleDisease, Pair<Long, MobSkill>> loadedDiseases = new LinkedHashMap<>();
ps = con.prepareStatement("SELECT * FROM playerdiseases WHERE charid = ?");
ps.setInt(1, ret.getId());
rs = ps.executeQuery();
while (rs.next()) {
final MapleDisease disease = MapleDisease.ordinal(rs.getInt("disease"));
if(disease == MapleDisease.NULL) continue;
final int skillid = rs.getInt("mobskillid"), skilllv = rs.getInt("mobskilllv");
final long length = rs.getInt("length");
MobSkill ms = MobSkillFactory.getMobSkill(skillid, skilllv);
if(ms != null) {
loadedDiseases.put(disease, new Pair<>(length, ms));
}
}
rs.close();
ps.close();
ps = con.prepareStatement("DELETE FROM playerdiseases WHERE charid = ?");
ps.setInt(1, ret.getId());
ps.executeUpdate();
ps.close();
if(!loadedDiseases.isEmpty()) Server.getInstance().getPlayerBuffStorage().addDiseasesToStorage(ret.id, loadedDiseases);
ps = con.prepareStatement("SELECT * FROM skillmacros WHERE characterid = ?");
ps.setInt(1, charid);
rs = ps.executeQuery();
@@ -6921,8 +6988,8 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public synchronized void saveCooldowns() {
List<PlayerCoolDownValueHolder> listcd = getAllCooldowns();
if (listcd.size() > 0) {
if (!listcd.isEmpty()) {
try {
Connection con = DatabaseConnection.getConnection();
deleteWhereCharacterId(con, "DELETE FROM cooldowns WHERE charid = ?");
@@ -6942,6 +7009,33 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
se.printStackTrace();
}
}
Map<MapleDisease, Pair<Long, MobSkill>> listds = getAllDiseases();
if (!listds.isEmpty()) {
try {
Connection con = DatabaseConnection.getConnection();
deleteWhereCharacterId(con, "DELETE FROM playerdiseases WHERE charid = ?");
try (PreparedStatement ps = con.prepareStatement("INSERT INTO playerdiseases (charid, disease, mobskillid, mobskilllv, length) VALUES (?, ?, ?, ?, ?)")) {
ps.setInt(1, getId());
for (Entry<MapleDisease, Pair<Long, MobSkill>> e : listds.entrySet()) {
ps.setInt(2, e.getKey().ordinal());
MobSkill ms = e.getValue().getRight();
ps.setInt(3, ms.getSkillId());
ps.setInt(4, ms.getSkillLevel());
ps.setInt(5, e.getValue().getLeft().intValue());
ps.addBatch();
}
ps.executeBatch();
}
con.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
}
public void saveGuildStatus() {
@@ -7454,13 +7548,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
psf.close();
ps.close();
ps = con.prepareStatement("UPDATE accounts SET gm = ? WHERE id = ?");
ps.setInt(1, gmLevel > 1 ? 1 : 0);
ps.setInt(2, client.getAccID());
ps.executeUpdate();
ps.close();
con.commit();
con.setAutoCommit(true);
+17 -3
View File
@@ -516,13 +516,13 @@ public class MapleClient {
ResultSet rs = null;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT id, password, salt, gender, banned, gm, pin, pic, characterslots, tos FROM accounts WHERE name = ?");
ps = con.prepareStatement("SELECT id, password, salt, gender, banned, pin, pic, characterslots, tos FROM accounts WHERE name = ?");
ps.setString(1, login);
rs = ps.executeQuery();
if (rs.next()) {
boolean banned = (rs.getByte("banned") == 1);
accId = rs.getInt("id");
gmlevel = rs.getInt("gm");
gmlevel = 0;
pin = rs.getString("pin");
pic = rs.getString("pic");
gender = rs.getByte("gender");
@@ -796,7 +796,6 @@ public class MapleClient {
player.setDisconnectedFromChannelWorld();
player.notifyMapTransferToPartner(-1);
player.cancelAllBuffs(true);
player.cancelAllDebuffs();
player.closePlayerInteractions();
QuestScriptManager.getInstance().dispose(this);
@@ -845,6 +844,7 @@ public class MapleClient {
removePlayer();
player.saveCooldowns();
player.cancelAllDebuffs();
player.saveCharToDB(true);
clear();
@@ -927,6 +927,7 @@ public class MapleClient {
//getChannelServer().removePlayer(player); already being done
player.saveCooldowns();
player.cancelAllDebuffs();
player.saveCharToDB(true);
if (player != null) {//no idea, occur :(
player.empty(false);
@@ -936,6 +937,7 @@ public class MapleClient {
getChannelServer().removePlayer(player);
player.saveCooldowns();
player.cancelAllDebuffs();
player.saveCharToDB();
}
}
@@ -1191,9 +1193,21 @@ public class MapleClient {
}
}
public short getAvailableCharacterSlots() {
return (short) Math.max(0, characterSlots - Server.getInstance().getAccountCharacterCount(accId));
}
public short getAvailableCharacterWorldSlots() {
return (short) Math.max(0, characterSlots - Server.getInstance().getAccountWorldCharacterCount(accId, world));
}
public short getCharacterSlots() {
return characterSlots;
}
public void setCharacterSlots(byte slots) {
characterSlots = slots;
}
public synchronized boolean gainCharacterSlot() {
if (characterSlots < 15) {
+11 -1
View File
@@ -21,6 +21,9 @@
*/
package client;
import java.util.ArrayList;
import java.util.List;
public enum MapleDisease {
NULL(0x0),
SLOW(0x1),
@@ -55,5 +58,12 @@ public enum MapleDisease {
public boolean isFirst() {
return first;
}
public static MapleDisease ordinal(int ord) {
try {
return MapleDisease.values()[ord];
} catch (IndexOutOfBoundsException io) {
return NULL;
}
}
}
+67 -1
View File
@@ -1201,7 +1201,7 @@ public class Commands {
player.dropMessage(5, "Player '" + victim.getName() + "' is at channel " + victim.getClient().getChannel() + ".");
} else {
MapleMap map = victim.getMap();
player.changeMap(map, map.findClosestPortal(victim.getPosition()));
player.forceChangeMap(map, map.findClosestPortal(victim.getPosition()));
}
} else {
player.dropMessage(6, "Unknown player.");
@@ -2417,6 +2417,72 @@ public class Commands {
} catch(Exception e) {}
break;
case "startquest":
if (sub.length < 2){
player.yellowMessage("Syntax: !startquest <questid>");
break;
}
int questid = Integer.parseInt(sub[1]);
if (player.getQuestStatus(questid) == 0) {
MapleQuest quest = MapleQuest.getInstance(questid);
if (quest != null) {
int npcid = quest.getNpcRequirement(false);
quest.forceStart(player, npcid);
player.dropMessage(5, "QUEST " + questid + " started.");
} else {
player.dropMessage(5, "QUESTID " + questid + " is invalid.");
}
} else {
player.dropMessage(5, "QUESTID " + questid + " already started/completed.");
}
break;
case "completequest":
if (sub.length < 2){
player.yellowMessage("Syntax: !completequest <questid>");
break;
}
int questId = Integer.parseInt(sub[1]);
if (player.getQuestStatus(questId) == 1) {
MapleQuest quest = MapleQuest.getInstance(questId);
if (quest != null) {
int npcid = quest.getNpcRequirement(true);
quest.forceComplete(player, npcid);
player.dropMessage(5, "QUEST " + questId + " completed.");
} else { // should not occur
player.dropMessage(5, "QUESTID " + questId + " is invalid.");
}
} else {
player.dropMessage(5, "QUESTID " + questId + " not started or already completed.");
}
break;
case "resetquest":
if (sub.length < 2){
player.yellowMessage("Syntax: !resetquest <questid>");
break;
}
int questid_ = Integer.parseInt(sub[1]);
if (player.getQuestStatus(questid_) != 0) {
MapleQuest quest = MapleQuest.getInstance(questid_);
if (quest != null) {
quest.reset(player);
player.dropMessage(5, "QUEST " + questid_ + " reseted.");
} else { // should not occur
player.dropMessage(5, "QUESTID " + questid_ + " is invalid.");
}
}
break;
default:
return false;
}
+5
View File
@@ -25,6 +25,7 @@ import client.MapleSkinColor;
import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import constants.ServerConstants;
import net.server.Server;
import server.MapleItemInformationProvider;
import tools.MaplePacketCreator;
@@ -36,6 +37,10 @@ import tools.MaplePacketCreator;
public abstract class CharacterFactory {
protected synchronized static int createNewCharacter(MapleClient c, String name, int face, int hair, int skin, int gender, CharacterFactoryRecipe recipe) {
if (ServerConstants.COLLECTIVE_CHARSLOT ? c.getAvailableCharacterSlots() <= 0 : c.getAvailableCharacterWorldSlots() <= 0) {
return -3;
}
if (!MapleCharacter.canCreateChar(name)) {
return -1;
}
+1 -1
View File
@@ -470,7 +470,7 @@ public class Equip extends Item {
lvupStr += "+UPGSLOT ";
}
showLevelupMessage(showStr, c); // thx to Polaris dev team !
showLevelupMessage(showStr, c); // thanks to Polaris dev team !
c.getPlayer().dropMessage(6, lvupStr);
c.announce(MaplePacketCreator.showEquipmentLevelUp());
+1
View File
@@ -32,6 +32,7 @@ public class ServerConstants {
public static final boolean AUTOMATIC_REGISTER = true; //Automatically register players when they login with a nonexistent username.
public static final boolean BCRYPT_MIGRATION = true; //Performs a migration from old SHA-1 and SHA-512 password to bcrypt.
public static final boolean COLLECTIVE_CHARSLOT = false; //Available character slots are contabilized globally rather than per world server.
//Ip Configuration
public static String HOST;
+44 -7
View File
@@ -100,6 +100,7 @@ public class Server {
private final Properties subnetInfo = new Properties();
private static Server instance = null;
private final Map<Integer, Set<Integer>> accountChars = new HashMap<>();
private final Map<Integer, Short> accountCharacterCount = new HashMap<>();
private final Map<Integer, Integer> worldChars = new HashMap<>();
private final Map<String, Integer> transitioningChars = new HashMap<>();
private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>();
@@ -601,9 +602,7 @@ public class Server {
MapleClient c = processDiseaseAnnounceClients.remove(0);
MapleCharacter player = c.getPlayer();
if(player != null && player.isLoggedinWorld()) {
for(MapleCharacter chr : player.getMap().getCharacters()) {
chr.announceDiseases(c);
}
player.announceDiseases();
}
}
@@ -1089,6 +1088,32 @@ public class Server {
}
}
public short getAccountCharacterCount(Integer accountid) {
lgnRLock.lock();
try {
return accountCharacterCount.get(accountid);
} finally {
lgnRLock.unlock();
}
}
public short getAccountWorldCharacterCount(Integer accountid, Integer worldid) {
lgnRLock.lock();
try {
short count = 0;
for(Integer chr : accountChars.get(accountid)) {
if(worldChars.get(chr).equals(worldid)) {
count++;
}
}
return count;
} finally {
lgnRLock.unlock();
}
}
private Set<Integer> getAccountCharacterEntries(Integer accountid) {
lgnRLock.lock();
try {
@@ -1115,6 +1140,8 @@ public class Server {
lgnWLock.lock();
try {
accountCharacterCount.put(accountid, (short)(accountCharacterCount.get(accountid) + 1));
Set<Integer> accChars = accountChars.get(accountid);
accChars.add(chrid);
@@ -1132,6 +1159,8 @@ public class Server {
public void deleteCharacterEntry(Integer accountid, Integer chrid) {
lgnWLock.lock();
try {
accountCharacterCount.put(accountid, (short)(accountCharacterCount.get(accountid) - 1));
Set<Integer> accChars = accountChars.get(accountid);
accChars.remove(chrid);
@@ -1169,6 +1198,7 @@ public class Server {
public void deleteAccountEntry(Integer accountid) { is this even a thing?
lgnWLock.lock();
try {
accountCharacterCount.remove(accountid);
accountChars.remove(accountid);
} finally {
lgnWLock.unlock();
@@ -1190,6 +1220,7 @@ public class Server {
List<MapleCharacter> wchars = w.getAccountCharactersView(accountId);
if(wchars == null) {
if(!accountChars.containsKey(accountId)) {
accountCharacterCount.put(accountId, (short) 0);
accountChars.put(accountId, new HashSet<Integer>()); // not advisable at all to write on the map on a read-protected environment
} // yet it's known there's no problem since no other point in the source does
} else if(!wchars.isEmpty()) { // this action.
@@ -1206,7 +1237,8 @@ public class Server {
return new Pair<>(new Pair<>(chrTotal, lastwchars), accChars);
}
private static List<List<MapleCharacter>> loadAccountCharactersViewFromDb(int accId, int wlen) {
private static Pair<Short, List<List<MapleCharacter>>> loadAccountCharactersViewFromDb(int accId, int wlen) {
short characterCount = 0;
List<List<MapleCharacter>> wchars = new ArrayList<>(wlen);
for(int i = 0; i < wlen; i++) wchars.add(i, new LinkedList<MapleCharacter>());
@@ -1231,8 +1263,10 @@ public class Server {
ps.setInt(1, accId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
characterCount++;
int cworld = rs.getByte("world");
if(cworld >= wlen) break;
if(cworld >= wlen) continue;
if(cworld > curWorld) {
wchars.add(curWorld, chars);
@@ -1253,7 +1287,7 @@ public class Server {
sqle.printStackTrace();
}
return wchars;
return new Pair<>(characterCount, wchars);
}
public void loadAccountCharacters(MapleClient c) {
@@ -1300,10 +1334,13 @@ public class Server {
private int loadAccountCharactersView(Integer accId, int gmLevel, int fromWorldid) { // returns the maximum gmLevel found
List<World> wlist = this.getWorlds();
List<List<MapleCharacter>> accChars = loadAccountCharactersViewFromDb(accId, wlist.size());
Pair<Short, List<List<MapleCharacter>>> accCharacters = loadAccountCharactersViewFromDb(accId, wlist.size());
lgnWLock.lock();
try {
List<List<MapleCharacter>> accChars = accCharacters.getRight();
accountCharacterCount.put(accId, accCharacters.getLeft());
Set<Integer> chars = accountChars.get(accId);
if(chars == null) {
chars = new HashSet<>(5);
@@ -75,6 +75,7 @@ public enum MonitoredLockType {
EM_LOBBY,
EM_QUEUE,
EM_SCHDL,
EM_START,
CASHSHOP,
VISITOR_PSHOP,
STORAGE,
@@ -37,6 +37,11 @@ public final class OwlWarpHandler extends AbstractMaplePacketHandler {
int ownerid = slea.readInt();
int mapid = slea.readInt();
if(ownerid == c.getPlayer().getId()) {
c.announce(MaplePacketCreator.serverNotice(1, "You cannot visit your own shop."));
return;
}
MapleHiredMerchant hm = c.getWorldServer().getHiredMerchant(ownerid); // if both hired merchant and player shop is on the same map
MaplePlayerShop ps;
if(hm == null || hm.getMapId() != mapid || !hm.hasItem(c.getPlayer().getOwlSearch())) {
@@ -27,6 +27,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import net.AbstractMaplePacketHandler;
import net.server.PlayerBuffValueHolder;
@@ -90,6 +91,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
e.printStackTrace();
}
} else {
c.setCharacterSlots((byte) player.getClient().getCharacterSlots());
player.newClient(c);
}
if (player == null) { //If you are still getting null here then please just uninstall the game >.>, we dont need you fucking with the logs
@@ -275,16 +277,6 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
c.announce(MaplePacketCreator.enableReport());
player.changeSkillLevel(SkillFactory.getSkill(10000000 * player.getJobType() + 12), (byte) (player.getLinkedLevel() / 10), 20, -1);
player.checkBerserk(player.isHidden());
player.buffExpireTask();
player.diseaseExpireTask();
player.skillCooldownTask();
player.expirationTask();
player.questExpirationTask();
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon();
}
player.commitExcludedItems();
if (newcomer){
/*
@@ -295,12 +287,31 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
if (player.isGM()){
Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.earnTitleMessage((player.gmLevel() < 6 ? "GM " : "Admin ") + player.getName() + " has logged in"));
}
if(diseases != null) {
for(Entry<MapleDisease, Pair<Long, MobSkill>> e : diseases.entrySet()) {
final List<Pair<MapleDisease, Integer>> debuff = Collections.singletonList(new Pair<>(e.getKey(), Integer.valueOf(e.getValue().getRight().getX())));
c.announce(MaplePacketCreator.giveDebuff(debuff, e.getValue().getRight()));
}
player.announceDiseases();
}
} else {
if(player.isRidingBattleship()) {
player.announceBattleshipHp();
}
}
player.buffExpireTask();
player.diseaseExpireTask();
player.skillCooldownTask();
player.expirationTask();
player.questExpirationTask();
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon();
}
player.commitExcludedItems();
showDueyNotification(c, player);
if (player.getMap().getHPDec() > 0) player.resetHpDecreaseTask();
@@ -39,8 +39,8 @@ public final class ScriptedItemHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
slea.readInt(); // trash stamp (thx rmzero)
short itemSlot = slea.readShort(); // item sl0t (thx rmzero)
slea.readInt(); // trash stamp (thanks rmzero)
short itemSlot = slea.readShort(); // item slot (thanks rmzero)
int itemId = slea.readInt(); // itemId
scriptedItem info = ii.getScriptedItemInfo(itemId);
if (info == null) return;
@@ -34,6 +34,7 @@ import client.inventory.ModifyInventory;
import constants.ItemConstants;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.AbstractMaplePacketHandler;
import client.inventory.manipulator.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
@@ -72,10 +73,17 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
Item scroll = useInventory.getItem(slot);
Item wscroll = null;
if (((Equip) toScroll).getUpgradeSlots() < 1 && !ItemConstants.isCleanSlate(scroll.getItemId())) {
if (ItemConstants.isCleanSlate(scroll.getItemId())) {
Map<String, Integer> eqStats = ii.getEquipStats(scroll.getItemId());
if (eqStats == null || eqStats.get("tuc") == 0) {
c.announce(MaplePacketCreator.getInventoryFull());
return;
}
} else if (((Equip) toScroll).getUpgradeSlots() < 1) {
c.announce(MaplePacketCreator.getInventoryFull());
return;
}
List<Integer> scrollReqs = ii.getScrollReqs(scroll.getItemId());
if (scrollReqs.size() > 0 && !scrollReqs.contains(toScroll.getItemId())) {
c.announce(MaplePacketCreator.getInventoryFull());
@@ -27,7 +27,6 @@ import java.sql.SQLException;
import net.AbstractMaplePacketHandler;
import net.server.world.World;
import tools.LogHelper;
import tools.DatabaseConnection;
import tools.FilePrinter;
import tools.MaplePacketCreator;
@@ -42,7 +41,8 @@ import java.sql.Connection;
* @author Matze
*/
public final class WhisperHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte mode = slea.readByte();
if (mode == 6) { // whisper
@@ -92,7 +92,7 @@ public final class WhisperHandler extends AbstractMaplePacketHandler {
} else {
c.announce(MaplePacketCreator.getFindReply(victim.getName(), victim.getMap().getId(), 1));
}
} else { // not found
} else if (c.getPlayer().gmLevel() > 1) { // not found
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT gm FROM characters WHERE name = ?");
@@ -116,6 +116,8 @@ public final class WhisperHandler extends AbstractMaplePacketHandler {
} catch (SQLException e) {
e.printStackTrace();
}
} else {
c.announce(MaplePacketCreator.getWhisperReply(recipient, (byte) 0));
}
} else if (mode == 0x44) {
//Buddy find?
+36 -25
View File
@@ -117,14 +117,16 @@ public class MapleGuild {
return;
}
Set<Integer> chs = Server.getInstance().getOpenChannels(world);
if (notifications.keySet().size() != chs.size()) {
notifications.clear();
for (Integer ch : chs) {
notifications.put(ch, new LinkedList<Integer>());
}
} else {
for (List<Integer> l : notifications.values()) {
l.clear();
synchronized (notifications) {
if (notifications.keySet().size() != chs.size()) {
notifications.clear();
for (Integer ch : chs) {
notifications.put(ch, new LinkedList<Integer>());
}
} else {
for (List<Integer> l : notifications.values()) {
l.clear();
}
}
}
@@ -134,7 +136,11 @@ public class MapleGuild {
if (!mgc.isOnline()) {
continue;
}
List<Integer> chl = notifications.get(mgc.getChannel());
List<Integer> chl;
synchronized (notifications) {
chl = notifications.get(mgc.getChannel());
}
if (chl != null) chl.add(mgc.getId());
//Unable to connect to Channel... error was here
}
@@ -279,26 +285,31 @@ public class MapleGuild {
}
public void broadcast(final byte[] packet, int exceptionId, BCOp bcop) {
synchronized (notifications) {
if (bDirty) {
buildNotifications();
}
try {
for (Integer b : Server.getInstance().getOpenChannels(world)) {
if (notifications.get(b).size() > 0) {
if (bcop == BCOp.DISBAND) {
Server.getInstance().getWorld(world).setGuildAndRank(notifications.get(b), 0, 5, exceptionId);
} else if (bcop == BCOp.EMBLEMCHANGE) {
Server.getInstance().getWorld(world).changeEmblem(this.id, notifications.get(b), new MapleGuildSummary(this));
} else {
Server.getInstance().getWorld(world).sendPacket(notifications.get(b), packet, exceptionId);
membersLock.lock(); // membersLock awareness thanks to ProjectNano dev team
try {
synchronized (notifications) {
if (bDirty) {
buildNotifications();
}
try {
for (Integer b : Server.getInstance().getOpenChannels(world)) {
if (notifications.get(b).size() > 0) {
if (bcop == BCOp.DISBAND) {
Server.getInstance().getWorld(world).setGuildAndRank(notifications.get(b), 0, 5, exceptionId);
} else if (bcop == BCOp.EMBLEMCHANGE) {
Server.getInstance().getWorld(world).changeEmblem(this.id, notifications.get(b), new MapleGuildSummary(this));
} else {
Server.getInstance().getWorld(world).sendPacket(notifications.get(b), packet, exceptionId);
}
}
}
} catch (Exception re) {
re.printStackTrace();
System.out.println("Failed to contact channel(s) for broadcast.");//fu?
}
} catch (Exception re) {
re.printStackTrace();
System.out.println("Failed to contact channel(s) for broadcast.");//fu?
}
} finally {
membersLock.unlock();
}
}
+10 -6
View File
@@ -224,14 +224,18 @@ public class EventInstanceManager {
}
public void registerPlayer(MapleCharacter chr) {
if (chr == null || !chr.isLoggedin()){
public synchronized void registerPlayer(MapleCharacter chr) {
if (chr == null || !chr.isLoggedinWorld() || disposed) {
return;
}
try {
wL.lock();
try {
if(chars.containsKey(chr.getId())) {
return;
}
chars.put(chr.getId(), chr);
chr.setEventInstance(this);
} finally {
@@ -249,7 +253,7 @@ public class EventInstanceManager {
}
}
public void exitPlayer(MapleCharacter chr) { //unused
public void exitPlayer(MapleCharacter chr) {
if (chr == null || !chr.isLoggedin()){
return;
}
@@ -299,7 +303,7 @@ public class EventInstanceManager {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement scheduledTimeout function.", ex);
}
}
}, time);
@@ -324,7 +328,7 @@ public class EventInstanceManager {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement scheduledTimeout function.", ex);
}
}
}, nextTime);
@@ -397,7 +401,7 @@ public class EventInstanceManager {
sL.unlock();
}
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, "Event '" + em.getName() + "' does not implement playerUnregistered function.", ex);
}
wL.lock();
+232 -122
View File
@@ -48,10 +48,14 @@ import server.life.MapleMonster;
import server.life.MapleLifeFactory;
import server.quest.MapleQuest;
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import net.server.audit.LockCollector;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
@@ -74,12 +78,16 @@ public class EventManager {
private final Map<Integer, Integer> queuedGuildLeaders = new HashMap<>();
private List<Boolean> openedLobbys;
private List<EventInstanceManager> readyInstances = new LinkedList<>();
private Integer readyId = 0;
private Integer readyId = 0, onLoadInstances = 0;
private Properties props = new Properties();
private String name;
private MonitoredReentrantLock lobbyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_LOBBY);
private MonitoredReentrantLock queueLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_QUEUE);
private MonitoredReentrantLock startLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EM_START);
private Set<Integer> playerPermit = new HashSet<>();
private Semaphore startSemaphore = new Semaphore(7);
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
public EventManager(Channel cserv, Invocable iv, String name) {
@@ -114,6 +122,7 @@ public class EventManager {
try {
readyEims = new ArrayList<>(readyInstances);
readyInstances.clear();
onLoadInstances = Integer.MIN_VALUE / 2;
} finally {
queueLock.unlock();
}
@@ -143,6 +152,7 @@ public class EventManager {
private void emptyLocks() {
lobbyLock = lobbyLock.dispose();
queueLock = queueLock.dispose();
startLock = startLock.dispose();
}
private static List<Integer> convertToIntegerArray(List<Double> list) {
@@ -333,33 +343,50 @@ public class EventManager {
//Expedition method: starts an expedition
public boolean startInstance(int lobbyId, MapleExpedition exped, MapleCharacter leader) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", leader.getClient().getChannel()));
if(eim == null) {
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", leader.getClient().getChannel()));
if(eim == null) {
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
exped.start();
eim.registerExpedition(exped);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
exped.start();
eim.registerExpedition(exped);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return true;
return false;
}
//Regular method: player
@@ -373,36 +400,53 @@ public class EventManager {
public boolean startInstance(int lobbyId, MapleCharacter chr, MapleCharacter leader, int difficulty) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) {
return false;
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) {
return false;
}
}
else {
if(!startLobbyInstance(lobbyId)) {
return false;
}
}
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);
if(chr != null) eim.registerPlayer(chr);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
}
else {
if(!startLobbyInstance(lobbyId)) {
return false;
}
}
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);
if(chr != null) eim.registerPlayer(chr);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return true;
return false;
}
//PQ method: starts a PQ
@@ -416,33 +460,50 @@ public class EventManager {
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, MapleCharacter leader) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null));
if(eim == null) {
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
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.setLeader(leader);
eim.registerParty(party, map);
party.setEligibleMembers(null);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
eim.registerParty(party, map);
party.setEligibleMembers(null);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return true;
return false;
}
//PQ method: starts a PQ with a difficulty level, requires function setup(difficulty, leaderid) instead of setup()
@@ -456,33 +517,50 @@ public class EventManager {
public boolean startInstance(int lobbyId, MapleParty party, MapleMap map, int difficulty, MapleCharacter leader) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : party.getLeaderId()));
if(eim == null) {
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
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.setLeader(leader);
eim.registerParty(party, map);
party.setEligibleMembers(null);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
eim.registerParty(party, map);
party.setEligibleMembers(null);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return true;
return false;
}
//non-PQ method for starting instance
@@ -500,32 +578,49 @@ public class EventManager {
public boolean startInstance(int lobbyId, EventInstanceManager eim, String ldr, MapleCharacter leader) {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
if(eim == null) {
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
if(!playerPermit.contains(leader.getId()) && startSemaphore.tryAcquire(7777, TimeUnit.MILLISECONDS)) {
playerPermit.add(leader.getId());
startLock.lock();
try {
try {
if(lobbyId == -1) {
lobbyId = availableLobbyInstance();
if(lobbyId == -1) return false;
}
else {
if(!startLobbyInstance(lobbyId)) return false;
}
if(eim == null) {
if(lobbyId > -1) {
setLockLobby(lobbyId, false);
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
iv.invokeFunction("setup", eim);
eim.setProperty("leader", ldr);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
} finally {
startLock.unlock();
playerPermit.remove(leader.getId());
startSemaphore.release();
}
return false;
}
instanceLocks.put(eim.getName(), lobbyId);
eim.setLeader(leader);
iv.invokeFunction("setup", eim);
eim.setProperty("leader", ldr);
eim.startEvent();
} catch (ScriptException | NoSuchMethodException ex) {
Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex);
} catch(InterruptedException ie) {
playerPermit.remove(leader.getId());
}
return true;
return false;
}
public List<MaplePartyCharacter> getEligibleParty(MapleParty party) {
@@ -713,16 +808,31 @@ public class EventManager {
}
private void instantiateQueuedInstance() {
int nextEventId;
queueLock.lock();
try {
if(readyInstances.size() >= Math.ceil((double)maxLobbys / 3.0)) return;
if(onLoadInstances <= -1000 || readyInstances.size() + onLoadInstances >= Math.ceil((double)maxLobbys / 3.0)) return;
readyInstances.add(new EventInstanceManager(this, "sampleName" + readyId));
onLoadInstances++;
nextEventId = readyId;
readyId++;
} finally {
queueLock.unlock();
}
EventInstanceManager eim = new EventInstanceManager(this, "sampleName" + nextEventId);
queueLock.lock();
try {
if(onLoadInstances <= -1000) { // EM already disposed
return;
}
readyInstances.add(eim);
onLoadInstances--;
} finally {
queueLock.unlock();
}
instantiateQueuedInstance(); // keep filling the queue until reach threshold.
}
@@ -344,7 +344,9 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
public void gainCloseness(int closeness) {
for (MaplePet pet : getPlayer().getPets()) {
if(pet != null) pet.gainClosenessFullness(getPlayer(), closeness, 0, 0);
if(pet != null) {
pet.gainClosenessFullness(getPlayer(), closeness, 0, 0);
}
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ import client.MapleCharacter;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class MapleExpedition {
@@ -26,7 +26,7 @@ import constants.ServerConstants;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public enum MapleExpeditionType {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class Ellinia extends GachaponItems {
+1 -1
View File
@@ -24,7 +24,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public abstract class GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class Global extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class Henesys extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class KerningCity extends GachaponItems {
+1 -1
View File
@@ -25,7 +25,7 @@ import tools.Randomizer;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class MapleGachapon {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class MushroomShrine extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class NautilusHarbor extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class NewLeafCity extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class Perion extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class ShowaSpaFemale extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class ShowaSpaMale extends GachaponItems {
+1 -1
View File
@@ -2,7 +2,7 @@ package server.gachapon;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public class Sleepywood extends GachaponItems {
+67 -7
View File
@@ -156,7 +156,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
return hp.get();
}
public void addHp(int hp) {
public synchronized void addHp(int hp) {
if(this.hp.get() <= 0) return;
this.hp.addAndGet(hp);
}
@@ -287,6 +288,10 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
}
public synchronized void disposeMapObject() { // mob is no longer associated with the map it was in
hp.set(-1);
}
public void broadcastMobHpBar(MapleCharacter from) {
if (hasBossHPBar()) {
from.setPlayerAggro(this.hashCode());
@@ -307,13 +312,58 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
}
public boolean damage(MapleCharacter attacker, int damage, boolean stayAlive) {
boolean lastHit = false;
this.lockMonster();
try {
if (!this.isAlive()) {
return false;
}
/* pyramid not implemented
Pair<Integer, Integer> cool = this.getStats().getCool();
if (cool != null) {
Pyramid pq = (Pyramid) chr.getPartyQuest();
if (pq != null) {
if (damage > 0) {
if (damage >= cool.getLeft()) {
if ((Math.random() * 100) < cool.getRight()) {
pq.cool();
} else {
pq.kill();
}
} else {
pq.kill();
}
} else {
pq.miss();
}
killed = true;
}
}
*/
if (damage > 0) {
this.applyDamage(attacker, damage, stayAlive);
if (!this.isAlive()) { // monster just died
lastHit = true;
}
}
} finally {
this.unlockMonster();
}
return lastHit;
}
/**
*
* @param from the player that dealt the damage
* @param damage
* @param stayAlive
*/
public synchronized void damage(MapleCharacter from, int damage, boolean stayAlive) {
private void applyDamage(MapleCharacter from, int damage, boolean stayAlive) {
Integer trueDamage = applyAndGetHpDamage(damage, stayAlive);
if (trueDamage == null) {
return;
@@ -628,10 +678,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
}
public synchronized void dispatchMonsterKilled(boolean hasKiller) {
if(!hasKiller) {
dispatchUpdateQuestMobCount();
}
public void dispatchMonsterKilled(boolean hasKiller) {
processMonsterKilled(hasKiller);
EventInstanceManager eim = getMap().getEventInstance();
if (eim != null) {
@@ -641,6 +689,12 @@ public class MapleMonster extends AbstractLoadedMapleLife {
eim.friendlyKilled(this, hasKiller);
}
}
}
private synchronized void processMonsterKilled(boolean hasKiller) {
if(!hasKiller) {
dispatchUpdateQuestMobCount();
}
MonsterListener[] listenersList;
statiLock.lock();
@@ -1321,7 +1375,13 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
}
if (damage > 0) {
damage(chr, damage, true);
lockMonster();
try {
applyDamage(chr, damage, true);
} finally {
unlockMonster();
}
if (type == 1) {
map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition());
} else if (type == 2) {
+5 -4
View File
@@ -24,6 +24,7 @@ package server.life;
import client.MapleCharacter;
import java.awt.Point;
import java.util.concurrent.atomic.AtomicInteger;
import net.server.Server;
public class SpawnPoint {
private int monster, mobTime, team, fh, f;
@@ -42,7 +43,7 @@ public class SpawnPoint {
this.f = monster.getF();
this.immobile = immobile;
this.mobInterval = mobInterval;
this.nextPossibleSpawn = System.currentTimeMillis();
this.nextPossibleSpawn = Server.getInstance().getCurrentTime();
}
public int getSpawned() {
@@ -61,7 +62,7 @@ public class SpawnPoint {
if (denySpawn || mobTime < 0 || spawnedMonsters.get() > 0) {
return false;
}
return nextPossibleSpawn <= System.currentTimeMillis();
return nextPossibleSpawn <= Server.getInstance().getCurrentTime();
}
public boolean shouldForceSpawn() {
@@ -82,7 +83,7 @@ public class SpawnPoint {
mob.addListener(new MonsterListener() {
@Override
public void monsterKilled(int aniTime) {
nextPossibleSpawn = System.currentTimeMillis();
nextPossibleSpawn = Server.getInstance().getCurrentTime();
if (mobTime > 0) {
nextPossibleSpawn += mobTime * 1000;
} else {
@@ -98,7 +99,7 @@ public class SpawnPoint {
public void monsterHealed(int trueHeal) {}
});
if (mobTime == 0) {
nextPossibleSpawn = System.currentTimeMillis() + mobInterval;
nextPossibleSpawn = Server.getInstance().getCurrentTime() + mobInterval;
}
return mob;
}
+124 -160
View File
@@ -295,28 +295,21 @@ public class MapleMap {
public int getTimeLeft() {
return (int) ((timeLimit - System.currentTimeMillis()) / 1000);
}
public void setReactorState() {
chrRLock.lock();
objectRLock.lock();
try {
for (MapleMapObject o : mapobjects.values()) {
if (o.getType() == MapleMapObjectType.REACTOR) {
if (((MapleReactor) o).getState() < 1) {
MapleReactor mr = (MapleReactor) o;
mr.lockReactor();
try {
mr.resetReactorActions(1);
broadcastMessage(MaplePacketCreator.triggerReactor((MapleReactor) o, 1));
} finally {
mr.unlockReactor();
}
for (MapleMapObject o : getMapObjects()) {
if (o.getType() == MapleMapObjectType.REACTOR) {
if (((MapleReactor) o).getState() < 1) {
MapleReactor mr = (MapleReactor) o;
mr.lockReactor();
try {
mr.resetReactorActions(1);
broadcastMessage(MaplePacketCreator.triggerReactor((MapleReactor) o, 1));
} finally {
mr.unlockReactor();
}
}
}
} finally {
objectRLock.unlock();
chrRLock.unlock();
}
}
@@ -1191,45 +1184,7 @@ public class MapleMap {
}
}
if (monster.isAlive()) {
boolean killed = false;
monster.lockMonster();
try {
if (!monster.isAlive()) {
return false;
}
/* pyramid not implemented
Pair<Integer, Integer> cool = monster.getStats().getCool();
if (cool != null) {
Pyramid pq = (Pyramid) chr.getPartyQuest();
if (pq != null) {
if (damage > 0) {
if (damage >= cool.getLeft()) {
if ((Math.random() * 100) < cool.getRight()) {
pq.cool();
} else {
pq.kill();
}
} else {
pq.kill();
}
} else {
pq.miss();
}
killed = true;
}
}
*/
if (damage > 0) {
monster.damage(chr, damage, false);
if (!monster.isAlive()) { // monster just died
killed = true;
}
}
} finally {
monster.unlockMonster();
}
boolean killed = monster.damage(chr, damage, false);
if (monster.getStats().selfDestruction() != null && monster.getStats().selfDestruction().getHp() > -1) {// should work ;p
if (monster.getHp() <= monster.getStats().selfDestruction().getHp()) {
killMonster(monster, chr, true, monster.getStats().selfDestruction().getAction());
@@ -1268,6 +1223,23 @@ public class MapleMap {
Server.getInstance().getWorld(world).dropMessage(6, "[VICTORY] In a swift stroke of sorts, the crew that has attempted Pink Bean at channel " + channel + " has ultimately defeated it. The Temple of Time shines radiantly once again, the day finally coming back, as the crew that managed to finally conquer it returns victoriously from the battlefield!!");
}
private boolean removeKilledMonsterObject(MapleMonster monster) {
monster.lockMonster();
try {
if(monster.getHp() < 0) {
return false;
}
spawnedMonstersOnMap.decrementAndGet();
removeMapObject(monster);
monster.disposeMapObject();
return true;
} finally {
monster.unlockMonster();
}
}
public void killMonster(final MapleMonster monster, final MapleCharacter chr, final boolean withDrops) {
killMonster(monster, chr, withDrops, 1);
}
@@ -1276,93 +1248,89 @@ public class MapleMap {
if(monster == null) return;
if (chr == null) {
spawnedMonstersOnMap.decrementAndGet();
monster.setHpZero();
removeMapObject(monster);
monster.dispatchMonsterKilled(false);
broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition());
return;
}
if (monster.getStats().getLevel() >= chr.getLevel() + 30 && !chr.isGM()) {
AutobanFactory.GENERAL.alert(chr, " for killing a " + monster.getName() + " which is over 30 levels higher.");
}
/*if (chr.getQuest(MapleQuest.getInstance(29400)).getStatus().equals(MapleQuestStatus.Status.STARTED)) {
if (chr.getLevel() >= 120 && monster.getStats().getLevel() >= 120) {
//FIX MEDAL SHET
} else if (monster.getStats().getLevel() >= chr.getLevel()) {
}
}*/
int buff = monster.getBuffToGive();
if (buff > -1) {
MapleItemInformationProvider mii = MapleItemInformationProvider.getInstance();
for (MapleMapObject mmo : this.getPlayers()) {
MapleCharacter character = (MapleCharacter) mmo;
if (character.isAlive()) {
MapleStatEffect statEffect = mii.getItemEffect(buff);
character.getClient().announce(MaplePacketCreator.showOwnBuffEffect(buff, 1));
broadcastMessage(character, MaplePacketCreator.showBuffeffect(character.getId(), buff, 1), false);
statEffect.applyTo(character);
}
if(removeKilledMonsterObject(monster)) {
monster.dispatchMonsterKilled(false);
broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition());
}
}
spawnedMonstersOnMap.decrementAndGet();
monster.setHpZero();
removeMapObject(monster);
if (monster.getCP() > 0 && chr.getCarnival() != null) {
chr.getCarnivalParty().addCP(chr, monster.getCP());
chr.announce(MaplePacketCreator.updateCP(chr.getCP(), chr.getObtainedCP()));
broadcastMessage(MaplePacketCreator.updatePartyCP(chr.getCarnivalParty()));
//they drop items too ):
}
if (monster.getId() >= 8800003 && monster.getId() <= 8800010) {
boolean makeZakReal = true;
Collection<MapleMapObject> objects = getMapObjects();
for (MapleMapObject object : objects) {
MapleMonster mons = getMonsterByOid(object.getObjectId());
if (mons != null) {
if (mons.getId() >= 8800003 && mons.getId() <= 8800010) {
makeZakReal = false;
break;
}
} else {
if(removeKilledMonsterObject(monster)) {
if (monster.getStats().getLevel() >= chr.getLevel() + 30 && !chr.isGM()) {
AutobanFactory.GENERAL.alert(chr, " for killing a " + monster.getName() + " which is over 30 levels higher.");
}
}
if (makeZakReal) {
MapleMap map = chr.getMap();
for (MapleMapObject object : objects) {
MapleMonster mons = map.getMonsterByOid(object.getObjectId());
if (mons != null) {
if (mons.getId() == 8800000) {
makeMonsterReal(mons);
updateMonsterController(mons);
break;
/*if (chr.getQuest(MapleQuest.getInstance(29400)).getStatus().equals(MapleQuestStatus.Status.STARTED)) {
if (chr.getLevel() >= 120 && monster.getStats().getLevel() >= 120) {
//FIX MEDAL SHET
} else if (monster.getStats().getLevel() >= chr.getLevel()) {
}
}*/
int buff = monster.getBuffToGive();
if (buff > -1) {
MapleItemInformationProvider mii = MapleItemInformationProvider.getInstance();
for (MapleMapObject mmo : this.getPlayers()) {
MapleCharacter character = (MapleCharacter) mmo;
if (character.isAlive()) {
MapleStatEffect statEffect = mii.getItemEffect(buff);
character.getClient().announce(MaplePacketCreator.showOwnBuffEffect(buff, 1));
broadcastMessage(character, MaplePacketCreator.showBuffeffect(character.getId(), buff, 1), false);
statEffect.applyTo(character);
}
}
}
}
}
MapleCharacter dropOwner = monster.killBy(chr);
if (withDrops && !monster.dropsDisabled()) {
if (dropOwner == null) {
dropOwner = chr;
}
dropFromMonster(dropOwner, monster, false);
}
if (monster.hasBossHPBar()) {
for(MapleCharacter mc : this.getAllPlayers()) {
if(mc.getTargetHpBarHash() == monster.hashCode()) {
mc.resetPlayerAggro();
if (monster.getCP() > 0 && chr.getCarnival() != null) {
chr.getCarnivalParty().addCP(chr, monster.getCP());
chr.announce(MaplePacketCreator.updateCP(chr.getCP(), chr.getObtainedCP()));
broadcastMessage(MaplePacketCreator.updatePartyCP(chr.getCarnivalParty()));
//they drop items too ):
}
if (monster.getId() >= 8800003 && monster.getId() <= 8800010) {
boolean makeZakReal = true;
Collection<MapleMapObject> objects = getMapObjects();
for (MapleMapObject object : objects) {
MapleMonster mons = getMonsterByOid(object.getObjectId());
if (mons != null) {
if (mons.getId() >= 8800003 && mons.getId() <= 8800010) {
makeZakReal = false;
break;
}
}
}
if (makeZakReal) {
MapleMap map = chr.getMap();
for (MapleMapObject object : objects) {
MapleMonster mons = map.getMonsterByOid(object.getObjectId());
if (mons != null) {
if (mons.getId() == 8800000) {
makeMonsterReal(mons);
updateMonsterController(mons);
break;
}
}
}
}
}
MapleCharacter dropOwner = monster.killBy(chr);
if (withDrops && !monster.dropsDisabled()) {
if (dropOwner == null) {
dropOwner = chr;
}
dropFromMonster(dropOwner, monster, false);
}
if (monster.hasBossHPBar()) {
for(MapleCharacter mc : this.getAllPlayers()) {
if(mc.getTargetHpBarHash() == monster.hashCode()) {
mc.resetPlayerAggro();
}
}
}
monster.dispatchMonsterKilled(true);
broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition());
}
}
monster.dispatchMonsterKilled(true);
broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition());
}
public void killFriendlies(MapleMonster mob) {
@@ -1407,11 +1375,9 @@ public class MapleMap {
continue;
}
spawnedMonstersOnMap.decrementAndGet();
monster.setHpZero();
removeMapObject(monster);
monster.dispatchMonsterKilled(false);
if(removeKilledMonsterObject(monster)) {
monster.dispatchMonsterKilled(false);
}
}
}
@@ -2228,33 +2194,31 @@ public class MapleMap {
int reactItem = reactProp.getLeft(), reactQty = reactProp.getRight();
Rectangle reactArea = react.getArea();
List<MapleMapItem> list = new ArrayList<>();
List<MapleMapItem> list;
objectRLock.lock();
try {
for(MapleMapItem mmi : droppedItems.keySet()) {
mmi.lockItem();
try {
if(!mmi.isPickedUp()) {
list.add(mmi);
}
} finally {
mmi.unlockItem();
}
}
list = new ArrayList<>(droppedItems.keySet());
} finally {
objectRLock.unlock();
}
for(final MapleMapItem drop : list) {
final Item item = drop.getItem();
if (item != null && reactItem == item.getItemId() && reactQty == item.getQuantity()) {
if (reactArea.contains(drop.getPosition())) {
MapleClient owner = drop.getOwnerClient();
if(owner != null) {
registerMapSchedule(new ActivateItemReactor(drop, react, owner), 5000);
drop.lockItem();
try {
if(!drop.isPickedUp()) {
final Item item = drop.getItem();
if (item != null && reactItem == item.getItemId() && reactQty == item.getQuantity()) {
if (reactArea.contains(drop.getPosition())) {
MapleClient owner = drop.getOwnerClient();
if(owner != null) {
registerMapSchedule(new ActivateItemReactor(drop, react, owner), 5000);
}
}
}
}
} finally {
drop.unlockItem();
}
}
}
@@ -2365,7 +2329,7 @@ public class MapleMap {
try {
characters.add(chr);
chrSize = characters.size();
addPartyMemberInternal(chr);
itemMonitorTimeout = 1;
} finally {
+1 -1
View File
@@ -23,7 +23,7 @@ package server.maps;
/**
*
* @author SharpAceX(Alan)
* @author Alan (SharpAceX)
*/
public enum MapleMiniDungeonInfo {
@@ -7,7 +7,7 @@ import server.maps.MapleMap;
import tools.MaplePacketCreator;
/**
* @author Rob //Thanks :3 - LOST MOTIVATION >=(
* @author Rob
*/
public class MonsterCarnivalParty {
+11
View File
@@ -540,6 +540,17 @@ public class MapleQuest {
return medalid != null ? medalid : -1;
}
public int getNpcRequirement(boolean complete) {
Map<MapleQuestRequirementType, MapleQuestRequirement> reqs = !complete ? startReqs : completeReqs;
MapleQuestRequirement mqr = reqs.get(MapleQuestRequirementType.NPC);
if (mqr != null) {
return ((NpcRequirement) mqr).get();
} else {
return -1;
}
}
public static void loadAllQuest() {
questInfo = questData.getData("QuestInfo.img");
questReq = questData.getData("Check.img");
@@ -49,4 +49,8 @@ public class NpcRequirement extends MapleQuestRequirement {
public boolean check(MapleCharacter chr, Integer npcid) {
return npcid != null && npcid == reqNPC;
}
public int get() {
return reqNPC;
}
}
@@ -55,6 +55,8 @@ public class PetRequirement extends MapleQuestRequirement {
@Override
public boolean check(MapleCharacter chr, Integer npcid) {
for(MaplePet pet : chr.getPets()) {
if(pet == null) continue; // thanks Arufonsu for showing a NPE occurring here
if(petIDs.contains(pet.getItemId()))
return true;
}
+1 -1
View File
@@ -29,7 +29,7 @@ import client.MapleClient;
/**
* Logs packets to console and file.
*
* @author SharpAceX (Alan)
* @author Alan (SharpAceX)
*/
public class MapleLogger {
+5 -5
View File
@@ -863,11 +863,11 @@ public class MaplePacketCreator {
List<MapleCharacter> chars = c.loadCharacters(serverId);
mplew.write((byte) chars.size());
for (MapleCharacter chr : chars) {
addCharEntry(mplew, chr, false);
addCharEntry(mplew, chr, false);
}
mplew.write(ServerConstants.ENABLE_PIC ? (c.getPic() == null ? 0 : 1) : 2);
mplew.writeInt(c.getCharacterSlots());
mplew.writeInt(ServerConstants.COLLECTIVE_CHARSLOT ? chars.size() + c.getAvailableCharacterSlots() : c.getCharacterSlots());
return mplew.getPacket();
}
@@ -2812,7 +2812,7 @@ public class MaplePacketCreator {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
mplew.writeInt(cid);
mplew.writeLong(MapleBuffStat.MONSTER_RIDING.getValue()); //Thanks?
mplew.writeLong(MapleBuffStat.MONSTER_RIDING.getValue());
mplew.writeLong(0);
mplew.writeShort(0);
mplew.writeInt(mount.getItemId());
@@ -6079,14 +6079,14 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
public static byte[] enableReport() { // by snow
public static byte[] enableReport() { // thanks to snow
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
mplew.writeShort(SendOpcode.CLAIM_STATUS_CHANGED.getValue());
mplew.write(1);
return mplew.getPacket();
}
public static byte[] giveFinalAttack(int skillid, int time) {//packets found by lailainoob
public static byte[] giveFinalAttack(int skillid, int time) { // packets found thanks to lailainoob
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.GIVE_BUFF.getValue());
mplew.writeLong(0);