Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Convert structure to C header file (AI generated)

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Extensions
View previous topic :: View next topic  
Author Message
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25796
Location: The netherlands

PostPosted: Mon Aug 18, 2025 4:25 am    Post subject: Convert structure to C header file (AI generated) Reply with quote

Here's a script that will convert a structure to a C header file
(100% ai written with only 15 prompts)

Code:

-- Lua script for Cheat Engine: Generate C header from a Structure object,
-- handling gaps, overlaps, recursion, nested structs, all value types, signed/unsigned integer display,
-- unnamed fields, and cleans up invalid C identifier characters in element names.
-- Assumes vtByte .. vtWideString are already defined in CE. (Do not redeclare them!)

local function mapVartypeToC(elem, child_struct_typename)
  local vt = elem.Vartype
  local display = elem.DisplayMethod
  local signed = (display == 'dtSignedInteger')
  if vt == vtByte then
    return signed and "signed char" or "unsigned char", elem.Bytesize
  elseif vt == vtWord then
    return signed and "short" or "unsigned short", elem.Bytesize
  elseif vt == vtDword then
    return signed and "int" or "unsigned int", elem.Bytesize
  elseif vt == vtQword then
    return signed and "long long" or "unsigned long long", elem.Bytesize
  elseif vt == vtSingle then
    return "float", elem.Bytesize
  elseif vt == vtDouble then
    return "double", elem.Bytesize
  elseif vt == vtPointer then
    if child_struct_typename then
      if elem.NestedStructure then
        return child_struct_typename, elem.Bytesize
      else
        return child_struct_typename .. "*", elem.Bytesize
      end
    else
      return "void*", elem.Bytesize
    end
  elseif vt == vtString then
    return "char", elem.Bytesize
  elseif vt == vtWideString then
    return "wchar_t", elem.Bytesize // 2
  else
    return "int", elem.Bytesize
  end
end

local function getStructTypeName(structure)
  -- Only allow valid C identifier characters for struct names
  return tostring(structure.Name):gsub("[^%w_]", "_")
end

local function getElementName(elem)
  local rawname = elem.Name or ""
  local name
  if rawname == "" then
    name = string.format("unnamed%X", elem.Offset or 0)
  else
    -- Replace invalid C identifier characters with '_'
    name = tostring(rawname):gsub("[^%w_]", "_")
    -- C identifiers can't start with a digit
    if name:match("^[0-9]") then
      name = "_" .. name
    end
  end
  return name
end

local function generate_c_header(structure, defined_structs)
  defined_structs = defined_structs or {}
  local struct_name = getStructTypeName(structure)
  if defined_structs[struct_name] then
    return "" -- already defined, skip
  end
  defined_structs[struct_name] = true

  local guard = ("_%s_H_"):format(struct_name):upper():gsub("%W","_")
  local out = {}
  table.insert(out, "#ifndef "..guard)
  table.insert(out, "#define "..guard)
  table.insert(out, "")
  table.insert(out, "#include <stdint.h>")
  table.insert(out, "#include <wchar.h>")
  table.insert(out, "")

  table.insert(out, ("typedef struct %s {"):format(struct_name))

  local used_bytes = {}
  local current_offset = 0
  local reserved_count = 0
  local child_struct_defs = {}

  for i=0, structure.Count-1 do
    local elem = structure.Element[i]
    if elem then
      local elem_offset = elem.Offset
      local elem_end = elem_offset + elem.Bytesize
      local child_struct_typename = nil
      local name = getElementName(elem)
      if elem.Vartype == vtPointer and elem.ChildStruct then
        child_struct_typename = getStructTypeName(elem.ChildStruct)
        if not defined_structs[child_struct_typename] then
          table.insert(child_struct_defs, generate_c_header(elem.ChildStruct, defined_structs))
        end
      end

      local ctype, size = mapVartypeToC(elem, child_struct_typename)
      local overlap = false
      for b = elem_offset, elem_end - 1 do
        if used_bytes[b] then
          overlap = true
          break
        end
      end
      if overlap then
        table.insert(out, ("    // Field '%s' REMOVED due to overlap with a previous field"):format(name))
      else
        if elem_offset > current_offset then
          local gap = elem_offset - current_offset
          reserved_count = reserved_count + 1
          table.insert(out, ("    unsigned char reserved_%d[%d]; // gap"):format(reserved_count, gap))
          current_offset = current_offset + gap
        end
        if elem.Vartype == vtString or elem.Vartype == vtWideString then
          table.insert(out, ("    %s %s[%d];"):format(ctype, name, size))
          if elem.Vartype == vtWideString then
            current_offset = current_offset + size * 2
          else
            current_offset = current_offset + size
          end
        elseif elem.Vartype == vtPointer and elem.ChildStruct and elem.NestedStructure then
          table.insert(out, ("    %s %s;"):format(ctype, name))
          current_offset = current_offset + elem.Bytesize
        else
          local use_array = false
          local type_size = size
          if elem.Vartype == vtByte then type_size = 1
          elseif elem.Vartype == vtWord then type_size = 2
          elseif elem.Vartype == vtDword then type_size = 4
          elseif elem.Vartype == vtQword then type_size = 8
          elseif elem.Vartype == vtSingle then type_size = 4
          elseif elem.Vartype == vtDouble then type_size = 8
          elseif elem.Vartype == vtPointer then type_size = elem.Bytesize
          end
          if elem.Bytesize > type_size then
            use_array = true
          end
          if use_array then
            table.insert(out, ("    %s %s[%d];"):format(ctype, name, elem.Bytesize // type_size))
          else
            table.insert(out, ("    %s %s;"):format(ctype, name))
          end
          current_offset = current_offset + elem.Bytesize
        end
        for b = elem_offset, elem_end - 1 do
          used_bytes[b] = true
        end
      end
    end
  end

  table.insert(out, ("} %s;"):format(struct_name))
  table.insert(out, "")
  table.insert(out, "#endif // "..guard)
  if #child_struct_defs > 0 then
    table.insert(out, table.concat(child_struct_defs, "\n"))
  end
  return table.concat(out, "\n")
end

-- Usage in Cheat Engine:
-- local header = generate_c_header(structure)
-- print(header)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Extensions All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites