fix: isolate listener exceptions in Before/After dispatch

This commit is contained in:
2026-06-17 20:39:43 +02:00
parent d0dcd599cf
commit 775c02794e
+26 -6
View File
@@ -1,3 +1,4 @@
using System;
using System.Collections.Frozen; using System.Collections.Frozen;
using System.Collections.Generic; using System.Collections.Generic;
using HarmonyLib; using HarmonyLib;
@@ -109,8 +110,8 @@ public class CommandHookModSystem : ModSystem
} }
foreach (var wildcard in wildcards) foreach (var wildcard in wildcards)
foreach (var mods in builder.Values) foreach (var mods in builder.Values)
mods[wildcard.ModId] = wildcard.Registration; mods[wildcard.ModId] = wildcard.Registration;
var pruned = new Dictionary<string, FrozenDictionary<string, CommandRegistration>>( var pruned = new Dictionary<string, FrozenDictionary<string, CommandRegistration>>(
builder.Count builder.Count
@@ -126,9 +127,17 @@ public class CommandHookModSystem : ModSystem
{ {
if (registrations.TryGetValue(commandName, out var mods)) if (registrations.TryGetValue(commandName, out var mods))
{ {
foreach (var (_, reg) in mods) foreach (var (modId, reg) in mods)
{ {
reg.Before?.Invoke(ref data); try
{
reg.Before?.Invoke(ref data);
}
catch (Exception ex)
{
Mod.Logger.Error("[{0}] Before /{1} threw: {2}", modId, commandName, ex);
}
if (data.Cancel) if (data.Cancel)
break; break;
} }
@@ -140,8 +149,19 @@ public class CommandHookModSystem : ModSystem
internal void FireAfter(string commandName, ref CommandData data, TextCommandResult result) internal void FireAfter(string commandName, ref CommandData data, TextCommandResult result)
{ {
if (registrations.TryGetValue(commandName, out var mods)) if (registrations.TryGetValue(commandName, out var mods))
foreach (var (_, reg) in mods) {
reg.After?.Invoke(ref data, result); foreach (var (modId, reg) in mods)
{
try
{
reg.After?.Invoke(ref data, result);
}
catch (Exception ex)
{
Mod.Logger.Error("[{0}] After /{1} threw: {2}", modId, commandName, ex);
}
}
}
} }
private void SyncWildcard(ICommandHookListener listener, IReadOnlyList<string> commands) private void SyncWildcard(ICommandHookListener listener, IReadOnlyList<string> commands)