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:
@@ -12,6 +12,8 @@ Being a NetBeans 8.2 Project, this means that it's easier to install the project
|
||||
|
||||
In this project, many gameplay-wise issues generated from either the original WZ files and the server source have been partially or completely solved. Considering the use of the provided edited WZ's and server-side wz.xml files should be of the greatest importance when dealing with this instance of server source, in order to perceive it at it's full potential. My opinion, though!
|
||||
|
||||
- In other case, as fallback from the provided ones, consider using **whole clean set**. Selecting part of the provided ones to play pretty much *may eventually* lead to unexpected issues.
|
||||
|
||||
The main objective of this project is to try as best as possible to recreate what once was the original MapleStory v83, while adding up some flavors that spices up the gameplay. In other words, aim to get the best of the MapleStory of that era.
|
||||
|
||||
---
|
||||
|
||||
@@ -310,7 +310,6 @@ server:
|
||||
MAX_AP: 32767 #Max AP allotted on the auto-assigner.
|
||||
MAX_EVENT_LEVELS: 8 #Event has different levels of rewarding system.
|
||||
BLOCK_NPC_RACE_CONDT: 500 # (0.5 * 1000) Time the player client must wait before reopening a conversation with an NPC.
|
||||
PET_LOOT_UPON_ATTACK: 700 # (0.7 * 1000) Time the pet must wait before trying to pick items up.
|
||||
TOT_MOB_QUEST_REQUIREMENT: 77 #Overwrites old 999-mobs requirement for the ToT questline with new requirement value, set 0 for default.
|
||||
MOB_REACTOR_REFRESH_TIME: 30000 # (30 * 1000) Overwrites refresh time for those reactors oriented to inflict damage to bosses (Ice Queen, Riche), set 0 for default.
|
||||
PARTY_SEARCH_REENTRY_LIMIT: 10 #Max amount of times a party leader is allowed to persist on the Party Search before entry expiration (thus needing to manually restart the Party Search to be able to search for members).
|
||||
|
||||
@@ -18,6 +18,7 @@ Known issues:
|
||||
- Reportedly, there are cases where mob positions fail to sync between player's client-view.
|
||||
- Visual equip EXP watch value will present stuttering for early levels requirement (EXP needed less than 100), and requirement at level 200 will not progress at all due to the level cap in client.
|
||||
- Monster Magnet will crash the player when trying to pull fixed monsters.
|
||||
- Some magic skills such as "Energy Bolt" or "Holy Arrow" doesn't display damage to other players when the attacks come from close range to the targeted mob. Oddly enough, using "closeRangeAttack" packet seems to clear the issue on most skills, however in others "Error 5" crash renders this unusable.
|
||||
---------------------------
|
||||
|
||||
---------------------------
|
||||
|
||||
@@ -2181,3 +2181,19 @@ Corrigido análise de alerta de HP/MP lado-servidor não contando com os atribut
|
||||
Corrigido skill "Energy Charge" levando atualização de buff ao tocar em mobs, levando a casos onde o buff nos stats poderia inesperadamente ficar retido além do tempo de atuação previsto.
|
||||
Substituído utilização de "Jackson annotations + SnakeYaml" por "YamlBeans", utilizando-se assim menos artefatos JARs no processo (anteriormente 5, agora somente 1). Nota: na transição, fora constatado que a utilização da tecnologia anterior era mais permissiva perante o arquivo de configurações, porém estrutura do novo arquivo foi normalizado e está agora funcional.
|
||||
Refatorado inicialização de eventos ao iniciar o servidor, em busca de melhorar o tempo de startup.
|
||||
|
||||
05 - 08 Outubro 2019,
|
||||
Refatorado os diversos schedulers que estavam presentes na classe de canais, agora abstraídas e atuando dentro de serviços.
|
||||
Corrigido circunstância onde movimentos de mobs poderiam estar sendo processados enquanto jogador está transitando mapas, levando a possível inconsistência na aplicação de movimento do mob na área acessada.
|
||||
|
||||
10 - 12 Outubro 2019,
|
||||
Modificado uso de "default" de petid nos itens de inventário armazenados na DB (de -1 para nulo), assim permitindo criar chaves únicas.
|
||||
Adicionado uso de chaves estrangeiras para o petid.
|
||||
Implementado código de suporte para cupons de "associação" de cosméticos de cabelo.
|
||||
Corrigido bug recente em bosses com atributo "link" sem HPbar sendo detectados como possuindo HPbar, se o mob base possui.
|
||||
Corrigido bug recente na skill "Body Pressure" não aplicando a sua passiva com chance de neutralizar ao tocar mobs.
|
||||
Corrigido quest com NPC "Shaman Rock" aplicando progresso que não corresponde com o esperado (progresso extra agora movido para um novo questid).
|
||||
Adicionado método que permite executar scripts de mapa no sistema de scripts de portal.
|
||||
Corrigido problema recente ao referenciar script com progresso "Touch the Sky" (script de portal utilizando métodos de scripts de mapa).
|
||||
Adicionado fallback para scripts de NPC MapleTV.
|
||||
Revisado aplicação e abordagem deste código-base nos arquivos XML legado.
|
||||
+9
-16
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
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 +19,11 @@
|
||||
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: kevintjuh93
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobMistScheduler extends BaseScheduler {
|
||||
public MobMistScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBMIST);
|
||||
}
|
||||
|
||||
public void registerMistCancelAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
*/
|
||||
function start(ms) {
|
||||
ms.touchTheSky();
|
||||
}
|
||||
@@ -72,7 +72,10 @@ function action(mode, type, selection) {
|
||||
} else if (status == 2){
|
||||
cm.dispose();
|
||||
if (beauty == 1){
|
||||
if (cm.haveItem(5150001)){
|
||||
if (cm.haveItem(5420002)){
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
} else if (cm.haveItem(5150001)){
|
||||
cm.gainItem(5150001, -1);
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
|
||||
@@ -78,7 +78,10 @@ function action(mode, type, selection) {
|
||||
else if (status == 2){
|
||||
cm.dispose();
|
||||
if (beauty == 1){
|
||||
if (cm.haveItem(5150003)){
|
||||
if (cm.haveItem(5420003)){
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
} else if (cm.haveItem(5150003)){
|
||||
cm.gainItem(5150003, -1);
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
*/
|
||||
var status = -1;
|
||||
|
||||
/*
|
||||
Custom Quest 100300
|
||||
*/
|
||||
function activateShamanRock(slot,progress) {
|
||||
var ch = progress[slot];
|
||||
if(ch == '0') {
|
||||
@@ -45,10 +48,10 @@ function start() {
|
||||
else if(map == 105070000) activateShamanRock(2,progress);
|
||||
|
||||
else if(map == 105090000) { // workaround... TWO SAME NPC ID ON SAME MAP
|
||||
var npcOid = cm.getQuestProgressInt(2236, 1);
|
||||
var npcOid = cm.getQuestProgressInt(100300, 1);
|
||||
if (npcOid == 0) {
|
||||
activateShamanRock(3,progress);
|
||||
cm.setQuestProgress(2236, 1, cm.getNpcObjectId());
|
||||
cm.setQuestProgress(100300, 1, cm.getNpcObjectId());
|
||||
} else if (cm.getNpcObjectId() != npcOid) {
|
||||
activateShamanRock(4,progress);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
*/
|
||||
var status = -1;
|
||||
|
||||
/*
|
||||
Custom Quest 100300
|
||||
*/
|
||||
function activateShamanRock(slot,progress) {
|
||||
var ch = progress[slot];
|
||||
if(ch == '0') {
|
||||
@@ -45,10 +48,10 @@ function start() {
|
||||
else if(map == 105070000) activateShamanRock(2,progress);
|
||||
|
||||
else if(map == 105090000) { // workaround... TWO SAME NPC ID ON SAME MAP
|
||||
var npcOid = cm.getQuestProgressInt(2236, 1);
|
||||
var npcOid = cm.getQuestProgressInt(100300, 1);
|
||||
if (npcOid == 0) {
|
||||
activateShamanRock(3,progress);
|
||||
cm.setQuestProgress(2236, 1, cm.getNpcObjectId());
|
||||
cm.setQuestProgress(100300, 1, cm.getNpcObjectId());
|
||||
} else if (cm.getNpcObjectId() != npcOid) {
|
||||
activateShamanRock(4,progress);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,10 @@ function action(mode, type, selection) {
|
||||
else if (status == 2){
|
||||
cm.dispose();
|
||||
if (beauty == 1){
|
||||
if (cm.haveItem(5150005) == true){
|
||||
if (cm.haveItem(5420004)){
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
} else if (cm.haveItem(5150005) == true){
|
||||
cm.gainItem(5150005, -1);
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
|
||||
@@ -81,7 +81,10 @@ function action(mode, type, selection) {
|
||||
else if (status == 2){
|
||||
cm.dispose();
|
||||
if (beauty == 1){
|
||||
if (cm.haveItem(5150007) == true){
|
||||
if (cm.haveItem(5420005)){
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
} else if (cm.haveItem(5150007) == true){
|
||||
cm.gainItem(5150007, -1);
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
|
||||
@@ -81,7 +81,10 @@ function action(mode, type, selection) {
|
||||
else if (status == 2){
|
||||
cm.dispose();
|
||||
if (beauty == 1){
|
||||
if (cm.haveItem(5150025)){
|
||||
if (cm.haveItem(5420006)){
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
} else if (cm.haveItem(5150025)){
|
||||
cm.gainItem(5150025, -1);
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
|
||||
@@ -40,7 +40,6 @@ function action(mode, type, selection) {
|
||||
|
||||
if(status == 0) {
|
||||
if(cm.isQuestStarted(3311)) {
|
||||
var slot = 2;
|
||||
var progress = cm.getQuestProgressInt(3311);
|
||||
|
||||
if (progress == 4) {
|
||||
|
||||
@@ -40,7 +40,6 @@ function action(mode, type, selection) {
|
||||
|
||||
if(status == 0) {
|
||||
if(cm.isQuestStarted(3311)) {
|
||||
var slot = 0;
|
||||
var progress = cm.getQuestProgressInt(3311);
|
||||
|
||||
if (progress == 4) {
|
||||
|
||||
@@ -84,7 +84,10 @@ function action(mode, type, selection) {
|
||||
else if (status == 2){
|
||||
cm.dispose();
|
||||
if (beauty == 1){
|
||||
if (cm.haveItem(5150020) == true){
|
||||
if (cm.haveItem(5420000)){
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
} else if (cm.haveItem(5150020) == true){
|
||||
cm.gainItem(5150020, -1);
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
|
||||
@@ -73,7 +73,10 @@ function action(mode, type, selection) {
|
||||
else if (status == 2){
|
||||
cm.dispose();
|
||||
if (beauty == 1){
|
||||
if (cm.haveItem(5150031)){
|
||||
if (cm.haveItem(5420001)){
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
} else if (cm.haveItem(5150031)){
|
||||
cm.gainItem(5150031, -1);
|
||||
cm.setHair(hairnew[selection]);
|
||||
cm.sendOk("Enjoy your new and improved hairstyle!");
|
||||
|
||||
@@ -17,24 +17,33 @@
|
||||
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
|
||||
/*
|
||||
Default Maple TV
|
||||
*/
|
||||
public class OverallScheduler extends BaseScheduler {
|
||||
public OverallScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_OVERALL);
|
||||
}
|
||||
|
||||
public void registerDelayedAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
var status;
|
||||
|
||||
public void forceRunDelayedAction(Runnable runAction) {
|
||||
interruptEntry(runAction);
|
||||
}
|
||||
function start() {
|
||||
status = -1;
|
||||
action(1, 0, 0);
|
||||
}
|
||||
|
||||
function action(mode, type, selection) {
|
||||
if (mode == -1) {
|
||||
cm.dispose();
|
||||
} else {
|
||||
if (mode == 0 && type > 0) {
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
if (mode == 1)
|
||||
status++;
|
||||
else
|
||||
status--;
|
||||
|
||||
if(status == 0) {
|
||||
// do nothing
|
||||
cm.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,10 +20,8 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Author: kevintjuh93
|
||||
*
|
||||
*/
|
||||
function start(ms) {
|
||||
ms.touchTheSky();
|
||||
// Author: Ronan
|
||||
function enter(ms) {
|
||||
ms.runMapScript();
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
var status = -1;
|
||||
|
||||
function start(mode, type, selection) {
|
||||
var familyEntry = qm.getPlayer().getFamilyEntry();
|
||||
if (familyEntry != null && familyEntry.getJuniorCount() > 0) {
|
||||
qm.forceCompleteQuest();
|
||||
qm.gainExp(3000);
|
||||
qm.sendNext("Good job!");
|
||||
} else {
|
||||
qm.sendNext("I see that you have not successfully find a Junior, ok?");
|
||||
}
|
||||
qm.dispose();
|
||||
}
|
||||
|
||||
function end(mode, type, selection) {
|
||||
var familyEntry = qm.getPlayer().getFamilyEntry();
|
||||
if (familyEntry != null && familyEntry.getJuniorCount() > 0) { // script found thanks to kvmba
|
||||
qm.forceCompleteQuest();
|
||||
qm.gainExp(3000);
|
||||
qm.sendNext("Good job!");
|
||||
} else {
|
||||
qm.sendNext("I see that you have not successfully find a Junior, ok?");
|
||||
}
|
||||
qm.dispose();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
-/*
|
||||
Author: Kevin
|
||||
Quest: Zombie Mushroom Signal 3 (2251)
|
||||
NPC: The Rememberer (1061011)
|
||||
Item: Recording Charm (4032399)
|
||||
*/
|
||||
|
||||
var status = -1; // script restored thanks to kvmba
|
||||
|
||||
function end(mode, type, selection) {
|
||||
if (mode == -1) {
|
||||
qm.dispose();
|
||||
} else {
|
||||
if(mode == 0 && type > 0) {
|
||||
qm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == 1)
|
||||
status++;
|
||||
else
|
||||
status--;
|
||||
|
||||
if (status == 0) {
|
||||
if(!qm.haveItem(4032399, 20)) {
|
||||
qm.sendOk("Please bring me 20 #b#t4032399##k... #i4032399#");
|
||||
}
|
||||
else {
|
||||
qm.gainItem(4032399, -20);
|
||||
qm.sendOk("Oh, you brought 20 #b#t4032399##k! Thank you.");
|
||||
qm.gainExp(8000);
|
||||
qm.forceCompleteQuest();
|
||||
}
|
||||
} else if (status == 1) {
|
||||
qm.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
-8
@@ -1,4 +1,4 @@
|
||||
#EXECUTE THIS FIRST, THEN NEXT SQL: 'db_drops.sql'
|
||||
#EXECUTE THIS FIRST, THEN NEXT SQL: 'db_drops.sql'
|
||||
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
SET time_zone = "+00:00";
|
||||
@@ -8,9 +8,9 @@ SET time_zone = "+00:00";
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8 */;
|
||||
|
||||
DROP DATABASE IF EXISTS `heavenms`;
|
||||
CREATE DATABASE `heavenms` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
USE `heavenms`;
|
||||
DROP DATABASE IF EXISTS `heavenms2`;
|
||||
CREATE DATABASE `heavenms2` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
USE `heavenms2`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `accounts` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
@@ -12968,7 +12968,7 @@ CREATE TABLE IF NOT EXISTS `inventoryitems` (
|
||||
`position` int(11) NOT NULL DEFAULT '0',
|
||||
`quantity` int(11) NOT NULL DEFAULT '0',
|
||||
`owner` tinytext NOT NULL,
|
||||
`petid` int(11) NOT NULL DEFAULT '-1',
|
||||
`petid` int(11) unsigned UNIQUE DEFAULT NULL,
|
||||
`flag` int(11) NOT NULL,
|
||||
`expiration` bigint(20) NOT NULL DEFAULT '-1',
|
||||
`giftFrom` varchar(26) NOT NULL,
|
||||
@@ -16463,7 +16463,7 @@ INSERT INTO `nxcoupons` (`id`, `couponid`, `rate`, `activeday`, `starthour`, `en
|
||||
(40,5360042,2,254,0,24);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `pets` (
|
||||
`petid` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`petid` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(13) DEFAULT NULL,
|
||||
`level` int(10) unsigned NOT NULL,
|
||||
`closeness` int(10) unsigned NOT NULL,
|
||||
@@ -16473,11 +16473,14 @@ CREATE TABLE IF NOT EXISTS `pets` (
|
||||
PRIMARY KEY (`petid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
|
||||
|
||||
ALTER TABLE `inventoryitems` ADD CONSTRAINT `fk_itempetid` FOREIGN KEY (`petid`) REFERENCES `pets` (`petid`) ON DELETE SET NULL ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `petignores` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`petid` int(10) unsigned NOT NULL ,
|
||||
`petid` int(11) unsigned NOT NULL ,
|
||||
`itemid` int(10) unsigned NOT NULL ,
|
||||
PRIMARY KEY (`id`)
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `fk_petignorepetid` FOREIGN KEY (`petid`) REFERENCES `pets` (`petid`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `playerdiseases` (
|
||||
@@ -20859,6 +20862,25 @@ INSERT INTO `shopitems` (`shopitemid`, `shopid`, `itemid`, `price`, `pitch`, `po
|
||||
(6531, 1337, 2040711, 1, 0, 62),
|
||||
(6532, 1337, 2340000, 1, 0, 63),
|
||||
(20020, 1337, 1082149, 1, 0, 64),
|
||||
(20255, 1337, 2044503, 1, 0, 86), # 20255~20273: thanks to ozanrijen
|
||||
(20256, 1337, 2044703, 1, 0, 87),
|
||||
(20257, 1337, 2044603, 1, 0, 88),
|
||||
(20258, 1337, 2043303, 1, 0, 89),
|
||||
(20259, 1337, 2043103, 1, 0, 90),
|
||||
(20260, 1337, 2043203, 1, 0, 91),
|
||||
(20261, 1337, 2043003, 1, 0, 92),
|
||||
(20262, 1337, 2044403, 1, 0, 93),
|
||||
(20263, 1337, 2044303, 1, 0, 94),
|
||||
(20264, 1337, 2043803, 1, 0, 95),
|
||||
(20265, 1337, 2044103, 1, 0, 96),
|
||||
(20266, 1337, 2044203, 1, 0, 97),
|
||||
(20267, 1337, 2044003, 1, 0, 98),
|
||||
(20268, 1337, 2043703, 1, 0, 99),
|
||||
(20269, 1337, 2040806, 1, 0, 100),
|
||||
(20270, 1337, 2040007, 1, 0, 101),
|
||||
(20271, 1337, 2040506, 1, 0, 102),
|
||||
(20272, 1337, 2040710, 1, 0, 103),
|
||||
(20273, 1337, 2040711, 1, 0, 104),
|
||||
(6533, 9000069, 2022503, 0, 5, 1),
|
||||
(6534, 9000069, 2000004, 0, 5, 2),
|
||||
(6535, 9000069, 2022514, 0, 10, 3),
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -127,6 +127,10 @@ public class Item implements Comparable<Item> {
|
||||
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) {
|
||||
@@ -235,43 +232,7 @@ public final class Channel {
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -316,6 +277,10 @@ public final class Channel {
|
||||
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)) {
|
||||
|
||||
+1
-1
@@ -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;
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+25
-9
@@ -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,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 MobClearSkillScheduler extends BaseScheduler {
|
||||
public MobClearSkillScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBSKILL);
|
||||
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 registerClearSkillAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
public T getService() {
|
||||
return cls.cast(service);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
service.dispose();
|
||||
service = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
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
|
||||
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;
|
||||
|
||||
import net.server.channel.services.task.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
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 Service createService() {
|
||||
return new Service(s);
|
||||
}
|
||||
|
||||
}
|
||||
+22
-14
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+11
-10
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,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;
|
||||
|
||||
@@ -45,6 +45,11 @@ public class PortalPlayerInteraction extends AbstractPlayerInteraction {
|
||||
return portal;
|
||||
}
|
||||
|
||||
public void runMapScript() {
|
||||
MapScriptManager msm = MapScriptManager.getInstance();
|
||||
msm.runMapScript(c, "onUserEnter/" + portal.getScriptName(), false);
|
||||
}
|
||||
|
||||
public boolean hasLevel30Character() {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = 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() {
|
||||
@@ -87,166 +90,30 @@ public class MapleSkillbookInformationProvider {
|
||||
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);
|
||||
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);
|
||||
|
||||
while((line = bufferedReader.readLine()) != null) {
|
||||
lineNumber++;
|
||||
translateActToken(line);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,10 +164,10 @@ 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) {
|
||||
@@ -1620,7 +1630,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);
|
||||
} 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;
|
||||
|
||||
+1
-1
@@ -445,7 +445,7 @@ public class MapleNoItemNameFetcher {
|
||||
|
||||
private static String getMissingEquipDesc(int itemid) {
|
||||
String s = descContentCache.get(itemid);
|
||||
if (s == null) {
|
||||
if (s == null && itemid >= 2000000) { // thanks Halcyon for noticing "missing info" on equips
|
||||
s = "MISSING INFO " + itemid;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user