DeanWang

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

UE3或者UE4的FString类型无法在内存中直接看到值,为了debug方便,需要第三方文件的协助,可以将以下两个文件UE3.natvis和UE4.natvis拷贝到$USERPROFILE/Documents/Visual Studio 2012/Visualizers 目录下,在debug的时候可以实时看到FString的值了:

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

  <!-- Epic Games, Inc. UE3 Visualizers -->
  <!-- Copy this into c:\Users\<Your user folder>\My Documents\Visual Studio 2012\Visualizers -->

  <!-- FString visualizer -->
  <Type Name="UE3::FString">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">{AllocatorInstance.Data,su}</DisplayString>
    <StringView Condition="ArrayMax &gt;= ArrayNum">AllocatorInstance.Data,su</StringView>
  </Type>

  <!-- FName visualizer -->
  <Type Name="UE3::FName">
    <DisplayString Condition="Index &gt;= Names.ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="Index &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="0 == (((((FNameEntry**) Names.AllocatorInstance.Data)[Index])->Index) &amp; 1) &amp;&amp; Number &gt; 0">{(((FNameEntry**) Names.AllocatorInstance.Data)[Index])->AnsiName,s}_{Number - 1}</DisplayString>
    <DisplayString Condition="1 == (((((FNameEntry**) Names.AllocatorInstance.Data)[Index])->Index) &amp; 1) &amp;&amp; Number &gt; 0">{(((FNameEntry**) Names.AllocatorInstance.Data)[Index])->UniName,su}_{Number - 1}</DisplayString>
    <DisplayString Condition="0 == (((((FNameEntry**) Names.AllocatorInstance.Data)[Index])->Index) &amp; 1)">{(((FNameEntry**) Names.AllocatorInstance.Data)[Index])->AnsiName,s}</DisplayString>
    <DisplayString Condition="1 == (((((FNameEntry**) Names.AllocatorInstance.Data)[Index])->Index) &amp; 1)">{(((FNameEntry**) Names.AllocatorInstance.Data)[Index])->UniName,su}</DisplayString>
  </Type>

  <!-- TArray visualizer -->
  <Type Name="UE3::TArray&lt;*,*&gt;|UE3::TArrayNoInit&lt;*,*&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems Condition="ArrayNum &lt;= ArrayMax">
        <Size>ArrayNum</Size>
        <ValuePointer>($T1*) AllocatorInstance.Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TIndirectArray visualizer -->
  <Type Name="UE3::TIndirectArray&lt;*,*&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <IndexListItems Condition="ArrayNum &lt;= ArrayMax">
        <Size>ArrayNum</Size>
        <ValueNode>*(($T1**)AllocatorInstance.Data)[$i]</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- TSparseArray visualizer -->
  <Type Name="UE3::TSparseArray&lt;*,*&gt;|UE3::TSparseArrayNoInit&lt;*,*&gt;">
    <DisplayString Condition="Data.ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="Data.ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="Data.ArrayMax &lt; Data.ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="Data.ArrayMax &gt;= Data.ArrayNum">Num={Data.ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems Condition="Data.ArrayNum &lt;= Data.ArrayMax">
        <Size>Data.ArrayNum</Size>
        <ValuePointer>($T1*) Data.AllocatorInstance.Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TMapBase::FPair visualizer -->
  <Type Name="UE3::TMapBase&lt;*,*,*,*,*&gt;::FPair">
      <DisplayString>({Key}, {Value})</DisplayString>
  </Type>

  <!-- TMapBase visualizer -->
  <Type Name="UE3::TMapBase&lt;*,*,*,*,*&gt;">
    <DisplayString Condition="Pairs.Elements.Data.ArrayNum &lt;= 0">Empty</DisplayString>
    <DisplayString Condition="Pairs.Elements.Data.ArrayNum &lt;= Pairs.Elements.Data.ArrayMax">Num={Pairs.Elements.Data.ArrayNum - Pairs.Elements.NumFreeIndices}</DisplayString>
    <Expand>
      <IndexListItems Condition="Pairs.Elements.Data.ArrayNum &gt; 0 &amp;&amp; Pairs.Elements.Data.ArrayNum &lt;= Pairs.Elements.Data.ArrayMax">
        <Size>Pairs.Elements.Data.ArrayNum</Size>
        <ValueNode>((TSet&lt;TMapBase&lt;$T1,$T2,$T3,$T4&gt;::FPair,TMapBase&lt;$T1,$T2,$T3,$T4&gt;::KeyFuncs,$T4&gt;::FElement *) Pairs.Elements.Data.AllocatorInstance.Data + $i)-&gt;Value</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- GFx GAtomicValueBase visualizer -->
  <Type Name="GAtomicValueBase">
    <DisplayString>{Value}</DisplayString>
  </Type>

  <!-- UObject visualizer -->
  <Type Name="UE3::UObject">
    <DisplayString Condition="Outer">(Name={Name}, Outer={Outer})</DisplayString>
    <DisplayString Condition="!Outer">(Name={Name})</DisplayString>
  </Type>

