搬运自OpenMod官网,经过翻译,可能有些不足,欢迎指正!原文链接
事件和事件侦听器
事件用于通知组件正在发生某些事情,如用户断开连接。
有两种类型的事件:
OpenMod事件
C#事件
本指南将介绍OpenMod事件。
订阅事件
有两种方式去订阅事件:
实现IEventListener接口:
public class UserConnectListener : IEventListener<UserConnectedEvent>
{
[EventListener(Priority = EventListenerPriority.Lowest)]
public async Task HandleEventAsync(object sender, UserConnectEvent @event)
{
// 做点什么
}
}
使用IEventBus服务的订阅方法:
public class MyPlugin : OpenModUniversalPlugin
{
private readonly IEventBus m_EventBus;
public MyPlugin(IEventBus eventBus, IServiceProvider serviceProvider) : base(serviceProvider)
{
m_EventBus = eventBus;
}
public async Task OnLoadAsync()
{
m_EventBus.Subscribe(this, (sender, @event) => {
// 做点什么
});
}
}
当插件卸载时,所有OpenMod事件侦听器都将自动取消订阅。您不必在卸载时手动取消订阅。
事件侦听器优先级和执行顺序
OpenMod允许您控制事件侦听器的执行顺序。执行顺序基于优先级。
您可以使用[EventListener]属性设置事件侦听器优先级。
执行顺序是从最低优先级到最高优先级。换句话说,最低优先级被称为第一优先级。
public class UserConnectListener1 : IEventListener<UserConnectedEvent>
{
[EventListener(Priority = EventListenerPriority.Lowest)]
public async Task HandleEventAsync(object sender, UserConnectEvent @event)
{
}
}
public class UserConnectListener2 : IEventListener<UserConnectedEvent>
{
[EventListener(Priority = EventListenerPriority.Low)]
public async Task HandleEventAsync(object sender, UserConnectEvent @event)
{
}
}
public class UserConnectListener3 : IEventListener<UserConnectedEvent>
{
[EventListener(Priority = EventListenerPriority.High)]
public async Task HandleEventAsync(object sender, UserConnectEvent @event)
{
}
}
在上面的示例中,首先调用UserConnectListener1,然后调用UserConnectListener2,最后调用UserConnectListener3。
取消事件和忽略取消的事件
事件必须实现ICancellableEvent接口才能取消。如果事件被取消,[EventListener]属性中没有IgnoreCancelled设置为true的事件侦听器,将不会收到通知。
UserConnectingEvent就是这样一个可取消的事件。如果事件被取消,它将断开连接用户的连接。
public class UserConnectingListener1 : IEventListener<UserConnectingEvent>
{
[EventListener(Priority = EventListenerPriority.Lowest)]
public async Task HandleEventAsync(object sender, UserConnectingEvent @event)
{
if(user.DisplayName.Equals("Trojaner"))
{
@event.IsCancelled = true;
}
}
}
public class UserConnectingListener2 : IEventListener<UserConnectingEvent>
{
[EventListener(Priority = EventListenerPriority.Low)]
public async Task HandleEventAsync(object sender, UserConnectingEvent @event)
{
// 此事件侦听器将不被调用,因为它不忽略取消
}
}
public class UserConnectingListener3 : IEventListener<UserConnectingEvent>
{
[EventListener(Priority = EventListenerPriority.High, IgnoreCancelled = true)]
public async Task HandleEventAsync(object sender, UserConnectingEvent @event)
{
// 即使事件被取消,也会调用此事件侦听器
}
}
在上面的示例中,如果名为“Trojaner”的用户连接,UserConnectingListener1将取消该事件。在这种情况下,不会调用UserConnectingListener2,因为它不会像UserConnectingListener3那样忽略取消的事件。
事件侦听器生存期
事件侦听器可以有三种类型的生存期:
Transient – 总是在每个事件上重新创建事件侦听器。如果您有多个IEventListener,那么所有IEventListener都有自己的实例。这是默认的生存期。
Scoped – 如果在一个类中实现多个IEventListener,那么所有IEventListener都将共享同一个实例。否则与Transient相同。
Singleton – 事件侦听器只有一个共享生存期,直到插件卸载为止。
您可以通过添加[EventListenerLifetime(ServiceLifetime)]属性来设置事件侦听器生存期:
[EventListenerLifetime(ServiceLifetime.Transient)] public class UserConnectBroadcaster : IEventListener<UserConnectedEvent> // ...
自定义事件
创建自定义事件很简单:只需创建一个从Event继承的新类。
举个例子:
public class SampleEvent : Event
{
public int MyValue { get; set; }
// 也可以添加其他属性
}
然后,可以使用事件总线发出它:
MyPlugin myPlugin = ...;
IEventBus eventBus = ...;
ILogger<xxx> logger = ...;
var @event = new SampleEvent
{
MyValue = 20
};
await m_EventBus.EmitAsync(myPlugin, this /* 发送人 */, @event);
logger.LogInformation($"Event value: {@event.MyValue}");
如果希望事件可取消,则必须实现ICancellableEvent接口:
public class SampleEvent : Event, ICancellableEvent
{
public int MyValue { get; set; }
public bool IsCancelled { get; set; }
}
——————————————————————————————————
MyPlugin myPlugin = ...;
IEventBus eventBus = ...;
ILogger<xxx> logger = ...;
var @event = new SampleEvent
{
MyValue = 20
};
await m_EventBus.EmitAsync(myPlugin, this /* 发送人 */, @event);
if(@event.IsCancelled)
{
logger.LogInformation($"Event has been cancelled!");
return;
}
logger.LogInformation($"Event value: {@event.MyValue}");
当你的插件卸载或服务被释放时,不要忘记取消订阅C#事件和委托。例如,如果要在加载插件时从Unturned订阅onEnemyConnected事件,还必须按以下方式取消订阅:
public async UniTask OnLoadAsync()
{
Provider.onEnemyConnected += OnPlayerConnected;
}
public async UniTask OnUnloadAsync()
{
// 这是非常重要的,否则你的插件将无法正确支持重新加载和卸载。
Provider.onEnemyConnected -= OnPlayerConnected;
}
避免编写单例事件侦听器。如果事件侦听器具有临时或作用域依赖项,则这可能会导致问题。
游戏交流区
攻略区
问答区
Mod发布区
Mod地图发布区
Mod技术区
汉化区
角色扮演交流区
技术交流
开服教程区
服务器宣传区
游戏更新公告区
MiaBot框架
圆心云开服面板
话题中心
社区公告
认证申请
工具/软件区
RGB颜色对照表
签到中心
幸运抽奖
排行榜
友情链接
小黑屋
周边商城


