Skip to content

Commit c120339

Browse files
authored
Add Pointer Inspector dialog (#1136)
1 parent 30c5989 commit c120339

37 files changed

+2024
-213
lines changed

src/Exports.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,12 @@ static void UpdateUIForFrameChange()
514514
TALLY_PERFORMANCE(PerformanceCheckpoint::AssetEditorDoFrame);
515515
pWindowManager.AssetEditor.DoFrame();
516516

517+
TALLY_PERFORMANCE(PerformanceCheckpoint::PointerFinderDoFrame);
517518
pWindowManager.PointerFinder.DoFrame();
518519

520+
TALLY_PERFORMANCE(PerformanceCheckpoint::PointerInspectorDoFrame);
521+
pWindowManager.PointerInspector.DoFrame();
522+
519523
auto& pFrameEventQueue = ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>();
520524
pFrameEventQueue.DoFrame();
521525
}

src/RA_Integration.vcxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
<ClCompile Include="ui\viewmodels\OverlaySettingsViewModel.cpp" />
135135
<ClCompile Include="ui\viewmodels\OverlayViewModel.cpp" />
136136
<ClCompile Include="ui\viewmodels\PointerFinderViewModel.cpp" />
137+
<ClCompile Include="ui\viewmodels\PointerInspectorViewModel.cpp" />
137138
<ClCompile Include="ui\viewmodels\PopupMessageViewModel.cpp" />
138139
<ClCompile Include="ui\viewmodels\PopupViewModelBase.cpp" />
139140
<ClCompile Include="ui\viewmodels\ProgressTrackerViewModel.cpp" />
@@ -169,6 +170,7 @@
169170
<ClCompile Include="ui\win32\OverlaySettingsDialog.cpp" />
170171
<ClCompile Include="ui\win32\OverlayWindow.cpp" />
171172
<ClCompile Include="ui\win32\PointerFinderDialog.cpp" />
173+
<ClCompile Include="ui\win32\PointerInspectorDialog.cpp" />
172174
<ClCompile Include="ui\win32\ProgressDialog.cpp" />
173175
<ClCompile Include="ui\win32\RichPresenceDialog.cpp" />
174176
<ClCompile Include="ui\win32\UnknownGameDialog.cpp" />
@@ -309,6 +311,7 @@
309311
<ClInclude Include="ui\viewmodels\OverlaySettingsViewModel.hh" />
310312
<ClInclude Include="ui\viewmodels\OverlayViewModel.hh" />
311313
<ClInclude Include="ui\viewmodels\PointerFinderViewModel.hh" />
314+
<ClInclude Include="ui\viewmodels\PointerInspectorViewModel.hh" />
312315
<ClInclude Include="ui\viewmodels\PopupMessageViewModel.hh" />
313316
<ClInclude Include="ui\viewmodels\PopupViewModelBase.hh" />
314317
<ClInclude Include="ui\viewmodels\ProgressTrackerViewModel.hh" />
@@ -327,6 +330,8 @@
327330
<ClInclude Include="ui\win32\bindings\ControlBinding.hh" />
328331
<ClInclude Include="ui\win32\bindings\GridAddressColumnBinding.hh" />
329332
<ClInclude Include="ui\win32\bindings\GridBinding.hh" />
333+
<ClInclude Include="ui\win32\bindings\GridBookmarkFormatColumnBinding.hh" />
334+
<ClInclude Include="ui\win32\bindings\GridBookmarkValueColumnBinding.hh" />
330335
<ClInclude Include="ui\win32\bindings\GridBooleanColumnBinding.hh" />
331336
<ClInclude Include="ui\win32\bindings\GridCheckBoxColumnBinding.hh" />
332337
<ClInclude Include="ui\win32\bindings\GridColumnBinding.hh" />
@@ -356,6 +361,7 @@
356361
<ClInclude Include="ui\win32\OverlaySettingsDialog.hh" />
357362
<ClInclude Include="ui\win32\OverlayWindow.hh" />
358363
<ClInclude Include="ui\win32\PointerFinderDialog.hh" />
364+
<ClInclude Include="ui\win32\PointerInspectorDialog.hh" />
359365
<ClInclude Include="ui\win32\ProgressDialog.hh" />
360366
<ClInclude Include="ui\win32\RichPresenceDialog.hh" />
361367
<ClInclude Include="ui\win32\IDialogPresenter.hh" />

src/RA_Integration.vcxproj.filters

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,12 @@
411411
<ClCompile Include="data\models\CodeNoteModel.cpp">
412412
<Filter>Data\Models</Filter>
413413
</ClCompile>
414+
<ClCompile Include="ui\viewmodels\PointerInspectorViewModel.cpp">
415+
<Filter>UI\ViewModels</Filter>
416+
</ClCompile>
417+
<ClCompile Include="ui\win32\PointerInspectorDialog.cpp">
418+
<Filter>UI\Win32</Filter>
419+
</ClCompile>
414420
<ClCompile Include="services\AchievementLogicSerializer.cpp">
415421
<Filter>Services</Filter>
416422
</ClCompile>
@@ -980,6 +986,18 @@
980986
<ClInclude Include="data\models\CodeNoteModel.hh">
981987
<Filter>Data\Models</Filter>
982988
</ClInclude>
989+
<ClInclude Include="ui\viewmodels\PointerInspectorViewModel.hh">
990+
<Filter>UI\ViewModels</Filter>
991+
</ClInclude>
992+
<ClInclude Include="ui\win32\PointerInspectorDialog.hh">
993+
<Filter>UI\Win32</Filter>
994+
</ClInclude>
995+
<ClInclude Include="ui\win32\bindings\GridBookmarkFormatColumnBinding.hh">
996+
<Filter>UI\Win32\Bindings</Filter>
997+
</ClInclude>
998+
<ClInclude Include="ui\win32\bindings\GridBookmarkValueColumnBinding.hh">
999+
<Filter>UI\Win32\Bindings</Filter>
1000+
</ClInclude>
9831001
<ClInclude Include="services\AchievementLogicSerializer.hh">
9841002
<Filter>Services</Filter>
9851003
</ClInclude>

src/RA_Resource.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
#define IDD_RA_PROGRESS 1512
165165
#define IDD_RA_NEWASSET 1513
166166
#define IDD_RA_POINTERFINDER 1514
167+
#define IDD_RA_POINTERINSPECTOR 1515
167168
#define IDC_RA_PASSWORD 1535
168169
#define IDC_RA_SAVEPASSWORD 1536
169170
#define IDC_RA_USERNAME 1549
@@ -209,6 +210,7 @@
209210
#define IDM_RA_NON_HARDCORE_WARNING 1718
210211
#define IDM_RA_FILES_OPENALL 1719
211212
#define IDM_RA_FILES_POINTERFINDER 1720
213+
#define IDM_RA_FILES_POINTERINSPECTOR 1721
212214
#define IDM_RA_MENUEND 1739
213215

214216
// Next default values for new objects

src/RA_Shared.rc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,25 @@ BEGIN
263263
PUSHBUTTON "Move Down",IDC_RA_MOVE_BOOKMARK_DOWN,290,137,50,14
264264
END
265265

266+
IDD_RA_POINTERINSPECTOR DIALOGEX 0, 0, 341, 232
267+
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
268+
CAPTION "Pointer Inspector"
269+
FONT 8, "MS Shell Dlg", 400, 0, 0x0
270+
BEGIN
271+
LTEXT "Root Address:",IDC_STATIC,6,5,63,11
272+
EDITTEXT IDC_RA_ADDRESS,55,3,54,12,ES_AUTOHSCROLL,WS_EX_RIGHT
273+
LTEXT "Viewing Node:",IDC_STATIC,120,5,83,11
274+
COMBOBOX IDC_RA_FILTER_VALUE,170,3,168,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
275+
LTEXT "Description:",IDC_STATIC,6,20,63,11
276+
EDITTEXT IDC_RA_DESCRIPTION,55,18,283,12,ES_AUTOHSCROLL
277+
CONTROL "",IDC_RA_LBX_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_CLIPCHILDREN | WS_BORDER,4,32,334,60
278+
CONTROL "",IDC_RA_LBX_ADDRESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_CLIPCHILDREN | WS_BORDER,4,95,334,118
279+
PUSHBUTTON "Bookmark Selected",IDC_RA_ADDBOOKMARK,4,215,70,14,BS_MULTILINE
280+
PUSHBUTTON "Copy Chain",IDC_RA_COPY_ALL,75,215,70,14
281+
PUSHBUTTON "Pause",IDC_RA_PAUSE,236,215,50,14,BS_MULTILINE
282+
PUSHBUTTON "Freeze",IDC_RA_FREEZE,288,215,50,14,BS_MULTILINE
283+
END
284+
266285
IDD_RA_CODENOTES DIALOGEX 0, 0, 287, 230
267286
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
268287
CAPTION "Code Notes"

src/RA_StringUtils.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ std::wstring& NormalizeLineEndings(_Inout_ std::wstring& str);
4646
// ----- ToString -----
4747