</AutoVisualizer>
UE3.natvis
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

  <!-- Epic Games, Inc. UE4 Visualizers -->
  <!-- Copy this into c:\Users\<Your user folder>\My Documents\Visual Studio 2012\Visualizers -->

  <!-- FString visualizer -->
  <Type Name="FString">
    <DisplayString Condition="Data.ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="Data.ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="Data.ArrayMax &lt; Data.ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="Data.ArrayMax &gt;= Data.ArrayNum">{Data.AllocatorInstance.Data,su}</DisplayString>
    <StringView Condition="Data.ArrayMax &gt;= Data.ArrayNum">Data.AllocatorInstance.Data,su</StringView>
  </Type>

  <!-- FName visualizer -->
  <Type Name="FName">
    <DisplayString Condition="ComparisonIndex &gt;= 2097152">Invalid</DisplayString>
    <DisplayString Condition="ComparisonIndex &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ComparisonIndex &lt; 2097152 &amp;&amp; Number &gt; 0">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[ComparisonIndex / 16384][ComparisonIndex % 16384]))->AnsiName,s}_{Number-1}</DisplayString>
    <DisplayString Condition="ComparisonIndex &lt; 2097152">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[ComparisonIndex / 16384][ComparisonIndex % 16384]))->AnsiName,s}</DisplayString>
    <StringView Condition="ComparisonIndex &lt; 2097152">((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[ComparisonIndex / 16384][ComparisonIndex % 16384]))->AnsiName</StringView>
  </Type>
  <Type Name="FName">
    <DisplayString Condition="DisplayIndex &gt;= 2097152">Invalid</DisplayString>
    <DisplayString Condition="DisplayIndex &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="DisplayIndex &lt; 2097152 &amp;&amp; Number &gt; 0">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[DisplayIndex / 16384][DisplayIndex % 16384]))->AnsiName,s}_{Number-1}</DisplayString>
    <DisplayString Condition="DisplayIndex &lt; 2097152">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[DisplayIndex / 16384][DisplayIndex % 16384]))->AnsiName,s}</DisplayString>
    <StringView Condition="DisplayIndex &lt; 2097152">((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[DisplayIndex / 16384][DisplayIndex % 16384]))->AnsiName</StringView>
  </Type>

  <Type Name="FMinimalName">
    <DisplayString Condition="Index &gt;= 2097152">Invalid</DisplayString>
    <DisplayString Condition="Index &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="Index &lt; 2097152 &amp;&amp; Number &gt; 0">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[Index / 16384][Index % 16384]))->AnsiName}_{Number-1}</DisplayString>
    <DisplayString Condition="Index &lt; 2097152">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[Index / 16384][Index % 16384]))->AnsiName}</DisplayString>
    <StringView Condition="Index &lt; 2097152">((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[Index / 16384][Index % 16384]))->AnsiName</StringView>
  </Type>

  <!-- FStatMessage visualizer @see Stats2.h -->
  <Type Name="FStatMessage">
    <!--ST_None=1-->
    <DisplayString Condition="((NameAndInfo.NameAndInfo.Number >> 9)&amp;0x7) == 1" >{{NoneType NameAndInfo={NameAndInfo.NameAndInfo}}}</DisplayString>
    <!--ST_int64=2-->
    <DisplayString Condition="((NameAndInfo.NameAndInfo.Number >> 9)&amp;0x7) == 2" >{{Int64={DebugStatData.Cycles},C={DebugStatData.CCAndDuration[0]},D={DebugStatData.CCAndDuration[1]} NameAndInfo={NameAndInfo.NameAndInfo}}}</DisplayString>
    <!--ST_double=3-->
    <DisplayString Condition="((NameAndInfo.NameAndInfo.Number >> 9)&amp;0x7) == 3" >{{Float={DebugStatData.Float} NameAndInfo={NameAndInfo.NameAndInfo}}}</DisplayString>
    <!--ST_FName=4-->
    <!--ST_Ptr=5-->
    <DisplayString Condition="((NameAndInfo.NameAndInfo.Number >> 9)&amp;0x7) == 5" >{{Ptr={DebugStatData.Ptr} NameAndInfo={NameAndInfo.NameAndInfo}}}</DisplayString>
  </Type>

  <Type Name="FVector_NetQuantize">
    <DisplayString>{{X={X} Y={Y} Z={Z}}</DisplayString>
  </Type>

  <Type Name="FVector_NetQuantize10">
    <DisplayString>{{X={X} Y={Y} Z={Z}}</DisplayString>
  </Type>

  <Type Name="FVector_NetQuantize100">
    <DisplayString>{{X={X} Y={Y} Z={Z}}</DisplayString>
  </Type>

  <Type Name="FVector_NetQuantizeNormal">
    <DisplayString>{{X={X} Y={Y} Z={Z}}</DisplayString>
  </Type>

  <!-- TEnumAsByte visualizer -->
  <Type Name="TEnumAsByte&lt;*&gt;">
    <DisplayString>{($T1)Value}</DisplayString>
  </Type>

  <!-- UObjectBase visualizer -->
  <Type Name="UObjectBase">
    <DisplayString Condition="Outer">(Name={Name}, Outer={Outer})</DisplayString>
    <DisplayString Condition="!Outer">(Name={Name})</DisplayString>
  </Type>

  <!-- TArray<*,TFixedAllocator<*> > visualizer -->
  <Type Name="TArray&lt;*,TFixedAllocator&lt;*&gt;&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems Condition="ArrayNum &lt;= ArrayMax">
        <Size>ArrayNum</Size>
        <ValuePointer>($T1*)AllocatorInstance.InlineData</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TArray<*,TInlineAllocator<*,*> > visualizer -->
  <Type Name="TArray&lt;*,TInlineAllocator&lt;*,*&gt;&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems Condition="ArrayNum &lt;= ArrayMax">
        <Size>ArrayNum</Size>
        <ValuePointer Condition="AllocatorInstance.SecondaryData.Data == 0">($T1*)AllocatorInstance.InlineData</ValuePointer>
        <ValuePointer Condition="AllocatorInstance.SecondaryData.Data != 0">($T1*)AllocatorInstance.SecondaryData.Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TArray visualizer -->
  <Type Name="TArray&lt;*,*&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems Condition="ArrayNum &lt;= ArrayMax">
        <Size>ArrayNum</Size>
        <ValuePointer>($T1*)AllocatorInstance.Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TIndirectArray visualizer -->
  <Type Name="TIndirectArray&lt;*,*&gt;">
    <DisplayString Condition="Array.ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="Array.ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="Array.ArrayMax &lt; Array.ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="Array.ArrayMax &gt;= Array.ArrayNum">Num={Array.ArrayNum}</DisplayString>
    <Expand>
      <IndexListItems Condition="Array.ArrayNum &lt;= Array.ArrayMax">
        <Size>Array.ArrayNum</Size>
        <ValueNode>*(($T1**)Array.AllocatorInstance.Data)[$i]</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- TChunkedArray visualizer -->
  <Type Name="TChunkedArray&lt;*,*&gt;">
    <DisplayString Condition="NumElements == 0">Empty</DisplayString>
    <DisplayString Condition="NumElements &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="NumElements &gt; 0">NumElements={NumElements}, NumChunks={Chunks.Array.ArrayNum}, {NumElementsPerChunk}</DisplayString>

    <Expand>
      <IndexListItems Condition="NumElements &gt; 0">
        <Size>NumElements</Size>
        <ValueNode>
          *(
          *(
          ($T1**)Chunks.Array.AllocatorInstance.Data + ($i / NumElementsPerChunk)
          ) + ($i % NumElementsPerChunk)
          )
        </ValueNode>
      </IndexListItems>
    </Expand>
  </Type>


  <!-- TSparseArray visualizer -->
  <Type Name="TSparseArray&lt;*,*&gt;">
    <DisplayString Condition="(Data.ArrayNum - NumFreeIndices) &lt;= 0">Empty</DisplayString>
    <DisplayString Condition="Data.ArrayNum &lt;= Data.ArrayMax">Num={Data.ArrayNum - NumFreeIndices}</DisplayString>
    <Expand>
      <IndexListItems Condition="Data.ArrayNum &gt; 0 &amp;&amp; Data.ArrayNum &lt;= Data.ArrayMax">
        <Size>Data.ArrayNum</Size>
        <ValueNode Condition="(AllocationFlags.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocationFlags.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) != 0">($T1*)Data.AllocatorInstance.Data + $i</ValueNode>
        <ValueNode Condition="(AllocationFlags.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocationFlags.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) != 0">($T1*)Data.AllocatorInstance.Data + $i</ValueNode>
        <ValueNode Condition="(AllocationFlags.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocationFlags.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
        <ValueNode Condition="(AllocationFlags.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocationFlags.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- TBitArray visualizer -->
  <Type Name="TBitArray&lt;*&gt;">
    <DisplayString Condition="NumBits == 0">Empty</DisplayString>
    <DisplayString Condition="NumBits &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="NumBits &gt; 0">NumBits={NumBits}, MaxBits={MaxBits}</DisplayString>
    <Expand>
      <IndexListItems Condition="NumBits &gt; 0">
        <Size>NumBits</Size>
        <ValueNode Condition="(AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocatorInstance.SecondaryData.Data    )[$i/32]&gt;&gt;$i &amp; 1) != 0">1</ValueNode>
        <ValueNode Condition="(AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocatorInstance.InlineData            )[$i/32]&gt;&gt;$i &amp; 1) != 0">1</ValueNode>
        <ValueNode Condition="(AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocatorInstance.SecondaryData.Data    )[$i/32]&gt;&gt;$i &amp; 1) == 0">0</ValueNode>
        <ValueNode Condition="(AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocatorInstance.InlineData            )[$i/32]&gt;&gt;$i &amp; 1) == 0">0</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- TPair visualizer -->
  <Type Name="TPair&lt;*,*&gt;">
    <DisplayString>({Key}, {Value})</DisplayString>
  </Type>

  <!-- TSharedPtr visualizer -->
  <Type Name="TSharedPtr&lt;*,*&gt;">
    <DisplayString Condition="Object == 0">Null</DisplayString>
    <DisplayString Condition="Object != 0">Ptr={(void*)Object}, SharedRefs={SharedReferenceCount.ReferenceController->SharedReferenceCount}, WeakRefs={SharedReferenceCount.ReferenceController->WeakReferenceCount}, Object={*Object}</DisplayString>
    <Expand>
      <Item Condition="Object != 0" Name="[SharedReferenceCount]">SharedReferenceCount.ReferenceController->SharedReferenceCount</Item>
      <Item Condition="Object != 0" Name="[WeakReferenceCount]">SharedReferenceCount.ReferenceController->WeakReferenceCount</Item>
      <Item Condition="Object != 0" Name="[Ptr]">(void*)Object</Item>
      <ExpandedItem Condition="Object != 0">*Object</ExpandedItem>
    </Expand>
  </Type>

  <!-- TSharedRef visualizer -->
  <Type Name="TSharedRef&lt;*,*&gt;">
    <DisplayString Condition="Object != 0">Ptr={(void*)Object}, SharedRefs={SharedReferenceCount.ReferenceController->SharedReferenceCount}, WeakRefs={SharedReferenceCount.ReferenceController->WeakReferenceCount}, Object={*Object}</DisplayString>
    <Expand>
      <Item Condition="Object != 0" Name="[SharedReferenceCount]">SharedReferenceCount.ReferenceController->SharedReferenceCount</Item>
      <Item Condition="Object != 0" Name="[WeakReferenceCount]">SharedReferenceCount.ReferenceController->WeakReferenceCount</Item>
      <Item Condition="Object != 0" Name="[Ptr]">(void*)Object</Item>
      <ExpandedItem Condition="Object != 0">*Object</ExpandedItem>
    </Expand>
  </Type>

  <!-- TWeakPtr visualizer -->
  <Type Name="TWeakPtr&lt;*,*&gt;">
    <DisplayString Condition="Object == 0">Null</DisplayString>
    <DisplayString Condition="WeakReferenceCount.ReferenceController->SharedReferenceCount == 0">Object has been destroyed</DisplayString>
    <DisplayString Condition="Object != 0">Ptr={(void*)Object}, SharedRefs={WeakReferenceCount.ReferenceController->SharedReferenceCount}, WeakRefs={WeakReferenceCount.ReferenceController->WeakReferenceCount}, Object={*Object}</DisplayString>
    <Expand>
      <Item Condition="Object != 0" Name="[SharedReferenceCount]">WeakReferenceCount.ReferenceController->SharedReferenceCount</Item>
      <Item Condition="Object != 0" Name="[WeakReferenceCount]">WeakReferenceCount.ReferenceController->WeakReferenceCount</Item>
      <Item Condition="Object != 0 &amp;&amp; WeakReferenceCount.ReferenceController->SharedReferenceCount > 0" Name="[Ptr]">(void*)Object</Item>
      <ExpandedItem Condition="Object != 0 &amp;&amp; WeakReferenceCount.ReferenceController->SharedReferenceCount > 0">*Object</ExpandedItem>
    </Expand>
  </Type>


  <!-- TMapBase visualizer -->
  <Type Name="TMapBase&lt;*,*,*,*&gt;">
    <DisplayString Condition="Pairs.Elements.Data.ArrayNum - Pairs.Elements.NumFreeIndices &lt;= 0">Empty</DisplayString>
    <DisplayString Condition="Pairs.Elements.Data.ArrayNum &lt;= Pairs.Elements.Data.ArrayMax" >Num={Pairs.Elements.Data.ArrayNum - Pairs.Elements.NumFreeIndices}</DisplayString>
    <Expand>
      <IndexListItems Condition="Pairs.Elements.Data.ArrayNum - Pairs.Elements.NumFreeIndices &gt; 0 &amp;&amp; Pairs.Elements.Data.ArrayNum &lt;= Pairs.Elements.Data.ArrayMax">
        <Size>Pairs.Elements.Data.ArrayNum</Size>
        <ValueNode Condition="(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) != 0">((TSetElement&lt;TPair&lt;$T1,$T2&gt; &gt; *)Pairs.Elements.Data.AllocatorInstance.Data)[$i].Value</ValueNode>
        <ValueNode Condition="(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Pairs.Elements.AllocationFlags.AllocatorInstance.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) != 0">((TSetElement&lt;TPair&lt;$T1,$T2&gt; &gt; *)Pairs.Elements.Data.AllocatorInstance.Data)[$i].Value</ValueNode>
        <ValueNode Condition="(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
        <ValueNode Condition="(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Pairs.Elements.AllocationFlags.AllocatorInstance.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- TSet visualizer -->
  <Type Name="TSet&lt;*,*,*&gt;">
    <DisplayString Condition="Elements.Data.ArrayNum - Elements.NumFreeIndices &lt;= 0">Empty</DisplayString>
    <DisplayString Condition="Elements.Data.ArrayNum &lt;= Elements.Data.ArrayMax">Num={Elements.Data.ArrayNum - Elements.NumFreeIndices}</DisplayString>
    <Expand>
      <IndexListItems Condition="Elements.Data.ArrayNum - Elements.NumFreeIndices &gt; 0 &amp;&amp; Elements.Data.ArrayNum &lt;= Elements.Data.ArrayMax">
        <Size>Elements.Data.ArrayNum</Size>
        <ValueNode Condition="(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) != 0">((TSetElement &lt;$T1&gt; *)Elements.Data.AllocatorInstance.Data)[$i].Value</ValueNode>
        <ValueNode Condition="(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Elements.AllocationFlags.AllocatorInstance.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) != 0">((TSetElement &lt;$T1&gt; *)Elements.Data.AllocatorInstance.Data)[$i].Value</ValueNode>
        <ValueNode Condition="(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
        <ValueNode Condition="(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Elements.AllocationFlags.AllocatorInstance.InlineData)[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- FWeakObjectPtr|TWeakObjectPtr<*>|TAutoWeakObjectPtr<*> visualizer -->
  <Type Name="FWeakObjectPtr|TWeakObjectPtr&lt;*&gt;|TAutoWeakObjectPtr&lt;*&gt;">
    <DisplayString Condition="ObjectSerialNumber &lt; 1">NULL</DisplayString>
    <DisplayString Condition="*((*(*GSerialNumberBlocksForDebugVisualizers + (ObjectIndex / 0x4000))) + (ObjectIndex % 0x4000)) != ObjectSerialNumber">STALE</DisplayString>
    <DisplayString>{GObjectArrayForDebugVisualizers[ObjectIndex / 0x4000][ObjectIndex % 0x4000]}</DisplayString>
    <Expand>
      <ExpandedItem>GObjectArrayForDebugVisualizers[ObjectIndex / 0x4000][ObjectIndex % 0x4000]</ExpandedItem>
    </Expand>
  </Type>

  <!-- FSubobjectPtr|TSubobjectPtr visualizer -->
  <Type Name="FSubobjectPtr|TSubobjectPtr&lt;*&gt;">
    <DisplayString>{Object}</DisplayString>
  </Type>

  <!-- TOptional visualizer -->
  <Type Name="TOptional&lt;*&gt;">
    <DisplayString Condition="!bIsSet">Unset</DisplayString>
    <DisplayString Condition="bIsSet">Set: {{{*($T1*)&amp;Value}}}</DisplayString>
    <Expand>
      <ExpandedItem Condition="bIsSet">*($T1*)&amp;Value</ExpandedItem>
    </Expand>
  </Type>

  <!-- TFunction visualizer -->
  <Type Name="UE4Function_Private::TDebugHelper&lt;*&gt;">
    <DisplayString>{*Ptr}</DisplayString>
    <Expand>
      <ExpandedItem>*Ptr</ExpandedItem>
    </Expand>
  </Type>
  <Type Name="TFunctionRef&lt;*&gt;">
    <DisplayString Condition="Ptr">{DebugPtrStorage}</DisplayString>
    <DisplayString Condition="!Ptr">Unset</DisplayString>
    <Expand>
      <ExpandedItem Condition="Ptr">DebugPtrStorage</ExpandedItem>
    </Expand>
  </Type>

</AutoVisualizer>
UE4.natvis

针对于PS4版本的debug,需要将以下两个文件拷贝到:c:\Users\username\Documents\SCE\orbis-debugger :

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

  <!-- UE3 Visualizers -->
  <!-- Copy this into $USERPROFILE/Documents/SCE/orbis-debugger -->

  <!-- FString visualizer -->
  <Type Name="UE3::FString">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">{AllocatorInstance.Data,su}</DisplayString>
    <StringView Condition="ArrayMax &gt;= ArrayNum">AllocatorInstance.Data,su</StringView>
  </Type>

  <!-- FName visualizer -->
  <Type Name="UE3::FName">
    <DisplayString Condition="Index &gt;= Names.ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="Index &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="0 == (((((::UE3::FNameEntry**) Names.AllocatorInstance.Data)[Index])->Index) &amp; 1)">{(((::UE3::FNameEntry**) Names.AllocatorInstance.Data)[Index])->AnsiName,s}_{Number - 1}</DisplayString>
    <DisplayString Condition="1 == (((((::UE3::FNameEntry**) Names.AllocatorInstance.Data)[Index])->Index) &amp; 1)">{(((::UE3::FNameEntry**) Names.AllocatorInstance.Data)[Index])->UniName,su}_{Number - 1}</DisplayString>
  </Type>

  <!-- TArray visualizer -->
  <Type Name="UE3::TArray&lt;*,*&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems>
        <Size>ArrayNum</Size>
        <ValuePointer>($T1 *) AllocatorInstance.Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>
  <!-- AC TArray has 3 template parameters -->
  <Type Name="UE3::TArray&lt;*,*,*&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems>
        <Size>ArrayNum</Size>
        <ValuePointer>($T1 *) AllocatorInstance.Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TSparseArray visualizer -->
  <Type Name="UE3::TSparseArray&lt;*,*&gt;">
    <DisplayString Condition="Data.ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="Data.ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="Data.ArrayMax &lt; Data.ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="Data.ArrayMax &gt;= Data.ArrayNum">Num={Data.ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems Condition="Data.ArrayNum &lt;= Data.ArrayMax">
        <Size>Data.ArrayNum</Size>
        <ValuePointer>(::$T1 *) Data.AllocatorInstance.Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TMapBase::FPair visualizer -->
  <Type Name="UE3::TMapBase&lt;*,*,*,*,*&gt;::FPair">
      <DisplayString>({Key}, {Value})</DisplayString>
  </Type>

  <!-- TMapBase visualizer -->
  <Type Name="UE3::TMapBase&lt;*,*,*,*,*&gt;">
    <DisplayString Condition="Pairs.Elements.Data.ArrayNum &lt;= 0">Empty</DisplayString>
    <DisplayString Condition="Pairs.Elements.Data.ArrayNum &lt;= Pairs.Elements.Data.ArrayMax">Num={Pairs.Elements.Data.ArrayNum - Pairs.Elements.NumFreeIndices}</DisplayString>
    <Expand>
      <IndexListItems Condition="Pairs.Elements.Data.ArrayNum &gt; 0 &amp;&amp; Pairs.Elements.Data.ArrayNum &lt;= Pairs.Elements.Data.ArrayMax">
        <Size>Pairs.Elements.Data.ArrayNum</Size>
        <ValueNode>((TSet&lt;TMapBase&lt;$T1,$T2,$T3,$T4&gt;::FPair,TMapBase&lt;$T1,$T2,$T3,$T4&gt;::KeyFuncs,$T4&gt;::FElement *) Pairs.Elements.Data.AllocatorInstance.Data + $i)-&gt;Value</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- GFx GAtomicValueBase visualizer -->
  <Type Name="GAtomicValueBase">
    <DisplayString>{Value}</DisplayString>
  </Type>

  <!-- UObject visualizer -->
  <Type Name="UE3::UObject">
    <DisplayString Condition="0 != Outer">(Name={Name}, Outer={Outer})</DisplayString>
    <DisplayString Condition="0 == Outer">(Name={Name})</DisplayString>
  </Type>

</AutoVisualizer>
PS4UE3.natvis
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

  <!-- Epic Games, Inc. UE4 Visualizers -->
  <!-- Copy this into Documents\SCE\orbis-debugger -->

  <!-- FString visualizer -->
  <Type Name="FString">
    <DisplayString Condition="Data.ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="Data.ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="Data.ArrayMax &lt; Data.ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="Data.ArrayMax &gt;= Data.ArrayNum">{Data.AllocatorInstance.Data,su}</DisplayString>
    <StringView Condition="Data.ArrayMax &gt;= Data.ArrayNum">Data.AllocatorInstance.Data,su</StringView>
  </Type>

  <!-- FName visualizer -->
  <Type Name="FName">
    <DisplayString Condition="ComparisonIndex &gt;= 2097152">Invalid</DisplayString>
    <DisplayString Condition="ComparisonIndex &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="(ComparisonIndex &lt; 2097152) &amp;&amp; (Number &gt; 0)">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[ComparisonIndex / 16384][ComparisonIndex % 16384]))->AnsiName,s}_{Number-1}</DisplayString>
    <DisplayString Condition="ComparisonIndex &lt; 2097152">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[ComparisonIndex / 16384][ComparisonIndex % 16384]))->AnsiName,s}</DisplayString>
    <StringView Condition="ComparisonIndex &lt; 2097152">((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[ComparisonIndex / 16384][ComparisonIndex % 16384]))->AnsiName</StringView>
  </Type>

  <Type Name="FMinimalName">
    <DisplayString Condition="Index &gt;= 2097152">Invalid</DisplayString>
    <DisplayString Condition="Index &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="(Index &lt; 2097152) &amp;&amp; (Number &gt; 0)">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[Index / 16384][Index % 16384]))->AnsiName}_{Number-1}</DisplayString>
    <DisplayString Condition="Index &lt; 2097152">{((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[Index / 16384][Index % 16384]))->AnsiName}</DisplayString>
    <StringView Condition="Index &lt; 2097152">((FNameEntry*)(((FNameEntry***)GFNameTableForDebuggerVisualizers_MT)[Index / 16384][Index % 16384]))->AnsiName</StringView>
  </Type>

  <!-- FStatMessage visualizer @see Stats2.h -->
  <Type Name="FStatMessage">
    <!--ST_None=1-->
    <DisplayString Condition="((NameAndInfo.NameAndInfo.Number >> 9)&amp;0x7) == 1" >{{NoneType NameAndInfo={NameAndInfo.NameAndInfo}}}</DisplayString>
    <!--ST_int64=2-->
    <DisplayString Condition="((NameAndInfo.NameAndInfo.Number >> 9)&amp;0x7) == 2" >{{Int64={DebugStatData.Cycles},C={DebugStatData.CCAndDuration[0]},D={DebugStatData.CCAndDuration[1]} NameAndInfo={NameAndInfo.NameAndInfo}}}</DisplayString>
    <!--ST_double=3-->
    <DisplayString Condition="((NameAndInfo.NameAndInfo.Number >> 9)&amp;0x7) == 3" >{{Float={DebugStatData.Float} NameAndInfo={NameAndInfo.NameAndInfo}}}</DisplayString>
    <!--ST_FName=4-->
    <!--ST_Ptr=5-->
    <DisplayString Condition="((NameAndInfo.NameAndInfo.Number >> 9)&amp;0x7) == 5" >{{Ptr={DebugStatData.Ptr} NameAndInfo={NameAndInfo.NameAndInfo}}}</DisplayString>
  </Type>

  <Type Name="FVector_NetQuantize">
    <DisplayString>{{X={X} Y={Y} Z={Z}}</DisplayString>
  </Type>

  <Type Name="FVector_NetQuantize10">
    <DisplayString>{{X={X} Y={Y} Z={Z}}</DisplayString>
  </Type>

  <Type Name="FVector_NetQuantize100">
    <DisplayString>{{X={X} Y={Y} Z={Z}}</DisplayString>
  </Type>

  <Type Name="FVector_NetQuantizeNormal">
    <DisplayString>{{X={X} Y={Y} Z={Z}}</DisplayString>
  </Type>

  <!-- TEnumAsByte visualizer -->
  <Type Name="TEnumAsByte&lt;*&gt;">
    <DisplayString>{($T1)Value}</DisplayString>
  </Type>

  <!-- UObjectBase visualizer -->
  <Type Name="UObjectBase">
    <DisplayString>(Name={Name}, Outer={Outer})</DisplayString>
  </Type>

  <!-- TArray<*,TFixedAllocator<*> > visualizer -->
  <Type Name="TArray&lt;*,TFixedAllocator&lt;*&gt;&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems Condition="ArrayNum &lt;= ArrayMax">
        <Size>ArrayNum</Size>
        <ValuePointer>($T1*)AllocatorInstance.InlineData</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TArray<*,TInlineAllocator<*,*> > visualizer -->
  <Type Name="TArray&lt;*,TInlineAllocator&lt;*,*&gt;&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems Condition="ArrayNum &lt;= ArrayMax">
        <Size>ArrayNum</Size>
        <ValuePointer Condition="AllocatorInstance.SecondaryData.Data == 0">($T1*)AllocatorInstance.InlineData</ValuePointer>
        <ValuePointer Condition="AllocatorInstance.SecondaryData.Data != 0">($T1*)AllocatorInstance.SecondaryData.Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TArray visualizer -->
  <Type Name="TArray&lt;*,*&gt;">
    <DisplayString Condition="ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &lt; ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="ArrayMax &gt;= ArrayNum">Num={ArrayNum}</DisplayString>
    <Expand>
      <ArrayItems Condition="ArrayNum &lt;= ArrayMax">
        <Size>ArrayNum</Size>
        <ValuePointer>(::$T1*)AllocatorInstance.Data</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <!-- TIndirectArray visualizer -->
  <Type Name="TIndirectArray&lt;*,*&gt;">
    <DisplayString Condition="Array.ArrayNum == 0">Empty</DisplayString>
    <DisplayString Condition="Array.ArrayNum &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="Array.ArrayMax &lt; Array.ArrayNum">Invalid</DisplayString>
    <DisplayString Condition="Array.ArrayMax &gt;= Array.ArrayNum">Num={Array.ArrayNum}</DisplayString>
    <Expand>
      <IndexListItems Condition="Array.ArrayNum &lt;= Array.ArrayMax">
        <Size>Array.ArrayNum</Size>
        <ValueNode>*(($T1**)Array.AllocatorInstance.Data)[$i]</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- TChunkedArray visualizer -->
  <Type Name="TChunkedArray&lt;*,*&gt;">
    <DisplayString Condition="NumElements == 0">Empty</DisplayString>
    <DisplayString Condition="NumElements &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="NumElements &gt; 0">NumElements={NumElements}, NumChunks={Chunks.Array.ArrayNum}, {NumElementsPerChunk}</DisplayString>

    <Expand>
      <IndexListItems Condition="NumElements &gt; 0">
        <Size>NumElements</Size>
        <ValueNode>
          *(
          *(
          ($T1**)Chunks.Array.AllocatorInstance.Data + ($i / NumElementsPerChunk)
          ) + ($i % NumElementsPerChunk)
          )
        </ValueNode>
      </IndexListItems>
    </Expand>
  </Type>


  <!-- TSparseArray visualizer -->
  <Type Name="TSparseArray&lt;*,*&gt;">
    <DisplayString Condition="(Data.ArrayNum - NumFreeIndices) &lt;= 0">Empty</DisplayString>
    <DisplayString Condition="Data.ArrayNum &lt;= Data.ArrayMax">Num={Data.ArrayNum - NumFreeIndices}</DisplayString>
    <Expand>
      <IndexListItems Condition="Data.ArrayNum &gt; 0 &amp;&amp; Data.ArrayNum &lt;= Data.ArrayMax">
        <Size>Data.ArrayNum</Size>
        <ValueNode Condition="(AllocationFlags.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocationFlags.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) != 0">($T1*)Data.AllocatorInstance.Data + $i</ValueNode>
        <ValueNode Condition="(AllocationFlags.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocationFlags.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) != 0">($T1*)Data.AllocatorInstance.Data + $i</ValueNode>
        <ValueNode Condition="(AllocationFlags.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocationFlags.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
        <ValueNode Condition="(AllocationFlags.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocationFlags.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- TBitArray visualizer -->
  <Type Name="TBitArray&lt;*&gt;">
    <DisplayString Condition="NumBits == 0">Empty</DisplayString>
    <DisplayString Condition="NumBits &lt; 0">Invalid</DisplayString>
    <DisplayString Condition="NumBits &gt; 0">NumBits={NumBits}, MaxBits={MaxBits}</DisplayString>
    <Expand>
      <IndexListItems Condition="NumBits &gt; 0">
        <Size>NumBits</Size>
        <ValueNode Condition="(AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocatorInstance.SecondaryData.Data    )[$i/32]&gt;&gt;$i &amp; 1) != 0">1</ValueNode>
        <ValueNode Condition="(AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocatorInstance.InlineData            )[$i/32]&gt;&gt;$i &amp; 1) != 0">1</ValueNode>
        <ValueNode Condition="(AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocatorInstance.SecondaryData.Data    )[$i/32]&gt;&gt;$i &amp; 1) == 0">0</ValueNode>
        <ValueNode Condition="(AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(AllocatorInstance.InlineData            )[$i/32]&gt;&gt;$i &amp; 1) == 0">0</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- TPair visualizer -->
  <Type Name="TPair&lt;*,*&gt;">
    <DisplayString>({Key}, {Value})</DisplayString>
  </Type>

  <!-- TSharedPtr visualizer -->
  <Type Name="TSharedPtr&lt;*,*&gt;">
    <DisplayString Condition="Object == 0">Null</DisplayString>
    <DisplayString Condition="Object != 0">Ptr={(void*)Object}, SharedRefs={SharedReferenceCount.ReferenceController->SharedReferenceCount}, WeakRefs={SharedReferenceCount.ReferenceController->WeakReferenceCount}, Object={*Object}</DisplayString>
    <Expand>
      <Item Condition="Object != 0" Name="[SharedReferenceCount]">SharedReferenceCount.ReferenceController->SharedReferenceCount</Item>
      <Item Condition="Object != 0" Name="[WeakReferenceCount]">SharedReferenceCount.ReferenceController->WeakReferenceCount</Item>
      <Item Condition="Object != 0" Name="[Ptr]">(void*)Object</Item>
      <ExpandedItem Condition="Object != 0">*Object</ExpandedItem>
    </Expand>
  </Type>

  <!-- TSharedRef visualizer -->
  <Type Name="TSharedRef&lt;*,*&gt;">
    <DisplayString Condition="Object != 0">Ptr={(void*)Object}, SharedRefs={SharedReferenceCount.ReferenceController->SharedReferenceCount}, WeakRefs={SharedReferenceCount.ReferenceController->WeakReferenceCount}, Object={*Object}</DisplayString>
    <Expand>
      <Item Condition="Object != 0" Name="[SharedReferenceCount]">SharedReferenceCount.ReferenceController->SharedReferenceCount</Item>
      <Item Condition="Object != 0" Name="[WeakReferenceCount]">SharedReferenceCount.ReferenceController->WeakReferenceCount</Item>
      <Item Condition="Object != 0" Name="[Ptr]">(void*)Object</Item>
      <ExpandedItem Condition="Object != 0">*Object</ExpandedItem>
    </Expand>
  </Type>

  <!-- TWeakPtr visualizer -->
  <Type Name="TWeakPtr&lt;*,*&gt;">
    <DisplayString Condition="Object == 0">Null</DisplayString>
    <DisplayString Condition="WeakReferenceCount.ReferenceController->SharedReferenceCount == 0">Object has been destroyed</DisplayString>
    <DisplayString Condition="Object != 0">Ptr={(void*)Object}, SharedRefs={WeakReferenceCount.ReferenceController->SharedReferenceCount}, WeakRefs={WeakReferenceCount.ReferenceController->WeakReferenceCount}, Object={*Object}</DisplayString>
    <Expand>
      <Item Condition="Object != 0" Name="[SharedReferenceCount]">WeakReferenceCount.ReferenceController->SharedReferenceCount</Item>
      <Item Condition="Object != 0" Name="[WeakReferenceCount]">WeakReferenceCount.ReferenceController->WeakReferenceCount</Item>
      <Item Condition="Object != 0 &amp;&amp; WeakReferenceCount.ReferenceController->SharedReferenceCount > 0" Name="[Ptr]">(void*)Object</Item>
      <ExpandedItem Condition="Object != 0 &amp;&amp; WeakReferenceCount.ReferenceController->SharedReferenceCount > 0">*Object</ExpandedItem>
    </Expand>
  </Type>


  <!-- TMapBase visualizer -->
  <Type Name="TMapBase&lt;*,*,*,*,*&gt;">
    <DisplayString Condition="Pairs.Elements.Data.ArrayNum - Pairs.Elements.NumFreeIndices &lt;= 0">Empty</DisplayString>
    <DisplayString Condition="Pairs.Elements.Data.ArrayNum &lt;= Pairs.Elements.Data.ArrayMax" >Num={Pairs.Elements.Data.ArrayNum - Pairs.Elements.NumFreeIndices}</DisplayString>
    <Expand>
      <IndexListItems Condition="Pairs.Elements.Data.ArrayNum - Pairs.Elements.NumFreeIndices &gt; 0 &amp;&amp; Pairs.Elements.Data.ArrayNum &lt;= Pairs.Elements.Data.ArrayMax">
        <Size>Pairs.Elements.Data.ArrayNum</Size>
        <ValueNode Condition="(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) != 0">((TSetElement&lt;TPair&lt;$T1,$T2&gt; &gt; *)Pairs.Elements.Data.AllocatorInstance.Data)[$i].Value</ValueNode>
        <ValueNode Condition="(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Pairs.Elements.AllocationFlags.AllocatorInstance.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) != 0">((TSetElement&lt;TPair&lt;$T1,$T2&gt; &gt; *)Pairs.Elements.Data.AllocatorInstance.Data)[$i].Value</ValueNode>
        <ValueNode Condition="(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
        <ValueNode Condition="(Pairs.Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Pairs.Elements.AllocationFlags.AllocatorInstance.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- TSet visualizer -->
  <Type Name="TSet&lt;*,*,*&gt;">
    <DisplayString Condition="Elements.Data.ArrayNum - Elements.NumFreeIndices &lt;= 0">Empty</DisplayString>
    <DisplayString Condition="Elements.Data.ArrayNum &lt;= Elements.Data.ArrayMax">Num={Elements.Data.ArrayNum - Elements.NumFreeIndices}</DisplayString>
    <Expand>
      <IndexListItems Condition="Elements.Data.ArrayNum - Elements.NumFreeIndices &gt; 0 &amp;&amp; Elements.Data.ArrayNum &lt;= Elements.Data.ArrayMax">
        <Size>Elements.Data.ArrayNum</Size>
        <ValueNode Condition="(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) != 0">((TSetElement &lt;$T1&gt; *)Elements.Data.AllocatorInstance.Data)[$i].Value</ValueNode>
        <ValueNode Condition="(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Elements.AllocationFlags.AllocatorInstance.InlineData        )[$i/32]&gt;&gt;$i &amp; 1) != 0">((TSetElement &lt;$T1&gt; *)Elements.Data.AllocatorInstance.Data)[$i].Value</ValueNode>
        <ValueNode Condition="(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data != 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data)[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
        <ValueNode Condition="(Elements.AllocationFlags.AllocatorInstance.SecondaryData.Data == 0) &amp;&amp; (reinterpret_cast&lt;uint32*&gt;(Elements.AllocationFlags.AllocatorInstance.InlineData)[$i/32]&gt;&gt;$i &amp; 1) == 0">Invalid</ValueNode>
      </IndexListItems>
    </Expand>
  </Type>

  <!-- FWeakObjectPtr|TWeakObjectPtr<*>|TAutoWeakObjectPtr<*> visualizer -->
  <Type Name="FWeakObjectPtr">
    <DisplayString Condition="ObjectSerialNumber &lt; 1">NULL</DisplayString>
    <DisplayString Condition="*((*(*GSerialNumberBlocksForDebugVisualizers + (ObjectIndex / 0x4000))) + (ObjectIndex % 0x4000)) != ObjectSerialNumber">STALE</DisplayString>
    <DisplayString>{GObjectArrayForDebugVisualizers[ObjectIndex / 0x4000][ObjectIndex % 0x4000]}</DisplayString>
    <Expand>
      <ExpandedItem>GObjectArrayForDebugVisualizers[ObjectIndex / 0x4000][ObjectIndex % 0x4000]</ExpandedItem>
    </Expand>
  </Type>

  <Type Name="TWeakObjectPtr&lt;*&gt;">
    <DisplayString Condition="ObjectSerialNumber &lt; 1">NULL</DisplayString>
    <DisplayString Condition="*((*(*GSerialNumberBlocksForDebugVisualizers + (ObjectIndex / 0x4000))) + (ObjectIndex % 0x4000)) != ObjectSerialNumber">STALE</DisplayString>
    <DisplayString>{GObjectArrayForDebugVisualizers[ObjectIndex / 0x4000][ObjectIndex % 0x4000]}</DisplayString>
    <Expand>
      <ExpandedItem>GObjectArrayForDebugVisualizers[ObjectIndex / 0x4000][ObjectIndex % 0x4000]</ExpandedItem>
    </Expand>
  </Type>

  <Type Name="TAutoWeakObjectPtr&lt;*&gt;">
    <DisplayString Condition="ObjectSerialNumber &lt; 1">NULL</DisplayString>
    <DisplayString Condition="*((*(*GSerialNumberBlocksForDebugVisualizers + (ObjectIndex / 0x4000))) + (ObjectIndex % 0x4000)) != ObjectSerialNumber">STALE</DisplayString>
    <DisplayString>{GObjectArrayForDebugVisualizers[ObjectIndex / 0x4000][ObjectIndex % 0x4000]}</DisplayString>
    <Expand>
      <ExpandedItem>GObjectArrayForDebugVisualizers[ObjectIndex / 0x4000][ObjectIndex % 0x4000]</ExpandedItem>
    </Expand>
  </Type>

  <!-- FSubobjectPtr|TSubobjectPtr visualizer -->
  <Type Name="FSubobjectPtr">
    <DisplayString>{Object}</DisplayString>
  </Type>
  <Type Name="TSubobjectPtr&lt;*&gt;">
    <DisplayString>{Object}</DisplayString>
  </Type>

  <!-- TOptional visualizer -->
  <Type Name="TOptional&lt;*&gt;">
    <DisplayString Condition="!bIsSet">Unset</DisplayString>
    <DisplayString Condition="bIsSet">Set: {{{*($T1*)&amp;Value}}}</DisplayString>
    <Expand>
      <ExpandedItem Condition="bIsSet">*($T1*)&amp;Value</ExpandedItem>
    </Expand>
  </Type>

  <!-- TFunction visualizer -->
  <Type Name="UE4Function_Private::TDebugHelper&lt;*&gt;">
    <DisplayString>{*Ptr}</DisplayString>
    <Expand>
      <ExpandedItem>*Ptr</ExpandedItem>
    </Expand>
  </Type>
  <Type Name="TFunctionRef&lt;*&gt;">
    <DisplayString Condition="Ptr">{DebugPtrStorage}</DisplayString>
    <DisplayString Condition="!Ptr">Unset</DisplayString>
    <Expand>
      <ExpandedItem Condition="Ptr">DebugPtrStorage</ExpandedItem>
    </Expand>
  </Type>

</AutoVisualizer>
PS4UE4.natvis

下面的sh执行文件可以用于一键执行:

#!/bin/bash

cp_args="-v --preserve=timestamps"
cp $cp_args UE{3,4}.natvis    "$USERPROFILE/Documents/Visual Studio 2012/Visualizers"
cp $cp_args UE{3,4}.natvis    "$USERPROFILE/Documents/Visual Studio 2013/Visualizers"
cp $cp_args PS4UE{3,4}.natvis "$USERPROFILE/Documents/SCE/orbis-debugger"

注意在以上几个文件中更改自己所使用的VS版本号使之与本机VS版本一致; 

 

posted on 2017-06-23 16:17  DeanWang  阅读(692)  评论(0编辑  收藏  举报