added items
This commit is contained in:
parent
c3de5fdb63
commit
5f90bc137b
158 changed files with 2316 additions and 512 deletions
141
src/Automata.Memory/TerrainReader.cs
Normal file
141
src/Automata.Memory/TerrainReader.cs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
using Serilog;
|
||||
|
||||
namespace Automata.Memory;
|
||||
|
||||
public sealed class WalkabilityGrid
|
||||
{
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public byte[] Data { get; }
|
||||
|
||||
public WalkabilityGrid(int width, int height, byte[] data)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public bool IsWalkable(int x, int y)
|
||||
{
|
||||
if (x < 0 || x >= Width || y < 0 || y >= Height)
|
||||
return false;
|
||||
return Data[y * Width + x] == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TerrainReader : IDisposable
|
||||
{
|
||||
private readonly TerrainOffsets _offsets;
|
||||
private ProcessMemory? _memory;
|
||||
private PatternScanner? _scanner;
|
||||
private nint _gameStateBase;
|
||||
private bool _disposed;
|
||||
|
||||
public bool IsReady => _gameStateBase != 0;
|
||||
|
||||
public TerrainReader(TerrainOffsets offsets)
|
||||
{
|
||||
_offsets = offsets;
|
||||
}
|
||||
|
||||
public bool Initialize()
|
||||
{
|
||||
_memory?.Dispose();
|
||||
_memory = ProcessMemory.Attach(_offsets.ProcessName);
|
||||
if (_memory is null)
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_offsets.GameStatePattern))
|
||||
{
|
||||
Log.Warning("GameStatePattern is empty — offsets not yet configured for POE2");
|
||||
return false;
|
||||
}
|
||||
|
||||
_scanner = new PatternScanner(_memory);
|
||||
_gameStateBase = _scanner.FindPatternRip(_offsets.GameStatePattern);
|
||||
|
||||
if (_gameStateBase == 0)
|
||||
{
|
||||
Log.Error("Failed to resolve GameState base pointer");
|
||||
return false;
|
||||
}
|
||||
|
||||
Log.Information("GameState base: 0x{Address:X}", _gameStateBase);
|
||||
return true;
|
||||
}
|
||||
|
||||
public WalkabilityGrid? ReadTerrain()
|
||||
{
|
||||
if (_memory is null || _gameStateBase == 0)
|
||||
return null;
|
||||
|
||||
// Follow pointer chain: GameState → InGameState → IngameData → TerrainData
|
||||
var terrainBase = _memory.FollowChain(_gameStateBase, [
|
||||
_offsets.InGameStateOffset,
|
||||
_offsets.IngameDataOffset,
|
||||
_offsets.TerrainDataOffset
|
||||
]);
|
||||
|
||||
if (terrainBase == 0)
|
||||
{
|
||||
Log.Debug("Terrain pointer chain returned null");
|
||||
return null;
|
||||
}
|
||||
|
||||
var numCols = _memory.Read<int>(terrainBase + _offsets.NumColsOffset);
|
||||
var numRows = _memory.Read<int>(terrainBase + _offsets.NumRowsOffset);
|
||||
var bytesPerRow = _memory.Read<int>(terrainBase + _offsets.BytesPerRowOffset);
|
||||
|
||||
if (numCols <= 0 || numRows <= 0 || bytesPerRow <= 0)
|
||||
{
|
||||
Log.Warning("Invalid terrain dimensions: {Cols}x{Rows}, bytesPerRow={Bpr}", numCols, numRows, bytesPerRow);
|
||||
return null;
|
||||
}
|
||||
|
||||
var gridWidth = numCols * _offsets.SubTilesPerCell;
|
||||
var gridHeight = numRows * _offsets.SubTilesPerCell;
|
||||
|
||||
// Read melee layer pointer
|
||||
var layerPtr = _memory.ReadPointer(terrainBase + _offsets.LayerMeleeOffset);
|
||||
if (layerPtr == 0)
|
||||
{
|
||||
Log.Warning("Melee layer pointer is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Read raw terrain data
|
||||
var rawSize = bytesPerRow * gridHeight;
|
||||
var rawData = _memory.ReadBytes(layerPtr, rawSize);
|
||||
if (rawData is null)
|
||||
{
|
||||
Log.Warning("Failed to read terrain data ({Size} bytes)", rawSize);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Unpack 4-bit nibbles: each byte → 2 cells (low nibble = even col, high nibble = odd col)
|
||||
var data = new byte[gridWidth * gridHeight];
|
||||
for (var row = 0; row < gridHeight; row++)
|
||||
{
|
||||
var rowStart = row * bytesPerRow;
|
||||
for (var col = 0; col < gridWidth; col++)
|
||||
{
|
||||
var byteIndex = rowStart + col / 2;
|
||||
if (byteIndex >= rawData.Length) break;
|
||||
|
||||
data[row * gridWidth + col] = (col % 2 == 0)
|
||||
? (byte)(rawData[byteIndex] & 0x0F)
|
||||
: (byte)((rawData[byteIndex] >> 4) & 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
Log.Information("Terrain read: {Width}x{Height} ({Cols}x{Rows} cells)", gridWidth, gridHeight, numCols, numRows);
|
||||
return new WalkabilityGrid(gridWidth, gridHeight, data);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
_memory?.Dispose();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue