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 


Update CE structures with new fields/offsets from Mono

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Extensions
View previous topic :: View next topic  
Author Message
HenryEx
Advanced Cheater
Reputation: 2

Joined: 18 Dec 2011
Posts: 97

PostPosted: Thu Jan 30, 2025 12:01 pm    Post subject: Update CE structures with new fields/offsets from Mono Reply with quote

function updateStructFromMonoClass( idx_struct, className, doDelete, verbose )

Tried of deleting and recreating your dissect structures after game updates, when offsets have shifted? Don't want to assign all your structure pointers anew and recreate all the local structures you've made?

Well, i was and wrote a simple function to automatically compare a current structure to a certain mono class and update the structure entries with new offsets, or add any entirely new fields into the structure.

This assumes that your structure entry name is identical to the class' field. If a field name changes between updates or you changed the structure entry name, a new entry will be created. You have the option to automatically delete any 'orphaned' structure entries upon update.

idx_struct is the integer index of the structure you want to update.
className is a string of the mono class to compare against.
doDelete == true will delete any entries that don't match the class fields
verbose is an integer, set to 1 or 2 for console output on what the function does


Put this into your autorun folder or paste it into your table's LUA script:

Code:
--- Update existing CE structure with with new offset / fields from a Mono class
-- Allows you to update structure offsets wtihout losing changes to existing fields
-- like structure pointers and local structures
-- @param idx_struct: integer index of CE Structure you want updated
-- @param className: string containing the mono class you want to take fields from
-- @param doDelete: Optional bool, deletes struct entries that don't correspond to current class fields
-- @param verbose: Optional integer; >0 prints info on structure changes, >1 prints all actions
-- @return true if structure was changed, false if not

function updateStructFromMonoClass( idx_struct, className, doDelete, verbose )
  if not idx_struct or not className then error('ERROR updateStructFromMonoClass: arguments malformed or missing!') end
  if idx_struct + 1 > getStructureCount() then error('ERROR updateStructFromMonoClass: structure index out of bounds!') end
  local classId = mono_findClass('', className)
  if not classId then error('ERROR updateStructFromMonoClass: no class ID found for given class name!') end
  verbose = type(verbose) == 'number' and verbose or 0
  local ver1 = verbose > 0 and true or false
  local ver2 = verbose > 1 and true or false
  local changed = false
  local st = getStructure(idx_struct)
  local st_name = st.getName()
  if ver1 then print( string.format('== Updating structure %s with mono class %s ==',st_name, className) ) end
  local st_count = st.Count
  local st_entry = {}


  for i = 1, st_count do st_entry[i] = st.getElement(i-1) end

  local st2 = monoform_exportStructInternal(createStructure(''), classId, true --[[recursive]], false --[[not static]], {'some struct map thing'}, false --[[not global]])
  local st2_count = st2.Count
  local st2_entry = {}
  for i = 1, st2_count do st2_entry[i] = st2.getElement(i-1) end

  local st2_tName = {}
  local st2_tOffset = {}

  for i = 1, st2_count do st2_tName[ st2_entry[i].Name ] = st2_entry[i].Offset end
  for i = 1, st2_count do st2_tOffset[ st2_entry[i].Offset ] = st2_entry[i].Name end

  -- simple offset adjust for existing fields
  st.beginUpdate()
  for i = 1, st_count do
    local ename = st_entry[i].Name
    if st2_tName[ename] then
      local newoff = st2_tName[ename]
      if st_entry[i].Offset ~= newoff then
        if ver1 then print( string.format('Updated offset of %s from %X to %X',ename,st_entry[i].Offset,newoff) ) end
        st_entry[i].Offset = newoff
        changed = true
      else
        if ver2 then print( string.format('Offset of %s unchanged from %X',ename,newoff) ) end
      end
    elseif doDelete then
      if ver1 then print( string.format( 'Entry %s not found, removed from structure', ename ) ) end
      st_entry[i].destroy()
    else
      if ver1 then print( string.format( 'Entry %s not found in new field list', ename ) ) end
    end
  end
  st.endUpdate()

  if st.Count ~= st_count then -- refresh if struct changed
    if ver2 then print('> Structure size changed, updating tables') end
    st_entry = {}
    st_count = st.Count
    for i = 1, st_count do st_entry[i] = st.getElement(i-1) end
    changed = true
  end


  local st_tName = {}
  for i = 1, st_count do st_tName[ st_entry[i].Name ] = st_entry[i].Offset end

  st.beginUpdate()
  for _,v in ipairs(st2_entry) do
    if not st_tName[v.Name] then -- check if new entry is in old struct
      if ver1 then print( string.format('Field %s not found, adding as new entry',v.Name) ) end
      local e = st.addElement()
      e.setName( v.getName() )
      e.setOffset( v.getOffset() )
      e.setVartype( v.getVartype() )
      e.setBytesize( v.getBytesize() )
      changed = true
    end
  end
  st.endUpdate()

  return changed

end




As a bonus, a small function to automatically update all table structures with the same name as a mono class, using the above function. The "doDelete" and "verbose" parameters get passed on to the above function.
Intentionally skips the "String" structure that gets auto-created by CE's mono features.

Code:
function updateAllMonoStructs( doDelete, verbose )
  verbose = type(verbose) == 'number' and verbose or 0
  local numStructs = getStructureCount()
  local numMonos = 0
  local numChanged = 0
  for i=0, numStructs-1 do
    repeat  -- workaround to continue for loop on break
      local stName = getStructure(i).Name
      local classId = mono_findClass('', stName)
      if not classId or stName == 'String' then break end
      numMonos = numMonos + 1
      local changed = updateStructFromMonoClass(i, stName, doDelete, verbose)
      if changed then
        numChanged = numChanged + 1
        if verbose > 0 then print(string.format('CHANGED: %s\n',stName)) end
      else
        if verbose > 0 then print(string.format('UNCHANGED: %s\n',stName)) end
      end
    until true
  end
  if verbose > 0 then print('Number of Mono Structures found:', numMonos) end
  if verbose > 0 then print('Number of Structures updated:', numChanged) end
end



edit: changed calling syntax from ':' to '.', since the former breaks the script in newer versions of CE. Hmmm.
Back to top
View user's profile Send private message
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