Код:
/**
* Класс реализующий список слушателей для каждого типа интерфейса.
*
* @author G1ta0
*
* @param <T> базовый интерфейс слушателя
*/
public class ListenerList<T> implements Closeable {
protected UnsafeCopyOnWriteArraySet<Listener<T>> listeners = new UnsafeCopyOnWriteArraySet<>();
public Object[] getListeners() {
return listeners.getUnsafeArray();
}
/**
* Добавить слушатель в список
* @param listener
* @return возвращает true, если слушатель был добавлен
*/
public boolean add(Listener<T> listener) {
return listeners.add(listener);
}
/**
* Удалить слушатель из списка.
* Не вызывает закрытие слушателя!
* @param listener
* @return возвращает true, если слушатель был удален
*/
public boolean remove(Listener<T> listener) {
return listeners.remove(listener);
}
/**
* Освобождает ресурсы занятые слушателями и очищает лист слушателей
*/
@SuppressWarnings("unchecked")
@Override
public void close() {
for(Object listener : getListeners())
((Listener<T>)listener).close();
listeners.clear();
}
}
Код:
/**
* @author Ro0TT
* @date 13.01.2013
*/
@Refactored(date="20.03.2015", author="PointerRage")
@AllArgsConstructor
public class CharListenerList extends ListenerList<L2Character> {
@Getter(value=AccessLevel.PROTECTED) private final static UnsafeCopyOnWriteArraySet<Listener<L2Character>> global = new UnsafeCopyOnWriteArraySet<>();
@Getter protected final L2Character actor;
public static void addGlobal(Listener<L2Character> listener) {
global.add(listener);
}
public static void removeGlobal(Listener<L2Character> listener) {
global.remove(listener);
}
public void onHit(int damage, L2Character attacker, L2Skill skill) {
for(Object listener : getListeners())
if(CharacterOnHit.class.isInstance(listener))
((CharacterOnHit) listener).onHit(getActor(), damage, attacker, skill);
for(Object listener : global.getUnsafeArray())
if(CharacterOnHit.class.isInstance(listener))
((CharacterOnHit) listener).onHit(getActor(), damage, attacker, skill);
}
Код:
public interface CharListener extends Listener<L2Character> {
}
Код:
public interface Listener<T> extends Closeable {
@Override default void close() {}
}
Код:
public interface CharacterOnHit extends CharListener {
public void onHit(L2Character actor, int damage, L2Character attacker, L2Skill skill);
}
L2Character::onHitTimer
Код:
...
// Notify AI with EVT_ATTACKED
target.getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, this);
target.getListeners().onHit(miss ? 0 : damage, this, null);
...
L2Character::callSkill
Код:
...
if (skill.getSkillType() != L2SkillType.SIGNET && skill.getSkillType() != L2SkillType.SIGNET_CASTTIME)
{
ctarget.getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, player);
ctarget.getListeners().onHit(0, this, skill);
...
default:
ctarget.addAttackerToAttackByList(this);
ctarget.getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, this);
ctarget.getListeners().onHit(0, this, skill);
...
L2Character
Код:
@Getter(lazy=true) protected final CharListenerList listeners = new CharListenerList(this);
public void addListener(Listener<L2Character> listener) {
getListeners().add(listener);
}
public void removeListener(Listener<L2Character> listener) {
getListeners().remove(listener);
}