This is the regenny wiki.
What is regenny?
regenny is a reverse engineering tool to interactively reconstruct structures and generate usable C++ header files. Header file generation is done by the sister project sdkgenny.
For those familiar with other tools, it is similar to ReClass.NET. It is written in C++.
Structures are defined in a plaintext .genny file rather than manually inserting types into a tree view. This allows for the structures to be version controlled, shared between users, and are human readable from a normal text editor.
It has a Lua scripting interface to easily read and manipulate the structures externally without compiling a separate program. This allows for easy testing, quick prototyping, or even writing a full blown tool in Lua. The Lua bindings can be used in a separate Lua installation/embedding, they are not tied to regenny.
Precompiled builds can currently be downloaded from the Actions page.
Getting started
To get started using ReGenny, create a project by clicking File->New on the top menu bar and entering a name in the dialog box. This will create a .json project file and a .genny file.
After that, you can click Action->Attach to attach to a running process and then you can edit the .genny file created earlier to start reverse engineering structures.
Once you’re finished, you can click Action->Generate SDK to generate corresponding C++ files.
ReGenny is a very powerful tool has many other features, but this should give you a good idea on how to get started with reverse engineering using ReGenny.
What is a .genny file?
.genny files are defined in a C/C++-like syntax. They provide the definitions of the types to be viewed in the GUI, generated, and/or reflected upon by the scripting API.
Structures can be given an explicit size, and fields within the structures can be given explicit offsets without manual padding, and out of order.
Simple C structures can sometimes be directly pasted into a .genny file.
Example
// Explicitly defined types.
// Format is type {type_name} {type_size} [[{metadata}]]
// the metadata determines how the type is displayed in the GUI and read by the Lua API.
type int 4 [[i32]]
type float 4 [[f32]]
type char 1
// Forward declared structure.
struct Bar{};
// Simple structure. Size is explicitly defined. It doesn't need to be, though.
struct Foo 0x100 {
int a @ 4 // Explicit offset
char* b @ 8 [[utf8*]]
int c // implicit offset, it's 0x10, inferred from the previous member
int d @ 0x70
float e @ 0x80
Bar* bar @ 0x90 // Pointer to a forward declared structure
};
struct Bar {
Foo* parent
int b
int c
};

