├── .gitignore ├── Config ├── DefaultCtrlLevelReferenceViewer.ini ├── DefaultCtrlReferenceVisualizer.ini └── FilterPlugin.ini ├── Content ├── Sample_Maps │ ├── CRV_Actor_Tests.umap │ ├── CRV_Component_Tests.umap │ ├── CRV_DefaultEnvironment.umap │ ├── CRV_Nesting_Tests.umap │ ├── CRV_Test_Map.umap │ ├── CRV_Test_Map2.umap │ ├── CRV_Test_Map_Trivial.umap │ └── SampleAssets │ │ ├── AC_CRV_TestComponent.uasset │ │ ├── BP_CRV_SampleFloor.uasset │ │ ├── BP_CRV_TestActor.uasset │ │ ├── BP_CRV_TestActorNative.uasset │ │ ├── BP_CRV_TestActorNative_WithChildActor.uasset │ │ ├── CRV_Cube_AFC9EB59.uasset │ │ ├── MI_CRV_FlatColor_27.uasset │ │ ├── MI_CRV_PrototypeGrid_Brown.uasset │ │ ├── MM_CRV_FlatColor_01.uasset │ │ ├── M_CRV_PrototypeGrid.uasset │ │ └── SM_CRV_SampleFloor.uasset └── __ExternalActors__ │ └── Sample_Maps │ ├── CRV_Actor_Tests │ ├── 0 │ │ ├── 1K │ │ │ └── HB7322RWV6H54QYB4HCZML.uasset │ │ ├── AP │ │ │ └── 7T54NFZASQDZY449X0XBX7.uasset │ │ ├── EK │ │ │ └── 4Z9GCU8ZAYESN0RN4P43VY.uasset │ │ ├── F5 │ │ │ └── IJ4GPCBY4DN6SXLKZZ68QN.uasset │ │ ├── IP │ │ │ └── 2NJAQ7UU1N0VY6P5ATDEMW.uasset │ │ └── M9 │ │ │ └── V2T6VEVXVLR462PTCGTFXC.uasset │ ├── 1 │ │ ├── 10 │ │ │ └── M2PXPYCROZE3YO4S31JGG2.uasset │ │ ├── 37 │ │ │ └── L77KZMYDO5ZD610B2WMV7M.uasset │ │ ├── BQ │ │ │ └── JOBAB3FMHCAMKDNAM94MXK.uasset │ │ └── WD │ │ │ └── 4NYNPX5IU51SKEEYZ751BP.uasset │ ├── 2 │ │ ├── 5R │ │ │ └── RX8WANBIUQ7YW6AH271F37.uasset │ │ ├── C5 │ │ │ └── W7FZGWSC43AVEJ5NEKHRI6.uasset │ │ ├── G4 │ │ │ └── J1IK0MWCMIVUUEWTG9D36C.uasset │ │ ├── QT │ │ │ └── CNZGTV0AGA01PCBFD43OS1.uasset │ │ └── WM │ │ │ └── LLNFQ8TKFR4IDFKKGMC7TC.uasset │ ├── 3 │ │ ├── 7R │ │ │ └── FF5UHJMXQUGRAW02CST87B.uasset │ │ └── PW │ │ │ └── B1RCFH5FN8IZC1YNZMHFFR.uasset │ ├── 4 │ │ └── 0C │ │ │ └── WNLNEKE3IQMYI70V4ZQETG.uasset │ ├── 5 │ │ ├── 29 │ │ │ └── YWNMNOP8HKMV5CJ5OB03F5.uasset │ │ └── MF │ │ │ └── BLQVG0K3DKM5ORBLXT8EIK.uasset │ ├── 6 │ │ └── P7 │ │ │ └── D2ZFA68TZMVQM792Y9G9Z7.uasset │ ├── 7 │ │ ├── 4L │ │ │ └── LBJX8X6CHE1RXPTY4K5AW4.uasset │ │ └── L6 │ │ │ └── RG5RWZTENLY8PS0IV0CXU5.uasset │ ├── 8 │ │ ├── 12 │ │ │ └── WHNSXWZ5OY0DDTP46RWLFG.uasset │ │ ├── 8U │ │ │ └── NZINKCEO85B41MHXAU1KHY.uasset │ │ ├── EW │ │ │ └── YQQMSZ3KPA89ATOAATP0NL.uasset │ │ └── MA │ │ │ └── JUOT1N7D0YTC58XAXOOGPB.uasset │ ├── 9 │ │ ├── 16 │ │ │ └── VE328OCJCYP5ITU159L5RB.uasset │ │ ├── 4F │ │ │ └── TLCUWP8ZI67T4V7WATEJPS.uasset │ │ ├── 5N │ │ │ └── JYZNTUY3ZCO14CPBZ0OYJB.uasset │ │ ├── OI │ │ │ └── SUWHJCC0PEC1C9I4X35TVY.uasset │ │ └── R1 │ │ │ └── ANV7VDB5SNSBQ0NZ6V6VIA.uasset │ ├── A │ │ ├── 3S │ │ │ └── NCNKDAW1MI1WJQSOEB7GVL.uasset │ │ └── 7J │ │ │ └── QL2Q70RZ1AD8ECCJ0DQOK0.uasset │ ├── B │ │ ├── 7O │ │ │ └── JVBJFPNP5YRV20VEL68QFD.uasset │ │ └── KQ │ │ │ └── CS70CFMJCXGP2HTJ43M7ID.uasset │ ├── C │ │ ├── 0Z │ │ │ └── BSEIYPE7Z7OVPWPCNT4CVR.uasset │ │ ├── 5W │ │ │ └── XKL6CWJ88V2MZQ1HTIL74K.uasset │ │ └── YQ │ │ │ └── TRP0QNVPI3X5RO9ITMYXKX.uasset │ ├── D │ │ ├── 6Y │ │ │ └── Y7CSU0157X4964YVD50LPM.uasset │ │ ├── KC │ │ │ └── PS6MQADHANF9CA5YB7HMSG.uasset │ │ ├── P2 │ │ │ └── YJPXDZPY0HLQJF114MC0FP.uasset │ │ ├── SH │ │ │ └── GXPSUV9MC3C7EUGO0CF2W9.uasset │ │ ├── VE │ │ │ └── OC0KL3GX9OJIYAN7K1V6R7.uasset │ │ └── WY │ │ │ └── F8A5KKZR3ZOX1778TXOGHP.uasset │ └── E │ │ ├── 2X │ │ └── CX5YCZ2GWG5RT20BY3W2NB.uasset │ │ ├── AZ │ │ └── JQ8V89VQ2LPX29RB7SQ415.uasset │ │ └── CW │ │ └── 7BEMYVPZ8FD7DX78M81AT9.uasset │ ├── CRV_Component_Tests │ ├── 0 │ │ └── 10 │ │ │ └── 8GQUCZOZEBNF8W6V5AVDWP.uasset │ ├── 1 │ │ ├── GO │ │ │ └── NTYM67SQHKD5HDM8NOWROU.uasset │ │ └── IT │ │ │ └── 6ROL3W3C5I3V4PYR32VIVT.uasset │ ├── 2 │ │ ├── JQ │ │ │ └── JHIK4YLTY022M6KKL4P2ES.uasset │ │ └── NG │ │ │ └── YK3C52K50GBJCO20BLXD6R.uasset │ ├── 3 │ │ ├── CX │ │ │ └── 540X88PL9D2SOC988GT14V.uasset │ │ ├── FH │ │ │ └── IVLO0QK593N8U1WOS059DE.uasset │ │ ├── FU │ │ │ └── S30EG04809ZFTYRQEQFT86.uasset │ │ ├── LC │ │ │ └── P48RYQ0RNIH18OWZARWW8R.uasset │ │ └── M9 │ │ │ └── J20P132W10EWMN71JLHZAA.uasset │ ├── 4 │ │ ├── 4W │ │ │ └── NOWDTQ1GW65BKN9L8U1FSB.uasset │ │ └── QU │ │ │ └── CEWHMSSTS899VWORCU54JY.uasset │ ├── 5 │ │ ├── 3N │ │ │ └── R92E55LZ77L444PAA1DU46.uasset │ │ └── KU │ │ │ └── 5Q0MSYI1QUSBIRH5NH8HOZ.uasset │ ├── 8 │ │ └── RF │ │ │ └── RSLZF7D7B2SZJVWH6YAP3H.uasset │ ├── 9 │ │ └── 39 │ │ │ └── 8LWDNM01R0TZR6M9Z3ELLO.uasset │ ├── C │ │ ├── HL │ │ │ └── F0ZZ7I3EHBGJ9BPID7CK3D.uasset │ │ └── Y0 │ │ │ └── 7YR3UWQSJLDWINQ5IN867E.uasset │ ├── D │ │ ├── 1D │ │ │ └── 5ENE0Z6D3N3T9EICYG92JA.uasset │ │ ├── U7 │ │ │ └── LW6FQYMUSQULU477OGB9EC.uasset │ │ └── X6 │ │ │ └── Z70B3JZYZL3NXPFU97TP8J.uasset │ └── E │ │ ├── 7F │ │ └── NVM740XZ0NWSIQ3Q7AFV3L.uasset │ │ ├── H0 │ │ └── GLR1CWABNKUMJSHHS5IZUW.uasset │ │ └── J3 │ │ └── 40G0U5I509TXV6FLYIFVGY.uasset │ ├── CRV_DefaultEnvironment │ ├── 1 │ │ └── SQ │ │ │ └── SS0APMSP1BG68MHEDJBEA8.uasset │ ├── 2 │ │ └── RH │ │ │ └── XQ412HIUEAOT1RUGY3P1PI.uasset │ ├── 3 │ │ └── A3 │ │ │ └── C5E15W1R1NGRK3PFP6DZPP.uasset │ └── C │ │ ├── 4O │ │ └── FVQ17H8S1UBHD5JPSBEUJB.uasset │ │ └── HO │ │ └── 3RUQHZ1ZTGI8CGO9HV8WM7.uasset │ └── CRV_Nesting_Tests │ ├── 1 │ └── QO │ │ └── C4A0OV2U50G2BCLNOTN4D7.uasset │ ├── 3 │ └── WP │ │ └── I0BPL983SWH7N5M45UCLWT.uasset │ ├── 4 │ └── 0S │ │ └── K9BSHYULX4J3PIZMCMCJFN.uasset │ ├── 5 │ └── GR │ │ └── L3XI6P8Z3MSWLGIRCTZEKZ.uasset │ ├── 8 │ ├── D8 │ │ └── 0NV4RJDI6JJJH341KZ9UFO.uasset │ └── K8 │ │ └── 9FQ5PNUKL2X2U5X483CHSW.uasset │ ├── 9 │ └── FK │ │ └── LCA3QO39IEVSZ0UM7UW5X9.uasset │ ├── B │ └── NK │ │ └── 4R1TYR48JUSXDQ2LGCHE75.uasset │ ├── C │ ├── 68 │ │ └── D5KDXR6EN0QFLBSLDZ5KEL.uasset │ └── JJ │ │ └── PAGXJ46ZRYWOU6043NCOD5.uasset │ ├── D │ └── 50 │ │ └── OL1PEWTMVIFPFTR85OE2Y8.uasset │ └── E │ ├── 49 │ └── 3H9O8BNIAG64RFVZKI1QSS.uasset │ └── MJ │ └── J8D4BFKTLH3OBFR4FRWYKY.uasset ├── CtrlReferenceVisualizer.uplugin ├── LICENSE.md ├── README.md ├── Resources ├── Icon128.png └── Icon16.png └── Source └── CtrlReferenceVisualizer ├── CtrlReferenceVisualizer.Build.cs ├── Private ├── CrvCommands.cpp ├── CrvComponent.cpp ├── CrvDrawUtils.cpp ├── CrvDrawUtils.h ├── CrvHitProxy.cpp ├── CrvRefCache.cpp ├── CrvRefCache.h ├── CrvRefSearch.cpp ├── CrvSampleFloorBase.h ├── CrvSettings.cpp ├── CrvStyle.cpp ├── CrvTestActorBase.cpp ├── CrvTestActorBase.h ├── CrvUtils.cpp ├── CrvUtils.h ├── CtrlReferenceVisualizer.cpp └── ReferenceVisualizerComponent.cpp └── Public ├── CrvCommands.h ├── CrvHitProxy.h ├── CrvRefSearch.h ├── CrvSettings.h ├── CrvStyle.h ├── CtrlReferenceVisualizer.h └── ReferenceVisualizerComponent.h /.gitignore: -------------------------------------------------------------------------------- 1 | Binaries/ 2 | Intermediate/ 3 | -------------------------------------------------------------------------------- /Config/DefaultCtrlLevelReferenceViewer.ini: -------------------------------------------------------------------------------- 1 | [CoreRedirects] 2 | +ClassRedirects=(OldName="/Script/CtrlReferenceVisualizer.LrvComponent",NewName="/Script/CtrlReferenceVisualizer.ReferenceVisualizerComponent") -------------------------------------------------------------------------------- /Config/DefaultCtrlReferenceVisualizer.ini: -------------------------------------------------------------------------------- 1 | [CoreRedirects] 2 | +EnumRedirects=(OldName="/Script/CtrlReferenceVisualizer.ECrvLineStyle",NewName="/Script/CtrlReferenceVisualizer.ECrvLineType") -------------------------------------------------------------------------------- /Config/FilterPlugin.ini: -------------------------------------------------------------------------------- 1 | [FilterPlugin] 2 | ; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and 3 | ; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. 4 | ; 5 | ; Examples: 6 | ; /README.txt 7 | ; /Extras/... 8 | ; /Binaries/ThirdParty/*.dll 9 | -------------------------------------------------------------------------------- /Content/Sample_Maps/CRV_Actor_Tests.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/CRV_Actor_Tests.umap -------------------------------------------------------------------------------- /Content/Sample_Maps/CRV_Component_Tests.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/CRV_Component_Tests.umap -------------------------------------------------------------------------------- /Content/Sample_Maps/CRV_DefaultEnvironment.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/CRV_DefaultEnvironment.umap -------------------------------------------------------------------------------- /Content/Sample_Maps/CRV_Nesting_Tests.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/CRV_Nesting_Tests.umap -------------------------------------------------------------------------------- /Content/Sample_Maps/CRV_Test_Map.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/CRV_Test_Map.umap -------------------------------------------------------------------------------- /Content/Sample_Maps/CRV_Test_Map2.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/CRV_Test_Map2.umap -------------------------------------------------------------------------------- /Content/Sample_Maps/CRV_Test_Map_Trivial.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/CRV_Test_Map_Trivial.umap -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/AC_CRV_TestComponent.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/AC_CRV_TestComponent.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/BP_CRV_SampleFloor.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/BP_CRV_SampleFloor.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/BP_CRV_TestActor.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/BP_CRV_TestActor.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/BP_CRV_TestActorNative.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/BP_CRV_TestActorNative.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/BP_CRV_TestActorNative_WithChildActor.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/BP_CRV_TestActorNative_WithChildActor.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/CRV_Cube_AFC9EB59.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/CRV_Cube_AFC9EB59.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/MI_CRV_FlatColor_27.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/MI_CRV_FlatColor_27.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/MI_CRV_PrototypeGrid_Brown.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/MI_CRV_PrototypeGrid_Brown.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/MM_CRV_FlatColor_01.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/MM_CRV_FlatColor_01.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/M_CRV_PrototypeGrid.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/M_CRV_PrototypeGrid.uasset -------------------------------------------------------------------------------- /Content/Sample_Maps/SampleAssets/SM_CRV_SampleFloor.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/Sample_Maps/SampleAssets/SM_CRV_SampleFloor.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/1K/HB7322RWV6H54QYB4HCZML.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/1K/HB7322RWV6H54QYB4HCZML.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/AP/7T54NFZASQDZY449X0XBX7.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/AP/7T54NFZASQDZY449X0XBX7.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/EK/4Z9GCU8ZAYESN0RN4P43VY.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/EK/4Z9GCU8ZAYESN0RN4P43VY.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/F5/IJ4GPCBY4DN6SXLKZZ68QN.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/F5/IJ4GPCBY4DN6SXLKZZ68QN.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/IP/2NJAQ7UU1N0VY6P5ATDEMW.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/IP/2NJAQ7UU1N0VY6P5ATDEMW.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/M9/V2T6VEVXVLR462PTCGTFXC.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/0/M9/V2T6VEVXVLR462PTCGTFXC.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/1/10/M2PXPYCROZE3YO4S31JGG2.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/1/10/M2PXPYCROZE3YO4S31JGG2.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/1/37/L77KZMYDO5ZD610B2WMV7M.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/1/37/L77KZMYDO5ZD610B2WMV7M.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/1/BQ/JOBAB3FMHCAMKDNAM94MXK.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/1/BQ/JOBAB3FMHCAMKDNAM94MXK.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/1/WD/4NYNPX5IU51SKEEYZ751BP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/1/WD/4NYNPX5IU51SKEEYZ751BP.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/5R/RX8WANBIUQ7YW6AH271F37.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/5R/RX8WANBIUQ7YW6AH271F37.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/C5/W7FZGWSC43AVEJ5NEKHRI6.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/C5/W7FZGWSC43AVEJ5NEKHRI6.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/G4/J1IK0MWCMIVUUEWTG9D36C.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/G4/J1IK0MWCMIVUUEWTG9D36C.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/QT/CNZGTV0AGA01PCBFD43OS1.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/QT/CNZGTV0AGA01PCBFD43OS1.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/WM/LLNFQ8TKFR4IDFKKGMC7TC.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/2/WM/LLNFQ8TKFR4IDFKKGMC7TC.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/3/7R/FF5UHJMXQUGRAW02CST87B.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/3/7R/FF5UHJMXQUGRAW02CST87B.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/3/PW/B1RCFH5FN8IZC1YNZMHFFR.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/3/PW/B1RCFH5FN8IZC1YNZMHFFR.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/4/0C/WNLNEKE3IQMYI70V4ZQETG.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/4/0C/WNLNEKE3IQMYI70V4ZQETG.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/5/29/YWNMNOP8HKMV5CJ5OB03F5.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/5/29/YWNMNOP8HKMV5CJ5OB03F5.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/5/MF/BLQVG0K3DKM5ORBLXT8EIK.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/5/MF/BLQVG0K3DKM5ORBLXT8EIK.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/6/P7/D2ZFA68TZMVQM792Y9G9Z7.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/6/P7/D2ZFA68TZMVQM792Y9G9Z7.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/7/4L/LBJX8X6CHE1RXPTY4K5AW4.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/7/4L/LBJX8X6CHE1RXPTY4K5AW4.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/7/L6/RG5RWZTENLY8PS0IV0CXU5.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/7/L6/RG5RWZTENLY8PS0IV0CXU5.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/8/12/WHNSXWZ5OY0DDTP46RWLFG.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/8/12/WHNSXWZ5OY0DDTP46RWLFG.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/8/8U/NZINKCEO85B41MHXAU1KHY.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/8/8U/NZINKCEO85B41MHXAU1KHY.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/8/EW/YQQMSZ3KPA89ATOAATP0NL.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/8/EW/YQQMSZ3KPA89ATOAATP0NL.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/8/MA/JUOT1N7D0YTC58XAXOOGPB.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/8/MA/JUOT1N7D0YTC58XAXOOGPB.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/16/VE328OCJCYP5ITU159L5RB.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/16/VE328OCJCYP5ITU159L5RB.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/4F/TLCUWP8ZI67T4V7WATEJPS.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/4F/TLCUWP8ZI67T4V7WATEJPS.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/5N/JYZNTUY3ZCO14CPBZ0OYJB.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/5N/JYZNTUY3ZCO14CPBZ0OYJB.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/OI/SUWHJCC0PEC1C9I4X35TVY.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/OI/SUWHJCC0PEC1C9I4X35TVY.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/R1/ANV7VDB5SNSBQ0NZ6V6VIA.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/9/R1/ANV7VDB5SNSBQ0NZ6V6VIA.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/A/3S/NCNKDAW1MI1WJQSOEB7GVL.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/A/3S/NCNKDAW1MI1WJQSOEB7GVL.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/A/7J/QL2Q70RZ1AD8ECCJ0DQOK0.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/A/7J/QL2Q70RZ1AD8ECCJ0DQOK0.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/B/7O/JVBJFPNP5YRV20VEL68QFD.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/B/7O/JVBJFPNP5YRV20VEL68QFD.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/B/KQ/CS70CFMJCXGP2HTJ43M7ID.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/B/KQ/CS70CFMJCXGP2HTJ43M7ID.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/C/0Z/BSEIYPE7Z7OVPWPCNT4CVR.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/C/0Z/BSEIYPE7Z7OVPWPCNT4CVR.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/C/5W/XKL6CWJ88V2MZQ1HTIL74K.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/C/5W/XKL6CWJ88V2MZQ1HTIL74K.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/C/YQ/TRP0QNVPI3X5RO9ITMYXKX.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/C/YQ/TRP0QNVPI3X5RO9ITMYXKX.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/6Y/Y7CSU0157X4964YVD50LPM.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/6Y/Y7CSU0157X4964YVD50LPM.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/KC/PS6MQADHANF9CA5YB7HMSG.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/KC/PS6MQADHANF9CA5YB7HMSG.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/P2/YJPXDZPY0HLQJF114MC0FP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/P2/YJPXDZPY0HLQJF114MC0FP.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/SH/GXPSUV9MC3C7EUGO0CF2W9.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/SH/GXPSUV9MC3C7EUGO0CF2W9.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/VE/OC0KL3GX9OJIYAN7K1V6R7.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/VE/OC0KL3GX9OJIYAN7K1V6R7.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/WY/F8A5KKZR3ZOX1778TXOGHP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/D/WY/F8A5KKZR3ZOX1778TXOGHP.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/E/2X/CX5YCZ2GWG5RT20BY3W2NB.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/E/2X/CX5YCZ2GWG5RT20BY3W2NB.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/E/AZ/JQ8V89VQ2LPX29RB7SQ415.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/E/AZ/JQ8V89VQ2LPX29RB7SQ415.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/E/CW/7BEMYVPZ8FD7DX78M81AT9.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Actor_Tests/E/CW/7BEMYVPZ8FD7DX78M81AT9.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/0/10/8GQUCZOZEBNF8W6V5AVDWP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/0/10/8GQUCZOZEBNF8W6V5AVDWP.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/1/GO/NTYM67SQHKD5HDM8NOWROU.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/1/GO/NTYM67SQHKD5HDM8NOWROU.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/1/IT/6ROL3W3C5I3V4PYR32VIVT.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/1/IT/6ROL3W3C5I3V4PYR32VIVT.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/2/JQ/JHIK4YLTY022M6KKL4P2ES.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/2/JQ/JHIK4YLTY022M6KKL4P2ES.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/2/NG/YK3C52K50GBJCO20BLXD6R.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/2/NG/YK3C52K50GBJCO20BLXD6R.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/CX/540X88PL9D2SOC988GT14V.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/CX/540X88PL9D2SOC988GT14V.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/FH/IVLO0QK593N8U1WOS059DE.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/FH/IVLO0QK593N8U1WOS059DE.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/FU/S30EG04809ZFTYRQEQFT86.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/FU/S30EG04809ZFTYRQEQFT86.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/LC/P48RYQ0RNIH18OWZARWW8R.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/LC/P48RYQ0RNIH18OWZARWW8R.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/M9/J20P132W10EWMN71JLHZAA.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/3/M9/J20P132W10EWMN71JLHZAA.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/4/4W/NOWDTQ1GW65BKN9L8U1FSB.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/4/4W/NOWDTQ1GW65BKN9L8U1FSB.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/4/QU/CEWHMSSTS899VWORCU54JY.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/4/QU/CEWHMSSTS899VWORCU54JY.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/5/3N/R92E55LZ77L444PAA1DU46.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/5/3N/R92E55LZ77L444PAA1DU46.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/5/KU/5Q0MSYI1QUSBIRH5NH8HOZ.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/5/KU/5Q0MSYI1QUSBIRH5NH8HOZ.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/8/RF/RSLZF7D7B2SZJVWH6YAP3H.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/8/RF/RSLZF7D7B2SZJVWH6YAP3H.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/9/39/8LWDNM01R0TZR6M9Z3ELLO.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/9/39/8LWDNM01R0TZR6M9Z3ELLO.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/C/HL/F0ZZ7I3EHBGJ9BPID7CK3D.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/C/HL/F0ZZ7I3EHBGJ9BPID7CK3D.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/C/Y0/7YR3UWQSJLDWINQ5IN867E.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/C/Y0/7YR3UWQSJLDWINQ5IN867E.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/D/1D/5ENE0Z6D3N3T9EICYG92JA.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/D/1D/5ENE0Z6D3N3T9EICYG92JA.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/D/U7/LW6FQYMUSQULU477OGB9EC.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/D/U7/LW6FQYMUSQULU477OGB9EC.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/D/X6/Z70B3JZYZL3NXPFU97TP8J.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/D/X6/Z70B3JZYZL3NXPFU97TP8J.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/E/7F/NVM740XZ0NWSIQ3Q7AFV3L.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/E/7F/NVM740XZ0NWSIQ3Q7AFV3L.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/E/H0/GLR1CWABNKUMJSHHS5IZUW.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/E/H0/GLR1CWABNKUMJSHHS5IZUW.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/E/J3/40G0U5I509TXV6FLYIFVGY.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Component_Tests/E/J3/40G0U5I509TXV6FLYIFVGY.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/1/SQ/SS0APMSP1BG68MHEDJBEA8.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/1/SQ/SS0APMSP1BG68MHEDJBEA8.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/2/RH/XQ412HIUEAOT1RUGY3P1PI.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/2/RH/XQ412HIUEAOT1RUGY3P1PI.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/3/A3/C5E15W1R1NGRK3PFP6DZPP.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/3/A3/C5E15W1R1NGRK3PFP6DZPP.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/C/4O/FVQ17H8S1UBHD5JPSBEUJB.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/C/4O/FVQ17H8S1UBHD5JPSBEUJB.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/C/HO/3RUQHZ1ZTGI8CGO9HV8WM7.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_DefaultEnvironment/C/HO/3RUQHZ1ZTGI8CGO9HV8WM7.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/1/QO/C4A0OV2U50G2BCLNOTN4D7.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/1/QO/C4A0OV2U50G2BCLNOTN4D7.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/3/WP/I0BPL983SWH7N5M45UCLWT.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/3/WP/I0BPL983SWH7N5M45UCLWT.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/4/0S/K9BSHYULX4J3PIZMCMCJFN.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/4/0S/K9BSHYULX4J3PIZMCMCJFN.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/5/GR/L3XI6P8Z3MSWLGIRCTZEKZ.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/5/GR/L3XI6P8Z3MSWLGIRCTZEKZ.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/8/D8/0NV4RJDI6JJJH341KZ9UFO.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/8/D8/0NV4RJDI6JJJH341KZ9UFO.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/8/K8/9FQ5PNUKL2X2U5X483CHSW.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/8/K8/9FQ5PNUKL2X2U5X483CHSW.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/9/FK/LCA3QO39IEVSZ0UM7UW5X9.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/9/FK/LCA3QO39IEVSZ0UM7UW5X9.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/B/NK/4R1TYR48JUSXDQ2LGCHE75.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/B/NK/4R1TYR48JUSXDQ2LGCHE75.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/C/68/D5KDXR6EN0QFLBSLDZ5KEL.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/C/68/D5KDXR6EN0QFLBSLDZ5KEL.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/C/JJ/PAGXJ46ZRYWOU6043NCOD5.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/C/JJ/PAGXJ46ZRYWOU6043NCOD5.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/D/50/OL1PEWTMVIFPFTR85OE2Y8.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/D/50/OL1PEWTMVIFPFTR85OE2Y8.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/E/49/3H9O8BNIAG64RFVZKI1QSS.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/E/49/3H9O8BNIAG64RFVZKI1QSS.uasset -------------------------------------------------------------------------------- /Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/E/MJ/J8D4BFKTLH3OBFR4FRWYKY.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Content/__ExternalActors__/Sample_Maps/CRV_Nesting_Tests/E/MJ/J8D4BFKTLH3OBFR4FRWYKY.uasset -------------------------------------------------------------------------------- /CtrlReferenceVisualizer.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0", 5 | "FriendlyName": "Ctrl Reference Visualizer", 6 | "Description": "Visualize references to actors & components in a level", 7 | "Category": "Other", 8 | "CreatedBy": "NTY.studio", 9 | "CreatedByURL": "https://nty.studio", 10 | "DocsURL": "https://github.com/ntystudio/CTRLReferenceVisualizer/blob/main/README.md", 11 | "MarketplaceURL": "", 12 | "CanContainContent": true, 13 | "IsBetaVersion": true, 14 | "IsExperimentalVersion": false, 15 | "EnabledByDefault": true, 16 | "Installed": true, 17 | "Modules": [ 18 | { 19 | "Name": "CtrlReferenceVisualizer", 20 | "Type": "Editor", 21 | "LoadingPhase": "PostDefault" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright © 2024 NTY.studio 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the “Software”), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 | CTRL Reference Visualizer is part of the [NTY.studio](https://www.nty.studio/) CTRL Framework, a library of utility plugins for Unreal Engine. 6 | 7 | ## Overview 8 | CTRL Reference Visualizer is an editor plugin for Unreal Engine 5 that enables level designers to see outgoing and incoming actor references for actors, components and objects in the world. 9 | 10 | 11 |
12 |
13 | 14 | See the plugin in action below: 15 |
16 | 17 | [![CTRL Reference Visualizer v1.0 Showcase](https://github.com/user-attachments/assets/5c9e618f-3147-4fa6-84c7-8d631d2265cb)](https://youtu.be/87IMYG2a7Qs?si=AoTZWZp94m92QSyj) 18 | 19 |
20 |
21 | 22 | ## Features 23 | - Visualize references between Actors, Components and Objects. 24 | - Filters to disable references to/from specific classes. 25 | - Customizable line colour settings. 26 | 27 |
28 | 29 | ## Prerequisites 30 | - Unreal Engine 5.4+ 31 | 32 |
33 | 34 | ## Get Started 35 | Once CTRL Reference Visualizer is installed, you will see a new icon on the action bar above your editor window where you can enable/disable the plugin and access its settings. 36 | 37 | 38 |
39 |
40 | 41 | With the plugin enabled, selecting any actor will show the outgoing references by default. 42 | 43 | If you want to show incoming references too, you'll need to enable this in the plugin settings. 44 | 45 | 46 |
47 |
48 | 49 | You can also customize the reference line styles: 50 | 51 | 52 |
53 |
54 | 55 | ## Feedback 56 | 57 | If you come across an issue while using the plugin or have a suggestion to improve the plugin, feel free to [open an issue](https://github.com/ntystudio/CTRL-reference-visualizer/issues) or leave a post in our [discord server](https://discord.gg/ntystudio) (CTRL Framework section in discord below). 58 | 59 | ![image](https://github.com/user-attachments/assets/07b8c1d0-a582-46dd-80dc-452ee5cf6ce2) 60 |
61 |
62 | 63 | ## Contribution 64 | Contributions from the community are welcome! If you decide to to contribute, we ask that you: 65 | - Fork the repository 66 | - Create a new branch 67 | - Make your changes 68 | - Submit a pull request 69 | 70 |
71 | 72 | ## License 73 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details. 74 | 75 | ---- 76 | 77 | > [!Tip] 78 | > # NTY Studio Plugins 79 | > 80 | > * [� Unicode Browser](https://github.com/ntystudio/UnicodeBrowser) 81 | > * [CTRL.StateTree](https://github.com/ntystudio/CTRL.StateTree) 82 | > * [CTRL.ReferenceVisualizer](https://github.com/ntystudio/CTRL.ReferenceVisualizer) 83 | > * [CTRL.Core](https://github.com/ntystudio/CTRL.Core) 84 | > * [CTRL.Gas](https://github.com/ntystudio/CTRL.Gas) 85 | -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Resources/Icon128.png -------------------------------------------------------------------------------- /Resources/Icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntystudio/CTRL.ReferenceVisualizer/d8f511bcf9f9b313b97a51c547d8b6e369e82315/Resources/Icon16.png -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/CtrlReferenceVisualizer.Build.cs: -------------------------------------------------------------------------------- 1 | using UnrealBuildTool; 2 | 3 | public class CtrlReferenceVisualizer : ModuleRules 4 | { 5 | public CtrlReferenceVisualizer(ReadOnlyTargetRules Target) : base(Target) 6 | { 7 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 8 | IncludeOrderVersion = EngineIncludeOrderVersion.Latest; 9 | #if UE_5_2_OR_LATER 10 | IWYUSupport = IWYUSupport.Full; 11 | #else 12 | bEnforceIWYU = true; 13 | #endif 14 | CppStandard = CppStandardVersion.Cpp20; 15 | 16 | PublicIncludePaths.AddRange( 17 | new string[] 18 | { 19 | } 20 | ); 21 | 22 | PrivateIncludePaths.AddRange( 23 | new string[] 24 | { 25 | } 26 | ); 27 | 28 | PublicDependencyModuleNames.AddRange( 29 | new[] 30 | { 31 | "Core", 32 | "CoreUObject", 33 | "Engine", 34 | "DeveloperSettings", 35 | "RenderCore", 36 | "RHI", 37 | "Slate", 38 | "SlateCore", 39 | "UMG", 40 | "Paper2D" 41 | } 42 | ); 43 | 44 | // PublicDependencyModuleNames.AddRange( 45 | // new string[] { 46 | // "Core", 47 | // "CoreUObject", 48 | // "Engine", 49 | // "RHI", 50 | // "SlateCore", 51 | // "Slate", 52 | // "NavigationSystem" 53 | // } 54 | // ); 55 | // 56 | // PrivateDependencyModuleNames.AddRange( 57 | // new string[] { 58 | // } 59 | // ); 60 | // 61 | // if (Target.bBuildEditor == true) 62 | // { 63 | // //@TODO: Needed for the triangulation code used for sprites (but only in editor mode) 64 | // //@TOOD: Try to move the code dependent on the triangulation code to the editor-only module 65 | // PrivateDependencyModuleNames.Add("EditorFramework"); 66 | // PrivateDependencyModuleNames.Add("UnrealEd"); 67 | // } 68 | 69 | PrivateDependencyModuleNames.AddRange( 70 | new string[] 71 | { 72 | "AssetTools", 73 | "Engine", 74 | "GameplayTags", 75 | "InputCore", 76 | "Json", 77 | "LevelEditor", 78 | "EditorSubsystem", 79 | "EditorFramework", 80 | "Renderer", 81 | "RenderCore", 82 | "TypedElementRuntime", 83 | "TypedElementFramework", 84 | "ToolMenus", 85 | "UnrealEd" 86 | } 87 | ); 88 | 89 | DynamicallyLoadedModuleNames.AddRange( 90 | new string[] 91 | { 92 | } 93 | ); 94 | } 95 | } -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvCommands.cpp: -------------------------------------------------------------------------------- 1 | #include "CrvCommands.h" 2 | 3 | #include "CrvSettings.h" 4 | 5 | #define LOCTEXT_NAMESPACE "ReferenceVisualizer" 6 | 7 | void FCrvCommands::ToggleEnabled_Execute() 8 | { 9 | const auto Settings = GetMutableDefault(); 10 | Settings->ToggleEnabled(); 11 | } 12 | 13 | bool FCrvCommands::ToggleEnabled_CanExecute() 14 | { 15 | return true; 16 | } 17 | 18 | bool FCrvCommands::ToggleEnabled_IsChecked() 19 | { 20 | const auto Settings = GetDefault(); 21 | return Settings->bIsEnabled; 22 | } 23 | 24 | void FCrvCommands::RegisterCommands() 25 | { 26 | UI_COMMAND( 27 | ToggleReferenceVisualizer, 28 | "Reference Visualizer", 29 | "Toggle Reference Visualizer", 30 | EUserInterfaceActionType::ToggleButton, 31 | FInputChord() 32 | ); 33 | 34 | if (CommandList.IsValid()) 35 | { 36 | return; 37 | } 38 | 39 | CommandList = MakeShareable(new FUICommandList); 40 | CommandList->MapAction( 41 | ToggleReferenceVisualizer, 42 | FExecuteAction::CreateRaw(this, &FCrvCommands::ToggleEnabled_Execute), 43 | FCanExecuteAction::CreateRaw(this, &FCrvCommands::ToggleEnabled_CanExecute), 44 | FIsActionChecked::CreateRaw(this, &FCrvCommands::ToggleEnabled_IsChecked) 45 | ); 46 | } 47 | 48 | #undef LOCTEXT_NAMESPACE 49 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "ReferenceVisualizerComponent.h" 2 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvDrawUtils.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "CrvDrawUtils.h" 4 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvDrawUtils.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Kismet/BlueprintFunctionLibrary.h" 7 | #include "CrvDrawUtils.generated.h" 8 | 9 | /** 10 | * 11 | */ 12 | UCLASS() 13 | class CTRLREFERENCEVISUALIZER_API UCrvDrawUtils : public UBlueprintFunctionLibrary 14 | { 15 | GENERATED_BODY() 16 | }; 17 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvHitProxy.cpp: -------------------------------------------------------------------------------- 1 | #include "CrvHitProxy.h" 2 | 3 | IMPLEMENT_HIT_PROXY(HCrvHitProxy, HComponentVisProxy); 4 | 5 | #define LOCTEXT_NAMESPACE "ReferenceVisualizer" 6 | 7 | #undef LOCTEXT_NAMESPACE 8 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvRefCache.cpp: -------------------------------------------------------------------------------- 1 | #include "CrvRefCache.h" 2 | 3 | #include "CrvRefSearch.h" 4 | #include "CrvSettings.h" 5 | #include "CrvUtils.h" 6 | #include "CtrlReferenceVisualizer.h" 7 | #include "Algo/AnyOf.h" 8 | 9 | #define LOCTEXT_NAMESPACE "ReferenceVisualizer" 10 | 11 | using namespace CtrlRefViz; 12 | 13 | bool UCrvRefCache::HasValues() const 14 | { 15 | return WeakRootObjects.Num() > 0 || Outgoing.Num() > 0 || Incoming.Num() > 0; 16 | } 17 | 18 | void UCrvRefCache::Reset(const FString& Reason) 19 | { 20 | bCached = false; 21 | bHadValidItems = false; 22 | WeakRootObjects.Reset(); 23 | Outgoing.Reset(); 24 | Incoming.Reset(); 25 | UE_CLOG(FCrvModule::IsDebugEnabled(), LogCrv, Log, TEXT("Cache reset... %s"), *Reason); 26 | } 27 | 28 | void UCrvRefCache::Invalidate(const FString& Reason) 29 | { 30 | UE_CLOG(FCrvModule::IsDebugEnabled(), LogCrv, Log, TEXT("Invalidating cache...")); 31 | Reset(Reason); 32 | ScheduleUpdate(); 33 | } 34 | 35 | bool UCrvRefCache::Contains(const UObject* Object) const 36 | { 37 | return WeakRootObjects.Contains(Object); 38 | } 39 | 40 | TSet UCrvRefCache::GetReferences(const UObject* Object, const ECrvDirection Direction) 41 | { 42 | static TSet Empty; 43 | if (!Contains(Object)) { return Empty; } 44 | const auto Cached = GetValidCached(Direction); 45 | if (const auto Found = Cached.Find(Object)) 46 | { 47 | return *Found; 48 | } else 49 | { 50 | return Empty; 51 | } 52 | } 53 | 54 | FCrvSet UCrvRefCache::GenerateAllRootObjects() 55 | { 56 | FCrvSet All; 57 | for (TObjectIterator It; It; ++It) 58 | { 59 | if (const auto Item = *It) 60 | { 61 | if (Item->HasAnyFlags(RF_ClassDefaultObject)) 62 | { 63 | continue; 64 | } 65 | if (const auto Owner = Item->GetOwner()) 66 | { 67 | All.Add(Owner); 68 | } 69 | } 70 | } 71 | return MoveTemp(All); 72 | } 73 | 74 | FCrvSet UCrvRefCache::GenerateRootObjects() 75 | { 76 | static FCrvSet Empty; 77 | switch (GetDefault()->Mode) 78 | { 79 | case ECrvMode::OnlySelected: 80 | { 81 | return FCrvRefSearch::GetSelectionSet(); 82 | } 83 | case ECrvMode::SelectedOrAll: 84 | { 85 | auto SelectionSet = FCrvRefSearch::GetSelectionSet(); 86 | if (SelectionSet.Num() > 0) 87 | { 88 | return MoveTemp(SelectionSet); 89 | } 90 | return GenerateAllRootObjects(); 91 | } 92 | case ECrvMode::All: 93 | { 94 | return GenerateAllRootObjects(); 95 | } 96 | default: 97 | { 98 | return Empty; 99 | } 100 | } 101 | } 102 | 103 | void UCrvRefCache::UpdateCache() 104 | { 105 | GEditor->GetTimerManager()->ClearTimer(UpdateCacheNextTickHandle); 106 | FillCache(GenerateRootObjects()); 107 | } 108 | 109 | void UCrvRefCache::ScheduleUpdate() 110 | { 111 | GEditor->GetTimerManager()->ClearTimer(UpdateCacheNextTickHandle); 112 | auto WeakThis = TWeakObjectPtr(this); 113 | UpdateCacheNextTickHandle = GEditor->GetTimerManager()->SetTimerForNextTick([WeakThis]() 114 | { 115 | if (WeakThis.IsValid()) 116 | { 117 | WeakThis->UpdateCache(); 118 | } 119 | }); 120 | } 121 | 122 | FCrvObjectGraph UCrvRefCache::GetValidCached(const ECrvDirection Direction) 123 | { 124 | static FCrvObjectGraph Empty; 125 | if (!bCached) { return Empty; } 126 | 127 | const auto Cached = Direction == ECrvDirection::Outgoing ? Outgoing : Incoming; 128 | bool bFoundInvalid = false; 129 | auto ValidCached = ResolveWeakGraph(Cached, bFoundInvalid); 130 | if (bFoundInvalid) 131 | { 132 | Invalidate(FString::Printf(TEXT("Invalid %s references"), Direction == ECrvDirection::Outgoing ? TEXT("Outgoing") : TEXT("Incoming"))); 133 | } 134 | return MoveTemp(ValidCached); 135 | } 136 | 137 | 138 | bool HasValidItems(const FCrvWeakGraph& CachedItems) 139 | { 140 | for (const auto& [WeakObject, Items] : CachedItems) 141 | { 142 | if (!WeakObject.IsValid()) 143 | { 144 | continue; 145 | } 146 | 147 | if (Items.Num() > 0) 148 | { 149 | if (Algo::AnyOf(Items, [](const TWeakObjectPtr& Item) { return Item.IsValid(); })) 150 | { 151 | return true; 152 | } 153 | } 154 | } 155 | return false; 156 | } 157 | 158 | void UCrvRefCache::AutoAddComponents(const FCrvSet& InRootObjects) 159 | { 160 | const auto bAutoAddComponents = GetDefault()->GetAutoAddComponents(); 161 | if (!bAutoAddComponents && AutoCreatedComponents.Num() == 0) { return; } 162 | // Remove Components 163 | { 164 | TSet ToRemove; 165 | auto CurrentAutoCreatedComponents = AutoCreatedComponents; 166 | for (auto Item : CurrentAutoCreatedComponents) 167 | { 168 | if (!Item.IsValid()) 169 | { 170 | AutoCreatedComponents.Remove(Item); 171 | bCached = false; 172 | continue; 173 | } 174 | 175 | if (!bAutoAddComponents || !InRootObjects.Contains(Item->GetOwner())) 176 | { 177 | AutoCreatedComponents.Remove(Item); 178 | bCached = false; 179 | ToRemove.Add(Item.Get()); 180 | } 181 | } 182 | 183 | for (const auto Item : ToRemove) 184 | { 185 | const auto Owner = Item->GetOwner(); 186 | Owner->RemoveOwnedComponent(Item); 187 | if (IsValid(Item)) 188 | { 189 | Item->DestroyComponent(); 190 | } 191 | } 192 | } 193 | 194 | if (!bAutoAddComponents) { return; } 195 | auto AddComponent = [this](AActor* Actor) 196 | { 197 | if (Actor->FindComponentByClass()) 198 | { 199 | return; // already has component 200 | } 201 | bCached = false; 202 | auto* DebugComponent = Cast( 203 | Actor->AddComponentByClass( 204 | UReferenceVisualizerComponent::StaticClass(), 205 | false, 206 | FTransform::Identity, 207 | false 208 | ) 209 | ); 210 | 211 | if (!DebugComponent) { return; } 212 | AutoCreatedComponents.Add(DebugComponent); 213 | Actor->AddOwnedComponent(DebugComponent); 214 | if (!DebugComponent->IsRegistered()) 215 | { 216 | DebugComponent->RegisterComponent(); 217 | } 218 | }; 219 | 220 | for (const auto Item : InRootObjects) 221 | { 222 | ensure(Item != nullptr); 223 | if (const auto Actor = Cast(Item)) 224 | { 225 | AddComponent(Actor); 226 | } 227 | else if (auto OuterActor = Item->GetTypedOuter()) 228 | { 229 | AddComponent(OuterActor); 230 | } 231 | } 232 | } 233 | 234 | void UCrvRefCache::FillCache(const FCrvSet& InRootObjects) 235 | { 236 | if (bCached && !AreSetsEqual(ResolveWeakSet(WeakRootObjects), InRootObjects)) 237 | { 238 | Reset(FString::Printf(TEXT("FillCache: RootObjects Changed"))); 239 | } 240 | 241 | const auto Config = GetDefault(); 242 | AutoAddComponents(InRootObjects); 243 | WeakRootObjects = ToWeakSet(InRootObjects); 244 | WeakRootObjects.Compact(); 245 | const auto RootObjects = InRootObjects; 246 | 247 | if (bCached) 248 | { 249 | UE_CLOG(FCrvModule::IsDebugEnabled(), LogCrv, Log, TEXT("Cache already filled. RootObjects: %d, Outgoing: %d, Incoming: %d"), RootObjects.Num(), Outgoing.Num(), Incoming.Num()); 250 | return; 251 | } 252 | 253 | if (Config->bShowOutgoingReferences) 254 | { 255 | FCrvObjectGraph OutRefs; 256 | FCrvRefSearch::FindOutRefs(RootObjects, OutRefs); 257 | Outgoing = ToWeakGraph(OutRefs); 258 | Outgoing.Compact(); 259 | } 260 | else 261 | { 262 | Outgoing.Reset(); 263 | } 264 | 265 | if (Config->bShowIncomingReferences) 266 | { 267 | FCrvObjectGraph InRefs; 268 | FCrvRefSearch::FindInRefs(RootObjects, InRefs); 269 | Incoming = ToWeakGraph(InRefs); 270 | Incoming.Compact(); 271 | } 272 | else 273 | { 274 | Incoming.Reset(); 275 | } 276 | 277 | if (!bHadValidItems) 278 | { 279 | bHadValidItems = HasValidItems(Outgoing) || HasValidItems(Incoming); 280 | } 281 | 282 | if (OnCacheUpdated.IsBound()) 283 | { 284 | OnCacheUpdated.Broadcast(); 285 | } 286 | 287 | bCached = HasValues(); 288 | UE_CLOG(FCrvModule::IsDebugEnabled(), LogCrv, Log, TEXT("Cache filled: RootObjects: %d, Outgoing: %d, Incoming: %d"), RootObjects.Num(), Outgoing.Num(), Incoming.Num()); 289 | } 290 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvRefCache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "CrvHitProxy.h" 5 | #include "CrvSettings.h" 6 | #include "CrvUtils.h" 7 | #include "CtrlReferenceVisualizer.h" 8 | #include "CrvRefCache.generated.h" 9 | 10 | class UReferenceVisualizerComponent; 11 | using namespace CtrlRefViz; 12 | 13 | UCLASS(Transient, Hidden) 14 | class UCrvRefCache : public UObject 15 | { 16 | GENERATED_BODY() 17 | public: 18 | static FCrvSet GenerateRootObjects(); 19 | static FCrvSet GenerateAllRootObjects(); 20 | 21 | bool HasValues() const; 22 | bool Contains(const UObject* Object) const; 23 | 24 | void FillCache(const FCrvSet& InRootObjects); 25 | void Reset(const FString& String); 26 | // reset + schedule update 27 | void Invalidate(const FString& Reason); 28 | 29 | // Get all incoming/outgoing references for a given object 30 | TSet GetReferences(const UObject* Object, ECrvDirection Direction); 31 | FCrvObjectGraph GetValidCached(ECrvDirection Direction); 32 | 33 | void UpdateCache(); 34 | void ScheduleUpdate(); 35 | 36 | FCrvWeakGraph Outgoing; 37 | FCrvWeakGraph Incoming; 38 | // Objects we want to find references for 39 | UPROPERTY(Transient) 40 | TSet> WeakRootObjects; 41 | void AutoAddComponents(const FCrvSet& InRootObjects); 42 | 43 | bool bCached = false; 44 | bool bHadValidItems = false; 45 | 46 | DECLARE_MULTICAST_DELEGATE(FOnCacheUpdated) 47 | FOnCacheUpdated OnCacheUpdated; 48 | protected: 49 | UPROPERTY(Transient) 50 | TSet> AutoCreatedComponents; 51 | private: 52 | FTimerHandle UpdateCacheNextTickHandle; 53 | }; 54 | 55 | struct FCrvHitProxyRef 56 | { 57 | FHitProxyId Id; 58 | TWeakObjectPtr LeafObject; 59 | TWeakObjectPtr RootObject; 60 | 61 | bool IsValid() const 62 | { 63 | return Id != FHitProxyId() && LeafObject.IsValid() && RootObject.IsValid(); 64 | } 65 | 66 | FCrvHitProxyRef(HCrvHitProxy* HitProxy) 67 | : Id(HitProxy->Id), 68 | LeafObject(HitProxy->LeafObject), 69 | RootObject(HitProxy->RootObject) {} 70 | }; 71 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvRefSearch.cpp: -------------------------------------------------------------------------------- 1 | #include "CrvRefSearch.h" 2 | 3 | #include "CrvSettings.h" 4 | #include "CrvUtils.h" 5 | #include "CtrlReferenceVisualizer.h" 6 | #include "ReferenceVisualizerComponent.h" 7 | #include "Selection.h" 8 | 9 | #include "Styling/SlateIconFinder.h" 10 | 11 | #include "UObject/ReferenceChainSearch.h" 12 | #include "UObject/ReferencerFinder.h" 13 | 14 | using namespace CtrlRefViz; 15 | 16 | namespace CtrlRefViz::Search 17 | { 18 | bool IsExternal(const FReferenceChainSearch::FReferenceChain* Chain) 19 | { 20 | if (Chain == nullptr) 21 | { 22 | return false; 23 | } 24 | 25 | if (Chain->Num() > 1) 26 | { 27 | // Reference is external if the root (the last node) is not in the first node (target) 28 | return !Chain->GetRootNode()->ObjectInfo->IsIn(Chain->GetNode(0)->ObjectInfo); 29 | } 30 | else 31 | { 32 | return false; 33 | } 34 | } 35 | 36 | template 37 | void TryAddValue(FCrvSet& Found, T PropValue) 38 | { 39 | if (!PropValue.IsValid()) { return; } 40 | Found.Add(PropValue.Get()); 41 | } 42 | 43 | TArray FindSoftObjectReferences(const UObject* RootObject) 44 | { 45 | if (!IsValid(RootObject)) { return {}; } 46 | const auto Settings = GetDefault(); 47 | FCrvSet Found; 48 | if (Settings->bWalkObjectProperties && RootObject->GetClass()) 49 | { 50 | for (TFieldIterator PropIt(RootObject->GetClass(), EFieldIterationFlags::IncludeSuper); PropIt; ++PropIt) 51 | { 52 | if (const auto SoftObjectProperty = CastField(*PropIt)) 53 | { 54 | TryAddValue(Found, SoftObjectProperty->GetPropertyValue_InContainer(RootObject)); 55 | } 56 | else if (const auto WeakObjectProperty = CastField(*PropIt)) 57 | { 58 | TryAddValue(Found, WeakObjectProperty->GetPropertyValue_InContainer(RootObject)); 59 | } 60 | else if (const auto LazyObjectProperty = CastField(*PropIt)) 61 | { 62 | TryAddValue(Found, LazyObjectProperty->GetPropertyValue_InContainer(RootObject)); 63 | } 64 | } 65 | } 66 | return Found.Array(); 67 | } 68 | 69 | FCrvSet FindOwnedObjects(FCrvSet Targets) 70 | { 71 | const auto CrvSettings = GetDefault(); 72 | TArray Owned; 73 | for (const auto Target : Targets) 74 | { 75 | FReferenceFinder RefFinder( 76 | Owned, 77 | Target, 78 | false, 79 | CrvSettings->bIgnoreArchetype, 80 | CrvSettings->bIsRecursive, 81 | CrvSettings->bIgnoreTransient 82 | ); 83 | RefFinder.FindReferences(Target); 84 | } 85 | 86 | return TSet(Owned); 87 | } 88 | 89 | FCrvSet FindOwnedObjects(UObject* Target) 90 | { 91 | const auto CrvSettings = GetDefault(); 92 | TArray Owned; 93 | FReferenceFinder RefFinder( 94 | Owned, 95 | Target, 96 | false, 97 | CrvSettings->bIgnoreArchetype, 98 | CrvSettings->bIsRecursive, 99 | CrvSettings->bIgnoreTransient 100 | ); 101 | 102 | RefFinder.FindReferences(Target); 103 | return TSet(Owned); 104 | } 105 | 106 | #pragma region GetObjectFlagsString 107 | FString GetObjectFlagsString(const UObject* InObject) 108 | { 109 | if (!InObject) 110 | { 111 | return FString(""); 112 | } 113 | TArray Flags; 114 | if (!IsValid(InObject)) 115 | { 116 | Flags.Add(TEXT("Invalid")); 117 | } 118 | if (InObject->IsRooted()) 119 | { 120 | Flags.Add(TEXT("Root")); 121 | } 122 | 123 | if (InObject->HasAnyFlags(RF_ClassDefaultObject)) 124 | { 125 | Flags.Add(TEXT("CDO")); 126 | } 127 | 128 | if (InObject->HasAnyFlags(RF_Transient)) 129 | { 130 | Flags.Add(TEXT("Transient")); 131 | } 132 | if (InObject->HasAnyFlags(RF_Public)) 133 | { 134 | Flags.Add(TEXT("Public")); 135 | } 136 | if (InObject->HasAnyFlags(RF_Standalone)) 137 | { 138 | Flags.Add(TEXT("Standalone")); 139 | } 140 | if (InObject->HasAnyFlags(RF_NeedLoad)) 141 | { 142 | Flags.Add(TEXT("NeedLoad")); 143 | } 144 | if (InObject->HasAnyFlags(RF_NeedPostLoad)) 145 | { 146 | Flags.Add(TEXT("NeedPostLoad")); 147 | } 148 | if (InObject->HasAnyFlags(RF_NeedPostLoadSubobjects)) 149 | { 150 | Flags.Add(TEXT("NeedPostLoadSubobjects")); 151 | } 152 | if (InObject->HasAnyFlags(RF_WasLoaded)) 153 | { 154 | Flags.Add(TEXT("WasLoaded")); 155 | } 156 | 157 | CA_SUPPRESS(6011) 158 | if (InObject->IsNative()) 159 | { 160 | Flags.Add(TEXT("Native")); 161 | } 162 | 163 | if (InObject->HasAnyInternalFlags(EInternalObjectFlags::Garbage)) 164 | { 165 | Flags.Add(TEXT("Garbage")); 166 | } 167 | 168 | if (InObject->HasAnyInternalFlags(EInternalObjectFlags::Async)) 169 | { 170 | Flags.Add(TEXT("Async")); 171 | } 172 | 173 | if (InObject->HasAnyInternalFlags(EInternalObjectFlags::AsyncLoading)) 174 | { 175 | Flags.Add(TEXT("AsyncLoading")); 176 | } 177 | 178 | return FString::Printf(TEXT("%s"), *FString::Join(Flags, TEXT(", "))); 179 | } 180 | #pragma endregion GetObjectFlagsString 181 | } 182 | 183 | FCrvMenuItem FCrvRefSearch::MakeMenuEntry(const UObject* Parent, const UObject* Object) 184 | { 185 | static FCrvMenuItem Empty; 186 | if (!Object) 187 | { 188 | return Empty; 189 | } 190 | const auto FlagsString = Search::GetObjectFlagsString(Object); 191 | const auto PackageShortName = FPackageName::GetShortName(Object->GetPackage()->GetName()); 192 | auto Tooltip = FString::Printf(TEXT("%s\nPath: %s\nPkgName: %s\nFlags: %s"), *GetDebugName(Object), *GetPathNameSafe(Object), *PackageShortName, *FlagsString); 193 | if (const auto OuterActor = Object->GetTypedOuter()) 194 | { 195 | if (OuterActor != Object) 196 | { 197 | Tooltip += FString::Printf(TEXT("\nOuterActor: %s"), *OuterActor->GetActorNameOrLabel()); 198 | } 199 | } 200 | if (const auto OuterComponent = Object->GetTypedOuter()) 201 | { 202 | if (OuterComponent != Object) 203 | { 204 | Tooltip += FString::Printf(TEXT("\nOuterComponent: %s"), *OuterComponent->GetReadableName()); 205 | } 206 | } 207 | 208 | if (const auto Actor = Cast(Object)) 209 | { 210 | const auto Label = FText::FromString(FString::Printf(TEXT("%s"), *Actor->GetActorNameOrLabel())); 211 | const auto ActorTooltip = FText::FromString(FString::Printf(TEXT("%ls\nGuid: %s"), *Tooltip, *Actor->GetActorInstanceGuid().ToString())); 212 | return { 213 | Actor->GetFName(), 214 | Label, 215 | ActorTooltip, 216 | FSlateIconFinder::FindIconForClass(Actor->GetClass()), 217 | FUIAction( 218 | FExecuteAction::CreateWeakLambda( 219 | Actor, 220 | [Actor]() 221 | { 222 | FCrvModule::Get().SelectReference(const_cast(Actor)); 223 | } 224 | ) 225 | ) 226 | }; 227 | } 228 | else if (const auto Component = Cast(Object)) 229 | { 230 | const auto Label = FText::FromString(FString::Printf(TEXT("%s"), *Component->GetReadableName())); 231 | return { 232 | Component->GetFName(), 233 | Label, 234 | FText::FromString(Tooltip), 235 | FSlateIconFinder::FindIconForClass(Component->GetClass()), 236 | FUIAction( 237 | FExecuteAction::CreateWeakLambda( 238 | Component, 239 | [Component]() 240 | { 241 | FCrvModule::Get().SelectReference(const_cast(Component)); 242 | } 243 | ) 244 | ) 245 | }; 246 | } 247 | 248 | return { 249 | Object->GetFName(), 250 | FText::FromString(Object->GetName()), 251 | FText::FromString(Tooltip), 252 | FSlateIconFinder::FindIconForClass(Object->GetClass()), 253 | FUIAction() 254 | }; 255 | } 256 | 257 | bool IsObjectProperty(const FProperty* InProperty) 258 | { 259 | return CastField(InProperty) != nullptr; 260 | } 261 | 262 | #pragma region CanDisplayReference 263 | bool FCrvRefSearch::CanDisplayReference(const UObject* RootObject, const UObject* LeafObject) 264 | { 265 | if (!IsValid(LeafObject)) 266 | { 267 | return false; 268 | } 269 | if (!IsValid(RootObject)) 270 | { 271 | return false; 272 | } 273 | if (LeafObject == RootObject) 274 | { 275 | return false; 276 | } 277 | if (LeafObject->IsA()) 278 | { 279 | return false; 280 | } 281 | if (LeafObject->IsA()) 282 | { 283 | return false; 284 | } 285 | if (LeafObject->IsA()) 286 | { 287 | return false; 288 | } 289 | if (LeafObject->IsA()) 290 | { 291 | return false; 292 | } 293 | if (LeafObject->IsA()) 294 | { 295 | return false; 296 | } 297 | 298 | const auto CrvSettings = GetDefault(); 299 | 300 | // hide references to self... 301 | if (LeafObject->IsInOuter(RootObject)) 302 | { 303 | // unless it's an actor (e.g. child actor) 304 | if (!LeafObject->IsA()) 305 | { 306 | return false; 307 | } 308 | } 309 | 310 | if (CrvSettings->bIgnoreTransient && LeafObject->HasAnyFlags(RF_Transient)) 311 | { 312 | return false; 313 | } 314 | if (CrvSettings->bIgnoreArchetype && LeafObject->HasAnyFlags(RF_ArchetypeObject)) 315 | { 316 | return false; 317 | } 318 | if (CrvSettings->TargetSettings.IgnoreReferencesToClasses.Contains(LeafObject->GetClass())) 319 | { 320 | return false; 321 | } 322 | if (LeafObject->IsA()) 323 | { 324 | return true; 325 | } 326 | 327 | if (LeafObject->IsA()) 328 | { 329 | return CrvSettings->bShowComponents; 330 | } 331 | 332 | return CrvSettings->bShowObjects; 333 | } 334 | #pragma endregion CanDisplayReference 335 | 336 | FCrvSet FCrvRefSearch::GetSelectionSet() 337 | { 338 | TArray SelectedActors; 339 | TArray SelectedComponents; 340 | GEditor->GetSelectedActors()->GetSelectedObjects(SelectedActors); 341 | GEditor->GetSelectedComponents()->GetSelectedObjects(SelectedComponents); 342 | FCrvSet Selected; 343 | Selected.Append(SelectedActors); 344 | Selected.Append(SelectedComponents); 345 | 346 | FCrvSet SelectedSet; 347 | SelectedSet.Append(Selected); 348 | return MoveTemp(SelectedSet); 349 | } 350 | 351 | static auto GetCanDisplayReference(UObject* RootObject) 352 | { 353 | return [RootObject](const UObject* LeafObject) 354 | { 355 | return FCrvRefSearch::CanDisplayReference(RootObject, LeafObject); 356 | }; 357 | } 358 | 359 | FCrvSet Search::FindTargetObjects(UObject* RootObject) 360 | { 361 | static FCrvSet Empty; 362 | if (!IsValid(RootObject)) { return Empty; } 363 | FCrvSet TargetObjects; 364 | TargetObjects.Append(Search::FindOwnedObjects(RootObject)); 365 | TargetObjects.Add(RootObject); 366 | return MoveTemp(TargetObjects); 367 | } 368 | 369 | void FCrvRefSearch::FindOutRefs(FCrvSet RootObjects, FCrvObjectGraph& Graph) 370 | { 371 | auto* const CrvSettings = GetDefault(); 372 | Graph.Reserve(RootObjects.Num()); 373 | Graph.Reset(); 374 | for (auto RootObject : RootObjects) 375 | { 376 | FCrvSet RootObjectReferences; 377 | const auto TargetObjects = Search::FindTargetObjects(RootObject); 378 | for (const auto TargetObject : TargetObjects) 379 | { 380 | TArray NewItemsArray; 381 | FReferenceFinder RefFinder( 382 | NewItemsArray, 383 | nullptr, 384 | false, 385 | CrvSettings->bIgnoreArchetype, 386 | CrvSettings->bIsRecursive, 387 | CrvSettings->bIgnoreTransient 388 | ); 389 | RefFinder.FindReferences(TargetObject); 390 | RootObjectReferences.Append(NewItemsArray.FilterByPredicate(GetCanDisplayReference(RootObject))); 391 | } 392 | for (const auto TargetObject : TargetObjects) 393 | { 394 | if (CrvSettings->bWalkObjectProperties) 395 | { 396 | RootObjectReferences.Append(Search::FindSoftObjectReferences(TargetObject).FilterByPredicate(GetCanDisplayReference(RootObject))); 397 | } 398 | } 399 | Graph.Add(RootObject, RootObjectReferences); 400 | } 401 | } 402 | 403 | bool ChainContains(const FReferenceChainSearch::FReferenceChain* Chain, const UObject* Object) 404 | { 405 | if (!Chain) 406 | { 407 | return false; 408 | } 409 | if (const auto Root = Chain->GetRootNode()->ObjectInfo->TryResolveObject()) 410 | { 411 | if (Root == Object) 412 | { 413 | return true; 414 | } 415 | } 416 | 417 | for (int32 i = 0; i < Chain->Num(); i++) 418 | { 419 | if (Chain->GetNode(i)->ObjectInfo->TryResolveObject() == Object) 420 | { 421 | return true; 422 | } 423 | } 424 | return false; 425 | } 426 | 427 | void FCrvRefSearch::FindInRefs(FCrvSet RootObjects, FCrvObjectGraph& Graph) 428 | { 429 | Graph.Reserve(RootObjects.Num()); 430 | for (auto RootObject : RootObjects) 431 | { 432 | auto TargetObjects = Search::FindTargetObjects(RootObject); 433 | auto Referencers = FReferencerFinder::GetAllReferencers(TargetObjects, nullptr, EReferencerFinderFlags::SkipInnerReferences); 434 | auto Filtered = Referencers.FilterByPredicate(GetCanDisplayReference(RootObject)); 435 | Graph.Add(RootObject, TSet(Filtered)); 436 | } 437 | } -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvSampleFloorBase.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CrvUtils.h" 6 | #include "CtrlReferenceVisualizer.h" 7 | #include "Components/TextRenderComponent.h" 8 | #include "Kismet/BlueprintFunctionLibrary.h" 9 | #include "CrvSampleFloorBase.generated.h" 10 | 11 | UENUM(meta=(Bitflags, UseEnumValuesAsMaskValuesInEditor = "true")) 12 | enum class ECrvHorizontalDirection: uint32 13 | { 14 | None = 0, 15 | North = 1 << 0, 16 | NorthEast = 1 << 1, 17 | East = 1 << 2, 18 | SouthEast = 1 << 3, 19 | South = 1 << 4, 20 | SouthWest = 1 << 5, 21 | West = 1 << 6, 22 | NorthWest = 1 << 7, 23 | Middle = 1 << 8, 24 | All = North | NorthEast | East | SouthEast | South | SouthWest | West | NorthWest | Middle, 25 | }; 26 | 27 | ENUM_CLASS_FLAGS(ECrvHorizontalDirection); 28 | 29 | constexpr bool EnumHasAnyFlags(const int32 Flags, ECrvHorizontalDirection Contains) { return (Flags & static_cast(Contains)) != 0; } 30 | 31 | /** 32 | * Base class for sample floor. 33 | * Handles neatly auto-positioning heading text. 34 | * Ok to scale floor to change floor size. 35 | */ 36 | UCLASS(Blueprintable, BlueprintType, ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) 37 | class ACrvSampleFloorBase : public AActor 38 | { 39 | GENERATED_BODY() 40 | 41 | public: 42 | ACrvSampleFloorBase() 43 | { 44 | SceneRoot = CreateDefaultSubobject(TEXT("SceneRoot")); 45 | RootComponent = SceneRoot; 46 | FloorMesh = CreateDefaultSubobject(TEXT("FloorMesh")); 47 | FloorMesh->SetupAttachment(RootComponent); 48 | SampleHeading = CreateDefaultSubobject(TEXT("SampleHeading")); 49 | SampleHeading->SetupAttachment(RootComponent); 50 | Update(); 51 | } 52 | 53 | // position heading if auto position is enabled 54 | UFUNCTION(BlueprintCallable) 55 | void AutoPositionHeading() const 56 | { 57 | if (!bAutoPositionHeading) { return; } 58 | PositionHeading(); 59 | } 60 | 61 | UFUNCTION(BlueprintCallable, CallInEditor) 62 | void PositionHeading() const 63 | { 64 | FVector Min, Max; 65 | FloorMesh->GetLocalBounds(Min, Max); 66 | // rotate text to look up 67 | SampleHeading->SetRelativeRotation(FRotator(90, 180, 0)); 68 | // bottom left corner 69 | const auto NewLocation = GetCoordinate(ECrvHorizontalDirection::SouthWest); 70 | SampleHeading->SetRelativeLocation(NewLocation); 71 | OnSampleFloorBaseUpdated.Broadcast(Min, Max); 72 | } 73 | 74 | UFUNCTION(BlueprintCallable) 75 | FVector GetCoordinate(const ECrvHorizontalDirection Direction) const 76 | { 77 | FVector Min, Max; 78 | FloorMesh->GetLocalBounds(Min, Max); 79 | switch (Direction) 80 | { 81 | case ECrvHorizontalDirection::North: 82 | return FVector((Max.X - Min.X) / 2, Max.Y - HeadingPadding.Y, Max.Z + HeadingPadding.Z) * FloorMesh->GetComponentScale(); 83 | case ECrvHorizontalDirection::East: 84 | return FVector(Max.X - HeadingPadding.X, (Max.Y - Min.Y) / 2, Max.Z + HeadingPadding.Z) * FloorMesh->GetComponentScale(); 85 | case ECrvHorizontalDirection::West: 86 | return FVector(Min.X + HeadingPadding.X, (Max.Y - Min.Y) / 2, Max.Z + HeadingPadding.Z) * FloorMesh->GetComponentScale(); 87 | case ECrvHorizontalDirection::South: 88 | return FVector((Max.X - Min.X) / 2, Min.Y + HeadingPadding.Y, Max.Z + HeadingPadding.Z) * FloorMesh->GetComponentScale(); 89 | case ECrvHorizontalDirection::SouthWest: 90 | return FVector(Min.X + HeadingPadding.X, Min.Y + HeadingPadding.Y, Max.Z + HeadingPadding.Z) * FloorMesh->GetComponentScale(); 91 | case ECrvHorizontalDirection::SouthEast: 92 | return FVector(Max.X - HeadingPadding.X, Min.Y + HeadingPadding.Y, Max.Z + HeadingPadding.Z) * FloorMesh->GetComponentScale(); 93 | case ECrvHorizontalDirection::NorthEast: 94 | return FVector(Max.X - HeadingPadding.X, Max.Y - HeadingPadding.Y, Max.Z + HeadingPadding.Z) * FloorMesh->GetComponentScale(); 95 | case ECrvHorizontalDirection::NorthWest: 96 | return FVector(Min.X + HeadingPadding.X, Max.Y - HeadingPadding.Y, Max.Z + HeadingPadding.Z) * FloorMesh->GetComponentScale(); 97 | case ECrvHorizontalDirection::None: 98 | case ECrvHorizontalDirection::Middle: 99 | case ECrvHorizontalDirection::All: 100 | default: 101 | UE_LOG(LogCrv, Warning, TEXT("%s Invalid direction %s"), *CRV_LOG_LINE, *UEnum::GetValueAsString(Direction)); 102 | break; 103 | } 104 | return FVector::ZeroVector; 105 | } 106 | 107 | UFUNCTION(BlueprintCallable) 108 | void Update() const 109 | { 110 | SampleHeading->SetWorldSize(HeadingTextSize); 111 | SampleHeading->SetText(HeadingText); 112 | AutoPositionHeading(); 113 | } 114 | 115 | protected: 116 | virtual void OnConstruction(const FTransform& Transform) override 117 | { 118 | Super::OnConstruction(Transform); 119 | if (SampleHeading == nullptr) 120 | { 121 | SampleHeading = NewObject(this); 122 | SampleHeading->SetupAttachment(RootComponent); 123 | } 124 | Update(); 125 | } 126 | 127 | virtual void PostInitializeComponents() override 128 | { 129 | Super::PostInitializeComponents(); 130 | Update(); 131 | } 132 | 133 | #if WITH_EDITOR 134 | virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override 135 | { 136 | Super::PostEditChangeProperty(PropertyChangedEvent); 137 | Update(); 138 | } 139 | #endif 140 | 141 | public: 142 | // exists so floor can be scaled independently of text 143 | UPROPERTY(BlueprintReadWrite, VisibleAnywhere) 144 | TObjectPtr SceneRoot = nullptr; 145 | 146 | UPROPERTY(BlueprintReadWrite, VisibleAnywhere) 147 | TObjectPtr FloorMesh = nullptr; 148 | 149 | UPROPERTY(BlueprintReadWrite, VisibleAnywhere) 150 | TObjectPtr SampleHeading = nullptr; 151 | 152 | /** e.g. name of sample */ 153 | UPROPERTY(BlueprintReadWrite, EditAnywhere, meta=(ExposeOnSpawn="true")) 154 | FText HeadingText = FText::FromString("Sample"); 155 | 156 | UPROPERTY(BlueprintReadWrite, EditAnywhere, meta=(ExposeOnSpawn="true")) 157 | float HeadingTextSize = 350.f; 158 | 159 | // disable to manually position heading 160 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 161 | bool bAutoPositionHeading = true; 162 | 163 | UPROPERTY(BlueprintReadWrite, EditAnywhere, meta=(MultiLine="true", ExposeOnSpawn="true", EditCondition="bAutoPositionHeading")) 164 | FVector HeadingPadding = FVector(50.0, 100.0, 1.0); 165 | 166 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSampleFloorBaseUpdated, FVector, Min, FVector, Max); 167 | 168 | UPROPERTY(BlueprintAssignable) 169 | FOnSampleFloorBaseUpdated OnSampleFloorBaseUpdated; 170 | }; 171 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvSettings.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "CrvSettings.h" 4 | 5 | #include "CrvUtils.h" 6 | #include "CtrlReferenceVisualizer.h" 7 | #include "HAL/PlatformProcess.h" 8 | #include "Misc/FileHelper.h" 9 | #include "Misc/Paths.h" 10 | 11 | #define LOCTEXT_NAMESPACE "ReferenceVisualizer" 12 | 13 | FCrvLineStyle FCrvLineStyle::DefaultOutgoingLineStyle = { 14 | // LineStyle 15 | ECrvLineType::Arrow, 16 | // LineColor 17 | FColor::Green, 18 | // LineColorComponent 19 | FColor::Emerald, 20 | // LineColorObject 21 | FColor::Cyan, 22 | // LineThickness 23 | 2.f, 24 | // ArrowSize 25 | 10.f, 26 | // Depth Priority 27 | SDPG_Foreground 28 | }; 29 | 30 | FCrvLineStyle FCrvLineStyle::DefaultIncomingLineStyle = { 31 | // LineStyle 32 | ECrvLineType::Dash, 33 | // LineColor 34 | FColor::Blue, 35 | // LineColorComponent 36 | (FLinearColor(FColor::Emerald) * FLinearColor::Blue).ToFColor(true), 37 | // LineColorObject 38 | (FLinearColor(FColor::Cyan) * FLinearColor::Blue).ToFColor(true), 39 | // LineThickness 40 | 1.f, 41 | // ArrowSize 42 | 5.f, 43 | // Depth Priority 44 | SDPG_Foreground 45 | }; 46 | 47 | FCrvStyleSettings::FCrvStyleSettings() 48 | { 49 | } 50 | 51 | FCrvTargetSettings::FCrvTargetSettings() 52 | : IgnoreReferencesToClasses({}), 53 | TargetComponentClasses({TSoftClassPtr(UReferenceVisualizerComponent::StaticClass())}) 54 | { 55 | 56 | } 57 | 58 | UCrvSettings::UCrvSettings() 59 | { 60 | CategoryName = "Ctrl"; 61 | SectionName = "Reference Visualizer"; 62 | Help = LOCTEXT("Help", "Shows references between actors and components in the level."); 63 | } 64 | 65 | FText UCrvSettings::GetSectionText() const 66 | { 67 | return LOCTEXT("CtrlReferenceVisualizerSettingsName", "Reference Visualizer"); 68 | } 69 | 70 | FText UCrvSettings::GetSectionDescription() const 71 | { 72 | return LOCTEXT("CtrlReferenceVisualizerSettingsDescription", "Configure Ctrl Reference Visualizer Plugin"); 73 | } 74 | 75 | void UCrvSettings::AddComponentClass(const TSoftClassPtr& ComponentClass) 76 | { 77 | TargetSettings.TargetComponentClasses.AddUnique(ComponentClass); 78 | UpdateTargets(); 79 | } 80 | 81 | void UCrvSettings::SetEnabled(bool bNewEnabled) 82 | { 83 | if (bIsEnabled == bNewEnabled) { return; } 84 | bIsEnabled = bNewEnabled; 85 | const auto Property = StaticClass()->FindPropertyByName( 86 | GET_MEMBER_NAME_CHECKED(UCrvSettings, bIsEnabled) 87 | ); 88 | auto Event = FPropertyChangedEvent(Property); 89 | PostEditChangeProperty(Event); 90 | } 91 | 92 | void UCrvSettings::ToggleEnabled() 93 | { 94 | SetEnabled(!bIsEnabled); 95 | } 96 | 97 | void UCrvSettings::SetShowIncomingReferences(bool bNewShowIncomingReferences) 98 | { 99 | if (bShowIncomingReferences == bNewShowIncomingReferences) { return; } 100 | 101 | bShowIncomingReferences = bNewShowIncomingReferences; 102 | const auto Property = StaticClass()->FindPropertyByName( 103 | GET_MEMBER_NAME_CHECKED(UCrvSettings, bShowIncomingReferences) 104 | ); 105 | auto Event = FPropertyChangedEvent(Property); 106 | PostEditChangeProperty(Event); 107 | } 108 | 109 | void UCrvSettings::SetShowOutgoingReferences(bool bNewShowOutgoingReferences) 110 | { 111 | if (bShowOutgoingReferences == bNewShowOutgoingReferences) { return; } 112 | bShowOutgoingReferences = bNewShowOutgoingReferences; 113 | const auto Property = StaticClass()->FindPropertyByName( 114 | GET_MEMBER_NAME_CHECKED(UCrvSettings, bShowOutgoingReferences) 115 | ); 116 | auto Event = FPropertyChangedEvent(Property); 117 | PostEditChangeProperty(Event); 118 | } 119 | 120 | void UCrvSettings::Refresh() 121 | { 122 | UpdateTargets(); 123 | } 124 | 125 | void UCrvSettings::UpdateTargets() 126 | { 127 | if (bIsUpdating) { return; } 128 | TGuardValue UpdateGuard(bIsUpdating, true); 129 | CleanTargets(); 130 | const auto Property = StaticClass()->FindPropertyByName( 131 | GET_MEMBER_NAME_CHECKED(UCrvSettings, TargetSettings) 132 | ); 133 | OnModified.Broadcast(this, Property); 134 | } 135 | 136 | void UCrvSettings::CleanTargets() 137 | { 138 | // only allow at most one null entry 139 | auto OnlyOneNull = [](auto IsNullFunc) 140 | { 141 | bool bFoundOneNull = false; 142 | auto Fn = [&bFoundOneNull, &IsNullFunc](const auto& Item) 143 | { 144 | auto bIsOk = !IsNullFunc(Item); 145 | if (!bIsOk && !bFoundOneNull) 146 | { 147 | bFoundOneNull = true; 148 | return false; 149 | } 150 | return !bIsOk; 151 | }; 152 | return Fn; 153 | }; 154 | 155 | // clean target component classes 156 | TargetSettings.TargetComponentClasses.RemoveAll( 157 | OnlyOneNull([](const TSoftClassPtr& ClassPtr) { return ClassPtr.IsNull(); }) 158 | ); 159 | } 160 | 161 | bool UCrvSettings::IsEnabled() const 162 | { 163 | return bIsEnabled; 164 | } 165 | 166 | bool UCrvSettings::GetAutoAddComponents() const 167 | { 168 | return IsEnabled() && bAutoAddComponents; 169 | } 170 | 171 | // Function to open plugin documentation 172 | void OpenPluginDocumentation(const FString& PluginName) 173 | { 174 | // Construct the path to the plugin descriptor file 175 | const FString PluginPath = FPaths::ProjectPluginsDir() / PluginName / FString::Printf(TEXT("%s.uplugin"), *PluginName); 176 | 177 | // Read the plugin descriptor file 178 | FString FileContents; 179 | const bool bDidLoadFile = FFileHelper::LoadFileToString(FileContents, *PluginPath); 180 | if (!bDidLoadFile) 181 | { 182 | UE_LOG(LogCrv, Warning, TEXT("Failed to load plugin descriptor for %s"), *PluginName); 183 | return; 184 | } 185 | // Parse the JSON content 186 | TSharedPtr JsonObject; 187 | const TSharedRef> Reader = TJsonReaderFactory<>::Create(FileContents); 188 | const bool bDidDeserialize = FJsonSerializer::Deserialize(Reader, JsonObject); 189 | if (!bDidDeserialize) 190 | { 191 | UE_LOG(LogCrv, Warning, TEXT("Failed to deserialize plugin descriptor for %s"), *PluginName); 192 | return; 193 | } 194 | // Extract the DocsURL 195 | FString DocsURL; 196 | const bool Success = JsonObject->TryGetStringField(TEXT("DocsURL"), DocsURL); 197 | if (!Success) 198 | { 199 | UE_LOG(LogCrv, Warning, TEXT("No DocsURL found in plugin descriptor for %s"), *PluginName); 200 | return; 201 | } 202 | // Open the documentation URL in the default web browser 203 | FPlatformProcess::LaunchURL(*DocsURL, nullptr, nullptr); 204 | } 205 | 206 | void UCrvSettings::Documentation() const 207 | { 208 | OpenPluginDocumentation(TEXT("CtrlReferenceVisualizer")); 209 | } 210 | 211 | void UCrvSettings::PostInitProperties() 212 | { 213 | Super::PostInitProperties(); 214 | #if WITH_EDITOR 215 | IConsoleManager::Get().RegisterConsoleVariableSink_Handle( 216 | FConsoleCommandDelegate::CreateUObject(this, &UCrvSettings::CVarSink) 217 | ); 218 | #endif 219 | UpdateTargets(); 220 | } 221 | 222 | #if WITH_EDITOR 223 | 224 | FCrvLineStyle UCrvSettings::GetLineStyle(const ECrvDirection Direction) const 225 | { 226 | return Direction == ECrvDirection::Incoming ? Style.LineStyleIncoming : Style.LineStyleOutgoing; 227 | } 228 | 229 | void UCrvSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) 230 | { 231 | Super::PostEditChangeProperty(PropertyChangedEvent); 232 | if (!PropertyChangedEvent.Property) { return; } 233 | 234 | UpdateTargets(); 235 | OnModified.Broadcast(this, PropertyChangedEvent.Property); 236 | } 237 | 238 | void UCrvSettings::CVarSink() 239 | { 240 | if (IsTemplate()) 241 | { 242 | ImportConsoleVariableValues(); 243 | SetEnabled(CrvConsoleVars::CVarReferenceVisualizerEnabled->GetBool()); 244 | UpdateTargets(); 245 | } 246 | } 247 | #endif 248 | #undef LOCTEXT_NAMESPACE 249 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvStyle.cpp: -------------------------------------------------------------------------------- 1 | #include "CrvStyle.h" 2 | 3 | #include "Styling/ISlateStyle.h" 4 | #include "Styling/SlateStyle.h" 5 | #include "Styling/SlateStyleRegistry.h" 6 | #include "Styling/StyleColors.h" 7 | 8 | TSharedPtr FCrvStyle::StyleSet = nullptr; 9 | 10 | TSharedPtr FCrvStyle::Get() 11 | { 12 | ensure(StyleSet.IsValid()); 13 | return StyleSet; 14 | } 15 | 16 | FCrvStyle::FCrvStyle() 17 | : FSlateStyleSet(FCrvStyle::GetStyleSetName()) 18 | { 19 | } 20 | 21 | void FCrvStyle::Startup() 22 | { 23 | if (StyleSet.IsValid()) { return; } // only init once 24 | StyleSet = MakeShared(); 25 | StyleSet->Initialize(); 26 | } 27 | 28 | void FCrvStyle::Register() 29 | { 30 | if (!StyleSet.IsValid()) { return; } 31 | FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get()); 32 | } 33 | 34 | void FCrvStyle::Shutdown() 35 | { 36 | if (StyleSet.IsValid()) 37 | { 38 | FSlateStyleRegistry::UnRegisterSlateStyle(*StyleSet.Get()); 39 | ensure(StyleSet.IsUnique()); 40 | StyleSet.Reset(); 41 | } 42 | } 43 | 44 | const FName& FCrvStyle::GetStyleSetName() const 45 | { 46 | static FName CtrlStyleName(TEXT("CrvStyle")); 47 | return CtrlStyleName; 48 | } 49 | 50 | void FCrvStyle::Initialize() 51 | { 52 | const FVector2D Icon128x128(128.0f, 128.0f); 53 | const FVector2D Icon16x16(16.f, 16.f); 54 | const FVector2D Icon32x32(32.f, 32.f); 55 | 56 | SetContentRoot(FPaths::ProjectPluginsDir() / TEXT("CtrlReferenceVisualizer/Resources")); 57 | Set("Ctrl.TabIcon", new FSlateImageBrush(GetContentRootDir() / TEXT("Icon128.png"), Icon128x128)); 58 | Set("Ctrl.PlacementModeIcon", new FSlateImageBrush(GetContentRootDir() / TEXT("Icon16.png"), Icon16x16)); 59 | // use outliner style to get colors for selection + unfocused selection + hover 60 | auto RowStyle = FAppStyle::Get().GetWidgetStyle("SceneOutliner.TableViewRow"); 61 | // add alternating row color 62 | FLinearColor AltColor = FStyleColors::Panel.GetSpecifiedColor().CopyWithNewOpacity(0.2f); 63 | Set( 64 | "Ctrl.TreeView.TableRow", 65 | FTableRowStyle(RowStyle) 66 | .SetEvenRowBackgroundBrush(FSlateColorBrush(FStyleColors::Recessed)) 67 | .SetOddRowBackgroundBrush(FSlateColorBrush(FLinearColor(AltColor))) 68 | ); 69 | } 70 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvTestActorBase.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "CrvTestActorBase.h" 4 | #include "ObjectTools.h" 5 | #include "HAL/PlatformApplicationMisc.h" 6 | #include "Components/TextRenderComponent.h" 7 | 8 | UCrvTestComponentBase::UCrvTestComponentBase() 9 | { 10 | TestObject = CreateDefaultSubobject(TEXT("TestObject")); 11 | } 12 | 13 | ACrvTestActorBase::ACrvTestActorBase() 14 | { 15 | PrimaryActorTick.bCanEverTick = false; 16 | 17 | DefaultSceneRoot = CreateDefaultSubobject(TEXT("DefaultSceneRoot")); 18 | RootComponent = DefaultSceneRoot; 19 | Sphere = CreateDefaultSubobject(TEXT("Sphere")); 20 | Sphere->SetupAttachment(DefaultSceneRoot); 21 | TextRender = CreateDefaultSubobject(TEXT("TextRender")); 22 | TextRender->SetupAttachment(Sphere); 23 | TextRender->SetRelativeLocation(FVector(0, 0, 100)); 24 | TextRender->SetRelativeRotation(FRotator(0, 180, 0)); 25 | TextRender->HorizontalAlignment = EHorizTextAligment::EHTA_Center; 26 | TestComponent = CreateDefaultSubobject(TEXT("TestComponent")); 27 | TestComponent->SetupAttachment(Sphere); 28 | TestComponent->SetRelativeLocation(FVector(0, 0, 200)); 29 | TestObject = CreateDefaultSubobject(TEXT("TestObject")); 30 | } 31 | 32 | void ACrvTestActorBase::OnConstruction(const FTransform& Transform) 33 | { 34 | Super::OnConstruction(Transform); 35 | 36 | TextRender->SetText(FText::FromName(TestName)); 37 | } 38 | 39 | void ACrvTestActorBase::CopySettingsToTestComponent() 40 | { 41 | TestComponent->ActorRef = ActorRef; 42 | TestComponent->ActorRef2 = ActorRef2; 43 | TestComponent->SoftActorRef = SoftActorRef; 44 | TestComponent->ComponentRef = ComponentRef; 45 | TestComponent->SoftComponentRef = SoftComponentRef; 46 | TestComponent->OptionalActorRef = OptionalActorRef; 47 | TestComponent->OptionalComponentRef = OptionalComponentRef; 48 | TestComponent->WeakActorRef = WeakActorRef; 49 | TestComponent->WeakComponentRef = WeakComponentRef; 50 | TestComponent->ActorRefArray= ActorRefArray; 51 | TestComponent->ActorRefMap = ActorRefMap; 52 | TestComponent->TestStruct = TestStruct; 53 | TestComponent->TestObject = TestObject; 54 | ActorRef = nullptr; 55 | ActorRef2 = nullptr; 56 | SoftActorRef = nullptr; 57 | ComponentRef = nullptr; 58 | SoftComponentRef = nullptr; 59 | OptionalActorRef = nullptr; 60 | OptionalComponentRef = nullptr; 61 | WeakActorRef = nullptr; 62 | WeakComponentRef = nullptr; 63 | ActorRefArray.Empty(); 64 | ActorRefMap.Empty(); 65 | } 66 | void ACrvTestActorBase::CopySettingsToTestObject() 67 | { 68 | TestObject->ActorRef = ActorRef; 69 | TestObject->ActorRef2 = ActorRef2; 70 | TestObject->SoftActorRef = SoftActorRef; 71 | TestObject->ComponentRef = ComponentRef; 72 | TestObject->SoftComponentRef = SoftComponentRef; 73 | TestObject->OptionalActorRef = OptionalActorRef; 74 | TestObject->OptionalComponentRef = OptionalComponentRef; 75 | TestObject->WeakActorRef = WeakActorRef; 76 | TestObject->WeakComponentRef = WeakComponentRef; 77 | TestObject->ActorRefArray = ActorRefArray; 78 | TestObject->ActorRefMap = ActorRefMap; 79 | TestObject->TestStruct = TestStruct; 80 | ActorRef = nullptr; 81 | ActorRef2 = nullptr; 82 | SoftActorRef = nullptr; 83 | ComponentRef = nullptr; 84 | SoftComponentRef = nullptr; 85 | OptionalActorRef = nullptr; 86 | OptionalComponentRef = nullptr; 87 | WeakActorRef = nullptr; 88 | WeakComponentRef = nullptr; 89 | ActorRefArray.Empty(); 90 | ActorRefMap.Empty(); 91 | } 92 | void UCrvCopyReference::CopyReference() 93 | { 94 | 95 | // auto CopyRef = [](UObject* Object) 96 | // { 97 | // if (!Object) { return; } 98 | // FPlatformApplicationMisc::ClipboardCopy(*Object->GetFullName()); 99 | // }; 100 | // if (What == ECrvCopyWhatReference::ChildActor) 101 | // { 102 | // if (auto OwnerWithChild = GetTypedOuter()) 103 | // { 104 | // CopyRef(OwnerWithChild->ChildActor); 105 | // } 106 | // return; 107 | // } 108 | // 109 | // auto Owner = GetTypedOuter(); 110 | // if (!Owner) { return; } 111 | // if (What == ECrvCopyWhatReference::ActorRef) 112 | // { 113 | // CopyRef(Owner->ActorRef); 114 | // return; 115 | // } 116 | // 117 | // if (What == ECrvCopyWhatReference::ActorRef2) 118 | // { 119 | // CopyRef(Owner->ActorRef2); 120 | // return; 121 | // } 122 | } 123 | 124 | ACrvTestActorWithChildActorBase::ACrvTestActorWithChildActorBase() 125 | { 126 | ChildActorComponent = CreateDefaultSubobject(TEXT("ChildActorComponent")); 127 | ChildActorComponent->SetupAttachment(RootComponent); 128 | ChildActorComponent->SetRelativeLocation(FVector(200, 0, 0)); 129 | ChildActorComponent->SetRelativeScale3D(FVector(0.5, 0.5, 0.5)); 130 | ChildActorComponent->SetChildActorClass(ACrvTestActorBase::StaticClass()); 131 | } 132 | void ACrvTestActorWithChildActorBase::CopySettingsToChildActor() 133 | { 134 | if (auto Child = Cast(ChildActorComponent->GetChildActor())) 135 | { 136 | Child->ActorRef = ActorRef; 137 | Child->ActorRef2 = ActorRef2; 138 | Child->SoftActorRef = SoftActorRef; 139 | Child->ComponentRef = ComponentRef; 140 | Child->SoftComponentRef = SoftComponentRef; 141 | Child->OptionalActorRef = OptionalActorRef; 142 | Child->OptionalComponentRef = OptionalComponentRef; 143 | Child->WeakActorRef = WeakActorRef; 144 | Child->WeakComponentRef = WeakComponentRef; 145 | Child->ActorRefArray= ActorRefArray; 146 | Child->ActorRefMap = ActorRefMap; 147 | Child->TestStruct = TestStruct; 148 | Child->TestObject = TestObject; 149 | ActorRef = nullptr; 150 | ActorRef2 = nullptr; 151 | SoftActorRef = nullptr; 152 | ComponentRef = nullptr; 153 | SoftComponentRef = nullptr; 154 | OptionalActorRef = nullptr; 155 | OptionalComponentRef = nullptr; 156 | WeakActorRef = nullptr; 157 | WeakComponentRef = nullptr; 158 | ActorRefArray.Empty(); 159 | ActorRefMap.Empty(); 160 | } 161 | } 162 | void ACrvTestActorWithChildActorBase::OnConstruction(const FTransform& Transform) 163 | { 164 | Super::OnConstruction(Transform); 165 | ChildActor = ChildActorComponent->GetChildActor(); 166 | } 167 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvTestActorBase.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GameFramework/Actor.h" 7 | #include "CrvTestActorBase.generated.h" 8 | 9 | class UCrvTestObject; 10 | class UTextRenderComponent; 11 | 12 | USTRUCT(BlueprintType) 13 | struct FCrvTestStructNested 14 | { 15 | GENERATED_BODY() 16 | 17 | // Direct Reference to an Actor 18 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 19 | TObjectPtr ActorRef; 20 | }; 21 | USTRUCT(BlueprintType) 22 | struct FCrvTestStruct 23 | { 24 | GENERATED_BODY() 25 | 26 | // Direct Reference to an Actor 27 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 28 | TObjectPtr ActorRef; 29 | 30 | // Direct Reference to another Actor 31 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 32 | TObjectPtr ActorRef2; 33 | 34 | // Soft Reference to an Actor 35 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 36 | TSoftObjectPtr SoftActorRef; 37 | 38 | // Direct Reference to an Actor Component 39 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 40 | TObjectPtr ComponentRef; 41 | 42 | // Soft Reference to an Actor Component 43 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 44 | TSoftObjectPtr SoftComponentRef; 45 | 46 | // Optional Reference to an Actor 47 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 48 | TOptional OptionalActorRef; 49 | 50 | // Optional Reference to an Actor Component 51 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 52 | TOptional OptionalComponentRef; 53 | 54 | // Weak Reference to an Actor 55 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 56 | TWeakObjectPtr WeakActorRef; 57 | 58 | // Weak Reference to an Actor Component 59 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 60 | TWeakObjectPtr WeakComponentRef; 61 | 62 | // Array of Actors 63 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 64 | TArray ActorRefArray; 65 | 66 | // Map of Actors 67 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 68 | TMap ActorRefMap; 69 | 70 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly, Instanced) 71 | TObjectPtr TestObject; 72 | 73 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 74 | FCrvTestStructNested TestStructNested; 75 | }; 76 | 77 | UCLASS(BlueprintType, DefaultToInstanced, EditInlineNew) 78 | class UCrvTestObject: public UObject 79 | { 80 | GENERATED_BODY() 81 | 82 | public: 83 | 84 | // Direct Reference to an Actor 85 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 86 | TObjectPtr ActorRef; 87 | 88 | // Direct Reference to another Actor 89 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 90 | TObjectPtr ActorRef2; 91 | 92 | // Soft Reference to an Actor 93 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 94 | TSoftObjectPtr SoftActorRef; 95 | 96 | // Direct Reference to an Actor Component 97 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 98 | TObjectPtr ComponentRef; 99 | 100 | // Soft Reference to an Actor Component 101 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 102 | TSoftObjectPtr SoftComponentRef; 103 | 104 | // Optional Reference to an Actor 105 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 106 | TOptional OptionalActorRef; 107 | 108 | // Optional Reference to an Actor Component 109 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 110 | TOptional OptionalComponentRef; 111 | 112 | // Weak Reference to an Actor 113 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 114 | TWeakObjectPtr WeakActorRef; 115 | 116 | // Weak Reference to an Actor Component 117 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 118 | TWeakObjectPtr WeakComponentRef; 119 | 120 | // Array of Actors 121 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 122 | TArray ActorRefArray; 123 | 124 | // Map of Actors 125 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 126 | TMap ActorRefMap; 127 | 128 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 129 | FCrvTestStruct TestStruct; 130 | 131 | UFUNCTION(BlueprintCallable, CallInEditor) 132 | void CopyActorToWeakActor() 133 | { 134 | 135 | WeakActorRef = ActorRef; 136 | ActorRef = nullptr; 137 | } 138 | UFUNCTION(BlueprintCallable, CallInEditor) 139 | void ClearWeakActorRef() 140 | { 141 | WeakActorRef = nullptr; 142 | } 143 | UFUNCTION(BlueprintCallable, CallInEditor) 144 | void CopyCompToWeakComp() 145 | { 146 | 147 | WeakComponentRef = ComponentRef; 148 | ComponentRef = nullptr; 149 | } 150 | UFUNCTION(BlueprintCallable, CallInEditor) 151 | void ClearWeakCompRef() 152 | { 153 | WeakComponentRef = nullptr; 154 | } 155 | }; 156 | 157 | UCLASS(Blueprintable, BlueprintType) 158 | class CTRLREFERENCEVISUALIZER_API UCrvTestComponentBase : public USceneComponent 159 | { 160 | GENERATED_BODY() 161 | 162 | public: 163 | 164 | UCrvTestComponentBase(); 165 | // Direct Reference to an Actor 166 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 167 | TObjectPtr ActorRef; 168 | 169 | // Direct Reference to another Actor 170 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 171 | TObjectPtr ActorRef2; 172 | 173 | // Soft Reference to an Actor 174 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 175 | TSoftObjectPtr SoftActorRef; 176 | 177 | // Direct Reference to an Actor Component 178 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 179 | TObjectPtr ComponentRef; 180 | 181 | // Soft Reference to an Actor Component 182 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 183 | TSoftObjectPtr SoftComponentRef; 184 | 185 | // Optional Reference to an Actor 186 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 187 | TOptional OptionalActorRef; 188 | 189 | // Optional Reference to an Actor Component 190 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 191 | TOptional OptionalComponentRef; 192 | 193 | // Weak Reference to an Actor 194 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 195 | TWeakObjectPtr WeakActorRef; 196 | 197 | // Weak Reference to an Actor Component 198 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 199 | TWeakObjectPtr WeakComponentRef; 200 | 201 | // Array of Actors 202 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 203 | TArray ActorRefArray; 204 | 205 | // Map of Actors 206 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 207 | TMap ActorRefMap; 208 | 209 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 210 | FCrvTestStruct TestStruct; 211 | 212 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly, Instanced) 213 | TObjectPtr TestObject; 214 | 215 | UFUNCTION(BlueprintCallable, CallInEditor) 216 | void CopyActorToWeakActor() 217 | { 218 | 219 | WeakActorRef = ActorRef; 220 | ActorRef = nullptr; 221 | } 222 | UFUNCTION(BlueprintCallable, CallInEditor) 223 | void ClearWeakActorRef() 224 | { 225 | WeakActorRef = nullptr; 226 | } 227 | UFUNCTION(BlueprintCallable, CallInEditor) 228 | void CopyCompToWeakComp() 229 | { 230 | 231 | WeakComponentRef = ComponentRef; 232 | ComponentRef = nullptr; 233 | } 234 | UFUNCTION(BlueprintCallable, CallInEditor) 235 | void ClearWeakCompRef() 236 | { 237 | WeakComponentRef = nullptr; 238 | } 239 | 240 | }; 241 | 242 | UCLASS(Blueprintable, BlueprintType) 243 | class CTRLREFERENCEVISUALIZER_API ACrvTestActorBase : public AActor 244 | { 245 | GENERATED_BODY() 246 | 247 | public: 248 | ACrvTestActorBase(); 249 | virtual void OnConstruction(const FTransform& Transform) override; 250 | 251 | UPROPERTY(BlueprintReadOnly, EditAnywhere, meta=(GetOptions="GetTestNames")) 252 | FName TestName = TEXT("A"); 253 | 254 | UFUNCTION(BlueprintCallable, Category = "CrvTestActorBase") 255 | static TArray GetTestNames() { return TArray{TEXT("A"), TEXT("B"), TEXT("C"), TEXT("D"), TEXT("E"), TEXT("F"), TEXT("G") }; } 256 | 257 | UPROPERTY(BlueprintReadOnly, VisibleAnywhere) 258 | TObjectPtr DefaultSceneRoot; 259 | 260 | UPROPERTY(BlueprintReadOnly, VisibleAnywhere) 261 | TObjectPtr TextRender; 262 | 263 | UPROPERTY(BlueprintReadOnly, VisibleAnywhere) 264 | TObjectPtr Sphere; 265 | 266 | UPROPERTY(BlueprintReadOnly, VisibleAnywhere) 267 | TObjectPtr TestComponent; 268 | 269 | // Test Properties // 270 | 271 | // Direct Reference to an Actor 272 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 273 | TObjectPtr ActorRef; 274 | 275 | // Direct Reference to another Actor 276 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 277 | TObjectPtr ActorRef2; 278 | 279 | // Soft Reference to an Actor 280 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 281 | TSoftObjectPtr SoftActorRef; 282 | 283 | // Direct Reference to an Actor Component 284 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 285 | TObjectPtr ComponentRef; 286 | 287 | // Soft Reference to an Actor Component 288 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 289 | TSoftObjectPtr SoftComponentRef; 290 | 291 | // Optional Reference to an Actor 292 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 293 | TOptional OptionalActorRef; 294 | 295 | // Optional Reference to an Actor Component 296 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 297 | TOptional OptionalComponentRef; 298 | 299 | // Weak Reference to an Actor 300 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 301 | TWeakObjectPtr WeakActorRef; 302 | 303 | // Weak Reference to an Actor Component 304 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly) 305 | TWeakObjectPtr WeakComponentRef; 306 | 307 | // Array of Actors 308 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 309 | TArray ActorRefArray; 310 | 311 | // Map of Actors 312 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 313 | TMap ActorRefMap; 314 | 315 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 316 | FCrvTestStruct TestStruct; 317 | 318 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 319 | TObjectPtr TestObject; 320 | 321 | UPROPERTY(BlueprintReadWrite, EditInstanceOnly) 322 | TObjectPtr ObjectRef; 323 | 324 | UFUNCTION(BlueprintCallable, CallInEditor) 325 | void CopySettingsToTestComponent(); 326 | 327 | void CopySettingsToTestObject(); 328 | 329 | UFUNCTION(BlueprintCallable, CallInEditor) 330 | void CopyActorToWeakActor() 331 | { 332 | 333 | WeakActorRef = ActorRef; 334 | ActorRef = nullptr; 335 | } 336 | UFUNCTION(BlueprintCallable, CallInEditor) 337 | void ClearWeakActorRef() 338 | { 339 | WeakActorRef = nullptr; 340 | } 341 | UFUNCTION(BlueprintCallable, CallInEditor) 342 | void CopyCompToWeakComp() 343 | { 344 | 345 | WeakComponentRef = ComponentRef; 346 | ComponentRef = nullptr; 347 | } 348 | UFUNCTION(BlueprintCallable, CallInEditor) 349 | void ClearWeakCompRef() 350 | { 351 | WeakComponentRef = nullptr; 352 | } 353 | }; 354 | 355 | UENUM() 356 | enum class ECrvCopyWhatReference : uint8 357 | { 358 | ChildActor, 359 | ChildActorComponent, 360 | TestComponent, 361 | TestObject, 362 | ActorRef, 363 | ActorRef2, 364 | SoftActorRef, 365 | ComponentRef, 366 | SoftComponentRef, 367 | OptionalActorRef, 368 | }; 369 | UCLASS(BlueprintType) 370 | class UCrvCopyReference: public UObject 371 | { 372 | GENERATED_BODY() 373 | public: 374 | UPROPERTY(BlueprintReadWrite, EditAnywhere) 375 | ECrvCopyWhatReference What; 376 | 377 | UFUNCTION(BlueprintCallable, CallInEditor) 378 | void CopyReference(); 379 | 380 | }; 381 | 382 | UCLASS() 383 | class ACrvTestActorWithChildActorBase : public ACrvTestActorBase 384 | { 385 | GENERATED_BODY() 386 | public: 387 | ACrvTestActorWithChildActorBase(); 388 | 389 | UPROPERTY(BlueprintReadWrite, VisibleAnywhere) 390 | TObjectPtr ChildActorComponent; 391 | 392 | UPROPERTY(BlueprintReadOnly, VisibleAnywhere) 393 | TObjectPtr ChildActor; 394 | 395 | UFUNCTION(BlueprintCallable, CallInEditor) 396 | void CopySettingsToChildActor(); 397 | 398 | virtual void OnConstruction(const FTransform& Transform) override; 399 | }; -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "CrvUtils.h" 2 | 3 | FString CtrlRefViz::GetDebugName(const UObject* Object) 4 | { 5 | if (!Object) 6 | { 7 | return TEXT("null"); 8 | } 9 | FString Name = GetNameSafe(Object); 10 | if (Object->IsA()) 11 | { 12 | Name = Cast(Object)->GetActorNameOrLabel(); 13 | } 14 | if (Object->IsA()) 15 | { 16 | Name = Cast(Object)->GetReadableName(); 17 | } 18 | return FString::Printf(TEXT("<%s>%s"), *GetNameSafe(Object->GetClass()), *Name); 19 | } 20 | 21 | AActor* CtrlRefViz::GetOwner(const UObject* Object) 22 | { 23 | return GetOwner(const_cast(Object)); 24 | } 25 | 26 | AActor* CtrlRefViz::GetOwner(UObject* Object) 27 | { 28 | if (!Object) { return nullptr; } 29 | if (const auto Actor = Cast(Object)) 30 | { 31 | return Actor; 32 | } 33 | if (const auto Component = Cast(Object)) 34 | { 35 | return Component->GetOwner(); 36 | } 37 | return Object->GetTypedOuter(); 38 | } 39 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CrvUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CoreMinimal.h" 3 | 4 | #define CRV_LOG_LINE FString::Printf(TEXT("%s:%d"), *FPaths::GetCleanFilename(ANSI_TO_TCHAR(__FILE__)), __LINE__) 5 | 6 | namespace CtrlRefViz 7 | { 8 | FString GetDebugName(const UObject* Object); 9 | AActor* GetOwner(UObject* Object); 10 | AActor* GetOwner(const UObject* Object); 11 | } 12 | 13 | namespace CrvConsoleVars 14 | { 15 | static int32 IsEnabled = 1; 16 | static FAutoConsoleVariableRef CVarReferenceVisualizerEnabled( 17 | TEXT("ctrl.ReferenceVisualizer"), 18 | IsEnabled, 19 | TEXT("Enable Actor Reference Visualizer Level Editor Display") 20 | ); 21 | } 22 | 23 | namespace CtrlRefViz 24 | { 25 | using FCrvSet = TSet; 26 | using FCrvSetProp = TSet>; 27 | using FCrvWeakSet = TSet>; 28 | using FCrvObjectGraph = TMap, FCrvSet>; 29 | using FCrvWeakGraph = TMap, FCrvWeakSet>; 30 | 31 | template 32 | bool AreSetsEqual(const T& Set, const T& RHS) 33 | { 34 | return Set.Num() == RHS.Num() && Set.Difference(RHS).Num() == 0 && RHS.Difference(Set).Num() == 0; 35 | } 36 | 37 | template 38 | TSet> ToWeakSet(const TSet& In) 39 | { 40 | static TSet> EmptySet; 41 | if (In.IsEmpty()) { return EmptySet; } 42 | FCrvWeakSet Out; 43 | Out.Reserve(In.Num()); 44 | for (const auto Object : In) 45 | { 46 | if (!IsValid(Object)) { continue; } 47 | Out.Add(Object); 48 | } 49 | return MoveTemp(Out); 50 | } 51 | 52 | template 53 | TSet ResolveWeakSet(const TSet>& Set, bool& bFoundInvalid) 54 | { 55 | static TSet EmptySet; 56 | bFoundInvalid = false; 57 | if (Set.IsEmpty()) { return EmptySet; } 58 | FCrvSet ValidPointers; 59 | // ValidPointers.Reserve(Set.Num()); 60 | for (const auto LinkedObject : Set) 61 | { 62 | if (LinkedObject.IsValid()) 63 | { 64 | ValidPointers.Add(LinkedObject.Get()); 65 | } 66 | else 67 | { 68 | bFoundInvalid = true; 69 | } 70 | } 71 | return MoveTemp(ValidPointers); 72 | } 73 | 74 | template 75 | TSet ResolveWeakSet(const TSet>& Set) 76 | { 77 | bool bFoundInvalid = false; 78 | return ResolveWeakSet(Set, bFoundInvalid); 79 | } 80 | 81 | inline FCrvObjectGraph ResolveWeakGraph(const FCrvWeakGraph& Graph, bool& bFoundInvalid) 82 | { 83 | bFoundInvalid = false; 84 | static FCrvObjectGraph EmptyGraph; 85 | if (Graph.IsEmpty()) { return EmptyGraph; } 86 | FCrvObjectGraph ValidItems; 87 | ValidItems.Reserve(Graph.Num()); 88 | for (const auto [Object, WeakSetPtrs] : Graph) 89 | { 90 | if (!Object.IsValid()) 91 | { 92 | bFoundInvalid = true; 93 | continue; 94 | } 95 | ValidItems.Add(Object.Get(), ResolveWeakSet(WeakSetPtrs)); 96 | } 97 | return MoveTemp(ValidItems); 98 | } 99 | 100 | inline FCrvObjectGraph ResolveWeakGraph(const FCrvWeakGraph& Graph) 101 | { 102 | bool bFoundInvalid = false; 103 | return ResolveWeakGraph(Graph, bFoundInvalid); 104 | } 105 | 106 | inline FCrvWeakGraph ToWeakGraph(const FCrvObjectGraph& Graph) 107 | { 108 | static FCrvWeakGraph EmptyGraph; 109 | if (Graph.IsEmpty()) { return EmptyGraph; } 110 | FCrvWeakGraph Out; 111 | Out.Reserve(Graph.Num()); 112 | for (const auto [Object, Set] : Graph) 113 | { 114 | if (!IsValid(Object)) { continue; } 115 | Out.Add(Object, ToWeakSet(Set)); 116 | } 117 | return MoveTemp(Out); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/CtrlReferenceVisualizer.cpp: -------------------------------------------------------------------------------- 1 | #include "CtrlReferenceVisualizer.h" 2 | 3 | #include "CrvCommands.h" 4 | #include "CrvRefSearch.h" 5 | #include "CrvSettings.h" 6 | #include "CrvStyle.h" 7 | #include "CrvUtils.h" 8 | #include "ISettingsModule.h" 9 | #include "LevelEditorSubsystem.h" 10 | #include "ObjectEditorUtils.h" 11 | 12 | #include "Styling/SlateIconFinder.h" 13 | 14 | #include "UObject/Object.h" 15 | 16 | #define LOCTEXT_NAMESPACE "ReferenceVisualizer" 17 | using namespace CtrlRefViz; 18 | 19 | DEFINE_LOG_CATEGORY(LogCrv); 20 | 21 | void FCrvModule::MakeReferenceListSubMenu(UToolMenu* SubMenu, const ECrvDirection Direction) const 22 | { 23 | if (!GetDefault()->IsEnabled()) 24 | { 25 | const auto ToolEntry = FToolMenuEntry::InitMenuEntry( 26 | FName("CtrlReferenceVisualizer_Disabled"), 27 | LOCTEXT("Disabled", "Disabled"), 28 | LOCTEXT("DisabledTooltip", "Disabled"), 29 | FSlateIcon(), 30 | FUIAction() 31 | ); 32 | SubMenu->AddMenuEntry(FName("CtrlReferenceVisualizer_Disabled"), ToolEntry); 33 | return; 34 | } 35 | auto CrvEditorSubsystem = GEditor->GetEditorSubsystem(); 36 | auto MenuCache = CrvEditorSubsystem->MenuCache; 37 | MenuCache->FillCache(FCrvRefSearch::GetSelectionSet()); 38 | 39 | bool bFoundEntry = false; 40 | FCrvSet Visited; 41 | auto ValidCache = MenuCache->GetValidCached(Direction); 42 | for (auto SelectedObject : FCrvRefSearch::GetSelectionSet()) 43 | { 44 | if (!SelectedObject) { return; } 45 | UE_CLOG(IsDebugEnabled(), LogCrv, Log, TEXT("Find %s for SelectedObject: %s"), *SelectedObject->GetFullName(), Direction == ECrvDirection::Outgoing ? TEXT("Outgoing") : TEXT("Incoming")); 46 | auto Refs = MenuCache->GetReferences(SelectedObject, Direction); 47 | if (!Refs.Num()) { continue; } 48 | 49 | auto RefsArray = Refs.Array(); 50 | RefsArray.Sort( 51 | [](const UObject& A, const UObject& B) { return A.GetFullName().Compare(B.GetFullName()) < 0; } 52 | ); 53 | for (auto Ref : RefsArray) 54 | { 55 | if (Visited.Contains(Ref)) { continue; } 56 | 57 | FToolMenuSection& Section = SubMenu->FindOrAddSection(FName(Ref->GetClass()->GetPathName())); 58 | FToolMenuSection* SectionPtr = &Section; 59 | if (auto BP = UBlueprint::GetBlueprintFromClass(Ref->GetClass()->GetAuthoritativeClass())) 60 | { 61 | auto& Section2 = SubMenu->FindOrAddSection(FName(BP->GetFullName())); 62 | SectionPtr = &Section2; 63 | // get human-readable name from uobject 64 | SectionPtr->Label = FText::FromString(BP->GetFriendlyName()); 65 | } 66 | else 67 | { 68 | SectionPtr->Label = FText::FromString(Ref->GetClass()->GetName()); 69 | } 70 | auto [Name, Label, ToolTip, Icon, Action] = FCrvRefSearch::MakeMenuEntry(SelectedObject, Ref); 71 | const auto ToolEntry = FToolMenuEntry::InitMenuEntry(Name, Label, ToolTip, Icon, Action); 72 | SectionPtr->AddEntry(ToolEntry); 73 | bFoundEntry = true; 74 | } 75 | Visited.Append(Refs); 76 | } 77 | 78 | if (!bFoundEntry) 79 | { 80 | const auto ToolEntry = FToolMenuEntry::InitMenuEntry( 81 | FName("CtrlReferenceVisualizer_None"), 82 | LOCTEXT("NoReferencesFound", "No references found"), 83 | LOCTEXT("NoReferencesFoundTooltip", "No references found"), 84 | FSlateIcon(), 85 | FUIAction() 86 | ); 87 | SubMenu->AddMenuEntry(FName("CtrlReferenceVisualizer_None"), ToolEntry); 88 | } 89 | } 90 | 91 | void FCrvModule::SelectReference(UObject* Object) 92 | { 93 | if (!Object) { return; } 94 | GEditor->GetEditorSubsystem()->OpenEditorForAsset(Object); 95 | const bool bMoveCamera = GetDefault()->bMoveViewportCameraToReference; 96 | if (const auto Actor = Cast(Object)) 97 | { 98 | GEditor->SelectNone(false, true); 99 | GEditor->SelectActor(Actor, true, true); 100 | if (bMoveCamera) 101 | { 102 | GEditor->MoveViewportCamerasToActor(*Actor, false); 103 | } 104 | return; 105 | } 106 | if (const auto Component = Cast(Object)) 107 | { 108 | GEditor->SelectNone(false, true); 109 | GEditor->SelectComponent(const_cast(Component), true, true); 110 | if (bMoveCamera) 111 | { 112 | if (const auto SceneComponent = Cast(Component)) 113 | { 114 | GEditor->MoveViewportCamerasToComponent(SceneComponent, false); 115 | } 116 | else 117 | { 118 | GEditor->MoveViewportCamerasToActor(*Component->GetOwner(), false); 119 | } 120 | } 121 | return; 122 | } 123 | 124 | if (const auto OwningComponent = Object->GetTypedOuter()) 125 | { 126 | SelectReference(OwningComponent); 127 | return; 128 | } 129 | if (const auto OwningActor = Object->GetTypedOuter()) 130 | { 131 | SelectReference(OwningActor); 132 | return; 133 | } 134 | } 135 | 136 | void FCrvModule::InitActorMenu() const 137 | { 138 | const auto SubMenu = FToolMenuEntry::InitSubMenu( 139 | FName("CtrlReferenceVisualizerOutgoing"), 140 | LOCTEXT("References", "References"), 141 | LOCTEXT("ReferencesTooltip", "List of actor & component references from selected objects"), 142 | FNewToolMenuDelegate::CreateLambda( 143 | [this](UToolMenu* Menu) 144 | { 145 | const auto SubMenuOutgoing = FToolMenuEntry::InitSubMenu( 146 | FName("CtrlReferenceVisualizerOutgoing"), 147 | LOCTEXT("OutgoingReferences", "Outgoing"), 148 | LOCTEXT("OutgoingReferencesTooltip", "List of actor & component references from selected objects"), 149 | FNewToolMenuDelegate::CreateRaw(this, &FCrvModule::MakeReferenceListSubMenu, ECrvDirection::Outgoing), 150 | FToolUIActionChoice(), 151 | EUserInterfaceActionType::None, 152 | false, 153 | FSlateIcon(FAppStyle::GetAppStyleSetName(), "BlendSpaceEditor.ArrowRight") 154 | ); 155 | const auto SubMenuIncoming = FToolMenuEntry::InitSubMenu( 156 | FName("CtrlReferenceVisualizerIncoming"), 157 | LOCTEXT("IncomingReferences", "Incoming"), 158 | LOCTEXT("IncomingReferencesTooltip", "List of incoming actor & component references to selected objects"), 159 | FNewToolMenuDelegate::CreateRaw(this, &FCrvModule::MakeReferenceListSubMenu, ECrvDirection::Incoming), 160 | FToolUIActionChoice(), 161 | EUserInterfaceActionType::None, 162 | false, 163 | FSlateIcon(FAppStyle::GetAppStyleSetName(), "BlendSpaceEditor.ArrowLeft") 164 | ); 165 | Menu->AddMenuEntry(SubMenuOutgoing.Name, SubMenuOutgoing); 166 | Menu->AddMenuEntry(SubMenuIncoming.Name, SubMenuIncoming); 167 | Menu->AddMenuEntry(FName(), FToolMenuEntry::InitSeparator(NAME_None)); 168 | 169 | const auto SubMenuOptions = FToolMenuEntry::InitSubMenu( 170 | FName("CtrlReferenceVisualizerOptions"), 171 | LOCTEXT("Options", "Options"), 172 | LOCTEXT("OptionsTooltip", "More Options"), 173 | FNewToolMenuDelegate::CreateRaw(this, &FCrvModule::MakeActorOptionsSubmenu), 174 | FToolUIActionChoice(), 175 | EUserInterfaceActionType::None, 176 | false, 177 | FSlateIcon() 178 | ); 179 | Menu->AddMenuEntry(SubMenuOptions.Name, SubMenuOptions); 180 | } 181 | ), 182 | FToolUIActionChoice(), 183 | EUserInterfaceActionType::None, 184 | false, 185 | FSlateIcon(FAppStyle::GetAppStyleSetName(), "ContentBrowser.ReferenceVisualizer") 186 | ); 187 | auto* ActorContextMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.ActorContextMenu"); 188 | auto&& Section = ActorContextMenu->FindOrAddSection(FName("Ctrl")); 189 | Section.AddEntry(SubMenu); 190 | } 191 | 192 | void FCrvModule::MakeActorOptionsSubmenu(UToolMenu* Menu) const 193 | { 194 | const auto CanExecuteIfEnabled = FCanExecuteAction::CreateLambda( 195 | [this]() 196 | { 197 | return FCrvModule::IsEnabled(); 198 | } 199 | ); 200 | Menu->AddMenuEntry( 201 | FName("CtrlReferenceVisualizer"), 202 | FToolMenuEntry::InitMenuEntry( 203 | FName("CtrlReferenceVisualizer"), 204 | LOCTEXT("CtrlReferenceVisualizer", "Enable"), 205 | LOCTEXT("CtrlReferenceVisualizer_Tooltip", "Toggle Reference Visualizer"), 206 | FSlateIcon(), 207 | FUIAction( 208 | FExecuteAction::CreateLambda( 209 | [this]() 210 | { 211 | auto* Settings = GetMutableDefault(); 212 | Settings->ToggleEnabled(); 213 | Settings->SaveConfig(); 214 | // get level editor viewport 215 | auto* LevelEditor = GEditor->GetEditorSubsystem(); 216 | LevelEditor->EditorInvalidateViewports(); 217 | } 218 | ), 219 | FCanExecuteAction(), 220 | FIsActionChecked::CreateLambda( 221 | [this]() 222 | { 223 | return FCrvModule::IsEnabled(); 224 | } 225 | ) 226 | ), 227 | EUserInterfaceActionType::ToggleButton 228 | ) 229 | ); 230 | 231 | Menu->AddMenuEntry( 232 | FName("CtrlReferenceVisualizer"), 233 | FToolMenuEntry::InitMenuEntry( 234 | FName("CtrlShowIncoming"), 235 | LOCTEXT("ShowIncoming", "Visualize Incoming"), 236 | LOCTEXT("ShowIncoming_Tooltip", "Show incoming references as links in the viewport"), 237 | FSlateIcon(), 238 | FUIAction( 239 | FExecuteAction::CreateLambda( 240 | [this]() 241 | { 242 | const auto Config = GetMutableDefault(); 243 | Config->SetShowIncomingReferences(!Config->bShowIncomingReferences); 244 | } 245 | ), 246 | CanExecuteIfEnabled, 247 | FIsActionChecked::CreateLambda( 248 | [this]() 249 | { 250 | return GetDefault()->bShowIncomingReferences; 251 | } 252 | ) 253 | ), 254 | EUserInterfaceActionType::ToggleButton 255 | ) 256 | ); 257 | 258 | Menu->AddMenuEntry( 259 | FName("CtrlReferenceVisualizer"), 260 | FToolMenuEntry::InitMenuEntry( 261 | FName("CtrlShowOutgoing"), 262 | LOCTEXT("ShowOutgoing", "Visualize Outgoing"), 263 | LOCTEXT("ShowOutgoing_Tooltip", "Show outgoing references as links in the viewport"), 264 | FSlateIcon(), 265 | FUIAction( 266 | FExecuteAction::CreateLambda( 267 | [this]() 268 | { 269 | const auto Config = GetMutableDefault(); 270 | Config->SetShowOutgoingReferences(!Config->bShowOutgoingReferences); 271 | } 272 | ), 273 | CanExecuteIfEnabled, 274 | FIsActionChecked::CreateLambda( 275 | [this]() 276 | { 277 | return GetDefault()->bShowOutgoingReferences; 278 | } 279 | ) 280 | ), 281 | EUserInterfaceActionType::ToggleButton 282 | ) 283 | ); 284 | 285 | Menu->AddMenuEntry( 286 | FName("CtrlReferenceVisualizer"), 287 | FToolMenuEntry::InitMenuEntry( 288 | FName("CtrlRefresh"), 289 | LOCTEXT("Refresh", "Refresh"), 290 | LOCTEXT("Refresh_Tooltip", "Refresh References"), 291 | FSlateIcon(), 292 | FUIAction( 293 | FExecuteAction::CreateLambda( 294 | [this]() 295 | { 296 | const auto Config = GetMutableDefault(); 297 | Config->Refresh(); 298 | } 299 | ), 300 | CanExecuteIfEnabled 301 | ), 302 | EUserInterfaceActionType::Button 303 | ) 304 | ); 305 | 306 | Menu->AddMenuEntry( 307 | FName("CtrlReferenceVisualizerSettings"), 308 | GetSettingsMenuEntry() 309 | ); 310 | } 311 | 312 | void FCrvModule::InitLevelMenus() const 313 | { 314 | const auto Menu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar.PlayToolBar"); 315 | auto& Section = Menu->FindOrAddSection("PluginTools"); 316 | if (!Section.FindEntry("CtrlMenuButton")) 317 | { 318 | Section.AddEntry( 319 | FToolMenuEntry::InitComboButton( 320 | "CtrlMenuButton", 321 | FToolUIActionChoice(), 322 | FOnGetContent::CreateLambda( 323 | [this]() -> TSharedRef 324 | { 325 | const FToolMenuContext MenuContext; 326 | return UToolMenus::Get()->GenerateWidget("Ctrl.CtrlMenu", MenuContext); 327 | } 328 | ), 329 | LOCTEXT("CtrlMenuEntry", "Ctrl"), 330 | LOCTEXT("CtrlMenuEntry", "Ctrl Tools"), 331 | FSlateIcon( 332 | FCrvStyle::Get()->GetStyleSetName(), 333 | "Ctrl.TabIcon" 334 | ) 335 | ) 336 | ); 337 | } 338 | 339 | const auto InNewToolMenu = UToolMenus::Get()->ExtendMenu("Ctrl.CtrlMenu"); 340 | 341 | auto ReferenceVisualizerSubMenu = FToolMenuEntry::InitSubMenu( 342 | "CtrlReferenceVisualizerSubMenu", 343 | LOCTEXT("CtrlReferenceVisualizerSubMenu", "Reference Visualizer"), 344 | LOCTEXT("CtrlReferenceVisualizerSubMenu_Tooltip", "Ctrl Reference Visualizer Actions"), 345 | FNewToolMenuChoice( 346 | FNewToolMenuDelegate::CreateLambda( 347 | [this](UToolMenu* SubMenu) 348 | { 349 | const auto MenuSection = SubMenu->AddSection("CtrlReferenceVisualizerSection", LOCTEXT("CtrlReferenceVisualizerSection", "Reference Visualizer")); 350 | SubMenu->AddMenuEntry( 351 | MenuSection.Name, 352 | FToolMenuEntry::InitMenuEntry( 353 | FName("CtrlReferenceVisualizer"), 354 | LOCTEXT("CtrlReferenceVisualizer", "Enable"), 355 | LOCTEXT("CtrlReferenceVisualizer_Tooltip", "Toggle Reference Visualizer"), 356 | FSlateIcon(), 357 | FUIAction( 358 | FExecuteAction::CreateLambda( 359 | [this]() 360 | { 361 | auto* Settings = GetMutableDefault(); 362 | Settings->ToggleEnabled(); 363 | Settings->SaveConfig(); 364 | // get level editor viewport 365 | auto* LevelEditor = GEditor->GetEditorSubsystem(); 366 | LevelEditor->EditorInvalidateViewports(); 367 | } 368 | ), 369 | FCanExecuteAction(), 370 | FIsActionChecked::CreateLambda( 371 | [this]() 372 | { 373 | return GetDefault()->bIsEnabled; 374 | } 375 | ) 376 | ), 377 | EUserInterfaceActionType::ToggleButton 378 | ) 379 | ); 380 | 381 | SubMenu->AddMenuEntry(MenuSection.Name, FToolMenuEntry::InitSeparator(NAME_None)); 382 | SubMenu->AddMenuEntry(MenuSection.Name, GetSettingsMenuEntry()); 383 | } 384 | ) 385 | ) 386 | ); 387 | ReferenceVisualizerSubMenu.Icon = FSlateIconFinder::FindIcon("BTEditor.Graph.BTNode.Task.RunBehavior.Icon"); 388 | InNewToolMenu->AddMenuEntry("CtrlEditorSubmenu", ReferenceVisualizerSubMenu); 389 | } 390 | 391 | class SCrvDialog : public SCompoundWidget 392 | { 393 | public: 394 | SLATE_BEGIN_ARGS(SCrvDialog) {} 395 | SLATE_END_ARGS() 396 | 397 | // Constructs this widget with InArgs 398 | void Construct(const FArguments& InArgs); 399 | 400 | // virtual ~SCrvDialog() override; 401 | }; 402 | 403 | void SCrvDialog::Construct(const FArguments& InArgs) 404 | { 405 | ChildSlot 406 | [ 407 | SNew(SBorder) 408 | .BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop")) 409 | .Padding(FMargin(0.0f, 3.0f, 1.0f, 0.0f)) 410 | [ 411 | SNew(SHorizontalBox) 412 | + SHorizontalBox::Slot() 413 | .FillWidth(1.0f) 414 | [ 415 | SNew(STextBlock) 416 | .Text(LOCTEXT("CtrlReferenceVisualizer", "Content")) 417 | ] 418 | ] 419 | ]; 420 | 421 | } 422 | 423 | void FCrvModule::InitTab() 424 | { 425 | // create and register tab 426 | const FText TitleText = LOCTEXT("CrvWindowTitle", "Ctrl Reference Visualizer"); 427 | // Create the window to pick the class 428 | TSharedRef CrvWindow = SNew(SWindow) 429 | .Title(TitleText) 430 | .SizingRule(ESizingRule::UserSized) 431 | .ClientSize(FVector2D(1000.f, 700.f)) 432 | .AutoCenter(EAutoCenter::PreferredWorkArea) 433 | .SupportsMinimize(false); 434 | 435 | TSharedRef Dialog = SNew(SCrvDialog); 436 | 437 | CrvWindow->SetContent(Dialog); 438 | TSharedPtr RootWindow = FGlobalTabmanager::Get()->GetRootWindow(); 439 | if (RootWindow.IsValid()) 440 | { 441 | FSlateApplication::Get().AddWindowAsNativeChild(CrvWindow, RootWindow.ToSharedRef()); 442 | } 443 | else 444 | { 445 | FSlateApplication::Get().AddWindow(CrvWindow); 446 | } 447 | 448 | 449 | } 450 | 451 | FToolMenuEntry FCrvModule::GetSettingsMenuEntry() const 452 | { 453 | return FToolMenuEntry::InitMenuEntry( 454 | FName("CtrlReferenceVisualizerSettings"), 455 | LOCTEXT("CtrlReferenceVisualizerSettings", "Settings"), 456 | LOCTEXT("CtrlReferenceVisualizerSettings_Tooltip", "Open Reference Visualizer Settings"), 457 | FSlateIconFinder::FindIcon("LevelViewport.AdvancedSettings"), 458 | FUIAction( 459 | FExecuteAction::CreateLambda( 460 | [this]() 461 | { 462 | FModuleManager::LoadModuleChecked("Settings").ShowViewer("Editor", "Ctrl", "Reference Visualizer"); 463 | } 464 | ) 465 | ) 466 | ); 467 | } 468 | 469 | 470 | void FCrvModule::OnPostEngineInit() 471 | { 472 | InitCategories(); 473 | FCrvCommands::Register(); 474 | InitActorMenu(); 475 | InitLevelMenus(); 476 | 477 | } 478 | 479 | void FCrvModule::StartupModule() 480 | { 481 | FCrvStyle::Startup(); 482 | FCrvStyle::Register(); 483 | FCoreDelegates::OnPostEngineInit.AddRaw(this, &FCrvModule::OnPostEngineInit); 484 | } 485 | 486 | bool FCrvModule::IsEnabled() 487 | { 488 | return GetDefault()->IsEnabled(); 489 | } 490 | 491 | bool FCrvModule::IsDebugEnabled() 492 | { 493 | return IsEnabled() && GetDefault()->bDebugEnabled; 494 | } 495 | 496 | void FCrvModule::ShutdownModule() 497 | { 498 | if (!UObjectInitialized()) { return; } 499 | SettingsModifiedHandle.Reset(); 500 | FCrvCommands::Unregister(); 501 | FCrvStyle::Shutdown(); 502 | } 503 | 504 | void FCrvModule::AddTargetComponentClass(UClass* Class) 505 | { 506 | auto* Settings = GetMutableDefault(); 507 | Settings->AddComponentClass(Class); 508 | } 509 | 510 | void FCrvModule::InitCategories() 511 | { 512 | FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); 513 | auto IsRelevantClass = [](UClass* Class) 514 | { 515 | return Class->GetClassPathName().ToString().StartsWith("/Script/CtrlReferenceVisualizer"); 516 | }; 517 | 518 | for (auto* const Class : TObjectRange()) 519 | { 520 | if (!IsRelevantClass(Class)) { continue; } 521 | const TSharedRef Section = PropertyModule.FindOrCreateSection( 522 | Class->GetFName(), 523 | TEXT("CtrlReferenceVisualizer"), 524 | LOCTEXT("CtrlReferenceVisualizer", "💛 CTRL Reference Visualizer") 525 | ); 526 | 527 | // Find all categories for this class 528 | for (TFieldIterator It(Class, EFieldIteratorFlags::IncludeSuper); It; ++It) 529 | { 530 | const auto* const Property = *It; 531 | if (!IsRelevantClass(Property->GetOwnerClass())) { continue; } 532 | 533 | auto Category = FObjectEditorUtils::GetCategoryFName(Property).ToString(); 534 | 535 | // prevent crash 536 | if (Category.Contains(TEXT("|"))) 537 | { 538 | Category = Category.Left(Category.Find(TEXT("|"))); 539 | } 540 | Section->AddCategory(FName(*Category.TrimStartAndEnd())); 541 | } 542 | Section->AddCategory(TEXT("Default")); 543 | Section->AddCategory(Class->GetFName()); 544 | } 545 | } 546 | #undef LOCTEXT_NAMESPACE 547 | 548 | IMPLEMENT_MODULE(FCrvModule, CtrlReferenceVisualizer) -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Private/ReferenceVisualizerComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "ReferenceVisualizerComponent.h" 2 | 3 | #include "CrvRefCache.h" 4 | #include "CrvSettings.h" 5 | #include "Selection.h" 6 | 7 | #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 2 8 | // Added in UE 5.2 9 | #include "Materials/MaterialRenderProxy.h" 10 | #endif 11 | 12 | void UReferenceVisualizerEditorSubsystem::OnObjectModified(UObject* Object) 13 | { 14 | if (Cache->WeakRootObjects.Contains(Object)) 15 | { 16 | Cache->Invalidate(FString::Printf(TEXT("Object modified: %s"), *GetDebugName(Object))); 17 | } 18 | } 19 | 20 | void UReferenceVisualizerEditorSubsystem::OnPropertyChanged(UObject* Object, FPropertyChangedEvent& PropertyChangedEvent) 21 | { 22 | const FString PropertyChangeDescription = PropertyChangedEvent.GetMemberPropertyName().ToString(); 23 | if (Cache->WeakRootObjects.Contains(Object)) 24 | { 25 | Cache->Invalidate(FString::Printf(TEXT("Property modified: %s %s"), *GetDebugName(Object), *PropertyChangeDescription)); 26 | } 27 | } 28 | 29 | void UReferenceVisualizerEditorSubsystem::OnSettingsModified(UObject* Object, FProperty* Property) 30 | { 31 | UpdateCache(); 32 | } 33 | 34 | UReferenceVisualizerEditorSubsystem::UReferenceVisualizerEditorSubsystem() 35 | { 36 | Cache = CreateDefaultSubobject(TEXT("Cache")); 37 | MenuCache = CreateDefaultSubobject(TEXT("MenuCache")); 38 | } 39 | 40 | void UReferenceVisualizerEditorSubsystem::Initialize(FSubsystemCollectionBase& Collection) 41 | { 42 | Super::Initialize(Collection); 43 | UCrvSettings* Settings = GetMutableDefault(); 44 | Settings->OnModified.RemoveAll(this); 45 | SettingsModifiedHandle.Reset(); 46 | SettingsModifiedHandle = Settings->OnModified.AddUObject(this, &UReferenceVisualizerEditorSubsystem::OnSettingsModified); 47 | // Settings->AddComponentClass(UReferenceVisualizerComponent::StaticClass()); 48 | // add visualizer to actors when editor selection is changed 49 | USelection::SelectionChangedEvent.AddUObject(this, &UReferenceVisualizerEditorSubsystem::OnSelectionChanged); 50 | FCoreUObjectDelegates::OnObjectModified.AddUObject(this, &UReferenceVisualizerEditorSubsystem::OnObjectModified); 51 | FCoreUObjectDelegates::OnObjectPropertyChanged.AddUObject(this, &UReferenceVisualizerEditorSubsystem::OnPropertyChanged); 52 | } 53 | 54 | void UReferenceVisualizerEditorSubsystem::OnSelectionChanged(UObject* SelectionObject) 55 | { 56 | if (bIsRefreshingSelection) 57 | { 58 | return; 59 | } 60 | TGuardValue ReentrantGuard(bIsRefreshingSelection, true); 61 | UpdateCache(); 62 | } 63 | 64 | void UReferenceVisualizerEditorSubsystem::Deinitialize() 65 | { 66 | Super::Deinitialize(); 67 | } 68 | 69 | void UReferenceVisualizerEditorSubsystem::UpdateCache() 70 | { 71 | Cache->ScheduleUpdate(); 72 | } 73 | 74 | FDebugRenderSceneProxy* UReferenceVisualizerComponent::CreateDebugSceneProxy() 75 | { 76 | FCtrlReferenceVisualizerSceneProxy* DebugProxy = new FCtrlReferenceVisualizerSceneProxy(this); 77 | Lines.Reset(); 78 | CreateLines(GetOwner(), ECrvDirection::Outgoing); 79 | CreateLines(GetOwner(), ECrvDirection::Incoming); 80 | DebugProxy->DrawLines(Lines); 81 | Lines.Compact(); 82 | return DebugProxy; 83 | } 84 | 85 | void UReferenceVisualizerComponent::CreateLines( 86 | const UObject* RootObject, 87 | const ECrvDirection Direction 88 | ) 89 | { 90 | const auto Config = GetDefault(); 91 | if (Direction == ECrvDirection::Outgoing && !Config->bShowOutgoingReferences || Direction == ECrvDirection::Incoming && !Config->bShowIncomingReferences) 92 | { 93 | return; 94 | } 95 | 96 | FVector BaseOffset(0, 0, 10); 97 | TObjectPtr RootObjectPtr = const_cast(RootObject); 98 | auto References = CrvEditorSubsystem->Cache->GetReferences(RootObjectPtr, Direction); 99 | if (!CrvEditorSubsystem->Cache->Contains(RootObjectPtr)) { return; } 100 | if (References.Num() == 0) { return; } 101 | // when multiple roots are selected, don't show incoming references that are also outgoing to same node 102 | if (Direction == ECrvDirection::Incoming && CrvEditorSubsystem->Cache->WeakRootObjects.Num() > 1) 103 | { 104 | References = TSet(References.Array().FilterByPredicate([this, RootObjectPtr](UObject* Ref) 105 | { 106 | const auto OutReferences = CrvEditorSubsystem->Cache->GetReferences(Ref, ECrvDirection::Outgoing); 107 | if (!OutReferences.Num()) { return true; } 108 | return !OutReferences.Contains(RootObjectPtr); 109 | })); 110 | if (References.Num() == 0) { return; } 111 | } 112 | const FVector SourceLocation = FCtrlReferenceVisualizerSceneProxy::GetObjectLocation(RootObject); 113 | // draw links to referenced objects 114 | Lines.Reserve(Lines.Num() + References.Num()); 115 | UE_CLOG(FCrvModule::IsDebugEnabled(), LogCrv, Log, TEXT("References %s %s"), Direction == ECrvDirection::Outgoing ? TEXT(" Out ") : TEXT(" In "), *CtrlRefViz::GetDebugName(RootObject)); 116 | for (const auto DstRef : References) 117 | { 118 | UE_CLOG(FCrvModule::IsDebugEnabled(), LogCrv, Log, TEXT("\t%s"), *CtrlRefViz::GetDebugName(DstRef)); 119 | auto DstLocation = FCtrlReferenceVisualizerSceneProxy::GetObjectLocation(DstRef); 120 | auto Offset = Direction == ECrvDirection::Outgoing ? BaseOffset : -BaseOffset; 121 | auto Line = CreateLine(SourceLocation + Offset, DstLocation + Offset, Direction, DstRef->GetClass()); 122 | Lines.Add(Line); 123 | } 124 | } 125 | 126 | FCrvLine UReferenceVisualizerComponent::CreateLine(const FVector& SrcOrigin, const FVector& DstOrigin, const ECrvDirection Direction, const UClass* Type) 127 | { 128 | if (Direction == ECrvDirection::Incoming) 129 | { 130 | Swap(SrcOrigin, DstOrigin); 131 | } 132 | const FVector LineDirection = (DstOrigin - SrcOrigin).GetSafeNormal(); 133 | const auto Config = GetDefault(); 134 | float Distance = FVector::Distance(SrcOrigin, DstOrigin) - (Config->Style.CircleRadius * 2); 135 | Distance = FMath::Max(1.f, Distance); // clamp distance to be at least 1 136 | auto SpacedSrcOrigin = SrcOrigin + LineDirection * Config->Style.CircleRadius; 137 | auto SpacedDstOrigin = SpacedSrcOrigin + LineDirection * Distance; 138 | auto LineStyle = Config->GetLineStyle(Direction); 139 | auto [LineType, LineColor, LineColorComponent, LineColorObject, LineThickness, ArrowSize, DepthPriority] = LineStyle; 140 | auto Color = LineColor; 141 | if (Type->IsChildOf(AActor::StaticClass())) 142 | { 143 | Color = LineColor; 144 | } 145 | else if (Type->IsChildOf(UActorComponent::StaticClass())) 146 | { 147 | Color = LineColorComponent; 148 | } 149 | else 150 | { 151 | Color = LineColorObject; 152 | } 153 | FCrvLine Line; 154 | Line.Start = SpacedSrcOrigin; 155 | Line.End = SpacedDstOrigin; 156 | Line.Style = LineStyle; 157 | Line.Color = Color.ToFColor(true); 158 | return Line; 159 | } 160 | 161 | void FCtrlReferenceVisualizerSceneProxy::GetDynamicMeshElementsForView( 162 | const FSceneView* View, 163 | const int32 ViewIndex, 164 | const FSceneViewFamily& ViewFamily, 165 | const uint32 VisibilityMap, 166 | FMeshElementCollector& Collector, 167 | FMaterialCache& DefaultMaterialCache, 168 | FMaterialCache& SolidMeshMaterialCache 169 | ) const 170 | { 171 | FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex); 172 | 173 | // Draw Lines 174 | const int32 LinesNum = Lines.Num(); 175 | PDI->AddReserveLines(SDPG_World, LinesNum, false, false); 176 | for (const FDebugLine& Line : Lines) 177 | { 178 | PDI->DrawLine(Line.Start, Line.End, Line.Color, DepthPriorityGroup, Line.Thickness, 0, Line.Thickness > 0); 179 | } 180 | 181 | // Draw Dashed Lines 182 | for (const FDashedLine& Dash : DashedLines) 183 | { 184 | DrawDashedLine(PDI, Dash.Start, Dash.End, Dash.Color, Dash.DashSize, DepthPriorityGroup); 185 | } 186 | 187 | // Draw Arrows 188 | const uint32 ArrowsNum = ArrowLines.Num(); 189 | PDI->AddReserveLines(DepthPriorityGroup, 5 * ArrowsNum, false, false); 190 | for (const FArrowLine& ArrowLine : ArrowLines) 191 | { 192 | // draw a pretty arrow 193 | FVector Dir = ArrowLine.End - ArrowLine.Start; 194 | const float DirMag = Dir.Size(); 195 | Dir /= DirMag; 196 | FVector YAxis, ZAxis; 197 | Dir.FindBestAxisVectors(YAxis, ZAxis); 198 | FMatrix ArrowTM(Dir, YAxis, ZAxis, ArrowLine.Start); 199 | DrawDirectionalArrow( 200 | PDI, 201 | ArrowTM, 202 | ArrowLine.Color, 203 | DirMag, 204 | 8.f, 205 | DepthPriorityGroup, 206 | 1.f 207 | ); 208 | } 209 | 210 | // Draw Stars 211 | for (const FWireStar& Star : Stars) 212 | { 213 | Star.Draw(PDI); 214 | } 215 | 216 | // Draw Cylinders 217 | for (const FWireCylinder& Cylinder : Cylinders) 218 | { 219 | Cylinder.Draw(PDI, (Cylinder.DrawTypeOverride != EDrawType::Invalid) ? Cylinder.DrawTypeOverride : DrawType, DrawAlpha, DefaultMaterialCache, ViewIndex, Collector); 220 | } 221 | 222 | // Draw Boxes 223 | for (const FDebugBox& Box : Boxes) 224 | { 225 | Box.Draw(PDI, (Box.DrawTypeOverride != EDrawType::Invalid) ? Box.DrawTypeOverride : DrawType, DrawAlpha, DefaultMaterialCache, ViewIndex, Collector); 226 | } 227 | 228 | // Draw Cones 229 | TArray Verts; 230 | for (const FCone& Cone : Cones) 231 | { 232 | Cone.Draw(PDI, (Cone.DrawTypeOverride != EDrawType::Invalid) ? Cone.DrawTypeOverride : DrawType, DrawAlpha, DefaultMaterialCache, ViewIndex, Collector, &Verts); 233 | } 234 | 235 | // Draw spheres 236 | for (const FSphere& Sphere : Spheres) 237 | { 238 | if (PointInView(Sphere.Location, View)) 239 | { 240 | Sphere.Draw(PDI, (Sphere.DrawTypeOverride != EDrawType::Invalid) ? Sphere.DrawTypeOverride : DrawType, DrawAlpha, DefaultMaterialCache, ViewIndex, Collector); 241 | } 242 | } 243 | 244 | // Draw Capsules 245 | for (const FCapsule& Capsule : Capsules) 246 | { 247 | if (PointInView(Capsule.Base, View)) 248 | { 249 | Capsule.Draw(PDI, (Capsule.DrawTypeOverride != EDrawType::Invalid) ? Capsule.DrawTypeOverride : DrawType, DrawAlpha, DefaultMaterialCache, ViewIndex, Collector); 250 | } 251 | } 252 | 253 | // Draw Meshes 254 | for (const FMesh& Mesh : Meshes) 255 | { 256 | FDynamicMeshBuilder MeshBuilder(View->GetFeatureLevel()); 257 | MeshBuilder.AddVertices(Mesh.Vertices); 258 | MeshBuilder.AddTriangles(Mesh.Indices); 259 | 260 | // auto&& MeshMaterialCache = Mesh.Color.A == 255 ? SolidMeshMaterialCache : DefaultMaterialCache; 261 | // MeshBuilder.GetMesh(FMatrix::Identity, MeshMaterialCache[Mesh.Color], SDPG_World, false, false, ViewIndex, Collector); 262 | // Parent caches these (only within this function) but let's assume that's not worth it. Will people really 263 | // have lots of meshes with a shared colour in this single context to make it worth it? 264 | const auto MatRenderProxy = new FColoredMaterialRenderProxy(GEngine->WireframeMaterial->GetRenderProxy(), Mesh.Color); 265 | FDynamicMeshBuilderSettings Settings; 266 | Settings.bWireframe = true; 267 | Settings.bUseSelectionOutline = false; 268 | Settings.bUseWireframeSelectionColoring = true; 269 | MeshBuilder.GetMesh(FMatrix::Identity, MatRenderProxy, DepthPriorityGroup, Settings, nullptr, ViewIndex, Collector); 270 | } 271 | } 272 | 273 | void FCtrlReferenceVisualizerSceneProxy::DrawLines(TSet InLines) 274 | { 275 | for (auto Line : InLines) 276 | { 277 | auto [LineType, LineColor, LineColorComponent, LineColorObject, LineThickness, ArrowSize, DepthPriority] = Line.Style; 278 | auto Direction = (Line.End - Line.Start).GetSafeNormal(); 279 | auto Distance = FVector::Distance(Line.Start, Line.End); 280 | 281 | if (LineType == ECrvLineType::Dash) 282 | { 283 | DashedLines.Add(FDebugRenderSceneProxy::FDashedLine(Line.Start, Line.End, Line.Color.ToFColor(true), Distance / 20)); 284 | auto ArrowStart = Line.Start + Direction * (Distance - ArrowSize * UE_GOLDEN_RATIO * 2); 285 | ArrowLines.Add(FDebugRenderSceneProxy::FArrowLine(ArrowStart, Line.End, Line.Color.ToFColor(true))); 286 | } 287 | else if (LineType == ECrvLineType::Arrow) 288 | { 289 | ArrowLines.Add(FDebugRenderSceneProxy::FArrowLine(Line.Start, Line.End, Line.Color.ToFColor(true))); 290 | } 291 | } 292 | } 293 | 294 | FVector FCtrlReferenceVisualizerSceneProxy::GetComponentLocation(const UActorComponent* Component) 295 | { 296 | if (!IsValid(Component)) 297 | { 298 | UE_LOG(LogCrv, Warning, TEXT("Invalid component passed to %s"), *FString(__FUNCTION__)); 299 | return FVector::ZeroVector; 300 | } 301 | const auto Owner = Component->GetOwner(); 302 | // use component location if it is a scene component 303 | const auto SceneComponent = Cast(Component); 304 | return SceneComponent ? SceneComponent->GetComponentLocation() : GetActorOrigin(Owner); 305 | } 306 | 307 | FVector FCtrlReferenceVisualizerSceneProxy::GetActorOrigin(const AActor* Actor) 308 | { 309 | if (!IsValid(Actor)) 310 | { 311 | UE_LOG(LogCrv, Warning, TEXT("Invalid actor passed to %s"), *FString(__FUNCTION__)); 312 | return FVector::ZeroVector; 313 | } 314 | const auto Config = GetDefault(); 315 | if (Config->bUseActorBounds) 316 | { 317 | const auto BoundingBox = Actor->GetComponentsBoundingBox(Config->bIncludeNonCollidingBounds, Config->bIncludeChildActorsInBounds); 318 | if (BoundingBox.IsValid && !BoundingBox.ContainsNaN()) 319 | { 320 | FVector Center; 321 | FVector Extents; 322 | BoundingBox.GetCenterAndExtents(Center, Extents); 323 | if (!Extents.IsNearlyZero()) 324 | { 325 | return Center; 326 | } 327 | } 328 | } 329 | return Actor->GetActorLocation(); 330 | } 331 | 332 | FCtrlReferenceVisualizerSceneProxy::FCtrlReferenceVisualizerSceneProxy(const UPrimitiveComponent* InComponent): FDebugRenderSceneProxy(InComponent) {} 333 | 334 | SIZE_T FCtrlReferenceVisualizerSceneProxy::GetTypeHash() const 335 | { 336 | static size_t UniquePointer; 337 | return reinterpret_cast(&UniquePointer); 338 | } 339 | 340 | FPrimitiveViewRelevance FCtrlReferenceVisualizerSceneProxy::GetViewRelevance(const FSceneView* View) const 341 | { 342 | FPrimitiveViewRelevance Result; 343 | Result.bDrawRelevance = IsShown(View); 344 | Result.bDynamicRelevance = true; 345 | Result.bShadowRelevance = false; 346 | Result.bStaticRelevance = true; 347 | Result.bEditorPrimitiveRelevance = true; 348 | Result.bEditorVisualizeLevelInstanceRelevance = true; 349 | return Result; 350 | } 351 | 352 | uint32 FCtrlReferenceVisualizerSceneProxy::GetMemoryFootprint() const 353 | { 354 | return sizeof(*this) + GetAllocatedSize(); 355 | } 356 | 357 | FVector FCtrlReferenceVisualizerSceneProxy::GetObjectLocation(const UObject* Object) 358 | { 359 | if (const auto Component = Cast(Object)) 360 | { 361 | return GetComponentLocation(Component); 362 | } 363 | else if (const auto Actor = Cast(Object)) 364 | { 365 | return GetActorOrigin(Actor); 366 | } 367 | else if (const auto OwnerComponent = Object->GetTypedOuter()) 368 | { 369 | return GetComponentLocation(OwnerComponent); 370 | } 371 | else if (const auto OwnerActor = Object->GetTypedOuter()) 372 | { 373 | return GetActorOrigin(OwnerActor); 374 | } 375 | 376 | return FVector::ZeroVector; 377 | } 378 | 379 | FBoxSphereBounds UReferenceVisualizerComponent::CalcBounds(const FTransform& LocalToWorld) const 380 | { 381 | auto SphereBounds = Super::CalcBounds(LocalToWorld); 382 | if (!GetOwner()) { return SphereBounds; } 383 | if (!CrvEditorSubsystem) 384 | { 385 | return SphereBounds; 386 | } 387 | const auto World = GetWorld(); 388 | if (!World) { return SphereBounds; } 389 | if (!CrvEditorSubsystem->Cache->Contains(GetOwner())) 390 | { 391 | return SphereBounds; 392 | } 393 | 394 | FBoxSphereBounds::Builder DebugBoundsBuilder; 395 | DebugBoundsBuilder += SphereBounds; 396 | FVector Origin; 397 | FVector BoxExtent; 398 | GetOwner()->GetActorBounds(false, Origin, BoxExtent); 399 | FBox ActorBounds = FBox::BuildAABB(Origin, BoxExtent); 400 | DebugBoundsBuilder += ActorBounds; 401 | for (auto [Start, End, Color, Style] : Lines) 402 | { 403 | DebugBoundsBuilder += Start; 404 | DebugBoundsBuilder += End; 405 | } 406 | FBoxSphereBounds NewBounds = DebugBoundsBuilder; //.TransformBy(LocalToWorld); 407 | NewBounds = NewBounds.ExpandBy(100); 408 | return NewBounds; 409 | } 410 | 411 | void UReferenceVisualizerComponent::OnRegister() 412 | { 413 | Super::OnRegister(); 414 | CrvEditorSubsystem = GEditor->GetEditorSubsystem(); 415 | CrvEditorSubsystem->Cache->OnCacheUpdated.AddUObject(this, &UReferenceVisualizerComponent::MarkRenderStateDirty); 416 | CrvEditorSubsystem->Cache->ScheduleUpdate(); 417 | } 418 | 419 | void UReferenceVisualizerComponent::OnUnregister() 420 | { 421 | Super::OnUnregister(); 422 | if (CrvEditorSubsystem) 423 | { 424 | CrvEditorSubsystem->Cache->ScheduleUpdate(); 425 | } 426 | } 427 | 428 | UReferenceVisualizerComponent::UReferenceVisualizerComponent() 429 | { 430 | PrimaryComponentTick.bCanEverTick = false; 431 | bVisibleInReflectionCaptures = false; 432 | bVisibleInRayTracing = false; 433 | bVisibleInRealTimeSkyCaptures = false; 434 | bAutoActivate = true; 435 | AlwaysLoadOnClient = false; 436 | bIsEditorOnly = true; 437 | 438 | SetHiddenInGame(true); 439 | 440 | #if WITH_EDITOR 441 | // Do not show bounding box for better visibility 442 | SetIsVisualizationComponent(true); 443 | 444 | // Disable use of bounds to focus to avoid de-zoom 445 | SetIgnoreBoundsForEditorFocus(true); 446 | 447 | #endif 448 | #if WITH_EDITORONLY_DATA 449 | // Show sprite for this component to visualize it when empty 450 | bVisualizeComponent = true; 451 | #endif 452 | } 453 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Public/CrvCommands.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "Framework/Commands/Commands.h" 5 | 6 | class FCrvCommands : public TCommands 7 | { 8 | public: 9 | TSharedPtr ToggleReferenceVisualizer; 10 | FCrvCommands() 11 | : TCommands( 12 | TEXT("FCrvCommands"), 13 | NSLOCTEXT("ReferenceVisualizer", "ReferenceVisualizerCommands", "Reference Visualizer Commands"), 14 | NAME_None, 15 | FAppStyle::GetAppStyleSetName() 16 | ) 17 | { 18 | } 19 | 20 | virtual ~FCrvCommands() override = default; 21 | 22 | void ToggleEnabled_Execute(); 23 | bool ToggleEnabled_CanExecute(); 24 | bool ToggleEnabled_IsChecked(); 25 | virtual void RegisterCommands() override; 26 | 27 | TSharedPtr CommandList; 28 | }; -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Public/CrvHitProxy.h: -------------------------------------------------------------------------------- 1 |  2 | #pragma once 3 | 4 | #include "CoreMinimal.h" 5 | #include "ComponentVisualizer.h" 6 | 7 | struct CTRLREFERENCEVISUALIZER_API HCrvHitProxy : public HComponentVisProxy 8 | { 9 | DECLARE_HIT_PROXY(); 10 | const TWeakObjectPtr LeafObject; 11 | const TWeakObjectPtr RootObject; 12 | 13 | DECLARE_DELEGATE(FOnHitProxyHover) 14 | FOnHitProxyHover OnHover; 15 | 16 | bool IsValid() const 17 | { 18 | return LeafObject.IsValid() && RootObject.IsValid(); 19 | } 20 | 21 | HCrvHitProxy(const UActorComponent* ParentComponent, const UObject* InRootObject, const UObject* InLeafObject) 22 | : HComponentVisProxy(ParentComponent, HPP_Foreground), 23 | LeafObject(InLeafObject), 24 | RootObject(InRootObject) 25 | { 26 | } 27 | 28 | virtual EMouseCursor::Type GetMouseCursor() override 29 | { 30 | if (OnHover.IsBound()) 31 | { 32 | OnHover.Execute(); 33 | } 34 | return EMouseCursor::EyeDropper; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Public/CrvRefSearch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "CrvUtils.h" 5 | #include "UObject/ReferenceChainSearch.h" 6 | 7 | using namespace CtrlRefViz; 8 | 9 | struct FCrvMenuItem 10 | { 11 | FName Name; 12 | FText Label; 13 | FText ToolTip; 14 | FSlateIcon Icon; 15 | FUIAction Action; 16 | }; 17 | 18 | namespace CtrlRefViz::Search 19 | { 20 | FString LexToString(const FReferenceChainSearch::FReferenceChain* Chain); 21 | bool IsExternal(const FReferenceChainSearch::FReferenceChain* Chain); 22 | FCrvSet FindTargetObjects(UObject* RootObject); 23 | } 24 | 25 | class FCrvRefSearch 26 | { 27 | public: 28 | static FCrvSet GetSelectionSet(); 29 | 30 | static void FindOutRefs(FCrvSet RootObjects, FCrvObjectGraph& Graph); 31 | static void FindInRefs(FCrvSet RootObjects, FCrvObjectGraph& Graph); 32 | 33 | static FCrvMenuItem MakeMenuEntry(const UObject* Parent, const UObject* Object); 34 | static bool CanDisplayReference(const UObject* RootObject, const UObject* LeafObject); 35 | }; 36 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Public/CrvSettings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "Engine/DeveloperSettingsBackedByCVars.h" 5 | #include "Templates/TypeHash.h" 6 | #include "UObject/ReferenceChainSearch.h" 7 | 8 | #include "CrvSettings.generated.h" 9 | 10 | UENUM() 11 | enum class ECrvDirection: uint8 12 | { 13 | Incoming, 14 | Outgoing, 15 | }; 16 | 17 | UENUM() 18 | enum class ECrvMode: uint8 19 | { 20 | OnlySelected, // Only show references to/from the selected actor or component 21 | SelectedOrAll, // Show references to/from the selected actor or component, or all references if nothing is selected 22 | All, // Show all references 23 | }; 24 | 25 | UENUM() 26 | enum class ECrvLineType: uint8 27 | { 28 | Dash, 29 | Arrow, 30 | }; 31 | 32 | USTRUCT() 33 | struct FCrvLineStyle 34 | { 35 | GENERATED_BODY() 36 | 37 | FCrvLineStyle() = default; 38 | 39 | FCrvLineStyle( 40 | const ECrvLineType LineType, 41 | const FLinearColor LineColor, 42 | const FLinearColor LineColorComponent, 43 | const FLinearColor LineColorObject, 44 | const float LineThickness, 45 | const float ArrowSize, 46 | const ESceneDepthPriorityGroup DepthPriority 47 | ) 48 | : LineType(LineType), 49 | LineColor(LineColor), 50 | LineColorComponent(LineColorComponent), 51 | LineColorObject(LineColorObject), 52 | LineThickness(LineThickness), 53 | ArrowSize(ArrowSize), 54 | DepthPriority(DepthPriority) {} 55 | 56 | UPROPERTY(Config, EditAnywhere, Category = "Style | General") 57 | ECrvLineType LineType = ECrvLineType::Arrow; 58 | 59 | UPROPERTY(Config, EditAnywhere, Category = "Style | General", DisplayName = "Line Color") 60 | FLinearColor LineColor = FLinearColor::Green; 61 | 62 | UPROPERTY(Config, EditAnywhere, Category = "Style | General", DisplayName = "Line Color (Component)") 63 | FLinearColor LineColorComponent = FColor::Emerald; 64 | 65 | UPROPERTY(Config, EditAnywhere, Category = "Style | General", DisplayName = "Line Color (Object)") 66 | FLinearColor LineColorObject = FColor::Cyan; 67 | 68 | UPROPERTY(Config, EditAnywhere, Category = "Style | General", meta = (ClampMin = "0", UIMin = "0", UIMax = "10", EditCondition = "LineType != ECrvLineStyle::Dash")) 69 | float LineThickness = 2.f; 70 | 71 | UPROPERTY(Config, EditAnywhere, Category = "Style | General", meta = (ClampMin = "0", UIMin = "0", UIMax = "100", EditCondition = "LineType == ECrvLineStyle::Arrow")) 72 | float ArrowSize = 10.f; 73 | 74 | UPROPERTY(Config, EditAnywhere, Category = "Style | General") 75 | TEnumAsByte DepthPriority = ESceneDepthPriorityGroup::SDPG_Foreground; 76 | 77 | friend bool operator==(const FCrvLineStyle& Lhs, const FCrvLineStyle& RHS) 78 | { 79 | return Lhs.LineType == RHS.LineType 80 | && Lhs.LineColor == RHS.LineColor 81 | && Lhs.LineColorComponent == RHS.LineColorComponent 82 | && Lhs.LineColorObject == RHS.LineColorObject 83 | && Lhs.LineThickness == RHS.LineThickness 84 | && Lhs.ArrowSize == RHS.ArrowSize 85 | && Lhs.DepthPriority == RHS.DepthPriority; 86 | } 87 | 88 | friend bool operator!=(const FCrvLineStyle& Lhs, const FCrvLineStyle& RHS) 89 | { 90 | return !(Lhs == RHS); 91 | } 92 | 93 | friend uint32 GetTypeHash(const FCrvLineStyle& Arg) 94 | { 95 | uint32 Hash = HashCombine(GetTypeHash(Arg.LineType), GetTypeHash(Arg.LineColor)); 96 | Hash = HashCombine(Hash, GetTypeHash(Arg.LineColorComponent)); 97 | Hash = HashCombine(Hash, GetTypeHash(Arg.LineColorObject)); 98 | Hash = HashCombine(Hash, GetTypeHash(Arg.LineThickness)); 99 | Hash = HashCombine(Hash, GetTypeHash(Arg.ArrowSize)); 100 | Hash = HashCombine(Hash, GetTypeHash(Arg.DepthPriority)); 101 | return Hash; 102 | } 103 | 104 | static FCrvLineStyle DefaultOutgoingLineStyle; 105 | 106 | static FCrvLineStyle DefaultIncomingLineStyle; 107 | }; 108 | 109 | 110 | USTRUCT() 111 | struct FCrvStyleSettings 112 | { 113 | GENERATED_BODY() 114 | 115 | FCrvStyleSettings(); 116 | 117 | UPROPERTY(Config, EditAnywhere, Category = "Style | General") 118 | FCrvLineStyle LineStyleOutgoing = FCrvLineStyle::DefaultOutgoingLineStyle; 119 | 120 | UPROPERTY(Config, EditAnywhere, Category = "Style | General") 121 | FCrvLineStyle LineStyleIncoming = FCrvLineStyle::DefaultIncomingLineStyle; 122 | 123 | /* Draw circles around current target & references. */ 124 | UPROPERTY(Config, EditAnywhere, Category = "Style | Target Circles") 125 | bool bDrawTargetCircles = false; 126 | 127 | UPROPERTY( 128 | Config, 129 | EditAnywhere, 130 | Category = "Style | Target Circles", 131 | meta = (ClampMin = "0", UIMin = "0", UIMax = "1000", EditCondition = "bDrawTargetCircles") 132 | ) 133 | float CircleRadius = 50.f; 134 | 135 | UPROPERTY( 136 | Config, 137 | EditAnywhere, 138 | Category = "Style | Target Circles", 139 | meta = (ClampMin = "3", UIMin = "3", UIMax = "100", EditCondition = "bDrawTargetCircles") 140 | ) 141 | float CircleResolution = 32.f; 142 | 143 | UPROPERTY( 144 | Config, 145 | EditAnywhere, 146 | Category = "Style | Target Circles", 147 | meta = (ClampMin = "0", UIMin = "0", UIMax = "10", EditCondition = "bDrawTargetCircles") 148 | ) 149 | float CircleLineThickness = 1.f; 150 | /* Circle around the currently selected actor or scene component */ 151 | UPROPERTY(Config, EditAnywhere, Category = "Style | Target Circles", meta = (EditCondition = "bDrawTargetCircles")) 152 | FLinearColor CurrentCircleColor = FLinearColor::Gray; 153 | 154 | /* Circle around referenced actors or scene components */ 155 | UPROPERTY(Config, EditAnywhere, Category = "Style | Target Circles", meta = (EditCondition = "bDrawTargetCircles")) 156 | FLinearColor LinkedCircleColor = FLinearColor::Transparent; 157 | }; 158 | 159 | USTRUCT() 160 | struct FCrvTargetSettings 161 | { 162 | explicit FCrvTargetSettings(); 163 | 164 | GENERATED_BODY() 165 | 166 | UPROPERTY(Config, EditAnywhere, Category = "Targets") 167 | TArray> IgnoreReferencesToClasses; 168 | 169 | /* The target actor component classes to enable with the reference viewer debug visualization. */ 170 | UPROPERTY(Config, EditAnywhere, AdvancedDisplay, Category = "Targets") 171 | TArray> TargetComponentClasses; 172 | }; 173 | 174 | UENUM(meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true")) 175 | enum class EReferenceChainSearchMode_K2: uint32 176 | { 177 | // Returns all reference chains found 178 | Default = 0, 179 | // Returns only reference chains from external objects 180 | ExternalOnly = 1 << 0, 181 | // Returns only the shortest reference chain for each rooted object 182 | Shortest = 1 << 1, 183 | // Returns only the longest reference chain for each rooted object 184 | Longest = 1 << 2, 185 | // Returns only the direct referencers 186 | Direct = 1 << 3, 187 | // Returns complete chains. (Ignoring non GC objects) 188 | FullChain = 1 << 4, 189 | // Returns the shortest path to a garbage object from which the target object is reachable 190 | ShortestToGarbage = 1 << 5, 191 | // Attempts to find a plausible path to the target object with minimal memory usage 192 | // E.g. returns a direct external reference to the target object if one is found 193 | // otherwise returns an external reference to an inner of the target object 194 | Minimal = 1 << 6, 195 | // Skips the disregard-for-GC set that will never be GCd and whose outgoing references are not checked during GC 196 | GCOnly = 1 << 7, 197 | 198 | // Print results 199 | PrintResults = 1 << 16, 200 | // Print ALL results (in some cases there may be thousands of reference chains) 201 | PrintAllResults = 1 << 17, 202 | }; 203 | 204 | namespace CtrlRefViz 205 | { 206 | inline FString LexToString(const EReferenceChainSearchMode_K2 Mode) 207 | { 208 | return UEnum::GetValueOrBitfieldAsString(Mode); 209 | } 210 | 211 | inline FString LexToString(EReferenceChainSearchMode Mode) 212 | { 213 | return LexToString(static_cast(Mode)); 214 | } 215 | } 216 | 217 | /** 218 | * 219 | */ 220 | UCLASS( 221 | Config = EditorPerProjectUserSettings, 222 | PerObjectConfig, 223 | meta = (DisplayName = "Ctrl - Reference Visualizer Settings") 224 | ) 225 | class CTRLREFERENCEVISUALIZER_API UCrvSettings : public UDeveloperSettingsBackedByCVars 226 | { 227 | GENERATED_BODY() 228 | 229 | public: 230 | UCrvSettings(); 231 | 232 | virtual FName GetContainerName() const override 233 | { 234 | return FName("Editor"); 235 | } 236 | 237 | virtual FText GetSectionText() const override; 238 | 239 | virtual FText GetSectionDescription() const override; 240 | 241 | UFUNCTION() 242 | void AddComponentClass(const TSoftClassPtr& ComponentClass); 243 | 244 | void SetEnabled(bool bNewEnabled); 245 | 246 | void ToggleEnabled(); 247 | 248 | void SetShowIncomingReferences(bool bNewShowIncomingReferences); 249 | 250 | void SetShowOutgoingReferences(bool bNewShowOutgoingReferences); 251 | 252 | void Refresh(); 253 | 254 | void UpdateTargets(); 255 | 256 | UFUNCTION() 257 | void CleanTargets(); 258 | 259 | bool IsEnabled() const; 260 | bool GetAutoAddComponents() const; 261 | 262 | /* Whether the reference viewer display is enabled */ 263 | UPROPERTY(Config, EditAnywhere, Category = "General", meta = (ConsoleVariable = "ctrl.ReferenceVisualizer")) 264 | bool bIsEnabled = true; 265 | 266 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "General", meta=(MultiLine=true)) 267 | FText Help; 268 | 269 | UPROPERTY(Config, EditAnywhere, Category = "General") 270 | ECrvMode Mode = ECrvMode::SelectedOrAll; 271 | 272 | // automatically add/remove ReferenceVisualizerComponent to actors 273 | UPROPERTY(Config, EditAnywhere, Category = "General") 274 | bool bAutoAddComponents = true; 275 | 276 | // show recursive references to/from the selected actor or component 277 | // UPROPERTY(Config, EditAnywhere, Category = "General", meta = (ClampMin = "1", UIMin = "1", UIMax = "100", EditCondition = "Mode == ECrvMode::OnlySelected || Mode == ECrvMode::SelectedOrAll")) 278 | // int32 Depth = 1; 279 | 280 | UFUNCTION(BlueprintCallable, Exec, CallInEditor) 281 | void Documentation() const; 282 | 283 | UPROPERTY(Config, EditAnywhere, Category = "General", DisplayName = "Visualize Outgoing References") 284 | bool bShowOutgoingReferences = true; 285 | 286 | UPROPERTY(Config, EditAnywhere, Category = "General", DisplayName = "Visualize Incoming References (Potentially Slow)") 287 | bool bShowIncomingReferences = true; 288 | 289 | UPROPERTY(Config, EditAnywhere, Category = "General", DisplayName = "Move Camera to Reference On Select") 290 | bool bMoveViewportCameraToReference = false; 291 | 292 | /* Use the actor bounds to determine center points, otherwise uses actor/scene component location */ 293 | UPROPERTY(Config, EditAnywhere, Category = "General", DisplayName = "Use Center of Actor Bounds as Target Point", Experimental) 294 | bool bUseActorBounds = false; 295 | 296 | UPROPERTY(Config, EditAnywhere, Category = "General|Bounds", meta = (EditCondition = "bUseActorBounds"), DisplayName = "Include Non-Colliding Components") 297 | bool bIncludeNonCollidingBounds = false; 298 | 299 | UPROPERTY(Config, EditAnywhere, Category = "General|Bounds", meta = (EditCondition = "bUseActorBounds"), DisplayName = "Include Child Actors") 300 | bool bIncludeChildActorsInBounds = false; 301 | 302 | /* Controls the style of the reference viewer debug drawing */ 303 | UPROPERTY(Config, EditAnywhere, Category = "Style", meta = (ShowOnlyInnerProperties)) 304 | FCrvStyleSettings Style; 305 | 306 | UPROPERTY(Config, EditAnywhere, Category = "General|Filtering", meta = (ShowOnlyInnerProperties)) 307 | FCrvTargetSettings TargetSettings; 308 | /* Include recursive references to child actors and components */ 309 | UPROPERTY(Config, EditAnywhere, Category = "General|Filtering") 310 | bool bIsRecursive = true; 311 | // /* Include references from parent actor, rather than just the selected component */ 312 | // UPROPERTY(Config, EditAnywhere, Category = "General|Filtering") 313 | // bool bAlwaysIncludeReferencesFromParent = false; 314 | 315 | UPROPERTY(Config, EditAnywhere, Category = "General|Filtering") 316 | bool bShowComponents = true; 317 | 318 | UPROPERTY(Config, EditAnywhere, Category = "General|Filtering") 319 | bool bShowObjects = false; 320 | 321 | // UPROPERTY(Config, EditAnywhere, Category = "General|Filtering", meta = (EditCondition = "bIsRecursive")) 322 | // bool bWalkComponents = true; 323 | // 324 | // UPROPERTY(Config, EditAnywhere, Category = "General|Filtering", meta = (EditCondition = "bIsRecursive")) 325 | // bool bWalkSceneChildComponents = true; 326 | // 327 | // UPROPERTY(Config, EditAnywhere, Category = "General|Filtering", meta = (EditCondition = "bIsRecursive")) 328 | // bool bWalkChildActors = true; 329 | 330 | UPROPERTY(Config, EditAnywhere, Category = "General|Filtering") 331 | bool bWalkObjectProperties = true; 332 | 333 | /* Skip ObjectArchetype references */ 334 | UPROPERTY(Config, EditAnywhere, Category = "General|Filtering") 335 | bool bIgnoreArchetype = true; 336 | 337 | /* Skip transient properties */ 338 | UPROPERTY(Config, EditAnywhere, Category = "General|Filtering") 339 | bool bIgnoreTransient = true; 340 | 341 | UPROPERTY(Config, EditAnywhere, AdvancedDisplay, Category = "General") 342 | bool bDebugEnabled = false; 343 | 344 | UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "General") 345 | bool bRefreshEnabled = true; 346 | 347 | /* Delegate called when this settings object is modified */ 348 | DECLARE_MULTICAST_DELEGATE_TwoParams(UCrvSettingsModified, UObject*, FProperty*); 349 | UCrvSettingsModified OnModified; 350 | 351 | FCrvLineStyle GetLineStyle(ECrvDirection Direction) const; 352 | 353 | #if WITH_EDITOR 354 | virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; 355 | 356 | void CVarSink(); 357 | #endif 358 | virtual void PostInitProperties() override; 359 | 360 | private: 361 | bool bIsUpdating = false; 362 | }; 363 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Public/CrvStyle.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Styling/SlateStyle.h" 7 | 8 | class CTRLREFERENCEVISUALIZER_API FCrvStyle : public FSlateStyleSet 9 | { 10 | public: 11 | explicit FCrvStyle(); 12 | 13 | static void Startup(); 14 | static void Register(); 15 | static void Shutdown(); 16 | 17 | static TSharedPtr Get(); 18 | virtual const FName& GetStyleSetName() const override; 19 | void Initialize(); 20 | 21 | private: 22 | static TSharedPtr StyleSet; 23 | }; 24 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Public/CtrlReferenceVisualizer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "CrvRefCache.h" 5 | #include "ReferenceVisualizerComponent.h" 6 | #include "HAL/IConsoleManager.h" 7 | #include "Modules/ModuleManager.h" 8 | 9 | class UToolMenu; 10 | class FCrvDebugVisualizer; 11 | class UReferenceVisualizerComponent; 12 | class UCrvSettings; 13 | class UCrvRefCache; 14 | 15 | DECLARE_LOG_CATEGORY_EXTERN(LogCrv, Log, All); 16 | 17 | class FCrvModule : public IModuleInterface 18 | { 19 | public: 20 | void MakeReferenceListSubMenu(UToolMenu* SubMenu, ECrvDirection Direction) const; 21 | void SelectReference(UObject* Object); 22 | void InitActorMenu() const; 23 | void MakeActorOptionsSubmenu(UToolMenu* Menu) const; 24 | void InitLevelMenus() const; 25 | 26 | void InitTab(); 27 | 28 | void OnPostEngineInit(); 29 | /** IModuleInterface implementation */ 30 | virtual void StartupModule() override; 31 | virtual void ShutdownModule() override; 32 | /** end IModuleInterface implementation */ 33 | 34 | virtual void AddTargetComponentClass(class UClass* Class); 35 | 36 | /** 37 | * Singleton-like access to this module's interface. This is just for convenience! 38 | * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. 39 | * 40 | * @return Returns singleton instance, loading the module on demand if needed 41 | */ 42 | static FCrvModule& Get() 43 | { 44 | return FModuleManager::LoadModuleChecked("CtrlReferenceVisualizer"); 45 | } 46 | 47 | /** 48 | * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. 49 | * 50 | * @return True if the module is loaded and ready to use 51 | */ 52 | static bool IsAvailable() 53 | { 54 | return FModuleManager::Get().IsModuleLoaded("CtrlReferenceVisualizer"); 55 | } 56 | 57 | static bool IsEnabled(); 58 | static bool IsDebugEnabled(); 59 | 60 | protected: 61 | static void InitCategories(); 62 | FToolMenuEntry GetSettingsMenuEntry() const; 63 | TArray RegisteredClasses; 64 | FDelegateHandle SettingsModifiedHandle; 65 | }; 66 | 67 | -------------------------------------------------------------------------------- /Source/CtrlReferenceVisualizer/Public/ReferenceVisualizerComponent.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "CrvRefCache.h" 7 | #include "CrvSettings.h" 8 | #include "DebugRenderSceneProxy.h" 9 | #include "Components/ActorComponent.h" 10 | #include "Debug/DebugDrawComponent.h" 11 | #include "Templates/TypeHash.h" 12 | #include "ReferenceVisualizerComponent.generated.h" 13 | 14 | class UReferenceVisualizerComponent; 15 | class UCrvRefCache; 16 | 17 | UCLASS() 18 | class UReferenceVisualizerEditorSubsystem : public UEditorSubsystem 19 | { 20 | GENERATED_BODY() 21 | 22 | public: 23 | UReferenceVisualizerEditorSubsystem(); 24 | 25 | UPROPERTY(Transient) 26 | TObjectPtr Cache; 27 | UPROPERTY(Transient) 28 | TObjectPtr MenuCache; 29 | 30 | virtual void Initialize(FSubsystemCollectionBase& Collection) override; 31 | virtual void Deinitialize() override; 32 | 33 | void UpdateCache(); 34 | 35 | void OnObjectModified(UObject* Object); 36 | void OnPropertyChanged(UObject* Object, FPropertyChangedEvent& PropertyChangedEvent); 37 | void OnSettingsModified(UObject* Object, FProperty* Property); 38 | void OnSelectionChanged(UObject* SelectionObject); 39 | 40 | private: 41 | bool bIsRefreshingSelection = false; 42 | FDelegateHandle SettingsModifiedHandle; 43 | FTimerHandle UpdateCacheNextTickHandle; 44 | }; 45 | 46 | USTRUCT() 47 | struct FCrvLine 48 | { 49 | GENERATED_BODY() 50 | UPROPERTY() 51 | FVector Start; 52 | UPROPERTY() 53 | FVector End; 54 | UPROPERTY() 55 | FLinearColor Color; 56 | UPROPERTY() 57 | FCrvLineStyle Style; 58 | 59 | friend bool operator==(const FCrvLine& Lhs, const FCrvLine& RHS) 60 | { 61 | return Lhs.Start == RHS.Start 62 | && Lhs.End == RHS.End 63 | && Lhs.Color == RHS.Color 64 | && Lhs.Style == RHS.Style; 65 | } 66 | 67 | friend bool operator!=(const FCrvLine& Lhs, const FCrvLine& RHS) 68 | { 69 | return !(Lhs == RHS); 70 | } 71 | 72 | friend uint32 GetTypeHash(const FCrvLine& Arg) 73 | { 74 | uint32 Hash = HashCombine(GetTypeHash(Arg.Start), GetTypeHash(Arg.End)); 75 | Hash = HashCombine(Hash, GetTypeHash(Arg.Color)); 76 | Hash = HashCombine(Hash, GetTypeHash(Arg.Style)); 77 | return Hash; 78 | } 79 | }; 80 | 81 | /** 82 | * Component used to visualize references in the editor. 83 | * This component is hidden and not blueprintable. 84 | * This component is added/removed automatically on selection, to trigger the visualizer. 85 | */ 86 | UCLASS(ClassGroup = Debug, NotBlueprintable, NotBlueprintType, NotEditInlineNew, meta = (BlueprintSpawnableComponent)) 87 | class CTRLREFERENCEVISUALIZER_API UReferenceVisualizerComponent : public UDebugDrawComponent 88 | { 89 | GENERATED_BODY() 90 | 91 | public: 92 | virtual FDebugRenderSceneProxy* CreateDebugSceneProxy() override; 93 | 94 | FCrvLine CreateLine(const FVector& SrcOrigin, const FVector& DstOrigin, ECrvDirection Direction, const UClass* Type); 95 | 96 | void CreateLines(const UObject* RootObject, ECrvDirection Direction); 97 | 98 | virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const override; 99 | virtual void OnRegister() override; 100 | virtual void OnUnregister() override; 101 | 102 | UPROPERTY(Transient) 103 | TObjectPtr CrvEditorSubsystem; 104 | 105 | UPROPERTY(Transient) 106 | TSet Lines; 107 | 108 | UReferenceVisualizerComponent(); 109 | }; 110 | 111 | class FCtrlReferenceVisualizerSceneProxy : public FDebugRenderSceneProxy 112 | { 113 | public: 114 | static FVector GetComponentLocation(const UActorComponent* Component); 115 | static FVector GetActorOrigin(const AActor* Actor); 116 | 117 | FCtrlReferenceVisualizerSceneProxy(const UPrimitiveComponent* InComponent); 118 | 119 | virtual SIZE_T GetTypeHash() const override; 120 | 121 | virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override; 122 | 123 | virtual uint32 GetMemoryFootprint() const override; 124 | 125 | virtual void GetDynamicMeshElementsForView( 126 | const FSceneView* View, 127 | int32 ViewIndex, 128 | const FSceneViewFamily& ViewFamily, 129 | uint32 VisibilityMap, 130 | FMeshElementCollector& Collector, 131 | FMaterialCache& DefaultMaterialCache, 132 | FMaterialCache& SolidMeshMaterialCache 133 | ) const override; 134 | 135 | void DrawLines(TSet InLines); 136 | 137 | static FVector GetObjectLocation(const UObject* Object); 138 | 139 | private: 140 | ESceneDepthPriorityGroup DepthPriorityGroup = SDPG_World; 141 | 142 | protected: 143 | inline static bool bMultiple = false; 144 | }; 145 | --------------------------------------------------------------------------------