Merge pull request #20 from CarlPoppa1/CharFlags

Add character flags
This commit is contained in:
guiyomu-dev
2025-10-27 20:25:52 +01:00
committed by GitHub
2 changed files with 73 additions and 0 deletions

View File

@@ -1,6 +1,7 @@
package memory package memory
import ( import (
"errors"
"fmt" "fmt"
"log" "log"
"math" "math"
@@ -35,6 +36,13 @@ type MercOption struct {
Cost int Cost int
} }
type CharacterFlags struct {
Hardcore bool
HasEverDied bool
Expansion bool
Ladder bool
}
var WidgetStateFlags = map[string]uint64{ var WidgetStateFlags = map[string]uint64{
"WeaponSwap": 0xF2D7CF8E9CC08212, "WeaponSwap": 0xF2D7CF8E9CC08212,
} }
@@ -494,3 +502,60 @@ func (gd *GameReader) GetActiveWeaponSlot() int {
} }
return state return state
} }
func (gd *GameReader) GetCharacterFlags(characterName string) (CharacterFlags, error) {
const (
charDataHeaderSize = 16
charNameOffset = 0x010
charFlagsOffset = 0x122
maxCharCount = 47
flagHardcore = 0x04
flagDead = 0x08
flagExpansion = 0x20
flagLadder = 0x40
)
charDataPtr := gd.moduleBaseAddressPtr + gd.offset.CharData
if charDataPtr == 0 {
return CharacterFlags{}, errors.New("character data pointer is invalid")
}
headerBuffer := gd.Process.ReadBytesFromMemory(charDataPtr, charDataHeaderSize)
if len(headerBuffer) < charDataHeaderSize {
return CharacterFlags{}, errors.New("failed to read character data header")
}
charArrayPtr := uintptr(ReadUIntFromBuffer(headerBuffer, 0x00, Uint64))
charCount := int(ReadIntFromBuffer(headerBuffer, 0x08, Uint64))
if charArrayPtr == 0 || charCount <= 0 || charCount > maxCharCount {
return CharacterFlags{}, fmt.Errorf("invalid character metadata: arrayPtr=%v, count=%d", charArrayPtr, charCount)
}
charPointerArray := gd.Process.ReadBytesFromMemory(charArrayPtr, uint(charCount*8))
for i := 0; i < charCount; i++ {
charStructPtr := uintptr(ReadUIntFromBuffer(charPointerArray, uint(i*8), Uint64))
if charStructPtr == 0 {
continue
}
charName := gd.Process.ReadStringFromMemory(charStructPtr+charNameOffset, 0)
if charName == characterName {
fieldValue := uint16(gd.Process.ReadUInt(charStructPtr+charFlagsOffset, Uint16))
flags := CharacterFlags{
Hardcore: (fieldValue & flagHardcore) != 0,
HasEverDied: (fieldValue & flagDead) != 0,
Expansion: (fieldValue & flagExpansion) != 0,
Ladder: (fieldValue & flagLadder) != 0,
}
return flags, nil
}
}
return CharacterFlags{}, fmt.Errorf("character not found: %s", characterName)
}

View File

@@ -22,6 +22,7 @@ type Offset struct {
Quests uintptr Quests uintptr
Ping uintptr Ping uintptr
LegacyGraphics uintptr LegacyGraphics uintptr
CharData uintptr
} }
func calculateOffsets(process *Process) Offset { func calculateOffsets(process *Process) Offset {
@@ -118,6 +119,12 @@ func calculateOffsets(process *Process) Offset {
legacyGfxPtr := uintptr(process.ReadUInt(pattern+2, Uint32)) legacyGfxPtr := uintptr(process.ReadUInt(pattern+2, Uint32))
legacyGfxOffset := pattern - process.moduleBaseAddressPtr + 7 + legacyGfxPtr legacyGfxOffset := pattern - process.moduleBaseAddressPtr + 7 + legacyGfxPtr
// CharData
pattern = process.FindPattern(memory, "\x48\x8D\x05\x00\x00\x00\x00\x89\x93\xF4\x0C\x00\x00", "xxx????xxxxxx")
bytes = process.ReadBytesFromMemory(pattern+3, 4)
relativeOffset = int32(binary.LittleEndian.Uint32(bytes))
charDataOffset := pattern - process.moduleBaseAddressPtr + 7 + uintptr(relativeOffset)
return Offset{ return Offset{
GameData: gameDataOffset, GameData: gameDataOffset,
UnitTable: unitTableOffset, UnitTable: unitTableOffset,
@@ -136,5 +143,6 @@ func calculateOffsets(process *Process) Offset {
Quests: questDataOffset, Quests: questDataOffset,
Ping: pingOffset, Ping: pingOffset,
LegacyGraphics: legacyGfxOffset, LegacyGraphics: legacyGfxOffset,
CharData: charDataOffset,
} }
} }