mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
profiling nh (#1030)
semi-automated profile marker generation. disable-able with a project-wide compiler flag
This commit is contained in:
commit
7697e5bb49
@ -56,6 +56,7 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
private static void SceneManager_sceneUnloaded(Scene scene)
|
||||
{
|
||||
// would be nice to only clear when system changes, but fixed prefabs rely on stuff in the scene
|
||||
foreach (var prefab in _fixedPrefabCache.Values)
|
||||
{
|
||||
UnityEngine.Object.Destroy(prefab.prefab);
|
||||
@ -230,15 +231,10 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
if (detail.removeChildren != null)
|
||||
{
|
||||
var detailPath = prop.transform.GetPath();
|
||||
var transforms = prop.GetComponentsInChildren<Transform>(true);
|
||||
foreach (var childPath in detail.removeChildren)
|
||||
{
|
||||
// Multiple children can have the same path so we delete all that match
|
||||
var path = $"{detailPath}/{childPath}";
|
||||
|
||||
var flag = true;
|
||||
foreach (var childObj in transforms.Where(x => x.GetPath() == path))
|
||||
foreach (var childObj in prop.transform.FindAll(childPath))
|
||||
{
|
||||
flag = false;
|
||||
childObj.gameObject.SetActive(false);
|
||||
|
||||
@ -147,7 +147,7 @@ namespace NewHorizons.Builder.ShipLog
|
||||
|
||||
Rect rect = new Rect(0, 0, texture.width, texture.height);
|
||||
Vector2 pivot = new Vector2(texture.width / 2, texture.height / 2);
|
||||
newImage.sprite = Sprite.Create(texture, rect, pivot);
|
||||
newImage.sprite = Sprite.Create(texture, rect, pivot, 100, 0, SpriteMeshType.FullRect, Vector4.zero, false);
|
||||
|
||||
return newImageGO;
|
||||
}
|
||||
|
||||
@ -246,7 +246,7 @@ namespace NewHorizons.Builder.ShipLog
|
||||
Texture2D newTexture = ImageUtilities.GetTexture(body.Mod, relativePath);
|
||||
Rect rect = new Rect(0, 0, newTexture.width, newTexture.height);
|
||||
Vector2 pivot = new Vector2(newTexture.width / 2, newTexture.height / 2);
|
||||
return Sprite.Create(newTexture, rect, pivot);
|
||||
return Sprite.Create(newTexture, rect, pivot, 100, 0, SpriteMeshType.FullRect, Vector4.zero, false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
@ -13,7 +13,7 @@ namespace NewHorizons.Components.Props
|
||||
public bool CloseEyes;
|
||||
public bool SetActiveWithCondition;
|
||||
|
||||
private PlayerCameraEffectController _playerCameraEffectController;
|
||||
private static PlayerCameraEffectController _playerCameraEffectController;
|
||||
private bool _changeConditionOnExitConversation;
|
||||
private bool _inConversation;
|
||||
|
||||
@ -45,7 +45,7 @@ namespace NewHorizons.Components.Props
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
_playerCameraEffectController = GameObject.FindObjectOfType<PlayerCameraEffectController>();
|
||||
if (_playerCameraEffectController == null) _playerCameraEffectController = GameObject.FindObjectOfType<PlayerCameraEffectController>();
|
||||
GlobalMessenger<string, bool>.AddListener("DialogueConditionChanged", OnDialogueConditionChanged);
|
||||
GlobalMessenger.AddListener("ExitConversation", OnExitConversation);
|
||||
GlobalMessenger.AddListener("EnterConversation", OnEnterConversation);
|
||||
|
||||
@ -279,7 +279,7 @@ namespace NewHorizons.Components.ShipLog
|
||||
{
|
||||
var rect = new Rect(0, 0, texture.width, texture.height);
|
||||
var pivot = new Vector2(texture.width / 2, texture.height / 2);
|
||||
return Sprite.Create(texture, rect, pivot);
|
||||
return Sprite.Create(texture, rect, pivot, 100, 0, SpriteMeshType.FullRect, Vector4.zero, false);
|
||||
}
|
||||
|
||||
private void OnTargetReferenceFrame(ReferenceFrame referenceFrame)
|
||||
|
||||
5
NewHorizons/External/Configs/PlanetConfig.cs
vendored
5
NewHorizons/External/Configs/PlanetConfig.cs
vendored
@ -64,6 +64,11 @@ namespace NewHorizons.External.Configs
|
||||
/// </summary>
|
||||
public string[] removeChildren;
|
||||
|
||||
/// <summary>
|
||||
/// optimization. turn this off if you know you're generating a new body and aren't worried about other addons editing it.
|
||||
/// </summary>
|
||||
[DefaultValue(true)] public bool checkForExisting = true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Modules
|
||||
|
||||
@ -172,6 +172,8 @@ namespace NewHorizons.Handlers
|
||||
|
||||
// I don't remember doing this why is it exceptions what am I doing
|
||||
GameObject existingPlanet = null;
|
||||
if (body.Config.checkForExisting) // TODO: remove this when we cache name->fullpath in Find
|
||||
{
|
||||
try
|
||||
{
|
||||
existingPlanet = AstroObjectLocator.GetAstroObject(body.Config.name).gameObject;
|
||||
@ -193,6 +195,7 @@ namespace NewHorizons.Handlers
|
||||
NHLogger.LogError($"{body.Config.name} was meant to be destroyed, but was not found");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (existingPlanet != null)
|
||||
{
|
||||
@ -1003,15 +1006,10 @@ namespace NewHorizons.Handlers
|
||||
|
||||
private static void RemoveChildren(GameObject go, NewHorizonsBody body)
|
||||
{
|
||||
var goPath = go.transform.GetPath();
|
||||
var transforms = go.GetComponentsInChildren<Transform>(true);
|
||||
foreach (var childPath in body.Config.removeChildren)
|
||||
{
|
||||
// Multiple children can have the same path so we delete all that match
|
||||
var path = $"{goPath}/{childPath}";
|
||||
|
||||
var flag = true;
|
||||
foreach (var childObj in transforms.Where(x => x.GetPath() == path))
|
||||
foreach (var childObj in go.transform.FindAll(childPath))
|
||||
{
|
||||
flag = false;
|
||||
// idk why we wait here but we do
|
||||
|
||||
@ -2,6 +2,7 @@ using NewHorizons.Utility;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace NewHorizons.Handlers
|
||||
{
|
||||
@ -51,6 +52,9 @@ namespace NewHorizons.Handlers
|
||||
/// </summary>
|
||||
public static void SetUpStreaming(GameObject obj, Sector sector)
|
||||
{
|
||||
// TODO: used OFTEN by detail builder. 20-40ms adds up to seconds. speed up!
|
||||
|
||||
Profiler.BeginSample("get bundles");
|
||||
// find the asset bundles to load
|
||||
// tries the cache first, then builds
|
||||
if (!_objectCache.TryGetValue(obj, out var assetBundles))
|
||||
@ -94,7 +98,9 @@ namespace NewHorizons.Handlers
|
||||
assetBundles = assetBundlesList.ToArray();
|
||||
_objectCache[obj] = assetBundles;
|
||||
}
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("get sectors");
|
||||
foreach (var assetBundle in assetBundles)
|
||||
{
|
||||
// Track the sector even if its null. null means stay loaded forever
|
||||
@ -105,7 +111,9 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
sectors.SafeAdd(sector);
|
||||
}
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("load assets");
|
||||
if (sector)
|
||||
{
|
||||
sector.OnOccupantEnterSector += _ =>
|
||||
@ -128,6 +136,7 @@ namespace NewHorizons.Handlers
|
||||
foreach (var assetBundle in assetBundles)
|
||||
StreamingManager.LoadStreamingAssets(assetBundle);
|
||||
}
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
public static bool IsBundleInUse(string assetBundle)
|
||||
|
||||
@ -109,7 +109,7 @@ namespace NewHorizons.Handlers
|
||||
var tex = ImageUtilities.GetTexture(mod, filepath, false);
|
||||
if (tex == null) return;
|
||||
|
||||
var sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100.0f);
|
||||
var sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100, 0, SpriteMeshType.FullRect, Vector4.zero, false);
|
||||
AddSubtitle(sprite);
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using static NewHorizons.External.Configs.StarSystemConfig;
|
||||
|
||||
namespace NewHorizons.Handlers
|
||||
@ -47,7 +48,7 @@ namespace NewHorizons.Handlers
|
||||
if (_textureCache == null) _textureCache = new List<Texture2D>();
|
||||
_textureCache.Add(texture);
|
||||
|
||||
var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(texture.width / 2f, texture.height / 2f));
|
||||
var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(texture.width / 2f, texture.height / 2f), 100, 0, SpriteMeshType.FullRect, Vector4.zero, false);
|
||||
|
||||
var name = ShipLogStarChartMode.UniqueIDToName(systemID);
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
|
||||
<NoWarn>1701;1702;1591</NoWarn>
|
||||
|
||||
<!-- <DefineConstants>ENABLE_PROFILER</DefineConstants>-->
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugType>none</DebugType>
|
||||
|
||||
73
NewHorizons/Patches/ProfilerPatch.cs
Normal file
73
NewHorizons/Patches/ProfilerPatch.cs
Normal file
@ -0,0 +1,73 @@
|
||||
#if ENABLE_PROFILER
|
||||
|
||||
using HarmonyLib;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace NewHorizons.Patches;
|
||||
|
||||
/// <summary>
|
||||
/// attach profiler markers to important methods
|
||||
/// </summary>
|
||||
[HarmonyPatch]
|
||||
public static class ProfilerPatch
|
||||
{
|
||||
private static string FriendlyName(this MethodBase @this) => $"{@this.DeclaringType.Name}.{@this.Name}";
|
||||
|
||||
[HarmonyTargetMethods]
|
||||
public static IEnumerable<MethodBase> TargetMethods()
|
||||
{
|
||||
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
|
||||
{
|
||||
if (!(
|
||||
type.Name == "Main" ||
|
||||
type.Name.EndsWith("Builder") ||
|
||||
type.Name.EndsWith("Handler") ||
|
||||
type.Name.EndsWith("Utilities")
|
||||
)) continue;
|
||||
|
||||
foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
|
||||
{
|
||||
if (method.ContainsGenericParameters) continue;
|
||||
|
||||
// Main.Instance.ModHelper.Console.WriteLine($"[profiler] profiling {method.FriendlyName()}");
|
||||
yield return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix(MethodBase __originalMethod /*, out Stopwatch __state*/)
|
||||
{
|
||||
Profiler.BeginSample(__originalMethod.FriendlyName());
|
||||
|
||||
// __state = new Stopwatch();
|
||||
// __state.Start();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
public static void Postfix( /*MethodBase __originalMethod, Stopwatch __state*/)
|
||||
{
|
||||
Profiler.EndSample();
|
||||
|
||||
// __state.Stop();
|
||||
// Main.Instance.ModHelper.Console.WriteLine($"[profiler] {__originalMethod.MethodName()} took {__state.Elapsed.TotalMilliseconds:f1} ms");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// bundle loading causes log spam that slows loading, but only in unity dev profiler mode.
|
||||
/// patch it out so it doesnt do false-positive slowness.
|
||||
/// </summary>
|
||||
[HarmonyPatch]
|
||||
public static class DisableShaderLogSpamPatch
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(StackTraceUtility), "ExtractStackTrace")]
|
||||
[HarmonyPatch(typeof(Application), "CallLogCallback")]
|
||||
private static bool DisableShaderLogSpam() => false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -43,6 +43,11 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"checkForExisting": {
|
||||
"type": "boolean",
|
||||
"description": "optimization. turn this off if you know you're generating a new body and aren't worried about other addons editing it.",
|
||||
"default": true
|
||||
},
|
||||
"AmbientLights": {
|
||||
"type": "array",
|
||||
"description": "Add ambient lights to this body",
|
||||
|
||||
@ -12,6 +12,7 @@ namespace NewHorizons.Utility.Files
|
||||
public static class AssetBundleUtilities
|
||||
{
|
||||
public static Dictionary<string, (AssetBundle bundle, bool keepLoaded)> AssetBundles = new();
|
||||
private static Dictionary<string, GameObject> _prefabCache = new();
|
||||
|
||||
private static readonly List<AssetBundleCreateRequest> _loadingBundles = new();
|
||||
|
||||
@ -52,6 +53,7 @@ namespace NewHorizons.Utility.Files
|
||||
|
||||
}
|
||||
AssetBundles = AssetBundles.Where(x => x.Value.keepLoaded).ToDictionary(x => x.Key, x => x.Value);
|
||||
_prefabCache.Clear();
|
||||
}
|
||||
|
||||
public static void PreloadBundle(string assetBundleRelativeDir, IModBehaviour mod)
|
||||
@ -113,12 +115,18 @@ namespace NewHorizons.Utility.Files
|
||||
|
||||
public static GameObject LoadPrefab(string assetBundleRelativeDir, string pathInBundle, IModBehaviour mod)
|
||||
{
|
||||
var prefab = Load<GameObject>(assetBundleRelativeDir, pathInBundle, mod);
|
||||
if (_prefabCache.TryGetValue(assetBundleRelativeDir + pathInBundle, out var prefab))
|
||||
return prefab;
|
||||
|
||||
prefab = Load<GameObject>(assetBundleRelativeDir, pathInBundle, mod);
|
||||
|
||||
prefab.SetActive(false);
|
||||
|
||||
ReplaceShaders(prefab);
|
||||
|
||||
// replacing shaders is expensive, so cache it
|
||||
_prefabCache.Add(assetBundleRelativeDir + pathInBundle, prefab);
|
||||
|
||||
return prefab;
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ using NewHorizons.Utility.OWML;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
@ -116,13 +117,17 @@ namespace NewHorizons.Utility
|
||||
if (CachedGameObjects.TryGetValue(path, out var go)) return go;
|
||||
|
||||
// 1: normal find
|
||||
Profiler.BeginSample("1");
|
||||
go = GameObject.Find(path);
|
||||
if (go)
|
||||
{
|
||||
CachedGameObjects.Add(path, go);
|
||||
Profiler.EndSample();
|
||||
return go;
|
||||
}
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("2");
|
||||
// 2: find inactive using root + transform.find
|
||||
var names = path.Split('/');
|
||||
|
||||
@ -142,9 +147,12 @@ namespace NewHorizons.Utility
|
||||
if (go)
|
||||
{
|
||||
CachedGameObjects.Add(path, go);
|
||||
Profiler.EndSample();
|
||||
return go;
|
||||
}
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("3");
|
||||
var name = names.Last();
|
||||
if (warn) NHLogger.LogWarning($"Couldn't find object in path {path}, will look for potential matches for name {name}");
|
||||
// 3: find resource to include inactive objects (but skip prefabs)
|
||||
@ -153,10 +161,12 @@ namespace NewHorizons.Utility
|
||||
if (go)
|
||||
{
|
||||
CachedGameObjects.Add(path, go);
|
||||
Profiler.EndSample();
|
||||
return go;
|
||||
}
|
||||
|
||||
if (warn) NHLogger.LogWarning($"Couldn't find object with name {name}");
|
||||
Profiler.EndSample();
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -169,5 +179,31 @@ namespace NewHorizons.Utility
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// transform.find but works for gameobjects with same name
|
||||
/// </summary>
|
||||
public static List<Transform> FindAll(this Transform @this, string path)
|
||||
{
|
||||
var names = path.Split('/');
|
||||
var currentTransforms = new List<Transform> { @this };
|
||||
foreach (var name in names)
|
||||
{
|
||||
var newTransforms = new List<Transform>();
|
||||
foreach (var currentTransform in currentTransforms)
|
||||
{
|
||||
foreach (Transform child in currentTransform)
|
||||
{
|
||||
if (child.name == name)
|
||||
{
|
||||
newTransforms.Add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
currentTransforms = newTransforms;
|
||||
}
|
||||
|
||||
return currentTransforms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user