A src/Extensions/NosSmooth.Extensions.SharedBinding/EventArgs/HookStateEventArgs.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/EventArgs/HookStateEventArgs.cs +25 -0
@@ 0,0 1,25 @@
+//
+// HookStateEventArgs.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.
+
+namespace NosSmooth.Extensions.SharedBinding.EventArgs;
+
+/// <inheritdoc />
+public class HookStateEventArgs : System.EventArgs
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HookStateEventArgs"/> class.
+ /// </summary>
+ /// <param name="enabled">The new state.</param>
+ public HookStateEventArgs(bool enabled)
+ {
+ Enabled = enabled;
+ }
+
+ /// <summary>
+ /// Gets the new state.
+ /// </summary>
+ public bool Enabled { get; }
+}<
\ No newline at end of file
M src/Extensions/NosSmooth.Extensions.SharedBinding/Extensions/ServiceCollectionExtensions.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Extensions/ServiceCollectionExtensions.cs +42 -40
@@ 4,10 4,13 @@
// 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.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NosSmooth.Data.NOSFiles;
+using NosSmooth.Extensions.SharedBinding.Hooks;
using NosSmooth.LocalBinding;
+using NosSmooth.LocalBinding.Hooks;
using NosSmooth.PacketSerializer.Packets;
namespace NosSmooth.Extensions.SharedBinding.Extensions;
@@ 18,81 21,80 @@ namespace NosSmooth.Extensions.SharedBinding.Extensions;
public static class ServiceCollectionExtensions
{
/// <summary>
- /// Replaces <see cref="NosBindingManager"/>
- /// with shared equivalent. That allows for multiple programs injected inside NosTale.
+ /// Adds shared <see cref="IHookManager"/>.
/// </summary>
/// <param name="serviceCollection">The collection.</param>
/// <returns>The same collection.</returns>
- public static IServiceCollection ShareBinding(this IServiceCollection serviceCollection)
+ public static IServiceCollection ShareHooks(this IServiceCollection serviceCollection)
{
var original = serviceCollection
- .Last(x => x.ServiceType == typeof(NosBindingManager));
+ .Last(x => x.ServiceType == typeof(IHookManager));
+ serviceCollection.Configure<SharedOptions>(o => o.AddDescriptor(original));
return serviceCollection
- .Configure<SharedOptions>(o => o.BindingDescriptor = original)
- .Replace
- (ServiceDescriptor.Singleton<NosBindingManager>(p => SharedManager.Instance.GetNosBindingManager(p)));
+ .AddSingleton<SharedHookManager>
+ (
+ p =>
+ {
+ var sharedHookManager = p.GetRequiredService<SharedManager>().GetShared<IHookManager>(p);
+ return new SharedHookManager(sharedHookManager);
+ }
+ )
+ .Replace(ServiceDescriptor.Singleton<IHookManager, SingleHookManager>());
}
/// <summary>
- /// Replaces <see cref="NostaleDataFilesManager"/>
+ /// Replaces <typeparamref name="T"/>
/// with shared equivalent. That allows for multiple programs injected inside NosTale.
/// </summary>
/// <param name="serviceCollection">The collection.</param>
+ /// <typeparam name="T">The shared type.</typeparam>
/// <returns>The same collection.</returns>
- public static IServiceCollection ShareFileManager(this IServiceCollection serviceCollection)
+ public static IServiceCollection Share<T>(this IServiceCollection serviceCollection)
+ where T : class
{
var original = serviceCollection
- .Last(x => x.ServiceType == typeof(NostaleDataFilesManager));
+ .Last(x => x.ServiceType == typeof(T));
return serviceCollection
- .Configure<SharedOptions>(o => o.FileDescriptor = original)
+ .Configure<SharedOptions>(o => o.AddDescriptor(original))
.Replace
- (ServiceDescriptor.Singleton<NostaleDataFilesManager>(p => SharedManager.Instance.GetFilesManager(p)));
+ (
+ ServiceDescriptor.Singleton<T>(p => SharedManager.Instance.GetShared<T>(p))
+ );
}
/// <summary>
- /// Replaces <see cref="IPacketTypesRepository"/>
+ /// Tries to replace <see cref="T"/>
/// with shared equivalent. That allows for multiple programs injected inside NosTale.
/// </summary>
/// <param name="serviceCollection">The collection.</param>
+ /// <typeparam name="T">The shared type.</typeparam>
/// <returns>The same collection.</returns>
- public static IServiceCollection SharePacketRepository(this IServiceCollection serviceCollection)
+ public static IServiceCollection TryShare<T>(this IServiceCollection serviceCollection)
+ where T : class
{
- var original = serviceCollection
- .Last(x => x.ServiceType == typeof(IPacketTypesRepository));
+ if (serviceCollection.Any(x => x.ServiceType == typeof(T)))
+ {
+ return serviceCollection.Share<T>();
+ }
- return serviceCollection
- .Configure<SharedOptions>(o => o.PacketRepositoryDescriptor = original)
- .Replace
- (
- ServiceDescriptor.Singleton<IPacketTypesRepository>(p => SharedManager.Instance.GetPacketRepository(p))
- );
+ return serviceCollection;
}
/// <summary>
- /// Replaces <see cref="NosBindingManager"/>, <see cref="NostaleDataFilesManager"/> and <see cref="IPacketTypesRepository"/>
- /// with their shared equvivalents. That allows for multiple programs injected inside NosTale.
+ /// Replaces some NosSmooth types with their shared equivalents.
+ /// That allows for multiple programs injected inside NosTale.
/// </summary>
/// <param name="serviceCollection">The collection.</param>
/// <returns>The same collection.</returns>
public static IServiceCollection ShareNosSmooth(this IServiceCollection serviceCollection)
{
- if (serviceCollection.Any(x => x.ServiceType == typeof(NosBindingManager)))
- {
- serviceCollection.ShareBinding();
- }
-
- if (serviceCollection.Any(x => x.ServiceType == typeof(NostaleDataFilesManager)))
- {
- serviceCollection.ShareFileManager();
- }
-
- if (serviceCollection.Any(x => x.ServiceType == typeof(IPacketTypesRepository)))
- {
- serviceCollection.SharePacketRepository();
- }
-
- return serviceCollection;
+ return serviceCollection
+ .AddSingleton<SharedManager>(p => SharedManager.Instance)
+ .ShareHooks()
+ .TryShare<NosBrowserManager>()
+ .TryShare<IPacketTypesRepository>()
+ .TryShare<NostaleDataFilesManager>();
}
}=
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SharedHookManager.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SharedHookManager.cs +174 -0
@@ 0,0 1,174 @@
+//
+// 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;
+
+/// <summary>
+/// A hook manager managing <see cref="SingleHookManager"/>s of all of the instances.
+/// </summary>
+public class SharedHookManager
+{
+ private readonly IHookManager _underlyingManager;
+
+ private bool _initialized;
+ private Dictionary<string, int> _hookedCount;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SharedHookManager"/> class.
+ /// </summary>
+ /// <param name="underlyingManager">The underlying hook manager.</param>
+ /// <param name="bindingManager">The binding manager.</param>
+ /// <param name="browserManager">The browser manager.</param>
+ public SharedHookManager
+ (
+ IHookManager underlyingManager
+ )
+ {
+ _hookedCount = new Dictionary<string, int>();
+ _underlyingManager = underlyingManager;
+ }
+
+ /// <summary>
+ /// Initialize a shared NosSmooth instance.
+ /// </summary>
+ /// <param name="bindingManager">The binding manager.</param>
+ /// <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
+ (NosBindingManager bindingManager, NosBrowserManager browserManager, HookManagerOptions options)
+ {
+ if (!_initialized)
+ {
+ _underlyingManager.Initialize(bindingManager, browserManager);
+ _initialized = true;
+ }
+
+ var hooks = new Dictionary<string, INostaleHook>();
+
+ // TODO: initialize using reflection
+ hooks.Add
+ (
+ _underlyingManager.Periodic.Name,
+ InitializeSingleHook
+ (
+ new PeriodicHook(_underlyingManager.Periodic),
+ options.PeriodicHook
+ )
+ );
+
+ hooks.Add
+ (
+ _underlyingManager.EntityFocus.Name,
+ InitializeSingleHook
+ (
+ new EntityFocusHook(_underlyingManager.EntityFocus),
+ options.EntityFocusHook
+ )
+ );
+
+ hooks.Add
+ (
+ _underlyingManager.EntityFollow.Name,
+ InitializeSingleHook
+ (
+ new EntityFollowHook(_underlyingManager.EntityFollow),
+ options.EntityFollowHook
+ )
+ );
+
+ hooks.Add
+ (
+ _underlyingManager.EntityUnfollow.Name,
+ InitializeSingleHook
+ (
+ new EntityUnfollowHook(_underlyingManager.EntityUnfollow),
+ options.EntityUnfollowHook
+ )
+ );
+
+ hooks.Add
+ (
+ _underlyingManager.PacketReceive.Name,
+ InitializeSingleHook
+ (
+ new PacketReceiveHook(_underlyingManager.PacketReceive),
+ options.PacketReceiveHook
+ )
+ );
+
+ hooks.Add
+ (
+ _underlyingManager.PacketSend.Name,
+ InitializeSingleHook
+ (
+ new PacketSendHook(_underlyingManager.PacketSend),
+ options.PacketSendHook
+ )
+ );
+
+ hooks.Add
+ (
+ _underlyingManager.PetWalk.Name,
+ InitializeSingleHook
+ (
+ new PetWalkHook(_underlyingManager.PetWalk),
+ options.PetWalkHook
+ )
+ );
+
+ hooks.Add
+ (
+ _underlyingManager.PlayerWalk.Name,
+ InitializeSingleHook
+ (
+ new PlayerWalkHook(_underlyingManager.PlayerWalk),
+ options.PlayerWalkHook
+ )
+ );
+
+ return hooks;
+ }
+
+ private INostaleHook<TFunction, TWrapperFunction, TEventArgs> InitializeSingleHook<TFunction, TWrapperFunction,
+ TEventArgs>(SingleHook<TFunction, TWrapperFunction, TEventArgs> hook, HookOptions options)
+ where TFunction : Delegate
+ where TWrapperFunction : Delegate
+ where TEventArgs : System.EventArgs
+ {
+ 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;
+ }
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SingleHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SingleHook.cs +86 -0
@@ 0,0 1,86 @@
+//
+// 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;
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SingleHookManager.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/SingleHookManager.cs +125 -0
@@ 0,0 1,125 @@
+//
+// SingleHookManager.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 Microsoft.Extensions.Options;
+using NosSmooth.LocalBinding;
+using NosSmooth.LocalBinding.Hooks;
+using NosSmooth.LocalBinding.Options;
+using Remora.Results;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks;
+
+/// <summary>
+/// A hook manager for a single NosSmooth instance using shared data.
+/// </summary>
+public class SingleHookManager : IHookManager
+{
+ private readonly SharedHookManager _sharedHookManager;
+ private readonly HookManagerOptions _options;
+ private Dictionary<string, INostaleHook> _hooks;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SingleHookManager"/> class.
+ /// </summary>
+ /// <param name="sharedHookManager">The shared hook manager.</param>
+ /// <param name="options">The hook options.</param>
+ public SingleHookManager(SharedHookManager sharedHookManager, IOptions<HookManagerOptions> options)
+ {
+ _hooks = new Dictionary<string, INostaleHook>();
+ _sharedHookManager = sharedHookManager;
+ _options = options.Value;
+ }
+
+ /// <inheritdoc />
+ public IPacketSendHook PacketSend => GetHook<IPacketSendHook>(IHookManager.PacketSendName);
+
+ /// <inheritdoc />
+ public IPacketReceiveHook PacketReceive => GetHook<IPacketReceiveHook>(IHookManager.PacketReceiveName);
+
+ /// <inheritdoc />
+ public IPlayerWalkHook PlayerWalk => GetHook<IPlayerWalkHook>(IHookManager.CharacterWalkName);
+
+ /// <inheritdoc />
+ public IEntityFollowHook EntityFollow => GetHook<IEntityFollowHook>(IHookManager.EntityFollowName);
+
+ /// <inheritdoc />
+ public IEntityUnfollowHook EntityUnfollow => GetHook<IEntityUnfollowHook>(IHookManager.EntityUnfollowName);
+
+ /// <inheritdoc />
+ public IPetWalkHook PetWalk => GetHook<IPetWalkHook>(IHookManager.PetWalkName);
+
+ /// <inheritdoc />
+ public IEntityFocusHook EntityFocus => GetHook<IEntityFocusHook>(IHookManager.EntityFocusName);
+
+ /// <inheritdoc />
+ public IPeriodicHook Periodic => GetHook<IPeriodicHook>(IHookManager.PeriodicName);
+
+ /// <inheritdoc />
+ public IReadOnlyList<INostaleHook> Hooks => _hooks.Values.ToList();
+
+ /// <inheritdoc />
+ public IResult Initialize(NosBindingManager bindingManager, NosBrowserManager browserManager)
+ {
+ var hooksResult = _sharedHookManager.InitializeInstance(bindingManager, browserManager, _options);
+ if (!hooksResult.IsDefined(out var hooks))
+ {
+ return hooksResult;
+ }
+
+ _hooks = hooks;
+ return Result.FromSuccess();
+ }
+
+ /// <inheritdoc />
+ public void Enable(IEnumerable<string> names)
+ {
+ foreach (var name in names)
+ {
+ var hook = GetHook<INostaleHook>(name);
+ hook.Enable();
+ }
+ }
+
+ /// <inheritdoc />
+ public void Disable(IEnumerable<string> names)
+ {
+ foreach (var name in names)
+ {
+ var hook = GetHook<INostaleHook>(name);
+ hook.Disable();
+ }
+ }
+
+ /// <inheritdoc />
+ public void DisableAll()
+ {
+ foreach (var hook in _hooks.Values)
+ {
+ hook.Disable();
+ }
+ }
+
+ /// <inheritdoc />
+ public void EnableAll()
+ {
+ foreach (var hook in _hooks.Values)
+ {
+ hook.Enable();
+ }
+ }
+
+ private T GetHook<T>(string name)
+ where T : INostaleHook
+ {
+ if (!_hooks.ContainsKey(name) || _hooks[name] is not T typed)
+ {
+ throw new InvalidOperationException
+ ($"Could not load hook {name}. Did you forget to call IHookManager.Initialize?");
+ }
+
+ return typed;
+ }
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/EntityFocusHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/EntityFocusHook.cs +24 -0
@@ 0,0 1,24 @@
+//
+// EntityFocusHook.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.EventArgs;
+using NosSmooth.LocalBinding.Hooks;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks.Specific;
+
+/// <inheritdoc />
+internal class EntityFocusHook : SingleHook<IEntityFocusHook.EntityFocusDelegate,
+ IEntityFocusHook.EntityFocusWrapperDelegate, EntityEventArgs>, IEntityFocusHook
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EntityFocusHook"/> class.
+ /// </summary>
+ /// <param name="underlyingHook">The underlying hook.</param>
+ public EntityFocusHook(INostaleHook<IEntityFocusHook.EntityFocusDelegate, IEntityFocusHook.EntityFocusWrapperDelegate, EntityEventArgs> underlyingHook)
+ : base(underlyingHook)
+ {
+ }
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/EntityFollowHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/EntityFollowHook.cs +24 -0
@@ 0,0 1,24 @@
+//
+// EntityFollowHook.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.EventArgs;
+using NosSmooth.LocalBinding.Hooks;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks.Specific;
+
+/// <inheritdoc />
+internal class EntityFollowHook : SingleHook<IEntityFollowHook.EntityFollowDelegate,
+ IEntityFollowHook.EntityFollowWrapperDelegate, EntityEventArgs>, IEntityFollowHook
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EntityFollowHook"/> class.
+ /// </summary>
+ /// <param name="underlyingHook">The underlying hook.</param>
+ public EntityFollowHook(INostaleHook<IEntityFollowHook.EntityFollowDelegate, IEntityFollowHook.EntityFollowWrapperDelegate, EntityEventArgs> underlyingHook)
+ : base(underlyingHook)
+ {
+ }
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/EntityUnfollowHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/EntityUnfollowHook.cs +24 -0
@@ 0,0 1,24 @@
+//
+// EntityUnfollowHook.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.EventArgs;
+using NosSmooth.LocalBinding.Hooks;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks.Specific;
+
+/// <inheritdoc />
+internal class EntityUnfollowHook : SingleHook<IEntityUnfollowHook.EntityUnfollowDelegate,
+ IEntityUnfollowHook.EntityUnfollowWrapperDelegate, EntityEventArgs>, IEntityUnfollowHook
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EntityUnfollowHook"/> class.
+ /// </summary>
+ /// <param name="underlyingHook">The underlying hook.</param>
+ public EntityUnfollowHook(INostaleHook<IEntityUnfollowHook.EntityUnfollowDelegate, IEntityUnfollowHook.EntityUnfollowWrapperDelegate, EntityEventArgs> underlyingHook)
+ : base(underlyingHook)
+ {
+ }
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PacketReceiveHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PacketReceiveHook.cs +24 -0
@@ 0,0 1,24 @@
+//
+// PacketReceiveHook.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.EventArgs;
+using NosSmooth.LocalBinding.Hooks;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks.Specific;
+
+/// <inheritdoc />
+internal class PacketReceiveHook : SingleHook<IPacketReceiveHook.PacketReceiveDelegate,
+ IPacketReceiveHook.PacketReceiveWrapperDelegate, PacketEventArgs>, IPacketReceiveHook
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PacketReceiveHook"/> class.
+ /// </summary>
+ /// <param name="underlyingHook">The underlying hook.</param>
+ public PacketReceiveHook(INostaleHook<IPacketReceiveHook.PacketReceiveDelegate, IPacketReceiveHook.PacketReceiveWrapperDelegate, PacketEventArgs> underlyingHook)
+ : base(underlyingHook)
+ {
+ }
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PacketSendHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PacketSendHook.cs +24 -0
@@ 0,0 1,24 @@
+//
+// PacketSendHook.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.EventArgs;
+using NosSmooth.LocalBinding.Hooks;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks.Specific;
+
+/// <inheritdoc />
+internal class PacketSendHook : SingleHook<IPacketSendHook.PacketSendDelegate,
+ IPacketSendHook.PacketSendWrapperDelegate, PacketEventArgs>, IPacketSendHook
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PacketSendHook"/> class.
+ /// </summary>
+ /// <param name="underlyingHook">The underlying hook.</param>
+ public PacketSendHook(INostaleHook<IPacketSendHook.PacketSendDelegate, IPacketSendHook.PacketSendWrapperDelegate, PacketEventArgs> underlyingHook)
+ : base(underlyingHook)
+ {
+ }
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PeriodicHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PeriodicHook.cs +26 -0
@@ 0,0 1,26 @@
+//
+// 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)
+ {
+ }
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PetWalkHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PetWalkHook.cs +23 -0
@@ 0,0 1,23 @@
+//
+// PetWalkHook.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.EventArgs;
+using NosSmooth.LocalBinding.Hooks;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks.Specific;
+
+/// <inheritdoc />
+internal class PetWalkHook : SingleHook<IPetWalkHook.PetWalkDelegate, IPetWalkHook.PetWalkWrapperDelegate, PetWalkEventArgs>, IPetWalkHook
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PetWalkHook"/> class.
+ /// </summary>
+ /// <param name="underlyingHook">The underlying hook.</param>
+ public PetWalkHook(INostaleHook<IPetWalkHook.PetWalkDelegate, IPetWalkHook.PetWalkWrapperDelegate, PetWalkEventArgs> underlyingHook)
+ : base(underlyingHook)
+ {
+ }
+}<
\ No newline at end of file
A src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PlayerWalkHook.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/Hooks/Specific/PlayerWalkHook.cs +23 -0
@@ 0,0 1,23 @@
+//
+// PlayerWalkHook.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.EventArgs;
+using NosSmooth.LocalBinding.Hooks;
+
+namespace NosSmooth.Extensions.SharedBinding.Hooks.Specific;
+
+/// <inheritdoc />
+internal class PlayerWalkHook : SingleHook<IPlayerWalkHook.WalkDelegate, IPlayerWalkHook.WalkWrapperDelegate, WalkEventArgs>, IPlayerWalkHook
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PlayerWalkHook"/> class.
+ /// </summary>
+ /// <param name="underlyingHook">The underlying hook.</param>
+ public PlayerWalkHook(INostaleHook<IPlayerWalkHook.WalkDelegate, IPlayerWalkHook.WalkWrapperDelegate, WalkEventArgs> underlyingHook)
+ : base(underlyingHook)
+ {
+ }
+}<
\ No newline at end of file
M src/Extensions/NosSmooth.Extensions.SharedBinding/NosSmooth.Extensions.SharedBinding.csproj => src/Extensions/NosSmooth.Extensions.SharedBinding/NosSmooth.Extensions.SharedBinding.csproj +1 -0
@@ 7,6 7,7 @@
</PropertyGroup>
<ItemGroup>
+ <PackageReference Include="NosSmooth.Core" Version="3.0.1" />
<PackageReference Include="NosSmooth.Data.NOSFiles" Version="2.0.2" />
<PackageReference Include="NosSmooth.PacketSerializer" Version="2.0.0" />
</ItemGroup>
M src/Extensions/NosSmooth.Extensions.SharedBinding/SharedManager.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/SharedManager.cs +14 -41
@@ 20,9 20,7 @@ namespace NosSmooth.Extensions.SharedBinding;
public class SharedManager
{
private static SharedManager? _instance;
- private NosBindingManager? _bindingManager;
- private NostaleDataFilesManager? _filesManager;
- private IPacketTypesRepository? _packetRepository;
+ private Dictionary<Type, object> _sharedData = new();
/// <summary>
/// A singleton instance.
@@ 41,58 39,33 @@ public class SharedManager
}
}
- /// <summary>
- /// Gets the shared nos binding manager.
- /// </summary>
- /// <param name="services">The service provider.</param>
- /// <returns>The shared manager.</returns>
- public NosBindingManager GetNosBindingManager(IServiceProvider services)
- {
- if (_bindingManager is null)
- {
- _bindingManager = GetFromDescriptor<NosBindingManager>(services, o => o.BindingDescriptor);
- }
-
- return _bindingManager;
-
- }
-
- /// <summary>
- /// Gets the shared file manager.
- /// </summary>
- /// <param name="services">The service provider.</param>
- /// <returns>The shared manager.</returns>
- public NostaleDataFilesManager GetFilesManager(IServiceProvider services)
+ private SharedManager()
{
- if (_filesManager is null)
- {
- _filesManager = GetFromDescriptor<NostaleDataFilesManager>(services, o => o.FileDescriptor);
- }
-
- return _filesManager;
-
}
/// <summary>
- /// Gets the shared packet type repository.
+ /// Get shared equivalent of the given type.
/// </summary>
/// <param name="services">The service provider.</param>
- /// <returns>The shared repository.</returns>
- public IPacketTypesRepository GetPacketRepository(IServiceProvider services)
+ /// <typeparam name="T">The type to get shared instance of.</typeparam>
+ /// <returns>The shared instance.</returns>
+ /// <exception cref="InvalidOperationException">Thrown in case the type is not shared.</exception>
+ public T GetShared<T>(IServiceProvider services)
+ where T : class
{
- if (_packetRepository is null)
+ if (!_sharedData.ContainsKey(typeof(T)))
{
- _packetRepository = GetFromDescriptor<IPacketTypesRepository>(services, o => o.PacketRepositoryDescriptor);
+ _sharedData[typeof(T)] = CreateShared<T>(services);
}
- return _packetRepository;
-
+ return (T)_sharedData[typeof(T)];
}
- private T GetFromDescriptor<T>(IServiceProvider services, Func<SharedOptions, ServiceDescriptor?> getDescriptor)
+ private T CreateShared<T>(IServiceProvider services)
+ where T : class
{
var options = services.GetRequiredService<IOptions<SharedOptions>>();
- var descriptor = getDescriptor(options.Value);
+ var descriptor = options.Value.GetDescriptor(typeof(T));
if (descriptor is null)
{
M src/Extensions/NosSmooth.Extensions.SharedBinding/SharedOptions.cs => src/Extensions/NosSmooth.Extensions.SharedBinding/SharedOptions.cs +20 -8
@@ 16,18 16,30 @@ namespace NosSmooth.Extensions.SharedBinding;
/// </summary>
internal class SharedOptions
{
- /// <summary>
- /// Gets or sets the original descriptor of <see cref="NosBindingManager"/>.
- /// </summary>
- public ServiceDescriptor? BindingDescriptor { get; set; }
+ private Dictionary<Type, ServiceDescriptor> _descriptors = new();
/// <summary>
- /// Gets or sets the original descriptor of <see cref="NostaleDataFilesManager"/>.
+ /// Add service descriptor for given type.
/// </summary>
- public ServiceDescriptor? FileDescriptor { get; set; }
+ /// <param name="descriptor">The service descriptor.</param>
+ public void AddDescriptor(ServiceDescriptor descriptor)
+ {
+ var type = descriptor.ServiceType;
+ if (_descriptors.ContainsKey(type))
+ {
+ return;
+ }
+
+ _descriptors[type] = descriptor;
+ }
/// <summary>
- /// Gets or sets the original descriptor of <see cref="IPacketTypesRepository"/>.
+ /// Get descriptor for the given type.
/// </summary>
- public ServiceDescriptor? PacketRepositoryDescriptor { get; set; }
+ /// <param name="type">The type of the descriptor.</param>
+ /// <returns>A descriptor.</returns>
+ public ServiceDescriptor GetDescriptor(Type type)
+ {
+ return _descriptors[type];
+ }
}=
\ No newline at end of file