diff --git a/BeatSaberMarkupLanguage/BSMLParser.cs b/BeatSaberMarkupLanguage/BSMLParser.cs index 0bf589fa..27aa0d64 100644 --- a/BeatSaberMarkupLanguage/BSMLParser.cs +++ b/BeatSaberMarkupLanguage/BSMLParser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -11,6 +12,7 @@ using BeatSaberMarkupLanguage.Tags; using BeatSaberMarkupLanguage.TypeHandlers; using BeatSaberMarkupLanguage.Util; +using IPA.Loader; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; @@ -19,7 +21,7 @@ namespace BeatSaberMarkupLanguage { - public class BSMLParser : PersistentSingleton, IInitializable + public class BSMLParser : PersistentSingleton, ILateDisposable { internal static readonly string MacroPrefix = "macro."; internal static readonly string RetrieveValuePrefix = "~"; @@ -35,6 +37,8 @@ public class BSMLParser : PersistentSingleton, IInitializable IgnoreComments = true, }; + private bool sceneContextResolved; + public BSMLParser() { foreach (BSMLTag tag in Utilities.GetInstancesOfDescendants()) @@ -59,37 +63,9 @@ public BSMLParser() } } - public void Initialize() + public void LateDispose() { - foreach (BSMLTag tag in tags.Values) - { - if (!tag.isInitialized) - { - tag.Setup(); - tag.isInitialized = true; - } - } - -#if false//don't worry about this, it's for the docs - string contents = ""; - foreach (BSMLTag tag in Utilities.GetListOfType()) - { - tag.Setup(); - contents += $"- type: {tag.GetType().Name}\n"; - contents += $" aliases:\n"; - foreach (string alias in tag.Aliases) - contents += $" - {alias}\n"; - contents += $" components:\n"; - GameObject currentNode = tag.CreateObject(transform); - foreach (TypeHandler typeHandler in typeHandlers) - { - Type type = typeHandler.GetType().GetCustomAttribute(true).type; - if (GetExternalComponent(currentNode, type) != null) - contents += $" - {type.Name}\n"; - } - } - File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "Tags.yml"), contents); -#endif + sceneContextResolved = false; } public void RegisterTag(BSMLTag tag) @@ -126,6 +102,11 @@ public BSMLParserParams Parse(XmlNode parentNode, GameObject parent, object host return null; } + if (!sceneContextResolved) + { + Logger.Log.Warn($"BSMLParser.Parse called by {GetCallerMods()} before Zenject initialization was completed! This may lead to unexpected results and will throw an exception in a future release."); + } + BSMLParserParams parserParams = new(host); FieldAccessOption fieldAccessOptions = FieldAccessOption.Auto; @@ -291,6 +272,51 @@ public void HandleNode(XmlNode node, GameObject parent, BSMLParserParams parserP } } + internal void SceneContext_PreResolve() + { + Stopwatch stopwatch = Stopwatch.StartNew(); + foreach (BSMLTag tag in tags.Values.Distinct()) + { +#pragma warning disable CS0612, CS0618 + if (!tag.isInitialized) + { + tag.Setup(); + tag.isInitialized = true; + } +#pragma warning restore CS0612, CS0618 + + tag.SetUp(); + } + + Logger.Log.Notice("Setup completed in " + stopwatch.Elapsed); + +#if false//don't worry about this, it's for the docs + string contents = ""; + foreach (BSMLTag tag in Utilities.GetListOfType()) + { + tag.Setup(); + contents += $"- type: {tag.GetType().Name}\n"; + contents += $" aliases:\n"; + foreach (string alias in tag.Aliases) + contents += $" - {alias}\n"; + contents += $" components:\n"; + GameObject currentNode = tag.CreateObject(transform); + foreach (TypeHandler typeHandler in typeHandlers) + { + Type type = typeHandler.GetType().GetCustomAttribute(true).type; + if (GetExternalComponent(currentNode, type) != null) + contents += $" - {type.Name}\n"; + } + } + File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "Tags.yml"), contents); +#endif + } + + internal void SceneContext_PostResolve() + { + sceneContextResolved = true; + } + private void HandleTagNode(XmlNode node, GameObject parent, BSMLParserParams parserParams, out IEnumerable componentInfo) { if (!this.tags.TryGetValue(node.Name, out BSMLTag currentTag)) @@ -467,6 +493,28 @@ private bool IsMainMenuSceneLoaded() return instance.IsValid() && ((SceneProvider.SceneOp)instance.m_InternalOp).m_DepOp.Result.Select(op => op.Result).OfType().All(ab => ab.m_AssetBundle != null); } + private string GetCallerMods() + { + List callers = new StackTrace() + .GetFrames() + .Select(f => f.GetMethod().DeclaringType.Assembly) + .Distinct() + .Where(a => a != Assembly.GetExecutingAssembly()) + .Select(a => PluginManager.EnabledPlugins.FirstOrDefault(p => p.Assembly == a)) + .Where(m => m != null) + .Select(m => $"{m.Name} ({m.Assembly.GetName()?.Name})") + .ToList(); + + if (callers.Count > 0) + { + return string.Join(", ", callers); + } + else + { + return ""; + } + } + public struct ComponentTypeWithData { public TypeHandler typeHandler; diff --git a/BeatSaberMarkupLanguage/Components/CustomCellListTableData.cs b/BeatSaberMarkupLanguage/Components/CustomCellListTableData.cs index bf482e3b..be74fd1c 100644 --- a/BeatSaberMarkupLanguage/Components/CustomCellListTableData.cs +++ b/BeatSaberMarkupLanguage/Components/CustomCellListTableData.cs @@ -41,6 +41,14 @@ public int NumberOfCells() { return data.Count; } + + private void Awake() + { + if (tableView != null) + { + tableView.SetDataSource(this, false); + } + } } public class CustomCellTableCell : TableCell diff --git a/BeatSaberMarkupLanguage/Components/CustomListTableData.cs b/BeatSaberMarkupLanguage/Components/CustomListTableData.cs index a0a618a0..ee33f71e 100644 --- a/BeatSaberMarkupLanguage/Components/CustomListTableData.cs +++ b/BeatSaberMarkupLanguage/Components/CustomListTableData.cs @@ -184,6 +184,14 @@ public int NumberOfCells() return data.Count(); } + private void Awake() + { + if (tableView != null) + { + tableView.SetDataSource(this, false); + } + } + public class CustomCellInfo { public string text; diff --git a/BeatSaberMarkupLanguage/Components/TabSelector.cs b/BeatSaberMarkupLanguage/Components/TabSelector.cs index 3746db68..56d90f2f 100644 --- a/BeatSaberMarkupLanguage/Components/TabSelector.cs +++ b/BeatSaberMarkupLanguage/Components/TabSelector.cs @@ -48,7 +48,7 @@ public void Setup() tab.selector = this; } - if (leftButtonTag != null) + if (!string.IsNullOrEmpty(leftButtonTag)) { leftButton = parserParams.GetObjectsWithTag(leftButtonTag).FirstOrDefault().GetComponent