Files
aibis-dream/Assets/Scripts/Framework/Core/SingleCastEventSystem.cs
T

164 lines
4.4 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace AibisDream.Framework
{
/// <summary>
/// 单播事件系统
/// 特点:通过枚举索引事件,多处可触发,但仅有一个方法能被注册(后注册覆盖先注册)
/// 用途:用于解耦项目中的单例依赖
/// </summary>
public class SingleCastEventSystem
{
public static readonly SingleCastEventSystem Global = new();
// 内部接口:用于统一存储不同类型的事件
private interface IEventEntry
{
}
// 类型化的条目存储
private class Entry<T> : IEventEntry where T : Delegate
{
public T Handler;
}
// 按枚举类型分组的存储
// Key: 枚举类型, Value: 该枚举所有值的条目数组
private readonly Dictionary<Type, IEventEntry[]> _entries = new(50);
#region 无参数
public void Register<T>(T key, Action handler) where T : IConvertible
{
var entry = GetEntry<T, Action>(key);
#if DEBUG
if (entry.Handler != null)
{
Debug.LogWarning($"[SingleCastEvent] {typeof(T).Name}.{key} 已被注册,正在覆盖");
}
#endif
entry.Handler = handler;
}
public void Trigger<T>(T key) where T : IConvertible
{
var entry = GetEntryOrNull<T, Action>(key);
entry?.Handler?.Invoke();
}
#endregion
#region 1个参数
public void Register<T, T1>(T key, Action<T1> handler) where T : IConvertible
{
var entry = GetEntry<T, Action<T1>>(key);
#if DEBUG
if (entry.Handler != null)
{
Debug.LogWarning($"[SingleCastEvent] {typeof(T).Name}.{key} 已被注册,正在覆盖");
}
#endif
entry.Handler = handler;
}
public void Trigger<T, T1>(T key, T1 arg1) where T : IConvertible
{
var entry = GetEntryOrNull<T, Action<T1>>(key);
entry?.Handler?.Invoke(arg1);
}
#endregion
#region 2个参数
public void Register<T, T1, T2>(T key, Action<T1, T2> handler) where T : IConvertible
{
var entry = GetEntry<T, Action<T1, T2>>(key);
#if DEBUG
if (entry.Handler != null)
{
Debug.LogWarning($"[SingleCastEvent] {typeof(T).Name}.{key} 已被注册,正在覆盖");
}
#endif
entry.Handler = handler;
}
public void Trigger<T, T1, T2>(T key, T1 arg1, T2 arg2) where T : IConvertible
{
var entry = GetEntryOrNull<T, Action<T1, T2>>(key);
entry?.Handler?.Invoke(arg1, arg2);
}
#endregion
#region 注销
public void Unregister<T>(T key) where T : IConvertible
{
var index = key.ToInt32(null);
var enumType = typeof(T);
if (_entries.TryGetValue(enumType, out var arr) && index < arr.Length)
{
arr[index] = null;
}
}
public void UnregisterAll()
{
_entries.Clear();
}
#endregion
#region 内部辅助方法
private Entry<TDelegate> GetEntry<TEnum, TDelegate>(TEnum key)
where TEnum : IConvertible
where TDelegate : Delegate
{
var index = key.ToInt32(null);
var enumType = typeof(TEnum);
if (!_entries.TryGetValue(enumType, out var arr))
{
// 首次使用该枚举类型,创建条目数组
var valueCount = Enum.GetValues(enumType).Length;
arr = new IEventEntry[valueCount];
_entries[enumType] = arr;
}
if (arr[index] == null)
{
arr[index] = new Entry<TDelegate>();
}
return (Entry<TDelegate>)arr[index];
}
private Entry<TDelegate> GetEntryOrNull<TEnum, TDelegate>(TEnum key)
where TEnum : IConvertible
where TDelegate : Delegate
{
var index = key.ToInt32(null);
var enumType = typeof(TEnum);
if (!_entries.TryGetValue(enumType, out var arr)) return null;
if (index >= arr.Length) return null;
return arr[index] as Entry<TDelegate>;
}
#endregion
}
}