Skip to content

Commit

Permalink
Add Pointer Inspector dialog (#1136)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamiras authored Jan 4, 2025
1 parent 30c5989 commit c120339
Show file tree
Hide file tree
Showing 37 changed files with 2,024 additions and 213 deletions.
4 changes: 4 additions & 0 deletions src/Exports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,8 +514,12 @@ static void UpdateUIForFrameChange()
TALLY_PERFORMANCE(PerformanceCheckpoint::AssetEditorDoFrame);
pWindowManager.AssetEditor.DoFrame();

TALLY_PERFORMANCE(PerformanceCheckpoint::PointerFinderDoFrame);
pWindowManager.PointerFinder.DoFrame();

TALLY_PERFORMANCE(PerformanceCheckpoint::PointerInspectorDoFrame);
pWindowManager.PointerInspector.DoFrame();

auto& pFrameEventQueue = ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>();
pFrameEventQueue.DoFrame();
}
Expand Down
6 changes: 6 additions & 0 deletions src/RA_Integration.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
<ClCompile Include="ui\viewmodels\OverlaySettingsViewModel.cpp" />
<ClCompile Include="ui\viewmodels\OverlayViewModel.cpp" />
<ClCompile Include="ui\viewmodels\PointerFinderViewModel.cpp" />
<ClCompile Include="ui\viewmodels\PointerInspectorViewModel.cpp" />
<ClCompile Include="ui\viewmodels\PopupMessageViewModel.cpp" />
<ClCompile Include="ui\viewmodels\PopupViewModelBase.cpp" />
<ClCompile Include="ui\viewmodels\ProgressTrackerViewModel.cpp" />
Expand Down Expand Up @@ -169,6 +170,7 @@
<ClCompile Include="ui\win32\OverlaySettingsDialog.cpp" />
<ClCompile Include="ui\win32\OverlayWindow.cpp" />
<ClCompile Include="ui\win32\PointerFinderDialog.cpp" />
<ClCompile Include="ui\win32\PointerInspectorDialog.cpp" />
<ClCompile Include="ui\win32\ProgressDialog.cpp" />
<ClCompile Include="ui\win32\RichPresenceDialog.cpp" />
<ClCompile Include="ui\win32\UnknownGameDialog.cpp" />
Expand Down Expand Up @@ -309,6 +311,7 @@
<ClInclude Include="ui\viewmodels\OverlaySettingsViewModel.hh" />
<ClInclude Include="ui\viewmodels\OverlayViewModel.hh" />
<ClInclude Include="ui\viewmodels\PointerFinderViewModel.hh" />
<ClInclude Include="ui\viewmodels\PointerInspectorViewModel.hh" />
<ClInclude Include="ui\viewmodels\PopupMessageViewModel.hh" />
<ClInclude Include="ui\viewmodels\PopupViewModelBase.hh" />
<ClInclude Include="ui\viewmodels\ProgressTrackerViewModel.hh" />
Expand All @@ -327,6 +330,8 @@
<ClInclude Include="ui\win32\bindings\ControlBinding.hh" />
<ClInclude Include="ui\win32\bindings\GridAddressColumnBinding.hh" />
<ClInclude Include="ui\win32\bindings\GridBinding.hh" />
<ClInclude Include="ui\win32\bindings\GridBookmarkFormatColumnBinding.hh" />
<ClInclude Include="ui\win32\bindings\GridBookmarkValueColumnBinding.hh" />
<ClInclude Include="ui\win32\bindings\GridBooleanColumnBinding.hh" />
<ClInclude Include="ui\win32\bindings\GridCheckBoxColumnBinding.hh" />
<ClInclude Include="ui\win32\bindings\GridColumnBinding.hh" />
Expand Down Expand Up @@ -356,6 +361,7 @@
<ClInclude Include="ui\win32\OverlaySettingsDialog.hh" />
<ClInclude Include="ui\win32\OverlayWindow.hh" />
<ClInclude Include="ui\win32\PointerFinderDialog.hh" />
<ClInclude Include="ui\win32\PointerInspectorDialog.hh" />
<ClInclude Include="ui\win32\ProgressDialog.hh" />
<ClInclude Include="ui\win32\RichPresenceDialog.hh" />
<ClInclude Include="ui\win32\IDialogPresenter.hh" />
Expand Down
18 changes: 18 additions & 0 deletions src/RA_Integration.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,12 @@
<ClCompile Include="data\models\CodeNoteModel.cpp">
<Filter>Data\Models</Filter>
</ClCompile>
<ClCompile Include="ui\viewmodels\PointerInspectorViewModel.cpp">
<Filter>UI\ViewModels</Filter>
</ClCompile>
<ClCompile Include="ui\win32\PointerInspectorDialog.cpp">
<Filter>UI\Win32</Filter>
</ClCompile>
<ClCompile Include="services\AchievementLogicSerializer.cpp">
<Filter>Services</Filter>
</ClCompile>
Expand Down Expand Up @@ -980,6 +986,18 @@
<ClInclude Include="data\models\CodeNoteModel.hh">
<Filter>Data\Models</Filter>
</ClInclude>
<ClInclude Include="ui\viewmodels\PointerInspectorViewModel.hh">
<Filter>UI\ViewModels</Filter>
</ClInclude>
<ClInclude Include="ui\win32\PointerInspectorDialog.hh">
<Filter>UI\Win32</Filter>
</ClInclude>
<ClInclude Include="ui\win32\bindings\GridBookmarkFormatColumnBinding.hh">
<Filter>UI\Win32\Bindings</Filter>
</ClInclude>
<ClInclude Include="ui\win32\bindings\GridBookmarkValueColumnBinding.hh">
<Filter>UI\Win32\Bindings</Filter>
</ClInclude>
<ClInclude Include="services\AchievementLogicSerializer.hh">
<Filter>Services</Filter>
</ClInclude>
Expand Down
2 changes: 2 additions & 0 deletions src/RA_Resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
#define IDD_RA_PROGRESS 1512
#define IDD_RA_NEWASSET 1513
#define IDD_RA_POINTERFINDER 1514
#define IDD_RA_POINTERINSPECTOR 1515
#define IDC_RA_PASSWORD 1535
#define IDC_RA_SAVEPASSWORD 1536
#define IDC_RA_USERNAME 1549
Expand Down Expand Up @@ -209,6 +210,7 @@
#define IDM_RA_NON_HARDCORE_WARNING 1718
#define IDM_RA_FILES_OPENALL 1719
#define IDM_RA_FILES_POINTERFINDER 1720
#define IDM_RA_FILES_POINTERINSPECTOR 1721
#define IDM_RA_MENUEND 1739

