// // SharedHookManager.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.Extensions.SharedBinding.Hooks.Specific; using NosSmooth.LocalBinding; using NosSmooth.LocalBinding.Hooks; using NosSmooth.LocalBinding.Options; using Remora.Results; namespace NosSmooth.Extensions.SharedBinding.Hooks; /// /// A hook manager managing s of all of the instances. /// public class SharedHookManager { private readonly IHookManager _underlyingManager; private bool _initialized; private Dictionary _hookedCount; /// /// Initializes a new instance of the class. /// /// The underlying hook manager. public SharedHookManager ( IHookManager underlyingManager ) { _hookedCount = new Dictionary(); _underlyingManager = underlyingManager; } /// /// Initialize a shared NosSmooth instance. /// /// The binding manager. /// The browser manager. /// The initial options to be respected. /// The dictionary containing all of the hooks. public (Dictionary, IResult) InitializeInstance (NosBindingManager bindingManager, NosBrowserManager browserManager, HookManagerOptions options) { IResult result = Result.FromSuccess(); if (!_initialized) { result = _underlyingManager.Initialize(bindingManager, browserManager); _initialized = true; } var hooks = new Dictionary(); // TODO: initialize using reflection HandleAdd ( hooks, IHookManager.PeriodicName, InitializeSingleHook ( _underlyingManager.Periodic, u => new PeriodicHook(u), options.PeriodicHook ) ); HandleAdd ( hooks, IHookManager.EntityFocusName, InitializeSingleHook ( _underlyingManager.EntityFocus, u => new EntityFocusHook(u), options.EntityFocusHook ) ); HandleAdd ( hooks, IHookManager.EntityFollowName, InitializeSingleHook ( _underlyingManager.EntityFollow, u => new EntityFollowHook(u), options.EntityFollowHook ) ); HandleAdd ( hooks, IHookManager.EntityUnfollowName, InitializeSingleHook ( _underlyingManager.EntityUnfollow, u => new EntityUnfollowHook(u), options.EntityUnfollowHook ) ); HandleAdd ( hooks, IHookManager.PacketReceiveName, InitializeSingleHook ( _underlyingManager.PacketReceive, u => new PacketReceiveHook(u), options.PacketReceiveHook ) ); HandleAdd ( hooks, IHookManager.PacketSendName, InitializeSingleHook ( _underlyingManager.PacketSend, u => new PacketSendHook(u), options.PacketSendHook ) ); HandleAdd ( hooks, IHookManager.PetWalkName, InitializeSingleHook ( _underlyingManager.PetWalk, u => new PetWalkHook(u), options.PetWalkHook ) ); HandleAdd ( hooks, IHookManager.CharacterWalkName, InitializeSingleHook ( _underlyingManager.PlayerWalk, u => new PlayerWalkHook(u), options.PlayerWalkHook ) ); return (hooks, result); } private INostaleHook? InitializeSingleHook ( Optional hookOptional, Func> 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)) { _hookedCount[hook.Name] = 0; } _hookedCount[hook.Name] += state.Enabled ? 1 : -1; if (state.Enabled) { _underlyingManager.Enable(new[] { hook.Name }); } else if (_hookedCount[hook.Name] == 0) { _underlyingManager.Disable(new[] { hook.Name }); } }; if (options.Hook) { hook.Enable(); } return hook; } private void HandleAdd(Dictionary hooks, string name, INostaleHook? hook) { if (hook is not null) { hooks.Add(name, hook); } } }