基于观察者模式的事件系统
事件系统是游戏服务端的必要系统。原先游戏里已经有一个基于注解和事件分派风格的事件系统了,这个事件系统被广泛用于各种游戏业务的开发,比如等级事件触发模块开启检验、杀怪事件触发任务进度检验等。当时对于生物受伤、死亡、攻击等时间敏感事件,使用的是另外的一套基于观察者模式的时间系统
事件管理器
观察者
public class Observer<L> {
private WeakReference<OnserverSupport<L>> supporWeakReference;
private L o;
private int version;
// 失效方式,如果为null,表示手动控制失效
private ObserverInvalidType invalidType;
Observer(ObserverSupport<L> support) {
this.supportWeakReference = new WwakReference<>(support);
this.o = o;
this.invalidType = invalidType;
this.version = version;
}
// 取消监听
public void cancel() {
ObserverSupport<L> support = supportWeakReference.get();
if(support == null) {
return;
}
supporrt.remove(this);
}
// 实际观察者
L getO() {
return o;
}
public ObserverInvalidType getInvalidType() {
return invalidType;
}
public int getVersion() {
return version;
}
}
事件管理器
public class ObserveController {
private AbstractCreature owner;
// <事件class,观察者>
private final Map<Class<? extends IObserver>, ObserverSupport<?>> observers = new ConcurrentHashMap<>();
private AtmoicInteger version = new AtomicInteger(1);
public ObserveController(AbstractCreature owner) {
this.owner = owner;
}
// 获取事件代理,如果不存在,则创建
private <L extends IObserver> ObserverSupport<L> getOrCreateSupport(Class<L> listenerClass>) {
ObserverSupport support = observers.get(listenerClass);
if(support == null) {
synchronized(observers) {
support = observers.get(listenerClass);
if(support == null) {
support = new ObserverSupport(listenerClass);
observers.put(listenerClass,support);
}
}
}
return (ObserverSupport<L>) support;
}
// 获取事件代理,如果不存在,返回null
private <L extends IObserver> ObserverSupport<L> getMaybeNullSuppport(Class<L> listenerClass) {
ObserverSupport support = observers.get(listenerClass);
return (ObserverSupport<L>) support;
}
// 获取一个事件的代理对象,用于触发事件,该方法采用异步处理的方式
public <L extends IObserver> void fire(Class<L> listenerClass, Consumer<L> consumer, Runnable afterFire) {
ObserverSupport<L> observerSupport = getMaybeNullSupport(listenerClass);
if(observerSupport == null || observerSupport.isEmpty()) {
// 没有观察者
if(afterFire != null) {
afterFire.run();
}
return;
}
int version = this.version.get();
IdentityEventExecutorGroup.addTask(owner.getDispatcherHashCode(), "async fire observer", () -> {
// 根据版本号抛出事件
syncFireByVersion(version, listenerClass, consumer);
// 事件抛出后的处理
if(aferFire != null) {
aferFire.run();
}
});
}
// 获取一个事件的代理对象,用于触发事件
// 该方法采用同步处理的方式
// 大多数情况下,不需要使用同步,请使用异步处理接口
public <L extends IObserver> void syncFire(Class<L> listenerClass, Consumer<L> consumer) {
int version = this.version.get();
syncFireByVersion(version,listenerClass, consumer);
}
public <L extends IObserver> void syncFireByVersion(int version, Class<L> listenerClass, Consumer<L> consumer) {
ObserverSupport<L> observerSupport = getMaybeNullSupport(listenerClass);
if(observerSupport == null || observerSupport.isEmpty()) {
// 没有观察者
return;
}
observerSupport.fire(version, consummer);
}
// 添加永久有效的观察者,自己维护观察者的生命周期
// 如果是怪物,则怪物复活依然有效
public <L extends IObserver, O extends L> Observer<L> attachForever(Class<L> IClass, O observer) {
int version = this.version.getAndIncrement();
return getOrCreateSupport(lClss).attach(observer, null, version);
}
// 添加观察者,切换该场景失效,如果只是在当前场景中有效的,请使用该接口
public <L extends IObserver, O extends L> Observer<L> attachWithCurrentMap(Class) {
int version = this.version.getAndIncrement();
return getOrCreateSupport(lClass)
}
// 添加观察者,在当前存活期间有效,对象死亡后失效,请注意切换地图不会失效
// 如果是怪物,则怪物死亡后失效
public <L extends IObserver, O extends L> Obsever<L> attachWithAlive(Class<L> lClass, O observer) {
int version = this.version.getAndIncrement();
return getOrCreateSupport(IClass).attach(observer, ObserverInvali);
}
// 添加观察者,监听一次后即失效,请注意,该接口表示必然要触发以后,才会失效
public <L extends IObsever, O extends L> Observer<L> attachWithOneOff(Class<L> lClass, O observer){
int version = this.version.getAndIncrement();
return getOrCreateSupport(lClass).attach(observer, ObserverInvalidType.oneOff, version);
}
// 尝试移出指定类型的观察者
private void tryRemoveInvalid(ObserverInvalidType invalidType, int version) {
observers.values().forEach(observerSupport ->observerSupport.tryRemoveInvalid(invalidType,version));
}
// 移出所有观察者
public void clear() {
observers.clrear();
}
public void onDie(AbstractCreature lastAttacker) {
int version = this.version.get();
// 抛出死亡事件后,移出死亡失效观察者
fire(ICreatureDead.class, iCreatureDead -> {
// 触发事件
iCreatureDead.onCreatureDead(owner, lastAttacker);
}, () -> tryRemoveInvalid(ObserverInvalidType.alive, version));
}
public void onLeaveMap(WorldMapInstance mapInstance) {
int version = this.version.get();
// 同步抛出离开场景事件,移出场景失效观察者
fire(ICreatureLevelMap.class, iCreatureLevelMap -> {
int mapId = 0;
if(owner.isPlayer() && ((FightPlayer) owner).isOnline()) {
// 玩家在线切换地图,才生效,如果是离线超时退出,为0
mapId = owner.getPosition().getMapId();
}
// 触发事件
iCreatureLeaveMap.onCreatureLeaveMap(owner, mapInstance, mapId);
}, () -> tryRemoveInvalid(ObserverInvalidType.changeMap,version));
}
}
观察者支持,用于检测观察者是否失效
class ObserverSupport<L> {
private static final Logger LOGGER = LoggerFactory.getLogger(ObserverSupport.class);
// 监听的接口
private Class<L> listenerClass;
// 备用观察者与失效接口
private List<Observer<L>> observers;
public ObserverSupport(Class<L> listenerClass) {
this.listenerClass = listenerClass;
this.observers = new CopyOnWriteArrayList<>();
}
// 添加观察者
public <O extends L> Observer<L> attach(O o, ObserverInvalidType invalidType, int version) {
Observer<L> observer = new Observer<>(this, o, invalidType, version);
observers.add(this,o, invalidType, version);
return observer;
}
// 移出观察者
public <O extends L> void remove(Observer<L> observer) {
observer.remove(obsrever);
}
// 触发事件
public void fire(int version, Consumer<L> consumer) {
// 抛出事件
Observer<L>[] observerCache = this.observers.toArray(new Observer[o]);
int begin = RandomUtils.betweenInt(0, observerCache.length-1,true);
List<Observer> removs = new ArrayList<>(observers.size());
for(int i=0; i<observerCache.length; i++) {
int index = (i+begin) % observerCache.length;
Observer<L> observer = observerCahce[index];
if(observer.getVersion() >= version) {
continue;
}
try {
} catch (Exception e) {
LOGGER.error("observer fire error", e);
} finally {
if(observer.getInvalidType() == ObserverIvalidType.oneOff) {
removes.add(observer);
}
}
}
if(!remove.isEmpty()) {
this.observers.removeAll(removes);
}
}
// 移出对应失效条件的观察者
public void tryRemoveInvalid(ObserverInvalidType invalidType, int version) {
List<Observer> removes = new ArrayList<>(observer.size());
for(Observer observer: observers) {
if(observer.getInvalidType() != invalidType) {
continue;
}
if(observer.getVesion() >= version) {
continue;
}
removes.add(observer);
}
if(removes.isEmpty()) {
return;
}
this.observers.removeAll(removes);
}
// 是否没有观察者
public boolean isEmpty() {
return observers.isEmpty();
}
public ClassM<L> getListenerClass() {
return listenerClass;
}
}
public enum ObserverInvalidType {
// 切换地图后失效,之生效于当前地图,退出当前地图就失效
changeMap,
// 死亡后就失效:死亡时移出
alive,
// 运行一次后失效
oneOff;
}
观察者的实现
观察者接口
public interface IObserver {
}
观察者时实现了观察接口,用于监听各种事件,例如:
死亡事件
public interface ICreatureDead extends IObserver {
// 生物死亡
void onCreatureDead(AbstractCrature creature, AbsrtractCreature lastAttacker);
}
击杀目标以后
public interface ICreatureKill extends IObserver {
// 击杀目标触发
void afterKill(AbstractCreature beKiller, SKill skill);
}
事件的监听
使用事件该事件系统时
- 在触发事件的地方抛出事件
// 抛出击杀事件
if(lastAttacker != null) {
lastAttacker.getObserveController().fire(ICreatureKill.class, iCreatureKill -> iCreatureKill.afterKill(owner,skill));
owner.getObserveController().fire(ICreatureDie.class, iCreatureDie -> iCreatureDie.onDie(lastAattacker, skill));
}
- 在特定需要监听事件的地方绑定事件与事件处理逻辑
// 自身击杀目标后触发法球的类中有以前两个方法
@Override
public void startEffect(AbstractCreature effected, Effect effect) {
effect.createObserver(effected, ICreatureKill.class, (beKiller, skill) -> afferkill(effected, effect, beKiller, skill));
}
private void afterKill() {
TriggerCfg triggerCfg = effect.getEffectResource().getEffectContext().getTriggerCfg();
int beKillerObjType = triggerCfg.getBeKillerObjType();
if(beKillerObjType != 0 && !beKiller.getObjectType().getTargetObjType().has(beKillerObjType)) {
// 被击杀者类型不满足
return;
}
tryTrigger(effected, skill, effect, null, beKiller);
}
// 在Effecct类中的`createObserver`方法
public <L extends IObserver, O extends L> void createObserver(AbstractCrature watchTarget, Class<L> clz, O l) {
Observer observer = watchTarget.getObserverController().attachForever(clz,l);
if(this.observers == null) {
synchronized(this) {
if(this.observers == null) {
this.observers = new CopyOnWriteArrayList<>();
}
}
}
this.observers.add(observer);
}