~ruther/NosSmooth

11b39ddc1f9e681e04354f144c4563f4f6ca87cb — František Boháček 3 years ago 2dd46d8
feat: add external memory nostale browser
A Local/NosSmooth.LocalBinding/ExternalNosBrowser.cs => Local/NosSmooth.LocalBinding/ExternalNosBrowser.cs +101 -0
@@ 0,0 1,101 @@
//
//  ExternalNosBrowser.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 NosSmooth.LocalBinding.Structs;
using Reloaded.Memory.Sigscan;
using Reloaded.Memory.Sources;
using Remora.Results;

namespace NosSmooth.LocalBinding;

/// <summary>
/// Used for browsing a nostale process data.
/// </summary>
public class ExternalNosBrowser
{
    private readonly CharacterBindingOptions _characterOptions;
    private readonly SceneManagerBindingOptions _sceneManagerOptions;
    private PlayerManager? _playerManager;
    private SceneManager? _sceneManager;

    /// <summary>
    /// Initializes a new instance of the <see cref="ExternalNosBrowser"/> class.
    /// </summary>
    /// <param name="process">The process to browse.</param>
    /// <param name="characterOptions">The options for obtaining player manager.</param>
    /// <param name="sceneManagerOptions">The scene manager options.</param>
    public ExternalNosBrowser
    (
        Process process,
        CharacterBindingOptions characterOptions,
        SceneManagerBindingOptions sceneManagerOptions
    )
    {
        _characterOptions = characterOptions;
        _sceneManagerOptions = sceneManagerOptions;
        Process = process;
        Memory = new ExternalMemory(process);
        Scanner = new Scanner(process, process.MainModule);
    }

    /// <summary>
    /// The NosTale process.
    /// </summary>
    public Process Process { get; }

    /// <summary>
    /// Gets the memory scanner.
    /// </summary>
    internal Scanner Scanner { get; }

    /// <summary>
    /// Gets the current process memory.
    /// </summary>
    internal IMemory Memory { get; }

    /// <summary>
    /// Get the player manager.
    /// </summary>
    /// <returns>The player manager or an error.</returns>
    public Result<PlayerManager> GetPlayerManager()
    {
        if (_playerManager is null)
        {
            var playerManagerResult = PlayerManager.Create(this, _characterOptions);
            if (!playerManagerResult.IsSuccess)
            {
                return playerManagerResult;
            }

            _playerManager = playerManagerResult.Entity;
        }

        return _playerManager;
    }

    /// <summary>
    /// Get the player manager.
    /// </summary>
    /// <returns>The player manager or an error.</returns>
    public Result<SceneManager> GetSceneManager()
    {
        if (_sceneManager is null)
        {
            var sceneManagerResult = SceneManager.Create(this, _sceneManagerOptions);
            if (!sceneManagerResult.IsSuccess)
            {
                return sceneManagerResult;
            }

            _sceneManager = sceneManagerResult.Entity;
        }

        return _sceneManager;
    }
}
\ No newline at end of file

A Local/NosSmooth.LocalBinding/Structs/MapPlayerObj.cs => Local/NosSmooth.LocalBinding/Structs/MapPlayerObj.cs +45 -0
@@ 0,0 1,45 @@
//
//  MapPlayerObj.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.Runtime.InteropServices;
using System.Text;
using Reloaded.Memory.Sources;

namespace NosSmooth.LocalBinding.Structs;

/// <summary>
/// NosTale Player object.
/// </summary>
public class MapPlayerObj : MapBaseObj
{
    private readonly IMemory _memory;

    /// <summary>
    /// Initializes a new instance of the <see cref="MapPlayerObj"/> class.
    /// </summary>
    /// <param name="memory">The memory.</param>
    /// <param name="mapObjPointer">The player object pointer.</param>
    public MapPlayerObj(IMemory memory, IntPtr mapObjPointer)
        : base(memory, mapObjPointer)
    {
        _memory = memory;
    }

    /// <summary>
    /// Gets the name of the player.
    /// </summary>
    public string? Name
    {
        get
        {
            _memory.SafeRead(Address + 0x1EC, out int nameAddress);
            _memory.SafeRead((IntPtr)nameAddress - 4, out int nameLength);
            byte[] data = new byte[nameLength];
            _memory.SafeReadRaw((IntPtr)nameAddress, out data, nameLength);
            return Encoding.ASCII.GetString(data);
        }
    }
}
\ No newline at end of file

A Local/NosSmooth.LocalBinding/Structs/PlayerManager.cs => Local/NosSmooth.LocalBinding/Structs/PlayerManager.cs +134 -0
@@ 0,0 1,134 @@
//
//  PlayerManager.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.Errors;
using NosSmooth.LocalBinding.Options;
using Reloaded.Memory.Sources;
using Remora.Results;

namespace NosSmooth.LocalBinding.Structs;

