areatemplate added
This commit is contained in:
parent
0c14d78d8a
commit
94b460bbc8
8 changed files with 125 additions and 20 deletions
|
|
@ -103,6 +103,13 @@ public partial class MemoryViewModel : ObservableObject
|
|||
private MemoryNodeViewModel? _entityListNode;
|
||||
private MemoryNodeViewModel? _skillsNode;
|
||||
private MemoryNodeViewModel? _questsNode;
|
||||
private MemoryNodeViewModel? _areaRawName;
|
||||
private MemoryNodeViewModel? _areaDisplayName;
|
||||
private MemoryNodeViewModel? _areaAct;
|
||||
private MemoryNodeViewModel? _areaIsTown;
|
||||
private MemoryNodeViewModel? _areaHasWaypoint;
|
||||
private MemoryNodeViewModel? _areaMonsterLevel;
|
||||
private MemoryNodeViewModel? _worldAreaId;
|
||||
|
||||
partial void OnIsEnabledChanged(bool value)
|
||||
{
|
||||
|
|
@ -235,7 +242,25 @@ public partial class MemoryViewModel : ObservableObject
|
|||
terrain.Children.Add(_terrainGrid);
|
||||
terrain.Children.Add(_terrainWalkable);
|
||||
|
||||
// AreaTemplate (from WorldData — zone metadata)
|
||||
var areaTemplateGroup = new MemoryNodeViewModel("AreaTemplate");
|
||||
_areaRawName = new MemoryNodeViewModel("RawName:");
|
||||
_areaDisplayName = new MemoryNodeViewModel("Name:");
|
||||
_areaAct = new MemoryNodeViewModel("Act:");
|
||||
_areaIsTown = new MemoryNodeViewModel("IsTown:");
|
||||
_areaHasWaypoint = new MemoryNodeViewModel("HasWaypoint:");
|
||||
_areaMonsterLevel = new MemoryNodeViewModel("MonsterLevel:");
|
||||
_worldAreaId = new MemoryNodeViewModel("WorldAreaId:");
|
||||
areaTemplateGroup.Children.Add(_areaRawName);
|
||||
areaTemplateGroup.Children.Add(_areaDisplayName);
|
||||
areaTemplateGroup.Children.Add(_areaAct);
|
||||
areaTemplateGroup.Children.Add(_areaIsTown);
|
||||
areaTemplateGroup.Children.Add(_areaHasWaypoint);
|
||||
areaTemplateGroup.Children.Add(_areaMonsterLevel);
|
||||
areaTemplateGroup.Children.Add(_worldAreaId);
|
||||
|
||||
inGameStateGroup.Children.Add(areaInstanceGroup);
|
||||
inGameStateGroup.Children.Add(areaTemplateGroup);
|
||||
inGameStateGroup.Children.Add(player);
|
||||
inGameStateGroup.Children.Add(entitiesGroup);
|
||||
inGameStateGroup.Children.Add(terrain);
|
||||
|
|
@ -437,6 +462,15 @@ public partial class MemoryViewModel : ObservableObject
|
|||
snap.EntityCount > 0 ? snap.EntityCount.ToString() : "—",
|
||||
snap.EntityCount > 0);
|
||||
|
||||
// AreaTemplate
|
||||
_areaRawName!.Set(snap.AreaRawName ?? "—", snap.AreaRawName is not null);
|
||||
_areaDisplayName!.Set(snap.AreaName ?? "—", snap.AreaName is not null);
|
||||
_areaAct!.Set(snap.AreaAct > 0 ? snap.AreaAct.ToString() : "—", snap.AreaAct > 0);
|
||||
_areaIsTown!.Set(snap.AreaIsTown ? "Yes" : "No", snap.AreaIsTown);
|
||||
_areaHasWaypoint!.Set(snap.AreaHasWaypoint ? "Yes" : "No", snap.AreaHasWaypoint);
|
||||
_areaMonsterLevel!.Set(snap.AreaMonsterLevel > 0 ? snap.AreaMonsterLevel.ToString() : "—", snap.AreaMonsterLevel > 0);
|
||||
_worldAreaId!.Set(snap.WorldAreaId > 0 ? snap.WorldAreaId.ToString() : "—", snap.WorldAreaId > 0);
|
||||
|
||||
// Player position
|
||||
if (snap.HasPosition)
|
||||
_playerPos!.Set($"({snap.PlayerX:F1}, {snap.PlayerY:F1}, {snap.PlayerZ:F1})");
|
||||
|
|
@ -1355,4 +1389,16 @@ public partial class MemoryViewModel : ObservableObject
|
|||
|
||||
ScanResult = _reader.Diagnostics!.ScanQuestStateObjects();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ScanAreaTemplateExecute()
|
||||
{
|
||||
if (_reader is null || !_reader.IsAttached)
|
||||
{
|
||||
ScanResult = "Error: not attached";
|
||||
return;
|
||||
}
|
||||
|
||||
ScanResult = _reader.Diagnostics!.ScanAreaTemplate();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -784,6 +784,8 @@
|
|||
Padding="10,4" FontWeight="Bold" Margin="0,0,6,4" />
|
||||
<Button Content="Quest Objects" Command="{Binding ScanQuestObjectsExecuteCommand}"
|
||||
Padding="10,4" FontWeight="Bold" Margin="0,0,6,4" />
|
||||
<Button Content="Area Template" Command="{Binding ScanAreaTemplateExecuteCommand}"
|
||||
Padding="10,4" FontWeight="Bold" Margin="0,0,6,4" />
|
||||
</WrapPanel>
|
||||
<TextBox Text="{Binding ScanResult, Mode=OneWay}" FontFamily="Consolas"
|
||||
FontSize="10" Foreground="#e6edf3" Background="#0d1117"
|
||||
|
|
|
|||
|
|
@ -5520,4 +5520,64 @@ public sealed class MemoryDiagnostics
|
|||
BfsSearchUiElements(mem, offsets, childPtr, childPath, currentDepth + 1, maxDepth, visited, results, predicate, selfOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic: dump AreaInstance → AreaTemplate pointer chain.
|
||||
/// </summary>
|
||||
public string ScanAreaTemplate()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var mem = _ctx.Memory;
|
||||
var offsets = _ctx.Offsets;
|
||||
|
||||
// Resolve InGameState
|
||||
var controller = mem.ReadPointer(_ctx.GameStateBase);
|
||||
if (controller == 0) { sb.AppendLine("ERROR: controller is null"); return sb.ToString(); }
|
||||
|
||||
nint inGameState;
|
||||
if (offsets.InGameStateDirectOffset > 0)
|
||||
inGameState = mem.ReadPointer(controller + offsets.InGameStateDirectOffset);
|
||||
else
|
||||
inGameState = 0;
|
||||
if (inGameState == 0) { sb.AppendLine("ERROR: InGameState is null"); return sb.ToString(); }
|
||||
|
||||
sb.AppendLine($"InGameState: 0x{inGameState:X}");
|
||||
|
||||
// AreaInstance ptr
|
||||
var aiPtr = mem.ReadPointer(inGameState + offsets.IngameDataFromStateOffset);
|
||||
sb.AppendLine($"AreaInstance (+0x{offsets.IngameDataFromStateOffset:X}): 0x{aiPtr:X}");
|
||||
if (aiPtr == 0) { sb.AppendLine("ERROR: AreaInstance is null"); return sb.ToString(); }
|
||||
|
||||
// AreaTemplate ptr
|
||||
var atPtr = mem.ReadPointer(aiPtr + offsets.AreaTemplateOffset);
|
||||
sb.AppendLine($"AreaTemplate (+0x{offsets.AreaTemplateOffset:X}): 0x{atPtr:X}");
|
||||
if (atPtr == 0) { sb.AppendLine("ERROR: AreaTemplate pointer is null"); return sb.ToString(); }
|
||||
|
||||
sb.AppendLine();
|
||||
DumpAreaTemplateAt(sb, mem, atPtr, offsets);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private void DumpAreaTemplateAt(StringBuilder sb, ProcessMemory mem, nint addr, GameOffsets offsets)
|
||||
{
|
||||
var rawNamePtr = mem.ReadPointer(addr + offsets.AreaTemplateRawNameOffset);
|
||||
var namePtr = mem.ReadPointer(addr + offsets.AreaTemplateNameOffset);
|
||||
var act = mem.Read<int>(addr + offsets.AreaTemplateActOffset);
|
||||
var isTown = mem.Read<byte>(addr + offsets.AreaTemplateIsTownOffset);
|
||||
var hasWaypoint = mem.Read<byte>(addr + offsets.AreaTemplateHasWaypointOffset);
|
||||
var monsterLevel = mem.Read<int>(addr + offsets.AreaTemplateMonsterLevelOffset);
|
||||
var worldAreaId = mem.Read<int>(addr + offsets.AreaTemplateWorldAreaIdOffset);
|
||||
|
||||
var rawName = _strings.ReadNullTermWString(rawNamePtr);
|
||||
var name = _strings.ReadNullTermWString(namePtr);
|
||||
|
||||
sb.AppendLine($" RawNamePtr (+0x{offsets.AreaTemplateRawNameOffset:X2}): 0x{rawNamePtr:X} → \"{rawName}\"");
|
||||
sb.AppendLine($" NamePtr (+0x{offsets.AreaTemplateNameOffset:X2}): 0x{namePtr:X} → \"{name}\"");
|
||||
sb.AppendLine($" Act (+0x{offsets.AreaTemplateActOffset:X2}): {act}");
|
||||
sb.AppendLine($" IsTown (+0x{offsets.AreaTemplateIsTownOffset:X2}): {isTown}");
|
||||
sb.AppendLine($" HasWaypoint(+0x{offsets.AreaTemplateHasWaypointOffset:X2}): {hasWaypoint}");
|
||||
sb.AppendLine($" MonsterLvl (+0x{offsets.AreaTemplateMonsterLevelOffset:X2}): {monsterLevel}");
|
||||
sb.AppendLine($" WorldAreaId(+0x{offsets.AreaTemplateWorldAreaIdOffset:X2}): {worldAreaId}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,8 +192,8 @@ public class GameMemoryReader : IDisposable
|
|||
snap.AreaLevel = areaLevel;
|
||||
snap.AreaHash = ai.AreaHash;
|
||||
|
||||
// Area template from WorldData
|
||||
var at = gs.InGame.WorldData.AreaTemplate;
|
||||
// Area template from AreaInstance
|
||||
var at = ai.AreaTemplate;
|
||||
if (at.IsValid)
|
||||
{
|
||||
snap.AreaRawName = at.RawName;
|
||||
|
|
|
|||
|
|
@ -235,9 +235,9 @@ public sealed class GameOffsets
|
|||
/// <summary>Offset within Camera struct to the Matrix4x4 (64 bytes). 0 = disabled.</summary>
|
||||
public int CameraMatrixOffset { get; set; } = 0x1A0;
|
||||
|
||||
// ── AreaTemplate (WorldData → WorldAreaDetailsPtr → AreaTemplate) ──
|
||||
/// <summary>WorldData struct → WorldAreaDetailsPtr offset. Already in struct at 0x98.</summary>
|
||||
public int WorldAreaDetailsOffset { get; set; } = 0x98;
|
||||
// ── AreaTemplate (AreaInstance +0xA0 → AreaTemplate) ──
|
||||
/// <summary>AreaInstance → AreaTemplate pointer. Confirmed: 0xA0.</summary>
|
||||
public int AreaTemplateOffset { get; set; } = 0xA0;
|
||||
/// <summary>AreaTemplate → RawName wchar_t* pointer.</summary>
|
||||
public int AreaTemplateRawNameOffset { get; set; } = 0x00;
|
||||
/// <summary>AreaTemplate → Name wchar_t* pointer (display name).</summary>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ public sealed class AreaInstance : RemoteObject
|
|||
public PlayerSkills PlayerSkills { get; }
|
||||
public QuestFlags QuestFlags { get; }
|
||||
public Terrain Terrain { get; }
|
||||
public AreaTemplate AreaTemplate { get; }
|
||||
|
||||
public AreaInstance(MemoryContext ctx, ComponentReader components, MsvcStringReader strings, QuestNameLookup? questNames)
|
||||
: base(ctx)
|
||||
|
|
@ -28,6 +29,7 @@ public sealed class AreaInstance : RemoteObject
|
|||
PlayerSkills = new PlayerSkills(ctx, components, strings);
|
||||
QuestFlags = new QuestFlags(ctx, strings, questNames);
|
||||
Terrain = new Terrain(ctx);
|
||||
AreaTemplate = new AreaTemplate(ctx, strings);
|
||||
}
|
||||
|
||||
protected override bool ReadData()
|
||||
|
|
@ -99,6 +101,13 @@ public sealed class AreaInstance : RemoteObject
|
|||
else
|
||||
QuestFlags.Reset();
|
||||
|
||||
// AreaTemplate — pointer at AreaInstance + AreaTemplateOffset
|
||||
var areaTemplatePtr = mem.ReadPointer(Address + offsets.AreaTemplateOffset);
|
||||
if (areaTemplatePtr != 0)
|
||||
AreaTemplate.Update(areaTemplatePtr);
|
||||
else
|
||||
AreaTemplate.Reset();
|
||||
|
||||
// Terrain — pass loading/area state before update
|
||||
Terrain.AreaHash = AreaHash;
|
||||
Terrain.Update(Address);
|
||||
|
|
@ -133,5 +142,6 @@ public sealed class AreaInstance : RemoteObject
|
|||
PlayerSkills.Reset();
|
||||
QuestFlags.Reset();
|
||||
Terrain.Reset();
|
||||
AreaTemplate.Reset();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public sealed class InGameState : RemoteObject
|
|||
: base(ctx)
|
||||
{
|
||||
AreaInstance = new AreaInstance(ctx, components, strings, questNames);
|
||||
WorldData = new WorldData(ctx, strings);
|
||||
WorldData = new WorldData(ctx);
|
||||
}
|
||||
|
||||
protected override bool ReadData()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ namespace Roboto.Memory.Objects;
|
|||
/// <summary>
|
||||
/// Reads WorldData struct (168B, 1 RPM) and resolves the camera matrix.
|
||||
/// Primary camera source: WorldData.CameraPtr. Fallback: InGameState.CameraPtr (set via FallbackCameraPtr).
|
||||
/// Owns AreaTemplate child for area metadata.
|
||||
/// </summary>
|
||||
public sealed class WorldData : RemoteObject
|
||||
{
|
||||
|
|
@ -21,12 +20,7 @@ public sealed class WorldData : RemoteObject
|
|||
/// <summary>Resolved address of the camera matrix for hot-path caching.</summary>
|
||||
public nint CameraMatrixAddress { get; private set; }
|
||||
|
||||
public AreaTemplate AreaTemplate { get; }
|
||||
|
||||
public WorldData(MemoryContext ctx, MsvcStringReader strings) : base(ctx)
|
||||
{
|
||||
AreaTemplate = new AreaTemplate(ctx, strings);
|
||||
}
|
||||
public WorldData(MemoryContext ctx) : base(ctx) { }
|
||||
|
||||
protected override bool ReadData()
|
||||
{
|
||||
|
|
@ -36,12 +30,6 @@ public sealed class WorldData : RemoteObject
|
|||
// Read the full WorldData struct (0xA8 = 168 bytes, 1 RPM)
|
||||
_data = mem.Read<WdStruct>(Address);
|
||||
|
||||
// Cascade to AreaTemplate
|
||||
if (_data.WorldAreaDetailsPtr != 0)
|
||||
AreaTemplate.Update(_data.WorldAreaDetailsPtr);
|
||||
else
|
||||
AreaTemplate.Reset();
|
||||
|
||||
// Resolve camera: primary from WorldData, fallback from InGameState
|
||||
if (offsets.CameraMatrixOffset <= 0)
|
||||
return true;
|
||||
|
|
@ -69,6 +57,5 @@ public sealed class WorldData : RemoteObject
|
|||
FallbackCameraPtr = 0;
|
||||
CameraMatrix = null;
|
||||
CameraMatrixAddress = 0;
|
||||
AreaTemplate.Reset();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue