-
Notifications
You must be signed in to change notification settings - Fork 44
/
01_Basics.cpp
155 lines (116 loc) · 5.62 KB
/
01_Basics.cpp
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
#include <BNM/UserSettings/GlobalSettings.hpp>
#include <BNM/Class.hpp>
#include <BNM/Field.hpp>
#include <BNM/Method.hpp>
#include <BNM/Property.hpp>
#include <BNM/Operators.hpp>
#include <BNM/BasicMonoStructures.hpp>
// Used to not write BNM::Structures for each type
using namespace BNM::Structures; // Mono::String, Mono::Array etc.
using namespace BNM::Operators; // Operators for methods, fields, and properties
// Variable for storing class
BNM::Class ObjectClass{};
// Variable for storing property
BNM::Property<Mono::String *> ObjectName{};
// Variable for storing method
BNM::Method<Mono::String *> ObjectToString{};
// Variable for storing field
BNM::Field<void *> PlayerConfig{};
BNM::Field<Mono::String *> ConfigName{};
BNM::Field<int> ConfigHealth{};
BNM::Field<int> ConfigCoins{};
// Variable for storing pointer to field
void **PlayerConfigPtr = nullptr;
BNM::UnityEngine::Object *Player = nullptr;
void (*old_PlayerStart)(BNM::UnityEngine::Object *);
void PlayerStart(BNM::UnityEngine::Object *instance) {
old_PlayerStart(instance); // Call original code
// Checking whether the Unity object is alive (UnityEngine.Object and its child classes)
//! ALWAYS use this check instead of basic nullptr check!
if (Player->Alive() /*BNM::UnityEngine::IsUnityObjectAlive(Player)*/) {
BNM_LOG_WARN("Player's Start called twice?");
}
Player = instance;
//! Mono::String - C# string (string or System.String) in BNM
// In this case, the field has a type and the property will automatically call the Get method to get the name.
// If you use auto, the field will be a copy of objectName and you will either have to call Get() or add() to objectName, i.e.:
// (instance >> ObjectName)() // for >> and ->*
// ObjectName[instance]() // for []
Mono::String *playerObjectName =
// Alternatives:
// * instance >> ObjectName
// * instance->*ObjectName;
ObjectName[instance];
// Get pointers to these fields
PlayerConfigPtr = PlayerConfig[instance].GetPointer();
// In the case of fields, the ->* operator immediately returns a reference to the field data
auto playerName = *PlayerConfigPtr->*ConfigName;
// Log name of the player's object
BNM_LOG_INFO("Player's object name: \"%s\"; Player's name: \"%s\"",
// str() - convert string to std::string
playerObjectName->str().c_str(),
// -> - iterator operator for checking data and warning if it is incorrect (in debugging mode)
playerName->str().c_str());
//! Call ObjectToString, you can write arguments in (), as when calling any methods
// Alternative method call with an object
// auto objectToStringResult = (instance >> ObjectToString)();
auto objectToStringResult = ObjectToString[instance]();
BNM_LOG_INFO("objectToStringResult: \"%s\"", objectToStringResult->str().c_str());
//! Changing the player's name
*playerName = BNM::CreateMonoString(BNM_OBFUSCATE("BNM_Player"));
}
void (*old_PlayerUpdate)(BNM::UnityEngine::Object *);
void PlayerUpdate(BNM::UnityEngine::Object *instance) {
old_PlayerUpdate(instance); // Call original code
// Checking whether the pointer to the m_Config field data is correct
if (PlayerConfigPtr == nullptr) return;
// Set 99999 lives using the operator ->*
//! *((*PlayerConfigPtr)->*ConfigHealth) = 99999;
// Or using []
ConfigHealth[*PlayerConfigPtr] = 99999;
// Set 99999 coins
ConfigCoins[*PlayerConfigPtr] = 99999;
}
// Here you can get all the necessary information
void OnLoaded_Example_01() {
using namespace BNM; // To avoid writing BNM:: in this method
// Get the UnityEngine class.Object
ObjectClass = Class(BNM_OBFUSCATE("UnityEngine"), BNM_OBFUSCATE("Object"));
// Get UnityEngine.Object::ToString method with 0 parameters
ObjectToString = ObjectClass.GetMethod(BNM_OBFUSCATE("ToString"), 0);
// Get UnityEngine.Object::name property
ObjectName = ObjectClass.GetProperty(BNM_OBFUSCATE("name"));
/* Let's imagine that there is a class in the game:
public class Player : MonoBehaviour {
private void Start();
private void Update();
private Config m_Config;
public class Config {
string Name;
int Health;
int Coins;
}
}
*/
// Get the Player class
auto PlayerClass = Class(BNM_OBFUSCATE(""), BNM_OBFUSCATE("Player"));
// Get the Player::Config class
auto PlayerConfigClass = PlayerClass.GetInnerClass(BNM_OBFUSCATE("Config"));
// Get the Update and Start methods of the Player class
auto Update = PlayerClass.GetMethod(BNM_OBFUSCATE("Update"));
auto Start = PlayerClass.GetMethod(BNM_OBFUSCATE("Start"));
// Get the Player.m_Config field
PlayerConfig = PlayerClass.GetField(BNM_OBFUSCATE("m_Config"));
// Get Player::Config's fields
ConfigName = PlayerConfigClass.GetField(BNM_OBFUSCATE("Name"));
ConfigHealth = PlayerConfigClass.GetField(BNM_OBFUSCATE("Health"));
ConfigCoins = PlayerConfigClass.GetField(BNM_OBFUSCATE("Coins"));
// Hook Update and Start methods
// There are 3 methods for hooking methods:
// * HOOK - hook via hooking software
// * InvokeHook - hook that works for those methods that are called directly by the engine (constructors (.ctor), events (Start, Update, etc.))
// * VirtualHook - hook for virtual methods
// To replace Start and Update for this class, the best option is InvokeHook
InvokeHook(Update, PlayerUpdate, old_PlayerUpdate);
InvokeHook(Start, PlayerStart, old_PlayerStart);
}