~ruther/NosSmooth

f6a5b5809481898dc9d99f17c67b4a74f06c672e — Rutherther 3 years ago 2a4adc2
refactor!(localbinding): abstract nostale list and nostale objects
M Local/NosSmooth.LocalBinding/Structs/ControlManager.cs => Local/NosSmooth.LocalBinding/Structs/ControlManager.cs +8 -14
@@ 11,32 11,26 @@ namespace NosSmooth.LocalBinding.Structs;
/// <summary>
/// Base for player and pet managers.
/// </summary>
public abstract class ControlManager
public abstract class ControlManager : NostaleObject
{
    private readonly IMemory _memory;

    /// <summary>
    /// Initializes a new instance of the <see cref="ControlManager"/> class.
    /// </summary>
    /// <param name="memory">The memory.</param>
    public ControlManager(IMemory memory)
    /// <param name="address">The address of the manager.</param>
    protected ControlManager(IMemory memory, IntPtr address)
        : base(memory, address)
    {
        _memory = memory;
    }

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

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


@@ 48,7 42,7 @@ public abstract class ControlManager
    {
        get
        {
            _memory.SafeRead(Address + 0x6, out short y);
            Memory.SafeRead(Address + 0x6, out short y);
            return y;
        }
    }


@@ 60,7 54,7 @@ public abstract class ControlManager
    {
        get
        {
            _memory.SafeRead(Address + 0x8, out short targetX);
            Memory.SafeRead(Address + 0x8, out short targetX);
            return targetX;
        }
    }


@@ 72,7 66,7 @@ public abstract class ControlManager
    {
        get
        {
            _memory.SafeRead(Address + 0xA, out short targetX);
            Memory.SafeRead(Address + 0xA, out short targetX);
            return targetX;
        }
    }

M Local/NosSmooth.LocalBinding/Structs/MapBaseObj.cs => Local/NosSmooth.LocalBinding/Structs/MapBaseObj.cs +9 -11
@@ 11,10 11,14 @@ namespace NosSmooth.LocalBinding.Structs;
/// <summary>
/// Base map object. Common for players, monsters, npcs.
/// </summary>
public class MapBaseObj
public class MapBaseObj : NostaleObject
{
    private readonly IMemory _memory;
    private readonly IntPtr _mapObjPointer;
    /// <summary>
    /// Initializes a new instance of the <see cref="MapBaseObj"/> class.
    /// </summary>
    public MapBaseObj()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="MapBaseObj"/> class.


@@ 22,24 26,18 @@ public class MapBaseObj
    /// <param name="memory">The memory.</param>
    /// <param name="mapObjPointer">The map object pointer.</param>
    public MapBaseObj(IMemory memory, IntPtr mapObjPointer)
        : base(memory, mapObjPointer)
    {
        _memory = memory;
        _mapObjPointer = mapObjPointer;
    }

    /// <summary>
    /// Gets the pointer to the object.
    /// </summary>
    public IntPtr Address => _mapObjPointer;

    /// <summary>
    /// Gets the id of the entity.
    /// </summary>
    public long Id
    {
        get
        {
            _memory.SafeRead(_mapObjPointer + 0x08, out int id);
            Memory.SafeRead(Address + 0x08, out int id);
            return id;
        }
    }

R Local/NosSmooth.LocalBinding/Structs/MapObjBaseList.cs => Local/NosSmooth.LocalBinding/Structs/NostaleList.cs +29 -19
@@ 1,5 1,5 @@
//
//  MapObjBaseList.cs
//  NostaleList.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.


@@ 11,33 11,36 @@ using Reloaded.Memory.Sources;
namespace NosSmooth.LocalBinding.Structs;

/// <summary>
/// List of map objects.
/// A class representing a list from nostale.
/// </summary>
public class MapObjBaseList : IEnumerable<MapBaseObj>
/// <typeparam name="T">The type.</typeparam>
public class NostaleList<T> : IEnumerable<T>
    where T : NostaleObject, new()
{
    private readonly IMemory _memory;
    private readonly IntPtr _objListPointer;
    private readonly ArrayPtr<int> _objList;

    /// <summary>
    /// Initializes a new instance of the <see cref="MapObjBaseList"/> class.
    /// Initializes a new instance of the <see cref="NostaleList{T}"/> class.
    /// </summary>
    /// <param name="memory">The memory.</param>
    /// <param name="objListPointer">The object list pointer.</param>
    public MapObjBaseList(IMemory memory, IntPtr objListPointer)
    public NostaleList(IMemory memory, IntPtr objListPointer)
    {
        memory.Read(objListPointer + 0x04, out uint arrayFirst);
        _objList = new ArrayPtr<int>(arrayFirst, source: memory);
        _memory = memory;
        _objListPointer = objListPointer;
        Address = objListPointer;
    }

    /// <summary>
    /// Gets the address.
    /// </summary>
    protected IntPtr Address { get; }

    /// <summary>
    /// Gets the element at the given index.
    /// </summary>
    /// <param name="index">The index of the element.</param>
    /// <exception cref="IndexOutOfRangeException">Thrown if the index is not in the bounds of the array.</exception>
    public MapBaseObj this[int index]
    public T this[int index]
    {
        get
        {


@@ 46,7 49,14 @@ public class MapObjBaseList : IEnumerable<MapBaseObj>
                throw new IndexOutOfRangeException();
            }

            return new MapBaseObj(_memory, (IntPtr)_objList[index]);
            _memory.SafeRead(Address + 0x04, out int arrayAddress);
            _memory.SafeRead((IntPtr)arrayAddress + (0x04 * index), out int objectAddress);

            return new T
            {
                Memory = _memory,
                Address = (IntPtr)objectAddress
            };
        }
    }



@@ 57,15 67,15 @@ public class MapObjBaseList : IEnumerable<MapBaseObj>
    {
        get
        {
            _memory.SafeRead(_objListPointer + 0x08, out int length);
            _memory.SafeRead(Address + 0x08, out int length);
            return length;
        }
    }

