Channel Services + Mob Movement patch + Portal map scripts
Refactored several schedulers within the channel class, now running within their own service modules. Fixed a case where mob movements would get mistakably processed for other than the target mob during a map transition, leading to weird movements on the mob in the entered area. Added usage of foreign key for petid's. Implemented functionality for "Hair Membership" coupons. Fixed skill Body Pressure not applying the chance to neutralise on touch. Fixed quest related to NPC Shaman Rock not completing due to unmatched progress. Fixed an issue with updating title progress "Touch the Sky".
This commit is contained in:
@@ -142,7 +142,6 @@ import client.processor.action.PetAutopotProcessor;
|
||||
import constants.game.ExpTable;
|
||||
import constants.game.GameConstants;
|
||||
import constants.inventory.ItemConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import constants.skills.Aran;
|
||||
import constants.skills.Beginner;
|
||||
import constants.skills.Bishop;
|
||||
@@ -172,6 +171,9 @@ import constants.skills.Shadower;
|
||||
import constants.skills.Sniper;
|
||||
import constants.skills.Warrior;
|
||||
import constants.skills.ThunderBreaker;
|
||||
import net.server.channel.services.ServiceType;
|
||||
import net.server.channel.services.task.BaseService;
|
||||
import net.server.channel.services.task.FaceExpressionService;
|
||||
import org.apache.mina.util.ConcurrentHashSet;
|
||||
|
||||
public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
@@ -320,7 +322,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
private boolean loggedIn = false;
|
||||
private boolean useCS; //chaos scroll upon crafting item.
|
||||
private long npcCd;
|
||||
private long petLootCd;
|
||||
private long lastHpDec = 0;
|
||||
private int newWarpMap = -1;
|
||||
private boolean canWarpMap = true; //only one "warp" must be used per call, and this will define the right one.
|
||||
@@ -398,8 +399,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
quests = new LinkedHashMap<>();
|
||||
setPosition(new Point(0, 0));
|
||||
|
||||
petLootCd = Server.getInstance().getCurrentTime();
|
||||
}
|
||||
|
||||
private static MapleJob getJobStyleInternal(int jobid, byte opt) {
|
||||
@@ -439,7 +438,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
public static MapleCharacter getDefault(MapleClient c) {
|
||||
MapleCharacter ret = new MapleCharacter();
|
||||
ret.client = c;
|
||||
ret.gmLevel = 0;
|
||||
ret.setGMLevel(0);
|
||||
ret.hp = 50;
|
||||
ret.setMaxHp(50);
|
||||
ret.mp = 5;
|
||||
@@ -569,14 +568,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
client.getSession().setAttribute(MapleClient.CLIENT_TRANSITION);
|
||||
}
|
||||
|
||||
public long getPetLootCd() {
|
||||
return petLootCd;
|
||||
}
|
||||
|
||||
public void setPetLootCd(long cd) {
|
||||
petLootCd = cd;
|
||||
}
|
||||
|
||||
public boolean getCS() {
|
||||
return useCS;
|
||||
}
|
||||
@@ -822,7 +813,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
mainstat = localstr;
|
||||
secondarystat = localdex;
|
||||
}
|
||||
return (int) (((weapon.getMaxDamageMultiplier() * mainstat + secondarystat) / 100.0) * watk);
|
||||
return (int) Math.ceil(((weapon.getMaxDamageMultiplier() * mainstat + secondarystat) / 100.0) * watk);
|
||||
}
|
||||
|
||||
public int calculateMaxBaseDamage(int watk) {
|
||||
@@ -838,7 +829,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
int attack = (int) Math.min(Math.floor((2 * getLevel() + 31) / 3), 31);
|
||||
maxbasedamage = (int) (localstr * weapMulti + localdex) * attack / 100;
|
||||
maxbasedamage = (int) Math.ceil((localstr * weapMulti + localdex) * attack / 100.0);
|
||||
} else {
|
||||
maxbasedamage = 1;
|
||||
}
|
||||
@@ -2346,6 +2337,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
ps.setInt(1, cid);
|
||||
ps.executeUpdate();
|
||||
}
|
||||
try (PreparedStatement ps = con.prepareStatement("DELETE FROM family_character WHERE cid = ?")) {
|
||||
ps.setInt(1, cid);
|
||||
ps.executeUpdate();
|
||||
}
|
||||
try (PreparedStatement ps = con.prepareStatement("DELETE FROM famelog WHERE characterid_to = ?")) {
|
||||
ps.setInt(1, cid);
|
||||
ps.executeUpdate();
|
||||
@@ -2383,7 +2378,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
int petid = rs.getInt("petid");
|
||||
if(petid > -1) {
|
||||
if(!rs.wasNull()) {
|
||||
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM pets WHERE petid = ?")) {
|
||||
ps2.setInt(1, petid);
|
||||
ps2.executeUpdate();
|
||||
@@ -2850,7 +2845,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
long timeNow = Server.getInstance().getCurrentTime();
|
||||
if(timeNow - lastExpression > 2000) {
|
||||
lastExpression = timeNow;
|
||||
client.getChannelServer().registerFaceExpression(map, this, emote);
|
||||
|
||||
FaceExpressionService service = (FaceExpressionService) client.getChannelServer().getServiceAccess(ServiceType.FACE_EXPRESSION);
|
||||
service.registerFaceExpression(map, this, emote);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5614,6 +5611,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
public void setGMLevel(int level) {
|
||||
this.gmLevel = Math.min(level, 6);
|
||||
this.gmLevel = Math.max(level, 0);
|
||||
|
||||
whiteChat = gmLevel >= 4; // thanks ozanrijen for suggesting default white chat
|
||||
}
|
||||
|
||||
public void closePartySearchInteractions() {
|
||||
@@ -6975,8 +6974,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
ret.gachaexp.set(rs.getInt("gachaexp"));
|
||||
ret.mapid = rs.getInt("map");
|
||||
ret.initialSpawnPoint = rs.getInt("spawnpoint");
|
||||
|
||||
ret.gmLevel = rs.getInt("gm");
|
||||
ret.setGMLevel(rs.getInt("gm"));
|
||||
ret.world = rs.getByte("world");
|
||||
ret.rank = rs.getInt("rank");
|
||||
ret.rankMove = rs.getInt("rankMove");
|
||||
@@ -7029,7 +7027,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
|
||||
ret.inventory[MapleInventoryType.EQUIPPED.ordinal()] = this.getInventory(MapleInventoryType.EQUIPPED);
|
||||
|
||||
ret.gmLevel = this.gmLevel();
|
||||
ret.setGMLevel(this.gmLevel());
|
||||
ret.world = this.getWorld();
|
||||
ret.rank = this.getRank();
|
||||
ret.rankMove = this.getRankMove();
|
||||
@@ -7091,7 +7089,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
ret.loadCharSkillPoints(rs.getString("sp").split(","));
|
||||
ret.meso.set(rs.getInt("meso"));
|
||||
ret.merchantmeso = rs.getInt("MerchantMesos");
|
||||
ret.gmLevel = rs.getInt("gm");
|
||||
ret.setGMLevel(rs.getInt("gm"));
|
||||
ret.skinColor = MapleSkinColor.getById(rs.getInt("skincolor"));
|
||||
ret.gender = rs.getInt("gender");
|
||||
ret.job = MapleJob.getById(rs.getInt("job"));
|
||||
@@ -7187,11 +7185,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
PreparedStatement ps2, ps3;
|
||||
ResultSet rs2, rs3;
|
||||
|
||||
ps3 = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid > -1");
|
||||
ps3 = con.prepareStatement("SELECT petid FROM inventoryitems WHERE characterid = ? AND petid IS NOT NULL");
|
||||
ps3.setInt(1, charid);
|
||||
rs3 = ps3.executeQuery();
|
||||
while(rs3.next()) {
|
||||
int petId = rs3.getInt("petid");
|
||||
if (rs3.wasNull()) {
|
||||
petId = -1;
|
||||
}
|
||||
|
||||
ps2 = con.prepareStatement("SELECT itemid FROM petignores WHERE petid = ?");
|
||||
ps2.setInt(1, petId);
|
||||
@@ -7371,7 +7372,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
ps.setInt(1, charid);
|
||||
rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
ret.skills.put(SkillFactory.getSkill(rs.getInt("skillid")), new SkillEntry(rs.getByte("skilllevel"), rs.getInt("masterlevel"), rs.getLong("expiration")));
|
||||
Skill pSkill = SkillFactory.getSkill(rs.getInt("skillid"));
|
||||
if(pSkill != null) // edit reported by shavit, thanks Zein for noticing an NPE here
|
||||
{
|
||||
ret.skills.put(pSkill, new SkillEntry(rs.getByte("skilllevel"), rs.getInt("masterlevel"), rs.getLong("expiration")));
|
||||
}
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
|
||||
@@ -126,7 +126,11 @@ public class Item implements Comparable<Item> {
|
||||
public int getPetId() {
|
||||
return petid;
|
||||
}
|
||||
|
||||
|
||||
public Integer getPetIdForDb() {
|
||||
return petid > -1 ? petid : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Item other) {
|
||||
if (this.id < other.getItemId()) {
|
||||
|
||||
@@ -173,7 +173,12 @@ public enum ItemFactory {
|
||||
if (mit.equals(MapleInventoryType.EQUIP) || mit.equals(MapleInventoryType.EQUIPPED)) {
|
||||
items.add(new Pair<Item, MapleInventoryType>(loadEquipFromResultSet(rs), mit));
|
||||
} else {
|
||||
Item item = new Item(rs.getInt("itemid"), (byte) rs.getInt("position"), (short) rs.getInt("quantity"), rs.getInt("petid"));
|
||||
int petid = rs.getInt("petid");
|
||||
if (rs.wasNull()) {
|
||||
petid = -1;
|
||||
}
|
||||
|
||||
Item item = new Item(rs.getInt("itemid"), (byte) rs.getInt("position"), (short) rs.getInt("quantity"), petid);
|
||||
item.setOwner(rs.getString("owner"));
|
||||
item.setExpiration(rs.getLong("expiration"));
|
||||
item.setGiftFrom(rs.getString("giftFrom"));
|
||||
@@ -229,7 +234,7 @@ public enum ItemFactory {
|
||||
ps.setInt(6, item.getPosition());
|
||||
ps.setInt(7, item.getQuantity());
|
||||
ps.setString(8, item.getOwner());
|
||||
ps.setInt(9, item.getPetId());
|
||||
ps.setObject(9, item.getPetIdForDb(), java.sql.Types.INTEGER);
|
||||
ps.setInt(10, item.getFlag());
|
||||
ps.setLong(11, item.getExpiration());
|
||||
ps.setString(12, item.getGiftFrom());
|
||||
@@ -329,7 +334,12 @@ public enum ItemFactory {
|
||||
items.add(new Pair<Item, MapleInventoryType>(loadEquipFromResultSet(rs), mit));
|
||||
} else {
|
||||
if(bundles > 0) {
|
||||
Item item = new Item(rs.getInt("itemid"), (byte) rs.getInt("position"), (short)(bundles * rs.getInt("quantity")), rs.getInt("petid"));
|
||||
int petid = rs.getInt("petid");
|
||||
if (rs.wasNull()) {
|
||||
petid = -1;
|
||||
}
|
||||
|
||||
Item item = new Item(rs.getInt("itemid"), (byte) rs.getInt("position"), (short)(bundles * rs.getInt("quantity")), petid);
|
||||
item.setOwner(rs.getString("owner"));
|
||||
item.setExpiration(rs.getLong("expiration"));
|
||||
item.setGiftFrom(rs.getString("giftFrom"));
|
||||
@@ -404,7 +414,7 @@ public enum ItemFactory {
|
||||
ps.setInt(6, item.getPosition());
|
||||
ps.setInt(7, item.getQuantity());
|
||||
ps.setString(8, item.getOwner());
|
||||
ps.setInt(9, item.getPetId());
|
||||
ps.setObject(9, item.getPetIdForDb(), java.sql.Types.INTEGER);
|
||||
ps.setInt(10, item.getFlag());
|
||||
ps.setLong(11, item.getExpiration());
|
||||
ps.setString(12, item.getGiftFrom());
|
||||
|
||||
@@ -98,75 +98,11 @@ public class MaplePet extends Item {
|
||||
}
|
||||
}
|
||||
|
||||
private static void unreferenceMissingPetsFromInventoryDb() {
|
||||
PreparedStatement ps = null;
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
|
||||
ps = con.prepareStatement("UPDATE inventoryitems SET petid = -1, expiration = 0 WHERE petid != -1 AND petid NOT IN (SELECT petid FROM pets)");
|
||||
ps.executeUpdate();
|
||||
|
||||
ps.close();
|
||||
con.close();
|
||||
} catch(SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if(ps != null && !ps.isClosed()) {
|
||||
ps.close();
|
||||
}
|
||||
if(con != null && !con.isClosed()) {
|
||||
con.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteMissingPetsFromDb() {
|
||||
PreparedStatement ps = null;
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
|
||||
ps = con.prepareStatement("DELETE FROM pets WHERE petid NOT IN (SELECT petid FROM inventoryitems WHERE petid != -1)");
|
||||
ps.executeUpdate();
|
||||
|
||||
ps.close();
|
||||
con.close();
|
||||
} catch(SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if(ps != null && !ps.isClosed()) {
|
||||
ps.close();
|
||||
}
|
||||
if(con != null && !con.isClosed()) {
|
||||
con.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearMissingPetsFromDb() {
|
||||
unreferenceMissingPetsFromInventoryDb();
|
||||
deleteMissingPetsFromDb();
|
||||
}
|
||||
|
||||
public static void deleteFromDb(MapleCharacter owner, int petid) {
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
|
||||
PreparedStatement ps = con.prepareStatement("DELETE FROM pets WHERE `petid` = ?");
|
||||
ps.setInt(1, petid);
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
|
||||
ps = con.prepareStatement("DELETE FROM petignores WHERE `petid` = ?"); // thanks Vcoc for detecting petignores remaining after deletion
|
||||
PreparedStatement ps = con.prepareStatement("DELETE FROM pets WHERE `petid` = ?"); // thanks Vcoc for detecting petignores remaining after deletion
|
||||
ps.setInt(1, petid);
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
|
||||
@@ -41,7 +41,10 @@ public class MapleCashidGenerator {
|
||||
ResultSet rs = ps.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
existentCashids.add(rs.getInt(1));
|
||||
int id = rs.getInt(1);
|
||||
if (!rs.wasNull()) {
|
||||
existentCashids.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
rs.close();
|
||||
|
||||
@@ -62,7 +62,7 @@ public class SpawnPetProcessor {
|
||||
long expiration = chr.getInventory(MapleInventoryType.CASH).getItem(slot).getExpiration();
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, petid, (short) 1, false, false);
|
||||
MapleInventoryManipulator.addById(c, evolveid, (short) 1, null, petId, expiration);
|
||||
MaplePet.deleteFromDb(chr, petid);
|
||||
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,6 @@ public class ServerConfig {
|
||||
public int MAX_AP;
|
||||
public int MAX_EVENT_LEVELS;
|
||||
public long BLOCK_NPC_RACE_CONDT;
|
||||
public long PET_LOOT_UPON_ATTACK;
|
||||
public int TOT_MOB_QUEST_REQUIREMENT;
|
||||
public int MOB_REACTOR_REFRESH_TIME;
|
||||
public int PARTY_SEARCH_REENTRY_LIMIT;
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
*/
|
||||
package net.server;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.Security;
|
||||
|
||||
@@ -50,7 +50,6 @@ import net.mina.MapleCodecFactory;
|
||||
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.Server;
|
||||
import net.server.channel.task.*;
|
||||
|
||||
import net.server.world.World;
|
||||
import net.server.world.MapleParty;
|
||||
@@ -77,7 +76,9 @@ import server.maps.MapleMiniDungeon;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import client.MapleCharacter;
|
||||
import client.status.MonsterStatusEffect;
|
||||
import net.server.channel.services.ServiceType;
|
||||
import net.server.channel.services.ServicesManager;
|
||||
import net.server.channel.services.task.BaseService;
|
||||
import server.maps.MapleMiniDungeonInfo;
|
||||
|
||||
public final class Channel {
|
||||
@@ -89,13 +90,7 @@ public final class Channel {
|
||||
private String ip, serverMessage;
|
||||
private MapleMapManager mapManager;
|
||||
private EventScriptManager eventSM;
|
||||
private MobStatusScheduler mobStatusSchedulers[] = new MobStatusScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
private MobAnimationScheduler mobAnimationSchedulers[] = new MobAnimationScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
private MobClearSkillScheduler mobClearSkillSchedulers[] = new MobClearSkillScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
private MobMistScheduler mobMistSchedulers[] = new MobMistScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
private FaceExpressionScheduler faceExpressionSchedulers[] = new FaceExpressionScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
private EventScheduler eventSchedulers[] = new EventScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
private OverallScheduler channelSchedulers[] = new OverallScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
private ServicesManager services = new ServicesManager();
|
||||
private Map<Integer, MapleHiredMerchant> hiredMerchants = new HashMap<>();
|
||||
private final Map<Integer, Integer> storedVars = new HashMap<>();
|
||||
private Set<Integer> playersAway = new HashSet<>();
|
||||
@@ -173,17 +168,7 @@ public final class Channel {
|
||||
dojoTask[i] = null;
|
||||
}
|
||||
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
faceLock[i] = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_FACEEXPRS, true);
|
||||
|
||||
mobStatusSchedulers[i] = new MobStatusScheduler();
|
||||
mobAnimationSchedulers[i] = new MobAnimationScheduler();
|
||||
mobClearSkillSchedulers[i] = new MobClearSkillScheduler();
|
||||
mobMistSchedulers[i] = new MobMistScheduler();
|
||||
faceExpressionSchedulers[i] = new FaceExpressionScheduler(faceLock[i]);
|
||||
eventSchedulers[i] = new EventScheduler();
|
||||
channelSchedulers[i] = new OverallScheduler();
|
||||
}
|
||||
services = new ServicesManager();
|
||||
|
||||
System.out.println(" Channel " + getId() + ": Listening on port " + port);
|
||||
} catch (Exception e) {
|
||||
@@ -191,15 +176,23 @@ public final class Channel {
|
||||
}
|
||||
}
|
||||
|
||||
public void reloadEventScriptManager(){
|
||||
public synchronized void reloadEventScriptManager(){
|
||||
if (finishedShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
eventSM.cancel();
|
||||
eventSM = null;
|
||||
eventSM = new EventScriptManager(this, getEvents());
|
||||
eventSM.init();
|
||||
}
|
||||
|
||||
public final void shutdown() {
|
||||
public final synchronized void shutdown() {
|
||||
try {
|
||||
if (finishedShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Shutting down Channel " + channel + " on World " + world);
|
||||
|
||||
closeAllMerchants();
|
||||
@@ -227,6 +220,10 @@ public final class Channel {
|
||||
}
|
||||
}
|
||||
|
||||
private void closeChannelServices() {
|
||||
services.shutdown();
|
||||
}
|
||||
|
||||
private void closeChannelSchedules() {
|
||||
for(int i = 0; i < 20; i++) {
|
||||
if(dojoTask[i] != null) {
|
||||
@@ -234,44 +231,8 @@ public final class Channel {
|
||||
dojoTask[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
if(mobStatusSchedulers[i] != null) {
|
||||
mobStatusSchedulers[i].dispose();
|
||||
mobStatusSchedulers[i] = null;
|
||||
}
|
||||
|
||||
if(mobAnimationSchedulers[i] != null) {
|
||||
mobAnimationSchedulers[i].dispose();
|
||||
mobAnimationSchedulers[i] = null;
|
||||
}
|
||||
|
||||
if(mobClearSkillSchedulers[i] != null) {
|
||||
mobClearSkillSchedulers[i].dispose();
|
||||
mobClearSkillSchedulers[i] = null;
|
||||
}
|
||||
|
||||
if(mobMistSchedulers[i] != null) {
|
||||
mobMistSchedulers[i].dispose();
|
||||
mobMistSchedulers[i] = null;
|
||||
}
|
||||
|
||||
if(faceExpressionSchedulers[i] != null) {
|
||||
faceExpressionSchedulers[i].dispose();
|
||||
faceExpressionSchedulers[i] = null;
|
||||
}
|
||||
|
||||
if(eventSchedulers[i] != null) {
|
||||
eventSchedulers[i].dispose();
|
||||
eventSchedulers[i] = null;
|
||||
}
|
||||
|
||||
if(channelSchedulers[i] != null) {
|
||||
channelSchedulers[i].dispose();
|
||||
channelSchedulers[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
closeChannelServices();
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
@@ -315,7 +276,11 @@ public final class Channel {
|
||||
public MapleMapManager getMapFactory() {
|
||||
return mapManager;
|
||||
}
|
||||
|
||||
|
||||
public BaseService getServiceAccess(ServiceType sv) {
|
||||
return services.getAccess(sv).getService();
|
||||
}
|
||||
|
||||
public int getWorld() {
|
||||
return world;
|
||||
}
|
||||
@@ -1030,84 +995,6 @@ public final class Channel {
|
||||
return !usedMC.contains(getMonsterCarnivalRoom(cpq1, field));
|
||||
}
|
||||
|
||||
private static int getChannelSchedulerIndex(int mapid) {
|
||||
int section = 1000000000 / YamlConfig.config.server.CHANNEL_LOCKS;
|
||||
return mapid / section;
|
||||
}
|
||||
|
||||
public void registerMobStatus(int mapid, MonsterStatusEffect mse, Runnable cancelAction, long duration) {
|
||||
registerMobStatus(mapid, mse, cancelAction, duration, null, -1);
|
||||
}
|
||||
|
||||
public void registerMobStatus(int mapid, MonsterStatusEffect mse, Runnable cancelAction, long duration, Runnable overtimeAction, int overtimeDelay) {
|
||||
mobStatusSchedulers[getChannelSchedulerIndex(mapid)].registerMobStatus(mse, cancelAction, duration, overtimeAction, overtimeDelay);
|
||||
}
|
||||
|
||||
public void interruptMobStatus(int mapid, MonsterStatusEffect mse) {
|
||||
mobStatusSchedulers[getChannelSchedulerIndex(mapid)].interruptMobStatus(mse);
|
||||
}
|
||||
|
||||
public boolean registerMobOnAnimationEffect(int mapid, int mobHash, long delay) {
|
||||
return mobAnimationSchedulers[getChannelSchedulerIndex(mapid)].registerAnimationMode(mobHash, delay);
|
||||
}
|
||||
|
||||
public void registerMobClearSkillAction(int mapid, Runnable runAction, long delay) {
|
||||
mobClearSkillSchedulers[getChannelSchedulerIndex(mapid)].registerClearSkillAction(runAction, delay);
|
||||
}
|
||||
|
||||
public void registerMobMistCancelAction(int mapid, Runnable runAction, long delay) {
|
||||
mobMistSchedulers[getChannelSchedulerIndex(mapid)].registerMistCancelAction(runAction, delay);
|
||||
}
|
||||
|
||||
public void registerEventAction(int mapid, Runnable runAction, long delay) {
|
||||
eventSchedulers[getChannelSchedulerIndex(mapid)].registerDelayedAction(runAction, delay);
|
||||
}
|
||||
|
||||
public void registerOverallAction(int mapid, Runnable runAction, long delay) {
|
||||
channelSchedulers[getChannelSchedulerIndex(mapid)].registerDelayedAction(runAction, delay);
|
||||
}
|
||||
|
||||
public void forceRunOverallAction(int mapid, Runnable runAction) {
|
||||
channelSchedulers[getChannelSchedulerIndex(mapid)].forceRunDelayedAction(runAction);
|
||||
}
|
||||
|
||||
public void registerFaceExpression(final MapleMap map, final MapleCharacter chr, int emote) {
|
||||
int lockid = getChannelSchedulerIndex(map.getId());
|
||||
|
||||
Runnable cancelAction = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(chr.isLoggedinWorld()) {
|
||||
map.broadcastMessage(chr, MaplePacketCreator.facialExpression(chr, 0), false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
faceLock[lockid].lock();
|
||||
try {
|
||||
if(!chr.isLoggedinWorld()) {
|
||||
return;
|
||||
}
|
||||
|
||||
faceExpressionSchedulers[lockid].registerFaceExpression(chr.getId(), cancelAction);
|
||||
} finally {
|
||||
faceLock[lockid].unlock();
|
||||
}
|
||||
|
||||
map.broadcastMessage(chr, MaplePacketCreator.facialExpression(chr, emote), false);
|
||||
}
|
||||
|
||||
public void unregisterFaceExpression(int mapid, MapleCharacter chr) {
|
||||
int lockid = getChannelSchedulerIndex(mapid);
|
||||
|
||||
faceLock[lockid].lock();
|
||||
try {
|
||||
faceExpressionSchedulers[lockid].unregisterFaceExpression(chr.getId());
|
||||
} finally {
|
||||
faceLock[lockid].unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void debugMarriageStatus() {
|
||||
System.out.println(" ----- WORLD DATA -----");
|
||||
getWorldServer().debugMarriageStatus();
|
||||
|
||||
@@ -656,7 +656,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
|
||||
// Find the base damage to base futher calculations on.
|
||||
// Several skills have their own formula in this section.
|
||||
long calcDmgMax = 0;
|
||||
long calcDmgMax;
|
||||
|
||||
if(magic && ret.skill != 0) { // thanks onechord for noticing a few false positives stemming from maxdmg as 0
|
||||
calcDmgMax = (long) (Math.ceil((chr.getTotalMagic() * Math.ceil(chr.getTotalMagic() / 1000.0) + chr.getTotalMagic()) / 30.0) + Math.ceil(chr.getTotalInt() / 200.0));
|
||||
@@ -846,7 +846,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
}
|
||||
} else if (ret.skill == Aran.BODY_PRESSURE) {
|
||||
if (monster != null) {
|
||||
int bodyPressureDmg = monster.getMaxHp() * SkillFactory.getSkill(Aran.BODY_PRESSURE).getEffect(ret.skilllevel).getDamage() / 100;
|
||||
int bodyPressureDmg = (int) Math.ceil(monster.getMaxHp() * SkillFactory.getSkill(Aran.BODY_PRESSURE).getEffect(ret.skilllevel).getDamage() / 100.0);
|
||||
if (bodyPressureDmg > calcDmgMax) {
|
||||
calcDmgMax = bodyPressureDmg;
|
||||
}
|
||||
|
||||
@@ -26,10 +26,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import config.YamlConfig;
|
||||
import server.MapleStatEffect;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleBuffStat;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
@@ -37,7 +33,6 @@ import client.MapleJob;
|
||||
import client.Skill;
|
||||
import client.SkillFactory;
|
||||
import constants.game.GameConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import constants.skills.Crusader;
|
||||
import constants.skills.DawnWarrior;
|
||||
import constants.skills.DragonKnight;
|
||||
@@ -45,13 +40,16 @@ import constants.skills.Hero;
|
||||
import constants.skills.NightWalker;
|
||||
import constants.skills.Rogue;
|
||||
import constants.skills.WindArcher;
|
||||
import server.MapleStatEffect;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
public final class CloseRangeDamageHandler extends AbstractDealDamageHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
//chr.setPetLootCd(currentServerTime());
|
||||
|
||||
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
|
||||
if(timeElapsed < 300) {
|
||||
|
||||
@@ -21,25 +21,24 @@
|
||||
*/
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import config.YamlConfig;
|
||||
import server.MapleStatEffect;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleBuffStat;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.Skill;
|
||||
import client.SkillFactory;
|
||||
import config.YamlConfig;
|
||||
import constants.skills.Bishop;
|
||||
import constants.skills.Evan;
|
||||
import constants.skills.FPArchMage;
|
||||
import constants.skills.ILArchMage;
|
||||
import server.MapleStatEffect;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
public final class MagicDamageHandler extends AbstractDealDamageHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
//chr.setPetLootCd(currentServerTime());
|
||||
|
||||
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
|
||||
if(timeElapsed < 300) {
|
||||
|
||||
@@ -55,6 +55,10 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
MapleCharacter player = c.getPlayer();
|
||||
MapleMap map = player.getMap();
|
||||
|
||||
if (player.isChangingMaps()) { // thanks Lame for noticing mob movement shuffle (mob OID on different maps) happening on map transitions
|
||||
return;
|
||||
}
|
||||
|
||||
int objectid = slea.readInt();
|
||||
short moveid = slea.readShort();
|
||||
MapleMapObject mmo = map.getMapObject(objectid);
|
||||
|
||||
@@ -59,16 +59,19 @@ public final class NPCTalkHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
if(npc.getId() >= 9100100 && npc.getId() <= 9100200) {
|
||||
// Custom handling for gachapon scripts to reduce the amount of scripts needed.
|
||||
|
||||
// Custom handling to reduce the amount of scripts needed.
|
||||
if (npc.getId() >= 9100100 && npc.getId() <= 9100200) {
|
||||
NPCScriptManager.getInstance().start(c, npc.getId(), "gachapon", null);
|
||||
} else if (npc.getName().endsWith("Maple TV")) {
|
||||
NPCScriptManager.getInstance().start(c, npc.getId(), "mapleTV", null);
|
||||
} else {
|
||||
boolean hasNpcScript = NPCScriptManager.getInstance().start(c, npc.getId(), oid, null);
|
||||
if (!hasNpcScript) {
|
||||
if (!npc.hasShop()) {
|
||||
FilePrinter.printError(FilePrinter.NPC_UNCODED, "NPC " + npc.getName() + "(" + npc.getId() + ") is not coded.");
|
||||
return;
|
||||
} else if(c.getPlayer().getShop() != null) {
|
||||
} else if (c.getPlayer().getShop() != null) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,13 +26,11 @@ import java.util.Set;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.inventory.MaplePet;
|
||||
import config.YamlConfig;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import server.maps.MapleMapItem;
|
||||
import server.maps.MapleMapObject;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import constants.net.ServerConstants;
|
||||
|
||||
/**
|
||||
* @author TheRamon
|
||||
@@ -42,10 +40,6 @@ public final class PetLootHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
if(currentServerTime() - chr.getPetLootCd() < YamlConfig.config.server.PET_LOOT_UPON_ATTACK) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
int petIndex = chr.getPetIndex(slea.readInt());
|
||||
MaplePet pet = chr.getPet(petIndex);
|
||||
|
||||
@@ -21,13 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import config.YamlConfig;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MapleStatEffect;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Randomizer;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleBuffStat;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
@@ -37,8 +30,9 @@ import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MapleWeaponType;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import config.YamlConfig;
|
||||
import constants.inventory.ItemConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import constants.skills.Aran;
|
||||
import constants.skills.Buccaneer;
|
||||
import constants.skills.NightLord;
|
||||
@@ -46,13 +40,18 @@ import constants.skills.NightWalker;
|
||||
import constants.skills.Shadower;
|
||||
import constants.skills.ThunderBreaker;
|
||||
import constants.skills.WindArcher;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MapleStatEffect;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Randomizer;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
|
||||
public final class RangedAttackHandler extends AbstractDealDamageHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
//chr.setPetLootCd(currentServerTime());
|
||||
|
||||
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
|
||||
if(timeElapsed < 300) {
|
||||
|
||||
@@ -213,7 +213,7 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
|
||||
map.broadcastMessage(chr, MaplePacketCreator.damageMonster(oid, bouncedamage), false, true);
|
||||
attacker.aggroMonsterDamage(chr, bouncedamage);
|
||||
}
|
||||
MapleStatEffect bPressure = chr.getBuffEffect(MapleBuffStat.COMBO_BARRIER);
|
||||
MapleStatEffect bPressure = chr.getBuffEffect(MapleBuffStat.BODY_PRESSURE);
|
||||
if (bPressure != null) {
|
||||
Skill skill = SkillFactory.getSkill(Aran.BODY_PRESSURE);
|
||||
if (!attacker.alreadyBuffedStats().contains(MonsterStatus.NEUTRALISE)) {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.task;
|
||||
package net.server.channel.services;
|
||||
|
||||
import config.YamlConfig;
|
||||
import java.util.Collections;
|
||||
@@ -17,7 +17,7 @@
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.task;
|
||||
package net.server.channel.services;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
@@ -17,24 +17,36 @@
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.task;
|
||||
package net.server.channel.services;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.channel.services.task.BaseService;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class OverallScheduler extends BaseScheduler {
|
||||
public OverallScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_OVERALL);
|
||||
public class Service <T extends BaseService> {
|
||||
|
||||
private Class<T> cls;
|
||||
private BaseService service;
|
||||
|
||||
public Service(Class<T> s) {
|
||||
try {
|
||||
cls = s;
|
||||
service = (BaseService) cls.getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerDelayedAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
public T getService() {
|
||||
return cls.cast(service);
|
||||
}
|
||||
|
||||
public void forceRunDelayedAction(Runnable runAction) {
|
||||
interruptEntry(runAction);
|
||||
public void dispose() {
|
||||
service.dispose();
|
||||
service = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
@@ -17,20 +17,32 @@
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.task;
|
||||
package net.server.channel.services;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.channel.services.task.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobMistScheduler extends BaseScheduler {
|
||||
public MobMistScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBMIST);
|
||||
public enum ServiceType {
|
||||
|
||||
MOB_STATUS(MobStatusService.class),
|
||||
MOB_ANIMATION(MobAnimationService.class),
|
||||
MOB_CLEAR_SKILL(MobClearSkillService.class),
|
||||
MOB_MIST(MobMistService.class),
|
||||
FACE_EXPRESSION(FaceExpressionService.class),
|
||||
EVENT(EventService.class),
|
||||
OVERALL(OverallService.class);
|
||||
|
||||
private Class<? extends BaseService> s;
|
||||
|
||||
private ServiceType(Class<? extends BaseService> service) {
|
||||
s = service;
|
||||
}
|
||||
|
||||
public void registerMistCancelAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
public Service createService() {
|
||||
return new Service(s);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
@@ -17,26 +17,34 @@
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.task;
|
||||
|
||||
import java.util.Collections;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
package net.server.channel.services;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class FaceExpressionScheduler extends BaseScheduler {
|
||||
public FaceExpressionScheduler(final MonitoredReentrantLock channelFaceLock) {
|
||||
super(MonitoredLockType.CHANNEL_FACESCHDL, Collections.singletonList(channelFaceLock));
|
||||
public class ServicesManager {
|
||||
|
||||
private Service[] services;
|
||||
|
||||
public ServicesManager() {
|
||||
ServiceType[] serviceTypes = ServiceType.values();
|
||||
|
||||
services = new Service[serviceTypes.length];
|
||||
for (ServiceType type : serviceTypes) {
|
||||
services[type.ordinal()] = type.createService();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerFaceExpression(Integer characterId, Runnable runAction) {
|
||||
registerEntry(characterId, runAction, 5000);
|
||||
public Service getAccess(ServiceType s) {
|
||||
return services[s.ordinal()];
|
||||
}
|
||||
|
||||
public void unregisterFaceExpression(Integer characterId) {
|
||||
interruptEntry(characterId);
|
||||
public void shutdown() {
|
||||
for (int i = 0; i < ServiceType.values().length; i++) {
|
||||
services[i].dispose();
|
||||
}
|
||||
services = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
@@ -17,20 +17,21 @@
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.task;
|
||||
package net.server.channel.services.task;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import config.YamlConfig;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class EventScheduler extends BaseScheduler {
|
||||
public EventScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_EVENTS);
|
||||
public abstract class BaseService {
|
||||
|
||||
protected static int getChannelSchedulerIndex(int mapid) {
|
||||
int section = 1000000000 / YamlConfig.config.server.CHANNEL_LOCKS;
|
||||
return mapid / section;
|
||||
}
|
||||
|
||||
public void registerDelayedAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
public abstract void dispose();
|
||||
|
||||
}
|
||||
65
src/net/server/channel/services/task/EventService.java
Normal file
65
src/net/server/channel/services/task/EventService.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.services.task;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.channel.services.BaseScheduler;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class EventService extends BaseService {
|
||||
|
||||
private EventScheduler eventSchedulers[] = new EventScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
|
||||
public EventService() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
eventSchedulers[i] = new EventScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
if(eventSchedulers[i] != null) {
|
||||
eventSchedulers[i].dispose();
|
||||
eventSchedulers[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerEventAction(int mapid, Runnable runAction, long delay) {
|
||||
eventSchedulers[getChannelSchedulerIndex(mapid)].registerDelayedAction(runAction, delay);
|
||||
}
|
||||
|
||||
private class EventScheduler extends BaseScheduler {
|
||||
|
||||
public EventScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_EVENTS);
|
||||
}
|
||||
|
||||
public void registerDelayedAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
128
src/net/server/channel/services/task/FaceExpressionService.java
Normal file
128
src/net/server/channel/services/task/FaceExpressionService.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.services.task;
|
||||
|
||||
import client.MapleCharacter;
|
||||
import config.YamlConfig;
|
||||
import java.util.Collections;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.channel.services.BaseScheduler;
|
||||
import server.maps.MapleMap;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class FaceExpressionService extends BaseService {
|
||||
|
||||
private FaceExpressionScheduler faceExpressionSchedulers[] = new FaceExpressionScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
private MonitoredReentrantLock faceLock[] = new MonitoredReentrantLock[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
|
||||
public FaceExpressionService() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
faceLock[i] = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_FACEEXPRS, true);
|
||||
faceExpressionSchedulers[i] = new FaceExpressionScheduler(faceLock[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
faceLock[i] = faceLock[i].dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
if(faceExpressionSchedulers[i] != null) {
|
||||
faceExpressionSchedulers[i].dispose();
|
||||
faceExpressionSchedulers[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
public void registerFaceExpression(final MapleMap map, final MapleCharacter chr, int emote) {
|
||||
int lockid = getChannelSchedulerIndex(map.getId());
|
||||
|
||||
Runnable cancelAction = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(chr.isLoggedinWorld()) {
|
||||
map.broadcastMessage(chr, MaplePacketCreator.facialExpression(chr, 0), false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
faceLock[lockid].lock();
|
||||
try {
|
||||
if(!chr.isLoggedinWorld()) {
|
||||
return;
|
||||
}
|
||||
|
||||
faceExpressionSchedulers[lockid].registerFaceExpression(chr.getId(), cancelAction);
|
||||
} finally {
|
||||
faceLock[lockid].unlock();
|
||||
}
|
||||
|
||||
map.broadcastMessage(chr, MaplePacketCreator.facialExpression(chr, emote), false);
|
||||
}
|
||||
|
||||
public void unregisterFaceExpression(int mapid, MapleCharacter chr) {
|
||||
int lockid = getChannelSchedulerIndex(mapid);
|
||||
|
||||
faceLock[lockid].lock();
|
||||
try {
|
||||
faceExpressionSchedulers[lockid].unregisterFaceExpression(chr.getId());
|
||||
} finally {
|
||||
faceLock[lockid].unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private class FaceExpressionScheduler extends BaseScheduler {
|
||||
|
||||
public FaceExpressionScheduler(final MonitoredReentrantLock channelFaceLock) {
|
||||
super(MonitoredLockType.CHANNEL_FACESCHDL, Collections.singletonList(channelFaceLock));
|
||||
}
|
||||
|
||||
public void registerFaceExpression(Integer characterId, Runnable runAction) {
|
||||
registerEntry(characterId, runAction, 5000);
|
||||
}
|
||||
|
||||
public void unregisterFaceExpression(Integer characterId) {
|
||||
interruptEntry(characterId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
125
src/net/server/channel/services/task/MobAnimationService.java
Normal file
125
src/net/server/channel/services/task/MobAnimationService.java
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.services.task;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.channel.services.BaseScheduler;
|
||||
import net.server.channel.services.SchedulerListener;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobAnimationService extends BaseService {
|
||||
|
||||
private MobAnimationScheduler mobAnimationSchedulers[] = new MobAnimationScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
|
||||
public MobAnimationService() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
mobAnimationSchedulers[i] = new MobAnimationScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
if(mobAnimationSchedulers[i] != null) {
|
||||
mobAnimationSchedulers[i].dispose();
|
||||
mobAnimationSchedulers[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean registerMobOnAnimationEffect(int mapid, int mobHash, long delay) {
|
||||
return mobAnimationSchedulers[getChannelSchedulerIndex(mapid)].registerAnimationMode(mobHash, delay);
|
||||
}
|
||||
|
||||
private static Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {} // do nothing
|
||||
};
|
||||
|
||||
private class MobAnimationScheduler extends BaseScheduler {
|
||||
Set<Integer> onAnimationMobs = new HashSet<>(1000);
|
||||
private MonitoredReentrantLock animationLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_MOBANIMAT, true);
|
||||
|
||||
public MobAnimationScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBACTION);
|
||||
|
||||
super.addListener(new SchedulerListener() {
|
||||
@Override
|
||||
public void removedScheduledEntries(List<Object> toRemove, boolean update) {
|
||||
animationLock.lock();
|
||||
try {
|
||||
for(Object hashObj : toRemove) {
|
||||
Integer mobHash = (Integer) hashObj;
|
||||
onAnimationMobs.remove(mobHash);
|
||||
}
|
||||
} finally {
|
||||
animationLock.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean registerAnimationMode(Integer mobHash, long animationTime) {
|
||||
animationLock.lock();
|
||||
try {
|
||||
if(onAnimationMobs.contains(mobHash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
registerEntry(mobHash, r, animationTime);
|
||||
onAnimationMobs.add(mobHash);
|
||||
return true;
|
||||
} finally {
|
||||
animationLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeLocks();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
animationLock = animationLock.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.services.task;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.channel.services.BaseScheduler;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobClearSkillService extends BaseService {
|
||||
|
||||
private MobClearSkillScheduler mobClearSkillSchedulers[] = new MobClearSkillScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
|
||||
public MobClearSkillService() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
mobClearSkillSchedulers[i] = new MobClearSkillScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
if(mobClearSkillSchedulers[i] != null) {
|
||||
mobClearSkillSchedulers[i].dispose();
|
||||
mobClearSkillSchedulers[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerMobClearSkillAction(int mapid, Runnable runAction, long delay) {
|
||||
mobClearSkillSchedulers[getChannelSchedulerIndex(mapid)].registerClearSkillAction(runAction, delay);
|
||||
}
|
||||
|
||||
private class MobClearSkillScheduler extends BaseScheduler {
|
||||
|
||||
public MobClearSkillScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBSKILL);
|
||||
}
|
||||
|
||||
public void registerClearSkillAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
65
src/net/server/channel/services/task/MobMistService.java
Normal file
65
src/net/server/channel/services/task/MobMistService.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.services.task;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.channel.services.BaseScheduler;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobMistService extends BaseService {
|
||||
|
||||
private MobMistScheduler mobMistSchedulers[] = new MobMistScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
|
||||
public MobMistService() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
mobMistSchedulers[i] = new MobMistScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
if(mobMistSchedulers[i] != null) {
|
||||
mobMistSchedulers[i].dispose();
|
||||
mobMistSchedulers[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerMobMistCancelAction(int mapid, Runnable runAction, long delay) {
|
||||
mobMistSchedulers[getChannelSchedulerIndex(mapid)].registerMistCancelAction(runAction, delay);
|
||||
}
|
||||
|
||||
private class MobMistScheduler extends BaseScheduler {
|
||||
|
||||
public MobMistScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBMIST);
|
||||
}
|
||||
|
||||
public void registerMistCancelAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
168
src/net/server/channel/services/task/MobStatusService.java
Normal file
168
src/net/server/channel/services/task/MobStatusService.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.services.task;
|
||||
|
||||
import client.status.MonsterStatusEffect;
|
||||
import config.YamlConfig;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.channel.services.BaseScheduler;
|
||||
import net.server.channel.services.SchedulerListener;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobStatusService extends BaseService {
|
||||
|
||||
private MobStatusScheduler mobStatusSchedulers[] = new MobStatusScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
|
||||
public MobStatusService() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
mobStatusSchedulers[i] = new MobStatusScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
if(mobStatusSchedulers[i] != null) {
|
||||
mobStatusSchedulers[i].dispose();
|
||||
mobStatusSchedulers[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerMobStatus(int mapid, MonsterStatusEffect mse, Runnable cancelAction, long duration) {
|
||||
registerMobStatus(mapid, mse, cancelAction, duration, null, -1);
|
||||
}
|
||||
|
||||
public void registerMobStatus(int mapid, MonsterStatusEffect mse, Runnable cancelAction, long duration, Runnable overtimeAction, int overtimeDelay) {
|
||||
mobStatusSchedulers[getChannelSchedulerIndex(mapid)].registerMobStatus(mse, cancelAction, duration, overtimeAction, overtimeDelay);
|
||||
}
|
||||
|
||||
public void interruptMobStatus(int mapid, MonsterStatusEffect mse) {
|
||||
mobStatusSchedulers[getChannelSchedulerIndex(mapid)].interruptMobStatus(mse);
|
||||
}
|
||||
|
||||
private class MobStatusScheduler extends BaseScheduler {
|
||||
|
||||
private Map<MonsterStatusEffect, MobStatusOvertimeEntry> registeredMobStatusOvertime = new HashMap<>();
|
||||
private MonitoredReentrantLock overtimeStatusLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_OVTSTATUS, true);
|
||||
|
||||
private class MobStatusOvertimeEntry {
|
||||
private int procCount;
|
||||
private int procLimit;
|
||||
private Runnable r;
|
||||
|
||||
protected MobStatusOvertimeEntry(int delay, Runnable run) {
|
||||
procCount = 0;
|
||||
procLimit = (int)Math.ceil((float) delay / YamlConfig.config.server.MOB_STATUS_MONITOR_PROC);
|
||||
r = run;
|
||||
}
|
||||
|
||||
protected void update(List<Runnable> toRun) {
|
||||
procCount++;
|
||||
if(procCount >= procLimit) {
|
||||
procCount = 0;
|
||||
toRun.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MobStatusScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBSTATUS);
|
||||
|
||||
super.addListener(new SchedulerListener() {
|
||||
@Override
|
||||
public void removedScheduledEntries(List<Object> toRemove, boolean update) {
|
||||
List<Runnable> toRun = new ArrayList<>();
|
||||
|
||||
overtimeStatusLock.lock();
|
||||
try {
|
||||
for(Object mseo : toRemove) {
|
||||
MonsterStatusEffect mse = (MonsterStatusEffect) mseo;
|
||||
registeredMobStatusOvertime.remove(mse);
|
||||
}
|
||||
|
||||
if(update) {
|
||||
// it's probably ok to use one thread for both management & overtime actions
|
||||
List<MobStatusOvertimeEntry> mdoeList = new ArrayList<>(registeredMobStatusOvertime.values());
|
||||
for(MobStatusOvertimeEntry mdoe : mdoeList) {
|
||||
mdoe.update(toRun);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
overtimeStatusLock.unlock();
|
||||
}
|
||||
|
||||
for(Runnable r : toRun) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void registerMobStatus(MonsterStatusEffect mse, Runnable cancelStatus, long duration, Runnable overtimeStatus, int overtimeDelay) {
|
||||
if(overtimeStatus != null) {
|
||||
MobStatusOvertimeEntry mdoe = new MobStatusOvertimeEntry(overtimeDelay, overtimeStatus);
|
||||
|
||||
overtimeStatusLock.lock();
|
||||
try {
|
||||
registeredMobStatusOvertime.put(mse, mdoe);
|
||||
} finally {
|
||||
overtimeStatusLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
registerEntry(mse, cancelStatus, duration);
|
||||
}
|
||||
|
||||
public void interruptMobStatus(MonsterStatusEffect mse) {
|
||||
interruptEntry(mse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeLocks();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
overtimeStatusLock = overtimeStatusLock.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
74
src/net/server/channel/services/task/OverallService.java
Normal file
74
src/net/server/channel/services/task/OverallService.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.services.task;
|
||||
|
||||
import config.YamlConfig;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.channel.services.BaseScheduler;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class OverallService extends BaseService { // thanks Alex for suggesting a refactor over the several channel schedulers unnecessarily populating the Channel class
|
||||
|
||||
private OverallScheduler channelSchedulers[] = new OverallScheduler[YamlConfig.config.server.CHANNEL_LOCKS];
|
||||
|
||||
public OverallService() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
channelSchedulers[i] = new OverallScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
for(int i = 0; i < YamlConfig.config.server.CHANNEL_LOCKS; i++) {
|
||||
if(channelSchedulers[i] != null) {
|
||||
channelSchedulers[i].dispose();
|
||||
channelSchedulers[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerOverallAction(int mapid, Runnable runAction, long delay) {
|
||||
channelSchedulers[getChannelSchedulerIndex(mapid)].registerDelayedAction(runAction, delay);
|
||||
}
|
||||
|
||||
public void forceRunOverallAction(int mapid, Runnable runAction) {
|
||||
channelSchedulers[getChannelSchedulerIndex(mapid)].forceRunDelayedAction(runAction);
|
||||
}
|
||||
|
||||
|
||||
public class OverallScheduler extends BaseScheduler {
|
||||
|
||||
public OverallScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_OVERALL);
|
||||
}
|
||||
|
||||
public void registerDelayedAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
|
||||
public void forceRunDelayedAction(Runnable runAction) {
|
||||
interruptEntry(runAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.task;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobAnimationScheduler extends BaseScheduler {
|
||||
Set<Integer> onAnimationMobs = new HashSet<>(1000);
|
||||
private MonitoredReentrantLock animationLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_MOBANIMAT, true);
|
||||
|
||||
private static Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {} // do nothing
|
||||
};
|
||||
|
||||
public MobAnimationScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBACTION);
|
||||
|
||||
super.addListener(new SchedulerListener() {
|
||||
@Override
|
||||
public void removedScheduledEntries(List<Object> toRemove, boolean update) {
|
||||
animationLock.lock();
|
||||
try {
|
||||
for(Object hashObj : toRemove) {
|
||||
Integer mobHash = (Integer) hashObj;
|
||||
onAnimationMobs.remove(mobHash);
|
||||
}
|
||||
} finally {
|
||||
animationLock.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean registerAnimationMode(Integer mobHash, long animationTime) {
|
||||
animationLock.lock();
|
||||
try {
|
||||
if(onAnimationMobs.contains(mobHash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
registerEntry(mobHash, r, animationTime);
|
||||
onAnimationMobs.add(mobHash);
|
||||
return true;
|
||||
} finally {
|
||||
animationLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeLocks();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
animationLock = animationLock.dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.task;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobClearSkillScheduler extends BaseScheduler {
|
||||
public MobClearSkillScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBSKILL);
|
||||
}
|
||||
|
||||
public void registerClearSkillAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.task;
|
||||
|
||||
import client.status.MonsterStatusEffect;
|
||||
import config.YamlConfig;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobStatusScheduler extends BaseScheduler {
|
||||
private Map<MonsterStatusEffect, MobStatusOvertimeEntry> registeredMobStatusOvertime = new HashMap<>();
|
||||
private MonitoredReentrantLock overtimeStatusLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHANNEL_OVTSTATUS, true);
|
||||
|
||||
private class MobStatusOvertimeEntry {
|
||||
private int procCount;
|
||||
private int procLimit;
|
||||
private Runnable r;
|
||||
|
||||
protected MobStatusOvertimeEntry(int delay, Runnable run) {
|
||||
procCount = 0;
|
||||
procLimit = (int)Math.ceil((float) delay / YamlConfig.config.server.MOB_STATUS_MONITOR_PROC);
|
||||
r = run;
|
||||
}
|
||||
|
||||
protected void update(List<Runnable> toRun) {
|
||||
procCount++;
|
||||
if(procCount >= procLimit) {
|
||||
procCount = 0;
|
||||
toRun.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MobStatusScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBSTATUS);
|
||||
|
||||
super.addListener(new SchedulerListener() {
|
||||
@Override
|
||||
public void removedScheduledEntries(List<Object> toRemove, boolean update) {
|
||||
List<Runnable> toRun = new ArrayList<>();
|
||||
|
||||
overtimeStatusLock.lock();
|
||||
try {
|
||||
for(Object mseo : toRemove) {
|
||||
MonsterStatusEffect mse = (MonsterStatusEffect) mseo;
|
||||
registeredMobStatusOvertime.remove(mse);
|
||||
}
|
||||
|
||||
if(update) {
|
||||
// it's probably ok to use one thread for both management & overtime actions
|
||||
List<MobStatusOvertimeEntry> mdoeList = new ArrayList<>(registeredMobStatusOvertime.values());
|
||||
for(MobStatusOvertimeEntry mdoe : mdoeList) {
|
||||
mdoe.update(toRun);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
overtimeStatusLock.unlock();
|
||||
}
|
||||
|
||||
for(Runnable r : toRun) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void registerMobStatus(MonsterStatusEffect mse, Runnable cancelStatus, long duration, Runnable overtimeStatus, int overtimeDelay) {
|
||||
if(overtimeStatus != null) {
|
||||
MobStatusOvertimeEntry mdoe = new MobStatusOvertimeEntry(overtimeDelay, overtimeStatus);
|
||||
|
||||
overtimeStatusLock.lock();
|
||||
try {
|
||||
registeredMobStatusOvertime.put(mse, mdoe);
|
||||
} finally {
|
||||
overtimeStatusLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
registerEntry(mse, cancelStatus, duration);
|
||||
}
|
||||
|
||||
public void interruptMobStatus(MonsterStatusEffect mse) {
|
||||
interruptEntry(mse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeLocks();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
overtimeStatusLock = overtimeStatusLock.dispose();
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,12 @@ public class MapleDataTool {
|
||||
} else if (data.getType() == MapleDataType.STRING) {
|
||||
return Integer.parseInt(getString(data));
|
||||
} else {
|
||||
return ((Integer) data.getData()).intValue();
|
||||
Object numData = data.getData();
|
||||
if (numData instanceof Integer) {
|
||||
return (Integer) numData;
|
||||
} else {
|
||||
return (Short) numData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import scripting.AbstractPlayerInteraction;
|
||||
import scripting.map.MapScriptManager;
|
||||
import server.maps.MaplePortal;
|
||||
import server.quest.MapleQuest;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
@@ -44,6 +44,11 @@ public class PortalPlayerInteraction extends AbstractPlayerInteraction {
|
||||
public MaplePortal getPortal() {
|
||||
return portal;
|
||||
}
|
||||
|
||||
public void runMapScript() {
|
||||
MapScriptManager msm = MapScriptManager.getInstance();
|
||||
msm.runMapScript(c, "onUserEnter/" + portal.getScriptName(), false);
|
||||
}
|
||||
|
||||
public boolean hasLevel30Character() {
|
||||
PreparedStatement ps = null;
|
||||
|
||||
@@ -21,7 +21,6 @@ package server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.sql.Connection;
|
||||
@@ -38,6 +37,9 @@ import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProviderFactory;
|
||||
import provider.MapleDataTool;
|
||||
import tools.DatabaseConnection;
|
||||
|
||||
/**
|
||||
@@ -45,6 +47,7 @@ import tools.DatabaseConnection;
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MapleSkillbookInformationProvider {
|
||||
|
||||
private final static MapleSkillbookInformationProvider instance = new MapleSkillbookInformationProvider();
|
||||
|
||||
public static MapleSkillbookInformationProvider getInstance() {
|
||||
@@ -86,167 +89,31 @@ public class MapleSkillbookInformationProvider {
|
||||
static {
|
||||
loadSkillbooks();
|
||||
}
|
||||
|
||||
private static String getName(String token) {
|
||||
int i, j;
|
||||
char[] dest;
|
||||
String d;
|
||||
|
||||
i = token.lastIndexOf("name");
|
||||
i = token.indexOf("\"", i) + 1; //lower bound of the string
|
||||
j = token.indexOf("\"", i); //upper bound
|
||||
|
||||
if(j < i) { //node value containing 'name' in it's scope, cheap fix since we don't deal with strings anyway
|
||||
System.out.println("[CRITICAL] Found this '" + token + "'");
|
||||
return "0";
|
||||
}
|
||||
|
||||
dest = new char[initialStringLength];
|
||||
token.getChars(i, j, dest, 0);
|
||||
|
||||
d = new String(dest);
|
||||
return(d.trim());
|
||||
}
|
||||
|
||||
private static String getValue(String token) {
|
||||
int i, j;
|
||||
char[] dest;
|
||||
String d;
|
||||
|
||||
i = token.lastIndexOf("value");
|
||||
i = token.indexOf("\"", i) + 1; //lower bound of the string
|
||||
j = token.indexOf("\"", i); //upper bound
|
||||
|
||||
dest = new char[initialStringLength];
|
||||
token.getChars(i, j, dest, 0);
|
||||
|
||||
d = new String(dest);
|
||||
return(d.trim());
|
||||
}
|
||||
|
||||
private static void forwardCursor(int st) {
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
while(status >= st && (line = bufferedReader.readLine()) != null) {
|
||||
simpleToken(line);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void simpleToken(String token) {
|
||||
if(token.contains("/imgdir")) {
|
||||
status -= 1;
|
||||
}
|
||||
else if(token.contains("imgdir") && !token.endsWith("/>")) { // '\>' XML node description not being accounted, issue found thanks to Robin Schulz, CanIGetaPR
|
||||
status += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void inspectQuestItemList(int st) {
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
while(status >= st && (line = bufferedReader.readLine()) != null) {
|
||||
readItemToken(line);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSkillBook(int itemid) {
|
||||
return itemid >= skillbookMinItemid && itemid < skillbookMaxItemid;
|
||||
}
|
||||
|
||||
private static void processCurrentItem() {
|
||||
try {
|
||||
if(isSkillBook(currentItemid)) {
|
||||
if(currentCount > 0) {
|
||||
foundSkillbooks.put(currentItemid, SkillBookEntry.QUEST);
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {}
|
||||
}
|
||||
|
||||
private static void readItemToken(String token) {
|
||||
if(token.contains("/imgdir")) {
|
||||
status -= 1;
|
||||
|
||||
processCurrentItem();
|
||||
|
||||
currentItemid = 0;
|
||||
currentCount = 0;
|
||||
}
|
||||
else if(token.contains("imgdir") && !token.endsWith("/>")) {
|
||||
status += 1;
|
||||
}
|
||||
else {
|
||||
String d = getName(token);
|
||||
|
||||
if(d.equals("id")) {
|
||||
currentItemid = Integer.parseInt(getValue(token));
|
||||
} else if(d.equals("count")) {
|
||||
currentCount = Integer.parseInt(getValue(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void translateActToken(String token) {
|
||||
String d;
|
||||
int temp;
|
||||
|
||||
if(token.contains("/imgdir")) {
|
||||
status -= 1;
|
||||
}
|
||||
else if(token.contains("imgdir") && !token.endsWith("/>")) {
|
||||
if(status == 1) { //getting QuestId
|
||||
d = getName(token);
|
||||
questId = Integer.parseInt(d);
|
||||
}
|
||||
else if(status == 2) { //start/complete
|
||||
d = getName(token);
|
||||
isCompleteState = Integer.parseInt(d);
|
||||
}
|
||||
else if(status == 3) {
|
||||
d = getName(token);
|
||||
|
||||
if(d.contains("item")) {
|
||||
temp = status;
|
||||
inspectQuestItemList(temp);
|
||||
} else {
|
||||
forwardCursor(status);
|
||||
}
|
||||
}
|
||||
|
||||
status += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void fetchSkillbooksFromQuests() {
|
||||
String line = "";
|
||||
int lineNumber = 0; // add line number, thanks to Alex (CanIGetaPR)
|
||||
MapleData actData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/" + "Quest.wz")).getData("Act.img");
|
||||
|
||||
try {
|
||||
fileReader = new InputStreamReader(new FileInputStream(wzPath + "/Quest.wz/Act.img.xml"), "UTF-8");
|
||||
bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
while((line = bufferedReader.readLine()) != null) {
|
||||
lineNumber++;
|
||||
translateActToken(line);
|
||||
for (MapleData questData : actData.getChildren()) {
|
||||
for (MapleData questStatusData : questData.getChildren()) {
|
||||
for (MapleData questNodeData : questStatusData.getChildren()) {
|
||||
if (questNodeData.getName().contentEquals("item")) {
|
||||
for (MapleData questItemData : questNodeData.getChildren()) {
|
||||
int itemid = MapleDataTool.getInt("id", questItemData, 0);
|
||||
int itemcount = MapleDataTool.getInt("count", questItemData, 0);
|
||||
|
||||
if (isSkillBook(itemid) && itemcount > 0) {
|
||||
foundSkillbooks.put(currentItemid, SkillBookEntry.QUEST);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
} catch(IOException ioe) {
|
||||
System.out.println("Failed to read Quest.wz file. Line " + lineNumber + ": " + line);
|
||||
ioe.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Failed to parse Quest.wz XML file."); // catch this exception, thanks to YonhNi
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -163,11 +163,11 @@ public class MapleLifeFactory {
|
||||
}
|
||||
stats.setFirstAttack(firstAttack > 0);
|
||||
stats.setDropPeriod(MapleDataTool.getIntConvert("dropItemPeriod", monsterInfoData, stats.getDropPeriod() / 10000) * 10000);
|
||||
|
||||
if (!(stats.isBoss() && !hpbarBosses.contains(mid))) { // thanks Riizade, Z1peR, Anesthetic for noticing some bosses crashing players due to missing requirements
|
||||
stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0));
|
||||
stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0));
|
||||
}
|
||||
|
||||
// thanks yuxaij, Riizade, Z1peR, Anesthetic for noticing some bosses crashing players due to missing requirements
|
||||
boolean hpbarBoss = stats.isBoss() && hpbarBosses.contains(mid);
|
||||
stats.setTagColor(hpbarBoss ? MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0) : 0);
|
||||
stats.setTagBgColor(hpbarBoss ? MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0) : 0);
|
||||
|
||||
for (MapleData idata : monsterData) {
|
||||
if (!idata.getName().equals("info")) {
|
||||
|
||||
@@ -72,6 +72,11 @@ import tools.Randomizer;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.channel.services.ServiceType;
|
||||
import net.server.channel.services.task.MobAnimationService;
|
||||
import net.server.channel.services.task.MobClearSkillService;
|
||||
import net.server.channel.services.task.MobStatusService;
|
||||
import net.server.channel.services.task.OverallService;
|
||||
import net.server.coordinator.world.MapleMonsterAggroCoordinator;
|
||||
import server.MapleStatEffect;
|
||||
import server.loot.MapleLootManager;
|
||||
@@ -333,7 +338,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
|
||||
if(animationTime > 0) {
|
||||
return map.getChannelServer().registerMobOnAnimationEffect(map.getId(), this.hashCode(), animationTime);
|
||||
MobAnimationService service = (MobAnimationService) map.getChannelServer().getServiceAccess(ServiceType.MOB_ANIMATION);
|
||||
return service.registerMobOnAnimationEffect(map.getId(), this.hashCode(), animationTime);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
@@ -1197,7 +1203,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
if (oldEffect != null) {
|
||||
oldEffect.removeActiveStatus(stat);
|
||||
if (oldEffect.getStati().isEmpty()) {
|
||||
ch.interruptMobStatus(mapid, oldEffect);
|
||||
MobStatusService service = (MobStatusService) map.getChannelServer().getServiceAccess(ServiceType.MOB_STATUS);
|
||||
service.interruptMobStatus(mapid, oldEffect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1303,7 +1310,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
statiLock.unlock();
|
||||
}
|
||||
|
||||
ch.registerMobStatus(mapid, status, cancelTask, duration + animationTime - 100, overtimeAction, overtimeDelay);
|
||||
MobStatusService service = (MobStatusService) map.getChannelServer().getServiceAccess(ServiceType.MOB_STATUS);
|
||||
service.registerMobStatus(mapid, status, cancelTask, duration + animationTime - 100, overtimeAction, overtimeDelay);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1354,7 +1362,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
statiLock.unlock();
|
||||
}
|
||||
|
||||
map.getChannelServer().registerMobStatus(map.getId(), effect, cancelTask, duration);
|
||||
MobStatusService service = (MobStatusService) map.getChannelServer().getServiceAccess(ServiceType.MOB_STATUS);
|
||||
service.registerMobStatus(map.getId(), effect, cancelTask, duration);
|
||||
}
|
||||
|
||||
public void refreshMobPosition() {
|
||||
@@ -1552,7 +1561,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
};
|
||||
|
||||
mmap.getChannelServer().registerMobClearSkillAction(mmap.getId(), r, cooltime);
|
||||
MobClearSkillService service = (MobClearSkillService) map.getChannelServer().getServiceAccess(ServiceType.MOB_CLEAR_SKILL);
|
||||
service.registerMobClearSkillAction(mmap.getId(), r, cooltime);
|
||||
}
|
||||
|
||||
private void clearSkill(int skillId, int level) {
|
||||
@@ -1619,8 +1629,9 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
mons.clearAttack(attackPos);
|
||||
}
|
||||
};
|
||||
|
||||
mmap.getChannelServer().registerMobClearSkillAction(mmap.getId(), r, cooltime);
|
||||
|
||||
MobClearSkillService service = (MobClearSkillService) map.getChannelServer().getServiceAccess(ServiceType.MOB_CLEAR_SKILL);
|
||||
service.registerMobClearSkillAction(mmap.getId(), r, cooltime);
|
||||
} finally {
|
||||
monsterLock.unlock();
|
||||
}
|
||||
@@ -1667,7 +1678,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
public void run() {
|
||||
int curHp = hp.get();
|
||||
if(curHp <= 1) {
|
||||
map.getChannelServer().interruptMobStatus(map.getId(), status);
|
||||
MobStatusService service = (MobStatusService) map.getChannelServer().getServiceAccess(ServiceType.MOB_STATUS);
|
||||
service.interruptMobStatus(map.getId(), status);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1675,7 +1687,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
if (damage >= curHp) {
|
||||
damage = curHp - 1;
|
||||
if (type == 1 || type == 2) {
|
||||
map.getChannelServer().interruptMobStatus(map.getId(), status);
|
||||
MobStatusService service = (MobStatusService) map.getChannelServer().getServiceAccess(ServiceType.MOB_STATUS);
|
||||
service.interruptMobStatus(map.getId(), status);
|
||||
}
|
||||
}
|
||||
if (damage > 0) {
|
||||
@@ -1731,7 +1744,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
};
|
||||
|
||||
mmap.getChannelServer().registerMobClearSkillAction(mmap.getId(), r, milli);
|
||||
MobClearSkillService service = (MobClearSkillService) mmap.getChannelServer().getServiceAccess(ServiceType.MOB_CLEAR_SKILL);
|
||||
service.registerMobClearSkillAction(mmap.getId(), r, milli);
|
||||
}
|
||||
} finally {
|
||||
monsterLock.unlock();
|
||||
@@ -2213,7 +2227,8 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
};
|
||||
|
||||
// had to schedule this since mob wouldn't stick to puppet aggro who knows why
|
||||
this.getMap().getChannelServer().registerOverallAction(this.getMap().getId(), r, YamlConfig.config.server.UPDATE_INTERVAL);
|
||||
OverallService service = (OverallService) this.getMap().getChannelServer().getServiceAccess(ServiceType.OVERALL);
|
||||
service.registerOverallAction(this.getMap().getId(), r, YamlConfig.config.server.UPDATE_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,8 @@ import client.status.MonsterStatus;
|
||||
import constants.game.GameConstants;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import net.server.channel.services.ServiceType;
|
||||
import net.server.channel.services.task.OverallService;
|
||||
import tools.Randomizer;
|
||||
import server.maps.MapleMap;
|
||||
import server.maps.MapleMapObject;
|
||||
@@ -115,7 +117,8 @@ public class MobSkill {
|
||||
}
|
||||
};
|
||||
|
||||
monster.getMap().getChannelServer().registerOverallAction(monster.getMap().getId(), toRun, animationTime);
|
||||
OverallService service = (OverallService) monster.getMap().getChannelServer().getServiceAccess(ServiceType.OVERALL);
|
||||
service.registerOverallAction(monster.getMap().getId(), toRun, animationTime);
|
||||
}
|
||||
|
||||
public void applyEffect(MapleCharacter player, MapleMonster monster, boolean skill, List<MapleCharacter> banishPlayers) {
|
||||
|
||||
@@ -37,8 +37,7 @@ public abstract class AbstractMapleMapObject implements MapleMapObject {
|
||||
|
||||
@Override
|
||||
public void setPosition(Point position) {
|
||||
this.position.x = position.x;
|
||||
this.position.y = position.y;
|
||||
this.position.move(position.x, position.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,7 +28,8 @@ import config.YamlConfig;
|
||||
import tools.Pair;
|
||||
|
||||
import client.MapleCharacter;
|
||||
import constants.net.ServerConstants;
|
||||
import net.server.channel.services.ServiceType;
|
||||
import net.server.channel.services.task.OverallService;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -131,7 +132,9 @@ public class MapleDoor {
|
||||
long effectTimeLeft = 3000 - destroyDoor.getElapsedDeployTime(); // portal deployment effect duration
|
||||
if (effectTimeLeft > 0) {
|
||||
MapleMap town = destroyDoor.getTown();
|
||||
town.getChannelServer().registerOverallAction(town.getId(), new Runnable() {
|
||||
|
||||
OverallService service = (OverallService) town.getChannelServer().getServiceAccess(ServiceType.OVERALL);
|
||||
service.registerOverallAction(town.getId(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
destroyDoor.broadcastRemoveDoor(owner); // thanks BHB88 for noticing doors crashing players when instantly cancelling buff
|
||||
|
||||
@@ -65,6 +65,10 @@ import java.lang.ref.WeakReference;
|
||||
import net.server.Server;
|
||||
import net.server.coordinator.world.MapleMonsterAggroCoordinator;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.channel.services.ServiceType;
|
||||
import net.server.channel.services.task.FaceExpressionService;
|
||||
import net.server.channel.services.task.MobMistService;
|
||||
import net.server.channel.services.task.OverallService;
|
||||
import net.server.world.World;
|
||||
import scripting.map.MapScriptManager;
|
||||
import server.MapleItemInformationProvider;
|
||||
@@ -1942,7 +1946,8 @@ public class MapleMap {
|
||||
public void dismissRemoveAfter(final MapleMonster monster) {
|
||||
Runnable removeAfterAction = monster.popRemoveAfterAction();
|
||||
if (removeAfterAction != null) {
|
||||
this.getChannelServer().forceRunOverallAction(mapid, removeAfterAction);
|
||||
OverallService service = (OverallService) this.getChannelServer().getServiceAccess(ServiceType.OVERALL);
|
||||
service.forceRunOverallAction(mapid, removeAfterAction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2203,7 +2208,8 @@ public class MapleMap {
|
||||
}
|
||||
};
|
||||
|
||||
this.getChannelServer().registerMobMistCancelAction(mapid, mistSchedule, duration);
|
||||
MobMistService service = (MobMistService) this.getChannelServer().getServiceAccess(ServiceType.MOB_MIST);
|
||||
service.registerMobMistCancelAction(mapid, mistSchedule, duration);
|
||||
}
|
||||
|
||||
public void spawnKite(final MapleKite kite) {
|
||||
@@ -2302,7 +2308,8 @@ public class MapleMap {
|
||||
}
|
||||
|
||||
private void registerMapSchedule(Runnable r, long delay) {
|
||||
this.getChannelServer().registerOverallAction(mapid, r, delay);
|
||||
OverallService service = (OverallService) this.getChannelServer().getServiceAccess(ServiceType.OVERALL);
|
||||
service.registerOverallAction(mapid, r, delay);
|
||||
}
|
||||
|
||||
private void activateItemReactors(final MapleMapItem drop, final MapleClient c) {
|
||||
@@ -2788,7 +2795,8 @@ public class MapleMap {
|
||||
public void removePlayer(MapleCharacter chr) {
|
||||
Channel cserv = chr.getClient().getChannelServer();
|
||||
|
||||
cserv.unregisterFaceExpression(mapid, chr);
|
||||
FaceExpressionService service = (FaceExpressionService) this.getChannelServer().getServiceAccess(ServiceType.FACE_EXPRESSION);
|
||||
service.unregisterFaceExpression(mapid, chr);
|
||||
chr.unregisterChairBuff();
|
||||
|
||||
chrWLock.lock();
|
||||
@@ -3548,7 +3556,8 @@ public class MapleMap {
|
||||
if (reactor.getDelay() > 0) {
|
||||
MapleMap reactorMap = reactor.getMap();
|
||||
|
||||
reactorMap.getChannelServer().registerOverallAction(reactorMap.getId(), new Runnable() {
|
||||
OverallService service = (OverallService) reactorMap.getChannelServer().getServiceAccess(ServiceType.OVERALL);
|
||||
service.registerOverallAction(reactorMap.getId(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reactor.lockReactor();
|
||||
|
||||
@@ -36,6 +36,8 @@ import server.TimerManager;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.channel.services.ServiceType;
|
||||
import net.server.channel.services.task.OverallService;
|
||||
import server.partyquest.GuardianSpawnPoint;
|
||||
|
||||
/**
|
||||
@@ -368,14 +370,17 @@ public class MapleReactor extends AbstractMapleMapObject {
|
||||
};
|
||||
|
||||
delayedRespawnRun = r;
|
||||
map.getChannelServer().registerOverallAction(map.getId(), r, this.getDelay());
|
||||
|
||||
OverallService service = (OverallService) map.getChannelServer().getServiceAccess(ServiceType.OVERALL);
|
||||
service.registerOverallAction(map.getId(), r, this.getDelay());
|
||||
}
|
||||
|
||||
public boolean forceDelayedRespawn() {
|
||||
Runnable r = delayedRespawnRun;
|
||||
|
||||
if (r != null) {
|
||||
map.getChannelServer().forceRunOverallAction(map.getId(), r);
|
||||
OverallService service = (OverallService) map.getChannelServer().getServiceAccess(ServiceType.OVERALL);
|
||||
service.forceRunOverallAction(map.getId(), r);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
package server.quest.actions;
|
||||
|
||||
import client.MapleCharacter;
|
||||
import client.MapleQuestStatus;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataTool;
|
||||
import server.quest.MapleQuest;
|
||||
|
||||
Reference in New Issue
Block a user