// Next default values for new objects
Expand Down
19 changes: 19 additions & 0 deletions src/RA_Shared.rc
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,25 @@ BEGIN
PUSHBUTTON "Move Down",IDC_RA_MOVE_BOOKMARK_DOWN,290,137,50,14
END

IDD_RA_POINTERINSPECTOR DIALOGEX 0, 0, 341, 232
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Pointer Inspector"
FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN
LTEXT "Root Address:",IDC_STATIC,6,5,63,11
EDITTEXT IDC_RA_ADDRESS,55,3,54,12,ES_AUTOHSCROLL,WS_EX_RIGHT
LTEXT "Viewing Node:",IDC_STATIC,120,5,83,11
COMBOBOX IDC_RA_FILTER_VALUE,170,3,168,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Description:",IDC_STATIC,6,20,63,11
EDITTEXT IDC_RA_DESCRIPTION,55,18,283,12,ES_AUTOHSCROLL
CONTROL "",IDC_RA_LBX_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_CLIPCHILDREN | WS_BORDER,4,32,334,60
CONTROL "",IDC_RA_LBX_ADDRESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_CLIPCHILDREN | WS_BORDER,4,95,334,118
PUSHBUTTON "Bookmark Selected",IDC_RA_ADDBOOKMARK,4,215,70,14,BS_MULTILINE
PUSHBUTTON "Copy Chain",IDC_RA_COPY_ALL,75,215,70,14
PUSHBUTTON "Pause",IDC_RA_PAUSE,236,215,50,14,BS_MULTILINE
PUSHBUTTON "Freeze",IDC_RA_FREEZE,288,215,50,14,BS_MULTILINE
END

IDD_RA_CODENOTES DIALOGEX 0, 0, 287, 230
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Code Notes"
Expand Down
22 changes: 11 additions & 11 deletions src/RA_StringUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ std::wstring& NormalizeLineEndings(_Inout_ std::wstring& str);
// ----- ToString -----