    /// <inheritdoc/>
    public IEnumerator<MapBaseObj> GetEnumerator()
    public IEnumerator<T> GetEnumerator()
    {
        return new MapObjBaseEnumerator(this);
        return new NostaleListEnumerator(this);
    }

    /// <inheritdoc/>


@@ 74,12 84,12 @@ public class MapObjBaseList : IEnumerable<MapBaseObj>
        return GetEnumerator();
    }

    private class MapObjBaseEnumerator : IEnumerator<MapBaseObj>
    private class NostaleListEnumerator : IEnumerator<T>
    {
        private readonly MapObjBaseList _list;
        private readonly NostaleList<T> _list;
        private int _index;

        public MapObjBaseEnumerator(MapObjBaseList list)
        public NostaleListEnumerator(NostaleList<T> list)
        {
            _index = -1;
            _list = list;


@@ 101,7 111,7 @@ public class MapObjBaseList : IEnumerable<MapBaseObj>
            _index = -1;
        }

        public MapBaseObj Current => _list[_index];
        public T Current => _list[_index];

        object IEnumerator.Current => Current;


A Local/NosSmooth.LocalBinding/Structs/NostaleObject.cs => Local/NosSmooth.LocalBinding/Structs/NostaleObject.cs +43 -0
@@ 0,0 1,43 @@
//
//  NostaleObject.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 Reloaded.Memory.Sources;

namespace NosSmooth.LocalBinding.Structs;

/// <summary>
/// A NosTale object base.
/// </summary>
public abstract class NostaleObject
{
    /// <summary>
    /// Initializes a new instance of the <see cref="NostaleObject"/> class.
    /// </summary>
    internal NostaleObject()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="NostaleObject"/> class.
    /// </summary>
    /// <param name="memory">The memory.</param>
    /// <param name="address">The address in the memory.</param>
    protected NostaleObject(IMemory memory, IntPtr address)
    {
        Memory = memory;
        Address = address;
    }

    /// <summary>
    /// Gets the memory the object is stored in.
    /// </summary>
    internal virtual IMemory Memory { get; set; } = null!;

    /// <summary>
    /// Gets the address of the object.
    /// </summary>
    public virtual IntPtr Address { get; internal set; } = IntPtr.Zero;
}
\ No newline at end of file

M Local/NosSmooth.LocalBinding/Structs/PetManager.cs => Local/NosSmooth.LocalBinding/Structs/PetManager.cs +10 -11
@@ 16,7 16,13 @@ namespace NosSmooth.LocalBinding.Structs;
/// </summary>
public class PetManager : ControlManager
{
    private readonly IMemory _memory;
    /// <summary>
    /// Initializes a new instance of the <see cref="PetManager"/> class.
    /// </summary>
    public PetManager()
        : base(null!, IntPtr.Zero)
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="PetManager"/> class.


@@ 24,26 30,19 @@ public class PetManager : ControlManager
    /// <param name="memory">The memory.</param>
    /// <param name="petManagerAddress">The pet manager address.</param>
    public PetManager(IMemory memory, IntPtr petManagerAddress)
        : base(memory)
        : base(memory, petManagerAddress)
    {
        _memory = memory;
        Address = petManagerAddress;
    }

    /// <summary>
    /// Gets the address of the pet manager.
    /// </summary>
    public override IntPtr Address { get; }

