Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions API/Events/EventId.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace WKLib.API.Events;

public enum HookId
{
GamemodeStart,
PlayerPerkAdded,
PlayerTookDamage,
PlayerDealtDamage,
PlayerTookGripStrengthDamage
}
10 changes: 10 additions & 0 deletions API/Events/EventPriority.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace WKLib.API.Events;

public enum EventPriority
{
Earliest = -200,
Early = -100,
Normal = 0,
Late = 100,
Latest = 200
}
41 changes: 41 additions & 0 deletions API/Events/EventService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using WKLib.Utilities;

namespace WKLib.API.Events;

public class EventService
{
private readonly WKLibAPI _owner;
private readonly List<(HookId hook, Action wrapped)> _subscriptions = new();

internal EventService(WKLibAPI owner) => _owner = owner;

public void Subscribe(HookId hook, Action callback, EventPriority priority = EventPriority.Normal)
{
WKLog.Debug($"[{_owner.DisplayName} ({_owner.GUID})] subscribing to {hook} with priority {priority}");
Action wrapped = () => Invoke(hook, callback);
_subscriptions.Add((hook, wrapped));
GameEvents.Subscribe(hook, wrapped, priority);
}

private void Invoke(HookId hook, Action callback)
{
WKLog.Debug($"[{_owner.DisplayName} ({_owner.GUID})] invoking {hook} callback");
try
{
callback();
}
catch (Exception ex)
{
WKLog.Error($"[{_owner.DisplayName} ({_owner.GUID})] threw in {hook} callback: {ex}");
}
}

internal void UnsubscribeAll()
{
foreach (var (hook, wrapped) in _subscriptions)
GameEvents.Unsubscribe(hook, wrapped);
_subscriptions.Clear();
}
}
59 changes: 59 additions & 0 deletions API/Events/GameEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using WKLib.Utilities;

namespace WKLib.API.Events;

public static class GameEvents
{
private readonly struct Subscription
{
public readonly EventPriority Priority;
public readonly long Order;
public readonly Action Handler;

public Subscription(EventPriority priority, long order, Action handler)
{
Priority = priority;
Order = order;
Handler = handler;
}
}

private static readonly Dictionary<HookId, List<Subscription>> _handlers = new();
private static long _nextOrder = 0;

internal static void Subscribe(HookId hook, Action handler, EventPriority priority)
{
if (!_handlers.TryGetValue(hook, out var list))
{
list = new List<Subscription>();
_handlers[hook] = list;
}

list.Add(new Subscription(priority, _nextOrder++, handler));

// handlers are sorted by priority, then by order of subscription
list.Sort((a, b) =>
{
int cmp = a.Priority.CompareTo(b.Priority);
return cmp != 0 ? cmp : a.Order.CompareTo(b.Order);
});
}

internal static void Unsubscribe(HookId hook, Action handler)
{
if (_handlers.TryGetValue(hook, out var list))
list.RemoveAll(s => s.Handler == handler);
}

internal static void Raise(HookId hook)
{
WKLog.Debug($"Raising event {hook}");
if (!_handlers.TryGetValue(hook, out var list) || list.Count == 0)
return;

foreach (var sub in list.ToArray())
sub.Handler.Invoke();
}
}
5 changes: 4 additions & 1 deletion API/WKLibAPI.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using WKLib.API.Assets;
using WKLib.API.Events;
using WKLib.API.UI;

namespace WKLib.API;
Expand All @@ -16,13 +17,15 @@ public class WKLibAPI
public ModTab ModTab { get; internal set; } = null;

public AssetService AssetService { get; internal set; } = null;

public EventService EventService { get; internal set; } = null;

private WKLibAPI(string displayName, string guid, string defaultConfigFileName)
{
DisplayName = displayName;
GUID = guid;

AssetService = new AssetService(this);
EventService = new EventService(this);
}

/// <summary>
Expand Down
7 changes: 7 additions & 0 deletions Core/Patches/CL_GameManagerPatch.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using HarmonyLib;
using WKLib.API.Events;
using WKLib.Core.Attributes;
using WKLib.Core.UI;
using static WKLib.Core.Config.ConfigManager;
Expand All @@ -22,4 +23,10 @@ private static void CL_GameManager_UnPause(CL_GameManager __instance)

RootPanel.Instance.IsOpen = false;
}

[HarmonyPatch(typeof(CL_GameManager), nameof(CL_GameManager.LoadIn)), HarmonyPostfix]
private static void CL_GameManager_LoadIn(CL_GameManager __instance)
{
GameEvents.Raise(HookId.GamemodeStart);
}
}
28 changes: 28 additions & 0 deletions Core/Patches/ENT_PlayerPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using HarmonyLib;
using WKLib.API.Events;
using WKLib.Core.Attributes;

namespace WKLib.Core.Patches;

[PatchOnEntry]
[HarmonyPatch]
internal static class ENT_PlayerPatch
{
[HarmonyPatch(typeof(ENT_Player), nameof(ENT_Player.AddPerk)), HarmonyPostfix]
private static void ENT_Player_AddPerk(ENT_Player __instance)
{
GameEvents.Raise(HookId.PlayerPerkAdded);
}

[HarmonyPatch(typeof(ENT_Player), nameof(ENT_Player.Damage)), HarmonyPostfix]
private static void ENT_Player_Damage(ENT_Player __instance)
{
GameEvents.Raise(HookId.PlayerTookDamage);
}

[HarmonyPatch(typeof(ENT_Player), nameof(ENT_Player.DamageGripStrength)), HarmonyPostfix]
private static void ENT_Player_DamageGripStrength(ENT_Player __instance)
{
GameEvents.Raise(HookId.PlayerTookGripStrengthDamage);
}
}
23 changes: 23 additions & 0 deletions Core/Patches/GameEntityPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Text;
using WKLib.API.Events;
using WKLib.Core.Attributes;

namespace WKLib.Core.Patches
{
[PatchOnEntry]
[HarmonyPatch]
internal static class GameEntityPatch
{
[HarmonyPatch(typeof(GameEntity), nameof(GameEntity.Damage)), HarmonyPostfix]
private static void GameEntity_Damage(GameEntity __instance, ref Damageable.DamageInfo info)
{
if (info.sourceEntity == ENT_Player.GetPlayer())
{
GameEvents.Raise(HookId.PlayerDealtDamage);
}
}
}
}