Skip to content

[Memhack] Base Struct

DasKeifer edited this page Sep 30, 2026 · 2 revisions

Memhack Struct Functions

All memhack structs share a common set of functions for memory access, debugging, and validation.

Usage Notes

Modders are not expected to typically use these functions. They are more relevant to memhack code.

Printing

Structs will by default generate a __tostring function that will print each field defined in the struct

Creating Structs

Most users don't need to call new() directly. Structs are typically obtained through functions added to Game objects or other memhack structs:

  • Pawn:GetPilot() - Returns a Pilot struct
  • Game:GetSquadPilots() - Returns array of Pilot structs
  • Pilot:getLvlUpSkill(index) - Returns a PilotLvlUpSkill struct

Memory Safety

Memhack structs provide direct access to game memory. Some important notes:

  • Addresses are only valid while the game is running
  • Structs may become invalid when the game state changes (e.g., loading a save)
  • Always check that required game objects exist before accessing struct data
  • Use validate() if you need to verify a struct is still valid

Validation

All structs will do basic validation. Structs can define additional validation in the form of a vtable if the object has one or a custom validation function

Parent Tracking

Some structs maintain parent relationships (e.g., a skill knows its owning pilot). This is tracked through the _parent field on supported structs.

Table of Contents

Core Functions

Core Fields

Field Access

Debugging

Metadata

Supporting Validation Functions (Optionally defined)

Parent Tracking (Optionally defined)

new

  • Struct StructType.new(address, doValidate)
Argument name Type Description
address number Memory address of the struct
doValidate boolean Optional - if true, validate after creation. On failure logs an error and returns nil (Does not throw. Does not return an error string).

Creates a new memhack struct instance from a memory address. This is the constructor for all memhack structs.

If doValidate is true, the struct is validated immediately after creation. If validation fails, an error is logged and new returns nil.

Example:

-- Create without validation
local pilot = memhack.structs.Pilot.new(0x12345678, false)

-- Create with validation (returns nil if invalid)
local pilot = memhack.structs.Pilot.new(0x12345678, true)
if not pilot then
    LOG("Invalid pilot address")
end

-- Most commonly, validation is omitted and defaults to false
local pilot = memhack.structs.Pilot.new(0x12345678)

getAddress

  • number struct:getAddress()

Returns the memory address of this struct instance.

Example:

local addr = pilot:getAddress()
LOG(string.format("Pilot at address: 0x%X", addr))

isMemhackObj

  • boolean

A field (not a function) that is always true for memhack struct objects. Useful for type checking.

Example:

if pilot.isMemhackObj then
    LOG("This is a memhack object")
end

validate

  • Struct, string struct:validate()
  • Struct, string StructType.validate(address)

Validates that the struct appears to be correctly formed in memory.

Can be called as an instance method (instance:validate()) or as a static method (StructType.validate(address)).

Returns two values:

  1. The struct instance if valid, or nil if invalid
  2. nil if valid, or an error message string if invalid

Validation checks:

  1. Address is not nil or 0
  2. Memory at the address is readable for the full struct size
  3. For structs with vtables: vtable pointer matches expected value
  4. Custom validation function if specified

Example:

-- Instance method
local pilot = pawn:GetPilot()
local validPilot, err = pilot:validate()
if not validPilot then
    LOG("WARNING: Pilot struct failed validation: " .. err)
end

-- Static method - validates and creates instance
local validPilot, err = memhack.structs.Pilot.validate(0x12345678)
if validPilot then
    LOG("Valid pilot at address")
else
    LOG("Invalid: " .. err)
end

_getFieldOffset

  • number struct:_getFieldOffset(fieldName)
Argument name Type Description
fieldName string Name of the field

Returns the byte offset of a field within the struct. This is primarily for internal use and debugging.

Example:

local xpOffset = pilot:_getFieldOffset("xp")
LOG("XP field is at offset: " .. xpOffset)

_getFieldAddress

  • number struct:_getFieldAddress(fieldName)
Argument name Type Description
fieldName string Name of the field

Returns the absolute memory address of a field. This is primarily for internal use and debugging.

Example:

local xpAddr = pilot:_getFieldAddress("xp")
LOG(string.format("XP field at address: 0x%X", xpAddr))

__tostring

  • string tostring(struct)

Returns a string representation of the struct for display. This is called automatically when converting a struct to a string.

Example:

LOG(tostring(pilot))
-- Output: multi line field dump from _toDebugString()

_toDebugString

  • string struct:_toDebugString()

Returns a detailed debug string with all field values. Useful for debugging and logging struct contents.

Example:

LOG(pilot:_toDebugString())
-- Output: Detailed dump of all pilot fields and values

Metadata Fields

These are fields available on all memhack struct instances:

_name

  • string

The name of the struct type.

Example:

LOG("Struct type: " .. pilot._name)
-- Output: "Pilot"

_address

  • number

The memory address of this struct instance. Same as calling getAddress().

Example:

LOG(string.format("Address: 0x%X", pilot._address))

_layout

  • table

The layout definition table for this struct type. Contains field definitions with offsets and types.

Example:

for fieldName, fieldDef in pairs(pilot._layout) do
    LOG(fieldName .. " at offset " .. fieldDef.offset)
end

stateDefinition

  • table

The state tracking definition for this struct. Lists which fields are tracked for change detection.

Example:

for _, field in ipairs(Pilot.stateDefinition) do
    LOG("Tracked field: " .. tostring(field))
end

StructSize

  • number StructType:StructSize() (method)

Returns the size in bytes of this struct type.

Example:

LOG("Pilot struct size: " .. memhack.structs.Pilot:StructSize())

getVtable

  • number struct:getVtable()

Returns the vtable address for this struct. Only present on structs defined with a numeric vtable address argument to structManager:define. Pilot does not currently use vtable validation (custom validatePilot instead), so getVtable / _vtableAddr are not available on Pilot.

Example:

-- Only for structs that were defined with a vtable address:
local vtable = someVtableStruct:getVtable()
LOG(string.format("Vtable at: 0x%X", vtable))

_setVtable

  • void struct:_setVtable(addr)
Argument name Type Description
addr number The vtable address

Sets the vtable address. For internal use only. Only applicable to structs with vtables.

_vtableAddr

  • number

Field containing the vtable address. Only present on structs with vtables.

_validateFn

  • function

Optional custom validation function for the struct type. When present, this function is called by validate() to perform struct-specific validation checks.

For example, structs with vtables use this to verify the vtable pointer matches the expected value.

Example:

-- Internal use - called by validate()
if struct._validateFn then
    return struct._validateFn(struct)
end

_parent

  • table

Field containing parent references for this struct. Used to track relationships between structs (e.g., a skill knows its owning pilot).

The table structure varies by struct type. For example:

  • PilotLvlUpSkill._parent contains Pilot and PilotLvlUpSkillsArray

Example:

-- Access parent pilot from a skill
local skill = pilot:getLvlUpSkill(1)
local parentPilot = skill._parent.Pilot
if parentPilot then
    LOG("Skill belongs to: " .. parentPilot:getName())
end

Clone this wiki locally