    /// <summary>
    /// Gets the player object.
    /// </summary>
    public MapNpcObj Pet
    {
        get
        {
            _memory.SafeRead(Address + 0x7C, out int playerAddress);
            return new MapNpcObj(_memory, (IntPtr)playerAddress);
            Memory.SafeRead(Address + 0x7C, out int playerAddress);
            return new MapNpcObj(Memory, (IntPtr)playerAddress);
        }
    }
}
\ No newline at end of file

M Local/NosSmooth.LocalBinding/Structs/PetManagerList.cs => Local/NosSmooth.LocalBinding/Structs/PetManagerList.cs +9 -71
@@ 9,41 9,38 @@ using NosSmooth.LocalBinding.Extensions;
using NosSmooth.LocalBinding.Options;
using Reloaded.Memory.Sources;
using Remora.Results;
using SharpDisasm.Udis86;

namespace NosSmooth.LocalBinding.Structs;

/// <summary>
/// NosTale list of <see cref="PetManager"/>.
/// </summary>
public class PetManagerList
public class PetManagerList : NostaleList<PetManager>
{
    /// <summary>
    /// Create <see cref="PlayerManager"/> instance.
    /// </summary>
    /// <param name="nosBrowser">The NosTale process browser.</param>
    /// <param name="nosBrowserManager">The NosTale process browser.</param>
    /// <param name="options">The options.</param>
    /// <returns>The player manager or an error.</returns>
    public static Result<PetManagerList> Create(ExternalNosBrowser nosBrowser, PetManagerOptions options)
    public static Result<PetManagerList> Create(NosBrowserManager nosBrowserManager, PetManagerOptions options)
    {
        var characterObjectAddress = nosBrowser.Scanner.CompiledFindPattern(options.PetManagerListPattern);
        var characterObjectAddress = nosBrowserManager.Scanner.CompiledFindPattern(options.PetManagerListPattern);
        if (!characterObjectAddress.Found)
        {
            return new BindingNotFoundError(options.PetManagerListPattern, "PetManagerList");
        }

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

        int staticManagerAddress = (int)nosBrowser.Process.MainModule.BaseAddress + characterObjectAddress.Offset;
        return new PetManagerList(nosBrowser.Memory, staticManagerAddress, options.PetManagerListOffsets);
        int staticManagerAddress = (int)nosBrowserManager.Process.MainModule.BaseAddress + characterObjectAddress.Offset;
        return new PetManagerList(nosBrowserManager.Memory, staticManagerAddress, options.PetManagerListOffsets);
    }

    private readonly IMemory _memory;
    private readonly int _staticPetManagerListAddress;
    private readonly int[] _staticPetManagerOffsets;

    /// <summary>
    /// Initializes a new instance of the <see cref="PetManagerList"/> class.
    /// </summary>


@@ 51,66 48,7 @@ public class PetManagerList
    /// <param name="staticPetManagerListAddress">The static pet manager address.</param>
    /// <param name="staticPetManagerOffsets">The offsets to follow to the pet manager list address.</param>
    public PetManagerList(IMemory memory, int staticPetManagerListAddress, int[] staticPetManagerOffsets)
        : base(memory, memory.FollowStaticAddressOffsets(staticPetManagerListAddress, staticPetManagerOffsets))
    {
        _memory = memory;
        _staticPetManagerListAddress = staticPetManagerListAddress;
        _staticPetManagerOffsets = staticPetManagerOffsets;
    }

    /// <summary>
    /// Gets the address of the pet manager.
    /// </summary>
    /// <returns>An address to the pet manager list.</returns>
    public IntPtr Address => _memory.FollowStaticAddressOffsets(_staticPetManagerListAddress, _staticPetManagerOffsets);

    /// <summary>
    /// Gets the length of the array.
    /// </summary>
    public int Length
    {
        get
        {
            _memory.SafeRead(Address + 0x08, out int length);
            return length;
        }
    }

    private IntPtr List
    {
        get
        {
            _memory.SafeRead(Address + 0x04, out int listPointer);
            return (IntPtr)listPointer;
        }
    }

    /// <summary>
    /// Get the first pet.
    /// </summary>
    /// <returns>First pet, if exists.</returns>
    public PetManager? GetFirst()
    {
        if (Length == 0)
        {
            return null;
        }

        _memory.SafeRead(List, out int firstAddress);
        return new PetManager(_memory, (IntPtr)firstAddress);
    }

