A Local/NosSmooth.LocalBinding/Errors/BindingNotFoundError.cs => Local/NosSmooth.LocalBinding/Errors/BindingNotFoundError.cs +17 -0
@@ 0,0 1,17 @@
+//
+// BindingNotFoundError.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 Remora.Results;
+
+namespace NosSmooth.LocalBinding.Errors;
+
+/// <summary>
+/// The memory pattern was not found in the memory.
+/// </summary>
+/// <param name="Pattern">The pattern that could not be found.</param>
+/// <param name="Path">The entity the pattern should represent.</param>
+public record BindingNotFoundError(string Pattern, string Path)
+ : ResultError($"Could not find pattern ({Pattern}) in the memory while searching for {Path}.");
A Local/NosSmooth.LocalBinding/Extensions/ServiceCollectionExtensions.cs => Local/NosSmooth.LocalBinding/Extensions/ServiceCollectionExtensions.cs +35 -0
@@ 0,0 1,35 @@
+//
+// ServiceCollectionExtensions.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.DependencyInjection;
+using NosSmooth.LocalBinding.Objects;
+
+namespace NosSmooth.LocalBinding.Extensions;
+
+/// <summary>
+/// Contains extension methods for <see cref="IServiceCollection"/>.
+/// </summary>
+public static class ServiceCollectionExtensions
+{
+ /// <summary>
+ /// Adds bindings to Nostale objects along with <see cref="NosBindingManager"/> to initialize those.
+ /// </summary>
+ /// <remarks>
+ /// Adds <see cref="CharacterBinding"/> and <see cref="NetworkBinding"/>.
+ /// You have to initialize these using <see cref="NosBindingManager"/>
+ /// prior to requesting them from the provider, otherwise an exception
+ /// will be thrown.
+ /// </remarks>
+ /// <param name="serviceCollection">The service collection.</param>
+ /// <returns>The collection.</returns>
+ public static IServiceCollection AddNostaleBindings(this IServiceCollection serviceCollection)
+ {
+ return serviceCollection
+ .AddSingleton<NosBindingManager>()
+ .AddSingleton(p => p.GetRequiredService<NosBindingManager>().Character)
+ .AddSingleton(p => p.GetRequiredService<NosBindingManager>().Network);
+ }
+}<
\ No newline at end of file
A Local/NosSmooth.LocalBinding/IsExternalInit.cs => Local/NosSmooth.LocalBinding/IsExternalInit.cs +15 -0
@@ 0,0 1,15 @@
+//
+// IsExternalInit.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 System.Runtime.CompilerServices
+{
+ /// <summary>
+ /// Dummy.
+ /// </summary>
+ public class IsExternalInit
+ {
+ }
+}<
\ No newline at end of file
A Local/NosSmooth.LocalBinding/NosBindingManager.cs => Local/NosSmooth.LocalBinding/NosBindingManager.cs +146 -0
@@ 0,0 1,146 @@
+//
+// NosBindingManager.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.Objects;
+using NosSmooth.LocalBinding.Options;
+using Reloaded.Hooks;
+using Reloaded.Hooks.Definitions;
+using Reloaded.Memory.Sigscan;
+using Reloaded.Memory.Sources;
+using Remora.Results;
+
+namespace NosSmooth.LocalBinding;
+
+/// <summary>
+/// Nostale entity binding manager.
+/// </summary>
+public class NosBindingManager : IDisposable
+{
+ private readonly CharacterBindingOptions _characterBindingOptions;
+ private readonly NetworkBindingOptions _networkBindingOptions;
+
+ private NetworkBinding? _networkBinding;
+ private CharacterBinding? _characterBinding;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="NosBindingManager"/> class.
+ /// </summary>
+ /// <param name="characterBindingOptions">The character binding options.</param>
+ /// <param name="networkBindingOptions">The network binding options.</param>
+ public NosBindingManager
+ (
+ IOptions<CharacterBindingOptions> characterBindingOptions,
+ IOptions<NetworkBindingOptions> networkBindingOptions
+ )
+ {
+ Hooks = new ReloadedHooks();
+ Memory = new Memory();
+ Scanner = new Scanner(Process.GetCurrentProcess(), Process.GetCurrentProcess().MainModule);
+ _characterBindingOptions = characterBindingOptions.Value;
+ _networkBindingOptions = networkBindingOptions.Value;
+ }
+
+ /// <summary>
+ /// Gets the memory scanner.
+ /// </summary>
+ internal Scanner Scanner { get; }
+
+ /// <summary>
+ /// Gets the reloaded hooks.
+ /// </summary>
+ internal IReloadedHooks Hooks { get; }
+
+ /// <summary>
+ /// Gets the current process memory.
+ /// </summary>
+ internal IMemory Memory { get; }
+
+ /// <summary>
+ /// Gets the network binding.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">Thrown if the manager is not initialized yet.</exception>
+ public NetworkBinding Network
+ {
+ get
+ {
+ if (_networkBinding is null)
+ {
+ throw new InvalidOperationException
+ ("Could not get network. The binding manager is not initialized. Did you forget to call NosBindingManager.Initialize?");
+ }
+
+ return _networkBinding;
+ }
+ }
+
+ /// <summary>
+ /// Gets the character binding.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">Thrown if the manager is not initialized yet.</exception>
+ public CharacterBinding Character
+ {
+ get
+ {
+ if (_characterBinding is null)
+ {
+ throw new InvalidOperationException
+ ("Could not get character. The binding manager is not initialized. Did you forget to call NosBindingManager.Initialize?");
+ }
+
+ return _characterBinding;
+ }
+ }
+
+ /// <summary>
+ /// Initialize the existing bindings and hook NosTale functions.
+ /// </summary>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Result Initialize()
+ {
+ var network = NetworkBinding.Create(this, _networkBindingOptions);
+ if (!network.IsSuccess)
+ {
+ return Result.FromError(network);
+ }
+ _networkBinding = network.Entity;
+
+ var character = CharacterBinding.Create(this, _characterBindingOptions);
+ if (!character.IsSuccess)
+ {
+ return Result.FromError(character);
+ }
+ _characterBinding = character.Entity;
+
+ return Result.FromSuccess();
+ }
+
+ /// <summary>
+ /// Disable the currently enabled nostale hooks.
+ /// </summary>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Result DisableHooks()
+ {
+ if (_networkBinding is not null)
+ {
+ var result = _networkBinding.DisableHooks();
+ if (!result.IsSuccess)
+ {
+ return result;
+ }
+ }
+
+ return Result.FromSuccess();
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Scanner.Dispose();
+ DisableHooks();
+ }
+}<
\ No newline at end of file
A Local/NosSmooth.LocalBinding/NosSmooth.LocalBinding.csproj => Local/NosSmooth.LocalBinding/NosSmooth.LocalBinding.csproj +18 -0
@@ 0,0 1,18 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ <LangVersion>10</LangVersion>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
+ <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
+ <PackageReference Include="Reloaded.Hooks" Version="3.5.0" />
+ <PackageReference Include="Reloaded.Memory.Sigscan" Version="1.2.1" />
+ <PackageReference Include="Remora.Results" Version="7.1.0" />
+ </ItemGroup>
+
+</Project>
A Local/NosSmooth.LocalBinding/Objects/CharacterBinding.cs => Local/NosSmooth.LocalBinding/Objects/CharacterBinding.cs +137 -0
@@ 0,0 1,137 @@
+//
+// CharacterBinding.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 NosSmooth.LocalBinding.Errors;
+using NosSmooth.LocalBinding.Options;
+using Reloaded.Hooks.Definitions;
+using Reloaded.Hooks.Definitions.X86;
+using Remora.Results;
+
+namespace NosSmooth.LocalBinding.Objects;
+
+/// <summary>
+/// The nostale binding of a character.
+/// </summary>
+public class CharacterBinding
+{
+ [Function
+ (
+ new[] { FunctionAttribute.Register.eax, FunctionAttribute.Register.edx },
+ FunctionAttribute.Register.eax,
+ FunctionAttribute.StackCleanup.Callee
+ )]
+ private delegate void WalkDelegate(IntPtr characterObject, int position, int unknown = 1);
+
+ /// <summary>
+ /// Create the network binding with finding the network object and functions.
+ /// </summary>
+ /// <param name="bindingManager">The binding manager.</param>
+ /// <param name="options">The options for the binding.</param>
+ /// <returns>A network binding or an error.</returns>
+ public static Result<CharacterBinding> Create(NosBindingManager bindingManager, CharacterBindingOptions options)
+ {
+ var process = Process.GetCurrentProcess();
+ var characterObjectAddress = bindingManager.Scanner.CompiledFindPattern(options.CharacterObjectPattern);
+ if (!characterObjectAddress.Found)
+ {
+ return new BindingNotFoundError(options.CharacterObjectPattern, "CharacterBinding");
+ }
+
+ var walkFunctionAddress = bindingManager.Scanner.CompiledFindPattern(options.WalkFunctionPattern);
+ if (!walkFunctionAddress.Found)
+ {
+ return new BindingNotFoundError(options.WalkFunctionPattern, "CharacterBinding.Walk");
+ }
+
+ var walkFunction = bindingManager.Hooks.CreateFunction<WalkDelegate>
+ (walkFunctionAddress.Offset + (int)process.MainModule!.BaseAddress);
+ var walkWrapper = walkFunction.GetWrapper();
+
+ var binding = new CharacterBinding
+ (
+ bindingManager,
+ (IntPtr)(characterObjectAddress.Offset + (int)process.MainModule!.BaseAddress + 0x06),
+ walkWrapper
+ );
+
+ if (options.HookWalk)
+ {
+ binding._walkHook = walkFunction
+ .Hook(binding.WalkDetour);
+ binding._originalWalk = binding._walkHook.OriginalFunction;
+ }
+
+ binding._walkHook?.Activate();
+ return binding;
+ }
+
+ private readonly NosBindingManager _bindingManager;
+ private readonly IntPtr _characterAddress;
+ private IHook<WalkDelegate>? _walkHook;
+ private WalkDelegate _originalWalk;
+
+ private CharacterBinding
+ (
+ NosBindingManager bindingManager,
+ IntPtr characterAddress,
+ WalkDelegate originalWalk
+ )
+ {
+ _bindingManager = bindingManager;
+ _characterAddress = characterAddress;
+ _originalWalk = originalWalk;
+ }
+
+ /// <summary>
+ /// Event that is called when walk was called by NosTale.
+ /// </summary>
+ /// <remarks>
+ /// The walk must be hooked for this event to be called.
+ /// </remarks>
+ public event Func<ushort, ushort, bool>? WalkCall;
+
+ /// <summary>
+ /// Disable all the hooks that are currently enabled.
+ /// </summary>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Result DisableHooks()
+ {
+ _walkHook?.Disable();
+ return Result.FromSuccess();
+ }
+
+ private IntPtr GetCharacterAddress()
+ {
+ IntPtr characterAddress = _characterAddress;
+ _bindingManager.Memory.Read(characterAddress, out characterAddress);
+ _bindingManager.Memory.Read(characterAddress, out characterAddress);
+
+ return characterAddress;
+ }
+
+ /// <summary>
+ /// Walk to the given position.
+ /// </summary>
+ /// <param name="x">The x coordinate.</param>
+ /// <param name="y">The y coordinate.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Result Walk(ushort x, ushort y)
+ {
+ int param = (y << 16) | x;
+ _originalWalk(GetCharacterAddress(), param);
+ return Result.FromSuccess();
+ }
+
+ private void WalkDetour(IntPtr characterObject, int position, int unknown)
+ {
+ var result = WalkCall?.Invoke((ushort)(position & 0xFFFF), (ushort)((position >> 16) & 0xFFFF));
+ if (result ?? true)
+ {
+ _originalWalk(characterObject, position, unknown);
+ }
+ }
+}<
\ No newline at end of file
A Local/NosSmooth.LocalBinding/Objects/NetworkBinding.cs => Local/NosSmooth.LocalBinding/Objects/NetworkBinding.cs +236 -0
@@ 0,0 1,236 @@
+//
+// NetworkBinding.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 System.Runtime.InteropServices;
+using NosSmooth.LocalBinding.Errors;
+using NosSmooth.LocalBinding.Options;
+using Reloaded.Hooks.Definitions;
+using Reloaded.Hooks.Definitions.X86;
+using Remora.Results;
+
+namespace NosSmooth.LocalBinding.Objects;
+
+/// <summary>
+/// The binding to nostale network object.
+/// </summary>
+public class NetworkBinding
+{
+ [Function
+ (
+ new[] { FunctionAttribute.Register.eax, FunctionAttribute.Register.edx },
+ FunctionAttribute.Register.eax,
+ FunctionAttribute.StackCleanup.Callee
+ )]
+ private delegate void PacketSendDelegate(IntPtr packetObject, IntPtr packetString);
+
+ [Function
+ (
+ new[] { FunctionAttribute.Register.eax, FunctionAttribute.Register.edx },
+ FunctionAttribute.Register.eax,
+ FunctionAttribute.StackCleanup.Callee
+ )]
+ private delegate void PacketReceiveDelegate(IntPtr packetObject, IntPtr packetString);
+
+ /// <summary>
+ /// Create the network binding with finding the network object and functions.
+ /// </summary>
+ /// <param name="bindingManager">The binding manager.</param>
+ /// <param name="options">The options for the binding.</param>
+ /// <returns>A network binding or an error.</returns>
+ public static Result<NetworkBinding> Create(NosBindingManager bindingManager, NetworkBindingOptions options)
+ {
+ var process = Process.GetCurrentProcess();
+ var networkObjectAddress = bindingManager.Scanner.CompiledFindPattern(options.NetworkObjectPattern);
+ if (!networkObjectAddress.Found)
+ {
+ return new BindingNotFoundError(options.NetworkObjectPattern, "NetworkBinding");
+ }
+
+ var packetSendAddress = bindingManager.Scanner.CompiledFindPattern(options.SendFunctionPattern);
+ if (!packetSendAddress.Found)
+ {
+ return new BindingNotFoundError(options.SendFunctionPattern, "NetworkBinding.SendPacket");
+ }
+
+ var packetReceiveAddress = bindingManager.Scanner.CompiledFindPattern(options.ReceiveFunctionPattern);
+ if (!packetReceiveAddress.Found)
+ {
+ return new BindingNotFoundError(options.ReceiveFunctionPattern, "NetworkBinding.ReceivePacket");
+ }
+
+ var sendFunction = bindingManager.Hooks.CreateFunction<PacketSendDelegate>
+ (packetSendAddress.Offset + (int)process.MainModule!.BaseAddress);
+ var sendWrapper = sendFunction.GetWrapper();
+
+ var receiveFunction = bindingManager.Hooks.CreateFunction<PacketReceiveDelegate>
+ (packetReceiveAddress.Offset + (int)process.MainModule!.BaseAddress);
+ var receiveWrapper = receiveFunction.GetWrapper();
+
+ var binding = new NetworkBinding
+ (
+ bindingManager,
+ (IntPtr)(networkObjectAddress.Offset + (int)process.MainModule!.BaseAddress + 0x01),
+ sendWrapper,
+ receiveWrapper
+ );
+
+ if (options.HookSend)
+ {
+ binding._sendHook = sendFunction
+ .Hook(binding.SendPacketDetour);
+ binding._originalSend = binding._sendHook.OriginalFunction;
+ }
+
+ if (options.HookReceive)
+ {
+ binding._receiveHook = receiveFunction
+ .Hook(binding.ReceivePacketDetour);
+ binding._originalReceive = binding._receiveHook.OriginalFunction;
+ }
+
+ binding._sendHook?.Activate();
+ binding._receiveHook?.Activate();
+ return binding;
+ }
+
+ private readonly NosBindingManager _bindingManager;
+ private readonly IntPtr _networkManagerAddress;
+ private IHook<PacketSendDelegate>? _sendHook;
+ private IHook<PacketReceiveDelegate>? _receiveHook;
+ private PacketSendDelegate _originalSend;
+ private PacketReceiveDelegate _originalReceive;
+
+ private NetworkBinding
+ (
+ NosBindingManager bindingManager,
+ IntPtr networkManagerAddress,
+ PacketSendDelegate originalSend,
+ PacketReceiveDelegate originalReceive
+ )
+ {
+ _bindingManager = bindingManager;
+ _networkManagerAddress = networkManagerAddress;
+ _originalSend = originalSend;
+ _originalReceive = originalReceive;
+ }
+
+ /// <summary>
+ /// Event that is called when packet send was called by NosTale.
+ /// </summary>
+ /// <remarks>
+ /// The send must be hooked for this event to be called.
+ /// </remarks>
+ public event Func<string, bool>? PacketSend;
+
+ /// <summary>
+ /// Event that is called when packet receive was called by NosTale.
+ /// </summary>
+ /// <remarks>
+ /// The receive must be hooked for this event to be called.
+ /// </remarks>
+ public event Func<string, bool>? PacketReceive;
+
+ /// <summary>
+ /// Send the given packet.
+ /// </summary>
+ /// <param name="packet">The packet to send.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Result SendPacket(string packet)
+ {
+ try
+ {
+ using var nostaleString = NostaleStringA.Create(_bindingManager.Memory, packet);
+ _originalSend(GetManagerAddress(false), nostaleString.Get());
+ }
+ catch (Exception e)
+ {
+ return e;
+ }
+
+ return Result.FromSuccess();
+ }
+
+ /// <summary>
+ /// Receive the given packet.
+ /// </summary>
+ /// <param name="packet">The packet to receive.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Result ReceivePacket(string packet)
+ {
+ try
+ {
+ using var nostaleString = NostaleStringA.Create(_bindingManager.Memory, packet);
+ _originalReceive(GetManagerAddress(true), nostaleString.Get());
+ }
+ catch (Exception e)
+ {
+ return e;
+ }
+
+ return Result.FromSuccess();
+ }
+
+ /// <summary>
+ /// Disable all the hooks that are currently enabled.
+ /// </summary>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Result DisableHooks()
+ {
+ _receiveHook?.Disable();
+ _sendHook?.Disable();
+ return Result.FromSuccess();
+ }
+
+ private IntPtr GetManagerAddress(bool third)
+ {
+ IntPtr networkManager = _networkManagerAddress;
+ _bindingManager.Memory.Read(networkManager, out networkManager);
+ _bindingManager.Memory.Read(networkManager, out networkManager);
+ _bindingManager.Memory.Read(networkManager, out networkManager);
+
+ if (third)
+ {
+ _bindingManager.Memory.Read(networkManager + 0x34, out networkManager);
+ }
+
+ return networkManager;
+ }
+
+ private void SendPacketDetour(IntPtr packetObject, IntPtr packetString)
+ {
+ var packet = Marshal.PtrToStringAnsi(packetString);
+ if (packet is null)
+ { // ?
+ _originalSend(packetObject, packetString);
+ }
+ else
+ {
+ var result = PacketSend?.Invoke(packet);
+ if (result ?? true)
+ {
+ _originalSend(packetObject, packetString);
+ }
+ }
+ }
+
+ private void ReceivePacketDetour(IntPtr packetObject, IntPtr packetString)
+ {
+ var packet = Marshal.PtrToStringAnsi(packetString);
+ if (packet is null)
+ { // ?
+ _originalReceive(packetObject, packetString);
+ }
+ else
+ {
+ var result = PacketReceive?.Invoke(packet);
+ if (result ?? true)
+ {
+ _originalReceive(packetObject, packetString);
+ }
+ }
+ }
+}<
\ No newline at end of file
A Local/NosSmooth.LocalBinding/Objects/NostaleStringA.cs => Local/NosSmooth.LocalBinding/Objects/NostaleStringA.cs +84 -0
@@ 0,0 1,84 @@
+//
+// NostaleStringA.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.Text;
+using Reloaded.Memory.Sources;
+
+namespace NosSmooth.LocalBinding.Objects;
+
+/// <summary>
+/// Represents nostale string object.
+/// </summary>
+public class NostaleStringA : IDisposable
+{
+ private readonly IMemory _memory;
+ private IntPtr _pointer;
+
+ /// <summary>
+ /// Create an instance of <see cref="NostaleStringA"/>.
+ /// </summary>
+ /// <param name="memory">The memory to allocate the string on.</param>
+ /// <param name="data">The string contents.</param>
+ /// <returns>A nostale string.</returns>
+ public static NostaleStringA Create(IMemory memory, string data)
+ {
+ var bytes = Encoding.ASCII.GetBytes(data);
+ var allocated = memory.Allocate(bytes.Length + 1 + 8);
+ memory.SafeWrite(allocated, 1);
+ memory.SafeWrite(allocated + 4, data.Length);
+ memory.SafeWriteRaw(allocated + 8, bytes);
+ memory.SafeWrite(allocated + 8 + data.Length, 0);
+
+ return new NostaleStringA(memory, allocated);
+ }
+
+ private NostaleStringA(IMemory memory, IntPtr pointer)
+ {
+ _memory = memory;
+ _pointer = pointer;
+
+ }
+
+ /// <summary>
+ /// Finalizes an instance of the <see cref="NostaleStringA"/> class.
+ /// </summary>
+ ~NostaleStringA()
+ {
+ Free();
+ }
+
+ /// <summary>
+ /// Gets whether the string is still allocated.
+ /// </summary>
+ public bool Allocated => _pointer != IntPtr.Zero;
+
+ /// <summary>
+ /// Get the pointer to the string.
+ /// </summary>
+ /// <returns>A pointer to the string to pass to NosTale.</returns>
+ public IntPtr Get()
+ {
+ return _pointer + 0x08;
+ }
+
+ /// <summary>
+ /// Free the memory allocated by the string.
+ /// </summary>
+ public void Free()
+ {
+ if (Allocated)
+ {
+ _memory.Free(_pointer);
+ _pointer = IntPtr.Zero;
+ }
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Free();
+ }
+}<
\ No newline at end of file
A Local/NosSmooth.LocalBinding/Options/CharacterBindingOptions.cs => Local/NosSmooth.LocalBinding/Options/CharacterBindingOptions.cs +34 -0
@@ 0,0 1,34 @@
+//
+// CharacterBindingOptions.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.Objects;
+
+namespace NosSmooth.LocalBinding.Options;
+
+/// <summary>
+/// Options for <see cref="CharacterBinding"/>.
+/// </summary>
+public class CharacterBindingOptions
+{
+ /// <summary>
+ /// Gets or sets whether to hook the walk function.
+ /// </summary>
+ public bool HookWalk { get; set; } = true;
+
+ /// <summary>
+ /// Gets or sets the pattern to find the character object at.
+ /// </summary>
+ /// <remarks>
+ /// The address of the object is "three pointers down" from address found on this pattern.
+ /// </remarks>
+ public string CharacterObjectPattern { get; set; }
+ = "33 C9 8B 55 FC A1 ?? ?? ?? ?? E8 ?? ?? ?? ??";
+
+ /// <summary>
+ /// Gets or sets the pattern to find the walk function at.
+ /// </summary>
+ public string WalkFunctionPattern { get; set; } = "55 8B EC 83 C4 EC 53 56 57 66 89 4D FA";
+}<
\ No newline at end of file
A Local/NosSmooth.LocalBinding/Options/NetworkBindingOptions.cs => Local/NosSmooth.LocalBinding/Options/NetworkBindingOptions.cs +44 -0
@@ 0,0 1,44 @@
+//
+// NetworkBindingOptions.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.Objects;
+
+namespace NosSmooth.LocalBinding.Options;
+
+/// <summary>
+/// Options for <see cref="NetworkBinding"/>.
+/// </summary>
+public class NetworkBindingOptions
+{
+ /// <summary>
+ /// Gets or sets whether to hook the send packet function.
+ /// </summary>
+ public bool HookSend { get; set; } = true;
+
+ /// <summary>
+ /// Gets or sets whether to hook the receive packet function.
+ /// </summary>
+ public bool HookReceive { get; set; } = true;
+
+ /// <summary>
+ /// Gets or sets the pattern to find the network object at.
+ /// </summary>
+ /// <remarks>
+ /// The address of the object is "three pointers down" from address found on this pattern.
+ /// </remarks>
+ public string NetworkObjectPattern { get; set; }
+ = "A1 ?? ?? ?? ?? 8B 00 BA ?? ?? ?? ?? E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? A1 ?? ?? ?? ?? 8B 00 8B 40 40";
+
+ /// <summary>
+ /// Gets or sets the pattern to find the send packet function at.
+ /// </summary>
+ public string SendFunctionPattern { get; set; } = "53 56 8B F2 8B D8 EB 04";
+
+ /// <summary>
+ /// Gets or sets the pattern to find the receive function at.
+ /// </summary>
+ public string ReceiveFunctionPattern { get; set; } = "55 8B EC 83 C4 F4 53 56 57 33 C9 89 4D F4 89 55 FC 8B D8 8B 45 FC";
+}<
\ No newline at end of file