M src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SharedHookManager.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SharedHookManager.cs +67 -34
@@ 44,112 44,137 @@ public class SharedHookManager
/// <param name="browserManager">The browser manager.</param>
/// <param name="options">The initial options to be respected.</param>
/// <returns>The dictionary containing all of the hooks.</returns>
- public Result<Dictionary<string, INostaleHook>> InitializeInstance
+ public (Dictionary<string, INostaleHook>, IResult) InitializeInstance
(NosBindingManager bindingManager, NosBrowserManager browserManager, HookManagerOptions options)
{
+ IResult result = Result.FromSuccess();
if (!_initialized)
{
- var result = _underlyingManager.Initialize(bindingManager, browserManager);
+ result = _underlyingManager.Initialize(bindingManager, browserManager);
_initialized = true;
-
- if (!result.IsSuccess)
- {
- return Result<Dictionary<string, INostaleHook>>.FromError(result.Error);
- }
}
var hooks = new Dictionary<string, INostaleHook>();
// TODO: initialize using reflection
- hooks.Add
+ HandleAdd
(
- _underlyingManager.Periodic.Name,
+ hooks,
+ IHookManager.PeriodicName,
InitializeSingleHook
(
- new PeriodicHook(_underlyingManager.Periodic),
+ _underlyingManager.Periodic,
+ u => new PeriodicHook(u),
options.PeriodicHook
)
);
- hooks.Add
+ HandleAdd
(
- _underlyingManager.EntityFocus.Name,
+ hooks,
+ IHookManager.EntityFocusName,
InitializeSingleHook
(
- new EntityFocusHook(_underlyingManager.EntityFocus),
+ _underlyingManager.EntityFocus,
+ u => new EntityFocusHook(u),
options.EntityFocusHook
)
);
- hooks.Add
+ HandleAdd
(
- _underlyingManager.EntityFollow.Name,
+ hooks,
+ IHookManager.EntityFollowName,
InitializeSingleHook
(
- new EntityFollowHook(_underlyingManager.EntityFollow),
+ _underlyingManager.EntityFollow,
+ u => new EntityFollowHook(u),
options.EntityFollowHook
)
);
- hooks.Add
+ HandleAdd
(
- _underlyingManager.EntityUnfollow.Name,
+ hooks,
+ IHookManager.EntityUnfollowName,
InitializeSingleHook
(
- new EntityUnfollowHook(_underlyingManager.EntityUnfollow),
+ _underlyingManager.EntityUnfollow,
+ u => new EntityUnfollowHook(u),
options.EntityUnfollowHook
)
);
- hooks.Add
+ HandleAdd
(
- _underlyingManager.PacketReceive.Name,
+ hooks,
+ IHookManager.PacketReceiveName,
InitializeSingleHook
(
- new PacketReceiveHook(_underlyingManager.PacketReceive),
+ _underlyingManager.PacketReceive,
+ u => new PacketReceiveHook(u),
options.PacketReceiveHook
)
);
- hooks.Add
+ HandleAdd
(
- _underlyingManager.PacketSend.Name,
+ hooks,
+ IHookManager.PacketSendName,
InitializeSingleHook
(
- new PacketSendHook(_underlyingManager.PacketSend),
+ _underlyingManager.PacketSend,
+ u => new PacketSendHook(u),
options.PacketSendHook
)
);
- hooks.Add
+ HandleAdd
(
- _underlyingManager.PetWalk.Name,
+ hooks,
+ IHookManager.PetWalkName,
InitializeSingleHook
(
- new PetWalkHook(_underlyingManager.PetWalk),
+ _underlyingManager.PetWalk,
+ u => new PetWalkHook(u),
options.PetWalkHook
)
);
- hooks.Add
+ HandleAdd
(
- _underlyingManager.PlayerWalk.Name,
+ hooks,
+ IHookManager.CharacterWalkName,
InitializeSingleHook
(
- new PlayerWalkHook(_underlyingManager.PlayerWalk),
+ _underlyingManager.PlayerWalk,
+ u => new PlayerWalkHook(u),
options.PlayerWalkHook
)
);
- return hooks;
+ return (hooks, result);
}
- private INostaleHook<TFunction, TWrapperFunction, TEventArgs> InitializeSingleHook<TFunction, TWrapperFunction,
- TEventArgs>(SingleHook<TFunction, TWrapperFunction, TEventArgs> hook, HookOptions options)
+ private INostaleHook<TFunction, TWrapperFunction, TEventArgs>? InitializeSingleHook<THook, TFunction,
+ TWrapperFunction,
+ TEventArgs>
+ (
+ Optional<THook> hookOptional,
+ Func<THook, SingleHook<TFunction, TWrapperFunction, TEventArgs>> hookCreator,
+ HookOptions options
+ )
+ where THook : notnull
where TFunction : Delegate
where TWrapperFunction : Delegate
where TEventArgs : System.EventArgs
{
+ if (!hookOptional.TryGet(out var underlyingHook))
+ {
+ return null;
+ }
+
+ var hook = hookCreator(underlyingHook);
hook.StateChanged += (_, state) =>
{
if (!_hookedCount.ContainsKey(hook.Name))
@@ 176,4 201,12 @@ public class SharedHookManager
return hook;
}
+
+ private void HandleAdd(Dictionary<string, INostaleHook> hooks, string name, INostaleHook? hook)
+ {
+ if (hook is not null)
+ {
+ hooks.Add(name, hook);
+ }
+ }
}=
\ No newline at end of file
M src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SingleHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SingleHook.cs +89 -85
@@ 1,86 1,90 @@
-//
-// SingleHook.cs
-//
-// Copyright (c) František Boháček. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System.ComponentModel;
-using NosSmooth.Extensions.SharedBinding.EventArgs;
-using NosSmooth.LocalBinding.Hooks;
-using Remora.Results;
-
-namespace NosSmooth.Extensions.SharedBinding.Hooks;
-
-/// <summary>
-/// A hook for a single instance of NosSmooth sharing with the rest of application.
-/// </summary>
-/// <typeparam name="TFunction">The function delegate.</typeparam>
-/// <typeparam name="TWrapperFunction">A wrapper function that abstracts the call to original function. May get the neccessary object to call the function and accept only relevant arguments.</typeparam>
-/// <typeparam name="TEventArgs">The event args used in case of a call.</typeparam>
-public class SingleHook<TFunction, TWrapperFunction, TEventArgs> : INostaleHook<TFunction, TWrapperFunction, TEventArgs>
- where TFunction : Delegate
- where TWrapperFunction : Delegate
- where TEventArgs : System.EventArgs
-{
- private readonly INostaleHook<TFunction, TWrapperFunction, TEventArgs> _underlyingHook;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="SingleHook{TFunction, TWrapperFunction, TEventArgs}"/> class.
- /// </summary>
- /// <param name="underlyingHook">The underlying hook.</param>
- public SingleHook(INostaleHook<TFunction, TWrapperFunction, TEventArgs> underlyingHook)
- {
- _underlyingHook = underlyingHook;
- }
-
- /// <summary>
- /// Called upon Enable or Disable.
- /// </summary>
- public event EventHandler<HookStateEventArgs>? StateChanged;
-
- /// <inheritdoc />
- public string Name => _underlyingHook.Name;
-
- /// <inheritdoc />
- public bool IsEnabled { get; private set; }
-
- /// <inheritdoc />
- public Result Enable()
- {
- if (!IsEnabled)
- {
- IsEnabled = true;
- StateChanged?.Invoke(this, new HookStateEventArgs(true));
- _underlyingHook.Called += FireCalled;
- }
-
- return Result.FromSuccess();
- }
-
- /// <inheritdoc />
- public Result Disable()
- {
- if (IsEnabled)
- {
- IsEnabled = true;
- StateChanged?.Invoke(this, new HookStateEventArgs(false));
- _underlyingHook.Called -= FireCalled;
- }
-
- return Result.FromSuccess();
- }
-
- private void FireCalled(object? owner, TEventArgs eventArgs)
- {
- Called?.Invoke(this, eventArgs);
- }
-
- /// <inheritdoc />
- public TWrapperFunction WrapperFunction => _underlyingHook.WrapperFunction;
-
- /// <inheritdoc />
- public TFunction OriginalFunction => _underlyingHook.OriginalFunction;
-
- /// <inheritdoc />
- public event EventHandler<TEventArgs>? Called;
+//
+// SingleHook.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.ComponentModel;
+using NosSmooth.Extensions.SharedBinding.EventArgs;
+using NosSmooth.LocalBinding;
+using NosSmooth.LocalBinding.Hooks;
+using Remora.Results;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks;
+
+/// <summary>
+/// A hook for a single instance of NosSmooth sharing with the rest of application.
+/// </summary>
+/// <typeparam name="TFunction">The function delegate.</typeparam>
+/// <typeparam name="TWrapperFunction">A wrapper function that abstracts the call to original function. May get the neccessary object to call the function and accept only relevant arguments.</typeparam>
+/// <typeparam name="TEventArgs">The event args used in case of a call.</typeparam>
+public class SingleHook<TFunction, TWrapperFunction, TEventArgs> : INostaleHook<TFunction, TWrapperFunction, TEventArgs>
+ where TFunction : Delegate
+ where TWrapperFunction : Delegate
+ where TEventArgs : System.EventArgs
+{
+ private readonly INostaleHook<TFunction, TWrapperFunction, TEventArgs> _underlyingHook;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SingleHook{TFunction, TWrapperFunction, TEventArgs}"/> class.
+ /// </summary>
+ /// <param name="underlyingHook">The underlying hook.</param>
+ public SingleHook(INostaleHook<TFunction, TWrapperFunction, TEventArgs> underlyingHook)
+ {
+ _underlyingHook = underlyingHook;
+ }
+
+ /// <summary>
+ /// Called upon Enable or Disable.
+ /// </summary>
+ public event EventHandler<HookStateEventArgs>? StateChanged;
+
+ /// <inheritdoc />
+ public bool IsUsable => _underlyingHook.IsUsable;
+
+ /// <inheritdoc />
+ public string Name => _underlyingHook.Name;
+
+ /// <inheritdoc />
+ public bool IsEnabled { get; private set; }
+
+ /// <inheritdoc />
+ public Result Enable()
+ {
+ if (!IsEnabled)
+ {
+ IsEnabled = true;
+ StateChanged?.Invoke(this, new HookStateEventArgs(true));
+ _underlyingHook.Called += FireCalled;
+ }
+
+ return Result.FromSuccess();
+ }
+
+ /// <inheritdoc />
+ public Result Disable()
+ {
+ if (IsEnabled)
+ {
+ IsEnabled = true;
+ StateChanged?.Invoke(this, new HookStateEventArgs(false));
+ _underlyingHook.Called -= FireCalled;
+ }
+
+ return Result.FromSuccess();
+ }
+
+ private void FireCalled(object? owner, TEventArgs eventArgs)
+ {
+ Called?.Invoke(this, eventArgs);
+ }
+
+ /// <inheritdoc />
+ public Optional<TWrapperFunction> WrapperFunction => _underlyingHook.WrapperFunction;
+
+ /// <inheritdoc />
+ public TFunction OriginalFunction => _underlyingHook.OriginalFunction;
+
+ /// <inheritdoc />
+ public event EventHandler<TEventArgs>? Called;
}=
\ No newline at end of file
M src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SingleHookManager.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SingleHookManager.cs +58 -20
@@ 20,6 20,7 @@ public class SingleHookManager : IHookManager
private readonly SharedHookManager _sharedHookManager;
private readonly HookManagerOptions _options;
private Dictionary<string, INostaleHook> _hooks;
+ private bool _initialized;
/// <summary>
/// Initializes a new instance of the <see cref="SingleHookManager"/> class.
@@ 34,28 35,28 @@ public class SingleHookManager : IHookManager
}
/// <inheritdoc />
- public IPacketSendHook PacketSend => GetHook<IPacketSendHook>(IHookManager.PacketSendName);
+ public Optional<IPacketSendHook> PacketSend => GetHook<IPacketSendHook>(IHookManager.PacketSendName);
/// <inheritdoc />
- public IPacketReceiveHook PacketReceive => GetHook<IPacketReceiveHook>(IHookManager.PacketReceiveName);
+ public Optional<IPacketReceiveHook> PacketReceive => GetHook<IPacketReceiveHook>(IHookManager.PacketReceiveName);
/// <inheritdoc />
- public IPlayerWalkHook PlayerWalk => GetHook<IPlayerWalkHook>(IHookManager.CharacterWalkName);
+ public Optional<IPlayerWalkHook> PlayerWalk => GetHook<IPlayerWalkHook>(IHookManager.CharacterWalkName);
/// <inheritdoc />
- public IEntityFollowHook EntityFollow => GetHook<IEntityFollowHook>(IHookManager.EntityFollowName);
+ public Optional<IEntityFollowHook> EntityFollow => GetHook<IEntityFollowHook>(IHookManager.EntityFollowName);
/// <inheritdoc />
- public IEntityUnfollowHook EntityUnfollow => GetHook<IEntityUnfollowHook>(IHookManager.EntityUnfollowName);
+ public Optional<IEntityUnfollowHook> EntityUnfollow => GetHook<IEntityUnfollowHook>(IHookManager.EntityUnfollowName);
/// <inheritdoc />
- public IPetWalkHook PetWalk => GetHook<IPetWalkHook>(IHookManager.PetWalkName);
+ public Optional<IPetWalkHook> PetWalk => GetHook<IPetWalkHook>(IHookManager.PetWalkName);
/// <inheritdoc />
- public IEntityFocusHook EntityFocus => GetHook<IEntityFocusHook>(IHookManager.EntityFocusName);
+ public Optional<IEntityFocusHook> EntityFocus => GetHook<IEntityFocusHook>(IHookManager.EntityFocusName);
/// <inheritdoc />
- public IPeriodicHook Periodic => GetHook<IPeriodicHook>(IHookManager.PeriodicName);
+ public Optional<IPeriodicHook> Periodic => GetHook<IPeriodicHook>(IHookManager.PeriodicName);
/// <inheritdoc />
public IReadOnlyList<INostaleHook> Hooks => _hooks.Values.ToList();
@@ 63,14 64,10 @@ public class SingleHookManager : IHookManager
/// <inheritdoc />
public IResult Initialize(NosBindingManager bindingManager, NosBrowserManager browserManager)
{
- var hooksResult = _sharedHookManager.InitializeInstance(bindingManager, browserManager, _options);
- if (!hooksResult.IsDefined(out var hooks))
- {
- return hooksResult;
- }
-
+ _initialized = true;
+ var (hooks, result) = _sharedHookManager.InitializeInstance(bindingManager, browserManager, _options);
_hooks = hooks;
- return Result.FromSuccess();
+ return result;
}
/// <inheritdoc />
@@ 79,7 76,7 @@ public class SingleHookManager : IHookManager
foreach (var name in names)
{
var hook = GetHook<INostaleHook>(name);
- hook.Enable();
+ hook.TryDo(h => h.Enable());
}
}
@@ 89,7 86,7 @@ public class SingleHookManager : IHookManager
foreach (var name in names)
{
var hook = GetHook<INostaleHook>(name);
- hook.Disable();
+ hook.TryDo(h => h.Disable());
}
}
@@ 111,15 108,56 @@ public class SingleHookManager : IHookManager
}
}
- private T GetHook<T>(string name)
+ /// <inheritdoc/>
+ public bool IsHookLoaded<THook>()
+ where THook : INostaleHook
+ => IsHookLoaded(typeof(THook));
+
+ /// <inheritdoc/>
+ public bool IsHookUsable<THook>()
+ where THook : INostaleHook
+ => IsHookUsable(typeof(THook));
+
+ /// <inheritdoc/>
+ public bool IsHookLoaded(Type hookType)
+ => GetHook(hookType).IsPresent;
+
+ /// <inheritdoc/>
+ public bool IsHookUsable(Type hookType)
+ => GetHook(hookType).TryGet(out var h) && h.IsUsable;
+
+ private Optional<T> GetHook<T>(string name)
where T : INostaleHook
{
- if (!_hooks.ContainsKey(name) || _hooks[name] is not T typed)
+ if (!_initialized)
{
throw new InvalidOperationException
- ($"Could not load hook {name}. Did you forget to call IHookManager.Initialize?");
+ ($"Could not load hook {typeof(T)}. Did you forget to call IHookManager.Initialize?");
+ }
+
+ var hook = _hooks.Values.FirstOrDefault(x => x is T);
+ if (hook is not T typed)
+ {
+ return Optional<T>.Empty;
}
return typed;
}
+
+ private Optional<INostaleHook> GetHook(Type hookType)
+ {
+ if (!_initialized)
+ {
+ throw new InvalidOperationException
+ ($"Could not load hook {hookType.Name}. Did you forget to call IHookManager.Initialize?");
+ }
+
+ var hook = _hooks.Values.FirstOrDefault(x => x.GetType() == hookType);
+ if (hook is null)
+ {
+ return Optional<INostaleHook>.Empty;
+ }
+
+ return new Optional<INostaleHook>(hook);
+ }
}=
\ No newline at end of file
M src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PeriodicHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PeriodicHook.cs +26 -25
@@ 1,26 1,27 @@
-//
-// PeriodicHook.cs
-//
-// Copyright (c) František Boháček. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using NosSmooth.LocalBinding.Hooks;
-
-namespace NosSmooth.Extensions.SharedBinding.Hooks.Specific;
-
-/// <summary>
-/// A hook of a periodic function,
-/// preferably called every frame.
-/// </summary>
-internal class PeriodicHook :
- SingleHook<IPeriodicHook.PeriodicDelegate, IPeriodicHook.PeriodicDelegate, System.EventArgs>, IPeriodicHook
-{
- /// <summary>
- /// Initializes a new instance of the <see cref="PeriodicHook"/> class.
- /// </summary>
- /// <param name="underlyingHook">The underlying hook.</param>
- public PeriodicHook(INostaleHook<IPeriodicHook.PeriodicDelegate, IPeriodicHook.PeriodicDelegate, System.EventArgs> underlyingHook)
- : base(underlyingHook)
- {
- }
+//
+// PeriodicHook.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using NosSmooth.LocalBinding;
+using NosSmooth.LocalBinding.Hooks;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks.Specific;
+
+/// <summary>
+/// A hook of a periodic function,
+/// preferably called every frame.
+/// </summary>
+internal class PeriodicHook :
+ SingleHook<IPeriodicHook.PeriodicDelegate, IPeriodicHook.PeriodicDelegate, System.EventArgs>, IPeriodicHook
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PeriodicHook"/> class.
+ /// </summary>
+ /// <param name="underlyingHook">The underlying hook.</param>
+ public PeriodicHook(INostaleHook<IPeriodicHook.PeriodicDelegate, IPeriodicHook.PeriodicDelegate, System.EventArgs> underlyingHook)
+ : base(underlyingHook)
+ {
+ }
}=
\ No newline at end of file