/// <summary>
/// NosTale player manager.
/// </summary>
public class PlayerManager
{
    /// <summary>
    /// Create <see cref="PlayerManager"/> instance.
    /// </summary>
    /// <param name="nosBrowser">The NosTale process browser.</param>
    /// <param name="options">The options.</param>
    /// <returns>The player manager or an error.</returns>
    public static Result<PlayerManager> Create(ExternalNosBrowser nosBrowser, CharacterBindingOptions options)
    {
        var characterObjectAddress = nosBrowser.Scanner.CompiledFindPattern(options.CharacterObjectPattern);
        if (!characterObjectAddress.Found)
        {
            return new BindingNotFoundError(options.CharacterObjectPattern, "PlayerManager");
        }

        if (nosBrowser.Process.MainModule is null)
        {
            return new NotFoundError("Cannot find the main module of the target process.");
        }

        var ptrAddress = nosBrowser.Process.MainModule.BaseAddress + characterObjectAddress.Offset + 0x06;
        nosBrowser.Memory.SafeRead(ptrAddress, out int address);
        nosBrowser.Memory.SafeRead((IntPtr)address, out address);
        return new PlayerManager(nosBrowser.Memory, (IntPtr)address);
    }

    private readonly IMemory _memory;

    /// <summary>
    /// Initializes a new instance of the <see cref="PlayerManager"/> class.
    /// </summary>
    /// <param name="memory">The memory.</param>
    /// <param name="playerManager">The pointer to the beginning of the player manager structure.</param>
    public PlayerManager(IMemory memory, IntPtr playerManager)
    {
        _memory = memory;
        Address = playerManager;
    }

    /// <summary>
    /// Gets the address to the player manager.
    /// </summary>
    public IntPtr Address { get; }

    /// <summary>
    /// Gets the current player position x coordinate.
    /// </summary>
    public int X
    {
        get
        {
            _memory.SafeRead(Address + 0x4, out short x);
            return x;
        }
    }

    /// <summary>
    /// Gets the current player position x coordinate.
    /// </summary>
    public int Y
    {
        get
        {
            _memory.SafeRead(Address + 0x6, out short y);
            return y;
        }
    }

    /// <summary>
    /// Gets the target x coordinate the player is moving to.
    /// </summary>
    public int TargetX
    {
        get
        {
            _memory.SafeRead(Address + 0x8, out short targetX);
            return targetX;
        }
    }

    /// <summary>
    /// Gets the target y coordinate the player is moving to.
    /// </summary>
    public int TargetY
    {
        get
        {
            _memory.SafeRead(Address + 0xA, out short targetX);
            return targetX;
        }
    }

    /// <summary>
    /// Gets the player object.
    /// </summary>
    public MapPlayerObj Player
    {
        get
        {
            _memory.SafeRead(Address + 0x20, out int playerAddress);
            return new MapPlayerObj(_memory, (IntPtr)playerAddress);
        }
    }

    /// <summary>
    /// Gets the player id.
    /// </summary>
    public int PlayerId
    {
        get
        {
            _memory.SafeRead(Address + 0x24, out int playerId);
            return playerId;
        }
    }
}
\ No newline at end of file

M Local/NosSmooth.LocalBinding/Structs/SceneManager.cs => Local/NosSmooth.LocalBinding/Structs/SceneManager.cs +27 -0
@@ 4,7 4,10 @@
//  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.Errors;
using NosSmooth.LocalBinding.Options;
using Reloaded.Memory.Sources;
using Remora.Results;

namespace NosSmooth.LocalBinding.Structs;



@@ 13,6 16,30 @@ namespace NosSmooth.LocalBinding.Structs;
/// </summary>
public class SceneManager
{
    /// <summary>
    /// Create <see cref="PlayerManager"/> instance.
    /// </summary>
    /// <param name="nosBrowser">The NosTale process browser.</param>
    /// <param name="options">The options.</param>
    /// <returns>The player manager or an error.</returns>
    public static Result<SceneManager> Create(ExternalNosBrowser nosBrowser, SceneManagerBindingOptions options)
    {
        var characterObjectAddress = nosBrowser.Scanner.CompiledFindPattern(options.SceneManagerObjectPattern);
        if (!characterObjectAddress.Found)
        {
            return new BindingNotFoundError(options.SceneManagerObjectPattern, "SceneManager");
        }

        if (nosBrowser.Process.MainModule is null)
        {
            return new NotFoundError("Cannot find the main module of the target process.");
        }

        var ptrAddress = nosBrowser.Process.MainModule.BaseAddress + characterObjectAddress.Offset;
        nosBrowser.Memory.SafeRead(ptrAddress, out ptrAddress);
        return new SceneManager(nosBrowser.Memory, ptrAddress);
    }

    private readonly IMemory _memory;
    private readonly IntPtr _sceneManager;


Do not follow this link