    /// <summary>
    /// Get the second pet.
    /// </summary>
    /// <returns>Second pet, if exists.</returns>
    public PetManager? GetSecond()
    {
        if (Length < 2)
        {
            return null;
        }

        _memory.SafeRead(List + 0x04, out int secondAddress);
        return new PetManager(_memory, (IntPtr)secondAddress);
    }
}
\ No newline at end of file

M Local/NosSmooth.LocalBinding/Structs/PlayerManager.cs => Local/NosSmooth.LocalBinding/Structs/PlayerManager.cs +7 -7
@@ 21,24 21,24 @@ public class PlayerManager : ControlManager
    /// <summary>
    /// Create <see cref="PlayerManager"/> instance.
    /// </summary>
    /// <param name="nosBrowser">The NosTale process browser.</param>
    /// <param name="nosBrowserManager">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, PlayerManagerOptions options)
    public static Result<PlayerManager> Create(NosBrowserManager nosBrowserManager, PlayerManagerOptions options)
    {
        var characterObjectAddress = nosBrowser.Scanner.CompiledFindPattern(options.PlayerManagerPattern);
        var characterObjectAddress = nosBrowserManager.Scanner.CompiledFindPattern(options.PlayerManagerPattern);
        if (!characterObjectAddress.Found)
        {
            return new BindingNotFoundError(options.PlayerManagerPattern, "PlayerManager");
        }

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

        var staticAddress = (int)nosBrowser.Process.MainModule.BaseAddress + characterObjectAddress.Offset;
        return new PlayerManager(nosBrowser.Memory, staticAddress, options.PlayerManagerOffsets);
        var staticAddress = (int)nosBrowserManager.Process.MainModule.BaseAddress + characterObjectAddress.Offset;
        return new PlayerManager(nosBrowserManager.Memory, staticAddress, options.PlayerManagerOffsets);
    }

    private readonly IMemory _memory;


@@ 52,7 52,7 @@ public class PlayerManager : ControlManager
    /// <param name="staticPlayerManagerAddress">The pointer to the beginning of the player manager structure.</param>
    /// <param name="playerManagerOffsets">The offsets to get the player manager address from the static one.</param>
    public PlayerManager(IMemory memory, int staticPlayerManagerAddress, int[] playerManagerOffsets)
        : base(memory)
        : base(memory, IntPtr.Zero)
    {
        _memory = memory;
        _staticPlayerManagerAddress = staticPlayerManagerAddress;

M Local/NosSmooth.LocalBinding/Structs/SceneManager.cs => Local/NosSmooth.LocalBinding/Structs/SceneManager.cs +10 -10
@@ 20,24 20,24 @@ public class SceneManager
    /// <summary>
    /// Create <see cref="PlayerManager"/> instance.
    /// </summary>
    /// <param name="nosBrowser">The NosTale process browser.</param>
    /// <param name="nosBrowserManager">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, SceneManagerOptions options)
    public static Result<SceneManager> Create(NosBrowserManager nosBrowserManager, SceneManagerOptions options)
    {
        var characterObjectAddress = nosBrowser.Scanner.CompiledFindPattern(options.SceneManagerObjectPattern);
        var characterObjectAddress = nosBrowserManager.Scanner.CompiledFindPattern(options.SceneManagerObjectPattern);
        if (!characterObjectAddress.Found)
        {
            return new BindingNotFoundError(options.SceneManagerObjectPattern, "SceneManager");
        }

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

        int staticManagerAddress = (int)nosBrowser.Process.MainModule.BaseAddress + characterObjectAddress.Offset;
        return new SceneManager(nosBrowser.Memory, staticManagerAddress, options.SceneManagerOffsets);
        int staticManagerAddress = (int)nosBrowserManager.Process.MainModule.BaseAddress + characterObjectAddress.Offset;
        return new SceneManager(nosBrowserManager.Memory, staticManagerAddress, options.SceneManagerOffsets);
    }

    private readonly int[] _sceneManagerOffsets;


@@ 65,22 65,22 @@ public class SceneManager
    /// <summary>
    /// Gets the player list.
    /// </summary>
    public MapObjBaseList PlayerList => new MapObjBaseList(_memory, ReadPtr(Address + 0xC));
    public NostaleList<MapBaseObj> PlayerList => new NostaleList<MapBaseObj>(_memory, ReadPtr(Address + 0xC));

    /// <summary>
    /// Gets the monster list.
    /// </summary>
    public MapObjBaseList MonsterList => new MapObjBaseList(_memory, ReadPtr(Address + 0x10));
    public NostaleList<MapBaseObj> MonsterList => new NostaleList<MapBaseObj>(_memory, ReadPtr(Address + 0x10));

    /// <summary>
    /// Gets the npc list.
    /// </summary>
    public MapObjBaseList NpcList => new MapObjBaseList(_memory, ReadPtr(Address + 0x14));
    public NostaleList<MapBaseObj> NpcList => new NostaleList<MapBaseObj>(_memory, ReadPtr(Address + 0x14));

    /// <summary>
    /// Gets the item list.
    /// </summary>
    public MapObjBaseList ItemList => new MapObjBaseList(_memory, ReadPtr(Address + 0x18));
    public NostaleList<MapBaseObj> ItemList => new NostaleList<MapBaseObj>(_memory, ReadPtr(Address + 0x18));

    /// <summary>
    /// Gets the entity that is currently being followed by the player.

Do not follow this link