#include <iostream>
int main()
{
// ***************************************
// This part of the code is in reality written in Delphi and not C++ and existing in the RPG Maker:
class XYZ {
public: // Note: Would also work with "private:"! But it simplifies the example.
int x;
int y;
int a;
int b;
int z;
};
XYZ xyzThing;
xyzThing.x = 111;
xyzThing.y = 222;
xyzThing.a = 333;
xyzThing.b = 444;
xyzThing.z = 555;
// ***************************************
// This part of the code is actually C++, in DynRPG or your own code, which is loaded into the
// same process as the RPG Maker's code so it has access to all its memory:
// We are now defining a structure whose memory layout is identical to XYZ, at least up to
// the last field we are interested in
class Something {
public:
// Let's say we don't know what the fields at the first 8 bytes in the structure are
// (they were originally x and y) and we don't care about their value much
int _unknown[2];
// We know this field is interesting for us (it's originally called a, but we can't know that)
int foo;
// And this field is interesting for us too (it's originally called b, but we can't know that)
int bar;
// The original structure also had a field z at the end but we don't care about that one,
// we may not even be aware of its existence, and there is nothing after it in
// the structure which we are interested in, so it doesn't matter (unlike x and y for
// which had to define *some* fields as padding because the a and b came afterwards
// and had to be aligned at the right location).
};
// Let's say we know for sure that xyzThing is always located at address 0x12345678, then we can write
// this reference assignment to get access to the same "thing" that is known as xyzThing to the
// third-party code that we don't normally have access to:
// Something &something = *reinterpret_cast<Something *>(0x12345678)
// However, to make this example actually compile, let's take advantage of the fact that this
// *is* an example where we *do* actually have xyzThing in scope. The following line does much
// the same as "Something &something = xyzThing;", but the latter wouldn't compile because according
// to the compiler, Something and XYZ are different types.
// Again - in reality we won't have access to "xyzThing" as variable, that's why
// we have to use its hardcoded memory address! This is just to make the example
// work. In reality we don't have access to anything of the code written above,
// the only "touching point" is that fact that both the RPG Maker's code and our
// own code live in the same process, i.e. memory space!
Something &something = *reinterpret_cast<Something *>(&xyzThing);
std::cout << something.foo << std::endl; // This will print 333, which is actually xyzThing.a!
std::cout << something.bar << std::endl; // This will print 444, which is actually xyzThing.b!
something.foo = 999; // Let's change something!
// ***************************************
// Now, the following part of the code is again RPG Maker's own code which wouldn't
// actually be C++ in reality. Let's say at some point later on, the RPG Maker
// now accesses xyzThing.a - which is known to us as something.foo above, i.e.
// we just changed this value!
std::cout << xyzThing.a << std::endl; // Prints 999!
// So, we achieved full read and write access to the data known as xyzThing to one
// part of the code from another part of the code, without having its source code or having
// access to its class definition or even variable definition (except for the line
// where we use &xyzThing but again that's just to make this example work smoothly.)
return 0;
}