binana/profile/3.3.5a-windows-386/cheatengine/Load_CGUnit.lua

1299 lines
44 KiB
Lua
Raw Permalink Normal View History

2026-01-15 01:11:38 +03:00
local CE = {
vtByte = 0,
vtWord = 1,
vtDword = 2,
vtQword = 3,
vtSingle = 4,
vtDouble = 5,
vtString = 6,
vtGrouped = 14,
}
local Types = {
-- Unsigned integers
uint8 = { ce = CE.vtByte, size = 1 },
uint16 = { ce = CE.vtWord, size = 2 },
uint32 = { ce = CE.vtDword, size = 4 },
uint64 = { ce = CE.vtQword, size = 8 },
-- Signed integers
int8 = { ce = CE.vtByte, size = 1 },
int16 = { ce = CE.vtWord, size = 2 },
int32 = { ce = CE.vtDword, size = 4 },
int64 = { ce = CE.vtQword, size = 8 },
-- Floating point
float = { ce = CE.vtSingle, size = 4 },
double = { ce = CE.vtDouble, size = 8 },
-- Pointers
ptr = { ce = CE.vtDword, size = 4 },
ptr32 = { ce = CE.vtDword, size = 4 },
ptr64 = { ce = CE.vtQword, size = 8 },
-- Aliases
bool = { ce = CE.vtByte, size = 1 },
bool32 = { ce = CE.vtDword, size = 4 },
char = { ce = CE.vtByte, size = 1 },
byte = { ce = CE.vtByte, size = 1 },
word = { ce = CE.vtWord, size = 2 },
dword = { ce = CE.vtDword, size = 4 },
qword = { ce = CE.vtQword, size = 8 },
}
function SetPointerSize(bits)
if bits == 64 then
Types.ptr = { ce = CE.vtQword, size = 8 }
else
Types.ptr = { ce = CE.vtDword, size = 4 }
end
end
local StructDef = {}
StructDef.__index = StructDef
-- @param name
-- @param parent
function StructDef.new(name, parent)
local self = setmetatable({}, StructDef)
self.name = name
self.parent = parent
self.ownFields = {}
self.embeddings = {}
if parent then
self._offset = parent:totalSize()
else
self._offset = 0
end
return self
end
-- @param name
-- @param typeName (uint32, float, ptr etc)
-- @param opts {hex=bool, color=number}
function StructDef:field(name, typeName, opts)
opts = opts or {}
local typeInfo = Types[typeName]
if not typeInfo then
error(string.format("Unknown type '%s' for field '%s'", typeName, name))
end
table.insert(self.ownFields, {
fieldOffset = self._offset,
name = name,
type = typeInfo.ce,
size = typeInfo.size,
color = opts.color,
hex = opts.hex,
})
self._offset = self._offset + typeInfo.size
return self
end
StructDef.f = StructDef.field
--- Add hex-field
function StructDef:hex(name, typeName, opts)
opts = opts or {}
opts.hex = true
return self:field(name, typeName, opts)
end
--- Add string
function StructDef:string(name, size, opts)
opts = opts or {}
table.insert(self.ownFields, {
fieldOffset = self._offset,
name = name,
type = CE.vtString,
string_size = size,
size = size,
color = opts.color,
})
self._offset = self._offset + size
return self
end
--- Add array
function StructDef:array(name, typeName, count, opts)
opts = opts or {}
local typeInfo = Types[typeName]
if not typeInfo then
error(string.format("Unknown type '%s' for array '%s'", typeName, name))
end
for i = 0, count - 1 do
table.insert(self.ownFields, {
fieldOffset = self._offset + i * typeInfo.size,
name = string.format("%s[%d]", name, i),
type = typeInfo.ce,
size = typeInfo.size,
color = opts.color,
hex = opts.hex,
})
end
self._offset = self._offset + count * typeInfo.size
return self
end
--- skip to X bytes
function StructDef:paddingTo(targetOffset, opts)
local size = targetOffset - self._offset
if size <= 0 then
return self
end
opts = opts or {}
local remaining = size
while remaining >= 4 do
local name = string.format("unk_%04X", self._offset)
self:field(name, "uint32", opts)
remaining = remaining - 4
end
while remaining >= 1 do
local name = string.format("unk_%04X", self._offset)
self:field(name, "uint8", opts)
remaining = remaining - 1
end
return self
end
--- skip N bytes
function StructDef:padding(size, opts)
opts = opts or {}
local remaining = size
while remaining >= 4 do
local name = string.format("unk_%04X", self._offset)
self:field(name, "uint32", opts)
remaining = remaining - 4
end
while remaining >= 1 do
local name = string.format("unk_%04X", self._offset)
self:field(name, "uint8", opts)
remaining = remaining - 1
end
return self
end
function StructDef:skip(size)
self._offset = self._offset + size
return self
end
function StructDef:unk(size, opts)
opts = opts or {}
local name = string.format("unk_%04X", self._offset)
if size == 1 then
return self:field(name, "uint8", opts)
elseif size == 2 then
return self:field(name, "uint16", opts)
elseif size == 4 then
return self:field(name, "uint32", opts)
elseif size == 8 then
return self:field(name, "uint64", opts)
else
return self:array(name, "uint8", size, opts)
end
end
function StructDef:alignTo(alignment)
local rem = self._offset % alignment
if rem ~= 0 then
self._offset = self._offset + (alignment - rem)
end
return self
end
function StructDef:at(offset)
self._offset = offset
return self
end
function StructDef:currentOffset()
return self._offset
end
-- @param name
-- @param otherStruct
-- @param opts {expand=bool}
function StructDef:embed(name, otherStruct, opts)
opts = opts or {}
local baseOffset = self._offset
table.insert(self.embeddings, {
type = "embed",
name = name,
struct = otherStruct,
offset = baseOffset,
size = otherStruct:totalSize(),
expand = opts.expand or false,
})
for _, f in ipairs(otherStruct:getAllFields()) do
local newField = {}
for k, v in pairs(f) do
newField[k] = v
end
newField.fieldOffset = baseOffset + f.fieldOffset
newField.name = name .. "." .. f.name
newField.structName = nil
newField._embeddedIn = name
table.insert(self.ownFields, newField)
end
self._offset = self._offset + otherStruct:totalSize()
return self
end
-- @param name
-- @param otherStruct
-- @param count
-- @param opts {expand=bool}
function StructDef:structArray(name, otherStruct, count, opts)
opts = opts or {}
local structSize = otherStruct:totalSize()
local baseOffset = self._offset
table.insert(self.embeddings, {
type = "structArray",
name = name,
struct = otherStruct,
offset = baseOffset,
count = count,
size = count * structSize,
elemSize = structSize,
expand = opts.expand or false,
})
for i = 0, count - 1 do
local elemOffset = self._offset + i * structSize
for _, f in ipairs(otherStruct:getAllFields()) do
local newField = {}
for k, v in pairs(f) do
newField[k] = v
end
newField.fieldOffset = elemOffset + f.fieldOffset
newField.name = string.format("%s[%d].%s", name, i, f.name)
newField._embeddedIn = name
newField._arrayIndex = i
table.insert(self.ownFields, newField)
end
end
self._offset = self._offset + count * structSize
return self
end
-- :ptrArray("fieldName", count) -- void*[]
-- :ptrArray("fieldName", count, opts) -- void*[] with opts
-- :ptrArray("TypeName", "fieldName", count) -- TypeName*[]
-- :ptrArray("TypeName", "fieldName", count, opts) -- TypeName*[] with opts
function StructDef:ptrArray(arg1, arg2, arg3, arg4)
local typeName, fieldName, count, opts
if type(arg2) == "number" then
-- ptrArray("fieldName", count) or ptrArray("fieldName", count, opts)
typeName = nil
fieldName = arg1
count = arg2
opts = arg3 or {}
elseif type(arg2) == "string" then
-- ptrArray("TypeName", "fieldName", count) or ptrArray("TypeName", "fieldName", count, opts)
typeName = arg1
fieldName = arg2
count = arg3
opts = arg4 or {}
else
error("Invalid arguments for ptrArray()")
end
local typeInfo = Types.ptr
for i = 0, count - 1 do
table.insert(self.ownFields, {
fieldOffset = self._offset + i * typeInfo.size,
name = string.format("%s[%d]", fieldName, i),
type = typeInfo.ce,
size = typeInfo.size,
color = opts.color,
hex = true,
isPointer = true,
ptrType = typeName,
_ptrArrayBase = fieldName,
})
end
self._offset = self._offset + count * typeInfo.size
return self
end
function StructDef:ptr(arg1, arg2, arg3)
local typeName, fieldName, opts
if arg2 == nil then
-- ptr("fieldName")
typeName = nil
fieldName = arg1
opts = {}
elseif type(arg2) == "table" then
-- ptr("fieldName", opts)
typeName = nil
fieldName = arg1
opts = arg2
elseif type(arg2) == "string" then
-- ptr("TypeName", "fieldName") or ptr("TypeName", "fieldName", opts)
typeName = arg1
fieldName = arg2
opts = arg3 or {}
else
error("Invalid arguments for ptr()")
end
local typeInfo = Types.ptr
table.insert(self.ownFields, {
fieldOffset = self._offset,
name = fieldName,
type = typeInfo.ce,
size = typeInfo.size,
color = opts.color,
hex = true,
isPointer = true,
ptrType = typeName,
})
self._offset = self._offset + typeInfo.size
return self
end
function StructDef:toCStruct(options)
options = options or {}
local indent = options.indent or " "
local collapsePadding = options.collapsePadding ~= false
local flattenInheritance = options.flattenInheritance or false
local lines = {}
local ceToC = {
[CE.vtByte] = "uint8_t",
[CE.vtWord] = "uint16_t",
[CE.vtDword] = "uint32_t",
[CE.vtQword] = "uint64_t",
[CE.vtSingle] = "float",
[CE.vtDouble] = "double",
[CE.vtString] = "char",
}
local function getPtrTypeName(field)
return field.ptrType or "void"
end
local function sanitizeName(name)
return name:gsub("%.", "_"):gsub("%[", "_"):gsub("%]", "")
end
local function isUnkField(name)
return name:match("^unk_[%dA-Fa-f]+$") ~= nil
end
local function isUnkArray(name)
return name:match("^unk_[%dA-Fa-f]+%[%d+%]$") ~= nil
end
local function isAnyUnk(name)
return isUnkField(name) or isUnkArray(name)
end
local fields
local embeddingMap = {}
if flattenInheritance then
fields = self:getAllFields()
for _, emb in ipairs(self:getAllEmbeddings()) do
embeddingMap[emb.offset] = emb
end
else
fields = self.ownFields
for _, emb in ipairs(self.embeddings) do
embeddingMap[emb.offset] = emb
end
end
if flattenInheritance and self.parent then
table.insert(lines, string.format("// Inherits from: %s (size: 0x%X)", self.parent.name, self.parent:totalSize()))
end
table.insert(lines, string.format("struct %s {", self.name))
if not flattenInheritance and self.parent then
table.insert(lines, string.format("%s%s base; // 0x%04X", indent, self.parent.name, 0))
end
local i = 1
local processedEmbeddings = {}
while i <= #fields do
local field = fields[i]
local cType = ceToC[field.type] or "uint8_t"
local emb = embeddingMap[field.fieldOffset]
if emb and not processedEmbeddings[emb.name] then
processedEmbeddings[emb.name] = true
if emb.type == "embed" then
if emb.expand then
table.insert(lines, string.format("%sstruct { // %s::%s", indent, emb.struct.name, emb.name))
for _, sf in ipairs(emb.struct:getAllFields()) do
local subType = ceToC[sf.type] or "uint8_t"
if sf.type == CE.vtString and sf.string_size then
table.insert(lines, string.format("%s%schar %s[%d]; // +0x%02X", indent, indent, sanitizeName(sf.name), sf.string_size, sf.fieldOffset))
elseif sf.isPointer then
table.insert(lines, string.format("%s%s%s* %s; // +0x%02X", indent, indent, getPtrTypeName(sf), sanitizeName(sf.name), sf.fieldOffset))
else
table.insert(lines, string.format("%s%s%s %s; // +0x%02X", indent, indent, subType, sanitizeName(sf.name), sf.fieldOffset))
end
end
table.insert(lines, string.format("%s} %s; // 0x%04X",
indent, emb.name, emb.offset))
else
table.insert(lines, string.format("%s%s %s; // 0x%04X",
indent, emb.struct.name, emb.name, emb.offset))
end
while i <= #fields and fields[i]._embeddedIn == emb.name do
i = i + 1
end
elseif emb.type == "structArray" then
if emb.expand then
table.insert(lines, string.format("%sstruct { // %s element", indent, emb.struct.name))
for _, sf in ipairs(emb.struct:getAllFields()) do
local subType = ceToC[sf.type] or "uint8_t"
if sf.isPointer then
table.insert(lines, string.format("%s%s%s* %s; // +0x%02X", indent, indent, getPtrTypeName(sf), sanitizeName(sf.name), sf.fieldOffset))
else
table.insert(lines, string.format("%s%s%s %s; // +0x%02X", indent, indent, subType, sanitizeName(sf.name), sf.fieldOffset))
end
end
table.insert(lines, string.format("%s} %s[%d]; // 0x%04X (0x%X bytes)", indent, emb.name, emb.count, emb.offset, emb.size))
else
table.insert(lines, string.format("%s%s %s[%d]; // 0x%04X (0x%X bytes)", indent, emb.struct.name, emb.name, emb.count, emb.offset, emb.size))
end
while i <= #fields and fields[i]._embeddedIn == emb.name do
i = i + 1
end
end
elseif collapsePadding and isAnyUnk(field.name) then
local startOffset = field.fieldOffset
local totalSize = 0
local j = i
while j <= #fields do
local f = fields[j]
local expectedOffset = startOffset + totalSize
if isAnyUnk(f.name) and f.fieldOffset == expectedOffset then
totalSize = totalSize + f.size
j = j + 1
else
break
end
end
if totalSize > 0 then
table.insert(lines, string.format("%suint8_t pad_%04X[0x%X]; // 0x%04X", indent, startOffset, totalSize, startOffset))
end
i = j
elseif field.isPointer and field._ptrArrayBase and field.name:match("%[0%]$") then
local baseName = field._ptrArrayBase
local j = i + 1
local count = 1
while j <= #fields do
if fields[j]._ptrArrayBase == baseName then
count = count + 1
j = j + 1
else
break
end
end
table.insert(lines, string.format("%s%s* %s[%d]; // 0x%04X", indent, getPtrTypeName(field), baseName, count, field.fieldOffset))
i = j
elseif field.name:match("%[0%]$") and not field.name:find("%.") then
local baseName = field.name:match("^([^%[]+)")
local j = i + 1
local count = 1
while j <= #fields do
local bn, ci = fields[j].name:match("^([^%[%.]+)%[(%d+)%]$")
if bn == baseName and tonumber(ci) == count then
count = count + 1
j = j + 1
else
break
end
end
table.insert(lines, string.format("%s%s %s[%d]; // 0x%04X", indent, cType, baseName, count, field.fieldOffset))
i = j
elseif field.type == CE.vtString and field.string_size then
table.insert(lines, string.format("%schar %s[%d]; // 0x%04X", indent, sanitizeName(field.name), field.string_size, field.fieldOffset))
i = i + 1
elseif field.isPointer then
table.insert(lines, string.format("%s%s* %s; // 0x%04X", indent, getPtrTypeName(field), sanitizeName(field.name), field.fieldOffset))
i = i + 1
else
table.insert(lines, string.format("%s%s %s; // 0x%04X", indent, cType, sanitizeName(field.name), field.fieldOffset))
i = i + 1
end
end
table.insert(lines, string.format("}; // sizeof: 0x%X (%d bytes)", self:totalSize(), self:totalSize()))
return table.concat(lines, "\n")
end
function StructDef:getDependencies()
local deps = {}
local seen = {}
local function collect(struct)
if seen[struct.name] then return end
seen[struct.name] = true
if struct.parent then
collect(struct.parent)
end
for _, emb in ipairs(struct.embeddings) do
collect(emb.struct)
end
table.insert(deps, struct)
end
collect(self)
return deps
end
function StructDef:toCStructWithDeps(options)
local deps = self:getDependencies()
local parts = {}
for _, struct in ipairs(deps) do
table.insert(parts, struct:toCStruct(options))
end
return table.concat(parts, "\n\n")
end
function StructDef:getAllEmbeddings()
local result = {}
if self.parent then
for _, e in ipairs(self.parent:getAllEmbeddings()) do
table.insert(result, e)
end
end
for _, e in ipairs(self.embeddings) do
table.insert(result, e)
end
return result
end
function StructDef:totalSize()
return self._offset
end
function StructDef:getOwnFields()
return self.ownFields
end
function StructDef:getAllFields()
local fields = {}
if self.parent then
for _, f in ipairs(self.parent:getAllFields()) do
table.insert(fields, f)
end
end
for _, f in ipairs(self.ownFields) do
local newField = {}
for k, v in pairs(f) do
newField[k] = v
end
newField.structName = self.name
table.insert(fields, newField)
end
return fields
end
-- @param struct
-- @param baseAddress
-- @param options
function loadStructToTable(struct, baseAddress, options)
options = options or {}
local showStructName = options.showStructName ~= false
local parentRecord = options.parentRecord
local fields = struct:getAllFields()
for _, field in ipairs(fields) do
local memrec = AddressList.createMemoryRecord()
if type(baseAddress) == "string" then
memrec.Address = string.format("%s+0x%X", baseAddress, field.fieldOffset)
else
memrec.Address = string.format("0x%X", field.fieldOffset + baseAddress)
end
if showStructName and field.structName then
memrec.Description = string.format("0x%03X %s::%s", field.fieldOffset, field.structName, field.name)
else
memrec.Description = string.format("0x%03X %s", field.fieldOffset, field.name)
end
memrec.Type = field.type
if field.string_size then
memrec.String.Size = field.string_size
end
if field.color then
memrec.Color = field.color
end
if field.hex then
memrec.ShowAsHex = true
end
if parentRecord then
memrec.appendToEntry(parentRecord)
end
end
end
function Struct(name, parent)
return StructDef.new(name, parent)
end
function GetCGObjectAddr(guidValue)
if type(guidValue) == "string" then
guidValue = tonumber(guidValue, 16)
end
if not guidValue or guidValue == 0 then
return nil
end
local VTABLE_TYPES = {
[0xA34D90] = "unit",
[0xA326C8] = "player",
[0xA33428] = "item",
[0xA332D0] = "container",
[0xA331C8] = "corpse",
}
2026-01-15 01:11:38 +03:00
local memScan = createMemScan()
local foundList = createFoundList(memScan)
local function cleanup()
foundList.destroy()
memScan.destroy()
end
2026-01-15 01:11:38 +03:00
memScan.firstScan(
soExactValue, vtQword, rtRounded,
2026-01-15 01:11:38 +03:00
string.format("%016X", guidValue),
nil, 0x0, 0x7FFFFFFFFFFFFFFF,
"", fsmNotAligned, nil,
true, false, false, false
2026-01-15 01:11:38 +03:00
)
memScan.waitTillDone()
foundList.initialize()
for i = 0, foundList.Count - 1 do
local addr = tonumber(foundList.Address[i], 16)
if addr then
local base = addr - 0x30
local objType = VTABLE_TYPES[readInteger(base)]
if objType then
cleanup()
return base, objType
2026-01-15 01:11:38 +03:00
end
end
end
cleanup()
2026-01-15 01:11:38 +03:00
return nil
end
local CGObject = Struct("CGObject")
CGObject:ptr("void*", "VtablePtr") -- 0x0000
CGObject:unk(4) -- 0x0004
CGObject:ptr("dataBeginPtr") -- 0x0008
CGObject:ptr("dataEndPtr") -- 0x000C
CGObject:hex("unkFlag", "int32") -- 0x0010
CGObject:field("TypeID", "int32") -- 0x0014
CGObject:hex("low_GUID", "uint32") -- 0x0018
CGObject:paddingTo(0x30)
CGObject:hex("ObjectGuid", "uint64") -- 0x0030
CGObject:paddingTo(0x98)
CGObject:field("m_objectSacle1", "float") -- 0x0098
CGObject:field("m_objectSacle2", "float") -- 0x009C
CGObject:field("m_objectScalingEndMS", "int32") -- 0x00A0
CGObject:field("m_objectLastScale", "float") -- 0x00A4
CGObject:ptr("specialEffectPtr") -- 0x00A8
CGObject:field("objectHeight", "float") -- 0x00AC
CGObject:ptr("unkPlayerNamePtr") -- 0x00B0
2026-01-15 01:11:38 +03:00
CGObject:ptr("CM2Model", "m_model") -- 0x00B4
CGObject:ptr("cmapEntityPtr") -- 0x00B8
CGObject:hex("unkMovementFlags", "int32") -- 0x00BC
CGObject:field("unk_00C0", "int32") -- 0x00C0
CGObject:field("unk_00C4", "int32") -- 0x00C4
CGObject:field("m_alpha", "uint8") -- 0x00C8
CGObject:field("m_startAlpha", "uint8") -- 0x00C9
CGObject:field("m_endAlpha", "uint8") -- 0x00CA
CGObject:field("m_maxAlpha", "uint8") -- 0x00CB
CGObject:ptr("effectManagerPtr") -- 0x00CC
local Vector2 = Struct("Vector2")
:field("x", "float")
:field("y", "float")
local Vector3 = Struct("Vector3")
:field("x", "float")
:field("y", "float")
:field("z", "float")
local ObjectFields = Struct("ObjectFields")
:hex("GUID", "uint64")
:field("type", "uint32")
:field("unk", "uint32")
:field("scale", "float")
:field("pad", "uint32")
local UnitFields = Struct("UnitFields")
:hex("CharmGUID", "uint64") -- 0x1970
:hex("SummonGUID", "uint64") -- 0x1978
:hex("CritterGUID", "uint64") -- 0x1980
:hex("CharmedByGUID", "uint64") -- 0x1988
:hex("SummonedByGUID", "uint64") -- 0x1990
:hex("CreatedByGUID", "uint64") -- 0x1998
:hex("TargetGUID", "uint64") -- 0x19A0
:hex("ChannelSpellTargetGUID", "uint64") -- 0x19A8
:field("ChanellSpellId", "int32") -- 0x19B0
:field("Race", "uint8") -- 0x19B4
:field("Class", "uint8") -- 0x19B5
:field("Gender", "uint8") -- 0x19B6
:field("DisplayPower", "uint8") -- 0x19B7
:field("Health", "int32") -- 0x19B8
:field("Mana", "int32") -- 0x19BC
:field("Rage", "int32") -- 0x19C0
:field("Focus", "int32") -- 0x19C4
:field("Energy", "int32") -- 0x19C8
:field("UnkResource1", "int32") -- 0x19CC
:field("UnkResource2", "int32") -- 0x19D0
:field("RunePower", "int32") -- 0x19D4
:field("MaxHealth", "int32") -- 0x19D8
:field("MaxMana", "int32") -- 0x19DC
:field("MaxRage", "int32") -- 0x19E0
:field("MaxFocus", "int32") -- 0x19E4
:field("MaxEnergy", "int32") -- 0x19E8
:field("UnkMaxResource1", "int32") -- 0x19EC
:field("UnkMaxResource2", "int32") -- 0x19F0
:field("MaxRunePower", "int32") -- 0x19F4
:field("ManaRegenFlatMod", "float") -- 0x19F8
:field("RageRegenFlatMod", "float") -- 0x19FC
:field("FocusRegenFlatMod", "float") -- 0x1A00
:field("EnergyFlatMod", "float") -- 0x1A04
:field("UnkRegenFlatMod", "float") -- 0x1A08
:field("UnkRegenFlatMod", "float") -- 0x1A0C
:field("RunePowerRegenFlatMod", "float") -- 0x1A10
:field("ManaRegenInterruptedFlatMod", "float") -- 0x1A14
:field("RageRegenInterruptedFlatMod", "float") -- 0x1A18
:field("FocusRegenInterruptedFlatMod", "float") -- 0x1A1C
:field("EnergyRegenInterruptedFlatMod", "float") -- 0x1A20
:field("UnkRegenInterruptedFlatMod", "float") -- 0x1A24
:field("UnkRegenInterruptedFlatMod", "float") -- 0x1A28
:field("RunePowerRegenInterruptedFlatMod", "float") -- 0x1A2C
:field("Level", "int32") -- 0x1A30
:field("FieldFactiontemplate", "int32") -- 0x1A34
:field("VirtualItemSlotIdMainHand", "int32") -- 0x1A38
:field("VirtualItemSlotIdOffHand", "int32") -- 0x1A3C
:field("VirtualItemSlotIdRanged", "int32") -- 0x1A40
:field("Flag1", "int32") -- 0x1A44
:field("Flag2", "int32") -- 0x1A48
:field("AuraState", "int32") -- 0x1A4C
:field("BaseAttackTimeMainHand", "int32") -- 0x1A50
:field("BaseAttackTimeOffHand", "int32") -- 0x1A54
:field("RangedAttackTime", "int32") -- 0x1A58
:field("BoundingRadius", "float") -- 0x1A5C
:field("CombatReach", "float") -- 0x1A60
:field("DisplayId", "int32") -- 0x1A64
:field("NativedisplayId", "int32") -- 0x1A68
:field("MountdisplayId", "int32") -- 0x1A6C
:field("MinMainHandDamage", "float") -- 0x1A70
:field("MaxMainHandDamage", "float") -- 0x1A74
:field("MinOffHandDamage", "int32") -- 0x1A78
:field("MaxOffHandDamage", "int32") -- 0x1A7C
:field("SitState", "int32") -- 0x1A80
:field("PetNumber", "int32") -- 0x1A84
:field("PetNameTamestamp", "int32") -- 0x1A88
:field("PetXP", "int32") -- 0x1A8C
:field("PetNextLevelXP", "int32") -- 0x1A90
:field("DynFlags", "int32") -- 0x1A94
:field("ModCastSpeed", "float") -- 0x1A98
:field("CreatedBySpell", "int32") -- 0x1A9C
:field("NPCFlags", "int32") -- 0x1AA0
:field("NPCEmoteState", "int32") -- 0x1AA4
:field("StatStrengthBase", "int32") -- 0x1AA8
:field("StatAgilityBase", "int32") -- 0x1AAC
:field("StatStaminaBase", "int32") -- 0x1AB0
:field("StatIntellectBase", "int32") -- 0x1AB4
:field("StatSpiritBase", "int32") -- 0x1AB8
:field("StatStrengthPositive", "int32") -- 0x1ABC
:field("StatAgilityPositive", "int32") -- 0x1AC0
:field("StatStaminaPositive", "int32") -- 0x1AC4
:field("StatIntellectPositive", "int32") -- 0x1AC8
:field("StatSpiritPositive", "int32") -- 0x1ACC
:field("StatStrengthNegative", "int32") -- 0x1AD0
:field("StatAgilityNegative", "int32") -- 0x1AD4
:field("StatStaminaNegative", "int32") -- 0x1AD8
:field("StatIntellectNegative", "int32") -- 0x1ADC
:field("StatSpiritNegative", "int32") -- 0x1AE0
:field("StatArmor", "int32") -- 0x1AE4
:field("ResistHoly", "int32") -- 0x1AE8
:field("ResistFire", "int32") -- 0x1AEC
:field("ResistNature", "int32") -- 0x1AF0
:field("ResistFrost", "int32") -- 0x1AF4
:field("ResistShadow", "int32") -- 0x1AF8
:field("ResistArcane", "int32") -- 0x1AFC
:field("UnkResist", "int32") -- 0x1B00
:field("ResistPositiveHoly", "int32") -- 0x1B04
:field("ResistPositiveFire", "int32") -- 0x1B08
:field("ResistPovisitveNature", "int32") -- 0x1B0C
:field("ResistPositiveFrost", "int32") -- 0x1B10
:field("ResistPositiveShadow", "int32") -- 0x1B14
:field("ResistPositiveArcane", "int32") -- 0x1B18
:field("UnkResist", "int32") -- 0x1B1C
:field("ResistNegativeHoly", "int32") -- 0x1B20
:field("ResistNegativeFire", "int32") -- 0x1B24
:field("ResistNegativeNature", "int32") -- 0x1B28
:field("ResistNegativeFrost", "int32") -- 0x1B2C
:field("ResistNegativeShadow", "int32") -- 0x1B30
:field("ResistNegativeArcane", "int32") -- 0x1B34
:field("UnkBaseMana", "int32") -- 0x1B38
:field("BaseHealth", "int32") -- 0x1B3C
:field("WeaponStandType", "int32") -- 0x1B40
:field("AttackPowerMelee", "int32") -- 0x1B44
:field("AttackPowerMeleeMod", "int32") -- 0x1B48
:field("AttackPowerMeleeMulti", "float") -- 0x1B4C
:field("AttackPowerRange", "int32") -- 0x1B50
:field("AttackPowerRangedMod", "int32") -- 0x1B54
:field("AttackPowerRangedMulti", "float") -- 0x1B58
:field("MinRangedDamage", "float") -- 0x1B5C
:field("MaxRangedDamage", "float") -- 0x1B60
:array("PowerCostModifier", "int32", 7) -- 0x1B64
:array("PowerCostMultiplier", "float", 7) -- 0x1B80
:field("MaxHealthMod", "int32") -- 0x1B9C
:field("HoverHeight", "float") -- 0x1BA0
:field("Pad", "int32") -- 0x1BA4
local UnitAura = Struct("Aura")
:hex("casterGUID", "uint64") -- 0x0C50
:field("buffId", "int32") -- 0x0C58
:field("unk", "int32") -- 0x0C5C
:field("maxDuration", "int32") -- 0x0C60
:hex("buffPtr", "int32") -- 0x0C64
local UnitBuff = Struct("Buff")
:field("index", "int32")
:field("buffId", "int32")
local CMovementData = Struct("CMovementData")
:field("unk_0788", "int32") -- 0x0788
:field("unk_078C", "int32") -- 0x078C
:hex("TransportGUID", "uint64") -- 0x0790
:embed("Position", Vector3)
:hex("unkFlag", "int32") -- 0x07A4
:field("Facing", "float") -- 0x07A8
:field("Pitch", "float") -- 0x07AC
:hex("dataPtr", "int32") -- 0x07B0
:hex("unkFlag2", "int32") -- 0x07B4
:field("unk_07B8", "int32") -- 0x07B8
:field("unk_07BC", "int32") -- 0x07BC
:embed("GroundNormal", Vector3)
:hex("moveFlag1", "int32") -- 0x07CC
:hex("moveFlag2", "int32") -- 0x07D0
:embed("Anchor", Vector3)
:field("AnchorFacing", "float") -- 0x07E0
:field("AnchorPitch", "float") -- 0x07E4
:field("unk_07E8", "int32") -- 0x07E8
:embed("Direction", Vector3)
:embed("Direction2d", Vector2)
:field("cosAnchorPitch", "float") -- 0x0800
:field("sinAnchorPitch", "float") -- 0x0804
:field("FallTime", "int32") -- 0x0808
:field("StartFallHeight", "float") -- 0x080C
:field("unkFloat", "float") -- 0x0810
:field("MoveSpeed", "float") -- 0x0814
:field("WalkSpeed", "float") -- 0x0818
:field("RunSpeed", "float") -- 0x081C
:field("BackSpeed", "float") -- 0x0820
:field("SwimSpeed", "float") -- 0x0824
:field("BackSwimSpeed", "float") -- 0x0828
:field("FlyMountSpeed", "float") -- 0x082C
:field("FlyMountBackSpeed", "float") -- 0x0830
:field("TurnSpeed", "float") -- 0x0834
:field("FlyMountUnkUpDownRotation1", "float") -- 0x0838
:field("FlyMountUnkUpDownRotation2", "float") -- 0x083C
:field("FallSpeed", "float") -- 0x0840
:hex("CGMoveSplinePtr", "int32") -- 0x0844
:field("PerfCount", "int32") -- 0x0848
:hex("unkFlag3", "int32") -- 0x084C
:field("CollisonBoxHalfWidth", "float") -- 0x0850
:field("CollisionBoxHeight", "float") -- 0x0854
:field("ObjectScale", "float") -- 0x0858
:field("unk_085C", "int32") -- 0x085C
:field("unk_0860", "int32") -- 0x0860
:field("unk_0864", "int32") -- 0x0864
:field("unk_0868", "int32") -- 0x0868
:field("unk_086C", "int32") -- 0x086C
:hex("unkFlags_00", "int32") -- 0x0870
:hex("unkFlags_01", "int32") -- 0x0874
:hex("unkFlags_02", "int32") -- 0x0878
:hex("unkFlags_03", "int32") -- 0x087C
:hex("unkFlags_04", "int32") -- 0x0880
:hex("unkFlags_05", "int32") -- 0x0884
:hex("unkFlags_06", "int32") -- 0x0888
:hex("unkFlags_07", "int32") -- 0x088C
:hex("unkFlags_08", "int32") -- 0x0890
:hex("unkFlags_09", "int32") -- 0x0894
:hex("unkFlags_10", "int32") -- 0x0898
:hex("unkFlags_11", "int32") -- 0x089C
:hex("unkFlags_12", "int32") -- 0x08A0
:hex("unkFlags_13", "int32") -- 0x08A4
:hex("unkFlags_14", "int32") -- 0x08A8
:hex("unkFlags_15", "int32") -- 0x08AC
:field("unk_08B0", "int32") -- 0x08B0
:field("unk_08B4", "int32") -- 0x08B4
:field("unk_08B8", "int32") -- 0x08B8
:field("unk_08BC", "int32") -- 0x08BC
:field("unk_08C0", "int32") -- 0x08C0
:ptr("linkedList_ptr1") -- 0x08C4
:ptr("linkedList_ptr2") -- 0x08C8
:ptr("CGObject_C", "objectPtr") -- 0x08CC
local CGUnit = Struct("CGUnit", CGObject)
:ptr("unitDataPtr") -- 0x00D0
:ptr("unk_00D4") -- 0x00D4
:ptr("CMovementData", "m_moveDataPtr") -- 0x00D8
--mirror handlers
:paddingTo(0x788)
:embed("CMovementData", CMovementData) -- 0x0788
:field("unitFacingAngle", "float") -- 0x08D0
:field("unk_08D4", "int32") -- 0x08D4
:field("unk_08D8", "int32") -- 0x08D8
:field("unitFacingAngle", "float") -- 0x08DC
:field("unk_08E0", "int32") -- 0x08E0
:field("unk_08E4", "int32") -- 0x08E4
:field("unk_08E8", "int32") -- 0x08E8
:field("unk_08EC", "int32") -- 0x08EC
:field("unk_08F0", "int32") -- 0x08F0
:field("unk_08F4", "int32") -- 0x08F4
:field("unk_08F8", "int32") -- 0x08F8
:field("unk_08FC", "int32") -- 0x08FC
:field("unk_0900", "int32") -- 0x0900
:field("unk_0904", "int32") -- 0x0904
:field("unk_0908", "int32") -- 0x0908
:field("unk_090C", "int32") -- 0x090C
:field("unk_0910", "int32") -- 0x0910
:field("unk_0914", "int32") -- 0x0914
:field("unk_0918", "int32") -- 0x0918
:field("unk_091C", "int32") -- 0x091C
:field("unk_0920", "int32") -- 0x0920
:field("unk_0924", "int32") -- 0x0924
:field("unk_0928", "int32") -- 0x0928
:field("unk_092C", "int32") -- 0x092C
:field("unk_0930", "int32") -- 0x0930
:field("unk_0934", "int32") -- 0x0934
:field("unk_0938", "int32") -- 0x0938
:field("unk_093C", "int32") -- 0x093C
:field("unk_0940", "int32") -- 0x0940
:field("unk_0944", "int32") -- 0x0944
:field("unk_0948", "int32") -- 0x0948
:field("unk_094C", "int32") -- 0x094C
:field("unk_0950", "int32") -- 0x0950
:field("unk_0954", "int32") -- 0x0954
:ptr("unk_0958") -- 0x0958
:ptr("unk_095C") -- 0x095C
:field("unk_0960", "int32") -- 0x0960
:ptr("unkCreatureStatsPtr") -- 0x0964
:ptr("CreatureDisplayInfoPtr") -- 0x0968
:ptr("CreatureDisplayInfoExtraPtr") -- 0x096C
:ptr("CreatureModelDataPtr") -- 0x0970
:ptr("CreatureSoundDataPtr") -- 0x0974
:ptr("mountedCreatureSoundDataPtr") -- 0x0978
:ptr("unkBloodPoolPtr") -- 0x097C
:field("unk_0980", "int32") -- 0x0980
:field("unk_0984", "int32") -- 0x0984
:field("unk_0988", "int32") -- 0x0988
:ptr("m_mountM2modelPtr") -- 0x098C
:field("m_mountScale", "float") -- 0x0990
:ptr("unk_0994") -- 0x0994
:field("unk_0998", "int32") -- 0x0998
:field("unk_099C", "int32") -- 0x099C
:field("unk_09A0", "int32") -- 0x09A0
:field("unk_09A4", "int32") -- 0x09A4
:field("unk_09A8", "int32") -- 0x09A8
:field("unk_09AC", "int32") -- 0x09AC
:field("unk_09B0", "int32") -- 0x09B0
:field("unk_09B4", "int32") -- 0x09B4
:field("unk_09B8", "int32") -- 0x09B8
:field("objectNextUpdateMillisec", "int32") -- 0x09BC
:field("mountModelId", "int32") -- 0x09C0
:field("unk_09C4", "int32") -- 0x09C4
:field("unk_09C8", "int32") -- 0x09C8
:field("unk_09CC", "int32") -- 0x09CC
:field("unk_09D0", "int32") -- 0x09D0
:field("unk_09D4", "int32") -- 0x09D4
:embed("GroundNormal", Vector3)
:field("unk_09E4", "int32") -- 0x09E4
:field("unk_09E8", "int32") -- 0x09E8
:field("unk_09EC", "int32") -- 0x09EC
:field("unk_09F0", "int32") -- 0x09F0
:ptr("unk_09F4") -- 0x09F4
:field("unk_09F8", "int32") -- 0x09F8
:field("unk_09FC", "int32") -- 0x09FC
:ptr("unk_0A00") -- 0x0A00
:field("unk_0A04", "int32") -- 0x0A04
:field("unk_0A08", "int32") -- 0x0A08
:field("unk_0A0C", "int32") -- 0x0A0C
:field("unk_0A10", "int32") -- 0x0A10
:field("unk_0A14", "int32") -- 0x0A14
:field("unk_0A18", "int32") -- 0x0A18
:field("unk_0A1C", "int32") -- 0x0A1C
:hex("unkGUID", "uint64") -- 0x0A20
:field("unk_0A28", "int32") -- 0x0A28
:field("unk_0A2C", "int32") -- 0x0A2C
:hex("unkJumpFlags", "int32") -- 0x0A30
:field("unk_0A34", "int32") -- 0x0A34
:hex("unk_0A38", "int32") -- 0x0A38
:field("m_footprintTexId", "int32") -- 0x0A3C
:field("m_terrain", "int32") -- 0x0A40
:embed("m_footPrintSize", Vector2)
:field("m_footPrintScale", "float") -- 0x0A4C
:field("m_facingAngle", "float") -- 0x0A50
:field("m_pitchAngle", "float") -- 0x0A54
:ptr("unk_0A58") -- 0x0A58
:field("UnkSpellCounter", "int32") -- 0x0A5C
:field("m_channelSpellId", "int32") -- 0x0A60
:field("unk_0A64", "int32") -- 0x0A64
:field("unk_0A68", "int32") -- 0x0A68
:field("m_channelSpellId", "int32") -- 0x0A6C
:field("unkCastSchoolImmunFlag", "int32") -- 0x0A70
:field("unkCastImmunFlag", "int32") -- 0x0A74
:field("m_spellCastStartMS", "int32") -- 0x0A78
:field("m_spellCastEndMS", "int32") -- 0x0A7C
:field("unk_0A80", "int32") -- 0x0A80
:field("unk_0A84", "int32") -- 0x0A84
:field("unk_0A88", "int32") -- 0x0A88
:field("unk_0A8C", "int32") -- 0x0A8C
:field("unk_0A90", "int32") -- 0x0A90
:field("m_facingAngle", "float") -- 0x0A94
:field("unkAnimValue", "float") -- 0x0A98
:field("unkAnimValue", "float") -- 0x0A9C
:field("m_HeadFacingAngle", "float") -- 0x0AA0
:field("unk_0AA4", "int32") -- 0x0AA4
:field("unk_0AA8", "int32") -- 0x0AA8
:embed("SmoothFacing", Vector3)
:ptr("unk_0AB8") -- 0x0AB8
:field("objectUpdateMillisec", "int32") -- 0x0ABC
:field("unk_0AC0", "int32") -- 0x0AC0
:field("unk_0AC4", "int32") -- 0x0AC4
:field("unk_0AC8", "int32") -- 0x0AC8
:ptr("unkSoundPtr") -- 0x0ACC
:field("unk_0AD0", "int32") -- 0x0AD0
:field("unk_0AD4", "int32") -- 0x0AD4
:field("m_mountFootprintTexId", "int32") -- 0x0AD8
:embed("m_mountFootprintSize", Vector2)
:ptr("unk_0AE4", "int32") -- 0x0AE4
:ptr("unk_0AE8", "int32") -- 0x0AE8
:ptr("unk_0AEC", "int32") -- 0x0AEC
:field("unk_0AF0", "int32") -- 0x0AF0
:field("unk_0AF4", "int32") -- 0x0AF4
:field("unk_0AF8", "int32") -- 0x0AF8
:field("unk_0AFC", "int32") -- 0x0AFC
:field("unk_0B00", "int32") -- 0x0B00
:field("unk_0B04", "int32") -- 0x0B04
:field("unk_0B08", "int32") -- 0x0B08
:field("m_selectionRadius", "float") -- 0x0B0C
:field("unk_0B10", "int32") -- 0x0B10
:field("unk_0B14", "int32") -- 0x0B14
:field("unkFloatValue", "float") -- 0x0B18
:field("unk_0B1C", "int32") -- 0x0B1C
:field("unk_0B20", "int32") -- 0x0B20
:field("unk_0B24", "int32") -- 0x0B24
:field("unk_0B28", "int32") -- 0x0B28
:field("unk_0B2C", "int32") -- 0x0B2C
:field("unk_0B30", "int32") -- 0x0B30
:field("unk_0B34", "int32") -- 0x0B34
:field("unk_0B38", "int32") -- 0x0B38
:field("m_unitScale", "float") -- 0x0B3C
:ptr("unkDisplayModeIdRangedPtr") -- 0x0B40
:field("unk_0B44", "int32") -- 0x0B44
:field("unk_0B48", "int32") -- 0x0B48
:ptr("CCharacterComponentPtr") -- 0x0B4C
:ptr("unkEquipedMainHandModelPtr") -- 0x0B50
:field("unk_0B54", "int32") -- 0x0B54
:hex("unkObjectWeaponLastStandValue", "int32") -- 0x0B58
:hex("unkObjectWeaponCurrentStandFlag", "int32") -- 0x0B5C
:field("unk_0B60", "int32") -- 0x0B60
:field("unk_0B64", "int32") -- 0x0B64
:field("unk_0B68", "int32") -- 0x0B68
:field("unk_0B6C", "int32") -- 0x0B6C
:field("unk_0B70", "int32") -- 0x0B70
:field("unk_0B74", "int32") -- 0x0B74
:field("unk_0B78", "int32") -- 0x0B78
:field("unk_0B7C", "int32") -- 0x0B7C
:field("unk_0B80", "int32") -- 0x0B80
:field("unk_0B84", "int32") -- 0x0B84
:hex("unk_0B88", "uint32") -- 0x0B88
:hex("unk_0B8C", "uint32") -- 0x0B8C
:hex("unk_0B90", "uint32") -- 0x0B90
:field("unk_0B94", "int32") -- 0x0B94
:field("unk_0B98", "int32") -- 0x0B98
:field("unk_0B9C", "int32") -- 0x0B9C
:field("unk_0BA0", "int32") -- 0x0BA0
:field("unk_0BA4", "int32") -- 0x0BA4
:field("unk_0BA8", "int32") -- 0x0BA8
:field("unk_0BAC", "int32") -- 0x0BAC
:field("unk_0BB0", "int32") -- 0x0BB0
:field("unk_0BB4", "int32") -- 0x0BB4
:field("unk_0BB8", "int32") -- 0x0BB8
:field("unk_0BBC", "int32") -- 0x0BBC
:field("unk_0BC0", "int32") -- 0x0BC0
:field("unk_0BC4", "int32") -- 0x0BC4
:field("unk_0BC8", "int32") -- 0x0BC8
:field("unkFloatValue", "float") -- 0x0BCC
:field("unk_0BD0", "int32") -- 0x0BD0
:field("unk_0BD4", "int32") -- 0x0BD4
:field("unk_0BD8", "int32") -- 0x0BD8
:field("unk_0BDC", "int32") -- 0x0BDC
:field("unk_0BE0", "int32") -- 0x0BE0
:field("unk_0BE4", "int32") -- 0x0BE4
:field("unk_0BE8", "int32") -- 0x0BE8
:hex("UnkCombatFlag", "int32") -- 0x0BEC
:field("unk_0BF0", "int32") -- 0x0BF0
:field("unk_0BF4", "int32") -- 0x0BF4
:field("unk_0BF8", "int32") -- 0x0BF8
:field("unk_0BFC", "int32") -- 0x0BFC
:field("unk_0C00", "int32") -- 0x0C00
:field("unk_0C04", "int32") -- 0x0C04
:field("unk_0C08", "int32") -- 0x0C08
:field("unk_0C0C", "int32") -- 0x0C0C
:field("unk_0C10", "int32") -- 0x0C10
:field("unk_0C14", "int32") -- 0x0C14
:field("unk_0C18", "int32") -- 0x0C18
:field("unk_0C1C", "int32") -- 0x0C1C
:field("unk_0C20", "int32") -- 0x0C20
:field("unk_0C24", "int32") -- 0x0C24
:field("unk_0C28", "int32") -- 0x0C28
:field("unk_0C2C", "int32") -- 0x0C2C
:field("unk_0C30", "int32") -- 0x0C30
:field("unk_0C34", "int32") -- 0x0C34
:ptr("CGNamePlateFramePtr") -- 0x0C38
:field("unk_0C3C", "int32") -- 0x0C3C
:field("unk_0C40", "int32") -- 0x0C40
:field("unk_0C44", "int32") -- 0x0C44
:field("unk_0C48", "int32") -- 0x0C48
:field("unk_0C4C", "int32") -- 0x0C4C
:structArray("UnitAura", UnitAura, 16)
:field("m_auraCount", "int32") -- 0x0DD0
:structArray("UnitBuff", UnitBuff, 16)
:field("auraCount", "int32") -- 0x0E54
:structArray("UnitBuffSorted", UnitBuff, 16)
:paddingTo(0xFB0)
:field("UnitHealthPredicted", "int32") -- 0x0FB0
:field("UnitManaPredicted", "int32") -- 0x0FB4
:field("UnitRagePredicted", "int32") -- 0x0FB8
:field("UnitFocusPredicted", "int32") -- 0x0FBC
:field("UnitEnergyPredicted", "int32") -- 0x0FC0
:field("UnkPowerPredicted", "int32") -- 0x0FC4
:field("UnkPowerPredicted", "int32") -- 0x0FC8
:field("UnitRunePowerPredicted", "int32") -- 0x0FCC
:field("UnkPowerPredictionTimer", "int32") -- 0x0FD0
:field("unk_0FD4", "int32") -- 0x0FD4
:field("unk_0FD8", "int32") -- 0x0FD8
:field("unk_0FDC", "int32") -- 0x0FDC
:ptr("ThreatVtblPtr") -- 0x0FE0
:field("unk_0FE4", "int32") -- 0x0FE4
:field("unk_0FE8", "int32") -- 0x0FE8
:field("unk_0FEC", "int32") -- 0x0FEC
:field("unk_0FF0", "int32") -- 0x0FF0
:field("unk_0FF4", "int32") -- 0x0FF4
:field("unk_0FF8", "int32") -- 0x0FF8
:field("unk_0FFC", "int32") -- 0x0FFC
:field("unk_1000", "int32") -- 0x1000
:field("unk_1004", "int32") -- 0x1004
:hex("playerBeginPtr", "int32") -- 0x1008 --if not a player then 8 byte GUID
:hex("playerEndPtr", "int32") -- 0x100C
:field("unk_1010", "int32") -- 0x1010
:paddingTo(0x1068)
:field("Health", "uint32") -- 0x1068
:field("Mana", "uint32") -- 0x106C
:paddingTo(0x1088)
:field("MaxHealth", "uint32") -- 0x1088
:field("MaxMana", "uint32") -- 0x108C
:paddingTo(0x1110)
:field("maxInteractDistance", "float") -- 0x1100
:padding(0x33C)
local addr, typ = GetCGObjectAddr(readQword(0x00bd07b0)) -- target guid
if addr then
if typ == "unit" then
loadStructToTable(CGUnit, addr)
end
end