From 934c395e8d079c5e3b4c80b6ed535fa708088779 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 13 Sep 2026 07:41:24 +0200 Subject: [PATCH 1/2] chore(natvis): Add Visual Studio debugger visualizers for the WWLib containers (#3283) The WWLib containers showed up in the Visual Studio debugger as raw structs, so reading their elements meant expanding pointers and slicing arrays by hand. Each WWLib header that declares a container used by the game now has a matching natvis file in resources/visualstudio/wwlib, registered alongside the existing natvis files under MSVC_IDE, so the containers expand directly to their elements. Covered are VectorClass, DynamicVectorClass, BooleanVectorClass, SimpleVecClass, SimpleDynVecClass, ShareBufferClass, UniqueArrayClass, GenericList, List, Node, DataNode, SList, the MultiList classes and their iterators, HashTableClass, HashTemplateClass, StringClass, WideStringClass and MPSCIntrusiveQueue. Types with no users outside WWLib are left out: IndexClass, NTreeClass, BinaryHeapClass, HashListClass, DoubleNode and Buffer. DynamicVectorClass, SimpleDynVecClass and the typed MultiList classes have rules of their own because natvis rules are inherited, and the base class rule would list the allocated slots instead of the live elements. BooleanVectorClass reports Copy for LastIndex, because that bit is only written back into the packed array once a different index is fetched. StringClass and WideStringClass count the characters when the stored length is 0, as Get_Length does, since a write through Get_Buffer leaves the stored length at 0. Co-Authored-By: Claude Opus 5 --- resources/CMakeLists.txt | 12 ++ resources/visualstudio/wwlib/hash.natvis | 36 ++++++ .../visualstudio/wwlib/hashtemplate.natvis | 36 ++++++ resources/visualstudio/wwlib/listnode.natvis | 64 +++++++++++ .../wwlib/mpsc_intrusive_queue.natvis | 19 ++++ resources/visualstudio/wwlib/multilist.natvis | 103 ++++++++++++++++++ resources/visualstudio/wwlib/sharebuf.natvis | 16 +++ resources/visualstudio/wwlib/simplevec.natvis | 27 +++++ resources/visualstudio/wwlib/slist.natvis | 27 +++++ resources/visualstudio/wwlib/uarray.natvis | 17 +++ resources/visualstudio/wwlib/vector.natvis | 44 ++++++++ .../visualstudio/wwlib/widestring.natvis | 18 +++ resources/visualstudio/wwlib/wwstring.natvis | 18 +++ 13 files changed, 437 insertions(+) create mode 100644 resources/visualstudio/wwlib/hash.natvis create mode 100644 resources/visualstudio/wwlib/hashtemplate.natvis create mode 100644 resources/visualstudio/wwlib/listnode.natvis create mode 100644 resources/visualstudio/wwlib/mpsc_intrusive_queue.natvis create mode 100644 resources/visualstudio/wwlib/multilist.natvis create mode 100644 resources/visualstudio/wwlib/sharebuf.natvis create mode 100644 resources/visualstudio/wwlib/simplevec.natvis create mode 100644 resources/visualstudio/wwlib/slist.natvis create mode 100644 resources/visualstudio/wwlib/uarray.natvis create mode 100644 resources/visualstudio/wwlib/vector.natvis create mode 100644 resources/visualstudio/wwlib/widestring.natvis create mode 100644 resources/visualstudio/wwlib/wwstring.natvis diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index d8d613ca9b2..3dee5754d4b 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -23,5 +23,17 @@ if (MSVC_IDE) visualstudio/stllist.natvis visualstudio/stlvector.natvis visualstudio/unicodestring.natvis + visualstudio/wwlib/hash.natvis + visualstudio/wwlib/hashtemplate.natvis + visualstudio/wwlib/listnode.natvis + visualstudio/wwlib/mpsc_intrusive_queue.natvis + visualstudio/wwlib/multilist.natvis + visualstudio/wwlib/sharebuf.natvis + visualstudio/wwlib/simplevec.natvis + visualstudio/wwlib/slist.natvis + visualstudio/wwlib/uarray.natvis + visualstudio/wwlib/vector.natvis + visualstudio/wwlib/widestring.natvis + visualstudio/wwlib/wwstring.natvis ) endif() diff --git a/resources/visualstudio/wwlib/hash.natvis b/resources/visualstudio/wwlib/hash.natvis new file mode 100644 index 00000000000..d31c64f960a --- /dev/null +++ b/resources/visualstudio/wwlib/hash.natvis @@ -0,0 +1,36 @@ + + + + + {{ buckets={HashTableSize} }} + + HashTableSize + + + + + + entry = HashTable[bucket] + + + entry + entry = entry->NextHash + + bucket = bucket + 1 + + + + + + + {{ done }} + {*CurrentEntry} + + CurrentEntry + NextEntry + Index + Table + + + diff --git a/resources/visualstudio/wwlib/hashtemplate.natvis b/resources/visualstudio/wwlib/hashtemplate.natvis new file mode 100644 index 00000000000..dbf81cc1d50 --- /dev/null +++ b/resources/visualstudio/wwlib/hashtemplate.natvis @@ -0,0 +1,36 @@ + + + + + {{ buckets={(int)Size} }} + + (int)Size + + + + + + handle = Hash[bucket] + + + Table[handle].Value + handle = Table[handle].Next + + bucket = bucket + 1 + + + + + + + {{ done }} + {HashTable.Table[Handle].Value} + + HashTable.Table[Handle].Key + HashTable.Table[Handle].Value + HashIndex + HashTable + + + diff --git a/resources/visualstudio/wwlib/listnode.natvis b/resources/visualstudio/wwlib/listnode.natvis new file mode 100644 index 00000000000..dc33d3d54e2 --- /dev/null +++ b/resources/visualstudio/wwlib/listnode.natvis @@ -0,0 +1,64 @@ + + + + + {{ size=0 }} + {{ GenericList }} + + + + + + node + node = node->NextNode + + + + + + + + {{ size=0 }} + {{ List }} + + + + + + ($T1)node + node = node->NextNode + + + + + + + {{ unlinked }} + {{ GenericNode }} + + NextNode + PrevNode + + + + + {{ unlinked }} + {{ Node }} + + ($T1)NextNode + ($T1)PrevNode + + + + + {Value} + + Value + (DataNode<$T1> *)NextNode + (DataNode<$T1> *)PrevNode + + + diff --git a/resources/visualstudio/wwlib/mpsc_intrusive_queue.natvis b/resources/visualstudio/wwlib/mpsc_intrusive_queue.natvis new file mode 100644 index 00000000000..543f35d07ff --- /dev/null +++ b/resources/visualstudio/wwlib/mpsc_intrusive_queue.natvis @@ -0,0 +1,19 @@ + + + + + {{ empty }} + {{ MPSCIntrusiveQueue }} + + + + + + node + node = node->next + + + + + diff --git a/resources/visualstudio/wwlib/multilist.natvis b/resources/visualstudio/wwlib/multilist.natvis new file mode 100644 index 00000000000..22e9d604af9 --- /dev/null +++ b/resources/visualstudio/wwlib/multilist.natvis @@ -0,0 +1,103 @@ + + + + + {{ size=0 }} + {{ GenericMultiList }} + + + + + + node->Object + node = node->Next + + + + + + + + {{ size=0 }} + {{ MultiList }} + + + + + + ($T1 *)node->Object + node = node->Next + + + + + + + {{ size=0 }} + {{ RefMultiList }} + + + + + + ($T1 *)node->Object + node = node->Next + + + + + + + + {{ not in any list }} + {{ in list(s) }} + + + lists this object belongs to + + + + + + node->List + node = node->NextList + + + + + + + + + {{ object={Object} }} + + Object + List + Next + Prev + NextList + + + + + {{ done }} + {CurNode->Object} + + CurNode->Object + List + + + + + + + {{ done }} + {*($T1 *)CurNode->Object} + + ($T1 *)CurNode->Object + List + + + diff --git a/resources/visualstudio/wwlib/sharebuf.natvis b/resources/visualstudio/wwlib/sharebuf.natvis new file mode 100644 index 00000000000..ed69a353423 --- /dev/null +++ b/resources/visualstudio/wwlib/sharebuf.natvis @@ -0,0 +1,16 @@ + + + + {{ size={Count} }} + + Count + NumRefs + + Msg,s + + Count + Array + + + + diff --git a/resources/visualstudio/wwlib/simplevec.natvis b/resources/visualstudio/wwlib/simplevec.natvis new file mode 100644 index 00000000000..8d46ec4fc69 --- /dev/null +++ b/resources/visualstudio/wwlib/simplevec.natvis @@ -0,0 +1,27 @@ + + + + {{ size={VectorMax} }} + + VectorMax + + VectorMax + Vector + + + + + + + {{ size={ActiveCount} }} + + ActiveCount + VectorMax + + ActiveCount + Vector + + + + diff --git a/resources/visualstudio/wwlib/slist.natvis b/resources/visualstudio/wwlib/slist.natvis new file mode 100644 index 00000000000..f7f26038b3e --- /dev/null +++ b/resources/visualstudio/wwlib/slist.natvis @@ -0,0 +1,27 @@ + + + + + {{ size=0 }} + {{ SList }} + + + + + + ($T1 *)node->NodeData + node = (SLNode<$T1> *)node->NodeNext + + + + + + + {*($T1 *)NodeData} + + ($T1 *)NodeData + (SLNode<$T1> *)NodeNext + + + diff --git a/resources/visualstudio/wwlib/uarray.natvis b/resources/visualstudio/wwlib/uarray.natvis new file mode 100644 index 00000000000..93a7368af86 --- /dev/null +++ b/resources/visualstudio/wwlib/uarray.natvis @@ -0,0 +1,17 @@ + + + + + {{ size={UniqueItems.ActiveCount} }} + + UniqueItems.ActiveCount + UniqueItems.VectorMax + HashTableSize + + UniqueItems.ActiveCount + UniqueItems.Vector[$i].Item + + + + diff --git a/resources/visualstudio/wwlib/vector.natvis b/resources/visualstudio/wwlib/vector.natvis new file mode 100644 index 00000000000..af37c172136 --- /dev/null +++ b/resources/visualstudio/wwlib/vector.natvis @@ -0,0 +1,44 @@ + + + + {{ size={VectorMax} }} + + VectorMax + IsAllocated + + VectorMax + Vector + + + + + + + {{ size={ActiveCount} }} + + ActiveCount + VectorMax + GrowthStep + + ActiveCount + Vector + + + + + + + {{ size={BitCount} }} + + BitCount + LastIndex + Copy + + BitCount + $i == LastIndex ? Copy : (bool)((BitArray.Vector[$i / 8] >> ($i % 8)) & 1) + + + + diff --git a/resources/visualstudio/wwlib/widestring.natvis b/resources/visualstudio/wwlib/widestring.natvis new file mode 100644 index 00000000000..815f6c61fab --- /dev/null +++ b/resources/visualstudio/wwlib/widestring.natvis @@ -0,0 +1,18 @@ + + + + + {m_Buffer,su} + m_Buffer,su + + ((int *)m_Buffer)[-1] != 0 ? ((int *)m_Buffer)[-1] : (int)wcsnlen(m_Buffer, ((int *)m_Buffer)[-2]) + ((int *)m_Buffer)[-2] + m_Buffer,su + m_Buffer + + + diff --git a/resources/visualstudio/wwlib/wwstring.natvis b/resources/visualstudio/wwlib/wwstring.natvis new file mode 100644 index 00000000000..9a4a1118879 --- /dev/null +++ b/resources/visualstudio/wwlib/wwstring.natvis @@ -0,0 +1,18 @@ + + + + + {m_Buffer,s} + m_Buffer,s + + ((int *)m_Buffer)[-1] != 0 ? ((int *)m_Buffer)[-1] : (int)strnlen(m_Buffer, ((int *)m_Buffer)[-2]) + ((int *)m_Buffer)[-2] + m_Buffer,s + m_Buffer + + + From bccf3f5959c3890cdb4c68c43b374016989a268e Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Mon, 14 Sep 2026 08:45:10 +0200 Subject: [PATCH 2/2] chore(natvis): Show length, capacity and reference count for AsciiString and UnicodeString (#3283) The [data] item of both visualizers was bound to the ref counted header instead of the text, so expanding it showed the reference count and the allocation size under a misleading name, and the length was not shown at all. Both visualizers now list [length], [capacity] and [refs] as named items. No length is stored, so [length] counts the characters like getLength does, capped at the allocation so that a missing terminator cannot read past the buffer. [capacity] includes the slot for the terminator, matching StringClass. A [refs] above 1 means the buffer is shared and will be copied on the next write. A StringView adds the text visualizer for long strings. Co-Authored-By: Claude Opus 5 --- resources/visualstudio/asciistring.natvis | 15 ++++++++++----- resources/visualstudio/unicodestring.natvis | 15 ++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/resources/visualstudio/asciistring.natvis b/resources/visualstudio/asciistring.natvis index 8f88151691e..4f9a8f1c48d 100644 --- a/resources/visualstudio/asciistring.natvis +++ b/resources/visualstudio/asciistring.natvis @@ -1,11 +1,16 @@ + - {(const char *)(& m_data[1]),s8} - "" + "" + {(const char *)(m_data + 1),s8} + (const char *)(m_data + 1),s8 - m_data - (const char *)(& m_data[1]) + m_data == 0 ? 0 : (int)strnlen((const char *)(m_data + 1), m_data->m_numCharsAllocated) + (int)m_data->m_numCharsAllocated + (int)m_data->m_refCount + (const char *)(m_data + 1),s8 - \ No newline at end of file + diff --git a/resources/visualstudio/unicodestring.natvis b/resources/visualstudio/unicodestring.natvis index 22aaf299cdc..a71be3c4ed9 100644 --- a/resources/visualstudio/unicodestring.natvis +++ b/resources/visualstudio/unicodestring.natvis @@ -1,11 +1,16 @@ + - {(const wchar_t *)(& m_data[1]),su} - "" + "" + {(const wchar_t *)(m_data + 1),su} + (const wchar_t *)(m_data + 1),su - m_data - (const wchar_t *)(& m_data[1]) + m_data == 0 ? 0 : (int)wcsnlen((const wchar_t *)(m_data + 1), m_data->m_numCharsAllocated) + (int)m_data->m_numCharsAllocated + (int)m_data->m_refCount + (const wchar_t *)(m_data + 1),su - \ No newline at end of file +