4848
template<typename T>
49-
_NODISCARD inline const std::string ToString(_In_ const T& value)
49+
_NODISCARD inline const std::string ToAString(_In_ const T& value)
5050
{
5151
if constexpr (std::is_arithmetic_v<T>)
5252
{
@@ -75,44 +75,44 @@ _NODISCARD inline const std::string ToString(_In_ const T& value)
7575
}
7676

7777
template<>
78-
_NODISCARD inline const std::string ToString(_In_ const std::string& value)
78+
_NODISCARD inline const std::string ToAString(_In_ const std::string& value)
7979
{
8080
return value;
8181
}
8282

8383
template<>
84-
_NODISCARD inline const std::string ToString(_In_ const std::wstring& value)
84+
_NODISCARD inline const std::string ToAString(_In_ const std::wstring& value)
8585
{
8686
return ra::Narrow(value);
8787
}
8888

8989
template<>
90-
_NODISCARD inline const std::string ToString(_In_ const wchar_t* const& value)
90+
_NODISCARD inline const std::string ToAString(_In_ const wchar_t* const& value)
9191
{
9292
return ra::Narrow(value);
9393
}
9494

9595
template<>
96-
_NODISCARD inline const std::string ToString(_In_ const char* const& value)
96+
_NODISCARD inline const std::string ToAString(_In_ const char* const& value)
9797
{
9898
return std::string(value);
9999
}
100100

101101
template<>
102-
_NODISCARD inline const std::string ToString(_In_ char* const& value)
102+
_NODISCARD inline const std::string ToAString(_In_ char* const& value)
103103
{
104104
return std::string(value);
105105
}
106106

107107
template<>
108-
_NODISCARD inline const std::string ToString(_In_ const char& value)
108+
_NODISCARD inline const std::string ToAString(_In_ const char& value)
109109
{
110110
return std::string(1, value);
111111
}
112112

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

117117
// ----- ToWString -----
118118

@@ -201,7 +201,7 @@ class StringBuilder
201201
if (m_bPrepareWide)
202202
m_vPending.emplace_back(std::wstring{ra::ToWString(arg)});
203203
else
204-
m_vPending.emplace_back(std::string{ra::ToString(arg)});
204+
m_vPending.emplace_back(std::string{ra::ToAString(arg)});
205205
}
206206

207207
template<>
@@ -442,7 +442,7 @@ class StringBuilder
442442
const char c = sFormat.back();
443443
sFormat.pop_back(); // remove 's'/'x'
444444
sFormat.pop_back(); // remove '*'
445-
sFormat.append(ra::ToString(value));
445+
sFormat.append(ra::ToAString(value));
446446
sFormat.push_back(c); // replace 's'/'x'
447447

448448
if constexpr (sizeof...(args) > 0)

src/data/ModelCollectionBase.hh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,40 @@ public:
180180
return -1;
181181
}
182182

183+
/// <summary>
184+
/// Finds the index of the first item where the specified property has the specified value.
185+
/// </summary>
186+
/// <param name="pProperty">The property to query.</param>
187+
/// <param name="sValue">The value to find.</param>
188+
/// <returns>Index of the first matching item, <c>-1</c> if not found.</returns>
189+
gsl::index FindItemIndex(const StringModelProperty& pProperty, const std::wstring& sValue) const
190+
{
191+
for (gsl::index nIndex = 0; nIndex < gsl::narrow<gsl::index>(m_nSize); ++nIndex)
192+
{
193+
if (m_vItems.at(nIndex)->GetValue(pProperty) == sValue)
194+
return nIndex;
195+
}
196+
197+
return -1;
198+
}
199+
200+
/// <summary>
201+
/// Finds the index of the first item where the specified property has the specified value.
202+
/// </summary>
203+
/// <param name="pProperty">The property to query.</param>
204+
/// <param name="bValue">The value to find.</param>
205+
/// <returns>Index of the first matching item, <c>-1</c> if not found.</returns>
206+
gsl::index FindItemIndex(const BoolModelProperty& pProperty, bool bValue) const
207+
{
208+
for (gsl::index nIndex = 0; nIndex < gsl::narrow<gsl::index>(m_nSize); ++nIndex)
209+
{
210+
if (m_vItems.at(nIndex)->GetValue(pProperty) == bValue)
211+
return nIndex;
212+
}
213+
214+
return -1;
215+
}
216+
183217
/// <summary>
184218
/// Calls the OnBeginModelCollectionUpdate method of any attached NotifyTargets.
185219
/// </summary>

src/data/models/CodeNoteModel.cpp

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ uint32_t CodeNoteModel::GetRawPointerValue() const noexcept
7070
return m_pPointerData != nullptr ? m_pPointerData->RawPointerValue : 0xFFFFFFFF;
7171
}
7272