template<typename T>
_NODISCARD inline const std::string ToString(_In_ const T& value)
_NODISCARD inline const std::string ToAString(_In_ const T& value)
{
if constexpr (std::is_arithmetic_v<T>)
{
Expand Down Expand Up @@ -75,44 +75,44 @@ _NODISCARD inline const std::string ToString(_In_ const T& value)
}

template<>
_NODISCARD inline const std::string ToString(_In_ const std::string& value)
_NODISCARD inline const std::string ToAString(_In_ const std::string& value)
{
return value;
}

template<>
_NODISCARD inline const std::string ToString(_In_ const std::wstring& value)
_NODISCARD inline const std::string ToAString(_In_ const std::wstring& value)
{
return ra::Narrow(value);
}

template<>
_NODISCARD inline const std::string ToString(_In_ const wchar_t* const& value)
_NODISCARD inline const std::string ToAString(_In_ const wchar_t* const& value)
{
return ra::Narrow(value);
}

template<>
_NODISCARD inline const std::string ToString(_In_ const char* const& value)
_NODISCARD inline const std::string ToAString(_In_ const char* const& value)
{
return std::string(value);
}

template<>
_NODISCARD inline const std::string ToString(_In_ char* const& value)
_NODISCARD inline const std::string ToAString(_In_ char* const& value)
{
return std::string(value);
}

template<>
_NODISCARD inline const std::string ToString(_In_ const char& value)
_NODISCARD inline const std::string ToAString(_In_ const char& value)
{
return std::string(1, value);
}

// literal strings can't be passed by reference, so won't call the templated methods
_NODISCARD inline const std::string ToString(_In_ const char* value) { return std::string(value); }
_NODISCARD inline const std::string ToString(_In_ const wchar_t* value) { return ra::Narrow(value); }
_NODISCARD inline const std::string ToAString(_In_ const char* value) { return std::string(value); }
_NODISCARD inline const std::string ToAString(_In_ const wchar_t* value) { return ra::Narrow(value); }

// ----- ToWString -----

Expand Down Expand Up @@ -201,7 +201,7 @@ class StringBuilder
if (m_bPrepareWide)
m_vPending.emplace_back(std::wstring{ra::ToWString(arg)});
else
m_vPending.emplace_back(std::string{ra::ToString(arg)});
m_vPending.emplace_back(std::string{ra::ToAString(arg)});
}

template<>
Expand Down Expand Up @@ -442,7 +442,7 @@ class StringBuilder
const char c = sFormat.back();
sFormat.pop_back(); // remove 's'/'x'
sFormat.pop_back(); // remove '*'
sFormat.append(ra::ToString(value));
sFormat.append(ra::ToAString(value));
sFormat.push_back(c); // replace 's'/'x'

if constexpr (sizeof...(args) > 0)
Expand Down
34 changes: 34 additions & 0 deletions src/data/ModelCollectionBase.hh
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,40 @@ public:
return -1;
}

/// <summary>
/// Finds the index of the first item where the specified property has the specified value.
/// </summary>
/// <param name="pProperty">The property to query.</param>
/// <param name="sValue">The value to find.</param>
/// <returns>Index of the first matching item, <c>-1</c> if not found.</returns>
gsl::index FindItemIndex(const StringModelProperty& pProperty, const std::wstring& sValue) const
{
for (gsl::index nIndex = 0; nIndex < gsl::narrow<gsl::index>(m_nSize); ++nIndex)
{
if (m_vItems.at(nIndex)->GetValue(pProperty) == sValue)
return nIndex;
}

return -1;
}

/// <summary>
/// Finds the index of the first item where the specified property has the specified value.
/// </summary>
/// <param name="pProperty">The property to query.</param>
/// <param name="bValue">The value to find.</param>
/// <returns>Index of the first matching item, <c>-1</c> if not found.</returns>
gsl::index FindItemIndex(const BoolModelProperty& pProperty, bool bValue) const
{
for (gsl::index nIndex = 0; nIndex < gsl::narrow<gsl::index>(m_nSize); ++nIndex)
{
if (m_vItems.at(nIndex)->GetValue(pProperty) == bValue)
return nIndex;
}

return -1;
}

/// <summary>
/// Calls the OnBeginModelCollectionUpdate method of any attached NotifyTargets.
/// </summary>
Expand Down
95 changes: 74 additions & 21 deletions src/data/models/CodeNoteModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ uint32_t CodeNoteModel::GetRawPointerValue() const noexcept
return m_pPointerData != nullptr ? m_pPointerData->RawPointerValue : 0xFFFFFFFF;
}

bool CodeNoteModel::HasNestedPointers() const noexcept
{
return m_pPointerData != nullptr && m_pPointerData->HasPointers;
}

