Маленькая шара от меня, так сказать подарочек на Новый Год
Многие наверное видели в сервере от l2jserver так называемые SkillHandlers, позволяющие без особого труда объявлять в датапаке новые обработчики скиллов и вызывать их когда зарегистрированный в них скилл использован.
Вобщем я реализовал нечто подобное и для серверов на базе феникса, но с небольшими отличиями: у l2jserver обрабатывается только useSkill и ничего более, у меня же дополнительно можно проверять условия для применения самого скилла, для старта эффекта в нем, делать какие-нибудь действия при старте и окончании эффекта, а так же действия с заданным периодом пока эффект работает.
Куда это все применить я пока даже хз - делал реализацию этого всего чисто ради интересу и руководствуясь принципом "потом может пригодится для чего нибудь"
Ладно, перейдем к делу, а конкретно к содержимому необходимых классов для ядра.
ISkillHandler.java:
PHP код:
package l2p.gameserver.handler;
import l2p.gameserver.model.L2Character;
import l2p.gameserver.model.L2Effect;
import l2p.gameserver.model.L2Skill;
import l2p.util.GArray;
/**
* Класс для обработки хэндлеров, прикрепляемых к скиллам и их эффектам.
* <br><br>
* Для того, чтобы вызывались методы checkCondition(L2Skill skill, ...), isUseAdditionalCheck(), isOffensive() и useSkill(L2Skill skill, ...),
* необходимо чтобы умение, к которому прикреплен хэндлер, имело тип HANDLER.
* <br><br>
* Для того, чтобы вызывались методы checkCondition(L2Effect effect, ...), onStart(L2Effect effect, ...), onExit(L2Effect effect, ...) и
* onActionTime(L2Effect effect, ...), необходимо чтобы в умении, к которому прикреплен хэндлер, имелся эффект с именем Handler.
*
* @author Gaikotsu
*/
public interface ISkillHandler
{
/**
* Проверка возможности использовать умение на заданную цель.
*
* @param skill - умение
* @param caster - персонаж, кастующий умение
* @param target - цель, на которую используется умение
* @param forceUse - форсированое использование умения (через Ctrl) или обычное
*
* @return - true - умение можно использовать, false - нельзя
* <br><br>
* Если метод isUseAdditionalCheck() хэндлера возвращает true, то после проверок в этом методе, дополнительно будет
* вызван одноименный метод и родительского класса (метод из L2Skill), который проведет дополнительно стандартные проверки на
* возможность использования умения на эту цель.
*/
public boolean checkCondition(L2Skill skill, L2Character caster, L2Character target, boolean forceUse);
/**
* Возвращает признак того, надо ли делать дополнительные проверки возможности использовать умение на заданную цель.
*
* @return - true - проверки проводить надо, false - дополнительные проверки не требуются
*/
public boolean isUseAdditionalCheck();
/**
* Возвращает признак того, является ли умение "плохим" (вызывающим PvP-флаг).
*
* @return - true - умение "плохое", false - умение "хорошее"
*/
public boolean isOffensive();
/**
* Использование умения на список целей.
*
* @param skill - умение
* @param caster - персонаж, кастующий умение
* @param targets - список целей, на которые используется умение
*/
public void useSkill(L2Skill skill, L2Character caster, GArray<L2Character> targets);
/**
* Проверка возможности использовать эффект на заданную цель.
*
* @param effect - эффект
* @param caster - персонаж, накладывающий эффект
* @param target - цель, на которую накладывается эффект
*
* @return - true - эффект можно использовать, false - нельзя
*/
public boolean checkCondition(L2Effect effect, L2Character caster, L2Character target);
/**
* Вызывается при начале работы эффекта.
*
* @param effect - эффект
* @param caster - персонаж, наложивший эффект
* @param target - цель, на которую действует эффект
*/
public void onStart(L2Effect effect, L2Character caster, L2Character target);
/**
* Вызывается при окончании работы эффекта.
*
* @param effect - эффект
* @param caster - персонаж, наложивший эффект
* @param target - цель, на которую действует эффект
*/
public void onExit(L2Effect effect, L2Character caster, L2Character target);
/**
* Вызывается периодически во время действия эффекта.<br>
* Количество и частота вызовов задается в самом описании эффекта в умении (параметры count и time).<br>
* Возвращает возможность дальнейшей работы эффекта.
*
* @param effect - эффект
* @param caster - персонаж, наложивший эффект
* @param target - цель, на которую действует эффект
*
* @return - true - эффект может работать дальше, false - работу эффекта необходимо прервать незамедлительно
*/
public boolean onActionTime(L2Effect effect, L2Character caster, L2Character target);
/**
* Возвращает список умений, на которые зарегистрирован хэндлер.
*
* @return - список умений в виде их идентификаторов
*/
public int[] getSkillIds();
}
SkillHandler.java:
PHP код:
package l2p.gameserver.handler;
import java.util.Map;
import java.util.TreeMap;
public class SkillHandler
{
private static SkillHandler _instance;
private Map<Integer, ISkillHandler> _datatable;
public static SkillHandler getInstance()
{
if (_instance == null)
_instance = new SkillHandler();
return _instance;
}
public int size()
{
return _datatable.size();
}
private SkillHandler()
{
_datatable = new TreeMap<Integer, ISkillHandler>();
}
public void registerSkillHandler(ISkillHandler handler)
{
int[] ids = handler.getSkillIds();
for (int element : ids)
_datatable.put(element, handler);
}
public ISkillHandler getSkillHandler(int skillId)
{
return _datatable.get(skillId);
}
public void clear()
{
_datatable.clear();
}
}
Handler.java:
PHP код:
package l2p.gameserver.skills.skillclasses;
import l2p.gameserver.handler.ISkillHandler;
import l2p.gameserver.handler.SkillHandler;
import l2p.gameserver.model.L2Character;
import l2p.gameserver.model.L2Skill;
import l2p.gameserver.templates.StatsSet;
import l2p.util.GArray;
public class Handler extends L2Skill
{
private ISkillHandler handler = null;
public Handler(StatsSet set)
{
super(set);
}
private ISkillHandler getHandler(int skillId)
{
if (handler == null)
handler = SkillHandler.getInstance().getSkillHandler(this.getId());
if (handler == null)
_log.warning("Warning: Not found skill handler for skill " + this.getId() + ", class");
return handler;
}
@Override
public boolean checkCondition(L2Character activeChar, L2Character target, boolean forceUse, boolean dontMove, boolean first)
{
if (getHandler(this.getId()) != null && handler.checkCondition(this, activeChar, target, forceUse))
{
if (handler.isUseAdditionalCheck())
return super.checkCondition(activeChar, target, forceUse, dontMove, first);
else
return true;
}
else
return false;
}
@Override
public void useSkill(L2Character activeChar, GArray<L2Character> targets)
{
if (getHandler(this.getId()) != null)
handler.useSkill(this, activeChar, targets);
}
@Override
public boolean isOffensive()
{
if (getHandler(this.getId()) != null)
return handler.isOffensive();
else
return super.isOffensive();
}
}
EffectHandler.java:
PHP код:
package l2p.gameserver.skills.effects;
import l2p.gameserver.handler.ISkillHandler;
import l2p.gameserver.handler.SkillHandler;
import l2p.gameserver.model.L2Effect;
import l2p.gameserver.skills.Env;
public final class EffectHandler extends L2Effect
{
private ISkillHandler handler = null;
public EffectHandler(Env env, EffectTemplate template)
{
super(env, template);
handler = SkillHandler.getInstance().getSkillHandler(this.getSkill().getId());
if (handler == null)
_log.warning("Warning: Not found skill handler for skill " + this.getSkill().getId() + ", effect");
}
@Override
public boolean checkCondition()
{
if (handler != null && handler.checkCondition(this, _effector, _effected))
return super.checkCondition();
else
return false;
}
@Override
public void onStart()
{
super.onStart();
if (handler != null)
handler.onStart(this, _effector, _effected);
}
@Override
public void onExit()
{
super.onExit();
if (handler != null)
handler.onExit(this, _effector, _effected);
}
@Override
public boolean onActionTime()
{
if (handler != null)
return handler.onActionTime(this, _effector, _effected);
else
return false;
}
}
Как зарегистрировать новые класс (HANDLER) и эффект (Handler) скилла в ядре - объяснять уж не буду - это делается легко и просто.
Ну и пример того, как это все работает:
Объявление самого скилла:
PHP код:
<skill id="7068" levels="1" name="Test Skill">
<set name="target" val="TARGET_ONE" />
<set name="skillType" val="HANDLER" />
<set name="operateType" val="OP_ACTIVE" />
<for>
<effect count="5" name="Handler" time="3" val="0" />
</for>
</skill>
Обработчик методов для этого скилла:
PHP код:
package handlers.skills;
import l2p.extensions.scripts.ScriptFile;
import l2p.gameserver.handler.ISkillHandler;
import l2p.gameserver.handler.SkillHandler;
import l2p.gameserver.model.L2Character;
import l2p.gameserver.model.L2Effect;
import l2p.gameserver.model.L2Skill;
import l2p.util.GArray;
/**
* Пример работы хэндлера, прицепленного к умению.<br>
* Ничего не делает кроме вывода разных сообщений о том, какой из методов хэндлера сработал при работе умения.
* <br><br>
* Для того, чтобы вызывались методы checkCondition(L2Skill skill, ...), isUseAdditionalCheck(), isOffensive() и useSkill(L2Skill skill, ...),
* необходимо чтобы умение, к которому прикреплен хэндлер, имело тип HANDLER.
* <br><br>
* Для того, чтобы вызывались методы checkCondition(L2Effect effect, ...), onStart(L2Effect effect, ...), onExit(L2Effect effect, ...) и
* onActionTime(L2Effect effect, ...), необходимо чтобы в умении, к которому прикреплен хэндлер, имелся эффект с именем Handler.
*
* @author Gaikotsu
*/
public class Sample implements ISkillHandler, ScriptFile
{
private static final int[] _skillIds = { 7068 };
/**
* Проверка возможности использовать умение на заданную цель.
*
* @param skill - умение
* @param caster - персонаж, кастующий умение
* @param target - цель, на которую используется умение
* @param forceUse - форсированое использование умения (через Ctrl) или обычное
*
* @return - true - умение можно использовать, false - нельзя
* <br><br>
* Если метод isUseAdditionalCheck() хэндлера возвращает true, то после проверок в этом методе, дополнительно будет
* вызван одноименный метод и родительского класса (метод из L2Skill), который проведет дополнительно стандартные проверки на
* возможность использования умения на эту цель.
*/
@Override
public boolean checkCondition(L2Skill skill, L2Character caster, L2Character target, boolean forceUse)
{
if (caster != null && caster.isPlayer())
caster.getPlayer().sendMessage("skill class: method - checkCondition, caster - " + caster.getName() + ", target - " + target.getName());
return true;
}
/**
* Возвращает признак того, надо ли делать дополнительные проверки возможности использовать умение на заданную цель.
*
* @return - true - проверки проводить надо, false - дополнительные проверки не требуются
*/
@Override
public boolean isUseAdditionalCheck()
{
return true;
}
/**
* Возвращает признак того, является ли умение "плохим" (вызывающим PvP-флаг).
*
* @return - true - умение "плохое", false - умение "хорошее"
*/
@Override
public boolean isOffensive()
{
return false;
}
/**
* Использование умения на список целей.
*
* @param skill - умение
* @param caster - персонаж, кастующий умение
* @param targets - список целей, на которые используется умение
*/
@Override
public void useSkill(L2Skill skill, L2Character caster, GArray<L2Character> targets)
{
if (caster != null && caster.isPlayer())
{
String _targets = "";
for (L2Character target : targets)
_targets = _targets + target.getName() + " ";
caster.getPlayer().sendMessage("skill class: method - useSkill, caster - " + caster.getName() + ", target(s) - " + _targets);
for (L2Character target : targets)
skill.getEffects(caster, target, false, false);
}
}
/**
* Проверка возможности использовать эффект на заданную цель.
*
* @param effect - эффект
* @param caster - персонаж, накладывающий эффект
* @param target - цель, на которую накладывается эффект
*
* @return - true - эффект можно использовать, false - нельзя
*/
@Override
public boolean checkCondition(L2Effect effect, L2Character caster, L2Character target)
{
if (caster != null && caster.isPlayer())
caster.getPlayer().sendMessage("skill effect: method - checkCondition, caster - " + caster.getName() + ", target - " + target.getName());
return true;
}
/**
* Вызывается при начале работы эффекта.
*
* @param effect - эффект
* @param caster - персонаж, наложивший эффект
* @param target - цель, на которую действует эффект
*/
@Override
public void onStart(L2Effect effect, L2Character caster, L2Character target)
{
if (caster != null && caster.isPlayer())
caster.getPlayer().sendMessage("skill effect: method - onStart, caster - " + caster.getName() + ", target - " + target.getName());
}
/**
* Вызывается при окончании работы эффекта.
*
* @param effect - эффект
* @param caster - персонаж, наложивший эффект
* @param target - цель, на которую действует эффект
*/
@Override
public void onExit(L2Effect effect, L2Character caster, L2Character target)
{
if (caster != null && caster.isPlayer())
caster.getPlayer().sendMessage("skill effect: method - onExit, caster - " + caster.getName() + ", target - " + target.getName());
}
/**
* Вызывается периодически во время действия эффекта.<br>
* Количество и частота вызовов задается в самом описании эффекта в умении (параметры count и time).<br>
* Возвращает возможность дальнейшей работы эффекта.
*
* @param effect - эффект
* @param caster - персонаж, наложивший эффект
* @param target - цель, на которую действует эффект
*
* @return - true - эффект может работать дальше, false - работу эффекта необходимо прервать незамедлительно
*/
@Override
public boolean onActionTime(L2Effect effect, L2Character caster, L2Character target)
{
if (caster != null && caster.isPlayer())
caster.getPlayer().sendMessage("skill effect: method - onActionTime, caster - " + caster.getName() + ", target - " + target.getName());
return true;
}
/**
* Возвращает список умений, на которые зарегистрирован хэндлер.
*
* @return - список умений в виде их идентификаторов
*/
@Override
public int[] getSkillIds()
{
return _skillIds;
}
@Override
public void onLoad()
{
SkillHandler.getInstance().registerSkillHandler(this);
}
@Override
public void onReload()
{}
@Override
public void onShutdown()
{}
}
P.S. С наступающим всех.