From efb08c4704bfa06a12e06788f4cd01c32f0efeef Mon Sep 17 00:00:00 2001 From: Nicolas Gnyra Date: Sat, 23 Mar 2024 13:06:04 -0400 Subject: [PATCH] Create prefabs for all tags on scene load --- BeatSaberMarkupLanguage/BSMLParser.cs | 110 +++++++++++++----- .../Components/CustomCellListTableData.cs | 8 ++ .../Components/CustomListTableData.cs | 8 ++ .../Components/TabSelector.cs | 4 +- .../Harmony Patches/MainMenuInstaller.cs | 10 +- BeatSaberMarkupLanguage/Tags/BSMLTag.cs | 7 ++ BeatSaberMarkupLanguage/Tags/BackgroundTag.cs | 15 +-- BeatSaberMarkupLanguage/Tags/ButtonTag.cs | 16 +-- .../Tags/ButtonWithIconTag.cs | 28 +++-- .../Tags/ClickableImageTag.cs | 7 +- .../Tags/ClickableTextTag.cs | 8 +- BeatSaberMarkupLanguage/Tags/CustomListTag.cs | 21 ++-- BeatSaberMarkupLanguage/Tags/GridLayoutTag.cs | 7 +- .../Tags/HorizontalLayoutTag.cs | 14 +-- .../Tags/IconSegmentedControlTag.cs | 16 +-- BeatSaberMarkupLanguage/Tags/ImageTag.cs | 7 +- .../Tags/LeaderboardTag.cs | 16 +-- BeatSaberMarkupLanguage/Tags/ListTag.cs | 20 ++-- .../Tags/LoadingIndicatorTag.cs | 16 +-- .../Tags/ModalColorPickerTag.cs | 4 +- .../Tags/ModalKeyboardTag.cs | 26 +++-- BeatSaberMarkupLanguage/Tags/ModalTag.cs | 23 ++-- .../Tags/ModifierContainerTag.cs | 8 +- BeatSaberMarkupLanguage/Tags/ModifierTag.cs | 18 +-- BeatSaberMarkupLanguage/Tags/PageButtonTag.cs | 33 +++--- BeatSaberMarkupLanguage/Tags/PrefabBSMLTag.cs | 76 ++++++++++++ .../Tags/PrimaryButtonTag.cs | 9 +- BeatSaberMarkupLanguage/Tags/RawImageTag.cs | 7 +- .../Tags/ScrollIndicatorTag.cs | 27 +---- BeatSaberMarkupLanguage/Tags/ScrollViewTag.cs | 16 +-- .../Tags/ScrollableContainerTag.cs | 30 +++-- .../Tags/ScrollableSettingsContainerTag.cs | 8 +- .../Tags/Settings/ColorSettingTag.cs | 5 +- .../Tags/Settings/DropdownListSettingTag.cs | 33 ++---- .../Tags/Settings/GenericSliderSettingTag.cs | 16 +-- .../Tags/Settings/IncDecSettingTag.cs | 16 +-- .../Tags/Settings/StringSettingTag.cs | 3 +- .../Tags/Settings/SubmenuTag.cs | 54 +++++---- .../Tags/Settings/ToggleSettingTag.cs | 19 +-- .../Tags/StackLayoutTag.cs | 7 +- .../Tags/TabSelectorTag.cs | 19 ++- BeatSaberMarkupLanguage/Tags/TabTag.cs | 11 +- .../Tags/TextPageScrollViewTag.cs | 15 +-- .../Tags/TextSegmentedControlTag.cs | 16 +-- BeatSaberMarkupLanguage/Tags/TextTag.cs | 16 +-- .../Tags/VerticalIconSegmentedControlTag.cs | 10 +- .../Tags/VerticalLayoutTag.cs | 14 +-- BeatSaberMarkupLanguage/Util/TestPresenter.cs | 6 +- 48 files changed, 439 insertions(+), 444 deletions(-) create mode 100644 BeatSaberMarkupLanguage/Tags/PrefabBSMLTag.cs 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