~ruther/NosSmooth

ref: 83ff4708df213d6f818732d70c222543028a3e4e NosSmooth/Local/NosSmooth.LocalBinding/Objects/SceneManagerBinding.cs -rw-r--r-- 6.7 KiB
83ff4708 — František Boháček fix(localbinding): represent follow entity input types correctly 3 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
//
//  SceneManagerBinding.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 NosSmooth.LocalBinding.Structs;
using Reloaded.Hooks;
using Reloaded.Hooks.Definitions;
using Reloaded.Hooks.Definitions.X86;
using Reloaded.Memory.Buffers.Internal.Kernel32;
using Remora.Results;

namespace NosSmooth.LocalBinding.Objects;

/// <summary>
/// The nostale binding of a scene manager.
/// </summary>
/// <remarks>
/// The scene manager holds addresses to entities, mouse position, ....
/// </remarks>
public class SceneManagerBinding
{
    [Function
    (
        new[] { FunctionAttribute.Register.eax, FunctionAttribute.Register.edx },
        FunctionAttribute.Register.ecx,
        FunctionAttribute.StackCleanup.Callee
    )]
    private delegate void FocusEntityDelegate(IntPtr outputStringPtr, IntPtr entityPtr);

    /// <summary>
    /// Create the scene manager binding.
    /// </summary>
    /// <param name="bindingManager">The binding manager.</param>
    /// <param name="bindingOptions">The options for the binding.</param>
    /// <returns>A network binding or an error.</returns>
    public static Result<SceneManagerBinding> Create
        (NosBindingManager bindingManager, SceneManagerBindingOptions bindingOptions)
    {
        var process = Process.GetCurrentProcess();
        var sceneManagerObjectAddress = bindingManager.Scanner.CompiledFindPattern
            (bindingOptions.SceneManagerObjectPattern);
        if (!sceneManagerObjectAddress.Found)
        {
            return new BindingNotFoundError(bindingOptions.SceneManagerObjectPattern, "SceneManagerBinding");
        }

        var focusEntityAddress = bindingManager.Scanner.CompiledFindPattern(bindingOptions.FocusEntityPattern);
        if (!focusEntityAddress.Found)
        {
            return new BindingNotFoundError(bindingOptions.FocusEntityPattern, "SceneManagerBinding.FocusEntity");
        }

        var focusEntityFunction = bindingManager.Hooks.CreateFunction<FocusEntityDelegate>
            (focusEntityAddress.Offset + (int)process.MainModule!.BaseAddress + 0x04);
        var focusEntityWrapper = focusEntityFunction.GetWrapper();

        var binding = new SceneManagerBinding
        (
            bindingManager,
            (IntPtr)(sceneManagerObjectAddress.Offset + (int)process.MainModule!.BaseAddress + 0x01),
            focusEntityWrapper
        );

        if (bindingOptions.HookFocusEntity)
        {
            binding._focusHook = focusEntityFunction.Hook(binding.FocusEntityDetour);
            binding._originalFocusEntity = binding._focusHook.OriginalFunction;
        }

        binding._focusHook?.Activate();
        return binding;
    }

    private readonly NosBindingManager _bindingManager;
    private readonly IntPtr _sceneManagerAddress;
    private FocusEntityDelegate _originalFocusEntity;

    private IHook<FocusEntityDelegate>? _focusHook;

    private SceneManagerBinding
    (
        NosBindingManager bindingManager,
        IntPtr sceneManagerAddress,
        FocusEntityDelegate originalFocusEntity
    )
    {
        _originalFocusEntity = originalFocusEntity;
        _bindingManager = bindingManager;
        _sceneManagerAddress = sceneManagerAddress;
    }

    /// <summary>
    /// Event that is called when entity focus was called by NosTale.
    /// </summary>
    /// <remarks>
    /// The focus entity must be hooked for this event to be called.
    /// </remarks>
    public event Func<MapBaseObj?, bool>? EntityFocus;

    /// <summary>
    /// Gets the scene manager object.
    /// </summary>
    public SceneManager SceneManager => new SceneManager(_bindingManager.Memory, GetSceneManagerAddress());

    private IntPtr GetSceneManagerAddress()
    {
        IntPtr sceneManagerAddress = _sceneManagerAddress;
        _bindingManager.Memory.Read(sceneManagerAddress, out sceneManagerAddress);

        return sceneManagerAddress;
    }

    /// <summary>
    /// Focus the entity with the given id.
    /// </summary>
    /// <param name="id">The id of the entity.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Result FocusEntity(int id)
    {
        var entityResult = FindEntity(id);
        if (!entityResult.IsSuccess)
        {
            return Result.FromError(entityResult);
        }

        return FocusEntity(entityResult.Entity);
    }

    /// <summary>
    /// Focus the entity.
    /// </summary>
    /// <param name="entity">The entity.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Result FocusEntity(MapBaseObj? entity)
        => FocusEntity(entity?.Address ?? IntPtr.Zero);

    /// <summary>
    /// Focus the entity.
    /// </summary>
    /// <param name="entityAddress">The entity address.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Result FocusEntity(IntPtr entityAddress)
    {
        try
        {
            _originalFocusEntity(IntPtr.Zero, entityAddress);
        }
        catch (Exception e)
        {
            return e;
        }

        return Result.FromSuccess();
    }

    /// <summary>
    /// Find the given entity address.
    /// </summary>
    /// <param name="id">The id of the entity.</param>
    /// <returns>The pointer to the entity or an error.</returns>
    public Result<MapBaseObj?> FindEntity(int id)
    {
        if (id == 0)
        {
            return Result<MapBaseObj?>.FromSuccess(null);
        }

        var manager = SceneManager;

        var item = manager.ItemList.FirstOrDefault(x => x.Id == id);
        if (item is not null)
        {
            return item;
        }

        var monster = manager.MonsterList.FirstOrDefault(x => x.Id == id);
        if (monster is not null)
        {
            return monster;
        }

        var npc = manager.NpcList.FirstOrDefault(x => x.Id == id);
        if (npc is not null)
        {
            return npc;
        }

        var player = manager.PlayerList.FirstOrDefault(x => x.Id == id);
        if (player is not null)
        {
            return player;
        }

        return new NotFoundError($"Could not find entity with id {id}");
    }

    private void FocusEntityDetour(IntPtr outputStringPtr, IntPtr entityId)
    {
        MapBaseObj? obj = null;
        if (entityId != IntPtr.Zero)
        {
            obj = new MapBaseObj(_bindingManager.Memory, entityId);
        }

        var result = EntityFocus?.Invoke(obj);
        if (result ?? true)
        {
            _originalFocusEntity(outputStringPtr, entityId);
        }
    }
}
Do not follow this link