static ra::ByteAddress ConvertPointer(ra::ByteAddress nAddress)
{
const auto& pConsoleContext = ra::services::ServiceLocator::Get<ra::data::context::ConsoleContext>();
Expand Down Expand Up @@ -300,7 +305,19 @@ bool CodeNoteModel::GetNextAddress(ra::ByteAddress nAfterAddress, ra::ByteAddres
return bResult;
}

void CodeNoteModel::SetNote(const std::wstring& sNote)
std::wstring CodeNoteModel::GetPrimaryNote() const
{
if (m_pPointerData != nullptr)
{
const auto nIndex = m_sNote.find(L"\n+");
if (nIndex != std::wstring::npos)
return m_sNote.substr(0, nIndex);
}

return m_sNote;
}

void CodeNoteModel::SetNote(const std::wstring& sNote, bool bImpliedPointer)
{
if (m_sNote == sNote)
return;
Expand All @@ -314,28 +331,53 @@ void CodeNoteModel::SetNote(const std::wstring& sNote)
const auto nNextIndex = sNote.find(L'\n', nIndex);
sLine = (nNextIndex == std::string::npos) ?
sNote.substr(nIndex) : sNote.substr(nIndex, nNextIndex - nIndex);
StringMakeLowercase(sLine);
ExtractSize(sLine);

if (sLine.find(L"pointer") != std::string::npos)
if (!sLine.empty())
{
if (m_nMemSize == MemSize::Unknown)
if (sLine.at(0) == '+' && bImpliedPointer)
{
// pointer size not specified. assume 32-bit
m_nMemSize = MemSize::ThirtyTwoBit;
m_nBytes = 4;

// found a line starting with a plus sign, bit no pointer annotation. bImpliedPointer
// must be true. assume the parent note is not described. pass -1 as the note size
// because we already skipped over the newline character
ProcessIndirectNotes(sNote, gsl::narrow_cast<size_t>(-1));
m_pPointerData->HeaderLength = 0;
break;
}

// if there are any lines starting with a plus sign, extract the indirect code notes
nIndex = sNote.find(L"\n+", nIndex + 1);
if (nIndex != std::string::npos)
ProcessIndirectNotes(sNote, nIndex);
StringMakeLowercase(sLine);
ExtractSize(sLine);

break;
}
if (sLine.find(L"pointer") != std::string::npos)
{
if (m_nMemSize == MemSize::Unknown)
{
// pointer size not specified. assume 32-bit
m_nMemSize = MemSize::ThirtyTwoBit;
m_nBytes = 4;
}

if (m_nMemSize != MemSize::Unknown) // found a size. stop processing.
break;
// if there are any lines starting with a plus sign, extract the indirect code notes
nIndex = sNote.find(L"\n+", nIndex + 1);
if (nIndex != std::string::npos)
ProcessIndirectNotes(sNote, nIndex);

// failed to find nested code notes. create a PointerData object so the note still
// gets treated as a pointer
if (!m_pPointerData)
{
m_pPointerData.reset(new PointerData());
m_pPointerData->HeaderLength = gsl::narrow_cast<unsigned>(sNote.length());
}

break;
}

if (m_nMemSize != MemSize::Unknown) // found a size. stop processing.
break;
}

if (nNextIndex == std::string::npos) // end of string
break;
Expand Down Expand Up @@ -664,16 +706,27 @@ void CodeNoteModel::ProcessIndirectNotes(const std::wstring& sNote, size_t nInde

// skip over [whitespace] [optional separator] [whitespace]
const wchar_t* pStop = sNextNote.c_str() + sNextNote.length();
while (pEnd < pStop && isspace(*pEnd))
pEnd++;
if (pEnd < pStop && !isalnum(*pEnd))
while (pEnd < pStop && isspace(*pEnd) && *pEnd != '\n')
++pEnd;

if (pEnd < pStop)
{
pEnd++;
while (pEnd < pStop && isspace(*pEnd))
pEnd++;
if (*pEnd == '\n')
{
// no separator. found an unannotated note
++pEnd;
}
else if (!isalnum(*pEnd))
{
// found a separator. skip it and any following whitespace
++pEnd;

while (pEnd < pStop && isspace(*pEnd))
++pEnd;
}
}

offsetNote.SetNote(sNextNote.substr(pEnd - sNextNote.c_str()));
offsetNote.SetNote(sNextNote.substr(pEnd - sNextNote.c_str()), true);
pointerData->HasPointers |= offsetNote.IsPointer();

offsetNote.SetAddress(gsl::narrow_cast<ra::ByteAddress>(nOffset));
Expand Down
Loading

0 comments on commit c120339

Please sign in to comment.