~ruther/NosSmooth.Local

ref: 311bc033a111d2e125fd3821578d944c810391a8 NosSmooth.Local/src/Core/NosSmooth.LocalBinding/Objects/UnitManagerBinding.cs -rw-r--r-- 5.4 KiB
311bc033 — Rutherther feat(binding): make events follow common convention, using EventHandler 2 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
//
//  UnitManagerBinding.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.EventArgs;
using NosSmooth.LocalBinding.Extensions;
using NosSmooth.LocalBinding.Options;
using NosSmooth.LocalBinding.Structs;
using Reloaded.Hooks.Definitions;
using Reloaded.Hooks.Definitions.X86;
using Reloaded.Hooks.Internal.Testing;
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 UnitManagerBinding
{
    [Function
    (
        new[] { FunctionAttribute.Register.eax, FunctionAttribute.Register.edx },
        FunctionAttribute.Register.eax,
        FunctionAttribute.StackCleanup.Callee,
        new[] { FunctionAttribute.Register.ebx, FunctionAttribute.Register.esi, FunctionAttribute.Register.edi, FunctionAttribute.Register.ebp }
    )]
    private delegate nuint FocusEntityDelegate(nuint unitManagerPtr, nuint 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<UnitManagerBinding> Create
        (NosBindingManager bindingManager, UnitManagerBindingOptions bindingOptions)
    {
        var process = Process.GetCurrentProcess();

        var unitManagerStaticAddress = bindingManager.Scanner.FindPattern(bindingOptions.UnitManagerPattern);
        if (!unitManagerStaticAddress.Found)
        {
            return new BindingNotFoundError(bindingOptions.UnitManagerPattern, "UnitManagerBinding.UnitManager");
        }

        var binding = new UnitManagerBinding
        (
            bindingManager,
            (int)process.MainModule!.BaseAddress + unitManagerStaticAddress.Offset,
            bindingOptions.UnitManagerOffsets
        );

        var entityFocusHookResult = bindingManager.CreateCustomAsmHookFromPattern<FocusEntityDelegate>
            ("UnitManager.EntityFocus", binding.FocusEntityDetour, bindingOptions.EntityFocusHook);
        if (!entityFocusHookResult.IsDefined(out var entityFocusHook))
        {
            return Result<UnitManagerBinding>.FromError(entityFocusHookResult);
        }

        binding._focusHook = entityFocusHook;
        return binding;
    }

    private readonly int _staticUnitManagerAddress;
    private readonly int[] _unitManagerOffsets;

    private readonly NosBindingManager _bindingManager;

    private NosAsmHook<FocusEntityDelegate> _focusHook = null!;

    private bool _callingFocus;

    private UnitManagerBinding
    (
        NosBindingManager bindingManager,
        int staticUnitManagerAddress,
        int[] unitManagerOffsets
    )
    {
        _bindingManager = bindingManager;
        _staticUnitManagerAddress = staticUnitManagerAddress;
        _unitManagerOffsets = unitManagerOffsets;
    }

    /// <summary>
    /// Gets the address of unit manager.
    /// </summary>
    public nuint Address => _bindingManager.Memory.FollowStaticAddressOffsets
        (_staticUnitManagerAddress, _unitManagerOffsets);

    /// <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 EventHandler<EntityEventArgs>? EntityFocusCall;

    /// <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 ?? nuint.Zero);

    /// <summary>
    /// Disable all UnitManager hooks.
    /// </summary>
    public void DisableHooks()
    {
        _focusHook.Hook.Disable();
    }

    /// <summary>
    /// Enable all UnitManager hooks.
    /// </summary>
    public void EnableHooks()
    {
        _focusHook.Hook.EnableOrActivate();
    }

    /// <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(nuint entityAddress)
    {
        try
        {
            _callingFocus = true;
            _focusHook.OriginalFunction.GetWrapper()(Address, entityAddress);
            _callingFocus = false;
        }
        catch (Exception e)
        {
            return e;
        }

        return Result.FromSuccess();
    }

    private nuint FocusEntityDetour(nuint unitManagerPtr, nuint entityId)
    {
        if (_callingFocus)
        {
            // in case this is being called from UnitManagerBinding.FocusEntity,
            // do not handle.
            return 1;
        }

        MapBaseObj? obj = null;
        if (entityId != nuint.Zero)
        {
            obj = new MapBaseObj(_bindingManager.Memory, entityId);
        }

        var entityEventArgs = new EntityEventArgs(obj);
        EntityFocusCall?.Invoke(this, entityEventArgs);

        return entityEventArgs.Cancel ? 0 : (nuint)1;
    }
}
Do not follow this link