73+
bool CodeNoteModel::HasNestedPointers() const noexcept
74+
{
75+
return m_pPointerData != nullptr && m_pPointerData->HasPointers;
76+
}
77+
7378
static ra::ByteAddress ConvertPointer(ra::ByteAddress nAddress)
7479
{
7580
const auto& pConsoleContext = ra::services::ServiceLocator::Get<ra::data::context::ConsoleContext>();
@@ -300,7 +305,19 @@ bool CodeNoteModel::GetNextAddress(ra::ByteAddress nAfterAddress, ra::ByteAddres
300305
return bResult;
301306
}
302307

303-
void CodeNoteModel::SetNote(const std::wstring& sNote)
308+
std::wstring CodeNoteModel::GetPrimaryNote() const
309+
{
310+
if (m_pPointerData != nullptr)
311+
{
312+
const auto nIndex = m_sNote.find(L"\n+");
313+
if (nIndex != std::wstring::npos)
314+
return m_sNote.substr(0, nIndex);
315+
}
316+
317+
return m_sNote;
318+
}
319+
320+
void CodeNoteModel::SetNote(const std::wstring& sNote, bool bImpliedPointer)
304321
{
305322
if (m_sNote == sNote)
306323
return;
@@ -314,28 +331,53 @@ void CodeNoteModel::SetNote(const std::wstring& sNote)
314331
const auto nNextIndex = sNote.find(L'\n', nIndex);
315332
sLine = (nNextIndex == std::string::npos) ?
316333
sNote.substr(nIndex) : sNote.substr(nIndex, nNextIndex - nIndex);
317-
StringMakeLowercase(sLine);
318-
ExtractSize(sLine);
319334

320-
if (sLine.find(L"pointer") != std::string::npos)
335+
if (!sLine.empty())
321336
{
322-
if (m_nMemSize == MemSize::Unknown)
337+
if (sLine.at(0) == '+' && bImpliedPointer)
323338
{
324-
// pointer size not specified. assume 32-bit
325339
m_nMemSize = MemSize::ThirtyTwoBit;
326340
m_nBytes = 4;
341+
342+
// found a line starting with a plus sign, bit no pointer annotation. bImpliedPointer
343+
// must be true. assume the parent note is not described. pass -1 as the note size
344+
// because we already skipped over the newline character
345+
ProcessIndirectNotes(sNote, gsl::narrow_cast<size_t>(-1));
346+
m_pPointerData->HeaderLength = 0;
347+
break;
327348
}
328349

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

334-
break;
335-
}
353+
if (sLine.find(L"pointer") != std::string::npos)
354+
{
355+
if (m_nMemSize == MemSize::Unknown)
356+
{
357+
// pointer size not specified. assume 32-bit
358+
m_nMemSize = MemSize::ThirtyTwoBit;
359+
m_nBytes = 4;
360+
}
336361

337-
if (m_nMemSize != MemSize::Unknown) // found a size. stop processing.
338-
break;
362+
// if there are any lines starting with a plus sign, extract the indirect code notes
363+
nIndex = sNote.find(L"\n+", nIndex + 1);
364+
if (nIndex != std::string::npos)
365+
ProcessIndirectNotes(sNote, nIndex);
366+
367+
// failed to find nested code notes. create a PointerData object so the note still
368+
// gets treated as a pointer
369+
if (!m_pPointerData)
370+
{
371+
m_pPointerData.reset(new PointerData());
372+
m_pPointerData->HeaderLength = gsl::narrow_cast<unsigned>(sNote.length());
373+
}
374+
375+
break;
376+
}
377+
378+
if (m_nMemSize != MemSize::Unknown) // found a size. stop processing.
379+
break;
380+
}
339381

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

665707
// skip over [whitespace] [optional separator] [whitespace]
666708
const wchar_t* pStop = sNextNote.c_str() + sNextNote.length();
667-
while (pEnd < pStop && isspace(*pEnd))
668-
pEnd++;
669-
if (pEnd < pStop && !isalnum(*pEnd))
709+
while (pEnd < pStop && isspace(*pEnd) && *pEnd != '\n')
710+
++pEnd;
711+
712+
if (pEnd < pStop)
670713
{
671-
pEnd++;
672-
while (pEnd < pStop && isspace(*pEnd))
673-
pEnd++;
714+
if (*pEnd == '\n')
715+
{
716+
// no separator. found an unannotated note
717+
++pEnd;
718+
}
719+
else if (!isalnum(*pEnd))
720+
{
721+
// found a separator. skip it and any following whitespace
722+
++pEnd;
723+
724+
while (pEnd < pStop && isspace(*pEnd))
725+
++pEnd;
726+
}
674727
}
675728

676-
offsetNote.SetNote(sNextNote.substr(pEnd - sNextNote.c_str()));
729+
offsetNote.SetNote(sNextNote.substr(pEnd - sNextNote.c_str()), true);
677730
pointerData->HasPointers |= offsetNote.IsPointer();
678731

679732
offsetNote.SetAddress(gsl::narrow_cast<ra::ByteAddress>(nOffset));

0 commit comments

Comments
 (0)