// // HookManager.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.Diagnostics; using Microsoft.Extensions.Options; using NosSmooth.LocalBinding.Options; using Remora.Results; namespace NosSmooth.LocalBinding.Hooks.Implementations; /// internal class HookManager : IHookManager { private readonly HookManagerOptions _options; private List _hooks; /// /// Initializes a new instance of the class. /// /// The hook manager options. public HookManager(IOptions options) { _options = options.Value; _hooks = new List(); } /// public IPacketSendHook PacketSend => GetHook(IHookManager.PacketSendName); /// public IPacketReceiveHook PacketReceive => GetHook(IHookManager.PacketReceiveName); /// public IPlayerWalkHook PlayerWalk => GetHook(IHookManager.CharacterWalkName); /// public IEntityFollowHook EntityFollow => GetHook(IHookManager.EntityFollowName); /// public IEntityUnfollowHook EntityUnfollow => GetHook(IHookManager.EntityUnfollowName); /// public IPetWalkHook PetWalk => GetHook(IHookManager.PetWalkName); /// public IEntityFocusHook EntityFocus => GetHook(IHookManager.EntityFocusName); /// public IPeriodicHook Periodic => GetHook(IHookManager.PeriodicName); /// public IReadOnlyList Hooks => _hooks.AsReadOnly(); /// public IResult Initialize(NosBindingManager bindingManager, NosBrowserManager browserManager) { if (_hooks.Count > 0) { // already initialized return Result.FromSuccess(); } return HandleResults ( () => PeriodicHook.Create(bindingManager, _options.PeriodicHook).Map(MapHook), () => EntityFocusHook.Create(bindingManager, browserManager, _options.EntityFocusHook).Map(MapHook), () => EntityFollowHook.Create(bindingManager, browserManager, _options.EntityFollowHook).Map(MapHook), () => EntityUnfollowHook.Create(bindingManager, browserManager, _options.EntityUnfollowHook).Map(MapHook), () => PlayerWalkHook.Create(bindingManager, browserManager, _options.PlayerWalkHook).Map(MapHook), () => PetWalkHook.Create(bindingManager, _options.PetWalkHook).Map(MapHook), () => PacketSendHook.Create(bindingManager, browserManager, _options.PacketSendHook).Map(MapHook), () => PacketReceiveHook.Create(bindingManager, browserManager, _options.PacketReceiveHook).Map(MapHook) ); } private INostaleHook MapHook(T original) where T : INostaleHook { return original; } private IResult HandleResults(params Func>[] functions) { List errorResults = new List(); foreach (var func in functions) { try { var result = func(); if (result.IsSuccess) { _hooks.Add(result.Entity); } else { errorResults.Add(result); } } catch (Exception e) { errorResults.Add((Result)e); } } return errorResults.Count switch { 0 => Result.FromSuccess(), 1 => errorResults[0], _ => (Result)new AggregateError(errorResults) }; } /// public void Enable(IEnumerable names) { foreach (var hook in Hooks .Where(x => names.Contains(x.Name))) { hook.Enable(); } } /// public void Disable(IEnumerable names) { foreach (var hook in Hooks .Where(x => names.Contains(x.Name))) { hook.Disable(); } } /// public void DisableAll() { foreach (var hook in Hooks) { hook.Disable(); } } /// public void EnableAll() { foreach (var hook in Hooks) { hook.Enable(); } } private T GetHook(string name) where T : INostaleHook { var hook = _hooks.FirstOrDefault(x => x.Name == name); if (hook is null || hook is not T typed) { throw new InvalidOperationException ($"Could not load hook {name}. Did you forget to call IHookManager.Initialize?"); } return typed; } }