├── .gitattributes ├── .gitignore ├── Assembly-CSharp-Editor.csproj ├── Assembly-CSharp.csproj ├── Assets ├── Example.meta ├── Example │ ├── TestCallChain.cs │ └── TestCallChain.cs.meta ├── Scenes.meta ├── Scenes │ ├── SampleScene.unity │ └── SampleScene.unity.meta ├── UnityEventCallRedirector.Attribute.meta ├── UnityEventCallRedirector.Attribute │ ├── UnityEventCallRedirectAttribute.cs │ ├── UnityEventCallRedirectAttribute.cs.meta │ ├── UnityEventCallRedirector.Attribute.asmdef │ └── UnityEventCallRedirector.Attribute.asmdef.meta ├── UnityEventCallRedirector.Fody.meta ├── UnityEventCallRedirector.Fody │ ├── MethodBodyExtensions.cs │ ├── MethodBodyExtensions.cs.meta │ ├── ModuleWeaver.cs │ ├── ModuleWeaver.cs.meta │ ├── RequiredDll.meta │ ├── RequiredDll │ │ ├── FodyHelpers_debug.dll │ │ ├── FodyHelpers_debug.dll.meta │ │ ├── Mono.Cecil_debug.dll │ │ └── Mono.Cecil_debug.dll.meta │ ├── UnityEventCallRedirector.Fody.asmdef │ └── UnityEventCallRedirector.Fody.asmdef.meta ├── UnityEventCallRedirector.meta └── UnityEventCallRedirector │ ├── EditorButton.meta │ ├── EditorButton │ ├── Editor.meta │ ├── Editor │ │ ├── InspectorButton.cs │ │ └── InspectorButton.cs.meta │ ├── EditorButtonAttribute.cs │ └── EditorButtonAttribute.cs.meta │ ├── EventInterceptor.cs │ ├── EventInterceptor.cs.meta │ ├── FodyWeavers.xml │ ├── FodyWeavers.xml.meta │ ├── ProfilerUtilities.meta │ └── ProfilerUtilities │ ├── FrameFinder.cs │ ├── FrameFinder.cs.meta │ ├── FrameItemSelected.cs │ ├── FrameItemSelected.cs.meta │ ├── ProfileData.cs │ ├── ProfileData.cs.meta │ ├── ProfilerWindowInterface.cs │ └── ProfilerWindowInterface.cs.meta ├── LICENSE ├── Packages └── manifest.json ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── Physics2DSettings.asset ├── PresetManager.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset ├── UnityConnectSettings.asset ├── VFXManager.asset └── XRSettings.asset ├── UnityEventCallRedirector.Attribute.csproj ├── UnityEventCallRedirector.Fody.csproj ├── VisualisingUnityCallChains.sln ├── _github ├── UnityEventCallRedirector.unitypackage ├── ViewingUnityEventInvokeCallsInProfiler_VRTK.gif ├── ViewingUnityEventInvokeCallsInProfiler_workflow.gif ├── event-call-chain-profiler-view.png ├── event-call-chain-profiler-view_small.png └── event-call-chain-setup.png └── readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Library 2 | /Temp 3 | /.vs/VisualisingUnityCallChains/v16 4 | /Logs 5 | /obj/Debug 6 | /.vs/VisualisingUnityCallChains/config 7 | -------------------------------------------------------------------------------- /Assets/Example.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a6b22176de812434a8e813134a736df1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Example/TestCallChain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Threading; 4 | using UnityEngine; 5 | using UnityEngine.Events; 6 | 7 | public class TestCallChain : MonoBehaviour 8 | { 9 | [Serializable] 10 | public class UnityEvent : UnityEvent 11 | { 12 | 13 | } 14 | 15 | public UnityEvent Event = new UnityEvent(); 16 | 17 | public bool RunCallChain; 18 | 19 | void Start() 20 | { 21 | if (RunCallChain) 22 | { 23 | StartCoroutine(ExecuteEvent()); 24 | } 25 | } 26 | 27 | public void InvokeEvent(int number) 28 | { 29 | Thread.Sleep(10); 30 | Debug.Log($"{name} - {nameof(InvokeEvent)}: {number}"); 31 | Event?.Invoke(number); 32 | } 33 | 34 | public void PrintChainEnd(int number) 35 | { 36 | Thread.Sleep(10); 37 | Debug.Log($"{name} - Chain End"); 38 | } 39 | 40 | IEnumerator ExecuteEvent() 41 | { 42 | while (true) 43 | { 44 | if (!RunCallChain) yield break; 45 | 46 | InvokeEvent(Time.frameCount); 47 | yield return new WaitForSeconds(1); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Assets/Example/TestCallChain.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b400b8ba9aff38240bfc80f29fc38d22 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fa1b2f89a134ec841b2687fceb67d2ab 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scenes/SampleScene.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 11 47 | m_GIWorkflowMode: 0 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 1 55 | m_EnableRealtimeLightmaps: 0 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 1 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 1 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 500 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 500 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 2 83 | m_PVRDenoiserTypeDirect: 0 84 | m_PVRDenoiserTypeIndirect: 0 85 | m_PVRDenoiserTypeAO: 0 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 0 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ExportTrainingData: 0 98 | m_TrainingDataDestination: TrainingData 99 | m_LightingDataAsset: {fileID: 0} 100 | m_UseShadowmask: 1 101 | --- !u!196 &4 102 | NavMeshSettings: 103 | serializedVersion: 2 104 | m_ObjectHideFlags: 0 105 | m_BuildSettings: 106 | serializedVersion: 2 107 | agentTypeID: 0 108 | agentRadius: 0.5 109 | agentHeight: 2 110 | agentSlope: 45 111 | agentClimb: 0.4 112 | ledgeDropHeight: 0 113 | maxJumpAcrossDistance: 0 114 | minRegionArea: 2 115 | manualCellSize: 0 116 | cellSize: 0.16666667 117 | manualTileSize: 0 118 | tileSize: 256 119 | accuratePlacement: 0 120 | debug: 121 | m_Flags: 0 122 | m_NavMeshData: {fileID: 0} 123 | --- !u!1 &47341006 124 | GameObject: 125 | m_ObjectHideFlags: 0 126 | m_CorrespondingSourceObject: {fileID: 0} 127 | m_PrefabInstance: {fileID: 0} 128 | m_PrefabAsset: {fileID: 0} 129 | serializedVersion: 6 130 | m_Component: 131 | - component: {fileID: 47341008} 132 | - component: {fileID: 47341007} 133 | m_Layer: 0 134 | m_Name: Child-1 135 | m_TagString: Untagged 136 | m_Icon: {fileID: 0} 137 | m_NavMeshLayer: 0 138 | m_StaticEditorFlags: 0 139 | m_IsActive: 1 140 | --- !u!114 &47341007 141 | MonoBehaviour: 142 | m_ObjectHideFlags: 0 143 | m_CorrespondingSourceObject: {fileID: 0} 144 | m_PrefabInstance: {fileID: 0} 145 | m_PrefabAsset: {fileID: 0} 146 | m_GameObject: {fileID: 47341006} 147 | m_Enabled: 1 148 | m_EditorHideFlags: 0 149 | m_Script: {fileID: 11500000, guid: b400b8ba9aff38240bfc80f29fc38d22, type: 3} 150 | m_Name: 151 | m_EditorClassIdentifier: 152 | Event: 153 | m_PersistentCalls: 154 | m_Calls: 155 | - m_Target: {fileID: 1606664822} 156 | m_MethodName: InvokeEvent 157 | m_Mode: 0 158 | m_Arguments: 159 | m_ObjectArgument: {fileID: 0} 160 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 161 | m_IntArgument: 0 162 | m_FloatArgument: 0 163 | m_StringArgument: 164 | m_BoolArgument: 0 165 | m_CallState: 2 166 | - m_Target: {fileID: 582561918} 167 | m_MethodName: InvokeEvent 168 | m_Mode: 0 169 | m_Arguments: 170 | m_ObjectArgument: {fileID: 0} 171 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 172 | m_IntArgument: 0 173 | m_FloatArgument: 0 174 | m_StringArgument: 175 | m_BoolArgument: 0 176 | m_CallState: 2 177 | - m_Target: {fileID: 1677074597} 178 | m_MethodName: InvokeEvent 179 | m_Mode: 0 180 | m_Arguments: 181 | m_ObjectArgument: {fileID: 0} 182 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 183 | m_IntArgument: 0 184 | m_FloatArgument: 0 185 | m_StringArgument: 186 | m_BoolArgument: 0 187 | m_CallState: 2 188 | RunCallChain: 0 189 | --- !u!4 &47341008 190 | Transform: 191 | m_ObjectHideFlags: 0 192 | m_CorrespondingSourceObject: {fileID: 0} 193 | m_PrefabInstance: {fileID: 0} 194 | m_PrefabAsset: {fileID: 0} 195 | m_GameObject: {fileID: 47341006} 196 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 197 | m_LocalPosition: {x: 0, y: 0, z: 0} 198 | m_LocalScale: {x: 1, y: 1, z: 1} 199 | m_Children: 200 | - {fileID: 1606664821} 201 | - {fileID: 582561917} 202 | - {fileID: 1677074598} 203 | m_Father: {fileID: 2018199473} 204 | m_RootOrder: 0 205 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 206 | --- !u!1 &162857444 207 | GameObject: 208 | m_ObjectHideFlags: 0 209 | m_CorrespondingSourceObject: {fileID: 0} 210 | m_PrefabInstance: {fileID: 0} 211 | m_PrefabAsset: {fileID: 0} 212 | serializedVersion: 6 213 | m_Component: 214 | - component: {fileID: 162857446} 215 | - component: {fileID: 162857445} 216 | m_Layer: 0 217 | m_Name: Child-2 218 | m_TagString: Untagged 219 | m_Icon: {fileID: 0} 220 | m_NavMeshLayer: 0 221 | m_StaticEditorFlags: 0 222 | m_IsActive: 1 223 | --- !u!114 &162857445 224 | MonoBehaviour: 225 | m_ObjectHideFlags: 0 226 | m_CorrespondingSourceObject: {fileID: 0} 227 | m_PrefabInstance: {fileID: 0} 228 | m_PrefabAsset: {fileID: 0} 229 | m_GameObject: {fileID: 162857444} 230 | m_Enabled: 1 231 | m_EditorHideFlags: 0 232 | m_Script: {fileID: 11500000, guid: b400b8ba9aff38240bfc80f29fc38d22, type: 3} 233 | m_Name: 234 | m_EditorClassIdentifier: 235 | Event: 236 | m_PersistentCalls: 237 | m_Calls: 238 | - m_Target: {fileID: 1313593392} 239 | m_MethodName: InvokeEvent 240 | m_Mode: 0 241 | m_Arguments: 242 | m_ObjectArgument: {fileID: 0} 243 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 244 | m_IntArgument: 0 245 | m_FloatArgument: 0 246 | m_StringArgument: 247 | m_BoolArgument: 0 248 | m_CallState: 2 249 | RunCallChain: 0 250 | --- !u!4 &162857446 251 | Transform: 252 | m_ObjectHideFlags: 0 253 | m_CorrespondingSourceObject: {fileID: 0} 254 | m_PrefabInstance: {fileID: 0} 255 | m_PrefabAsset: {fileID: 0} 256 | m_GameObject: {fileID: 162857444} 257 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 258 | m_LocalPosition: {x: 0, y: 0, z: 0} 259 | m_LocalScale: {x: 1, y: 1, z: 1} 260 | m_Children: 261 | - {fileID: 1313593393} 262 | m_Father: {fileID: 2018199473} 263 | m_RootOrder: 1 264 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 265 | --- !u!1 &582561916 266 | GameObject: 267 | m_ObjectHideFlags: 0 268 | m_CorrespondingSourceObject: {fileID: 0} 269 | m_PrefabInstance: {fileID: 0} 270 | m_PrefabAsset: {fileID: 0} 271 | serializedVersion: 6 272 | m_Component: 273 | - component: {fileID: 582561917} 274 | - component: {fileID: 582561918} 275 | m_Layer: 0 276 | m_Name: Child-1-2 277 | m_TagString: Untagged 278 | m_Icon: {fileID: 0} 279 | m_NavMeshLayer: 0 280 | m_StaticEditorFlags: 0 281 | m_IsActive: 1 282 | --- !u!4 &582561917 283 | Transform: 284 | m_ObjectHideFlags: 0 285 | m_CorrespondingSourceObject: {fileID: 0} 286 | m_PrefabInstance: {fileID: 0} 287 | m_PrefabAsset: {fileID: 0} 288 | m_GameObject: {fileID: 582561916} 289 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 290 | m_LocalPosition: {x: 0, y: 0, z: 0} 291 | m_LocalScale: {x: 1, y: 1, z: 1} 292 | m_Children: 293 | - {fileID: 1665481682} 294 | m_Father: {fileID: 47341008} 295 | m_RootOrder: 1 296 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 297 | --- !u!114 &582561918 298 | MonoBehaviour: 299 | m_ObjectHideFlags: 0 300 | m_CorrespondingSourceObject: {fileID: 0} 301 | m_PrefabInstance: {fileID: 0} 302 | m_PrefabAsset: {fileID: 0} 303 | m_GameObject: {fileID: 582561916} 304 | m_Enabled: 1 305 | m_EditorHideFlags: 0 306 | m_Script: {fileID: 11500000, guid: b400b8ba9aff38240bfc80f29fc38d22, type: 3} 307 | m_Name: 308 | m_EditorClassIdentifier: 309 | Event: 310 | m_PersistentCalls: 311 | m_Calls: 312 | - m_Target: {fileID: 1665481683} 313 | m_MethodName: InvokeEvent 314 | m_Mode: 0 315 | m_Arguments: 316 | m_ObjectArgument: {fileID: 0} 317 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 318 | m_IntArgument: 0 319 | m_FloatArgument: 0 320 | m_StringArgument: 321 | m_BoolArgument: 0 322 | m_CallState: 2 323 | RunCallChain: 0 324 | --- !u!1 &1313593391 325 | GameObject: 326 | m_ObjectHideFlags: 0 327 | m_CorrespondingSourceObject: {fileID: 0} 328 | m_PrefabInstance: {fileID: 0} 329 | m_PrefabAsset: {fileID: 0} 330 | serializedVersion: 6 331 | m_Component: 332 | - component: {fileID: 1313593393} 333 | - component: {fileID: 1313593392} 334 | m_Layer: 0 335 | m_Name: Child-2-1 336 | m_TagString: Untagged 337 | m_Icon: {fileID: 0} 338 | m_NavMeshLayer: 0 339 | m_StaticEditorFlags: 0 340 | m_IsActive: 1 341 | --- !u!114 &1313593392 342 | MonoBehaviour: 343 | m_ObjectHideFlags: 0 344 | m_CorrespondingSourceObject: {fileID: 0} 345 | m_PrefabInstance: {fileID: 0} 346 | m_PrefabAsset: {fileID: 0} 347 | m_GameObject: {fileID: 1313593391} 348 | m_Enabled: 1 349 | m_EditorHideFlags: 0 350 | m_Script: {fileID: 11500000, guid: b400b8ba9aff38240bfc80f29fc38d22, type: 3} 351 | m_Name: 352 | m_EditorClassIdentifier: 353 | Event: 354 | m_PersistentCalls: 355 | m_Calls: 356 | - m_Target: {fileID: 1313593392} 357 | m_MethodName: PrintChainEnd 358 | m_Mode: 0 359 | m_Arguments: 360 | m_ObjectArgument: {fileID: 0} 361 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 362 | m_IntArgument: 0 363 | m_FloatArgument: 0 364 | m_StringArgument: 365 | m_BoolArgument: 0 366 | m_CallState: 2 367 | RunCallChain: 0 368 | --- !u!4 &1313593393 369 | Transform: 370 | m_ObjectHideFlags: 0 371 | m_CorrespondingSourceObject: {fileID: 0} 372 | m_PrefabInstance: {fileID: 0} 373 | m_PrefabAsset: {fileID: 0} 374 | m_GameObject: {fileID: 1313593391} 375 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 376 | m_LocalPosition: {x: 0, y: 0, z: 0} 377 | m_LocalScale: {x: 1, y: 1, z: 1} 378 | m_Children: [] 379 | m_Father: {fileID: 162857446} 380 | m_RootOrder: 0 381 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 382 | --- !u!1 &1606664820 383 | GameObject: 384 | m_ObjectHideFlags: 0 385 | m_CorrespondingSourceObject: {fileID: 0} 386 | m_PrefabInstance: {fileID: 0} 387 | m_PrefabAsset: {fileID: 0} 388 | serializedVersion: 6 389 | m_Component: 390 | - component: {fileID: 1606664821} 391 | - component: {fileID: 1606664822} 392 | m_Layer: 0 393 | m_Name: Child-1-1 394 | m_TagString: Untagged 395 | m_Icon: {fileID: 0} 396 | m_NavMeshLayer: 0 397 | m_StaticEditorFlags: 0 398 | m_IsActive: 1 399 | --- !u!4 &1606664821 400 | Transform: 401 | m_ObjectHideFlags: 0 402 | m_CorrespondingSourceObject: {fileID: 0} 403 | m_PrefabInstance: {fileID: 0} 404 | m_PrefabAsset: {fileID: 0} 405 | m_GameObject: {fileID: 1606664820} 406 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 407 | m_LocalPosition: {x: 0, y: 0, z: 0} 408 | m_LocalScale: {x: 1, y: 1, z: 1} 409 | m_Children: [] 410 | m_Father: {fileID: 47341008} 411 | m_RootOrder: 0 412 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 413 | --- !u!114 &1606664822 414 | MonoBehaviour: 415 | m_ObjectHideFlags: 0 416 | m_CorrespondingSourceObject: {fileID: 0} 417 | m_PrefabInstance: {fileID: 0} 418 | m_PrefabAsset: {fileID: 0} 419 | m_GameObject: {fileID: 1606664820} 420 | m_Enabled: 1 421 | m_EditorHideFlags: 0 422 | m_Script: {fileID: 11500000, guid: b400b8ba9aff38240bfc80f29fc38d22, type: 3} 423 | m_Name: 424 | m_EditorClassIdentifier: 425 | Event: 426 | m_PersistentCalls: 427 | m_Calls: 428 | - m_Target: {fileID: 1606664822} 429 | m_MethodName: PrintChainEnd 430 | m_Mode: 0 431 | m_Arguments: 432 | m_ObjectArgument: {fileID: 0} 433 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 434 | m_IntArgument: 0 435 | m_FloatArgument: 0 436 | m_StringArgument: 437 | m_BoolArgument: 0 438 | m_CallState: 2 439 | RunCallChain: 0 440 | --- !u!1 &1665481681 441 | GameObject: 442 | m_ObjectHideFlags: 0 443 | m_CorrespondingSourceObject: {fileID: 0} 444 | m_PrefabInstance: {fileID: 0} 445 | m_PrefabAsset: {fileID: 0} 446 | serializedVersion: 6 447 | m_Component: 448 | - component: {fileID: 1665481682} 449 | - component: {fileID: 1665481683} 450 | m_Layer: 0 451 | m_Name: Child-1-2-1 452 | m_TagString: Untagged 453 | m_Icon: {fileID: 0} 454 | m_NavMeshLayer: 0 455 | m_StaticEditorFlags: 0 456 | m_IsActive: 1 457 | --- !u!4 &1665481682 458 | Transform: 459 | m_ObjectHideFlags: 0 460 | m_CorrespondingSourceObject: {fileID: 0} 461 | m_PrefabInstance: {fileID: 0} 462 | m_PrefabAsset: {fileID: 0} 463 | m_GameObject: {fileID: 1665481681} 464 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 465 | m_LocalPosition: {x: 0, y: 0, z: 0} 466 | m_LocalScale: {x: 1, y: 1, z: 1} 467 | m_Children: [] 468 | m_Father: {fileID: 582561917} 469 | m_RootOrder: 0 470 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 471 | --- !u!114 &1665481683 472 | MonoBehaviour: 473 | m_ObjectHideFlags: 0 474 | m_CorrespondingSourceObject: {fileID: 0} 475 | m_PrefabInstance: {fileID: 0} 476 | m_PrefabAsset: {fileID: 0} 477 | m_GameObject: {fileID: 1665481681} 478 | m_Enabled: 1 479 | m_EditorHideFlags: 0 480 | m_Script: {fileID: 11500000, guid: b400b8ba9aff38240bfc80f29fc38d22, type: 3} 481 | m_Name: 482 | m_EditorClassIdentifier: 483 | Event: 484 | m_PersistentCalls: 485 | m_Calls: 486 | - m_Target: {fileID: 1665481683} 487 | m_MethodName: PrintChainEnd 488 | m_Mode: 0 489 | m_Arguments: 490 | m_ObjectArgument: {fileID: 0} 491 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 492 | m_IntArgument: 0 493 | m_FloatArgument: 0 494 | m_StringArgument: 495 | m_BoolArgument: 0 496 | m_CallState: 2 497 | RunCallChain: 0 498 | --- !u!1 &1677074596 499 | GameObject: 500 | m_ObjectHideFlags: 0 501 | m_CorrespondingSourceObject: {fileID: 0} 502 | m_PrefabInstance: {fileID: 0} 503 | m_PrefabAsset: {fileID: 0} 504 | serializedVersion: 6 505 | m_Component: 506 | - component: {fileID: 1677074598} 507 | - component: {fileID: 1677074597} 508 | m_Layer: 0 509 | m_Name: Child-1-3 510 | m_TagString: Untagged 511 | m_Icon: {fileID: 0} 512 | m_NavMeshLayer: 0 513 | m_StaticEditorFlags: 0 514 | m_IsActive: 1 515 | --- !u!114 &1677074597 516 | MonoBehaviour: 517 | m_ObjectHideFlags: 0 518 | m_CorrespondingSourceObject: {fileID: 0} 519 | m_PrefabInstance: {fileID: 0} 520 | m_PrefabAsset: {fileID: 0} 521 | m_GameObject: {fileID: 1677074596} 522 | m_Enabled: 1 523 | m_EditorHideFlags: 0 524 | m_Script: {fileID: 11500000, guid: b400b8ba9aff38240bfc80f29fc38d22, type: 3} 525 | m_Name: 526 | m_EditorClassIdentifier: 527 | Event: 528 | m_PersistentCalls: 529 | m_Calls: 530 | - m_Target: {fileID: 1677074597} 531 | m_MethodName: PrintChainEnd 532 | m_Mode: 0 533 | m_Arguments: 534 | m_ObjectArgument: {fileID: 0} 535 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 536 | m_IntArgument: 0 537 | m_FloatArgument: 0 538 | m_StringArgument: 539 | m_BoolArgument: 0 540 | m_CallState: 2 541 | RunCallChain: 0 542 | --- !u!4 &1677074598 543 | Transform: 544 | m_ObjectHideFlags: 0 545 | m_CorrespondingSourceObject: {fileID: 0} 546 | m_PrefabInstance: {fileID: 0} 547 | m_PrefabAsset: {fileID: 0} 548 | m_GameObject: {fileID: 1677074596} 549 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 550 | m_LocalPosition: {x: 0, y: 0, z: 0} 551 | m_LocalScale: {x: 1, y: 1, z: 1} 552 | m_Children: [] 553 | m_Father: {fileID: 47341008} 554 | m_RootOrder: 2 555 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 556 | --- !u!1 &1680437409 557 | GameObject: 558 | m_ObjectHideFlags: 0 559 | m_CorrespondingSourceObject: {fileID: 0} 560 | m_PrefabInstance: {fileID: 0} 561 | m_PrefabAsset: {fileID: 0} 562 | serializedVersion: 6 563 | m_Component: 564 | - component: {fileID: 1680437411} 565 | - component: {fileID: 1680437410} 566 | m_Layer: 0 567 | m_Name: FrameFinder 568 | m_TagString: Untagged 569 | m_Icon: {fileID: 0} 570 | m_NavMeshLayer: 0 571 | m_StaticEditorFlags: 0 572 | m_IsActive: 1 573 | --- !u!114 &1680437410 574 | MonoBehaviour: 575 | m_ObjectHideFlags: 0 576 | m_CorrespondingSourceObject: {fileID: 0} 577 | m_PrefabInstance: {fileID: 0} 578 | m_PrefabAsset: {fileID: 0} 579 | m_GameObject: {fileID: 1680437409} 580 | m_Enabled: 1 581 | m_EditorHideFlags: 0 582 | m_Script: {fileID: 11500000, guid: eaf9c969216928e44ad5e099418c0585, type: 3} 583 | m_Name: 584 | m_EditorClassIdentifier: 585 | FrameContains: '>__' 586 | StartFrame: 0 587 | EndFrame: -1 588 | ThreadIndex: 0 589 | LookInThread: 1:Main Thread 590 | --- !u!4 &1680437411 591 | Transform: 592 | m_ObjectHideFlags: 0 593 | m_CorrespondingSourceObject: {fileID: 0} 594 | m_PrefabInstance: {fileID: 0} 595 | m_PrefabAsset: {fileID: 0} 596 | m_GameObject: {fileID: 1680437409} 597 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 598 | m_LocalPosition: {x: 0, y: 0, z: 0} 599 | m_LocalScale: {x: 1, y: 1, z: 1} 600 | m_Children: [] 601 | m_Father: {fileID: 0} 602 | m_RootOrder: 1 603 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 604 | --- !u!1 &2018199471 605 | GameObject: 606 | m_ObjectHideFlags: 0 607 | m_CorrespondingSourceObject: {fileID: 0} 608 | m_PrefabInstance: {fileID: 0} 609 | m_PrefabAsset: {fileID: 0} 610 | serializedVersion: 6 611 | m_Component: 612 | - component: {fileID: 2018199473} 613 | - component: {fileID: 2018199472} 614 | m_Layer: 0 615 | m_Name: Root 616 | m_TagString: Untagged 617 | m_Icon: {fileID: 0} 618 | m_NavMeshLayer: 0 619 | m_StaticEditorFlags: 0 620 | m_IsActive: 1 621 | --- !u!114 &2018199472 622 | MonoBehaviour: 623 | m_ObjectHideFlags: 0 624 | m_CorrespondingSourceObject: {fileID: 0} 625 | m_PrefabInstance: {fileID: 0} 626 | m_PrefabAsset: {fileID: 0} 627 | m_GameObject: {fileID: 2018199471} 628 | m_Enabled: 1 629 | m_EditorHideFlags: 0 630 | m_Script: {fileID: 11500000, guid: b400b8ba9aff38240bfc80f29fc38d22, type: 3} 631 | m_Name: 632 | m_EditorClassIdentifier: 633 | Event: 634 | m_PersistentCalls: 635 | m_Calls: 636 | - m_Target: {fileID: 47341007} 637 | m_MethodName: InvokeEvent 638 | m_Mode: 0 639 | m_Arguments: 640 | m_ObjectArgument: {fileID: 0} 641 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 642 | m_IntArgument: 0 643 | m_FloatArgument: 0 644 | m_StringArgument: 645 | m_BoolArgument: 0 646 | m_CallState: 2 647 | - m_Target: {fileID: 162857445} 648 | m_MethodName: InvokeEvent 649 | m_Mode: 0 650 | m_Arguments: 651 | m_ObjectArgument: {fileID: 0} 652 | m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine 653 | m_IntArgument: 0 654 | m_FloatArgument: 0 655 | m_StringArgument: 656 | m_BoolArgument: 0 657 | m_CallState: 2 658 | RunCallChain: 1 659 | --- !u!4 &2018199473 660 | Transform: 661 | m_ObjectHideFlags: 0 662 | m_CorrespondingSourceObject: {fileID: 0} 663 | m_PrefabInstance: {fileID: 0} 664 | m_PrefabAsset: {fileID: 0} 665 | m_GameObject: {fileID: 2018199471} 666 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 667 | m_LocalPosition: {x: 0, y: 0, z: 0} 668 | m_LocalScale: {x: 1, y: 1, z: 1} 669 | m_Children: 670 | - {fileID: 47341008} 671 | - {fileID: 162857446} 672 | m_Father: {fileID: 0} 673 | m_RootOrder: 0 674 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 675 | -------------------------------------------------------------------------------- /Assets/Scenes/SampleScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9fc0d4010bbf28b4594072e72b8655ab 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Attribute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd2620aa1c676dc49bdcf0016e213865 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Attribute/UnityEventCallRedirectAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEventCallRedirector.Attribute 2 | { 3 | using System; 4 | 5 | /// 6 | /// Indicates that the property's backing field is serialized. 7 | /// 8 | [AttributeUsage(AttributeTargets.Assembly)] 9 | public sealed class UnityEventCallRedirectorAttribute : Attribute 10 | { 11 | public string EventInterceptorTypeName { get; } 12 | public string ReplaceCallsFromNamespacesRegex { get; } 13 | public string ExcludeFullMethodNameRegex { get; set; } = ""; 14 | 15 | public UnityEventCallRedirectorAttribute(string eventInterceptorTypeName, string replaceCallsFromNamespacesRegex) 16 | { 17 | EventInterceptorTypeName = eventInterceptorTypeName; 18 | ReplaceCallsFromNamespacesRegex = replaceCallsFromNamespacesRegex; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Attribute/UnityEventCallRedirectAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 434df6f331e0ffc408c115cf36155b08 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Attribute/UnityEventCallRedirector.Attribute.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UnityEventCallRedirector.Attribute", 3 | "references": [], 4 | "optionalUnityReferences": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false, 8 | "versionDefines": [ 9 | 10 | ] 11 | } -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Attribute/UnityEventCallRedirector.Attribute.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f9e380d0cd288084e85d3ab97dee5856 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1b104473ff8ba684e8aacc551ff22812 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/MethodBodyExtensions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Jb Evain (jbevain@gmail.com) 4 | // 5 | // Copyright (c) 2008 - 2015 Jb Evain 6 | // Copyright (c) 2008 - 2011 Novell, Inc. 7 | // 8 | // Licensed under the MIT/X11 license. 9 | // 10 | 11 | using System; 12 | 13 | using Mono.Cecil.Cil; 14 | 15 | namespace Mono.Cecil.Rocks 16 | { 17 | 18 | #if INSIDE_ROCKS 19 | public 20 | #endif 21 | static class MethodBodyRocks 22 | { 23 | 24 | public static void SimplifyMacros(this MethodBody self) 25 | { 26 | if (self == null) 27 | throw new ArgumentNullException("self"); 28 | 29 | foreach (var instruction in self.Instructions) 30 | { 31 | if (instruction.OpCode.OpCodeType != OpCodeType.Macro) 32 | continue; 33 | 34 | switch (instruction.OpCode.Code) 35 | { 36 | case Code.Ldarg_0: 37 | ExpandMacro(instruction, OpCodes.Ldarg, self.GetParameter(0)); 38 | break; 39 | case Code.Ldarg_1: 40 | ExpandMacro(instruction, OpCodes.Ldarg, self.GetParameter(1)); 41 | break; 42 | case Code.Ldarg_2: 43 | ExpandMacro(instruction, OpCodes.Ldarg, self.GetParameter(2)); 44 | break; 45 | case Code.Ldarg_3: 46 | ExpandMacro(instruction, OpCodes.Ldarg, self.GetParameter(3)); 47 | break; 48 | case Code.Ldloc_0: 49 | ExpandMacro(instruction, OpCodes.Ldloc, self.Variables[0]); 50 | break; 51 | case Code.Ldloc_1: 52 | ExpandMacro(instruction, OpCodes.Ldloc, self.Variables[1]); 53 | break; 54 | case Code.Ldloc_2: 55 | ExpandMacro(instruction, OpCodes.Ldloc, self.Variables[2]); 56 | break; 57 | case Code.Ldloc_3: 58 | ExpandMacro(instruction, OpCodes.Ldloc, self.Variables[3]); 59 | break; 60 | case Code.Stloc_0: 61 | ExpandMacro(instruction, OpCodes.Stloc, self.Variables[0]); 62 | break; 63 | case Code.Stloc_1: 64 | ExpandMacro(instruction, OpCodes.Stloc, self.Variables[1]); 65 | break; 66 | case Code.Stloc_2: 67 | ExpandMacro(instruction, OpCodes.Stloc, self.Variables[2]); 68 | break; 69 | case Code.Stloc_3: 70 | ExpandMacro(instruction, OpCodes.Stloc, self.Variables[3]); 71 | break; 72 | case Code.Ldarg_S: 73 | instruction.OpCode = OpCodes.Ldarg; 74 | break; 75 | case Code.Ldarga_S: 76 | instruction.OpCode = OpCodes.Ldarga; 77 | break; 78 | case Code.Starg_S: 79 | instruction.OpCode = OpCodes.Starg; 80 | break; 81 | case Code.Ldloc_S: 82 | instruction.OpCode = OpCodes.Ldloc; 83 | break; 84 | case Code.Ldloca_S: 85 | instruction.OpCode = OpCodes.Ldloca; 86 | break; 87 | case Code.Stloc_S: 88 | instruction.OpCode = OpCodes.Stloc; 89 | break; 90 | case Code.Ldc_I4_M1: 91 | ExpandMacro(instruction, OpCodes.Ldc_I4, -1); 92 | break; 93 | case Code.Ldc_I4_0: 94 | ExpandMacro(instruction, OpCodes.Ldc_I4, 0); 95 | break; 96 | case Code.Ldc_I4_1: 97 | ExpandMacro(instruction, OpCodes.Ldc_I4, 1); 98 | break; 99 | case Code.Ldc_I4_2: 100 | ExpandMacro(instruction, OpCodes.Ldc_I4, 2); 101 | break; 102 | case Code.Ldc_I4_3: 103 | ExpandMacro(instruction, OpCodes.Ldc_I4, 3); 104 | break; 105 | case Code.Ldc_I4_4: 106 | ExpandMacro(instruction, OpCodes.Ldc_I4, 4); 107 | break; 108 | case Code.Ldc_I4_5: 109 | ExpandMacro(instruction, OpCodes.Ldc_I4, 5); 110 | break; 111 | case Code.Ldc_I4_6: 112 | ExpandMacro(instruction, OpCodes.Ldc_I4, 6); 113 | break; 114 | case Code.Ldc_I4_7: 115 | ExpandMacro(instruction, OpCodes.Ldc_I4, 7); 116 | break; 117 | case Code.Ldc_I4_8: 118 | ExpandMacro(instruction, OpCodes.Ldc_I4, 8); 119 | break; 120 | case Code.Ldc_I4_S: 121 | ExpandMacro(instruction, OpCodes.Ldc_I4, (int)(sbyte)instruction.Operand); 122 | break; 123 | case Code.Br_S: 124 | instruction.OpCode = OpCodes.Br; 125 | break; 126 | case Code.Brfalse_S: 127 | instruction.OpCode = OpCodes.Brfalse; 128 | break; 129 | case Code.Brtrue_S: 130 | instruction.OpCode = OpCodes.Brtrue; 131 | break; 132 | case Code.Beq_S: 133 | instruction.OpCode = OpCodes.Beq; 134 | break; 135 | case Code.Bge_S: 136 | instruction.OpCode = OpCodes.Bge; 137 | break; 138 | case Code.Bgt_S: 139 | instruction.OpCode = OpCodes.Bgt; 140 | break; 141 | case Code.Ble_S: 142 | instruction.OpCode = OpCodes.Ble; 143 | break; 144 | case Code.Blt_S: 145 | instruction.OpCode = OpCodes.Blt; 146 | break; 147 | case Code.Bne_Un_S: 148 | instruction.OpCode = OpCodes.Bne_Un; 149 | break; 150 | case Code.Bge_Un_S: 151 | instruction.OpCode = OpCodes.Bge_Un; 152 | break; 153 | case Code.Bgt_Un_S: 154 | instruction.OpCode = OpCodes.Bgt_Un; 155 | break; 156 | case Code.Ble_Un_S: 157 | instruction.OpCode = OpCodes.Ble_Un; 158 | break; 159 | case Code.Blt_Un_S: 160 | instruction.OpCode = OpCodes.Blt_Un; 161 | break; 162 | case Code.Leave_S: 163 | instruction.OpCode = OpCodes.Leave; 164 | break; 165 | } 166 | } 167 | } 168 | 169 | static void ExpandMacro(Instruction instruction, OpCode opcode, object operand) 170 | { 171 | instruction.OpCode = opcode; 172 | instruction.Operand = operand; 173 | } 174 | 175 | static void MakeMacro(Instruction instruction, OpCode opcode) 176 | { 177 | instruction.OpCode = opcode; 178 | instruction.Operand = null; 179 | } 180 | 181 | public static void Optimize(this MethodBody self) 182 | { 183 | if (self == null) 184 | throw new ArgumentNullException("self"); 185 | 186 | OptimizeLongs(self); 187 | OptimizeMacros(self); 188 | } 189 | 190 | static void OptimizeLongs(this MethodBody self) 191 | { 192 | for (var i = 0; i < self.Instructions.Count; i++) 193 | { 194 | var instruction = self.Instructions[i]; 195 | if (instruction.OpCode.Code != Code.Ldc_I8) 196 | continue; 197 | var l = (long)instruction.Operand; 198 | if (l >= int.MaxValue || l <= int.MinValue) 199 | continue; 200 | ExpandMacro(instruction, OpCodes.Ldc_I4, (int)l); 201 | self.Instructions.Insert(++i, Instruction.Create(OpCodes.Conv_I8)); 202 | } 203 | } 204 | 205 | public static void OptimizeMacros(this MethodBody self) 206 | { 207 | if (self == null) 208 | throw new ArgumentNullException("self"); 209 | 210 | var method = self.Method; 211 | 212 | foreach (var instruction in self.Instructions) 213 | { 214 | int index; 215 | switch (instruction.OpCode.Code) 216 | { 217 | case Code.Ldarg: 218 | index = ((ParameterDefinition)instruction.Operand).Index; 219 | if (index == -1 && instruction.Operand == self.ThisParameter) 220 | index = 0; 221 | else if (method.HasThis) 222 | index++; 223 | 224 | switch (index) 225 | { 226 | case 0: 227 | MakeMacro(instruction, OpCodes.Ldarg_0); 228 | break; 229 | case 1: 230 | MakeMacro(instruction, OpCodes.Ldarg_1); 231 | break; 232 | case 2: 233 | MakeMacro(instruction, OpCodes.Ldarg_2); 234 | break; 235 | case 3: 236 | MakeMacro(instruction, OpCodes.Ldarg_3); 237 | break; 238 | default: 239 | if (index < 256) 240 | ExpandMacro(instruction, OpCodes.Ldarg_S, instruction.Operand); 241 | break; 242 | } 243 | break; 244 | case Code.Ldloc: 245 | index = ((VariableDefinition)instruction.Operand).Index; 246 | switch (index) 247 | { 248 | case 0: 249 | MakeMacro(instruction, OpCodes.Ldloc_0); 250 | break; 251 | case 1: 252 | MakeMacro(instruction, OpCodes.Ldloc_1); 253 | break; 254 | case 2: 255 | MakeMacro(instruction, OpCodes.Ldloc_2); 256 | break; 257 | case 3: 258 | MakeMacro(instruction, OpCodes.Ldloc_3); 259 | break; 260 | default: 261 | if (index < 256) 262 | ExpandMacro(instruction, OpCodes.Ldloc_S, instruction.Operand); 263 | break; 264 | } 265 | break; 266 | case Code.Stloc: 267 | index = ((VariableDefinition)instruction.Operand).Index; 268 | switch (index) 269 | { 270 | case 0: 271 | MakeMacro(instruction, OpCodes.Stloc_0); 272 | break; 273 | case 1: 274 | MakeMacro(instruction, OpCodes.Stloc_1); 275 | break; 276 | case 2: 277 | MakeMacro(instruction, OpCodes.Stloc_2); 278 | break; 279 | case 3: 280 | MakeMacro(instruction, OpCodes.Stloc_3); 281 | break; 282 | default: 283 | if (index < 256) 284 | ExpandMacro(instruction, OpCodes.Stloc_S, instruction.Operand); 285 | break; 286 | } 287 | break; 288 | case Code.Ldarga: 289 | index = ((ParameterDefinition)instruction.Operand).Index; 290 | if (index == -1 && instruction.Operand == self.ThisParameter) 291 | index = 0; 292 | else if (method.HasThis) 293 | index++; 294 | if (index < 256) 295 | ExpandMacro(instruction, OpCodes.Ldarga_S, instruction.Operand); 296 | break; 297 | case Code.Ldloca: 298 | if (((VariableDefinition)instruction.Operand).Index < 256) 299 | ExpandMacro(instruction, OpCodes.Ldloca_S, instruction.Operand); 300 | break; 301 | case Code.Ldc_I4: 302 | int i = (int)instruction.Operand; 303 | switch (i) 304 | { 305 | case -1: 306 | MakeMacro(instruction, OpCodes.Ldc_I4_M1); 307 | break; 308 | case 0: 309 | MakeMacro(instruction, OpCodes.Ldc_I4_0); 310 | break; 311 | case 1: 312 | MakeMacro(instruction, OpCodes.Ldc_I4_1); 313 | break; 314 | case 2: 315 | MakeMacro(instruction, OpCodes.Ldc_I4_2); 316 | break; 317 | case 3: 318 | MakeMacro(instruction, OpCodes.Ldc_I4_3); 319 | break; 320 | case 4: 321 | MakeMacro(instruction, OpCodes.Ldc_I4_4); 322 | break; 323 | case 5: 324 | MakeMacro(instruction, OpCodes.Ldc_I4_5); 325 | break; 326 | case 6: 327 | MakeMacro(instruction, OpCodes.Ldc_I4_6); 328 | break; 329 | case 7: 330 | MakeMacro(instruction, OpCodes.Ldc_I4_7); 331 | break; 332 | case 8: 333 | MakeMacro(instruction, OpCodes.Ldc_I4_8); 334 | break; 335 | default: 336 | if (i >= -128 && i < 128) 337 | ExpandMacro(instruction, OpCodes.Ldc_I4_S, (sbyte)i); 338 | break; 339 | } 340 | break; 341 | } 342 | } 343 | 344 | OptimizeBranches(self); 345 | } 346 | 347 | static void OptimizeBranches(MethodBody body) 348 | { 349 | ComputeOffsets(body); 350 | 351 | foreach (var instruction in body.Instructions) 352 | { 353 | if (instruction.OpCode.OperandType != OperandType.InlineBrTarget) 354 | continue; 355 | 356 | if (OptimizeBranch(instruction)) 357 | ComputeOffsets(body); 358 | } 359 | } 360 | 361 | static bool OptimizeBranch(Instruction instruction) 362 | { 363 | var offset = ((Instruction)instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4); 364 | if (!(offset >= -128 && offset <= 127)) 365 | return false; 366 | 367 | switch (instruction.OpCode.Code) 368 | { 369 | case Code.Br: 370 | instruction.OpCode = OpCodes.Br_S; 371 | break; 372 | case Code.Brfalse: 373 | instruction.OpCode = OpCodes.Brfalse_S; 374 | break; 375 | case Code.Brtrue: 376 | instruction.OpCode = OpCodes.Brtrue_S; 377 | break; 378 | case Code.Beq: 379 | instruction.OpCode = OpCodes.Beq_S; 380 | break; 381 | case Code.Bge: 382 | instruction.OpCode = OpCodes.Bge_S; 383 | break; 384 | case Code.Bgt: 385 | instruction.OpCode = OpCodes.Bgt_S; 386 | break; 387 | case Code.Ble: 388 | instruction.OpCode = OpCodes.Ble_S; 389 | break; 390 | case Code.Blt: 391 | instruction.OpCode = OpCodes.Blt_S; 392 | break; 393 | case Code.Bne_Un: 394 | instruction.OpCode = OpCodes.Bne_Un_S; 395 | break; 396 | case Code.Bge_Un: 397 | instruction.OpCode = OpCodes.Bge_Un_S; 398 | break; 399 | case Code.Bgt_Un: 400 | instruction.OpCode = OpCodes.Bgt_Un_S; 401 | break; 402 | case Code.Ble_Un: 403 | instruction.OpCode = OpCodes.Ble_Un_S; 404 | break; 405 | case Code.Blt_Un: 406 | instruction.OpCode = OpCodes.Blt_Un_S; 407 | break; 408 | case Code.Leave: 409 | instruction.OpCode = OpCodes.Leave_S; 410 | break; 411 | } 412 | 413 | return true; 414 | } 415 | 416 | static void ComputeOffsets(MethodBody body) 417 | { 418 | var offset = 0; 419 | foreach (var instruction in body.Instructions) 420 | { 421 | instruction.Offset = offset; 422 | offset += instruction.GetSize(); 423 | } 424 | } 425 | 426 | public static ParameterDefinition GetParameter(this MethodBody self, int index) 427 | { 428 | var method = self.Method; 429 | 430 | if (method.HasThis) 431 | { 432 | if (index == 0) 433 | return self.ThisParameter; 434 | 435 | index--; 436 | } 437 | 438 | var parameters = method.Parameters; 439 | 440 | if (index < 0 || index >= parameters.Count) 441 | return null; 442 | 443 | return parameters[index]; 444 | } 445 | } 446 | } -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/MethodBodyExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aebc25b1eee661344941f80139898aa1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/ModuleWeaver.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil.Rocks; 2 | using UnityEventCallRedirector.Attribute; 3 | 4 | namespace UnityEventCallRedirector.Fody 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text.RegularExpressions; 10 | using global::Fody; 11 | using Mono.Cecil; 12 | using Mono.Cecil.Cil; 13 | using System.Reflection; 14 | using UnityEngine.Profiling; 15 | 16 | public sealed class ModuleWeaver : BaseModuleWeaver 17 | { 18 | private static readonly string FullAttributeName = typeof(UnityEventCallRedirectorAttribute).FullName; 19 | 20 | private const string FallbackSampleNameFormatName = "FallbackSampleNameFormat"; 21 | private const string FallbackReplaceCallsFromNamespacesRegexName = "FallbackReplaceCallsFromNamespacesRegex"; 22 | private const string FallbackExcludeFullMethodNameRegexName = "FallbackExcludeFullMethodNameRegex"; 23 | private const string DefaultFallbackSampleNameFormat = "____{0} ({1}) <{2}>____"; 24 | private const string DefaultFallbackReplaceCallsFromNamespacesRegex = ".*"; 25 | private const string DefaultFallbackExcludeFullMethodNameRegex = ""; 26 | 27 | private const string UnityEventTypeName = "UnityEvent`1"; 28 | 29 | private MethodDefinition _interceptMethod; 30 | private MethodDefinition _unityEventInvokeMethod; 31 | private TypeDefinition _eventInterceptorType; 32 | private string _replaceCallsFromNamespacesRegex; 33 | private string _excludeFullMethodNameRegex; 34 | private MethodReference _unityObjectGetName; 35 | private MethodReference _objectGetType; 36 | private MethodReference _memberInfoGetName; 37 | private MethodReference _stringFormat; 38 | private MethodReference _beginSample; 39 | private MethodReference _endSample; 40 | private CustomAttribute _unityEventCallRedirectorAttribute; 41 | private string _fallbackSampleFormat; 42 | 43 | public override bool ShouldCleanReference => true; 44 | 45 | public override IEnumerable GetAssembliesForScanning() 46 | { 47 | yield return "UnityEngine"; 48 | } 49 | 50 | 51 | public override void Execute() 52 | { 53 | if (!TryFindRequiredAssemblyAttribute()) 54 | { 55 | LogInfo($"Assembly :{ModuleDefinition.Assembly.Name} does not specify attribute " + 56 | $"{FullAttributeName} which is needed for processing. Falling back to inline IL rewrite"); 57 | LoadXmlSetup(); 58 | } 59 | else 60 | { 61 | LoadAttributeSetup(); 62 | } 63 | 64 | FindReferences(); 65 | 66 | var methodWithInstructionsToReplace = FindMethodsWithInstructionsCallingUnityEvent(_unityEventInvokeMethod); 67 | InterceptUnityEventInvokeCalls(methodWithInstructionsToReplace); 68 | } 69 | 70 | private void InterceptUnityEventInvokeCalls(List methodWithInstructionsToReplace) 71 | { 72 | foreach (var methodWithInstructionToReplace in methodWithInstructionsToReplace) 73 | { 74 | var method = methodWithInstructionToReplace.MethodDefinition; 75 | var instruction = methodWithInstructionToReplace.Instruction; 76 | var il = method.Body.GetILProcessor(); 77 | 78 | method.Body.SimplifyMacros(); 79 | if (_interceptMethod != null) 80 | { 81 | var callValueGenericParameter = ((GenericInstanceType)((MethodReference)instruction.Operand).DeclaringType).GenericArguments[0]; 82 | var genericInterceptMethod = new GenericInstanceMethod(_interceptMethod); 83 | genericInterceptMethod.GenericArguments.Add(callValueGenericParameter); 84 | 85 | if (method.IsStatic) 86 | il.InsertBefore(instruction, il.Create(OpCodes.Ldstr, "Static:" + method.FullName)); 87 | else 88 | il.InsertBefore(instruction, il.Create(OpCodes.Ldarg_0)); 89 | il.InsertBefore(instruction, il.Create(OpCodes.Ldstr, method.Name)); 90 | il.Replace(instruction, il.Create(OpCodes.Call, genericInterceptMethod)); 91 | 92 | LogDebug($"Redirected: {method.DeclaringType.Name}::{method.Name} via interceptor"); 93 | } 94 | else 95 | { 96 | il.InsertBefore(instruction, il.Create(OpCodes.Ldstr, _fallbackSampleFormat)); 97 | if (method.IsStatic) 98 | { 99 | il.InsertBefore(instruction, il.Create(OpCodes.Ldstr, "Static" + method.FullName)); 100 | il.InsertBefore(instruction, il.Create(OpCodes.Ldstr, "Static" + method.FullName)); 101 | } 102 | else 103 | { 104 | il.InsertBefore(instruction, il.Create(OpCodes.Ldarg_0)); 105 | il.InsertBefore(instruction, il.Create(OpCodes.Callvirt, _unityObjectGetName)); 106 | il.InsertBefore(instruction, il.Create(OpCodes.Ldarg_0)); 107 | il.InsertBefore(instruction, il.Create(OpCodes.Callvirt, _objectGetType)); 108 | il.InsertBefore(instruction, il.Create(OpCodes.Callvirt, _memberInfoGetName)); 109 | } 110 | 111 | 112 | il.InsertBefore(instruction, il.Create(OpCodes.Ldstr, method.Name)); 113 | il.InsertBefore(instruction, il.Create(OpCodes.Call, _stringFormat)); 114 | if (method.IsStatic) 115 | il.InsertBefore(instruction, il.Create(OpCodes.Ldnull)); 116 | else 117 | il.InsertBefore(instruction, il.Create(OpCodes.Ldarg_0)); 118 | 119 | il.InsertBefore(instruction, il.Create(OpCodes.Call, _beginSample)); 120 | 121 | il.InsertAfter(instruction, il.Create(OpCodes.Call, _endSample)); 122 | 123 | LogDebug($"{ModuleDefinition.Assembly.Name} Redirected: {method.DeclaringType.Name}::{method.Name} via fallback inline IL"); 124 | } 125 | method.Body.OptimizeMacros(); 126 | } 127 | 128 | LogInfo($"{ModuleDefinition.Assembly.Name} Redirected: {methodWithInstructionsToReplace.Count} calls via {(_interceptMethod != null ? "interceptor" : "fallback inline IL")}"); 129 | } 130 | 131 | private List FindMethodsWithInstructionsCallingUnityEvent(MethodDefinition unityEventInvokeMethod) 132 | { 133 | var methodWithInstructionsToReplace = new List(); 134 | 135 | foreach (var t in ModuleDefinition.Types 136 | .Where(t => Regex.IsMatch(t.Namespace, _replaceCallsFromNamespacesRegex)) 137 | .Where(t => t != _eventInterceptorType)) 138 | { 139 | foreach (var method in t.Methods) 140 | { 141 | if (!string.IsNullOrEmpty(_excludeFullMethodNameRegex) 142 | && Regex.IsMatch($"{method.DeclaringType.FullName}::{method.FullName}", _excludeFullMethodNameRegex)) 143 | { 144 | Console.WriteLine( 145 | $"Skipping rewrite for excluded method: '{method.DeclaringType.FullName}::{method.FullName}'"); 146 | continue; 147 | } 148 | 149 | if (method.Body != null) 150 | { 151 | foreach (var instruction in method.Body.Instructions) 152 | { 153 | if ((instruction.Operand as MethodReference)?.Resolve() == unityEventInvokeMethod) 154 | { 155 | methodWithInstructionsToReplace.Add( 156 | new MethodDefinitionInstructionToReplacePair(method, instruction)); 157 | } 158 | } 159 | } 160 | } 161 | } 162 | 163 | return methodWithInstructionsToReplace; 164 | } 165 | 166 | private void FindReferences() 167 | { 168 | var unityEngineAssemblyFullReference = ModuleDefinition.AssemblyReferences.First(ar => ar.Name == "UnityEngine.CoreModule"); 169 | var unityAssembly = ModuleDefinition.AssemblyResolver.Resolve(unityEngineAssemblyFullReference); 170 | 171 | var unityEventType = ModuleDefinition.ImportReference(unityAssembly.MainModule.Types.First(t => t.Name == UnityEventTypeName)).Resolve(); 172 | _unityEventInvokeMethod = ModuleDefinition.ImportReference(unityEventType.Methods.First(m => m.Name == "Invoke" && m.Parameters.Count == 1)).Resolve(); 173 | 174 | _unityObjectGetName = ImportPropertyGetter(typeof(UnityEngine.Object), p => p.Name == nameof(UnityEngine.Object.name)); 175 | _objectGetType = ImportMethod(typeof(object), m => m.Name == nameof(object.GetType)); 176 | _memberInfoGetName = ImportPropertyGetter(typeof(MemberInfo), m => m.Name == nameof(MemberInfo.Name)); 177 | _stringFormat = ImportMethod(typeof(string), 178 | m => m.FullName == "System.String System.String::Format(System.String,System.Object,System.Object,System.Object)"); 179 | 180 | _beginSample = ImportMethod(typeof(Profiler), m => m.Name == nameof(Profiler.BeginSample) && m.Parameters.Count == 2); 181 | _endSample = ImportMethod(typeof(Profiler), m => m.Name == nameof(Profiler.EndSample)); 182 | } 183 | 184 | private bool TryFindRequiredAssemblyAttribute() 185 | { 186 | _unityEventCallRedirectorAttribute = ModuleDefinition.Assembly.CustomAttributes 187 | .FirstOrDefault(a => a.AttributeType.FullName == FullAttributeName); 188 | 189 | return _unityEventCallRedirectorAttribute != null; 190 | } 191 | 192 | private void LoadAttributeSetup() 193 | { 194 | var eventInterceptorTypeName = _unityEventCallRedirectorAttribute.ConstructorArguments[0].Value.ToString(); 195 | 196 | _eventInterceptorType = ModuleDefinition.Types.First(t => t.Name == eventInterceptorTypeName); 197 | _interceptMethod = _eventInterceptorType.Methods 198 | .First(m => m.Name == "Intercept" && m.GenericParameters.Count == 1); 199 | 200 | _replaceCallsFromNamespacesRegex = _unityEventCallRedirectorAttribute.ConstructorArguments[1].Value?.ToString(); 201 | _excludeFullMethodNameRegex = _unityEventCallRedirectorAttribute.Properties.Single(p => p.Name == nameof(UnityEventCallRedirectorAttribute.ExcludeFullMethodNameRegex)).Argument.Value?.ToString(); 202 | } 203 | 204 | private void LoadXmlSetup() 205 | { 206 | _fallbackSampleFormat = Config.Attribute(FallbackSampleNameFormatName)?.Value ?? DefaultFallbackSampleNameFormat; 207 | _replaceCallsFromNamespacesRegex = Config.Attribute(FallbackReplaceCallsFromNamespacesRegexName)?.Value ?? DefaultFallbackReplaceCallsFromNamespacesRegex; 208 | _excludeFullMethodNameRegex = Config.Attribute(FallbackExcludeFullMethodNameRegexName)?.Value ?? DefaultFallbackExcludeFullMethodNameRegex; 209 | } 210 | 211 | private MethodReference ImportMethod(Type type, Func methodPredicate) 212 | { 213 | return ModuleDefinition.ImportReference(ModuleDefinition.ImportReference(type).Resolve().Methods.First(methodPredicate)); 214 | } 215 | 216 | private MethodReference ImportPropertyGetter(Type type, Func propertyPredicate) 217 | { 218 | var prop = ModuleDefinition.ImportReference(type).Resolve().Properties.First(propertyPredicate); 219 | return ModuleDefinition.ImportReference(prop.GetMethod); 220 | } 221 | 222 | private class MethodDefinitionInstructionToReplacePair 223 | { 224 | public MethodDefinition MethodDefinition { get; } 225 | public Instruction Instruction { get; } 226 | 227 | public MethodDefinitionInstructionToReplacePair(MethodDefinition methodDefinition, Instruction instruction) 228 | { 229 | MethodDefinition = methodDefinition; 230 | Instruction = instruction; 231 | } 232 | } 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/ModuleWeaver.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b4fbe99e2aa3cba40bb1b9b0b3674eae 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/RequiredDll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 05fdb7c40225c0d48bc49a105d387201 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/RequiredDll/FodyHelpers_debug.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handzlikchris/Unity.VisualisingEventCallChains/680a827770ebe11d47505405e40bd2642a7d16bc/Assets/UnityEventCallRedirector.Fody/RequiredDll/FodyHelpers_debug.dll -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/RequiredDll/FodyHelpers_debug.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 45110aa6d8e60c941bccbe7f2ac627ba 3 | PluginImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | iconMap: {} 7 | executionOrder: {} 8 | defineConstraints: [] 9 | isPreloaded: 0 10 | isOverridable: 0 11 | isExplicitlyReferenced: 0 12 | validateReferences: 1 13 | platformData: 14 | - first: 15 | '': Any 16 | second: 17 | enabled: 0 18 | settings: 19 | Exclude Android: 1 20 | Exclude Editor: 0 21 | Exclude Linux64: 1 22 | Exclude OSXUniversal: 1 23 | Exclude Win: 1 24 | Exclude Win64: 1 25 | - first: 26 | Android: Android 27 | second: 28 | enabled: 0 29 | settings: 30 | CPU: ARMv7 31 | - first: 32 | Any: 33 | second: 34 | enabled: 0 35 | settings: {} 36 | - first: 37 | Editor: Editor 38 | second: 39 | enabled: 1 40 | settings: 41 | CPU: AnyCPU 42 | DefaultValueInitialized: true 43 | OS: AnyOS 44 | - first: 45 | Facebook: Win 46 | second: 47 | enabled: 0 48 | settings: 49 | CPU: AnyCPU 50 | - first: 51 | Facebook: Win64 52 | second: 53 | enabled: 0 54 | settings: 55 | CPU: AnyCPU 56 | - first: 57 | Standalone: Linux64 58 | second: 59 | enabled: 0 60 | settings: 61 | CPU: AnyCPU 62 | - first: 63 | Standalone: OSXUniversal 64 | second: 65 | enabled: 0 66 | settings: 67 | CPU: AnyCPU 68 | - first: 69 | Standalone: Win 70 | second: 71 | enabled: 0 72 | settings: 73 | CPU: AnyCPU 74 | - first: 75 | Standalone: Win64 76 | second: 77 | enabled: 0 78 | settings: 79 | CPU: AnyCPU 80 | - first: 81 | Windows Store Apps: WindowsStoreApps 82 | second: 83 | enabled: 0 84 | settings: 85 | CPU: AnyCPU 86 | userData: 87 | assetBundleName: 88 | assetBundleVariant: 89 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/RequiredDll/Mono.Cecil_debug.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handzlikchris/Unity.VisualisingEventCallChains/680a827770ebe11d47505405e40bd2642a7d16bc/Assets/UnityEventCallRedirector.Fody/RequiredDll/Mono.Cecil_debug.dll -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/RequiredDll/Mono.Cecil_debug.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dd3f328db12300940a1461d9c7f85a83 3 | PluginImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | iconMap: {} 7 | executionOrder: {} 8 | defineConstraints: [] 9 | isPreloaded: 0 10 | isOverridable: 0 11 | isExplicitlyReferenced: 0 12 | validateReferences: 1 13 | platformData: 14 | - first: 15 | '': Any 16 | second: 17 | enabled: 0 18 | settings: 19 | Exclude Android: 1 20 | Exclude Editor: 0 21 | Exclude Linux64: 1 22 | Exclude OSXUniversal: 1 23 | Exclude Win: 1 24 | Exclude Win64: 1 25 | - first: 26 | Android: Android 27 | second: 28 | enabled: 0 29 | settings: 30 | CPU: ARMv7 31 | - first: 32 | Any: 33 | second: 34 | enabled: 0 35 | settings: {} 36 | - first: 37 | Editor: Editor 38 | second: 39 | enabled: 1 40 | settings: 41 | CPU: AnyCPU 42 | DefaultValueInitialized: true 43 | OS: AnyOS 44 | - first: 45 | Facebook: Win 46 | second: 47 | enabled: 0 48 | settings: 49 | CPU: AnyCPU 50 | - first: 51 | Facebook: Win64 52 | second: 53 | enabled: 0 54 | settings: 55 | CPU: AnyCPU 56 | - first: 57 | Standalone: Linux64 58 | second: 59 | enabled: 0 60 | settings: 61 | CPU: AnyCPU 62 | - first: 63 | Standalone: OSXUniversal 64 | second: 65 | enabled: 0 66 | settings: 67 | CPU: AnyCPU 68 | - first: 69 | Standalone: Win 70 | second: 71 | enabled: 0 72 | settings: 73 | CPU: AnyCPU 74 | - first: 75 | Standalone: Win64 76 | second: 77 | enabled: 0 78 | settings: 79 | CPU: AnyCPU 80 | - first: 81 | Windows Store Apps: WindowsStoreApps 82 | second: 83 | enabled: 0 84 | settings: 85 | CPU: AnyCPU 86 | userData: 87 | assetBundleName: 88 | assetBundleVariant: 89 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/UnityEventCallRedirector.Fody.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UnityEventCallRedirector.Fody", 3 | "references": [ 4 | "UnityEventCallRedirector.Attribute" 5 | ], 6 | "includePlatforms": [], 7 | "excludePlatforms": [], 8 | "allowUnsafeCode": false, 9 | "overrideReferences": false, 10 | "precompiledReferences": [], 11 | "autoReferenced": true, 12 | "defineConstraints": [], 13 | "versionDefines": [] 14 | } -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.Fody/UnityEventCallRedirector.Fody.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 65f738f6656b4394c90a29908509c118 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f29b22de014f16e4389018e42611ea93 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/EditorButton.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aa0211667e2beb54d979a27d9a7e0e82 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/EditorButton/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dfbc0f8b4e196dd439a78077a2e43376 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/EditorButton/Editor/InspectorButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | // Initial Concept by http://www.reddit.com/user/zaikman 8 | // Revised by http://www.reddit.com/user/quarkism 9 | 10 | #if UNITY_EDITOR 11 | #endif 12 | 13 | #if UNITY_EDITOR 14 | [CustomEditor(typeof(MonoBehaviour), true)] 15 | public class EditorButton : UnityEditor.Editor 16 | { 17 | public override void OnInspectorGUI() 18 | { 19 | base.OnInspectorGUI(); 20 | 21 | var mono = target as MonoBehaviour; 22 | 23 | var methods = mono.GetType() 24 | .GetMembers(BindingFlags.Instance | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | 25 | BindingFlags.NonPublic) 26 | .Where(o => Attribute.IsDefined((MemberInfo)o, typeof(EditorButtonAttribute))); 27 | 28 | foreach (var memberInfo in methods) 29 | { 30 | if (GUILayout.Button(memberInfo.Name)) 31 | { 32 | var method = memberInfo as MethodInfo; 33 | method.Invoke(mono, null); 34 | } 35 | } 36 | } 37 | } 38 | #endif 39 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/EditorButton/Editor/InspectorButton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 050a7535e7cef7d48bde5eb28ccd1ffb 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/EditorButton/EditorButtonAttribute.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | [System.AttributeUsage(System.AttributeTargets.Method)] 4 | public class EditorButtonAttribute : PropertyAttribute 5 | { 6 | } -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/EditorButton/EditorButtonAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2fdf7a6a1d0c5b4b8b36b3669d1ccd5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/EventInterceptor.cs: -------------------------------------------------------------------------------- 1 | using Assets.UnityEventCallRedirector; 2 | using UnityEngine; 3 | using UnityEngine.Events; 4 | using UnityEngine.Profiling; 5 | using UnityEventCallRedirector.Attribute; 6 | 7 | [assembly: UnityEventCallRedirector( 8 | eventInterceptorTypeName: nameof(EventInterceptor), 9 | replaceCallsFromNamespacesRegex: ".*", 10 | ExcludeFullMethodNameRegex = "ObservableList.+::Start" 11 | )] 12 | 13 | namespace Assets.UnityEventCallRedirector 14 | { 15 | public class EventInterceptor 16 | { 17 | public static void Intercept(UnityEvent originalEvent, TArg arg, object self, string callingMethodName) 18 | { 19 | Profiler.BeginSample($"____{((MonoBehaviour)self).name} ({self.GetType().Name}) <{callingMethodName}>____+", (MonoBehaviour)self); 20 | originalEvent.Invoke(arg); 21 | Profiler.EndSample(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/EventInterceptor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6fb13628fa1f2d94fb355749a47e2c7b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | Info, Error, Warning 4 | ^Assembly-CSharp 5 | 6 | 7 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/FodyWeavers.xml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 108ebc620bf0bc44e8f697dfe11a4aac 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/ProfilerUtilities.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3509ffcb6a6297c4e9da0d61e394fbde 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/ProfilerUtilities/FrameFinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEditor.Performance.ProfileAnalyzer; 5 | using UnityEditor.Profiling; 6 | using UnityEditorInternal; 7 | using UnityEngine; 8 | 9 | public class FrameFinder : MonoBehaviour 10 | { 11 | public string FrameContains = ""; 12 | public int StartFrame = 0; 13 | public int EndFrame = -1; 14 | public int ThreadIndex = 0; 15 | public string LookInThread = "1:Main Thread"; 16 | 17 | private int LastFoundAtFrameIndex = 0; 18 | 19 | [EditorButton] 20 | private void ShowInProfiler() 21 | { 22 | ExecuteOnFoundProfilerFrame(FrameContains, ThreadIndex, StartFrame, 23 | EndFrame != -1 ? EndFrame : ProfilerDriver.lastFrameIndex, 24 | ShowFoundItemInProfiler); 25 | } 26 | 27 | private void ShowFoundItemInProfiler(HierarchyFrameDataView frameData, int matchingItemId, int frameIndex) 28 | { 29 | var goInstanceId = frameData.GetItemInstanceID(matchingItemId); 30 | var foundObject = EditorUtility.InstanceIDToObject(goInstanceId); 31 | //Selection.activeObject = foundObject; 32 | EditorGUIUtility.PingObject(foundObject); 33 | 34 | var profilerWindowInterface = new ProfilerWindowInterface(); 35 | profilerWindowInterface.OpenProfilerOrUseExisting(); 36 | profilerWindowInterface.JumpToFrame(frameIndex + 1); 37 | 38 | var markerName = frameData.GetItemName(matchingItemId); 39 | profilerWindowInterface.SetProfilerWindowMarkerName(markerName, new List() {LookInThread}); 40 | 41 | ProfilerDriver.enabled = false; 42 | EditorApplication.isPaused = true; 43 | } 44 | 45 | [EditorButton] 46 | private void FindNext() 47 | { 48 | ExecuteOnFoundProfilerFrame(FrameContains, ThreadIndex, LastFoundAtFrameIndex + 1, 49 | EndFrame != -1 ? EndFrame : ProfilerDriver.lastFrameIndex, 50 | ShowFoundItemInProfiler); 51 | } 52 | 53 | public int ExecuteOnFoundProfilerFrame(string frameContains, int threadIndex, int startFrame, int lastFrameIndex, 54 | Action executeOnceFound) 55 | { 56 | for (var frameIndex = startFrame; frameIndex <= lastFrameIndex; frameIndex++) 57 | { 58 | using (var frameData = ProfilerDriver.GetHierarchyFrameDataView(frameIndex, threadIndex, 59 | HierarchyFrameDataView.ViewModes.Default, HierarchyFrameDataView.columnSelfPercent, false)) 60 | { 61 | var rootId = frameData.GetRootItemID(); 62 | if (rootId != -1) 63 | { 64 | var matchingItemId = GetItemIdMatchingRecursive(frameData, rootId, 65 | (name) => name.Contains(frameContains)); 66 | 67 | if (matchingItemId != -1) 68 | { 69 | LastFoundAtFrameIndex = frameIndex; 70 | executeOnceFound(frameData, matchingItemId, frameIndex); 71 | return matchingItemId; 72 | } 73 | } 74 | } 75 | } 76 | 77 | return -1; 78 | } 79 | 80 | private static int GetItemIdMatchingRecursive(HierarchyFrameDataView frameData, int itemId, Func predicate) 81 | { 82 | string searchString = ""; 83 | 84 | var functionName = frameData.GetItemName(itemId); 85 | searchString += functionName; 86 | var goInstanceId = frameData.GetItemInstanceID(itemId); 87 | if (goInstanceId > 0) 88 | { 89 | var go = EditorUtility.InstanceIDToObject(goInstanceId); 90 | var typeName = go.GetType().Name; 91 | searchString += $" - {go.name} ({typeName})"; 92 | } 93 | 94 | var isMatch = predicate(searchString); 95 | if (isMatch) 96 | return itemId; 97 | else 98 | { 99 | var itemChildrenIds = new List(); 100 | frameData.GetItemChildren(itemId, itemChildrenIds); 101 | foreach (var childId in itemChildrenIds) 102 | { 103 | var foundId = GetItemIdMatchingRecursive(frameData, childId, predicate); 104 | if (foundId != -1) return foundId; 105 | } 106 | } 107 | 108 | return -1; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/ProfilerUtilities/FrameFinder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eaf9c969216928e44ad5e099418c0585 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/ProfilerUtilities/FrameItemSelected.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using UnityEditor.Performance.ProfileAnalyzer; 3 | using UnityEngine; 4 | 5 | [ExecuteInEditMode] 6 | public class FrameItemSelected : MonoBehaviour 7 | { 8 | public int FrameIndex; 9 | public string MarkerName; 10 | public int InstanceId; 11 | 12 | private ProfilerWindowInterface _profilerWindowInterface; 13 | 14 | private void Start() 15 | { 16 | } 17 | 18 | private void InitializePrifilerWindowInterface() 19 | { 20 | _profilerWindowInterface = new ProfilerWindowInterface(); 21 | _profilerWindowInterface.OpenProfilerOrUseExisting(); 22 | } 23 | 24 | [EditorButton] 25 | private void Update() 26 | { 27 | if(_profilerWindowInterface == null || _profilerWindowInterface.IsReady()) InitializePrifilerWindowInterface(); 28 | var timeLineGUI = _profilerWindowInterface.GetTimeLineGUI(); 29 | 30 | var m_SelectedEntryFieldInfo = (FieldInfo)typeof(ProfilerWindowInterface) 31 | .GetField("m_SelectedEntryFieldInfo", BindingFlags.NonPublic | BindingFlags.Instance) 32 | .GetValue(_profilerWindowInterface); 33 | var selectedEntry = m_SelectedEntryFieldInfo.GetValue(timeLineGUI); 34 | 35 | var m_SelectedEntryInstanceIdFieldInfo = (FieldInfo)typeof(ProfilerWindowInterface) 36 | .GetField("m_SelectedInstanceIdFieldInfo", BindingFlags.NonPublic | BindingFlags.Instance) 37 | .GetValue(_profilerWindowInterface); 38 | InstanceId = (int)m_SelectedEntryInstanceIdFieldInfo.GetValue(selectedEntry); 39 | 40 | var m_SelectedFrameIdFieldInfo = (FieldInfo)typeof(ProfilerWindowInterface) 41 | .GetField("m_SelectedFrameIdFieldInfo", BindingFlags.NonPublic | BindingFlags.Instance) 42 | .GetValue(_profilerWindowInterface); 43 | FrameIndex = (int)m_SelectedFrameIdFieldInfo.GetValue(selectedEntry); 44 | 45 | var m_SelectedNameFieldInfo = (FieldInfo)typeof(ProfilerWindowInterface) 46 | .GetField("m_SelectedNameFieldInfo", BindingFlags.NonPublic | BindingFlags.Instance) 47 | .GetValue(_profilerWindowInterface); 48 | MarkerName = (string)m_SelectedNameFieldInfo.GetValue(selectedEntry); 49 | } 50 | 51 | //private void FindDataForSelection() 52 | //{ 53 | // using (var frameData = ProfilerDriver.GetHierarchyFrameDataView(lastFrameIndex, threadIndex, 54 | // HierarchyFrameDataView.ViewModes.Default, HierarchyFrameDataView.columnSelfPercent, false)) 55 | // { 56 | // var rootId = frameData.GetRootItemID(); 57 | // if (rootId != -1) 58 | // { 59 | // var matchingItemId = GetItemIdMatchingRecursive(frameData, rootId, 60 | // (name) => name.Contains(frameContains)); 61 | 62 | // if (matchingItemId != -1) 63 | // { 64 | // executeOnceFound(frameData, matchingItemId, frameIndex); 65 | // return matchingItemId; 66 | // } 67 | // } 68 | // } 69 | //} 70 | } -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/ProfilerUtilities/FrameItemSelected.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a3f6b1128be9c3c4784df15128dee88f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/ProfilerUtilities/ProfileData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization.Formatters.Binary; 5 | using System.Text.RegularExpressions; 6 | using UnityEditorInternal; 7 | using UnityEngine; 8 | 9 | //This code comes directly from UnityEditor.Performance.ProfileAnalyzer, borrowed for simpler deployment 10 | 11 | namespace UnityEditor.Performance.ProfileAnalyzer 12 | { 13 | [Serializable] 14 | public class ProfileData 15 | { 16 | static int latestVersion = 7; 17 | /* 18 | Version 1 - Initial version. Thread names index:threadName (Some invalid thread names count:threadName index) 19 | Version 2 - Added frame start time. 20 | Version 3 - Saved out marker children times in the data (Never needed so rapidly skipped) 21 | Version 4 - Removed the child times again (at this point data was saved with 1 less frame at start and end) 22 | Version 5 - Updated the thread names to include the thread group as a prefix (index:threadGroup.threadName, index is 1 based, original is 0 based) 23 | Version 6 - fixed msStartTime (previously was 'seconds') 24 | Version 7 - Data now only skips the frame at the end 25 | */ 26 | private static Regex trailingDigit = new Regex(@"^(.*[^\s])[\s]+([\d]+)$", RegexOptions.Compiled); 27 | public int Version { get; private set; } 28 | private int frameIndexOffset = 0; 29 | private List frames = new List(); 30 | private List markerNames = new List(); 31 | private List threadNames = new List(); 32 | private Dictionary markerNamesDict = new Dictionary(); 33 | private Dictionary threadNameDict = new Dictionary(); 34 | 35 | public ProfileData() 36 | { 37 | Version = latestVersion; 38 | } 39 | 40 | private bool IsFrameSame(int frameIndex, ProfileData other) 41 | { 42 | ProfileFrame thisFrame = GetFrame(frameIndex); 43 | ProfileFrame otherFrame = other.GetFrame(frameIndex); 44 | return thisFrame.IsSame(otherFrame); 45 | } 46 | 47 | public bool IsSame(ProfileData other) 48 | { 49 | if (other == null) 50 | return false; 51 | 52 | int frameCount = GetFrameCount(); 53 | if (frameCount != other.GetFrameCount()) 54 | { 55 | // Frame counts differ 56 | return false; 57 | } 58 | 59 | if (frameCount == 0) 60 | { 61 | // Both empty 62 | return true; 63 | } 64 | 65 | if (!IsFrameSame(0, other)) 66 | return false; 67 | if (!IsFrameSame(frameCount - 1, other)) 68 | return false; 69 | 70 | // Close enough if same number of frames and first/last have exactly the same frame time and time offset. 71 | // If we see false matches we could add a full has of the data on load/pull 72 | return true; 73 | } 74 | 75 | static public string ThreadNameWithIndex(int index, string threadName) 76 | { 77 | return string.Format("{0}:{1}", index, threadName); 78 | } 79 | 80 | public void SetFrameIndexOffset(int offset) 81 | { 82 | frameIndexOffset = offset; 83 | } 84 | 85 | public int GetFrameCount() 86 | { 87 | return frames.Count; 88 | } 89 | 90 | public ProfileFrame GetFrame(int offset) 91 | { 92 | if (offset < 0 || offset >= frames.Count) 93 | return null; 94 | 95 | return frames[offset]; 96 | } 97 | 98 | public List GetThreadNames() 99 | { 100 | return threadNames; 101 | } 102 | 103 | public int OffsetToDisplayFrame(int offset) 104 | { 105 | return offset + (1 + frameIndexOffset); 106 | } 107 | 108 | public int DisplayFrameToOffset(int displayFrame) 109 | { 110 | return displayFrame - (1 + frameIndexOffset); 111 | } 112 | 113 | public void AddThreadName(string threadName, ProfileThread thread) 114 | { 115 | threadName = CorrectThreadName(threadName); 116 | 117 | int index = -1; 118 | 119 | if (!threadNameDict.TryGetValue(threadName, out index)) 120 | { 121 | threadNames.Add(threadName); 122 | index = threadNames.Count - 1; 123 | 124 | threadNameDict.Add(threadName, index); 125 | } 126 | 127 | thread.threadIndex = index; 128 | } 129 | 130 | public void AddMarkerName(string markerName, ProfileMarker marker) 131 | { 132 | int index = -1; 133 | if (!markerNamesDict.TryGetValue(markerName, out index)) 134 | { 135 | markerNames.Add(markerName); 136 | index = markerNames.Count - 1; 137 | 138 | markerNamesDict.Add(markerName, index); 139 | } 140 | 141 | marker.nameIndex = index; 142 | } 143 | 144 | public string GetThreadName(ProfileThread thread) 145 | { 146 | return threadNames[thread.threadIndex]; 147 | } 148 | 149 | public string GetMarkerName(ProfileMarker marker) 150 | { 151 | return markerNames[marker.nameIndex]; 152 | } 153 | 154 | public int GetMarkerIndex(string markerName) 155 | { 156 | for (int nameIndex = 0; nameIndex < markerNames.Count; ++nameIndex) 157 | { 158 | if (markerName == markerNames[nameIndex]) 159 | return nameIndex; 160 | } 161 | return -1; 162 | } 163 | 164 | public void Add(ProfileFrame frame) 165 | { 166 | frames.Add(frame); 167 | } 168 | 169 | public void Write(BinaryWriter writer) 170 | { 171 | Version = latestVersion; 172 | 173 | writer.Write(Version); 174 | writer.Write(frameIndexOffset); 175 | 176 | writer.Write(frames.Count); 177 | foreach (var frame in frames) 178 | { 179 | frame.Write(writer); 180 | }; 181 | 182 | writer.Write(markerNames.Count); 183 | foreach (var markerName in markerNames) 184 | { 185 | writer.Write(markerName); 186 | }; 187 | 188 | writer.Write(threadNames.Count); 189 | foreach (var threadName in threadNames) 190 | { 191 | writer.Write(threadName); 192 | }; 193 | } 194 | 195 | public static string CorrectThreadName(string threadNameWithIndex) 196 | { 197 | var info = threadNameWithIndex.Split(':'); 198 | if (info.Length >= 2) 199 | { 200 | string threadGroupIndexString = info[0]; 201 | string threadName = info[1]; 202 | if (threadName.Trim() == "") 203 | { 204 | // Scan seen with no thread name 205 | threadNameWithIndex = string.Format("{0}:[Unknown]", threadGroupIndexString); 206 | } 207 | else 208 | { 209 | // Some scans have thread names such as 210 | // "1:Worker Thread 0" 211 | // "1:Worker Thread 1" 212 | // rather than 213 | // "1:Worker Thread" 214 | // "2:Worker Thread" 215 | // Update to the second format so the 'All' case is correctly determined 216 | Match m = trailingDigit.Match(threadName); 217 | if (m.Success) 218 | { 219 | string threadNamePrefix = m.Groups[1].Value; 220 | int threadGroupIndex = 1 + int.Parse(m.Groups[2].Value); 221 | 222 | threadNameWithIndex = string.Format("{0}:{1}", threadGroupIndex, threadNamePrefix); 223 | } 224 | } 225 | } 226 | 227 | threadNameWithIndex = threadNameWithIndex.Trim(); 228 | 229 | return threadNameWithIndex; 230 | } 231 | 232 | public static string GetThreadNameWithGroup(string threadName, string groupName) 233 | { 234 | if (string.IsNullOrEmpty(groupName)) 235 | return threadName; 236 | 237 | return string.Format("{0}.{1}", groupName, threadName); 238 | } 239 | 240 | public static string GetThreadNameWithoutGroup(string threadNameWithGroup, out string groupName) 241 | { 242 | string[] tokens = threadNameWithGroup.Split('.'); 243 | if (tokens.Length <= 1) 244 | { 245 | groupName = ""; 246 | return tokens[0]; 247 | } 248 | 249 | groupName = tokens[0]; 250 | return tokens[1].TrimStart(); 251 | } 252 | 253 | public ProfileData(BinaryReader reader) 254 | { 255 | Version = reader.ReadInt32(); 256 | if (Version < 0 || Version > latestVersion) 257 | { 258 | throw new Exception(String.Format("File version unsupported : {0} != {1} expected", Version, latestVersion)); 259 | } 260 | 261 | frameIndexOffset = reader.ReadInt32(); 262 | int frameCount = reader.ReadInt32(); 263 | frames.Clear(); 264 | for (int frame = 0; frame < frameCount; frame++) 265 | { 266 | frames.Add(new ProfileFrame(reader, Version)); 267 | } 268 | 269 | int markerCount = reader.ReadInt32(); 270 | markerNames.Clear(); 271 | for (int marker = 0; marker < markerCount; marker++) 272 | { 273 | markerNames.Add(reader.ReadString()); 274 | } 275 | 276 | int threadCount = reader.ReadInt32(); 277 | threadNames.Clear(); 278 | for (int thread = 0; thread < threadCount; thread++) 279 | { 280 | var threadNameWithIndex = reader.ReadString(); 281 | 282 | threadNameWithIndex = CorrectThreadName(threadNameWithIndex); 283 | 284 | threadNames.Add(threadNameWithIndex); 285 | } 286 | } 287 | 288 | public static bool Save(string filename, ProfileData data) 289 | { 290 | if (filename.EndsWith(".json")) 291 | { 292 | var json = JsonUtility.ToJson(data); 293 | File.WriteAllText(filename, json); 294 | } 295 | else if (filename.EndsWith(".padata")) 296 | { 297 | FileStream stream = File.Create(filename); 298 | var formatter = new BinaryFormatter(); 299 | formatter.Serialize(stream, data); 300 | stream.Close(); 301 | } 302 | else if (filename.EndsWith(".pdata")) 303 | { 304 | FileStream stream = File.Create(filename); 305 | using (var writer = new BinaryWriter(stream)) 306 | { 307 | data.Write(writer); 308 | } 309 | } 310 | 311 | return true; 312 | } 313 | 314 | public static bool Load(string filename, out ProfileData data) 315 | { 316 | if (filename.EndsWith(".json")) 317 | { 318 | string json = File.ReadAllText(filename); 319 | data = JsonUtility.FromJson(json); 320 | } 321 | else if (filename.EndsWith(".padata")) 322 | { 323 | FileStream stream = File.OpenRead(filename); 324 | var formatter = new BinaryFormatter(); 325 | data = (ProfileData)formatter.Deserialize(stream); 326 | stream.Close(); 327 | 328 | if (data.Version != latestVersion) 329 | { 330 | Debug.Log(String.Format("Incorrect file version in {0} : (file {1} != {2} expected", filename, data.Version, latestVersion)); 331 | data = null; 332 | return false; 333 | } 334 | } 335 | else if (filename.EndsWith(".pdata")) 336 | { 337 | FileStream stream = File.OpenRead(filename); 338 | using (var reader = new BinaryReader(stream)) 339 | { 340 | try 341 | { 342 | data = new ProfileData(reader); 343 | } 344 | catch (Exception e) 345 | { 346 | Debug.Log(String.Format("Incorrect file version in {0} : {1}", filename, e.ToString())); 347 | data = null; 348 | return false; 349 | } 350 | } 351 | } 352 | else 353 | { 354 | data = null; 355 | return false; 356 | } 357 | 358 | // When loaded from disk the frame index offset is currently reset in the profiler view 359 | if (data.Version >= 3 && data.Version <= 6) 360 | { 361 | // This range of versions saved the data with the first frame skipped (and last frame omitted) 362 | data.frameIndexOffset = 1; 363 | } 364 | else 365 | { 366 | data.frameIndexOffset = 0; 367 | } 368 | 369 | data.Finalise(); 370 | return true; 371 | } 372 | 373 | private void PushMarker(List markerStack, ProfileMarker markerData) 374 | { 375 | Debug.Assert(markerData.depth == markerStack.Count + 1); 376 | markerStack.Add(markerData); 377 | } 378 | 379 | private ProfileMarker PopMarkerAndRecordTimeInParent(List markerStack) 380 | { 381 | ProfileMarker child = markerStack[markerStack.Count - 1]; 382 | markerStack.RemoveAt(markerStack.Count - 1); 383 | 384 | ProfileMarker parentMarker = (markerStack.Count > 0) ? markerStack[markerStack.Count - 1] : null; 385 | 386 | // Record the last markers time in its parent 387 | if (parentMarker != null) 388 | parentMarker.msChildren += child.msMarkerTotal; 389 | 390 | return parentMarker; 391 | } 392 | 393 | public void Finalise() 394 | { 395 | CalculateMarkerChildTimes(); 396 | markerNamesDict.Clear(); 397 | } 398 | 399 | private void CalculateMarkerChildTimes() 400 | { 401 | var markerStack = new List(); 402 | 403 | for (int frameOffset = 0; frameOffset <= frames.Count; ++frameOffset) 404 | { 405 | var frameData = GetFrame(frameOffset); 406 | if (frameData == null) 407 | continue; 408 | 409 | for (int threadIndex = 0; threadIndex < frameData.threads.Count; threadIndex++) 410 | { 411 | var threadData = frameData.threads[threadIndex]; 412 | 413 | // The markers are in depth first order and the depth is known 414 | // So we can infer a parent child relationship 415 | // Zero them first 416 | foreach (ProfileMarker markerData in threadData.markers) 417 | { 418 | markerData.msChildren = 0.0f; 419 | } 420 | 421 | // Update the child times 422 | markerStack.Clear(); 423 | foreach (ProfileMarker markerData in threadData.markers) 424 | { 425 | int depth = markerData.depth; 426 | 427 | // Update depth stack and record child times in the parent 428 | if (depth >= markerStack.Count) 429 | { 430 | // If at same level then remove the last item at this level 431 | if (depth == markerStack.Count) 432 | { 433 | PopMarkerAndRecordTimeInParent(markerStack); 434 | } 435 | 436 | // Assume we can't move down depth without markers between levels. 437 | } 438 | else if (depth < markerStack.Count) 439 | { 440 | // We can move up depth several layers so need to pop off all those markers 441 | while (markerStack.Count >= depth) 442 | { 443 | PopMarkerAndRecordTimeInParent(markerStack); 444 | } 445 | } 446 | 447 | PushMarker(markerStack, markerData); 448 | } 449 | } 450 | } 451 | } 452 | } 453 | 454 | [Serializable] 455 | public class ProfileFrame 456 | { 457 | public List threads = new List(); 458 | public double msStartTime; 459 | public float msFrame; 460 | 461 | public ProfileFrame() 462 | { 463 | } 464 | 465 | public bool IsSame(ProfileFrame otherFrame) 466 | { 467 | if (msStartTime != otherFrame.msStartTime) 468 | return false; 469 | if (msFrame != otherFrame.msFrame) 470 | return false; 471 | if (threads.Count != otherFrame.threads.Count) 472 | return false; 473 | 474 | // Close enough. 475 | return true; 476 | } 477 | 478 | public void Add(ProfileThread thread) 479 | { 480 | threads.Add(thread); 481 | } 482 | 483 | public void Write(BinaryWriter writer) 484 | { 485 | writer.Write(msStartTime); 486 | writer.Write(msFrame); 487 | writer.Write(threads.Count); 488 | foreach (var thread in threads) 489 | { 490 | thread.Write(writer); 491 | }; 492 | } 493 | 494 | public ProfileFrame(BinaryReader reader, int fileVersion) 495 | { 496 | if (fileVersion > 1) 497 | { 498 | if (fileVersion >= 6) 499 | { 500 | msStartTime = reader.ReadDouble(); 501 | } 502 | else 503 | { 504 | double sStartTime = reader.ReadDouble(); 505 | msStartTime = sStartTime * 1000.0; 506 | } 507 | } 508 | 509 | msFrame = reader.ReadSingle(); 510 | int threadCount = reader.ReadInt32(); 511 | threads.Clear(); 512 | for (int thread = 0; thread < threadCount; thread++) 513 | { 514 | threads.Add(new ProfileThread(reader, fileVersion)); 515 | } 516 | } 517 | } 518 | 519 | [Serializable] 520 | public class ProfileThread 521 | { 522 | public List markers = new List(); 523 | public int threadIndex; 524 | 525 | public ProfileThread() 526 | { 527 | } 528 | 529 | public void Add(ProfileMarker marker) 530 | { 531 | markers.Add(marker); 532 | } 533 | 534 | public void Write(BinaryWriter writer) 535 | { 536 | writer.Write(threadIndex); 537 | writer.Write(markers.Count); 538 | foreach (var marker in markers) 539 | { 540 | marker.Write(writer); 541 | }; 542 | } 543 | 544 | public ProfileThread(BinaryReader reader, int fileVersion) 545 | { 546 | threadIndex = reader.ReadInt32(); 547 | int markerCount = reader.ReadInt32(); 548 | markers.Clear(); 549 | for (int marker = 0; marker < markerCount; marker++) 550 | { 551 | markers.Add(new ProfileMarker(reader, fileVersion)); 552 | } 553 | } 554 | } 555 | 556 | [Serializable] 557 | public class ProfileMarker 558 | { 559 | public int nameIndex; 560 | public float msMarkerTotal; 561 | public int depth; 562 | public float msChildren; // Recalculated on load so not saved in file 563 | 564 | public ProfileMarker() 565 | { 566 | } 567 | 568 | public static ProfileMarker Create(ProfilerFrameDataIterator frameData) 569 | { 570 | var item = new ProfileMarker 571 | { 572 | msMarkerTotal = frameData.durationMS, 573 | depth = frameData.depth, 574 | msChildren = 0.0f 575 | }; 576 | 577 | return item; 578 | } 579 | 580 | public void Write(BinaryWriter writer) 581 | { 582 | writer.Write(nameIndex); 583 | writer.Write(msMarkerTotal); 584 | writer.Write(depth); 585 | } 586 | 587 | public ProfileMarker(BinaryReader reader, int fileVersion) 588 | { 589 | nameIndex = reader.ReadInt32(); 590 | msMarkerTotal = reader.ReadSingle(); 591 | depth = reader.ReadInt32(); 592 | if (fileVersion == 3) // In this version we saved the msChildren value but we don't need to as we now recalculate on load 593 | msChildren = reader.ReadSingle(); 594 | else 595 | msChildren = 0.0f; 596 | } 597 | } 598 | } -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/ProfilerUtilities/ProfileData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 994d76fefe25910479d6d4357417b51f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/ProfilerUtilities/ProfilerWindowInterface.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using UnityEditor; 6 | using UnityEditorInternal; 7 | using UnityEngine; 8 | using UnityEngine.Profiling; 9 | 10 | //This code comes directly from UnityEditor.Performance.ProfileAnalyzer, borrowed for simpler deployment 11 | 12 | namespace UnityEditor.Performance.ProfileAnalyzer 13 | { 14 | public class ProfilerWindowInterface 15 | { 16 | private Type m_ProfilerWindowType; 17 | private EditorWindow m_ProfilerWindow; 18 | private FieldInfo m_CurrentFrameFieldInfo; 19 | private FieldInfo m_TimeLineGUIFieldInfo; 20 | private FieldInfo m_SelectedEntryFieldInfo; 21 | private FieldInfo m_SelectedNameFieldInfo; 22 | private FieldInfo m_SelectedTimeFieldInfo; 23 | private FieldInfo m_SelectedDurationFieldInfo; 24 | private FieldInfo m_SelectedInstanceIdFieldInfo; 25 | private FieldInfo m_SelectedInstanceCountFieldInfo; 26 | private FieldInfo m_SelectedFrameIdFieldInfo; 27 | private FieldInfo m_SelectedThreadIdFieldInfo; 28 | private FieldInfo m_SelectedNativeIndexFieldInfo; 29 | 30 | private MethodInfo m_GetProfilerModuleInfo; 31 | private Type m_CPUProfilerModuleType; 32 | 33 | public ProfilerWindowInterface() 34 | { 35 | Assembly assem = typeof(Editor).Assembly; 36 | m_ProfilerWindowType = assem.GetType("UnityEditor.ProfilerWindow"); 37 | m_CurrentFrameFieldInfo = m_ProfilerWindowType.GetField("m_CurrentFrame", BindingFlags.NonPublic | BindingFlags.Instance); 38 | 39 | m_TimeLineGUIFieldInfo = m_ProfilerWindowType.GetField("m_CPUTimelineGUI", BindingFlags.NonPublic | BindingFlags.Instance); 40 | if (m_TimeLineGUIFieldInfo == null) 41 | { 42 | // m_CPUTimelineGUI isn't present in 2019.3.0a8 onward 43 | m_GetProfilerModuleInfo = m_ProfilerWindowType.GetMethod("GetProfilerModule", BindingFlags.NonPublic | BindingFlags.Instance); 44 | if (m_GetProfilerModuleInfo == null) 45 | { 46 | Debug.Log("Unable to initialise link to Profiler Timeline, no GetProfilerModule found"); 47 | } 48 | 49 | m_CPUProfilerModuleType = assem.GetType("UnityEditorInternal.Profiling.CPUProfilerModule"); 50 | m_TimeLineGUIFieldInfo = m_CPUProfilerModuleType.GetField("m_TimelineGUI", BindingFlags.NonPublic | BindingFlags.Instance); 51 | if (m_TimeLineGUIFieldInfo == null) 52 | { 53 | Debug.Log("Unable to initialise link to Profiler Timeline"); 54 | } 55 | } 56 | 57 | if (m_TimeLineGUIFieldInfo != null) 58 | m_SelectedEntryFieldInfo = m_TimeLineGUIFieldInfo.FieldType.GetField("m_SelectedEntry", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 59 | if (m_SelectedEntryFieldInfo != null) 60 | { 61 | m_SelectedNameFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("name", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 62 | m_SelectedTimeFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("time", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 63 | m_SelectedDurationFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("duration", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 64 | m_SelectedInstanceIdFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("instanceId", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 65 | m_SelectedInstanceCountFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("instanceCount", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 66 | m_SelectedFrameIdFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("frameId", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 67 | m_SelectedThreadIdFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("threadId", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 68 | m_SelectedNativeIndexFieldInfo = m_SelectedEntryFieldInfo.FieldType.GetField("nativeIndex", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 69 | } 70 | 71 | } 72 | 73 | /* 74 | public EditorWindow GetProfileWindow() 75 | { 76 | return m_profilerWindow; 77 | } 78 | */ 79 | 80 | public bool IsReady() 81 | { 82 | if (m_ProfilerWindow != null) 83 | return true; 84 | 85 | return false; 86 | } 87 | 88 | public bool IsProfilerWindowOpen() 89 | { 90 | Profiler.BeginSample("IsProfilerWindowOpen"); 91 | UnityEngine.Object[] windows = Resources.FindObjectsOfTypeAll(m_ProfilerWindowType); 92 | bool result = (windows != null && windows.Length > 0) ? true : false; 93 | Profiler.EndSample(); 94 | 95 | return result; 96 | } 97 | 98 | public void OpenProfilerOrUseExisting() 99 | { 100 | m_ProfilerWindow = EditorWindow.GetWindow(m_ProfilerWindowType); 101 | } 102 | 103 | public bool GetFrameRangeFromProfiler(out int first, out int last) 104 | { 105 | if (m_ProfilerWindow) 106 | //if (ProfilerDriver.enabled) 107 | { 108 | first = 1 + ProfilerDriver.firstFrameIndex; 109 | last = 1 + ProfilerDriver.lastFrameIndex; 110 | // Clip to the visible frames in the profile which indents 1 in from end 111 | if (first < last) 112 | last--; 113 | return true; 114 | } 115 | 116 | first = 1; 117 | last = 1; 118 | return false; 119 | } 120 | 121 | public void CloseProfiler() 122 | { 123 | if (m_ProfilerWindow) 124 | m_ProfilerWindow.Close(); 125 | } 126 | 127 | public object GetTimeLineGUI() 128 | { 129 | object timeLineGUI = null; 130 | 131 | if (m_CPUProfilerModuleType != null) 132 | { 133 | object[] parametersArray = new object[] { ProfilerArea.CPU }; 134 | var getCPUProfilerModuleInfo = m_GetProfilerModuleInfo.MakeGenericMethod(m_CPUProfilerModuleType); 135 | var cpuModule = getCPUProfilerModuleInfo.Invoke(m_ProfilerWindow, parametersArray); 136 | 137 | timeLineGUI = m_TimeLineGUIFieldInfo.GetValue(cpuModule); 138 | } 139 | else if (m_TimeLineGUIFieldInfo != null) 140 | { 141 | timeLineGUI = m_TimeLineGUIFieldInfo.GetValue(m_ProfilerWindow); 142 | } 143 | 144 | return timeLineGUI; 145 | } 146 | 147 | public string GetProfilerWindowMarkerName() 148 | { 149 | if (m_ProfilerWindow != null) 150 | { 151 | var timeLineGUI = GetTimeLineGUI(); 152 | if (timeLineGUI != null && m_SelectedEntryFieldInfo != null) 153 | { 154 | var selectedEntry = m_SelectedEntryFieldInfo.GetValue(timeLineGUI); 155 | if (selectedEntry != null && m_SelectedNameFieldInfo != null) 156 | { 157 | return m_SelectedNameFieldInfo.GetValue(selectedEntry).ToString(); 158 | } 159 | } 160 | } 161 | 162 | return null; 163 | } 164 | 165 | public float GetFrameTime(int frameIndex) 166 | { 167 | ProfilerFrameDataIterator frameData = new ProfilerFrameDataIterator(); 168 | 169 | frameData.SetRoot(frameIndex, 0); 170 | float ms = frameData.frameTimeMS; 171 | frameData.Dispose(); 172 | 173 | return ms; 174 | } 175 | 176 | private bool GetMarkerInfo(string markerName, int frameIndex, List threadFilters, out int outThreadIndex, out float time, out float duration, out int instanceId) 177 | { 178 | ProfilerFrameDataIterator frameData = new ProfilerFrameDataIterator(); 179 | 180 | outThreadIndex = 0; 181 | time = 0.0f; 182 | duration = 0.0f; 183 | instanceId = 0; 184 | bool found = false; 185 | 186 | int threadCount = frameData.GetThreadCount(frameIndex); 187 | Dictionary threadNameCount = new Dictionary(); 188 | for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex) 189 | { 190 | frameData.SetRoot(frameIndex, threadIndex); 191 | 192 | var threadName = frameData.GetThreadName(); 193 | // Name here could be "Worker Thread 1" 194 | 195 | var groupName = frameData.GetGroupName(); 196 | threadName = ProfileData.GetThreadNameWithGroup(threadName, groupName); 197 | 198 | int nameCount = 0; 199 | threadNameCount.TryGetValue(threadName, out nameCount); 200 | threadNameCount[threadName] = nameCount + 1; 201 | 202 | var threadNameWithIndex = ProfileData.ThreadNameWithIndex(threadNameCount[threadName], threadName); 203 | 204 | // To compare on the filter we need to remove the postfix on the thread name 205 | // "3:Worker Thread 0" -> "1:Worker Thread" 206 | // The index of the thread (0) is used +1 as a prefix 207 | // The preceding number (3) is the count of number of threads with this name 208 | // Unfortunately multiple threads can have the same name 209 | threadNameWithIndex = ProfileData.CorrectThreadName(threadNameWithIndex); 210 | 211 | if (threadFilters.Contains(threadNameWithIndex)) 212 | { 213 | const bool enterChildren = true; 214 | while (frameData.Next(enterChildren)) 215 | { 216 | if (frameData.name == markerName) 217 | { 218 | time = frameData.startTimeMS; 219 | duration = frameData.durationMS; 220 | instanceId = frameData.instanceId; 221 | outThreadIndex = threadIndex; 222 | found = true; 223 | break; 224 | } 225 | } 226 | } 227 | 228 | if (found) 229 | break; 230 | } 231 | 232 | frameData.Dispose(); 233 | return found; 234 | } 235 | 236 | public void SetProfilerWindowMarkerName(string markerName, List threadFilters) 237 | { 238 | if (m_ProfilerWindow == null) 239 | return; 240 | 241 | var timeLineGUI = GetTimeLineGUI(); 242 | if (timeLineGUI == null) 243 | return; 244 | 245 | if (m_SelectedEntryFieldInfo != null) 246 | { 247 | var selectedEntry = m_SelectedEntryFieldInfo.GetValue(timeLineGUI); 248 | if (selectedEntry != null) 249 | { 250 | // Read profiler data direct from profile to find time/duration 251 | int currentFrameIndex = (int)m_CurrentFrameFieldInfo.GetValue(m_ProfilerWindow); 252 | float time; 253 | float duration; 254 | int instanceId; 255 | int threadIndex; 256 | if (GetMarkerInfo(markerName, currentFrameIndex, threadFilters, out threadIndex, out time, out duration, out instanceId)) 257 | { 258 | /* 259 | Debug.Log(string.Format("Setting profiler to {0} on {1} at frame {2} at {3}ms for {4}ms ({5})", 260 | markerName, currentFrameIndex, threadFilter, time, duration, instanceId)); 261 | */ 262 | 263 | if (m_SelectedNameFieldInfo != null) 264 | m_SelectedNameFieldInfo.SetValue(selectedEntry, markerName); 265 | if (m_SelectedTimeFieldInfo != null) 266 | m_SelectedTimeFieldInfo.SetValue(selectedEntry, time); 267 | if (m_SelectedDurationFieldInfo != null) 268 | m_SelectedDurationFieldInfo.SetValue(selectedEntry, duration); 269 | if (m_SelectedInstanceIdFieldInfo != null) 270 | m_SelectedInstanceIdFieldInfo.SetValue(selectedEntry, instanceId); 271 | if (m_SelectedFrameIdFieldInfo != null) 272 | m_SelectedFrameIdFieldInfo.SetValue(selectedEntry, currentFrameIndex); 273 | if (m_SelectedThreadIdFieldInfo != null) 274 | m_SelectedThreadIdFieldInfo.SetValue(selectedEntry, threadIndex); 275 | 276 | // TODO : Update to fill in the total and number of instances. 277 | // For now we force Instance count to 1 to avoid the incorrect info showing. 278 | if (m_SelectedInstanceCountFieldInfo != null) 279 | m_SelectedInstanceCountFieldInfo.SetValue(selectedEntry, 1); 280 | 281 | // Set other values to non negative values so selection appears 282 | if (m_SelectedNativeIndexFieldInfo != null) 283 | m_SelectedNativeIndexFieldInfo.SetValue(selectedEntry, currentFrameIndex); 284 | 285 | m_ProfilerWindow.Repaint(); 286 | } 287 | } 288 | } 289 | } 290 | 291 | public bool JumpToFrame(int index) 292 | { 293 | //if (!ProfilerDriver.enabled) 294 | // return; 295 | 296 | if (!m_ProfilerWindow) 297 | return false; 298 | 299 | m_CurrentFrameFieldInfo.SetValue(m_ProfilerWindow, index - 1); 300 | m_ProfilerWindow.Repaint(); 301 | return true; 302 | } 303 | } 304 | 305 | } -------------------------------------------------------------------------------- /Assets/UnityEventCallRedirector/ProfilerUtilities/ProfilerWindowInterface.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0ad8b764e71d03b48b1b8e665ca36746 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Chris Handzlik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { "scopedRegistries": [ 2 | { 3 | "name": "npmjs", 4 | "url": "https://registry.npmjs.org/", 5 | "scopes": [ 6 | "io.extendreality" 7 | ] 8 | } 9 | ], 10 | "dependencies": { 11 | "io.extendreality.malimbe": "9.6.5", 12 | "com.unity.collab-proxy": "1.2.16", 13 | "com.unity.ext.nunit": "1.0.0", 14 | "com.unity.ide.rider": "1.1.0", 15 | "com.unity.ide.vscode": "1.1.2", 16 | "com.unity.package-manager-ui": "2.2.0", 17 | "com.unity.test-framework": "1.0.13", 18 | "com.unity.textmeshpro": "2.0.1", 19 | "com.unity.timeline": "1.1.0", 20 | "com.unity.ugui": "1.0.0", 21 | "com.unity.modules.ai": "1.0.0", 22 | "com.unity.modules.androidjni": "1.0.0", 23 | "com.unity.modules.animation": "1.0.0", 24 | "com.unity.modules.assetbundle": "1.0.0", 25 | "com.unity.modules.audio": "1.0.0", 26 | "com.unity.modules.cloth": "1.0.0", 27 | "com.unity.modules.director": "1.0.0", 28 | "com.unity.modules.imageconversion": "1.0.0", 29 | "com.unity.modules.imgui": "1.0.0", 30 | "com.unity.modules.jsonserialize": "1.0.0", 31 | "com.unity.modules.particlesystem": "1.0.0", 32 | "com.unity.modules.physics": "1.0.0", 33 | "com.unity.modules.physics2d": "1.0.0", 34 | "com.unity.modules.screencapture": "1.0.0", 35 | "com.unity.modules.terrain": "1.0.0", 36 | "com.unity.modules.terrainphysics": "1.0.0", 37 | "com.unity.modules.tilemap": "1.0.0", 38 | "com.unity.modules.ui": "1.0.0", 39 | "com.unity.modules.uielements": "1.0.0", 40 | "com.unity.modules.umbra": "1.0.0", 41 | "com.unity.modules.unityanalytics": "1.0.0", 42 | "com.unity.modules.unitywebrequest": "1.0.0", 43 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 44 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 45 | "com.unity.modules.unitywebrequesttexture": "1.0.0", 46 | "com.unity.modules.unitywebrequestwww": "1.0.0", 47 | "com.unity.modules.vehicles": "1.0.0", 48 | "com.unity.modules.video": "1.0.0", 49 | "com.unity.modules.vr": "1.0.0", 50 | "com.unity.modules.wind": "1.0.0", 51 | "com.unity.modules.xr": "1.0.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Volume: 1 8 | Rolloff Scale: 1 9 | Doppler Factor: 1 10 | Default Speaker Mode: 2 11 | m_SampleRate: 0 12 | m_DSPBufferSize: 1024 13 | m_VirtualVoiceCount: 512 14 | m_RealVoiceCount: 32 15 | m_SpatializerPlugin: 16 | m_AmbisonicDecoderPlugin: 17 | m_DisableAudio: 0 18 | m_VirtualizeEffects: 1 19 | m_RequestedDSPBufferSize: 1024 20 | -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 0 23 | m_ReuseCollisionCallbacks: 1 24 | m_ClothInterCollisionSettingsToggle: 0 25 | m_ContactPairsMode: 0 26 | m_BroadphaseType: 0 27 | m_WorldBounds: 28 | m_Center: {x: 0, y: 0, z: 0} 29 | m_Extent: {x: 250, y: 250, z: 250} 30 | m_WorldSubdivisions: 8 31 | m_FrictionType: 0 32 | m_EnableEnhancedDeterminism: 0 33 | m_EnableUnifiedHeightmaps: 1 34 | m_DefaultMaxAngluarSpeed: 7 35 | -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | m_configObjects: {} 9 | -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 8 7 | m_ExternalVersionControlSupport: Hidden Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 2 10 | m_DefaultBehaviorMode: 0 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 0 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref 20 | m_ProjectGenerationRootNamespace: 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | m_ShowLightmapResolutionOverlay: 1 27 | -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 12 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | m_PreloadedShaders: [] 39 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 40 | type: 0} 41 | m_CustomRenderPipeline: {fileID: 0} 42 | m_TransparencySortMode: 0 43 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 44 | m_DefaultRenderingPath: 1 45 | m_DefaultMobileRenderingPath: 1 46 | m_TierSettings: [] 47 | m_LightmapStripping: 0 48 | m_FogStripping: 0 49 | m_InstancingStripping: 0 50 | m_LightmapKeepPlain: 1 51 | m_LightmapKeepDirCombined: 1 52 | m_LightmapKeepDynamicPlain: 1 53 | m_LightmapKeepDynamicDirCombined: 1 54 | m_LightmapKeepShadowMask: 1 55 | m_LightmapKeepSubtractive: 1 56 | m_FogKeepLinear: 1 57 | m_FogKeepExp: 1 58 | m_FogKeepExp2: 1 59 | m_AlbedoSwatchInfos: [] 60 | m_LightsUseLinearIntensity: 0 61 | m_LightsUseColorTemperature: 0 62 | -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left shift 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_JobOptions: 23 | serializedVersion: 2 24 | useMultithreading: 0 25 | useConsistencySorting: 0 26 | m_InterpolationPosesPerJob: 100 27 | m_NewContactsPerJob: 30 28 | m_CollideContactsPerJob: 100 29 | m_ClearFlagsPerJob: 200 30 | m_ClearBodyForcesPerJob: 200 31 | m_SyncDiscreteFixturesPerJob: 50 32 | m_SyncContinuousFixturesPerJob: 50 33 | m_FindNearestContactsPerJob: 100 34 | m_UpdateTriggerContactsPerJob: 100 35 | m_IslandSolverCostThreshold: 100 36 | m_IslandSolverBodyCostScale: 1 37 | m_IslandSolverContactCostScale: 10 38 | m_IslandSolverJointCostScale: 10 39 | m_IslandSolverBodiesPerJob: 50 40 | m_IslandSolverContactsPerJob: 50 41 | m_AutoSimulation: 1 42 | m_QueriesHitTriggers: 1 43 | m_QueriesStartInColliders: 1 44 | m_CallbacksOnDisable: 1 45 | m_ReuseCollisionCallbacks: 1 46 | m_AutoSyncTransforms: 0 47 | m_AlwaysShowColliders: 0 48 | m_ShowColliderSleep: 1 49 | m_ShowColliderContacts: 0 50 | m_ShowColliderAABB: 0 51 | m_ContactArrowScale: 0.2 52 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 53 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 54 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 55 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 56 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 57 | -------------------------------------------------------------------------------- /ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | m_DefaultList: [] 7 | -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!129 &1 4 | PlayerSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 18 7 | productGUID: 52c59493aa296734c92ad6e3e8171e35 8 | AndroidProfiler: 0 9 | AndroidFilterTouchesWhenObscured: 0 10 | AndroidEnableSustainedPerformanceMode: 0 11 | defaultScreenOrientation: 4 12 | targetDevice: 2 13 | useOnDemandResources: 0 14 | accelerometerFrequency: 60 15 | companyName: DefaultCompany 16 | productName: VisualisingUnityCallChains 17 | defaultCursor: {fileID: 0} 18 | cursorHotspot: {x: 0, y: 0} 19 | m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} 20 | m_ShowUnitySplashScreen: 1 21 | m_ShowUnitySplashLogo: 1 22 | m_SplashScreenOverlayOpacity: 1 23 | m_SplashScreenAnimation: 1 24 | m_SplashScreenLogoStyle: 1 25 | m_SplashScreenDrawMode: 0 26 | m_SplashScreenBackgroundAnimationZoom: 1 27 | m_SplashScreenLogoAnimationZoom: 1 28 | m_SplashScreenBackgroundLandscapeAspect: 1 29 | m_SplashScreenBackgroundPortraitAspect: 1 30 | m_SplashScreenBackgroundLandscapeUvs: 31 | serializedVersion: 2 32 | x: 0 33 | y: 0 34 | width: 1 35 | height: 1 36 | m_SplashScreenBackgroundPortraitUvs: 37 | serializedVersion: 2 38 | x: 0 39 | y: 0 40 | width: 1 41 | height: 1 42 | m_SplashScreenLogos: [] 43 | m_VirtualRealitySplashScreen: {fileID: 0} 44 | m_HolographicTrackingLossScreen: {fileID: 0} 45 | defaultScreenWidth: 1024 46 | defaultScreenHeight: 768 47 | defaultScreenWidthWeb: 960 48 | defaultScreenHeightWeb: 600 49 | m_StereoRenderingPath: 0 50 | m_ActiveColorSpace: 0 51 | m_MTRendering: 1 52 | m_StackTraceTypes: 010000000100000001000000010000000100000001000000 53 | iosShowActivityIndicatorOnLoading: -1 54 | androidShowActivityIndicatorOnLoading: -1 55 | displayResolutionDialog: 0 56 | iosUseCustomAppBackgroundBehavior: 0 57 | iosAllowHTTPDownload: 1 58 | allowedAutorotateToPortrait: 1 59 | allowedAutorotateToPortraitUpsideDown: 1 60 | allowedAutorotateToLandscapeRight: 1 61 | allowedAutorotateToLandscapeLeft: 1 62 | useOSAutorotation: 1 63 | use32BitDisplayBuffer: 1 64 | preserveFramebufferAlpha: 0 65 | disableDepthAndStencilBuffers: 0 66 | androidStartInFullscreen: 1 67 | androidRenderOutsideSafeArea: 1 68 | androidUseSwappy: 0 69 | androidBlitType: 0 70 | defaultIsNativeResolution: 1 71 | macRetinaSupport: 1 72 | runInBackground: 1 73 | captureSingleScreen: 0 74 | muteOtherAudioSources: 0 75 | Prepare IOS For Recording: 0 76 | Force IOS Speakers When Recording: 0 77 | deferSystemGesturesMode: 0 78 | hideHomeButton: 0 79 | submitAnalytics: 1 80 | usePlayerLog: 1 81 | bakeCollisionMeshes: 0 82 | forceSingleInstance: 0 83 | useFlipModelSwapchain: 1 84 | resizableWindow: 0 85 | useMacAppStoreValidation: 0 86 | macAppStoreCategory: public.app-category.games 87 | gpuSkinning: 1 88 | graphicsJobs: 0 89 | xboxPIXTextureCapture: 0 90 | xboxEnableAvatar: 0 91 | xboxEnableKinect: 0 92 | xboxEnableKinectAutoTracking: 0 93 | xboxEnableFitness: 0 94 | visibleInBackground: 1 95 | allowFullscreenSwitch: 1 96 | graphicsJobMode: 0 97 | fullscreenMode: 1 98 | xboxSpeechDB: 0 99 | xboxEnableHeadOrientation: 0 100 | xboxEnableGuest: 0 101 | xboxEnablePIXSampling: 0 102 | metalFramebufferOnly: 0 103 | xboxOneResolution: 0 104 | xboxOneSResolution: 0 105 | xboxOneXResolution: 3 106 | xboxOneMonoLoggingLevel: 0 107 | xboxOneLoggingLevel: 1 108 | xboxOneDisableEsram: 0 109 | xboxOnePresentImmediateThreshold: 0 110 | switchQueueCommandMemory: 0 111 | switchQueueControlMemory: 16384 112 | switchQueueComputeMemory: 262144 113 | switchNVNShaderPoolsGranularity: 33554432 114 | switchNVNDefaultPoolsGranularity: 16777216 115 | switchNVNOtherPoolsGranularity: 16777216 116 | vulkanEnableSetSRGBWrite: 0 117 | m_SupportedAspectRatios: 118 | 4:3: 1 119 | 5:4: 1 120 | 16:10: 1 121 | 16:9: 1 122 | Others: 1 123 | bundleVersion: 0.1 124 | preloadedAssets: [] 125 | metroInputSource: 0 126 | wsaTransparentSwapchain: 0 127 | m_HolographicPauseOnTrackingLoss: 1 128 | xboxOneDisableKinectGpuReservation: 1 129 | xboxOneEnable7thCore: 1 130 | vrSettings: 131 | cardboard: 132 | depthFormat: 0 133 | enableTransitionView: 0 134 | daydream: 135 | depthFormat: 0 136 | useSustainedPerformanceMode: 0 137 | enableVideoLayer: 0 138 | useProtectedVideoMemory: 0 139 | minimumSupportedHeadTracking: 0 140 | maximumSupportedHeadTracking: 1 141 | hololens: 142 | depthFormat: 1 143 | depthBufferSharingEnabled: 1 144 | lumin: 145 | depthFormat: 0 146 | frameTiming: 2 147 | enableGLCache: 0 148 | glCacheMaxBlobSize: 524288 149 | glCacheMaxFileSize: 8388608 150 | oculus: 151 | sharedDepthBuffer: 1 152 | dashSupport: 1 153 | lowOverheadMode: 0 154 | protectedContext: 0 155 | v2Signing: 0 156 | enable360StereoCapture: 0 157 | isWsaHolographicRemotingEnabled: 0 158 | protectGraphicsMemory: 0 159 | enableFrameTimingStats: 0 160 | useHDRDisplay: 0 161 | m_ColorGamuts: 00000000 162 | targetPixelDensity: 30 163 | resolutionScalingMode: 0 164 | androidSupportedAspectRatio: 1 165 | androidMaxAspectRatio: 2.1 166 | applicationIdentifier: {} 167 | buildNumber: {} 168 | AndroidBundleVersionCode: 1 169 | AndroidMinSdkVersion: 16 170 | AndroidTargetSdkVersion: 0 171 | AndroidPreferredInstallLocation: 1 172 | aotOptions: 173 | stripEngineCode: 1 174 | iPhoneStrippingLevel: 0 175 | iPhoneScriptCallOptimization: 0 176 | ForceInternetPermission: 0 177 | ForceSDCardPermission: 0 178 | CreateWallpaper: 0 179 | APKExpansionFiles: 0 180 | keepLoadedShadersAlive: 0 181 | StripUnusedMeshComponents: 1 182 | VertexChannelCompressionMask: 4054 183 | iPhoneSdkVersion: 988 184 | iOSTargetOSVersionString: 9.0 185 | tvOSSdkVersion: 0 186 | tvOSRequireExtendedGameController: 0 187 | tvOSTargetOSVersionString: 9.0 188 | uIPrerenderedIcon: 0 189 | uIRequiresPersistentWiFi: 0 190 | uIRequiresFullScreen: 1 191 | uIStatusBarHidden: 1 192 | uIExitOnSuspend: 0 193 | uIStatusBarStyle: 0 194 | iPhoneSplashScreen: {fileID: 0} 195 | iPhoneHighResSplashScreen: {fileID: 0} 196 | iPhoneTallHighResSplashScreen: {fileID: 0} 197 | iPhone47inSplashScreen: {fileID: 0} 198 | iPhone55inPortraitSplashScreen: {fileID: 0} 199 | iPhone55inLandscapeSplashScreen: {fileID: 0} 200 | iPhone58inPortraitSplashScreen: {fileID: 0} 201 | iPhone58inLandscapeSplashScreen: {fileID: 0} 202 | iPadPortraitSplashScreen: {fileID: 0} 203 | iPadHighResPortraitSplashScreen: {fileID: 0} 204 | iPadLandscapeSplashScreen: {fileID: 0} 205 | iPadHighResLandscapeSplashScreen: {fileID: 0} 206 | iPhone65inPortraitSplashScreen: {fileID: 0} 207 | iPhone65inLandscapeSplashScreen: {fileID: 0} 208 | iPhone61inPortraitSplashScreen: {fileID: 0} 209 | iPhone61inLandscapeSplashScreen: {fileID: 0} 210 | appleTVSplashScreen: {fileID: 0} 211 | appleTVSplashScreen2x: {fileID: 0} 212 | tvOSSmallIconLayers: [] 213 | tvOSSmallIconLayers2x: [] 214 | tvOSLargeIconLayers: [] 215 | tvOSLargeIconLayers2x: [] 216 | tvOSTopShelfImageLayers: [] 217 | tvOSTopShelfImageLayers2x: [] 218 | tvOSTopShelfImageWideLayers: [] 219 | tvOSTopShelfImageWideLayers2x: [] 220 | iOSLaunchScreenType: 0 221 | iOSLaunchScreenPortrait: {fileID: 0} 222 | iOSLaunchScreenLandscape: {fileID: 0} 223 | iOSLaunchScreenBackgroundColor: 224 | serializedVersion: 2 225 | rgba: 0 226 | iOSLaunchScreenFillPct: 100 227 | iOSLaunchScreenSize: 100 228 | iOSLaunchScreenCustomXibPath: 229 | iOSLaunchScreeniPadType: 0 230 | iOSLaunchScreeniPadImage: {fileID: 0} 231 | iOSLaunchScreeniPadBackgroundColor: 232 | serializedVersion: 2 233 | rgba: 0 234 | iOSLaunchScreeniPadFillPct: 100 235 | iOSLaunchScreeniPadSize: 100 236 | iOSLaunchScreeniPadCustomXibPath: 237 | iOSUseLaunchScreenStoryboard: 0 238 | iOSLaunchScreenCustomStoryboardPath: 239 | iOSDeviceRequirements: [] 240 | iOSURLSchemes: [] 241 | iOSBackgroundModes: 0 242 | iOSMetalForceHardShadows: 0 243 | metalEditorSupport: 1 244 | metalAPIValidation: 1 245 | iOSRenderExtraFrameOnPause: 0 246 | appleDeveloperTeamID: 247 | iOSManualSigningProvisioningProfileID: 248 | tvOSManualSigningProvisioningProfileID: 249 | iOSManualSigningProvisioningProfileType: 0 250 | tvOSManualSigningProvisioningProfileType: 0 251 | appleEnableAutomaticSigning: 0 252 | iOSRequireARKit: 0 253 | iOSAutomaticallyDetectAndAddCapabilities: 1 254 | appleEnableProMotion: 0 255 | clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea 256 | templatePackageId: com.unity.template.3d@3.1.4 257 | templateDefaultScene: Assets/Scenes/SampleScene.unity 258 | AndroidTargetArchitectures: 1 259 | AndroidSplashScreenScale: 0 260 | androidSplashScreen: {fileID: 0} 261 | AndroidKeystoreName: '{inproject}: ' 262 | AndroidKeyaliasName: 263 | AndroidBuildApkPerCpuArchitecture: 0 264 | AndroidTVCompatibility: 0 265 | AndroidIsGame: 1 266 | AndroidEnableTango: 0 267 | androidEnableBanner: 1 268 | androidUseLowAccuracyLocation: 0 269 | androidUseCustomKeystore: 0 270 | m_AndroidBanners: 271 | - width: 320 272 | height: 180 273 | banner: {fileID: 0} 274 | androidGamepadSupportLevel: 0 275 | AndroidValidateAppBundleSize: 1 276 | AndroidAppBundleSizeToValidate: 150 277 | resolutionDialogBanner: {fileID: 0} 278 | m_BuildTargetIcons: [] 279 | m_BuildTargetPlatformIcons: [] 280 | m_BuildTargetBatching: 281 | - m_BuildTarget: Standalone 282 | m_StaticBatching: 1 283 | m_DynamicBatching: 0 284 | - m_BuildTarget: tvOS 285 | m_StaticBatching: 1 286 | m_DynamicBatching: 0 287 | - m_BuildTarget: Android 288 | m_StaticBatching: 1 289 | m_DynamicBatching: 0 290 | - m_BuildTarget: iPhone 291 | m_StaticBatching: 1 292 | m_DynamicBatching: 0 293 | - m_BuildTarget: WebGL 294 | m_StaticBatching: 0 295 | m_DynamicBatching: 0 296 | m_BuildTargetGraphicsAPIs: 297 | - m_BuildTarget: AndroidPlayer 298 | m_APIs: 150000000b000000 299 | m_Automatic: 0 300 | - m_BuildTarget: iOSSupport 301 | m_APIs: 10000000 302 | m_Automatic: 1 303 | - m_BuildTarget: AppleTVSupport 304 | m_APIs: 10000000 305 | m_Automatic: 0 306 | - m_BuildTarget: WebGLSupport 307 | m_APIs: 0b000000 308 | m_Automatic: 1 309 | m_BuildTargetVRSettings: 310 | - m_BuildTarget: Standalone 311 | m_Enabled: 0 312 | m_Devices: 313 | - Oculus 314 | - OpenVR 315 | openGLRequireES31: 0 316 | openGLRequireES31AEP: 0 317 | openGLRequireES32: 0 318 | vuforiaEnabled: 0 319 | m_TemplateCustomTags: {} 320 | mobileMTRendering: 321 | Android: 1 322 | iPhone: 1 323 | tvOS: 1 324 | m_BuildTargetGroupLightmapEncodingQuality: [] 325 | m_BuildTargetGroupLightmapSettings: [] 326 | playModeTestRunnerEnabled: 0 327 | runPlayModeTestAsEditModeTest: 0 328 | actionOnDotNetUnhandledException: 1 329 | enableInternalProfiler: 0 330 | logObjCUncaughtExceptions: 1 331 | enableCrashReportAPI: 0 332 | cameraUsageDescription: 333 | locationUsageDescription: 334 | microphoneUsageDescription: 335 | switchNetLibKey: 336 | switchSocketMemoryPoolSize: 6144 337 | switchSocketAllocatorPoolSize: 128 338 | switchSocketConcurrencyLimit: 14 339 | switchScreenResolutionBehavior: 2 340 | switchUseCPUProfiler: 0 341 | switchApplicationID: 0x01004b9000490000 342 | switchNSODependencies: 343 | switchTitleNames_0: 344 | switchTitleNames_1: 345 | switchTitleNames_2: 346 | switchTitleNames_3: 347 | switchTitleNames_4: 348 | switchTitleNames_5: 349 | switchTitleNames_6: 350 | switchTitleNames_7: 351 | switchTitleNames_8: 352 | switchTitleNames_9: 353 | switchTitleNames_10: 354 | switchTitleNames_11: 355 | switchTitleNames_12: 356 | switchTitleNames_13: 357 | switchTitleNames_14: 358 | switchPublisherNames_0: 359 | switchPublisherNames_1: 360 | switchPublisherNames_2: 361 | switchPublisherNames_3: 362 | switchPublisherNames_4: 363 | switchPublisherNames_5: 364 | switchPublisherNames_6: 365 | switchPublisherNames_7: 366 | switchPublisherNames_8: 367 | switchPublisherNames_9: 368 | switchPublisherNames_10: 369 | switchPublisherNames_11: 370 | switchPublisherNames_12: 371 | switchPublisherNames_13: 372 | switchPublisherNames_14: 373 | switchIcons_0: {fileID: 0} 374 | switchIcons_1: {fileID: 0} 375 | switchIcons_2: {fileID: 0} 376 | switchIcons_3: {fileID: 0} 377 | switchIcons_4: {fileID: 0} 378 | switchIcons_5: {fileID: 0} 379 | switchIcons_6: {fileID: 0} 380 | switchIcons_7: {fileID: 0} 381 | switchIcons_8: {fileID: 0} 382 | switchIcons_9: {fileID: 0} 383 | switchIcons_10: {fileID: 0} 384 | switchIcons_11: {fileID: 0} 385 | switchIcons_12: {fileID: 0} 386 | switchIcons_13: {fileID: 0} 387 | switchIcons_14: {fileID: 0} 388 | switchSmallIcons_0: {fileID: 0} 389 | switchSmallIcons_1: {fileID: 0} 390 | switchSmallIcons_2: {fileID: 0} 391 | switchSmallIcons_3: {fileID: 0} 392 | switchSmallIcons_4: {fileID: 0} 393 | switchSmallIcons_5: {fileID: 0} 394 | switchSmallIcons_6: {fileID: 0} 395 | switchSmallIcons_7: {fileID: 0} 396 | switchSmallIcons_8: {fileID: 0} 397 | switchSmallIcons_9: {fileID: 0} 398 | switchSmallIcons_10: {fileID: 0} 399 | switchSmallIcons_11: {fileID: 0} 400 | switchSmallIcons_12: {fileID: 0} 401 | switchSmallIcons_13: {fileID: 0} 402 | switchSmallIcons_14: {fileID: 0} 403 | switchManualHTML: 404 | switchAccessibleURLs: 405 | switchLegalInformation: 406 | switchMainThreadStackSize: 1048576 407 | switchPresenceGroupId: 408 | switchLogoHandling: 0 409 | switchReleaseVersion: 0 410 | switchDisplayVersion: 1.0.0 411 | switchStartupUserAccount: 0 412 | switchTouchScreenUsage: 0 413 | switchSupportedLanguagesMask: 0 414 | switchLogoType: 0 415 | switchApplicationErrorCodeCategory: 416 | switchUserAccountSaveDataSize: 0 417 | switchUserAccountSaveDataJournalSize: 0 418 | switchApplicationAttribute: 0 419 | switchCardSpecSize: -1 420 | switchCardSpecClock: -1 421 | switchRatingsMask: 0 422 | switchRatingsInt_0: 0 423 | switchRatingsInt_1: 0 424 | switchRatingsInt_2: 0 425 | switchRatingsInt_3: 0 426 | switchRatingsInt_4: 0 427 | switchRatingsInt_5: 0 428 | switchRatingsInt_6: 0 429 | switchRatingsInt_7: 0 430 | switchRatingsInt_8: 0 431 | switchRatingsInt_9: 0 432 | switchRatingsInt_10: 0 433 | switchRatingsInt_11: 0 434 | switchLocalCommunicationIds_0: 435 | switchLocalCommunicationIds_1: 436 | switchLocalCommunicationIds_2: 437 | switchLocalCommunicationIds_3: 438 | switchLocalCommunicationIds_4: 439 | switchLocalCommunicationIds_5: 440 | switchLocalCommunicationIds_6: 441 | switchLocalCommunicationIds_7: 442 | switchParentalControl: 0 443 | switchAllowsScreenshot: 1 444 | switchAllowsVideoCapturing: 1 445 | switchAllowsRuntimeAddOnContentInstall: 0 446 | switchDataLossConfirmation: 0 447 | switchUserAccountLockEnabled: 0 448 | switchSystemResourceMemory: 16777216 449 | switchSupportedNpadStyles: 22 450 | switchNativeFsCacheSize: 32 451 | switchIsHoldTypeHorizontal: 0 452 | switchSupportedNpadCount: 8 453 | switchSocketConfigEnabled: 0 454 | switchTcpInitialSendBufferSize: 32 455 | switchTcpInitialReceiveBufferSize: 64 456 | switchTcpAutoSendBufferSizeMax: 256 457 | switchTcpAutoReceiveBufferSizeMax: 256 458 | switchUdpSendBufferSize: 9 459 | switchUdpReceiveBufferSize: 42 460 | switchSocketBufferEfficiency: 4 461 | switchSocketInitializeEnabled: 1 462 | switchNetworkInterfaceManagerInitializeEnabled: 1 463 | switchPlayerConnectionEnabled: 1 464 | ps4NPAgeRating: 12 465 | ps4NPTitleSecret: 466 | ps4NPTrophyPackPath: 467 | ps4ParentalLevel: 11 468 | ps4ContentID: ED1633-NPXX51362_00-0000000000000000 469 | ps4Category: 0 470 | ps4MasterVersion: 01.00 471 | ps4AppVersion: 01.00 472 | ps4AppType: 0 473 | ps4ParamSfxPath: 474 | ps4VideoOutPixelFormat: 0 475 | ps4VideoOutInitialWidth: 1920 476 | ps4VideoOutBaseModeInitialWidth: 1920 477 | ps4VideoOutReprojectionRate: 60 478 | ps4PronunciationXMLPath: 479 | ps4PronunciationSIGPath: 480 | ps4BackgroundImagePath: 481 | ps4StartupImagePath: 482 | ps4StartupImagesFolder: 483 | ps4IconImagesFolder: 484 | ps4SaveDataImagePath: 485 | ps4SdkOverride: 486 | ps4BGMPath: 487 | ps4ShareFilePath: 488 | ps4ShareOverlayImagePath: 489 | ps4PrivacyGuardImagePath: 490 | ps4NPtitleDatPath: 491 | ps4RemotePlayKeyAssignment: -1 492 | ps4RemotePlayKeyMappingDir: 493 | ps4PlayTogetherPlayerCount: 0 494 | ps4EnterButtonAssignment: 1 495 | ps4ApplicationParam1: 0 496 | ps4ApplicationParam2: 0 497 | ps4ApplicationParam3: 0 498 | ps4ApplicationParam4: 0 499 | ps4DownloadDataSize: 0 500 | ps4GarlicHeapSize: 2048 501 | ps4ProGarlicHeapSize: 2560 502 | playerPrefsMaxSize: 32768 503 | ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ 504 | ps4pnSessions: 1 505 | ps4pnPresence: 1 506 | ps4pnFriends: 1 507 | ps4pnGameCustomData: 1 508 | playerPrefsSupport: 0 509 | enableApplicationExit: 0 510 | resetTempFolder: 1 511 | restrictedAudioUsageRights: 0 512 | ps4UseResolutionFallback: 0 513 | ps4ReprojectionSupport: 0 514 | ps4UseAudio3dBackend: 0 515 | ps4SocialScreenEnabled: 0 516 | ps4ScriptOptimizationLevel: 0 517 | ps4Audio3dVirtualSpeakerCount: 14 518 | ps4attribCpuUsage: 0 519 | ps4PatchPkgPath: 520 | ps4PatchLatestPkgPath: 521 | ps4PatchChangeinfoPath: 522 | ps4PatchDayOne: 0 523 | ps4attribUserManagement: 0 524 | ps4attribMoveSupport: 0 525 | ps4attrib3DSupport: 0 526 | ps4attribShareSupport: 0 527 | ps4attribExclusiveVR: 0 528 | ps4disableAutoHideSplash: 0 529 | ps4videoRecordingFeaturesUsed: 0 530 | ps4contentSearchFeaturesUsed: 0 531 | ps4attribEyeToEyeDistanceSettingVR: 0 532 | ps4IncludedModules: [] 533 | monoEnv: 534 | splashScreenBackgroundSourceLandscape: {fileID: 0} 535 | splashScreenBackgroundSourcePortrait: {fileID: 0} 536 | blurSplashScreenBackground: 1 537 | spritePackerPolicy: 538 | webGLMemorySize: 16 539 | webGLExceptionSupport: 1 540 | webGLNameFilesAsHashes: 0 541 | webGLDataCaching: 1 542 | webGLDebugSymbols: 0 543 | webGLEmscriptenArgs: 544 | webGLModulesDirectory: 545 | webGLTemplate: APPLICATION:Default 546 | webGLAnalyzeBuildSize: 0 547 | webGLUseEmbeddedResources: 0 548 | webGLCompressionFormat: 1 549 | webGLLinkerTarget: 1 550 | webGLThreadsSupport: 0 551 | webGLWasmStreaming: 0 552 | scriptingDefineSymbols: {} 553 | platformArchitecture: {} 554 | scriptingBackend: {} 555 | il2cppCompilerConfiguration: {} 556 | managedStrippingLevel: {} 557 | incrementalIl2cppBuild: {} 558 | allowUnsafeCode: 0 559 | additionalIl2CppArgs: 560 | scriptingRuntimeVersion: 1 561 | gcIncremental: 0 562 | gcWBarrierValidation: 0 563 | apiCompatibilityLevelPerPlatform: {} 564 | m_RenderingPath: 1 565 | m_MobileRenderingPath: 1 566 | metroPackageName: Template_3D 567 | metroPackageVersion: 568 | metroCertificatePath: 569 | metroCertificatePassword: 570 | metroCertificateSubject: 571 | metroCertificateIssuer: 572 | metroCertificateNotAfter: 0000000000000000 573 | metroApplicationDescription: Template_3D 574 | wsaImages: {} 575 | metroTileShortName: 576 | metroTileShowName: 0 577 | metroMediumTileShowName: 0 578 | metroLargeTileShowName: 0 579 | metroWideTileShowName: 0 580 | metroSupportStreamingInstall: 0 581 | metroLastRequiredScene: 0 582 | metroDefaultTileSize: 1 583 | metroTileForegroundText: 2 584 | metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} 585 | metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, 586 | a: 1} 587 | metroSplashScreenUseBackgroundColor: 0 588 | platformCapabilities: {} 589 | metroTargetDeviceFamilies: {} 590 | metroFTAName: 591 | metroFTAFileTypes: [] 592 | metroProtocolName: 593 | XboxOneProductId: 594 | XboxOneUpdateKey: 595 | XboxOneSandboxId: 596 | XboxOneContentId: 597 | XboxOneTitleId: 598 | XboxOneSCId: 599 | XboxOneGameOsOverridePath: 600 | XboxOnePackagingOverridePath: 601 | XboxOneAppManifestOverridePath: 602 | XboxOneVersion: 1.0.0.0 603 | XboxOnePackageEncryption: 0 604 | XboxOnePackageUpdateGranularity: 2 605 | XboxOneDescription: 606 | XboxOneLanguage: 607 | - enus 608 | XboxOneCapability: [] 609 | XboxOneGameRating: {} 610 | XboxOneIsContentPackage: 0 611 | XboxOneEnableGPUVariability: 1 612 | XboxOneSockets: {} 613 | XboxOneSplashScreen: {fileID: 0} 614 | XboxOneAllowedProductIds: [] 615 | XboxOnePersistentLocalStorageSize: 0 616 | XboxOneXTitleMemory: 8 617 | xboxOneScriptCompiler: 1 618 | XboxOneOverrideIdentityName: 619 | vrEditorSettings: 620 | daydream: 621 | daydreamIconForeground: {fileID: 0} 622 | daydreamIconBackground: {fileID: 0} 623 | cloudServicesEnabled: 624 | UNet: 1 625 | luminIcon: 626 | m_Name: 627 | m_ModelFolderPath: 628 | m_PortalFolderPath: 629 | luminCert: 630 | m_CertPath: 631 | m_SignPackage: 1 632 | luminIsChannelApp: 0 633 | luminVersion: 634 | m_VersionCode: 1 635 | m_VersionName: 636 | facebookSdkVersion: 7.9.4 637 | facebookAppId: 638 | facebookCookies: 1 639 | facebookLogging: 1 640 | facebookStatus: 1 641 | facebookXfbml: 0 642 | facebookFrictionlessRequests: 1 643 | apiCompatibilityLevel: 6 644 | cloudProjectId: 645 | framebufferDepthMemorylessMode: 0 646 | projectName: 647 | organizationId: 648 | cloudEnabled: 0 649 | enableNativePlatformBackendsForNewInputSystem: 0 650 | disableOldInputManagerSupport: 0 651 | legacyClampBlendShapeWeights: 0 652 | -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2019.2.13f1 2 | m_EditorVersionWithRevision: 2019.2.13f1 (e20f6c7e5017) 3 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 5 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Very Low 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | shadowNearPlaneOffset: 3 18 | shadowCascade2Split: 0.33333334 19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 20 | shadowmaskMode: 0 21 | blendWeights: 1 22 | textureQuality: 1 23 | anisotropicTextures: 0 24 | antiAliasing: 0 25 | softParticles: 0 26 | softVegetation: 0 27 | realtimeReflectionProbes: 0 28 | billboardsFaceCameraPosition: 0 29 | vSyncCount: 0 30 | lodBias: 0.3 31 | maximumLODLevel: 0 32 | streamingMipmapsActive: 0 33 | streamingMipmapsAddAllCameras: 1 34 | streamingMipmapsMemoryBudget: 512 35 | streamingMipmapsRenderersPerFrame: 512 36 | streamingMipmapsMaxLevelReduction: 2 37 | streamingMipmapsMaxFileIORequests: 1024 38 | particleRaycastBudget: 4 39 | asyncUploadTimeSlice: 2 40 | asyncUploadBufferSize: 16 41 | asyncUploadPersistentBuffer: 1 42 | resolutionScalingFixedDPIFactor: 1 43 | excludedTargetPlatforms: [] 44 | - serializedVersion: 2 45 | name: Low 46 | pixelLightCount: 0 47 | shadows: 0 48 | shadowResolution: 0 49 | shadowProjection: 1 50 | shadowCascades: 1 51 | shadowDistance: 20 52 | shadowNearPlaneOffset: 3 53 | shadowCascade2Split: 0.33333334 54 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 55 | shadowmaskMode: 0 56 | blendWeights: 2 57 | textureQuality: 0 58 | anisotropicTextures: 0 59 | antiAliasing: 0 60 | softParticles: 0 61 | softVegetation: 0 62 | realtimeReflectionProbes: 0 63 | billboardsFaceCameraPosition: 0 64 | vSyncCount: 0 65 | lodBias: 0.4 66 | maximumLODLevel: 0 67 | streamingMipmapsActive: 0 68 | streamingMipmapsAddAllCameras: 1 69 | streamingMipmapsMemoryBudget: 512 70 | streamingMipmapsRenderersPerFrame: 512 71 | streamingMipmapsMaxLevelReduction: 2 72 | streamingMipmapsMaxFileIORequests: 1024 73 | particleRaycastBudget: 16 74 | asyncUploadTimeSlice: 2 75 | asyncUploadBufferSize: 16 76 | asyncUploadPersistentBuffer: 1 77 | resolutionScalingFixedDPIFactor: 1 78 | excludedTargetPlatforms: [] 79 | - serializedVersion: 2 80 | name: Medium 81 | pixelLightCount: 1 82 | shadows: 1 83 | shadowResolution: 0 84 | shadowProjection: 1 85 | shadowCascades: 1 86 | shadowDistance: 20 87 | shadowNearPlaneOffset: 3 88 | shadowCascade2Split: 0.33333334 89 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 90 | shadowmaskMode: 0 91 | blendWeights: 2 92 | textureQuality: 0 93 | anisotropicTextures: 1 94 | antiAliasing: 0 95 | softParticles: 0 96 | softVegetation: 0 97 | realtimeReflectionProbes: 0 98 | billboardsFaceCameraPosition: 0 99 | vSyncCount: 1 100 | lodBias: 0.7 101 | maximumLODLevel: 0 102 | streamingMipmapsActive: 0 103 | streamingMipmapsAddAllCameras: 1 104 | streamingMipmapsMemoryBudget: 512 105 | streamingMipmapsRenderersPerFrame: 512 106 | streamingMipmapsMaxLevelReduction: 2 107 | streamingMipmapsMaxFileIORequests: 1024 108 | particleRaycastBudget: 64 109 | asyncUploadTimeSlice: 2 110 | asyncUploadBufferSize: 16 111 | asyncUploadPersistentBuffer: 1 112 | resolutionScalingFixedDPIFactor: 1 113 | excludedTargetPlatforms: [] 114 | - serializedVersion: 2 115 | name: High 116 | pixelLightCount: 2 117 | shadows: 2 118 | shadowResolution: 1 119 | shadowProjection: 1 120 | shadowCascades: 2 121 | shadowDistance: 40 122 | shadowNearPlaneOffset: 3 123 | shadowCascade2Split: 0.33333334 124 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 125 | shadowmaskMode: 1 126 | blendWeights: 2 127 | textureQuality: 0 128 | anisotropicTextures: 1 129 | antiAliasing: 0 130 | softParticles: 0 131 | softVegetation: 1 132 | realtimeReflectionProbes: 1 133 | billboardsFaceCameraPosition: 1 134 | vSyncCount: 1 135 | lodBias: 1 136 | maximumLODLevel: 0 137 | streamingMipmapsActive: 0 138 | streamingMipmapsAddAllCameras: 1 139 | streamingMipmapsMemoryBudget: 512 140 | streamingMipmapsRenderersPerFrame: 512 141 | streamingMipmapsMaxLevelReduction: 2 142 | streamingMipmapsMaxFileIORequests: 1024 143 | particleRaycastBudget: 256 144 | asyncUploadTimeSlice: 2 145 | asyncUploadBufferSize: 16 146 | asyncUploadPersistentBuffer: 1 147 | resolutionScalingFixedDPIFactor: 1 148 | excludedTargetPlatforms: [] 149 | - serializedVersion: 2 150 | name: Very High 151 | pixelLightCount: 3 152 | shadows: 2 153 | shadowResolution: 2 154 | shadowProjection: 1 155 | shadowCascades: 2 156 | shadowDistance: 70 157 | shadowNearPlaneOffset: 3 158 | shadowCascade2Split: 0.33333334 159 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 160 | shadowmaskMode: 1 161 | blendWeights: 4 162 | textureQuality: 0 163 | anisotropicTextures: 2 164 | antiAliasing: 2 165 | softParticles: 1 166 | softVegetation: 1 167 | realtimeReflectionProbes: 1 168 | billboardsFaceCameraPosition: 1 169 | vSyncCount: 1 170 | lodBias: 1.5 171 | maximumLODLevel: 0 172 | streamingMipmapsActive: 0 173 | streamingMipmapsAddAllCameras: 1 174 | streamingMipmapsMemoryBudget: 512 175 | streamingMipmapsRenderersPerFrame: 512 176 | streamingMipmapsMaxLevelReduction: 2 177 | streamingMipmapsMaxFileIORequests: 1024 178 | particleRaycastBudget: 1024 179 | asyncUploadTimeSlice: 2 180 | asyncUploadBufferSize: 16 181 | asyncUploadPersistentBuffer: 1 182 | resolutionScalingFixedDPIFactor: 1 183 | excludedTargetPlatforms: [] 184 | - serializedVersion: 2 185 | name: Ultra 186 | pixelLightCount: 4 187 | shadows: 2 188 | shadowResolution: 2 189 | shadowProjection: 1 190 | shadowCascades: 4 191 | shadowDistance: 150 192 | shadowNearPlaneOffset: 3 193 | shadowCascade2Split: 0.33333334 194 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 195 | shadowmaskMode: 1 196 | blendWeights: 4 197 | textureQuality: 0 198 | anisotropicTextures: 2 199 | antiAliasing: 2 200 | softParticles: 1 201 | softVegetation: 1 202 | realtimeReflectionProbes: 1 203 | billboardsFaceCameraPosition: 1 204 | vSyncCount: 1 205 | lodBias: 2 206 | maximumLODLevel: 0 207 | streamingMipmapsActive: 0 208 | streamingMipmapsAddAllCameras: 1 209 | streamingMipmapsMemoryBudget: 512 210 | streamingMipmapsRenderersPerFrame: 512 211 | streamingMipmapsMaxLevelReduction: 2 212 | streamingMipmapsMaxFileIORequests: 1024 213 | particleRaycastBudget: 4096 214 | asyncUploadTimeSlice: 2 215 | asyncUploadBufferSize: 16 216 | asyncUploadPersistentBuffer: 1 217 | resolutionScalingFixedDPIFactor: 1 218 | excludedTargetPlatforms: [] 219 | m_PerPlatformDefaultQuality: 220 | Android: 2 221 | Lumin: 5 222 | Nintendo 3DS: 5 223 | Nintendo Switch: 5 224 | PS4: 5 225 | PSP2: 2 226 | Standalone: 5 227 | WebGL: 3 228 | Windows Store Apps: 5 229 | XboxOne: 5 230 | iPhone: 2 231 | tvOS: 2 232 | -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_TestInitMode: 0 13 | CrashReportingSettings: 14 | m_EventUrl: https://perf-events.cloud.unity3d.com 15 | m_Enabled: 0 16 | m_LogBufferSize: 10 17 | m_CaptureEditorExceptions: 1 18 | UnityPurchasingSettings: 19 | m_Enabled: 0 20 | m_TestMode: 0 21 | UnityAnalyticsSettings: 22 | m_Enabled: 0 23 | m_TestMode: 0 24 | m_InitializeOnStartup: 1 25 | UnityAdsSettings: 26 | m_Enabled: 0 27 | m_InitializeOnStartup: 1 28 | m_TestMode: 0 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | m_GameIds: {} 32 | m_GameId: 33 | PerformanceReportingSettings: 34 | m_Enabled: 0 35 | -------------------------------------------------------------------------------- /ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 0} 7 | m_CopyBufferShader: {fileID: 0} 8 | m_SortShader: {fileID: 0} 9 | m_RenderPipeSettingsPath: 10 | m_FixedTimeStep: 0.016666668 11 | m_MaxDeltaTime: 0.05 12 | -------------------------------------------------------------------------------- /ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /VisualisingUnityCallChains.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 16 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityEventCallRedirector.Fody", "UnityEventCallRedirector.Fody.csproj", "{25218352-A734-BF72-0720-8F0A406678B4}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp", "Assembly-CSharp.csproj", "{5CB39989-DCD5-F910-C615-481E6A8A0418}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityEventCallRedirector.Attribute", "UnityEventCallRedirector.Attribute.csproj", "{76B52E63-1A9A-F0C5-716E-C83B20793161}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp-Editor", "Assembly-CSharp-Editor.csproj", "{B8CF9103-12A8-555A-70B1-E47A80E4814E}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {25218352-A734-BF72-0720-8F0A406678B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {25218352-A734-BF72-0720-8F0A406678B4}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {25218352-A734-BF72-0720-8F0A406678B4}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {25218352-A734-BF72-0720-8F0A406678B4}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {5CB39989-DCD5-F910-C615-481E6A8A0418}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {5CB39989-DCD5-F910-C615-481E6A8A0418}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {5CB39989-DCD5-F910-C615-481E6A8A0418}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {5CB39989-DCD5-F910-C615-481E6A8A0418}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {76B52E63-1A9A-F0C5-716E-C83B20793161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {76B52E63-1A9A-F0C5-716E-C83B20793161}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {76B52E63-1A9A-F0C5-716E-C83B20793161}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {76B52E63-1A9A-F0C5-716E-C83B20793161}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {B8CF9103-12A8-555A-70B1-E47A80E4814E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {B8CF9103-12A8-555A-70B1-E47A80E4814E}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {B8CF9103-12A8-555A-70B1-E47A80E4814E}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {B8CF9103-12A8-555A-70B1-E47A80E4814E}.Release|Any CPU.Build.0 = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /_github/UnityEventCallRedirector.unitypackage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handzlikchris/Unity.VisualisingEventCallChains/680a827770ebe11d47505405e40bd2642a7d16bc/_github/UnityEventCallRedirector.unitypackage -------------------------------------------------------------------------------- /_github/ViewingUnityEventInvokeCallsInProfiler_VRTK.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handzlikchris/Unity.VisualisingEventCallChains/680a827770ebe11d47505405e40bd2642a7d16bc/_github/ViewingUnityEventInvokeCallsInProfiler_VRTK.gif -------------------------------------------------------------------------------- /_github/ViewingUnityEventInvokeCallsInProfiler_workflow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handzlikchris/Unity.VisualisingEventCallChains/680a827770ebe11d47505405e40bd2642a7d16bc/_github/ViewingUnityEventInvokeCallsInProfiler_workflow.gif -------------------------------------------------------------------------------- /_github/event-call-chain-profiler-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handzlikchris/Unity.VisualisingEventCallChains/680a827770ebe11d47505405e40bd2642a7d16bc/_github/event-call-chain-profiler-view.png -------------------------------------------------------------------------------- /_github/event-call-chain-profiler-view_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handzlikchris/Unity.VisualisingEventCallChains/680a827770ebe11d47505405e40bd2642a7d16bc/_github/event-call-chain-profiler-view_small.png -------------------------------------------------------------------------------- /_github/event-call-chain-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/handzlikchris/Unity.VisualisingEventCallChains/680a827770ebe11d47505405e40bd2642a7d16bc/_github/event-call-chain-setup.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | # Visualising Unity Event Call Chains 6 | 7 | If you worked with `UnityEvents` you know that it's quite good way to decouple component logic and use events to pass data. You probably also found that when those call-chains get deep it's quite difficult to understand what's happening from wider perspective. 8 | 9 | This tool will help you visualise that workflow using Unity profiler, instead of going through the chain from node to node you can see **big picture** with profiler window while still easily navigating between game object nodes 10 | ![Event Call Chain Profiler view](/_github/event-call-chain-profiler-view_small.png) 11 | 12 | 13 | That should allow you to have much better understanding of what's actually happening. 14 | ![Event Call Chain Visualisation Workflow](/_github/ViewingUnityEventInvokeCallsInProfiler_workflow.gif) 15 | 16 | Which helps a lot if you have a solution that already uses event call chains extensively 17 | ![Event Call Chain Visualisation Workflow](/_github/ViewingUnityEventInvokeCallsInProfiler_VRTK.gif) 18 | *from [VRTK Farm example](https://github.com/ExtendRealityLtd/VRTK) which uses call chains extensively* 19 | 20 | 21 | ## Approach 22 | The tool will use IL Weaving and will redirect all the calls to `UnityEvent` **(with one generic argument)**, eg `UnityEvent` or `UnityEvent` to `EventInterceptor` where you could add any actions needed. 23 | 24 | Method signature and default implementation: 25 | ``` 26 | public class EventInterceptor 27 | { 28 | public static void Intercept(UnityEvent originalEvent, TArg arg, object self, string callingMethodName) 29 | { 30 | Profiler.BeginSample($"____{((MonoBehaviour)self).name} ({self.GetType().Name}) <{callingMethodName}>____+", (MonoBehaviour)self); 31 | originalEvent.Invoke(arg); 32 | Profiler.EndSample(); 33 | } 34 | } 35 | ``` 36 | 37 | ## Setup 38 | You can clone this repository and run it in Unity as an example. 39 | 40 | To import into your project: 41 | 1) In Unity add a package dependency to [Malimbe]([https://github.com/ExtendRealityLtd/Malimbe](https://github.com/ExtendRealityLtd/Malimbe)) which will hook up to Unity build process so the weaver code can work on your assemblies after Unity is done compiling them. 42 | 43 | You can do that via `manifest.json` file located in `/Packages` folder. You'll have to add following entries (as per Malimbe page) 44 | ``` 45 | 46 | "scopedRegistries": [ 47 | { 48 | "name": "npmjs", 49 | "url": "https://registry.npmjs.org/", 50 | "scopes": [ 51 | "io.extendreality" 52 | ] 53 | } 54 | ], 55 | "dependencies": { 56 | "io.extendreality.malimbe": "9.6.5", 57 | ... 58 | } 59 | } 60 | ``` 61 | 62 | 2) Download and import [UnityEventCallRedirector.unitypackage](https://github.com/handzlikchris/Unity.VisualisingEventCallChains/raw/master/_github/UnityEventCallRedirector.unitypackage) 63 | 3) Recompile 64 | - If you see an error 65 | `'A configuration lists 'UnityEventCallRedirector' but the assembly file wasn't found in the search paths'` 66 | That means `UnityEventCallRedirector.Fody` is not compiled, you can go to `ModuleWeaver.cs` and make some non-relevant change (like adding a space) followed by saving to make sure DLL is actually compiled 67 | 4) Now changes to your scripts will trigger recompile which will in turn trigger IL Weaving to intercept your calls 68 | 69 | ### Finding Interesting Frames 70 | You can use `FrameFinder` script located in `UnityEventCallRedirector/ProfilerUtilities` to find your custom markers. 71 | - drop the script onto a game object 72 | - change `FrameContains` to marker that you're after, for example, if you're looking for calls made from script `TestCallChain` by `Child-1-2-1` object you can put `Child-1-2-1 (TestCallChain)`. 73 | - hit `ShowInProfiler` 74 | - optionally you can navigate further with `FindNext` 75 | 76 | ### Configuring Interception 77 | In the package, you'll find `EventInterceptor.cs` with `Intercept` method. You can adjust that as needed. There's also an assembly attribute specified `UnityEventCallRedirector` where you can configure some more options. 78 | 79 | - `eventInterceptorTypeName` - if different than `EventInterceptor` 80 | - `replaceCallsFromNamespacesRegex` - it'll narrow down types to be looked at when searching for `UnityEvent``1.Invoke` calls 81 | - `ExcludeFullMethodNameRegex` - full method name (including) type regex to be excluded. eg. `ObservableList.+::Start` 82 | 83 | ### Using asmdef / Fallback Interception 84 | Separate assemblies will not have access to that `EventInterceptor` when that happens interception will still be performed but using IL as defined in `ModuleWeaver` - it'll simply add `BeginSample` and `EndSample` around event call (and build proper string). 85 | 86 | This is helpful if you like to weave external packages that you don't control (and don't wish to embed) - if you have control over assembly you can copy `EventInterceptor.cs` class with assembly attribute there. 87 | 88 | ### Configuring fallback interception 89 | You can control few parameters of fallback IL weaving, it's done via XML attributes in `FodyWeavers.xml` 90 | - `FallbackSampleNameFormat` - will control how you see entries in `Profiler Window`, there are 3 tokens that can be used and **refer to object that invokes the event**: 91 | - `{0}` - unity object name 92 | - `{1}` - unity object type name 93 | - `{2}` - unity object method name where event is being called from 94 | - `FallbackReplaceCallsFromNamespacesRegex` - it'll narrow down types to be looked at when searching for `UnityEvent``1.Invoke` calls 95 | - `FallbackExcludeFullMethodNameRegex` - full method name (including) type regex to be excluded. eg. `ObservableList.+::Start` 96 | 97 | 98 | ### Configuring Malimbe 99 | You can further configure Malimbe via `FodyWeavers.xml` file, you'll find the details in their repository. 100 | 101 | 102 | ## Known issues 103 | - Right now tool works just for `UnityEvent` - it doesn't work with no argument one or with more than 1 argument 104 | - You may see some errors that weaving assembly is not available when starting Unity, this is to do with compilation order and should not cause you issues, it'll be gone on next compilation. I've included weaver as source code with asmdef so it's easier to modify weaver. Ideally compiled DLL should just be included 105 | - There are some DLLs included with the package and also included in Malimbe package, it's not easy to get them referenced without embedding Malimbe package. It shouldn't give you troubles but if something funny happens it'd be worth to look if that's not the cause. --------------------------------------------------------------------------------