Skip to content

Commit 1fa3e30

Browse files
committed
Refactor pattern matching to support multiple signature variants
1 parent 0461e3d commit 1fa3e30

2 files changed

Lines changed: 114 additions & 48 deletions

File tree

FLDRPC/FLDRPC.cpp

Lines changed: 101 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,17 @@ enum DataType {
8080
TYPE_POINTER_TO_BYTE
8181
};
8282

83+
struct Signature {
84+
const char* pattern;
85+
int ripOffset;
86+
int instrLen;
87+
int postOffset;
88+
DataType type;
89+
};
90+
8391
struct Pattern {
8492
std::string name;
85-
std::vector<const char*> signatures; // take into consideration older and newer versions
86-
int ripOffset;
87-
int postOffset;
88-
DataType type;
93+
std::vector<Signature> signatures; // take into consideration older and newer versions
8994
};
9095

9196
struct MemHandle {
@@ -117,16 +122,59 @@ struct MemHandle {
117122
};
118123

119124
std::vector<Pattern> PatternList = {
120-
{ "Current BPM", {"F3 0F 11 05 ? ? ? ? F3 0F 2A 05 ? ? ? ?"}, 4, 0, TYPE_FLOAT },
121-
{ "Pattern/Song Toggle", {"48 8B 05 ? ? ? ? 83 38 ? 75 ? E8 ? ? ? ? 48 8D 88 48 1C 02 00"}, 3, 0, TYPE_POINTER_TO_INT },
122-
{ "Master Pitch",
125+
{
126+
"Current BPM",
123127
{
124-
"48 8B 05 ? ? ? ? 48 0F B7 00 66 89 85 08 02 00 00",
125-
"48 8B 05 ? ? ? ? 48 8B 8D 40 0B 00 00 48 8B 89 C0 44 00 00 48 0F BF 89 2C 00 10 00" // 25.2.2.5154
126-
}, 3, 0, TYPE_POINTER_TO_SHORT
128+
{ "F3 0F 11 05 ? ? ? ? F3 0F 2A 05 ? ? ? ?", 4, 6, 0, TYPE_FLOAT } // looks to be the same for every version
129+
}
130+
},
131+
{
132+
"Pattern/Song Toggle",
133+
{
134+
{ "48 8B 05 ? ? ? ? 83 38 ? 75 ? 48 8D 8D 90 02 00 00", 3, 6, 0, TYPE_POINTER_TO_INT }, // 24.1.2.4430
135+
{ "48 8B 05 ? ? ? ? 83 38 ? 75 ? E8 ? ? ? ? 48 8D 88 48 1C 02 00", 3, 6, 0, TYPE_POINTER_TO_INT },
136+
137+
{ "48 8B 05 ? ? ? ? 83 38 ? 0F 85 ? ? ? ? B1 ?", 3, 6, 0, TYPE_POINTER_TO_INT }, // 20.6.2.1549
138+
}
127139
},
128-
{ "Metronome Toggle", {"48 8B 0D ? ? ? ? 48 0F B6 09 88 88 88 09 00 00"}, 3, 0, TYPE_POINTER_TO_BYTE },
129-
{ "Playing Status", {"83 3D ? ? ? ? ? 74 ? 83 3D ? ? ? ? ? 7F"}, 2, 0, TYPE_BYTE }
140+
{
141+
"Master Pitch",
142+
{
143+
{ "48 8B 05 ? ? ? ? 03 18 48 8B 4D 20", 3, 6, 0, TYPE_POINTER_TO_SHORT },
144+
{ "48 8B 05 ? ? ? ? F3 0F 2A 00 48 8B 45 20", 3, 6, 0, TYPE_POINTER_TO_SHORT },
145+
{ "48 8B 05 ? ? ? ? 8B 8D B8 05 00 00 89 08 33 C0", 3, 6, 0, TYPE_POINTER_TO_SHORT },
146+
{ "48 8B 05 ? ? ? ? 8B 00 89 85 B8 05 00 00 8B 85 C0 05 00 00 A9 ? ? ? ? 74 ? 48 8B 8D 90 03 00 00", 3, 6, 0, TYPE_POINTER_TO_SHORT },
147+
148+
{ "48 8B 05 ? ? ? ? 48 0F B7 00 66 89 85 08 02 00 00", 3, 6, 0, TYPE_POINTER_TO_SHORT }, // 24.2.2.4597
149+
{ "48 8B 05 ? ? ? ? 48 8B 8D 40 0B 00 00 48 8B 89 C0 44 00 00 48 0F BF 89 2C 00 10 00", 3, 6, 0, TYPE_POINTER_TO_SHORT }, // 25.2.2.5154
150+
{ "48 8B 05 ? ? ? ? 48 0F B7 00 66 89 85 D8 04 00 00", 3, 6, 0, TYPE_POINTER_TO_SHORT }, // 21.0.3.3517
151+
{ "48 8B 05 ? ? ? ? 48 8B 8D 90 09 00 00 48 8B 89 00 04 00 00 48 0F BF 89 2C 00 10 00", 3, 6, 0, TYPE_POINTER_TO_SHORT }, // 21.1.1.3750
152+
{ "48 8B 05 ? ? ? ? 48 8B 8D C0 09 00 00 48 8B 89 20 48 00 00 48 0F BF 89 2C 00 10 00", 3, 6, 0, TYPE_POINTER_TO_SHORT }, // 24.1.2.4430
153+
{ "48 8B 05 ? ? ? ? 48 8B 8D 50 0B 00 00 48 8B 89 50 48 00 00 48 0F BF 89 2C 00 10 00", 3, 6, 0, TYPE_POINTER_TO_SHORT }, // 25.1.1.4879
154+
{ "48 8B 05 ? ? ? ? 48 8B 8D 40 0B 00 00 48 8B 89 40 48 00 00 48 0F BF 89 2C 00 10 00", 3, 6, 0, TYPE_POINTER_TO_SHORT }, // 25.1.5.4976
155+
156+
{ "48 8B 05 ? ? ? ? 48 8B 8D ? ? ? ? 48 8B 89 ? ? ? ? 48 0F BF 89", 3, 6, 0, TYPE_POINTER_TO_SHORT }, // 20.6.2.1549
157+
}
158+
},
159+
{
160+
"Metronome Toggle",
161+
{
162+
{ "48 8B 05 ? ? ? ? 48 0F B6 10 E8 ? ? ? ? 48 8B 05 ? ? ? ? 48 8B 00 48 8B 88 F8 0C 00 00", 3, 6, 0, TYPE_POINTER_TO_BYTE }, // 21.0.3.3517
163+
{ "48 8B 0D ? ? ? ? 48 0F B6 09 88 88 88 09 00 00", 3, 6, 0, TYPE_POINTER_TO_BYTE }, // 24.2.2.4597
164+
165+
{ "48 8B 05 ? ? ? ? ? ? ? 0F 84 ? ? ? ? 48 8B 05 ? ? ? ? ? ? 48 8B 05", 3, 6, 0, TYPE_POINTER_TO_BYTE }, // 20.6.2.1549
166+
}
167+
},
168+
{
169+
"Playing Status",
170+
{
171+
{ "48 8B 0D ? ? ? ? 83 39 ? 0F 94 C1 85 C0", 3, 6, 0, TYPE_POINTER_TO_INT }, // 21.0.3.3517
172+
{ "83 3D ? ? ? ? ? 74 ? 83 3D ? ? ? ? ? 7F", 2, 7, 0, TYPE_BYTE }, // versions 24 and up
173+
174+
{ "48 8B 05 ? ? ? ? ? ? ? 0F 85 ? ? ? ? 48 8B 05 ? ? ? ? ? ? 48 8B 0D", 3, 6, 0, TYPE_POINTER_TO_INT }, // 20.6.2.1549
175+
176+
}
177+
}
130178
};
131179

132180
DWORD GetProcId(const wchar_t* name) {
@@ -342,17 +390,19 @@ int main() {
342390
while (true) {
343391
for (const auto& p : PatternList) {
344392
uintptr_t hit = 0;
393+
const Signature* matchedSig = nullptr;
345394

346-
for (const char* sig : p.signatures) {
347-
hit = FindPattern(hProc, modBase, modSize, sig);
348-
if (hit) break;
395+
for (const auto& sig : p.signatures) {
396+
hit = FindPattern(hProc, modBase, modSize, sig.pattern);
397+
if (hit) {
398+
matchedSig = &sig;
399+
break;
400+
}
349401
}
350-
351-
if (!hit) continue;
402+
if (!hit || !matchedSig) continue;
352403

353404
MemHandle ptr{ hProc, hit };
354-
int instrLen = (p.name == "Playing Status") ? 7 : 6;
355-
MemHandle resolved = ptr.add(p.ripOffset).rip(instrLen);
405+
MemHandle resolved = ptr.add(matchedSig->ripOffset).rip(matchedSig->instrLen).add(matchedSig->postOffset);
356406

357407
if (!printedPatterns[p.name]) {
358408
std::cout << "[Memory] Pattern: " << p.name
@@ -361,49 +411,54 @@ int main() {
361411
printedPatterns[p.name] = true;
362412
}
363413

364-
if (p.type == TYPE_FLOAT) {
414+
if (p.name == "Current BPM") {
365415
g_bpm = resolved.as<float>();
366416
}
367-
else if (p.type == TYPE_INT) {
368-
g_playState = (resolved.as<int>() == 1) ? "Playing" : "Stopped";
369-
}
370-
else if (p.type == TYPE_POINTER_TO_INT) {
371-
auto ptrVal = resolved.as_ptr<int>();
372-
if (ptrVal) {
373-
int v{};
374-
if (ReadProcessMemory(hProc, ptrVal, &v, sizeof(v), nullptr))
375-
g_songMode = (v == 1);
417+
else if (p.name == "Pattern/Song Toggle") {
418+
int val = 0;
419+
if (matchedSig->type == TYPE_POINTER_TO_INT) {
420+
auto ptrVal = resolved.as_ptr<int>();
421+
if (ptrVal) ReadProcessMemory(hProc, ptrVal, &val, sizeof(val), nullptr);
376422
}
423+
g_songMode = (val == 1);
377424
}
378-
else if (p.type == TYPE_POINTER_TO_SHORT) {
379-
auto ptrVal = resolved.as_ptr<int16_t>();
380-
if (ptrVal) {
381-
int16_t raw{};
382-
if (ReadProcessMemory(hProc, ptrVal, &raw, sizeof(raw), nullptr))
383-
g_masterPitch = static_cast<int>(raw);
425+
else if (p.name == "Master Pitch") {
426+
int16_t raw = 0;
427+
if (matchedSig->type == TYPE_POINTER_TO_SHORT) {
428+
auto ptrVal = resolved.as_ptr<int16_t>();
429+
if (ptrVal) ReadProcessMemory(hProc, ptrVal, &raw, sizeof(raw), nullptr);
384430
}
431+
g_masterPitch = static_cast<int>(raw);
385432
}
386-
else if (p.type == TYPE_POINTER_TO_BYTE) {
387-
auto ptrVal = resolved.as_ptr<unsigned char>();
388-
if (ptrVal) {
389-
unsigned char v{};
390-
if (ReadProcessMemory(hProc, ptrVal, &v, sizeof(v), nullptr))
391-
g_metronome = (v != 0);
433+
else if (p.name == "Metronome Toggle") {
434+
unsigned char val = 0;
435+
if (matchedSig->type == TYPE_POINTER_TO_BYTE) {
436+
auto ptrVal = resolved.as_ptr<unsigned char>();
437+
if (ptrVal) ReadProcessMemory(hProc, ptrVal, &val, sizeof(val), nullptr);
392438
}
439+
g_metronome = (val != 0);
393440
}
394-
else if (p.type == TYPE_BYTE) {
395-
g_playState = (resolved.as<uint8_t>() == 1) ? "Playing" : "Stopped";
441+
else if (p.name == "Playing Status") {
442+
uint8_t val = 0;
443+
if (matchedSig->type == TYPE_BYTE) {
444+
val = resolved.as<uint8_t>();
445+
}
446+
else if (matchedSig->type == TYPE_POINTER_TO_INT) {
447+
int* ptrVal = resolved.as_ptr<int>();
448+
if (ptrVal) ReadProcessMemory(hProc, ptrVal, &val, sizeof(val), nullptr);
449+
}
450+
g_playState = (val == 1) ? "Playing" : "Stopped";
396451
}
397452
}
398453

399454
if (!initialCheckDone) {
400-
for (const auto& p : PatternList) {
455+
for (const auto& p : PatternList) {
401456
if (printedPatterns.find(p.name) == printedPatterns.end()) {
402457
std::cout << "WARNING: Pattern '" << p.name << "' was not found. Some features may not work.\n";
403458
}
404459
}
405-
initialCheckDone = true;
406-
}
460+
initialCheckDone = true;
461+
}
407462

408463
g_projectName = GetFLStudioProjectName();
409464

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,20 @@ This tool utilizes **AOB (Array of Bytes) scanning**, allowing it to dynamically
1717

1818
| FL Studio Version | Build Number | Status |
1919
| :--- | :--- | :--- |
20-
| **24.2.1** | 4526 | ✅ Confirmed |
21-
| **24.2.2** | 4597 | ✅ Confirmed |
2220
| **25.2.2** | 5154 | ✅ Confirmed |
21+
| **25.1.6** | 4997 | ✅ Confirmed |
22+
| **25.1.5** | 4976 | ✅ Confirmed |
23+
| **25.1.1** | 4879 | ✅ Confirmed |
24+
| **24.2.2** | 4597 | ✅ Confirmed |
25+
| **24.2.1** | 4526 | ✅ Confirmed |
26+
| **24.2.0** | 4503 | ✅ Confirmed |
27+
| **24.1.2** | 4430 | ✅ Confirmed |
28+
| **21.2.3** | 4004 | ✅ Confirmed |
29+
| **21.1.1** | 3750 | ✅ Confirmed |
30+
| **21.0.3** | 3517 | ✅ Confirmed |
31+
| **20.9.2** | 2963 | ✅ Confirmed |
32+
| **20.8.4** | 2576 | ✅ Confirmed |
33+
| **20.6.2** | 1549 | ✅ Confirmed |
2334

2435
> [!IMPORTANT]
2536
> While the tool is designed to be version-independent, internal memory structures can change. If you encounter issues or incorrect data with a specific build, please **[create an issue](https://github.com/nuiiv/FL-Studio-Discord-RPC/issues)** in this repository.

0 commit comments

Comments
 (0)