The above image is slightly out of date. There is no longer a text editor inside ReGenny itself. .genny files must be opened within ReGenny and edited with an external text editor now. Reason being ImGui’s text editor functionality was not that great and caused frustrating issues.
The corresponding generated C++ structure
Foo.hpp
#pragma once
struct Bar;
#pragma pack(push, 1)
struct Foo {
char pad_0[0x4];
int a; // 0x4
// Metadata: utf8*
char* b; // 0x8
int c; // 0x10
char pad_14[0x5c];
int d; // 0x70
char pad_74[0xc];
float e; // 0x80
char pad_84[0xc];
Bar* bar; // 0x90
char pad_98[0x68];
}; // Size: 0x100
#pragma pack(pop)
Bar.hpp
#pragma once
struct Foo;
#pragma pack(push, 1)
struct Bar {
Foo* parent; // 0x0
int b; // 0x8
int c; // 0xc
}; // Size: 0x10
#pragma pack(pop)
Accessing this structure from Lua
Before using this script, the structure in the GUI has to be set to Foo, regenny must be attached to a process, and the address of the structure must be set in the GUI.
-- An overlay is a special Lua type that allows access to the memory of a structure.
-- It has index and newindex metamethods that access to the members of the structure
-- seamlessly, with no magic numbers/offsets, completely externally.
local foo = regenny:overlay()
if not foo or foo:type():name() ~= "Foo" then
print("Overlay is not a Foo, cannot use this script.")
return
end
-- Dynamically read the structure memory from the target process.
print(foo.a) -- prints the value of foo.a
print(foo.b) -- prints the value of foo.b, will be a string
-- Setter demonstrations
-- These actually set the values within the target process's structure behind the scenes.
foo.c = 0x12345 -- sets foo.c to 0x12345
foo.e = 3.14159 -- sets foo.e to 3.14159
local bar = foo.bar -- gets the value of foo.bar
-- Because pointers can be null.
if bar ~= nil then
bar.b = 0x1337 -- sets bar.b to 0x1337
bar.c = bar.b + 0x100 -- sets bar.c to bar.b + 0x100
print(bar.parent:ptr() == foo:address()) -- prints true if bar.parent is equal to foo
if bar.parent:ptr() ~= foo:address() then
-- sets bar.parent to foo
-- pointers can be explicitly written to with a raw integer value
bar.parent = foo:address()
end
end
In addition to simply reading/modifying structures, the Lua API allows for more advanced features such as:
- Performing reflection on the structure types
- Reading and writing to the process memory
- Allocating memory in the process
- Parsing another
.gennyfile separately - Generating C++ header files from a new
.gennyfile or SDK instance
Supported types
Primitive types
Define primitive types with type name size [[metadata]]:
type int 4 [[i32]]
type float 4 [[f32]]
type char 1
type bool 1 [[u8]]
type void 0
See Type metadata for available metadata values.
Structs
struct Foo {
int a
float b
}
// With explicit size
struct Bar 0x100 {
int x @ 0x40
}
Classes
class MyClass : Foo {
int extra_field
}
Enums
enum Direction {
North = 0,
South = 1,
East = 2,
West = 3,
}
Namespaces
Namespaces can be nested. Types in other namespaces are referenced with dot notation.
namespace engine {
struct Entity {
int id
}
namespace physics {
struct RigidBody {
engine.Entity* owner
}
}
}
Pointers
struct Foo {
int* data
Foo* next
char* name [[utf8*]]
}
Arrays
Fixed-size arrays, including multi-dimensional:
struct Foo {
int[10] values
float[4][4] matrix
char[64] name [[utf8*]]
}
Bitfields
struct Date {
ushort nWeekDay : 3
ushort nMonthDay : 6
ushort nMonth : 5
ushort nYear : 8
}
Function prototypes
struct Foo {
virtual void Update() @ 0
virtual int GetHealth() @ 1
virtual void SetHealth(int value) @ 5
}
Static function prototypes
struct Foo {
static void Initialize()
static Foo* GetInstance()
}
Inheritance
Single and multiple inheritance, including across namespaces:
struct Base {
int id
}
struct Derived : Base {
float value
}
// Multiple inheritance
struct MultiDerived : Base, OtherBase {
int extra
}
// Cross-namespace inheritance
struct GameEntity : engine.BaseEntity 0x200 {
float health
}
Templates
Define template structs with template <typename T> before the struct/class keyword:
template <typename T>
struct WeakPtr {
T* data
int ref_count
}
// Multiple template parameters
template <typename K, typename V>
struct Pair {
K key
V value
}
Template parameters can be used anywhere a type is used — as fields, pointers, and arrays:
template <typename T>
struct Container {
T value
T* ptr
T[4] items
T** indirect
}
Use a template by providing concrete type arguments in angle brackets:
struct Player {
WeakPtr<Entity> target
Container<float> data
Pair<int, float> stats
}
Cross-namespace type arguments use dot notation:
struct World {
WeakPtr<engine.Entity> active_entity
Container<physics.RigidBody> bodies
}
Template fields support explicit offsets (@) and relative padding (+):
template <typename T>
struct TemplatedWrapper 0x100 {
int header @ 0x0
T payload @ 0x10
int footer + 0x8 // 0x8 bytes after the end of T
}
Note: Nested template arguments like
Foo<Bar<int>>are not supported.
Nesting
Structs, enums and classes can be nested within other structs and classes:
struct Outer {
struct Inner {
int x
}
Inner value
Inner* ptr
}
Type metadata
Types and variables can have a metadata attached to them. This metadata is used to determine how the type is displayed in the GUI and read by the Lua API.
For types, the format is type {type_name} {size} [[{metadata}]].
For variables, the format is {type_name} {variable_name} [[{metadata}]].
Example:
type int 4 [[i32]] // i32 metadata, will be displayed as a signed 32-bit integer in the GUI
type float 4 [[f32]] // f32 metadata, will be displayed as a 32-bit float in the GUI
type char 1 // no metadata
struct Foo {
// will be displayed as a signed 32-bit integer in the GUI, implicit metadata
int a;
// utf8* metadata, will be displayed as a utf8 string in the GUI
// must be explicitly specified, as the type is a pointer to 1 byte
char* b [[utf8*]]
// f32 metadata, will be displayed as a 32-bit float in the GUI
float c
// metadata does not need to be specified for this pointer
int* d
};
Valid metadata tokens
The following metadata tokens are recognized by the overlay system for reading and writing values:
| Token | Description |
|---|---|
bool | Boolean (1 byte, nonzero = true) |
u8 | Unsigned 8-bit integer |
u16 | Unsigned 16-bit integer |
u32 | Unsigned 32-bit integer |
u64 | Unsigned 64-bit integer |
i8 | Signed 8-bit integer |
i16 | Signed 16-bit integer |
i32 | Signed 32-bit integer |
i64 | Signed 64-bit integer |
f32 | 32-bit floating point |
f64 | 64-bit floating point |
utf8* | Null-terminated UTF-8 string (pointer or inline) |
Address
ReGenny parses addresses in a few different ways. Here you can find some examples.
For these examples, I’m going to be using numbers in the hexidecimal format (base 16), but decimal numbers (base 10) are also supported.
Absolute addresses
Inputting an absolute address will display whatever is at that address in the current virtual address space.
For example, on Windows if your process is based at 0x180000000, then you can input the address 0x180000000 to see the PE (MZ) header and 0x180001000 to see the start of code (or whatever else is after the PE header, assuming the PE header is 0x1000 bytes in size).
Relative addresses
Relative addresses can also be used. The syntax looks something like this: <module_name>+offset->offset->offset.
Module names can contain full paths or partial paths, as long as it ends with the input path.
For example, say we want to get the base address of a module loaded as C:\Windows\System32\kernel32.dll, we could do one of the following:
<kernel32.dll>+0x0(Partial ending)<System32\kernel32.dll>(Partial ending)<C:\Windows\System32\kernel32.dll>+0x0(Full path)
On Windows, Addresses are relative to a loaded DLL’s (Dynamic-Link Library) name or EXE (Executable) name of the attached app (basically, any loaded module, including itself).
For example, to get the start of code, after the PE header, you can enter something like:
<app.exe>+0x1000.
It also supports dereferencing (denoted by ->), like so: <app.exe>+0x5000->0x24. This will add 0x5000 to app.exe’s base address, dereference the result and then read out bytes starting from 0x24 after the resulting dereference.
Example genny files
Schema patterns
Basic type definitions
Define primitive types with their sizes and metadata for the overlay system:
type uint32_t 4 [[u32]]
type int32_t 4 [[i32]]
type float 4 [[f32]]
type uint8_t 1 [[u8]]
type bool 1 [[u8]]
type char 1
type void 0
Explicit struct sizes
When only a few fields of a struct are known, specify the total struct size after the name. This ensures pointer arithmetic and array strides are correct even with an incomplete field list:
// Full size is 0x1000, but we only know a few fields
struct PlayerController 0x1000 {
int32_t health @ 0x1A4
float stamina @ 0x1A8
}
// Empty struct with known size -- used as a placeholder
struct UnknownManager 0x200 {
}
Field offset pinning with @
Use @ offset to place a field at a specific byte offset, skipping unknown regions between known fields:
struct Camera {
Matrix3x4 view_matrix // starts at offset 0
Matrix3x4 projection
float near_z @ 0x68 // pin to offset 0x68, gap before is skipped
float far_z // auto-placed right after near_z
float fov_left
float fov_right
uint8_t flags @ 0x88 // jump to offset 0x88
uint32_t mode @ 0x8C
}
Relative padding with +
Use + N to add N bytes of padding before a field, relative to the previous field’s end:
struct PhysicsWorld 0x1000 {
Vector3 gravity @ 0x170
float target_delta_time
float delta_time + 4 // 4 bytes of padding after target_delta_time
}
Forward declarations
Declare a struct with an empty body, then define it fully later. This is common in iterative reverse engineering when types reference each other:
// Forward declarations
struct World {}
struct EntityManager {}
// Full definitions later
struct World 0x8000 {
EntityManager* entity_manager @ 0x100
}
struct EntityManager 0x500 {
Entity** entities
uint32_t capacity
uint32_t count
}
Namespaces and cross-namespace references
Organize types into namespaces. Reference types across namespaces with dot notation:
namespace engine {
struct BaseEntity 0x100 {
int32_t id
char* name [[utf8*]]
}
}
namespace game {
// Inherit from a type in another namespace
struct Player : engine.BaseEntity 0x200 {
float health @ 0x1A0
float armor
}
}
Multiple inheritance
Structs can inherit from multiple base types, including across namespaces:
struct SharedItem : BaseItem, RefCountObject {
}
struct GenericEntity : ManagedInstance, BaseItem, ComponentContainer 0x100 {
Matrix3x4 transform
}
Virtual function vtable slots
Document known virtual function slots with their vtable index:
struct BaseItem 0x8 {
virtual void pad() @ 0
virtual uint32_t GetHash() @ 1
virtual char* GetModuleName() @ 2
virtual uint32_t GetSize() @ 3
virtual void Destructor() @ 6
}
String pointer metadata
Use [[utf8*]] on char* fields to tell the overlay system to read them as null-terminated strings:
struct ClassInfo {
char* class_name @ 0x10 [[utf8*]]
char* module_name [[utf8*]]
uint32_t field_count
}
For inline character arrays, the same metadata works:
struct FixedString {
char[64] buffer [[utf8*]]
}
Dynamic array pattern
A common C++ dynamic array layout uses a pointer-to-pointer with capacity and size:
struct EntityList {
Entity** data
uint32_t capacity
uint32_t size
}
struct World 0x8000 {
EntityList entities @ 0x100
}
In Lua, access elements with world.entities.data[i]:deref().
Nested struct composition
Embed structs by value inside other structs:
struct BoneInfo {
Matrix3x4 transform
int32_t parent_index
}
struct BonesHolder {
BoneInfo* bone_infos
void* unk1
void* unk2
uint32_t bone_count
}
struct MeshObject 0x1000 {
BonesHolder bones @ 0xE0 // embedded by value at offset 0xE0
}
Template types
Define generic structs with template <typename T>. Template parameters act as placeholder types resolved at instantiation:
template <typename T>
struct WeakPtr 0x10 {
T* data @ 0x8
}
struct Player 0x200 {
WeakPtr<Entity> entity_ref
}
Multiple template parameters work the same way:
template <typename K, typename V>
struct Pair {
K key
V value
}
Templates can inherit from other structs:
template <typename T>
struct Container : BaseContainer {
T* items
int count
}
The + N relative padding syntax works inside templates. The delta is preserved across all instantiations:
template <typename T>
struct AlignedValue {
T value
int metadata + 4
}
When instantiated (e.g. AlignedValue<float>), the concrete struct has float value followed by 4 bytes of padding before int metadata. Cross-namespace types use dot notation in the angle brackets: Container<engine.Entity>.
Example scripts
- https://github.com/cursey/regenny/blob/master/examples/test.lua
- https://github.com/cursey/regenny/pull/10
Basic overlay usage
-- An overlay is a special Lua type that allows access to the memory of a structure.
-- It has index and newindex metamethods that access to the members of the structure
-- seamlessly, with no magic numbers/offsets, completely externally.
local foo = regenny:overlay()
if not foo or foo:type():name() ~= "Foo" then
print("Overlay is not a Foo, cannot use this script.")
return
end
-- Dynamically read the structure memory from the target process.
print(foo.a) -- prints the value of foo.a
print(foo.b) -- prints the value of foo.b, will be a string
-- Setter demonstrations
-- These actually set the values within the target process's structure behind the scenes.
foo.c = 0x12345 -- sets foo.c to 0x12345
foo.e = 3.14159 -- sets foo.e to 3.14159
local bar = foo.bar -- gets the value of foo.bar
-- Because pointers can be null.
if bar ~= nil then
bar.b = 0x1337 -- sets bar.b to 0x1337
bar.c = bar.b + 0x100 -- sets bar.c to bar.b + 0x100
print(bar.parent:ptr() == foo:address()) -- prints true if bar.parent is equal to foo
if bar.parent:ptr() ~= foo:address() then
-- sets bar.parent to foo
-- pointers can be explicitly written to with a raw integer value
bar.parent = foo:address()
end
end
Standalone usage with sdkgenny.parse_file()
Outside of the ReGenny GUI, you can parse a .genny schema file directly and build overlays manually.
-- Parse the schema
local sdk = sdkgenny.parse_file("types.genny")
local ns = sdk:global_ns()
-- Resolve a type through namespaces
local my_struct = ns:namespace("engine"):struct("Player")
-- Build an overlay at a known address
local player = sdkgenny.StructOverlay(0xDEADBEEF, my_struct)
print(player.health)
print(player.position.x, player.position.y, player.position.z)
Resolving C++ type names to genny types
When working with RTTI strings like "class engine::Player", you can parse them into namespace and type lookups:
function resolve_type(typename)
local ns = sdk:global_ns()
-- Split on "::" and strip "class " prefix
local pieces = {}
for piece in typename:gmatch("([^:]+)") do
piece = piece:gsub("^class ", "")
table.insert(pieces, piece)
end
local result = nil
for i = 1, #pieces do
if i < #pieces then
-- Intermediate pieces are namespaces
if i == 1 then
result = ns:find_namespace(pieces[i])
elseif result then
result = result:find_namespace(pieces[i])
end
else
-- Last piece is the struct name
if i == 1 then
result = ns:find_struct(pieces[i])
elseif result then
result = result:find_struct(pieces[i])
end
end
end
return result
end
local t = resolve_type("class engine::Player")
if t then
print("Found: " .. t:name()) -- prints "Player"
end
Navigating overlay chains
Nested struct fields and pointer fields are automatically wrapped in StructOverlay or PointerOverlay. You can chain through them with nil-guards for safety:
local entity = sdkgenny.StructOverlay(entity_addr, entity_type)
-- Chain through nested structs and pointers
-- Each field access returns an overlay if the field is a struct or pointer
local weapon_manager = entity.weapon_manager
local weapon_storage = weapon_manager and weapon_manager.weapon_storage
local weapon_slots = weapon_storage and weapon_storage.weapon_slots
local weapon = weapon_slots and weapon_slots.active_weapon
if weapon then
print("Weapon: " .. weapon.name)
end
Pointer arrays and iteration
A common pattern for dynamic arrays in C++ uses T** data; uint32_t size;. Access the pointer-to-pointer field, then index and dereference:
local entity_list = world.entity_list
-- entity_list.data is a T** (pointer to pointer)
-- entity_list.data[i] indexes into the pointer array
-- :deref() follows the pointer to get the actual object
for i = 0, entity_list.size - 1 do
local entity = entity_list.data[i]:deref()
if entity then
print(entity.name)
end
end
Writing values through overlays
Overlay field writes go directly to the target process memory:
local entity = regenny:overlay()
-- Write primitive fields
entity.health = 100
entity.armor = 50
-- Write through nested struct overlays
local transform = entity.transform
if transform then
transform.w.x = new_x
transform.w.y = new_y
transform.w.z = new_z
end
-- Write pointer values (set a pointer to a new address)
entity.target = some_address
entity.target = nil -- null the pointer (sets to 0)
Pointer overlay methods
PointerOverlay provides several ways to interact with pointer-typed fields:
local ptr = entity.some_pointer
-- Get the address of the pointer itself (where the pointer is stored)
local ptr_storage_addr = ptr:address()
-- Get the address the pointer points to
local pointed_to_addr = ptr:ptr()
-- ptr:p() is an alias for ptr:ptr()
-- Dereference the pointer to get the pointed-to value
local value = ptr:deref()
-- ptr:d() and ptr:dereference() are aliases for ptr:deref()
-- Array-style access through pointer arithmetic
local third_element = ptr[2] -- *(ptr + 2)
Using process read/write with overlay addresses
For operations the overlay system doesn’t handle directly, combine overlay addresses with process read/write methods:
local process = regenny:process()
-- Read raw memory at an overlay field's address
local some_overlay = regenny:overlay()
local raw_value = process:read_uint64(some_overlay.some_field:address())
-- Pointer arithmetic from overlay addresses
local base = some_overlay:address()
local custom_offset_value = process:read_float(base + 0x30)
-- Write typed values at specific addresses
process:write_float(some_overlay.health:address(), 100.0)
process:write_uint32(some_overlay.flags:address(), 0xFF)
Module enumeration
local process = regenny:process()
for _, mod in ipairs(process:modules()) do
print(string.format("%s: 0x%X - 0x%X (size: 0x%X)",
mod.name, mod.start, mod["end"], mod.size))
end
Globals
Globals
These can be accessed from anywhere in a script.
regenny
This is the global API for ReGenny.
sdkgenny
This is the global API for luagenny. It provides functions for parsing .genny type definitions and constructing overlay objects for reading/writing typed memory.
Functions
sdkgenny.parse(data: string)
Parses an in-memory genny schema string and returns an Sdk object.
local sdk = sdkgenny.parse([[
struct Foo {
int a;
float b;
};
]])
sdkgenny.parse_file(filename: string)
Reads a .genny schema file from disk and parses it, returning an Sdk object.
local sdk = sdkgenny.parse_file("types.genny")
Types
- Sdk - The root SDK object for code generation and reflection.
- StructOverlay - Overlay for reading/writing struct memory by field name.
- PointerOverlay - Overlay for interacting with pointer-typed memory.
- Type hierarchy - The full type model (Object, Type, Struct, Variable, etc.).
sdkgenny.Sdk
The Sdk is the top level object returned by sdkgenny.parse() or sdkgenny.parse_file(). It owns the global namespace and controls code generation settings.
Methods
self:global_ns()
Returns the root Namespace. All types are created within this namespace or nested namespaces below it.
local ns = sdk:global_ns()
local my_struct = ns:struct("MyStruct")
self:generate(output_path: string)
Generates SDK header and source files to the given directory path.
self:preamble(text: string)
Sets the preamble text inserted before all generated code. Returns self for chaining.
self:postamble(text: string)
Sets the postamble text inserted after all generated code. Returns self for chaining.
self:include(header: string)
Adds a global #include <header> directive to the generated output. Returns self for chaining.
self:include_local(header: string)
Adds a local #include "header" directive to the generated output. Returns self for chaining.
self:header_extension() / self:header_extension(ext: string)
Gets or sets the file extension for generated header files (default: .hpp). Returns self when setting.
self:source_extension() / self:source_extension(ext: string)
Gets or sets the file extension for generated source files (default: .cpp). Returns self when setting.
self:generate_namespaces() / self:generate_namespaces(flag: boolean)
Gets or sets whether to emit namespace wrappers in generated output. Returns self when setting.
sdkgenny.StructOverlay
An StructOverlay is a special Lua type that allows access to the memory of a structure. It has index and newindex metamethods that access to the members of the structure seamlessly, with no magic numbers/offsets, completely externally*.
* This is not true if using luagenny outside of regenny. By default it operates on memory as if it was in the same context as the current process. regenny overrides luagenny’s read and write functions to read and write from the target process.
Example assuming Foo is:
struct Foo {
int a;
int b;
};
local sdk = regenny:sdk() -- in another application, this would be different.
local overlay = sdkgenny.StructOverlay(0xdeadbeef, sdk:global_ns():find_type("Foo"))
overlay.a = 123
overlay.b = 456
Static methods
sdkgenny.StructOverlay(address: number, struct: sdkgenny.Struct)
Creates and returns a new StructOverlay.
Methods
self.index(key: string or number)
Or in other words, self.foo or self[1].
When key is a string, it returns the value of the member at the given key. Structs and Pointers are automatically returned as StructOverlay or PointerOverlay respectively.
When key is a number, it treats the structure as an inlined array and returns a new StructOverlay at the given index. Essentially, it returns self:address() + (key * self:type():size()).
self.newindex(key: string, value: any)
Or in other words, self.foo = 123
When key is a string, it sets the value of the member at the given key.
self:type()
Returns the sdkgenny.Struct that this overlay is for.
self:address()
Returns the base memory address of this overlay.
sdkgenny.PointerOverlay
A PointerOverlay is a special Lua type for interacting with pointers. When the pointed to structure is an sdkgenny.Struct, it is not much different from an sdkgenny.StructOverlay, but when the pointed to type is a primitive type or a pointer, it has different behavior.
Static methods
sdkgenny.PointerOverlay(address: number, pointer: sdkgenny.Pointer)
Creates and returns a new PointerOverlay.
Methods
self.index(key: string or number)
Or in other words, self.foo or self[1].
When key is a string
It returns the value of the member at the given key. This will only work if the pointed to type is an sdkgenny.Struct.
When key is a number
It treats the pointer as an array.
If the pointed to type is a primitive type, it returns the value at the given index.
Essentially, it returns self:ptr() + (key * self:type():to():size()), and dereferences the pointer.
If the pointed to type is a pointer, it returns a new sdkgenny.PointerOverlay at the given index. Essentially, it returns self:ptr() + (key * platform_pointer_size), and dereferences the pointer.
self.newindex(key: string, value: any)
Or in other words, self.foo = 123
When key is a string, it sets the value of the member at the given key.
self:address()
Returns the address of the pointer itself.
self:ptr()
Returns the pointed to address.
self:d() / self:deref() / self:dereference()
Dereferences the pointer and returns the pointed-to value. Returns nil if the pointer is null. All three names are aliases for the same operation. Equivalent to self[0].
self:type()
Returns the sdkgenny.Pointer that this overlay is for.
sdkgenny.ArrayOverlay
An ArrayOverlay is a special Lua type for interacting with fixed-size array fields. It is returned automatically when accessing an Array-typed field through a StructOverlay.
local arr = overlay.items -- Array-typed field returns an ArrayOverlay
print(#arr) -- element count
print(arr[0]) -- first element (0-based)
arr[2] = 42 -- write third element
Methods
self.index(n: number)
Or in other words, self[0].
Returns the value at 0-based index n. If the element type is an sdkgenny.Struct, returns a StructOverlay. If the element type is an sdkgenny.Pointer, returns a PointerOverlay. Otherwise returns the primitive value directly.
Returns nil for out-of-bounds indices (when n < 0 or n >= count).
self.newindex(n: number, value: any)
Or in other words, self[2] = 42.
Writes value at 0-based index n. No-op for out-of-bounds indices.
#self / __len
Returns the number of elements in the array.
Types
These are the types that make up the sdkgenny type model. All types inherit from Object.
The inheritance hierarchy is:
sdkgenny.Object
The base type that all sdkgenny types inherit from. Provides name access, metadata, and a polymorphic type dispatch system.
Methods
self:name() / self:name(new_name: string)
Gets or sets the object’s name. Returns self when setting.
self:metadata()
Returns the metadata string array for this object (e.g. {"i32"}, {"f32"}, {"utf8*"}).
self:is_a(typename: string)
Returns true if this object is of the given type. Valid type names: typename, type, generic_type, struct, class, enum, enum_class, namespace, reference, pointer, variable, function, virtual_function, static_function, array, parameter, constant, template_parameter.
self:as(typename: string)
Casts this object to the given type. Returns the casted object, or nil if the cast is invalid. Takes the same type names as is_a.
self:find(typename: string, name: string)
Searches the direct children of this object for a child of the given type with the given name. Returns the child, or nil if not found.
self:find_in_owners(typename: string, name: string, include_self: boolean)
Searches upward through ancestor owners for an object of the given type with the given name. If include_self is true, the search includes this object.
self:has_any(typename: string)
Returns true if this object has any direct children of the given type.
self:has_any_in_children(typename: string)
Returns true if any descendant (recursively) is of the given type.
self:owner(typename: string)
Returns the immediate owner of the given type, or nil.
self:topmost_owner(typename: string)
Returns the topmost (outermost) owner of the given type, or nil.
self:get_all(typename: string)
Returns all direct children of the given type as a list.
self:get_comment()
Returns the comment string for this object.
self:set_comment(str: string)
Sets the comment for this object.
Type shortcut methods
For every type name listed above, convenience methods are generated that eliminate the string argument. For example, for the type name struct:
self:is_struct()- equivalent toself:is_a("struct")self:as_struct()- equivalent toself:as("struct")self:find_struct(name)- equivalent toself:find("struct", name)self:find_struct_in_owners(name, include_self)- equivalent toself:find_in_owners("struct", name, include_self)self:has_any_struct()- equivalent toself:has_any("struct")self:has_any_struct_in_children()- equivalent toself:has_any_in_children("struct")self:owner_struct()- equivalent toself:owner("struct")self:topmost_owner_struct()- equivalent toself:topmost_owner("struct")self:get_all_struct()- equivalent toself:get_all("struct")
The same pattern applies to all type names: typename, type, generic_type, struct, class, enum, enum_class, namespace, reference, pointer, variable, function, virtual_function, static_function, array, parameter, constant, template_parameter.
local obj = sdk:global_ns():find_type("Foo")
if obj:is_struct() then
local s = obj:as_struct()
local vars = s:get_all_variable()
end
sdkgenny.Typename
Inherits from Object.
A named entity with control over how its type name is generated.
Methods
self:simple_typename_generation() / self:simple_typename_generation(flag: boolean)
Gets or sets whether to use simple typename generation. Returns self when setting.
sdkgenny.Namespace
Inherits from Typename.
A C++ namespace that can contain types, structs, enums, and nested namespaces.
Methods
self:type(name: string)
Finds or creates a named Type in this namespace.
self:generic_type(name: string)
Finds or creates a GenericType in this namespace.
self:struct(name: string)
Finds or creates a Struct in this namespace.
self:enum(name: string)
Finds or creates an Enum in this namespace.
self:enum_class(name: string)
Finds or creates an EnumClass in this namespace.
self:namespace(name: string)
Finds or creates a nested Namespace in this namespace.
sdkgenny.Type
Inherits from Typename.
A named type with a byte size. Provides factory methods for creating derived reference, pointer, and array types.
Methods
self:size() / self:size(bytes: number)
Gets or sets the byte size of this type. Returns self when setting.
self:ref()
Creates or retrieves a Reference type wrapping this type (i.e. T&).
self:ptr()
Creates or retrieves a Pointer type pointing to this type (i.e. T*).
self:array()
Creates or retrieves an Array type for this element type.
sdkgenny.Struct
Inherits from Type.
A C struct type. This is the central type for declaring fields, nested types, and member functions.
Methods
self:size() / self:size(bytes: number)
Gets or sets the explicit byte size of this struct. A size of 0 means the size is auto-calculated from the fields. Returns self when setting.
self:parent(parent_struct: sdkgenny.Struct)
Adds a base/parent struct for inheritance. Returns self for chaining.
self:parents()
Returns the list of direct parent structs.
self:variable(name: string)
Finds or creates a member Variable.
self:constant(name: string)
Finds or creates a named Constant.
self:struct(name: string)
Finds or creates a nested Struct.
self:class(name: string)
Finds or creates a nested Class.
self:enum(name: string)
Finds or creates a nested Enum.
self:enum_class(name: string)
Finds or creates a nested EnumClass.
self:function(name: string)
Finds or creates a member Function.
self:virtual_function(name: string)
Finds or creates a VirtualFunction.
self:static_function(name: string)
Finds or creates a StaticFunction.
self:bitfield(byte_offset: number)
Returns a table mapping bit offsets to Variable objects for all bitfield members at the given byte offset.
self:find_in_parents(typename: string, name: string)
Searches parent structs recursively for a child of the given type with the given name. Returns nil if not found.
Like Object, type-specific shortcut methods are also available. For example:
self:find_variable_in_parents(name)- equivalent toself:find_in_parents("variable", name)self:find_struct_in_parents(name)- equivalent toself:find_in_parents("struct", name)
The same pattern applies for all type names.
Template Methods
self:template_parameter(name: string)
Finds or creates a TemplateParameter child with the given name. Returns the TemplateParameter.
self:template_parameters()
Returns a list of all TemplateParameter children.
self:is_template()
Returns true if this struct has any template parameters.
self:instantiate({type1, type2, ...})
Creates a concrete Struct by substituting template parameters with the given types. The new struct is added as a sibling in the same namespace. Returns the instantiated Struct, or nil on failure.
self:is_template_instance()
Returns true if this struct was created by instantiate().
self:template_source()
Returns the template Struct this was instantiated from, or nil.
Example
-- Define a template struct with one type parameter
local vec = sdk:struct("Vector")
vec:template_parameter("T")
vec:variable("x"):type("T")
vec:variable("y"):type("T")
vec:variable("z"):type("T")
print(vec:is_template()) -- true
-- Instantiate the template with a concrete type
local float_t = sdk:type("float"):size(4)
local vec_float = vec:instantiate({float_t})
print(vec_float:name()) -- "Vector<float>"
print(vec_float:is_template_instance()) -- true
print(vec_float:template_source()) -- the original Vector struct
sdkgenny.Class
Inherits from Struct.
A C++ class type. Identical to Struct in the Lua API – all Struct methods are available.
sdkgenny.Pointer
Inherits from Reference.
A pointer type (T*). Inherits the to() method from Reference and has no additional methods of its own.
Pointer types are typically created via the Type:ptr() factory method rather than directly.
local int_type = ns:type("int"):size(4)
local int_ptr = int_type:ptr() -- creates int*
print(int_ptr:to():name()) -- prints "int"
sdkgenny.Reference
Inherits from Type.
A reference type (T&). Wraps a target type.
Methods
self:to() / self:to(type: sdkgenny.Type)
Gets or sets the type this reference refers to. Returns self when setting.
sdkgenny.Enum
Inherits from Type.
An enumeration type with named integer values.
Methods
self:value(name: string, val: number)
Adds an enumerator with the given name and integer value.
self:values()
Returns all enumerators as a list of {name, value} pairs.
local e = ns:enum("Color")
e:value("Red", 0)
e:value("Green", 1)
e:value("Blue", 2)
for _, pair in ipairs(e:values()) do
print(pair[1], pair[2]) -- name, value
end
self:type() / self:type(underlying_type: sdkgenny.Type)
Gets or sets the underlying integer type of this enum. Returns self when setting.
sdkgenny.EnumClass
Inherits from Enum.
A C++ scoped enum (enum class). Identical to Enum in the Lua API – all Enum methods are available.
sdkgenny.Constant
Inherits from Object.
A named constant with a type and string value.
Methods
self:type(type: sdkgenny.Type)
Sets the type of this constant. Returns self for chaining.
self:value() / self:value(v: string)
Gets or sets the constant’s value as a string. Returns self when setting.
self:string()
Marks this constant as a string-type constant. Returns self for chaining.
sdkgenny.Function
Inherits from Object.
A member function declaration with return type, parameters, and an optional body.
Methods
self:returns() / self:returns(type: sdkgenny.Type)
Gets or sets the return type. Returns self when setting.
self:procedure() / self:procedure(body: string)
Gets or sets the function body as a code string. Returns self when setting.
self:dependencies()
Returns the list of types this function explicitly depends on.
self:depends_on(type: sdkgenny.Type)
Declares that this function depends on the given type. Returns self for chaining.
self:defined() / self:defined(flag: boolean)
Gets or sets whether this function has an implementation body. Returns self when setting.
sdkgenny.VirtualFunction
Inherits from Function.
A virtual member function. Adds vtable index tracking on top of the base Function methods.
Methods
self:vtable_index() / self:vtable_index(index: number)
Gets or sets the vtable slot index for this virtual function. Returns self when setting.
sdkgenny.Parameter
Inherits from Object.
A function parameter with a name and type.
Methods
self:type() / self:type(type: sdkgenny.Type)
Gets or sets this parameter’s type. Returns self when setting.
sdkgenny.Variable
Inherits from Object.
A struct/class member variable with type, offset, and optional bitfield information.
Methods
self:type() / self:type(type: sdkgenny.Type) / self:type(typename: string)
Gets or sets the variable’s type. Accepts either a Type object or a type name string. Returns self when setting.
self:offset() / self:offset(bytes: number)
Gets or sets the byte offset of this variable within its parent struct. Returns self when setting.
self:append()
Sets this variable’s offset to the end of the last variable in the parent struct, effectively auto-packing it after the previous field. Returns self for chaining.
self:end()
Returns the byte offset immediately past the end of this variable (offset + type size).
self:bit_size() / self:bit_size(bits: number)
Gets or sets the bit-size for bitfield variables. Returns self when setting.
self:bit_offset() / self:bit_offset(bits: number)
Gets or sets the bit-offset within the storage unit for bitfield variables. Returns self when setting.
self:is_bitfield()
Returns true if this variable is a bitfield.
self:bit_append()
Appends this variable as the next bitfield after the previous bitfield in the same storage unit. Returns self for chaining.
self:delta() / self:delta(value: number)
Gets or sets the + N delta value for this variable. In genny schema, this corresponds to the + delta syntax for relative padding. When called with no arguments, returns the current delta as a number. When called with a number, sets the delta and returns self.
self:has_delta()
Returns true if a delta was explicitly set on this variable. This distinguishes + 0 (an intentional zero delta) from no delta at all.
sdkgenny.GenericType
Inherits from Type.
A generic/opaque type with no additional methods beyond those inherited from Type. Used to represent types that don’t fit into the struct/enum/reference categories.
sdkgenny.Array
Inherits from Type.
A fixed-size array type (T[N]).
Methods
self:of() / self:of(element_type: sdkgenny.Type)
Gets or sets the element type. Returns self when setting.
self:count() / self:count(n: number)
Gets or sets the number of elements. Returns self when setting.
sdkgenny.StaticFunction
Inherits from Function.
A static member function. Identical to Function in the Lua API – all Function methods are available.
sdkgenny.TemplateParameter
Inherits from Type.
A placeholder type representing a template parameter (e.g. T in template <typename T>). Has a size of 0 — it is never emitted directly but is substituted for a concrete type when the template is instantiated.
TemplateParameter types are created via Struct:template_parameter(name) or automatically by the genny parser when it encounters a template <typename ...> declaration.
local my_struct = ns:struct("Container")
local T = my_struct:template_parameter("T")
-- T can be used as a field type in the template definition
my_struct:field("value"):type(T)
my_struct:field("ptr"):type(T:ptr())
my_struct:field("items"):type(T:array():count(4))
TemplateParameter has no additional methods beyond those inherited from Type. It supports the standard ptr(), ref(), and array() factory methods for building compound types from the placeholder.
During code generation, template structs emit a template<typename T> prefix in C++ headers. The TemplateParameter itself is skipped — the C++ compiler handles substitution when the template is instantiated.
Types
These are the ReGenny-specific types available in the scripting API.
ReGenny
This is the class used to access the ReGenny API. It can be accessed through the global regenny variable.
Methods
self:process()
Returns the current Process. Gets upcasted to a WindowsProcess if the process is a Windows process.
self:address()
Returns the current address set in the GUI.
self:type()
Returns the current sdkgenny.Type set in the GUI.
Can usually be casted to an sdkgenny.Struct with self:type():as_struct().
self:sdk()
Returns the current sdkgenny.Sdk for the current project (generated from the editor).
self:overlay()
Constructs and returns an sdkgenny.StructOverlay using the address and current structure set in the GUI.
Any member reads or writes will be done from/to the process memory dynamically on each access.
Example:
local baz = regenny:overlay()
if baz == nil then
print("Cannot continue test, overlay does not exist.")
return false
end
if baz:type():name() ~= "Baz" then
print("Cannot continue test, selected type is not Baz")
return false
end
print(baz)
print(baz:type())
print(string.format("%x", baz:address()))
print(baz.hello) -- Prints "Hello, world!", which is the value pointed to by baz.hello
baz.foo.a = baz.foo.a + 1 -- Increments baz.foo.a by 1
Process
Class referring to the currently attached process in regenny.
Methods
self:protect(address: number, size: number, flags: number)
Modifies the protection of a region of memory in the process.
On Windows, the flags are the same as the flNewProtect flags in VirtualProtectEx.
Returns the old protection flags of the region.
self:allocate(address: number, size: number, flags: number)
Allocates a region of memory in the process.
address is optional, set it to 0 to let the OS choose the address.
On Windows, the flags are the same as the flProtect flags in VirtualAllocEx.
self:get_module_within(address: number)
Returns the ProcessModule that contains the given address.
self:get_module(name: string)
Returns the ProcessModule with the given name.
self:modules()
Returns a list of ProcessModules in the process.
self:allocations()
Returns a list of ProcessAllocations in the process.
self:read_int8(address: number)
Reads a int8_t from the process memory at the given address.
self:read_int16(address: number)
Reads a int16_t from the process memory at the given address.
self:read_int32(address: number)
Reads a int32_t from the process memory at the given address.
self:read_int64(address: number)
Reads a int64_t from the process memory at the given address.
self:read_uint8(address: number)
Reads a uint8_t from the process memory at the given address.
self:read_uint16(address: number)
Reads a uint16_t from the process memory at the given address.
self:read_uint32(address: number)
Reads a uint32_t from the process memory at the given address.
self:read_uint64(address: number)
Reads a uint64_t from the process memory at the given address.
self:read_float(address: number)
Reads a float from the process memory at the given address.
self:read_double(address: number)
Reads a double from the process memory at the given address.
self:read_string(address: number)
Reads a char* from the process memory at the given address.
Size is automatically deduced using a strlen-like algorithm.
self:write_int8(address: number, value: number)
Writes a int8_t to the process memory at the given address.
self:write_int16(address: number, value: number)
Writes a int16_t to the process memory at the given address.
self:write_int32(address: number, value: number)
Writes a int32_t to the process memory at the given address.
self:write_int64(address: number, value: number)
Writes a int64_t to the process memory at the given address.
self:write_uint8(address: number, value: number)
Writes a uint8_t to the process memory at the given address.
self:write_uint16(address: number, value: number)
Writes a uint16_t to the process memory at the given address.
self:write_uint32(address: number, value: number)
Writes a uint32_t to the process memory at the given address.
self:write_uint64(address: number, value: number)
Writes a uint64_t to the process memory at the given address.
self:write_float(address: number, value: number)
Writes a float to the process memory at the given address.
self:write_double(address: number, value: number)
Writes a double to the process memory at the given address.
WindowsProcess
Windows version of the Process class. Inherits from Process.
Methods
self:get_typename(obj: number)
Returns the RTTI name of the given object at the given address.
self:allocate_rwx(address: number, size: number)
Wrapper over Process.allocate that allocates a region of memory with the PAGE_EXECUTE_READWRITE protection.
self:protect_rwx(address: number, size: number)
Wrapper over Process.protect that changes the protection of a region of memory to PAGE_EXECUTE_READWRITE.
self:create_remote_thread(address: number, param: number)
ProcessModule
Fields
self.name
The name of the module.
self.start
The base address of the module.
self.end
The end address of the module.
self.size
The size of the module.
ProcessAllocation
Fields
self.start
The base address of the allocation.
self.end
The end address of the allocation.
self.size
The size of the allocation.
self.read
Whether the allocation is readable.
self.write
Whether the allocation is writable.
self.execute
Whether the allocation is executable.