272 lines
7.8 KiB
Go
272 lines
7.8 KiB
Go
package memory
|
|
|
|
import (
|
|
"github.com/hectorgimenez/d2go/pkg/data"
|
|
"github.com/hectorgimenez/d2go/pkg/data/area"
|
|
"github.com/hectorgimenez/d2go/pkg/data/skill"
|
|
"github.com/hectorgimenez/d2go/pkg/data/stat"
|
|
"github.com/hectorgimenez/d2go/pkg/data/state"
|
|
)
|
|
|
|
func (gd *GameReader) GetPlayerUnitPtr(roster data.Roster) (playerUnitPtr uintptr, corpse data.Corpse) {
|
|
for i := 0; i < 128; i++ {
|
|
unitOffset := gd.offset.UnitTable + uintptr(i*8)
|
|
playerUnitAddr := gd.Process.moduleBaseAddressPtr + unitOffset
|
|
playerUnit := uintptr(gd.Process.ReadUInt(playerUnitAddr, Uint64))
|
|
for playerUnit > 0 {
|
|
pInventory := playerUnit + 0x90
|
|
inventoryAddr := uintptr(gd.Process.ReadUInt(pInventory, Uint64))
|
|
|
|
pPath := playerUnit + 0x38
|
|
pathAddress := uintptr(gd.Process.ReadUInt(pPath, Uint64))
|
|
xPos := gd.Process.ReadUInt(pathAddress+0x02, Uint16)
|
|
yPos := gd.Process.ReadUInt(pathAddress+0x06, Uint16)
|
|
|
|
// Only current player has inventory
|
|
if inventoryAddr > 0 && xPos > 0 && yPos > 0 {
|
|
expCharPtr := uintptr(gd.Process.ReadUInt(gd.moduleBaseAddressPtr+gd.offset.Expansion, Uint64))
|
|
expChar := gd.Process.ReadUInt(expCharPtr+0x5C, Uint16)
|
|
baseCheck := gd.Process.ReadUInt(inventoryAddr+0x30, Uint16)
|
|
if expChar > 0 {
|
|
baseCheck = gd.Process.ReadUInt(inventoryAddr+0x70, Uint16)
|
|
}
|
|
|
|
if baseCheck > 0 {
|
|
isCorpse := gd.Process.ReadUInt(playerUnit+0x1A6, Uint8)
|
|
|
|
if isCorpse == 1 {
|
|
unitID := gd.Process.ReadUInt(playerUnit+0x08, Uint32)
|
|
hoveredUnitID, hoveredType, isHovered := gd.hoveredData()
|
|
corpse = data.Corpse{
|
|
Found: true,
|
|
IsHovered: isHovered && hoveredUnitID == unitID && hoveredType == 0,
|
|
Position: data.Position{
|
|
X: int(xPos),
|
|
Y: int(yPos),
|
|
},
|
|
}
|
|
} else {
|
|
playerUnitPtr = playerUnit
|
|
}
|
|
} else {
|
|
pUnitData := playerUnit + 0x10
|
|
playerNameAddr := uintptr(gd.Process.ReadUInt(pUnitData, Uint64))
|
|
name := gd.Process.ReadStringFromMemory(playerNameAddr, 0)
|
|
for k, rm := range roster {
|
|
if name != rm.Name {
|
|
continue
|
|
}
|
|
|
|
roster[k] = data.RosterMember{
|
|
Name: name,
|
|
Area: rm.Area,
|
|
Position: data.Position{
|
|
X: int(xPos),
|
|
Y: int(yPos),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
playerUnit = uintptr(gd.Process.ReadUInt(playerUnit+0x150, Uint64))
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (gd *GameReader) GetPlayerUnit(playerUnit uintptr) data.PlayerUnit {
|
|
// Read X and Y Positions
|
|
pPath := playerUnit + 0x38
|
|
pathAddress := uintptr(gd.Process.ReadUInt(pPath, Uint64))
|
|
xPos := gd.Process.ReadUInt(pathAddress+0x02, Uint16)
|
|
yPos := gd.Process.ReadUInt(pathAddress+0x06, Uint16)
|
|
|
|
// Player name
|
|
pUnitData := playerUnit + 0x10
|
|
playerNameAddr := uintptr(gd.Process.ReadUInt(pUnitData, Uint64))
|
|
name := gd.Process.ReadStringFromMemory(playerNameAddr, 0)
|
|
|
|
// Get Stats
|
|
statsListExPtr := uintptr(gd.Process.ReadUInt(playerUnit+0x88, Uint64))
|
|
statPtr := gd.Process.ReadUInt(statsListExPtr+0x30, Uint64)
|
|
statCount := gd.Process.ReadUInt(statsListExPtr+0x38, Uint64)
|
|
|
|
stats := map[stat.Stat]int{}
|
|
for j := 0; j < int(statCount); j++ {
|
|
statOffset := uintptr(statPtr) + 0x2 + uintptr(j*8)
|
|
statNumber := gd.Process.ReadUInt(statOffset, Uint16)
|
|
statValue := gd.Process.ReadUInt(statOffset+0x02, Uint32)
|
|
|
|
switch stat.Stat(statNumber) {
|
|
case stat.Life,
|
|
stat.MaxLife,
|
|
stat.Mana,
|
|
stat.MaxMana:
|
|
stats[stat.Stat(statNumber)] = int(uint32(statValue) >> 8)
|
|
default:
|
|
stats[stat.Stat(statNumber)] = int(statValue)
|
|
}
|
|
}
|
|
|
|
// States (Buff, Debuff, Auras)
|
|
states := gd.getStates(statsListExPtr)
|
|
|
|
// Skills
|
|
skills := gd.getSkills(playerUnit + 0x100)
|
|
|
|
// Level number
|
|
pathPtr := uintptr(gd.Process.ReadUInt(playerUnit+0x38, Uint64))
|
|
room1Ptr := uintptr(gd.Process.ReadUInt(pathPtr+0x20, Uint64))
|
|
room2Ptr := uintptr(gd.Process.ReadUInt(room1Ptr+0x18, Uint64))
|
|
levelPtr := uintptr(gd.Process.ReadUInt(room2Ptr+0x90, Uint64))
|
|
levelNo := gd.Process.ReadUInt(levelPtr+0x1F8, Uint32)
|
|
|
|
return data.PlayerUnit{
|
|
Name: name,
|
|
Area: area.Area(levelNo),
|
|
Position: data.Position{
|
|
X: int(xPos),
|
|
Y: int(yPos),
|
|
},
|
|
Stats: stats,
|
|
Skills: skills,
|
|
States: states,
|
|
}
|
|
}
|
|
|
|
func (gd *GameReader) getSkills(skillsPtr uintptr) map[skill.Skill]int {
|
|
skills := make(map[skill.Skill]int)
|
|
skillListPtr := uintptr(gd.Process.ReadUInt(skillsPtr, Uint64))
|
|
|
|
skillPtr := uintptr(gd.Process.ReadUInt(skillListPtr, Uint64))
|
|
|
|
for skillPtr != 0 {
|
|
skillTxtPtr := uintptr(gd.Process.ReadUInt(skillPtr, Uint64))
|
|
skillTxt := uintptr(gd.Process.ReadUInt(skillTxtPtr, Uint16))
|
|
skillLvl := gd.Process.ReadUInt(skillTxtPtr+0x34, Uint16)
|
|
|
|
skills[skill.Skill(skillTxt)] = int(skillLvl)
|
|
|
|
skillPtr = uintptr(gd.Process.ReadUInt(skillPtr+0x08, Uint64))
|
|
}
|
|
|
|
return skills
|
|
}
|
|
|
|
func (gd *GameReader) getStates(statsListExPtr uintptr) []state.State {
|
|
var states []state.State
|
|
for i := 0; i < 6; i++ {
|
|
offset := i * 4
|
|
stateByte := gd.Process.ReadUInt(statsListExPtr+0xAD0+uintptr(offset), Uint32)
|
|
|
|
offset = (32 * i) - 1
|
|
states = append(states, calculateStates(stateByte, uint(offset))...)
|
|
}
|
|
|
|
return states
|
|
}
|
|
|
|
func calculateStates(stateFlag uint, offset uint) []state.State {
|
|
var states []state.State
|
|
if 0x00000001&stateFlag != 0 {
|
|
states = append(states, state.State(1+offset))
|
|
}
|
|
if 0x00000002&stateFlag != 0 {
|
|
states = append(states, state.State(2+offset))
|
|
}
|
|
if 0x00000004&stateFlag != 0 {
|
|
states = append(states, state.State(3+offset))
|
|
}
|
|
if 0x00000008&stateFlag != 0 {
|
|
states = append(states, state.State(4+offset))
|
|
}
|
|
if 0x00000010&stateFlag != 0 {
|
|
states = append(states, state.State(5+offset))
|
|
}
|
|
if 0x00000020&stateFlag != 0 {
|
|
states = append(states, state.State(6+offset))
|
|
}
|
|
if 0x00000040&stateFlag != 0 {
|
|
states = append(states, state.State(7+offset))
|
|
}
|
|
if 0x00000080&stateFlag != 0 {
|
|
states = append(states, state.State(8+offset))
|
|
}
|
|
if 0x00000100&stateFlag != 0 {
|
|
states = append(states, state.State(9+offset))
|
|
}
|
|
if 0x00000200&stateFlag != 0 {
|
|
states = append(states, state.State(10+offset))
|
|
}
|
|
if 0x00000400&stateFlag != 0 {
|
|
states = append(states, state.State(11+offset))
|
|
}
|
|
if 0x00000800&stateFlag != 0 {
|
|
states = append(states, state.State(12+offset))
|
|
}
|
|
if 0x00001000&stateFlag != 0 {
|
|
states = append(states, state.State(13+offset))
|
|
}
|
|
if 0x00002000&stateFlag != 0 {
|
|
states = append(states, state.State(14+offset))
|
|
}
|
|
if 0x00004000&stateFlag != 0 {
|
|
states = append(states, state.State(15+offset))
|
|
}
|
|
if 0x00008000&stateFlag != 0 {
|
|
states = append(states, state.State(16+offset))
|
|
}
|
|
if 0x00010000&stateFlag != 0 {
|
|
states = append(states, state.State(17+offset))
|
|
}
|
|
if 0x00020000&stateFlag != 0 {
|
|
states = append(states, state.State(18+offset))
|
|
}
|
|
if 0x00040000&stateFlag != 0 {
|
|
states = append(states, state.State(19+offset))
|
|
}
|
|
if 0x00080000&stateFlag != 0 {
|
|
states = append(states, state.State(20+offset))
|
|
}
|
|
if 0x00100000&stateFlag != 0 {
|
|
states = append(states, state.State(21+offset))
|
|
}
|
|
if 0x00200000&stateFlag != 0 {
|
|
states = append(states, state.State(22+offset))
|
|
}
|
|
if 0x00400000&stateFlag != 0 {
|
|
states = append(states, state.State(23+offset))
|
|
}
|
|
if 0x00800000&stateFlag != 0 {
|
|
states = append(states, state.State(24+offset))
|
|
}
|
|
if 0x01000000&stateFlag != 0 {
|
|
states = append(states, state.State(25+offset))
|
|
}
|
|
if 0x02000000&stateFlag != 0 {
|
|
states = append(states, state.State(26+offset))
|
|
}
|
|
if 0x04000000&stateFlag != 0 {
|
|
states = append(states, state.State(27+offset))
|
|
}
|
|
if 0x08000000&stateFlag != 0 {
|
|
states = append(states, state.State(28+offset))
|
|
}
|
|
if 0x10000000&stateFlag != 0 {
|
|
states = append(states, state.State(29+offset))
|
|
}
|
|
if 0x20000000&stateFlag != 0 {
|
|
states = append(states, state.State(30+offset))
|
|
}
|
|
if 0x40000000&stateFlag != 0 {
|
|
states = append(states, state.State(31+offset))
|
|
}
|
|
if 0x80000000&stateFlag != 0 {
|
|
states = append(states, state.State(32+offset))
|
|
}
|
|
|
|
return states
|
|
}
|