In fact the more I think about it, the more that model makes sense because it means your published event is going to have a relatively fixed signature - whereas as your game or whtaever develops and you get more and more information that your subscribers need, they can just ask for whatever.
A while ago I used this model that had a player object, and I had a bunch of events like:
public static event Action<int> OnPlayerHealthUpdated;
public static event Action<int> OnPlayerLevelUpdated;
then it started getting bloated..
public static event Action<int, int> OnPlayerHealthUpdated;
public static event Action<int, int> OnPlayerLevelUpdated;
and pretty soon it was out of control...
public static event Action<int, int, int, int, int> OnPlayerHealthUpdated;
so you can just change it to either more granular events that never have a parameter list, but instead have an event ID that you can store for as long as you need - AND you only ever need one action:
public static event Action<Guid> OnPlayerUpdated;
struct PlayerHealthUpdated
{
Guid id;
Guid PlayerId;
int HealthBefore;
int HealthAfter;
int HowMuchDamage;
DamageTypeEnum DamageType;
}
...
public Dictionary<Guid, PlayerHealthUpdate> playerHealthUpdateEvents;
{
Guid eventGuid = Guid.NewGuid();
PlayerHealthUpdate hit = new()
{
id = eventGuid,
PlayerId = playerGuid,
HealthBefore = player.Health,
HowMuchDamage = damage,
}
playerHealthUpdateEvents[eventGuid] = hit;
OnPlayerUpdated?.Invoke(eventGuid);
}
... elsewhere ...
PlayerManager.OnPlayerUpdated += OnPlayerHealthUpdatedHandler;
public void OnPlayerHealthUpdatedHandler(Guid eventGuid)
{
PlayerHealthUpdate hit = PlayerManager.playerHealthUpdateEvents[eventGuid];
... do stuff with hit ...
}