From 22b24cba652698646b3ec3490e98ad00d30ad355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Sun, 23 Jun 2024 10:34:54 +0200 Subject: [PATCH 01/36] feat: added PieceManager AddPieceCategory and RemovePieceCategory without table parameter --- CHANGELOG.md | 4 +++ JotunnLib/Configs/PieceConfig.cs | 2 +- JotunnLib/Entities/CustomPiece.cs | 2 +- JotunnLib/Managers/PieceManager.cs | 31 +++++++++++++++++-- .../CreateCategoryTabCommand.cs | 9 ++---- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4b633d9a..9bb1f6b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Version 2.21.0 +* Added PieceManager.AddPieceCategory(string name) and PieceManager.RemovePieceCategory(string name) +* Deprecated PieceManager.AddPieceCategory(string table, string name) and PieceManager.RemovePieceCategory(string table, string name), use the new overloads without the table parameter + ## Version 2.20.1 * Fixed an error when cloning an item with an existing ExtEquipment * Changed prebuild to reference Mono.Cecil from the BepInEx folder to avoid version conflicts diff --git a/JotunnLib/Configs/PieceConfig.cs b/JotunnLib/Configs/PieceConfig.cs index b31f98c09..e98dc7891 100644 --- a/JotunnLib/Configs/PieceConfig.cs +++ b/JotunnLib/Configs/PieceConfig.cs @@ -143,7 +143,7 @@ public void Apply(GameObject prefab) if (!string.IsNullOrEmpty(Category)) { - piece.m_category = PieceManager.Instance.AddPieceCategory(PieceTable, Category); + piece.m_category = PieceManager.Instance.AddPieceCategory(Category); } } diff --git a/JotunnLib/Entities/CustomPiece.cs b/JotunnLib/Entities/CustomPiece.cs index 0fcaaf9bc..b28b837b0 100644 --- a/JotunnLib/Entities/CustomPiece.cs +++ b/JotunnLib/Entities/CustomPiece.cs @@ -41,7 +41,7 @@ public string Category if (Piece && !string.IsNullOrEmpty(category)) { - Piece.m_category = PieceManager.Instance.AddPieceCategory(PieceTable, category); + Piece.m_category = PieceManager.Instance.AddPieceCategory(category); } } } diff --git a/JotunnLib/Managers/PieceManager.cs b/JotunnLib/Managers/PieceManager.cs index 1efc0d386..e3d0dba85 100644 --- a/JotunnLib/Managers/PieceManager.cs +++ b/JotunnLib/Managers/PieceManager.cs @@ -193,7 +193,7 @@ public bool AddPieceTable(CustomPieceTable customPieceTable) // Create all custom categories on that table foreach (var category in customPieceTable.Categories) { - AddPieceCategory(customPieceTable.ToString(), category); + AddPieceCategory(category); } // Add the custom table to the PieceManager @@ -266,12 +266,25 @@ public List GetPieceTables() /// /// Add a new by name. A new category /// gets assigned a random integer for internal use. If you pass a vanilla category - /// the actual integer value of the enum is returned. + /// the actual integer value of the enum is returned. /// /// Prefab or item name of the PieceTable. /// Name of the category. /// int value of the vanilla or custom category + [Obsolete("Use AddPieceCategory(string name) instead")] public Piece.PieceCategory AddPieceCategory(string table, string name) + { + return AddPieceCategory(name); + } + + /// + /// Add a new by name. A new category + /// gets assigned a random integer for internal use. If you pass a vanilla category + /// the actual integer value of the enum is returned. + /// + /// Name of the category. + /// int value of the vanilla or custom category + public Piece.PieceCategory AddPieceCategory(string name) { Piece.PieceCategory categoryID = GetOrCreatePieceCategory(name, out bool isNew); @@ -319,7 +332,19 @@ public Piece.PieceCategory AddPieceCategory(string table, string name) /// /// Prefab or item name of the PieceTable. /// Name of the category. + [Obsolete("Use RemovePieceCategory(string name) instead")] public void RemovePieceCategory(string table, string name) + { + RemovePieceCategory(name); + } + + /// + /// Remove a from a table by name. + /// This does noting if a piece is still assigned to the category, remove it before calling this. + /// + /// Prefab or item name of the PieceTable. + /// Name of the category. + public void RemovePieceCategory(string name) { categoryRefreshNeeded = true; } @@ -574,7 +599,7 @@ private void RegisterPieceInPieceTable(GameObject prefab, string pieceTable, str if (!string.IsNullOrEmpty(category)) { - piece.m_category = AddPieceCategory(pieceTable, category); + piece.m_category = AddPieceCategory(category); } table.m_pieces.Add(prefab); diff --git a/TestMod/ConsoleCommands/CreateCategoryTabCommand.cs b/TestMod/ConsoleCommands/CreateCategoryTabCommand.cs index 742a3eeed..d2a50ba67 100644 --- a/TestMod/ConsoleCommands/CreateCategoryTabCommand.cs +++ b/TestMod/ConsoleCommands/CreateCategoryTabCommand.cs @@ -13,17 +13,12 @@ public class CreateCategoryTabCommand : ConsoleCommand public override void Run(string[] args) { - if (args.Length < 2) + if (args.Length < 1) { return; } - PieceManager.Instance.AddPieceCategory(args[0], args[1]); - } - - public override List CommandOptionList() - { - return PieceManager.Instance.GetPieceTables().Select(x => x.name).ToList(); + PieceManager.Instance.AddPieceCategory(args[0]); } } } From 69ec1628e339ec71a8c3f4aeaec45bc380695dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Sun, 23 Jun 2024 10:52:02 +0200 Subject: [PATCH 02/36] docs: updated asset creation guide dll copy instructions --- .../Documentation/tutorials/asset-creation.md | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/JotunnLib/Documentation/tutorials/asset-creation.md b/JotunnLib/Documentation/tutorials/asset-creation.md index 23f2f3571..b23bad741 100644 --- a/JotunnLib/Documentation/tutorials/asset-creation.md +++ b/JotunnLib/Documentation/tutorials/asset-creation.md @@ -35,11 +35,28 @@ After ripping the project you can open this as a reference on the vanilla prefab ### Mod Stub Project -Jötunn provides you with a barebone project stub which also includes a Unity project. You can get [that project in its entirety](https://github.com/Valheim-Modding/JotunnModStub) from our github. If you don't have already setup your dev environment, see our [step-by-step guide](../guides/guide.md) on how to do that. - -Before opening the Unity project, copy all files starting with `assembly_` and `ConnectedStorage.dll`, `PlayFab.dll`, `PlayFabParty.dll` from your ripped Valheim project at `\AuxiliaryFiles\GameAssemblies` into your stub project's `\JotunnModUnity\Assets\Assemblies` folder (create that if necessary). This enables us to exchange prefabs between the two projects without losing the references to the added Components. - - **Copy the files to the new project directly via the filesystem - don't import the assemblies via Unity**. +Jötunn provides you with a barebone project stub that also includes a Unity project. +You can get [this project in its entirety](https://github.com/Valheim-Modding/JotunnModStub) from our github. +If you haven't already setup your dev environment, see our [step-by-step guide](../guides/guide.md) on how to do this. + +Before opening the Unity project, copy the following files (especially the .meta files) from your ripped Valheim project at `\Assets\Plugins` folder into your stub project's `\JotunnModUnity\Assets\Assemblies` folder (create that if necessary).\ +If you are using the ModStub, you can compile the C# project instead, which will copy the necessary files for you. +See the [CopyToUnity Task](https://github.com/Valheim-Modding/JotunnModStub/blob/d8d48e6337bf842d57f0728d277c28543d016514/JotunnModStub/JotunnModStub.csproj#L83-L108) + +- all assembly_*.dll files +- PlayFab.dll +- PlayFabParty.dll +- PlatformTools.Core.dll +- PlatformTools.Common.dll +- ConnectedStorage.dll +- gui_framework.dll +- com.rlabrecque.steamworks.net.dll +- SoftReferenceableAssets.dll + +This allows us to exchange prefabs between the two projects without losing the references to the added components.\ +You can also copy the dll files from your game folder `/valheim_Data/Managed` and recover the missing references using e.g. the NG Missing Script Recovery tool. + +**Copy the files directly to the new project via the file system - don't import the assemblies via Unity**. After you copied the files, open UnityHub, add the JotunnModUnity project and open it. From a23ddc60466dd2cc97818bec47093b0b300a9140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Sun, 23 Jun 2024 11:02:57 +0200 Subject: [PATCH 03/36] docs: updated Unity version of Valheim to 2022.3.17 --- JotunnLib/Documentation/tutorials/asset-creation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JotunnLib/Documentation/tutorials/asset-creation.md b/JotunnLib/Documentation/tutorials/asset-creation.md index b23bad741..3325419cc 100644 --- a/JotunnLib/Documentation/tutorials/asset-creation.md +++ b/JotunnLib/Documentation/tutorials/asset-creation.md @@ -6,7 +6,7 @@ New Assets can be created with Unity and imported into Valheim using Jötunn. In Creation Tools * [Visual Studio](https://visualstudio.microsoft.com/de/downloads/) - Editor for our plugin code -* [Unity 2022.3.12](https://unity3d.com/unity/whats-new/2022.3.12) - Game engine that Valheim runs in +* [Unity 2022.3.17](https://unity3d.com/unity/whats-new/2022.3.17) - Game engine that Valheim runs in Game Mods (install these into your game as our mod has dependencies on them) * [Jötunn, the Valheim Library](https://thunderstore.io/c/valheim/p/ValheimModding/Jotunn/) - Mod with convenience methods we will use @@ -22,7 +22,7 @@ To add an item to the game, a mod maker will have to: ## Unity Editor Setup -Valheim uses Unity Version **2022.3.12** +Valheim uses Unity Version **2022.3.17** If you don't have Unity already installed, download [UnityHub](https://public-cdn.cloud.unity3d.com/hub/prod/UnityHubSetup.exe) from their website or install it with the Visual Studio Installer via `Individual Components` -> `Visual Studio Tools for Unity`. You will need an Unity account to register your PC and get a free licence. [Create the account](https://id.unity.com/account/new), login with it in UnityHub and get your licence via `Settings` -> `Licence Management`. From 866f2ab0869b368d454efb26cd68ea0743991827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Mon, 24 Jun 2024 07:03:34 +0200 Subject: [PATCH 04/36] docs: removed table param from docstring --- JotunnLib/Managers/PieceManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/JotunnLib/Managers/PieceManager.cs b/JotunnLib/Managers/PieceManager.cs index e3d0dba85..f26d8bdbc 100644 --- a/JotunnLib/Managers/PieceManager.cs +++ b/JotunnLib/Managers/PieceManager.cs @@ -342,7 +342,6 @@ public void RemovePieceCategory(string table, string name) /// Remove a from a table by name. /// This does noting if a piece is still assigned to the category, remove it before calling this. /// - /// Prefab or item name of the PieceTable. /// Name of the category. public void RemovePieceCategory(string name) { From 4e5a121915e3c2468b4f863415a99ed84267ae7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Sat, 13 Jul 2024 19:17:23 +0200 Subject: [PATCH 05/36] chore: simplified GUIManager asset loading --- JotunnLib/Managers/GUIManager.cs | 41 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/JotunnLib/Managers/GUIManager.cs b/JotunnLib/Managers/GUIManager.cs index 658ce4a2c..252ffc3a3 100644 --- a/JotunnLib/Managers/GUIManager.cs +++ b/JotunnLib/Managers/GUIManager.cs @@ -370,30 +370,21 @@ internal void InitializeAssets() { try { - SpriteAtlas[] atlas = Resources.FindObjectsOfTypeAll(); + UIAtlas = PrefabManager.Cache.GetPrefab("UIAtlas"); + IconAtlas = PrefabManager.Cache.GetPrefab("IconAtlas"); - UIAtlas = atlas.FirstOrDefault(x => x.name.Equals("UIAtlas")); - if (UIAtlas == null) - { - throw new Exception("UIAtlas not found"); - } + AssertMissingAsset(UIAtlas, nameof(UIAtlas), nameof(SpriteAtlas)); + AssertMissingAsset(IconAtlas, nameof(IconAtlas), nameof(SpriteAtlas)); - IconAtlas = atlas.FirstOrDefault(x => x.name.Equals("IconAtlas")); - if (IconAtlas == null) - { - throw new Exception("IconAtlas not found"); - } + AveriaSerif = PrefabManager.Cache.GetPrefab("AveriaSerifLibre-Regular"); + AveriaSerifBold = PrefabManager.Cache.GetPrefab("AveriaSerifLibre-Bold"); + Norse = PrefabManager.Cache.GetPrefab("Norse"); + NorseBold = PrefabManager.Cache.GetPrefab("Norsebold"); - // Fonts - Font[] fonts = Resources.FindObjectsOfTypeAll(); - AveriaSerif = fonts.FirstOrDefault(x => x.name == "AveriaSerifLibre-Regular"); - AveriaSerifBold = fonts.FirstOrDefault(x => x.name == "AveriaSerifLibre-Bold"); - Norse = fonts.FirstOrDefault(x => x.name == "Norse"); - NorseBold = fonts.FirstOrDefault(x => x.name == "Norsebold"); - if (AveriaSerifBold == null || AveriaSerif == null || Norse == null || NorseBold == null) - { - throw new Exception("Fonts not found"); - } + AssertMissingAsset(AveriaSerif, nameof(AveriaSerif), nameof(Font)); + AssertMissingAsset(AveriaSerifBold, nameof(AveriaSerifBold), nameof(Font)); + AssertMissingAsset(Norse, nameof(Norse), nameof(Font)); + AssertMissingAsset(NorseBold, nameof(NorseBold), nameof(Font)); // DefaultControls.Resources pack AssetBundle jotunnBundle = AssetUtils.LoadAssetBundleFromResources("jotunn", typeof(Main).Assembly); @@ -480,6 +471,14 @@ internal void InitializeAssets() } } + private void AssertMissingAsset(Object asset, string name, string type) + { + if (!asset) + { + Logger.LogWarning($"{name} ({type}) not found"); + } + } + private bool TryCreateGUI() { GUIInStart = SceneManager.GetActiveScene().name == "start"; From d01542bd2c24d551d80c3f5fd6be468eb82bf36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Wed, 17 Jul 2024 07:38:35 +0200 Subject: [PATCH 06/36] docs: added SynchronizationManager events to flow --- JotunnLib/Documentation/flow.puml | 8 ++++++++ JotunnLib/Documentation/images/data/eventFlow.svg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/JotunnLib/Documentation/flow.puml b/JotunnLib/Documentation/flow.puml index 7ed2c8ae9..2dafb5d0e 100644 --- a/JotunnLib/Documentation/flow.puml +++ b/JotunnLib/Documentation/flow.puml @@ -19,6 +19,7 @@ box Jotunn participant ZoneManager participant GUIManager participant MinimapManager + participant SynchronizationManager end box group For each mod @@ -83,6 +84,13 @@ Valheim -> Valheim++: Minimap.LoadMapData hnote over MinimapManager: OnVanillaMapDataLoaded deactivate Valheim +group client (only if connecting to a server) +Valheim -> Valheim++: ZRoutedRpc.HandleRoutedRPC + hnote over SynchronizationManager: OnAdminStatusChanged + hnote over SynchronizationManager: OnSyncingConfiguration + hnote over SynchronizationManager: OnConfigurationSynchronized +deactivate Valheim +end group note over Valheim #lightblue: Game interactable diff --git a/JotunnLib/Documentation/images/data/eventFlow.svg b/JotunnLib/Documentation/images/data/eventFlow.svg index 3304e9675..037b780c5 100644 --- a/JotunnLib/Documentation/images/data/eventFlow.svg +++ b/JotunnLib/Documentation/images/data/eventFlow.svg @@ -1 +1 @@ -JotunnModsJotunnValheimBepInExJotunnModLocalizationManagerCreatureManagerPrefabManagerPieceManagerItemManagerZoneManagerGUIManagerMinimapManagerFor each modLoaded byBepInExAwakeMain Menu SceneClutterSystem.AwakeOnVanillaClutterAvailableOnClutterRegisteredFejdStartup.SetupGuiOnCustomGUIAvailableOnLocalizationAddedObjectDB.CopyOtherDBOnVanillaCreaturesAvailableOnVanillaPrefabsAvailableOnItemsRegisteredFejdMain menu interactableLoading SceneGame SceneZNetScene.AwakeOnCreaturesRegisteredOnPrefabsRegisteredObjectDB.AwakeOnItemsRegisteredOnPiecesRegisteredClutterSystem.AwakeOnVanillaClutterAvailableOnClutterRegisteredGame.StartOnCustomGUIAvailableZoneSystem.SetupLocationsOnVanillaLocationsAvailableOnLocationsRegisteredOnVanillaVegetationAvailableOnVegetationRegisteredMinimap.StartOnVanillaMapAvailableMinimap.LoadMapDataOnVanillaMapDataLoadedGame interactable \ No newline at end of file +JotunnModsJotunnValheimBepInExJotunnModLocalizationManagerCreatureManagerPrefabManagerPieceManagerItemManagerZoneManagerGUIManagerMinimapManagerSynchronizationManagerFor each modLoaded byBepInExAwakeMain Menu SceneClutterSystem.AwakeOnVanillaClutterAvailableOnClutterRegisteredFejdStartup.SetupGuiOnCustomGUIAvailableOnLocalizationAddedObjectDB.CopyOtherDBOnVanillaCreaturesAvailableOnVanillaPrefabsAvailableOnItemsRegisteredFejdMain menu interactableLoading SceneGame SceneZNetScene.AwakeOnCreaturesRegisteredOnPrefabsRegisteredObjectDB.AwakeOnItemsRegisteredOnPiecesRegisteredClutterSystem.AwakeOnVanillaClutterAvailableOnClutterRegisteredGame.StartOnCustomGUIAvailableZoneSystem.SetupLocationsOnVanillaLocationsAvailableOnLocationsRegisteredOnVanillaVegetationAvailableOnVegetationRegisteredMinimap.StartOnVanillaMapAvailableMinimap.LoadMapDataOnVanillaMapDataLoadedclient (only if connecting to a server)ZRoutedRpc.HandleRoutedRPCOnAdminStatusChangedOnSyncingConfigurationOnConfigurationSynchronizedGame interactable \ No newline at end of file From c2a56c7131b9b3715ee33bbd5f5b7f68a99d02d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Wed, 17 Jul 2024 07:46:12 +0200 Subject: [PATCH 07/36] fix: allow editing of new admin-only configs in the main menu --- CHANGELOG.md | 1 + JotunnLib/Utils/ConfigurationManagerAttributes.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bb1f6b08..b3d00344d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Version 2.21.0 * Added PieceManager.AddPieceCategory(string name) and PieceManager.RemovePieceCategory(string name) * Deprecated PieceManager.AddPieceCategory(string table, string name) and PieceManager.RemovePieceCategory(string table, string name), use the new overloads without the table parameter +* Fixed adding admin-only configs after between loading to the main menu and before loading the game being locked for local editing ## Version 2.20.1 * Fixed an error when cloning an item with an existing ExtEquipment diff --git a/JotunnLib/Utils/ConfigurationManagerAttributes.cs b/JotunnLib/Utils/ConfigurationManagerAttributes.cs index 7b49afe38..9ca970557 100644 --- a/JotunnLib/Utils/ConfigurationManagerAttributes.cs +++ b/JotunnLib/Utils/ConfigurationManagerAttributes.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Linq; using System.Reflection; +using Jotunn.Managers; using UnityEngine; /// @@ -124,7 +125,7 @@ public bool IsAdminOnly set { isAdminOnly = value; - IsUnlocked = !value; + IsUnlocked = SynchronizationManager.Instance.PlayerIsAdmin; } } From aef11241d28982211559163877f1037cd2edbf6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Wed, 17 Jul 2024 07:47:45 +0200 Subject: [PATCH 08/36] docs: changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3d00344d..28fd7691f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Version 2.21.0 * Added PieceManager.AddPieceCategory(string name) and PieceManager.RemovePieceCategory(string name) * Deprecated PieceManager.AddPieceCategory(string table, string name) and PieceManager.RemovePieceCategory(string table, string name), use the new overloads without the table parameter +* Changed GUIManager asset loading to use the prefab cache and not hard crash on missing assets * Fixed adding admin-only configs after between loading to the main menu and before loading the game being locked for local editing ## Version 2.20.1 From 4031862d670a87f8e365b922aedc322e2d23e963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Wed, 17 Jul 2024 07:49:54 +0200 Subject: [PATCH 09/36] docs: changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28fd7691f..31ea19684 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * Added PieceManager.AddPieceCategory(string name) and PieceManager.RemovePieceCategory(string name) * Deprecated PieceManager.AddPieceCategory(string table, string name) and PieceManager.RemovePieceCategory(string table, string name), use the new overloads without the table parameter * Changed GUIManager asset loading to use the prefab cache and not hard crash on missing assets -* Fixed adding admin-only configs after between loading to the main menu and before loading the game being locked for local editing +* Fixed adding admin-only configs between loading to the main menu and before loading the game being locked for local editing ## Version 2.20.1 * Fixed an error when cloning an item with an existing ExtEquipment From 9215dd861ae4796a22c893baa24600443fd8d762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Wed, 17 Jul 2024 15:49:40 +0200 Subject: [PATCH 10/36] feat: added ConfigManagerUtils --- CHANGELOG.md | 1 + JotunnLib/Managers/SynchronizationManager.cs | 16 ++---- JotunnLib/Utils/ConfigManagerUtils.cs | 54 ++++++++++++++++++++ 3 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 JotunnLib/Utils/ConfigManagerUtils.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 31ea19684..3dfd99800 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Version 2.21.0 +* Added ConfigManagerUtils for soft access to common ConfigurationManager functionality * Added PieceManager.AddPieceCategory(string name) and PieceManager.RemovePieceCategory(string name) * Deprecated PieceManager.AddPieceCategory(string table, string name) and PieceManager.RemovePieceCategory(string table, string name), use the new overloads without the table parameter * Changed GUIManager asset loading to use the prefab cache and not hard crash on missing assets diff --git a/JotunnLib/Managers/SynchronizationManager.cs b/JotunnLib/Managers/SynchronizationManager.cs index 7c277d235..a6c657995 100644 --- a/JotunnLib/Managers/SynchronizationManager.cs +++ b/JotunnLib/Managers/SynchronizationManager.cs @@ -28,7 +28,6 @@ public class SynchronizationManager : IManager private readonly Dictionary CustomConfigs = new Dictionary(); private List> CachedConfigValues = new List>(); private readonly Dictionary CachedCustomConfigGUIDs = new Dictionary(); - private BaseUnityPlugin ConfigurationManager; private bool ConfigurationManagerWindowShown; /// @@ -89,20 +88,15 @@ void IManager.Init() // Hook start scene to reset config SceneManager.sceneLoaded += SceneManager_sceneLoaded; - // Find Configuration manager plugin and add to DisplayingWindowChanged event - const string configManagerGuid = "com.bepis.bepinex.configurationmanager"; - if (Chainloader.PluginInfos.TryGetValue(configManagerGuid, out var configManagerInfo) && configManagerInfo.Instance) + if (ConfigManagerUtils.Plugin) { - ConfigurationManager = configManagerInfo.Instance; - - Logger.LogDebug("Configuration manager found, trying to hook DisplayingWindowChanged"); - var eventinfo = ConfigurationManager.GetType().GetEvent("DisplayingWindowChanged"); + var eventinfo = ConfigManagerUtils.Plugin.GetType().GetEvent("DisplayingWindowChanged"); if (eventinfo != null) { Action local = ConfigurationManager_DisplayingWindowChanged; var converted = Delegate.CreateDelegate(eventinfo.EventHandlerType, local.Target, local.Method); - eventinfo.AddEventHandler(ConfigurationManager, converted); + eventinfo.AddEventHandler(ConfigManagerUtils.Plugin, converted); } } @@ -573,9 +567,7 @@ private void Menu_IsVisible(ref bool result) /// private void ConfigurationManager_DisplayingWindowChanged(object sender, object e) { - // Read configuration manager's DisplayingWindow property - var pi = ConfigurationManager.GetType().GetProperty("DisplayingWindow"); - ConfigurationManagerWindowShown = (bool)pi.GetValue(ConfigurationManager, null); + ConfigurationManagerWindowShown = ConfigManagerUtils.DisplayingWindow; if (!ConfigurationManagerWindowShown) { diff --git a/JotunnLib/Utils/ConfigManagerUtils.cs b/JotunnLib/Utils/ConfigManagerUtils.cs new file mode 100644 index 000000000..f6b5d10bd --- /dev/null +++ b/JotunnLib/Utils/ConfigManagerUtils.cs @@ -0,0 +1,54 @@ +using System; +using System.Reflection; +using BepInEx; +using BepInEx.Bootstrap; +using HarmonyLib; + +namespace Jotunn.Utils +{ + /// + /// Utility class for the BepInEx ConfigurationManager plugin, without requiring a hard dependency + /// + public static class ConfigManagerUtils + { + /// + /// The ConfigurationManager plugin instance if installed, otherwise null + /// + public static BaseUnityPlugin Plugin { get; private set; } + + private static PropertyInfo displayingWindowInfo; + private static MethodInfo buildSettingListMethodInfo; + + static ConfigManagerUtils() + { + if (Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var configManagerInfo) && configManagerInfo.Instance) + { + Plugin = configManagerInfo.Instance; + displayingWindowInfo = AccessTools.Property(Plugin.GetType(), "DisplayingWindow"); + buildSettingListMethodInfo = AccessTools.Method(Plugin.GetType(), "BuildSettingList"); + } + } + + /// + /// Is the config manager main window displayed on screen
+ /// Safe to use even if ConfigurationManager is not installed. + ///
+ public static bool DisplayingWindow + { + get => Plugin && (bool)displayingWindowInfo.GetValue(Plugin); + set => displayingWindowInfo?.SetValue(Plugin, value); + } + + /// + /// Rebuild the setting list. Use to update the config manager window if config settings were removed or added while it was open.
+ /// Safe to call even if ConfigurationManager is not installed. + ///
+ public static void BuildSettingList() + { + if (Plugin) + { + buildSettingListMethodInfo.Invoke(Plugin, null); + } + } + } +} From 7b3683519662e8ae98c2a9690f82e0da81b1e611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Wed, 17 Jul 2024 15:56:21 +0200 Subject: [PATCH 11/36] fix: GameVersions.NetworkVersion was evaluated at compile time --- CHANGELOG.md | 1 + JotunnLib/Utils/GameVersions.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dfd99800..4c2b6332f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Deprecated PieceManager.AddPieceCategory(string table, string name) and PieceManager.RemovePieceCategory(string table, string name), use the new overloads without the table parameter * Changed GUIManager asset loading to use the prefab cache and not hard crash on missing assets * Fixed adding admin-only configs between loading to the main menu and before loading the game being locked for local editing +* Fixed network version in the disconnect window was always 27 duo to being a constant value ## Version 2.20.1 * Fixed an error when cloning an item with an existing ExtEquipment diff --git a/JotunnLib/Utils/GameVersions.cs b/JotunnLib/Utils/GameVersions.cs index 230fc4d05..b883ad2d2 100644 --- a/JotunnLib/Utils/GameVersions.cs +++ b/JotunnLib/Utils/GameVersions.cs @@ -18,7 +18,8 @@ private static System.Version GetValheimVersion() private static uint GetNetworkVersion() { - return Version.m_networkVersion; + // use Reflection because Version.m_networkVersion is a constant field, i.e. evaluated at compile time + return (uint)AccessTools.Field(typeof(Version), nameof(Version.m_networkVersion)).GetValue(null); } } } From 91c218326333aede1e1f7781585e902ef4a90be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Wed, 17 Jul 2024 16:03:16 +0200 Subject: [PATCH 12/36] feat: added GameVersions to the API --- CHANGELOG.md | 1 + JotunnLib/Utils/GameVersions.cs | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c2b6332f..36d4434bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Version 2.21.0 +* Added GameVersions utility to check for specific game versions * Added ConfigManagerUtils for soft access to common ConfigurationManager functionality * Added PieceManager.AddPieceCategory(string name) and PieceManager.RemovePieceCategory(string name) * Deprecated PieceManager.AddPieceCategory(string table, string name) and PieceManager.RemovePieceCategory(string table, string name), use the new overloads without the table parameter diff --git a/JotunnLib/Utils/GameVersions.cs b/JotunnLib/Utils/GameVersions.cs index b883ad2d2..cd5a36419 100644 --- a/JotunnLib/Utils/GameVersions.cs +++ b/JotunnLib/Utils/GameVersions.cs @@ -5,10 +5,19 @@ namespace Jotunn.Utils { - internal static class GameVersions + /// + /// Utility class for getting game versions + /// + public static class GameVersions { + /// + /// The semantic version of the running Valheim game + /// public static System.Version ValheimVersion { get; } = GetValheimVersion(); + /// + /// The network version of the running Valheim game, determining compatibility with other clients + /// public static uint NetworkVersion { get; } = GetNetworkVersion(); private static System.Version GetValheimVersion() From 3c2202f75cc22a4cc6265d0d6113873676cf30f7 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:12:15 -0700 Subject: [PATCH 13/36] Initial checkin of (kory) DungeonManager - kory commit --- JotunnLib/Configs/RoomConfig.cs | 92 ++++++ JotunnLib/Entities/CustomRoom.cs | 172 ++++++++++ JotunnLib/Managers/DungeonManager.cs | 387 +++++++++++++++++++++++ JotunnLib/Utils/DungeonGeneratorTheme.cs | 15 + 4 files changed, 666 insertions(+) create mode 100644 JotunnLib/Configs/RoomConfig.cs create mode 100644 JotunnLib/Entities/CustomRoom.cs create mode 100644 JotunnLib/Managers/DungeonManager.cs create mode 100644 JotunnLib/Utils/DungeonGeneratorTheme.cs diff --git a/JotunnLib/Configs/RoomConfig.cs b/JotunnLib/Configs/RoomConfig.cs new file mode 100644 index 000000000..adefb52e3 --- /dev/null +++ b/JotunnLib/Configs/RoomConfig.cs @@ -0,0 +1,92 @@ +using Jotunn.Entities; + +namespace Jotunn.Configs +{ + /// + /// Configuration class for adding custom clutter.
+ /// Use this in a constructor of + ///
+ public class RoomConfig + { + /// + /// Theme name of this room. + /// + public string ThemeName { get; } + + /// + /// of this room. + /// + public Room.Theme Theme { get; } + + /// + /// If set to false, room will not be added to , thus + /// won't be used during generation. + /// + public bool? Enabled { get; set; } + + /// + /// Flag indicating if this room is a dungeon entrance. + /// + public bool? Entrance { get; set; } + + /// + /// Flag indicating if this room is an endcap. + /// + public bool? Endcap { get; set; } + + /// + /// Flag indicating if this room is a divider. + /// + public bool? Divider { get; set; } + + /// + /// A rank value to prioritize this endcap over others during generation. + /// + public int? EndcapPrio { get; set; } + + /// + /// Exclude this room if the adjoining connection's is less than this value. + /// + public int? MinPlaceOrder { get; set; } + + /// + /// A weight value used to sort available rooms during some modes of generation. Defaults to 1f. + /// + public float? Weight { get; set; } + + /// + /// Flag to orient this room towards the center. Used only for generating camps (draugr/fuling villages). + /// + public bool? FaceCenter { get; set; } + + /// + /// Flag to ensure this room is only placed around the perimeter of a camp. Used only for generating camps (draugr/fuling villages). + /// + public bool? Perimeter { get; set; } + + /// + /// Background music to play when a player gets in range of this room. + /// + public MusicVolume MusicPrefab { get; set; } + + /// + /// Create a config with a . + /// + /// + public RoomConfig(Room.Theme theme) + { + Theme = theme; + ThemeName = string.Empty; + } + + /// + /// Create a config with a theme name. + /// + /// + public RoomConfig(string themeName) + { + Theme = 0; + ThemeName = themeName; + } + } +} diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs new file mode 100644 index 000000000..9c786f774 --- /dev/null +++ b/JotunnLib/Entities/CustomRoom.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Jotunn.Configs; +using Jotunn.Managers; +using SoftReferenceableAssets; +using UnityEngine; + +namespace Jotunn.Entities +{ + /// + /// Main interface for adding custom dungeon rooms to the game.
+ /// All custom rooms have to be wrapped inside this class to add it to Jötunns . + ///
+ public class CustomRoom : CustomEntity + { + /// + /// The prefab for this custom room. + /// + public GameObject Prefab { get; } + + /// + /// The component for this custom room as a shortcut. + /// + public Room Room { get; } + + /// + /// The name of this custom room as a shortcut. + /// + public string Name { get; } + + /// + /// Indicator if references from s will be replaced at runtime. + /// + public bool FixReference { get; set; } + + /// + /// Theme name of this room. + /// + public string ThemeName { get; private set; } + + /// + /// of this room. + /// + public Room.Theme Theme { get; private set; } + + /// + /// Associated holding data used during generation. + /// + public DungeonDB.RoomData RoomData { get; private set; } + + + /// + /// Custom room from a prefab loaded from an with a made from a .
+ /// Can fix references for s. + ///
+ /// A preloaded + /// Name of the prefab in the bundle. + /// The config for this custom room. + public CustomRoom(AssetBundle assetBundle, string assetName, RoomConfig roomConfig) + : this(assetBundle, assetName, false, roomConfig) { } + + /// + /// Custom room from a prefab loaded from an with a made from a .
+ /// Can fix references for s. + ///
+ /// A preloaded + /// Name of the prefab in the bundle. + /// If true references for objects get resolved at runtime by Jötunn. + /// The config for this custom room. + public CustomRoom(AssetBundle assetBundle, string assetName, bool fixReference, RoomConfig roomConfig) : base(Assembly.GetCallingAssembly()) + { + Prefab = assetBundle.LoadAsset(assetName); + Name = Prefab.name; + if (Prefab != null && Prefab.TryGetComponent(out var room)) + { + Room = room; + } + else + { + Room = Prefab.AddComponent(); + } + FixReference = fixReference; + ApplyConfig(roomConfig); + } + + + /// + /// Custom room from a prefab with a made from a . + /// + /// The prefab for this custom room. + /// The config for this custom room. + public CustomRoom(GameObject prefab, RoomConfig roomConfig) + : this(prefab, false, roomConfig) { } + + + /// + /// Custom room from a prefab loaded from an with a made from a .
+ /// Can fix references for s. + ///
+ /// The prefab for this custom room. + /// If true references for objects get resolved at runtime by Jötunn. + /// The config for this custom room. + public CustomRoom(GameObject prefab, bool fixReference, RoomConfig roomConfig) : base(Assembly.GetCallingAssembly()) + { + Prefab = prefab; + Name = prefab.name; + if (prefab != null && prefab.TryGetComponent(out var room)) + { + Room = room; + } + else + { + Room = prefab.AddComponent(); + } + FixReference = fixReference; + ApplyConfig(roomConfig); + } + + /// + /// Helper method to determine if a prefab with a given name is a custom room created with Jötunn. + /// + /// Name of the prefab to test. + /// true if the prefab is added as a custom item to the . + public static bool IsCustomRoom(string prefabName) + { + return DungeonManager.Instance.Rooms.ContainsKey(prefabName); + } + + private void ApplyConfig(RoomConfig roomConfig) + { + // Ensure Room values are overwritten only when a value's present. + if (roomConfig.Enabled != null) Room.m_enabled = roomConfig.Enabled.Value; + if (roomConfig.Entrance != null) Room.m_entrance = roomConfig.Entrance.Value; + if (roomConfig.Endcap != null) Room.m_endCap = roomConfig.Endcap.Value; + if (roomConfig.Divider != null) Room.m_divider = roomConfig.Divider.Value; + if (roomConfig.EndcapPrio != null) Room.m_endCapPrio = roomConfig.EndcapPrio.Value; + if (roomConfig.MinPlaceOrder != null) Room.m_minPlaceOrder = roomConfig.MinPlaceOrder.Value; + if (roomConfig.Weight != null) Room.m_weight = roomConfig.Weight.Value; + if (roomConfig.FaceCenter != null) Room.m_faceCenter = roomConfig.FaceCenter.Value; + if (roomConfig.Perimeter != null) Room.m_perimeter = roomConfig.Perimeter.Value; + if (roomConfig.MusicPrefab != null) Room.m_musicPrefab = roomConfig.MusicPrefab; + + // Room can be matched by either a Room.Theme flag, or a ThemeName string. + if (roomConfig.Theme == 0) + { + ThemeName = roomConfig.ThemeName; + Theme = 0; + } + else + { + Theme = roomConfig.Theme; + ThemeName = string.Empty; + } + + // DungeonGenerator.PlaceRoom*() utilize soft references directly, thus registering the assets here. + RoomData = new DungeonDB.RoomData() + { + m_prefab = new SoftReference(AssetManager.Instance.AddAsset(Prefab)), + m_loadedRoom = Room, + m_prefabData = new RoomPrefabData() + { + m_enabled = Room.m_enabled, + m_theme = Theme + } + }; + } + } +} diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs new file mode 100644 index 000000000..3fd69ba21 --- /dev/null +++ b/JotunnLib/Managers/DungeonManager.cs @@ -0,0 +1,387 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using Jotunn.Entities; +using Jotunn.Managers.MockSystem; +using Jotunn.Utils; +using UnityEngine; + +namespace Jotunn.Managers +{ + /// + /// Manager for handling all custom data added to the game related to creatures. + /// + public class DungeonManager : IManager + { + private static DungeonManager _instance; + + /// + /// The singleton instance of this manager. + /// + public static DungeonManager Instance => _instance ??= new DungeonManager(); + + /// + /// Event that gets fired after the vanilla has loaded rooms. Your code will execute + /// every time a main scene is started (on joining a game).
+ /// If you want to execute just once you will need to unregister from the event after execution. + ///
+ public static event Action OnVanillaRoomsAvailable; + + /// + /// Internal dictionary of all custom rooms + /// + internal readonly Dictionary Rooms = new Dictionary(); + + private readonly Dictionary hashToName = new Dictionary(); + private readonly List themeList = new List(); + private readonly Dictionary prefabNames = new Dictionary(); + private readonly Dictionary envNames = new Dictionary(); + + /// + /// Container for Jötunn's DungeonRooms in the DontDestroyOnLoad scene. + /// + internal GameObject DungeonRoomContainer; + + + /// + /// Hide .ctor + /// + private DungeonManager() { } + + static DungeonManager() + { + ((IManager)Instance).Init(); + } + + + /// + /// Creates the spawner container and registers all hooks. + /// + void IManager.Init() + { + Main.LogInit("DungeonManager"); + + DungeonRoomContainer = new GameObject("DungeonRooms"); + DungeonRoomContainer.transform.parent = Main.RootObject.transform; + DungeonRoomContainer.SetActive(false); + + Main.Harmony.PatchAll(typeof(Patches)); + } + + private static class Patches + { + [HarmonyPatch(typeof(ZoneSystem), nameof(ZoneSystem.SetupLocations)), HarmonyPrefix] + private static void OnBeforeZoneSystemSetupLocations() => Instance.OnZoneSystemSetupLocations(); + + [HarmonyPatch(typeof(DungeonDB), nameof(DungeonDB.Start)), HarmonyPostfix] + private static void OnDungeonDBStarted() => Instance.OnDungeonDBStarted(); + + [HarmonyPatch(typeof(DungeonDB), nameof(DungeonDB.GetRoom)), HarmonyPostfix] + private static bool OnDungeonDBGetRoom(int hash, ref DungeonDB.RoomData __result) + { + DungeonDB.RoomData result = Instance.OnDungeonDBGetRoom(hash); + + if (result != null) + { + __result = result; + return false; + } + return true; + } + + [HarmonyPatch(typeof(DungeonGenerator), nameof(DungeonGenerator.SetupAvailableRooms)), HarmonyPostfix] + private static void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator __instance) => Instance.OnDungeonGeneratorSetupAvailableRooms(__instance); + } + + /// + /// Add a to the game.
+ /// Checks if the custom room is valid and unique and adds it to the list of custom rooms. + ///
+ /// The custom Room to add. + /// true if the custom Room was added to the manager. + public bool AddCustomRoom(CustomRoom customRoom) + { + if (customRoom == null) + { + throw new ArgumentException("Cannot be null", nameof(customRoom)); + } + + if (!string.IsNullOrEmpty(customRoom.ThemeName) && !themeList.Contains(customRoom.ThemeName)) + { + throw new ArgumentException($"Custom theme of this room ({customRoom.ThemeName}) must be registered.", nameof(customRoom)); + } + + if (Rooms.ContainsKey(customRoom.Name)) + { + Jotunn.Logger.LogWarning($"Room {customRoom.Name} already exists"); + return false; + } + + customRoom.Prefab.transform.SetParent(DungeonRoomContainer.transform); + customRoom.Prefab.SetActive(true); + Rooms.Add(customRoom.Name, customRoom); + return true; + } + + /// + /// Get a custom room by its name. + /// + /// Name of the custom room to search. + /// The if found. + public CustomRoom GetRoom(string name) + { + return Rooms.ContainsKey(name) ? Rooms[name] : null; + } + + /// + /// Remove a custom room by its name. + /// + /// Name of the room to remove. + public bool RemoveRoom(string name) + { + return Rooms.Remove(name); + } + + /// + /// Registers a new dungeon theme, identified by a unique theme name string.
+ /// Assets can be added at any time and will be registered as soon as the vanilla loader is ready. + ///
+ /// The prefab. + /// The name of the theme to register. + /// True if theme is successfullly registered, otherwise false. + public bool RegisterDungeonTheme(GameObject prefab, string themeName) + { + Logger.LogDebug($"RegisterDungeonTheme called with prefab {prefab.name} and themeName {themeName}."); + + if (prefab == null) + { + throw new ArgumentException("Cannot be null", nameof(prefab)); + } + if (string.IsNullOrEmpty(themeName)) + { + throw new ArgumentException("Cannot be null or empty", nameof(themeName)); + } + + DungeonGenerator dg = prefab.GetComponentInChildren(); + if (dg == null) + { + Logger.LogError($"Cannot find DungeonGenerator component in prefab {prefab.name}."); + throw new ArgumentException("Prefab must contain a DungeonGenerator component", "prefab"); + } + + DungeonGeneratorTheme dgt; + if (dg.gameObject.TryGetComponent(out dgt)) + { + if (!string.IsNullOrEmpty(dgt.m_themeName) && dgt.m_themeName != themeName) + { + Logger.LogWarning($"Overwriting existing theme name {dgt.m_themeName} with {themeName}."); + } + } + else + { + dgt = dg.gameObject.AddComponent(); + } + dgt.m_themeName = themeName; + themeList.Add(themeName); + + return true; + } + + + /// + /// Adds a new environment prefab to be registered when runs.
+ /// If you intend to use a custom interior environment , this method enables you + /// to provide a prefab with an appropriately configured containing atleast one + /// within . + ///
+ /// The containing the prefab. + /// The name of the prefab to register. + public void RegisterEnvironment(AssetBundle assetBundle, string prefabName) + { + if (assetBundle == null) + { + throw new ArgumentException("Cannot be null", nameof(assetBundle)); + } + if (string.IsNullOrEmpty(prefabName)) + { + throw new ArgumentException("Cannot be null or empty", nameof(prefabName)); + } + envNames.Add(prefabName, assetBundle); + } + + /// + /// Adds a new prefab to be registered when runs.
+ /// If you intend to use a custom door, this method enables you provide that prefab here. + ///
+ /// The containing the prefab. + /// The name of the prefab to register. + public void RegisterPrefab(AssetBundle assetBundle, string prefabName) + { + if (assetBundle == null) + { + throw new ArgumentException("Cannot be null", nameof(assetBundle)); + } + if (string.IsNullOrEmpty(prefabName)) + { + throw new ArgumentException("Cannot be null or empty", nameof(prefabName)); + } + prefabNames.Add(prefabName, assetBundle); + } + + private void GenerateHashes() + { + hashToName.Clear(); + + foreach (CustomRoom room in Rooms.Values) + { + int stableHashCode = room.Prefab.name.GetStableHashCode(); + if (hashToName.ContainsKey(stableHashCode)) + { + Logger.LogWarning($"Room {room.Name} is already registered with hash {stableHashCode}"); + } + else + { + hashToName.Add(stableHashCode, room.Name); + } + } + } + + private void OnZoneSystemSetupLocations() + { + // TODO - unsure if cache clearing is still necessary for resolving mocks of these assets + //ClearPrefabCache(typeof(Material)); + + if (envNames.Count > 0) + { + foreach (var kvp in envNames) + { + Logger.LogDebug($"Registering environment {kvp.Key}."); + + var env = kvp.Value.LoadAsset(kvp.Key); + env.FixReferences(true); + UnityEngine.Object.Instantiate(env); + } + } + + if (prefabNames.Count > 0) + { + foreach (var kvp in prefabNames) + { + Logger.LogDebug($"Registering prefab {kvp.Key}."); + + var env = kvp.Value.LoadAsset(kvp.Key); + env.FixReferences(true); + PrefabManager.Instance.AddPrefab(env); + } + } + } + + private void OnDungeonDBStarted() + { + InvokeOnVanillaRoomsAvailable(); + + if (Rooms.Count > 0) + { + hashToName.Clear(); + + List toDelete = new List(); + Logger.LogInfo(string.Format("Registering {0} custom rooms", Rooms.Count)); + foreach (CustomRoom customRoom in Rooms.Values) + { + try + { + Logger.LogDebug(string.Format("Adding custom room {0} with {1} theme", customRoom.Name, customRoom.Theme == 0 ? customRoom.ThemeName : customRoom.Theme.ToString())); + if (customRoom.FixReference) + { + customRoom.Prefab.FixReferences(true); + customRoom.FixReference = false; + } + + if (customRoom.Theme != 0) + { + RegisterRoomInDungeonDB(customRoom); + } + } + catch (MockResolveException ex) + { + Logger.LogWarning(string.Format("Skipping Room {0}: could not resolve mock {1} {2}", customRoom, ex.MockType.Name, ex.FailedMockName)); + toDelete.Add(customRoom.Name); + } + catch (Exception ex2) + { + Logger.LogWarning(string.Format("Exception caught while adding Room: {0}", ex2)); + toDelete.Add(customRoom.Name); + } + } + foreach (string name in toDelete) + { + Rooms.Remove(name); + } + + DungeonDB.instance.GenerateHashList(); + GenerateHashes(); + } + } + + private void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator self) + { + DungeonGeneratorTheme proxy = self?.gameObject.GetComponent(); + + if (DungeonGenerator.m_availableRooms != null) + { + if (proxy != null) + { + Logger.LogDebug($"This dungeon generator has a custom theme = {proxy.m_themeName}, adding available rooms"); + + DungeonGenerator.m_availableRooms.AddRange(Rooms.Values + .Where(r => r.Room.m_enabled) + .Where(r => r.ThemeName == proxy.m_themeName) + .Select(r => r.RoomData)); + } + else + { + Logger.LogDebug($"Adding additional rooms of type {self.m_themes} to available rooms"); + + DungeonGenerator.m_availableRooms.AddRange(Rooms.Values + .Where(r => r.Room.m_enabled) + .Where(r => self.m_themes.HasFlag(r.Theme)) + .Select(r => r.RoomData)); + } + + if (DungeonGenerator.m_availableRooms.Count <= 0) + { + Logger.LogDebug($"DungeonManager's SetupAvailableRooms yielded zero rooms."); + } + } + } + + + private void InvokeOnVanillaRoomsAvailable() + { + OnVanillaRoomsAvailable?.SafeInvoke(); + } + + private void RegisterRoomInDungeonDB(CustomRoom room) + { + DungeonDB.instance.m_rooms.Add(room.RoomData); + } + + /// + /// Attempt to get room by hash. + /// + /// + + private DungeonDB.RoomData OnDungeonDBGetRoom(int hash) + { + if (hashToName.TryGetValue(hash, out var roomName)) + { + CustomRoom room = Rooms[roomName]; + return room.RoomData; + } + return null; + } + } +} diff --git a/JotunnLib/Utils/DungeonGeneratorTheme.cs b/JotunnLib/Utils/DungeonGeneratorTheme.cs new file mode 100644 index 000000000..6cd967e85 --- /dev/null +++ b/JotunnLib/Utils/DungeonGeneratorTheme.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace Jotunn.Utils +{ + /// + /// Helper class for identifying the theme of custom rooms. + /// + public class DungeonGeneratorTheme : MonoBehaviour + { + /// + /// Name of a dungeon theme, used when matching generators with custom rooms. + /// + public string m_themeName = ""; + } +} From e28aeb7df33ac13de97a487d6f4528f05047ca22 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:13:21 -0700 Subject: [PATCH 14/36] derp - kory commit --- JotunnLib/Managers/DungeonManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 3fd69ba21..617b207bd 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -79,7 +79,7 @@ private static class Patches [HarmonyPatch(typeof(DungeonDB), nameof(DungeonDB.Start)), HarmonyPostfix] private static void OnDungeonDBStarted() => Instance.OnDungeonDBStarted(); - [HarmonyPatch(typeof(DungeonDB), nameof(DungeonDB.GetRoom)), HarmonyPostfix] + [HarmonyPatch(typeof(DungeonDB), nameof(DungeonDB.GetRoom)), HarmonyPrefix] private static bool OnDungeonDBGetRoom(int hash, ref DungeonDB.RoomData __result) { DungeonDB.RoomData result = Instance.OnDungeonDBGetRoom(hash); From 5991d7793bc68f46effaa47970290fd1f5e6f39f Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:15:52 -0700 Subject: [PATCH 15/36] Fix typo in summary --- JotunnLib/Configs/RoomConfig.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JotunnLib/Configs/RoomConfig.cs b/JotunnLib/Configs/RoomConfig.cs index adefb52e3..2f4e9c496 100644 --- a/JotunnLib/Configs/RoomConfig.cs +++ b/JotunnLib/Configs/RoomConfig.cs @@ -3,7 +3,7 @@ namespace Jotunn.Configs { /// - /// Configuration class for adding custom clutter.
+ /// Configuration class for adding custom rooms.
/// Use this in a constructor of ///
public class RoomConfig From 366b7ab3e91eaced3022366f83654e742578c06b Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:17:41 -0700 Subject: [PATCH 16/36] Remove MusicPrefab from RoomConfig and CustomRoom --- JotunnLib/Configs/RoomConfig.cs | 5 ----- JotunnLib/Entities/CustomRoom.cs | 1 - 2 files changed, 6 deletions(-) diff --git a/JotunnLib/Configs/RoomConfig.cs b/JotunnLib/Configs/RoomConfig.cs index 2f4e9c496..6d5feb105 100644 --- a/JotunnLib/Configs/RoomConfig.cs +++ b/JotunnLib/Configs/RoomConfig.cs @@ -64,11 +64,6 @@ public class RoomConfig ///
public bool? Perimeter { get; set; } - /// - /// Background music to play when a player gets in range of this room. - /// - public MusicVolume MusicPrefab { get; set; } - /// /// Create a config with a . /// diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs index 9c786f774..2bc8c424a 100644 --- a/JotunnLib/Entities/CustomRoom.cs +++ b/JotunnLib/Entities/CustomRoom.cs @@ -142,7 +142,6 @@ private void ApplyConfig(RoomConfig roomConfig) if (roomConfig.Weight != null) Room.m_weight = roomConfig.Weight.Value; if (roomConfig.FaceCenter != null) Room.m_faceCenter = roomConfig.FaceCenter.Value; if (roomConfig.Perimeter != null) Room.m_perimeter = roomConfig.Perimeter.Value; - if (roomConfig.MusicPrefab != null) Room.m_musicPrefab = roomConfig.MusicPrefab; // Room can be matched by either a Room.Theme flag, or a ThemeName string. if (roomConfig.Theme == 0) From 5fb11c61edd45d61c090db6a73e9967e53e0c3f0 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:18:58 -0700 Subject: [PATCH 17/36] Remove constructor that is missing fixReference --- JotunnLib/Entities/CustomRoom.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs index 2bc8c424a..a8474bac0 100644 --- a/JotunnLib/Entities/CustomRoom.cs +++ b/JotunnLib/Entities/CustomRoom.cs @@ -52,17 +52,6 @@ public class CustomRoom : CustomEntity ///
public DungeonDB.RoomData RoomData { get; private set; } - - /// - /// Custom room from a prefab loaded from an with a made from a .
- /// Can fix references for s. - ///
- /// A preloaded - /// Name of the prefab in the bundle. - /// The config for this custom room. - public CustomRoom(AssetBundle assetBundle, string assetName, RoomConfig roomConfig) - : this(assetBundle, assetName, false, roomConfig) { } - /// /// Custom room from a prefab loaded from an with a made from a .
/// Can fix references for s. From d218a4db11c0522c22ad899e2ead3ec4e5c855f4 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:24:12 -0700 Subject: [PATCH 18/36] Move ApplyConfig method to RoomConfig class and refactor CustomRoom constructor functions to use new RoomConfig.ApplyConfig method --- JotunnLib/Configs/RoomConfig.cs | 39 ++++++++++++++++++- JotunnLib/Entities/CustomRoom.cs | 66 +++++++++++++------------------- 2 files changed, 64 insertions(+), 41 deletions(-) diff --git a/JotunnLib/Configs/RoomConfig.cs b/JotunnLib/Configs/RoomConfig.cs index 6d5feb105..518c7d56c 100644 --- a/JotunnLib/Configs/RoomConfig.cs +++ b/JotunnLib/Configs/RoomConfig.cs @@ -11,12 +11,12 @@ public class RoomConfig /// /// Theme name of this room. /// - public string ThemeName { get; } + public string ThemeName { get; set; } /// /// of this room. /// - public Room.Theme Theme { get; } + public Room.Theme Theme { get; set; } /// /// If set to false, room will not be added to , thus @@ -83,5 +83,40 @@ public RoomConfig(string themeName) Theme = 0; ThemeName = themeName; } + + + /// + /// Converts the RoomConfig to a Valheim style . + /// + public Room ApplyConfig(RoomConfig roomConfig) + { + // Create a new Room instance + Room room = new Room(); + + // Ensure Room values are overwritten only when a value's present. + if (roomConfig.Enabled != null) room.m_enabled = roomConfig.Enabled.Value; + if (roomConfig.Entrance != null) room.m_entrance = roomConfig.Entrance.Value; + if (roomConfig.Endcap != null) room.m_endCap = roomConfig.Endcap.Value; + if (roomConfig.Divider != null) room.m_divider = roomConfig.Divider.Value; + if (roomConfig.EndcapPrio != null) room.m_endCapPrio = roomConfig.EndcapPrio.Value; + if (roomConfig.MinPlaceOrder != null) room.m_minPlaceOrder = roomConfig.MinPlaceOrder.Value; + if (roomConfig.Weight != null) room.m_weight = roomConfig.Weight.Value; + if (roomConfig.FaceCenter != null) room.m_faceCenter = roomConfig.FaceCenter.Value; + if (roomConfig.Perimeter != null) room.m_perimeter = roomConfig.Perimeter.Value; + + // Room can be matched by either a Room.Theme flag, or a ThemeName string. + if (roomConfig.Theme == 0) + { + ThemeName = roomConfig.ThemeName; + Theme = 0; + } + else + { + Theme = roomConfig.Theme; + ThemeName = string.Empty; + } + + return room; + } } } diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs index a8474bac0..cf5a47794 100644 --- a/JotunnLib/Entities/CustomRoom.cs +++ b/JotunnLib/Entities/CustomRoom.cs @@ -64,6 +64,8 @@ public CustomRoom(AssetBundle assetBundle, string assetName, bool fixReference, { Prefab = assetBundle.LoadAsset(assetName); Name = Prefab.name; + Room = roomConfig.ApplyConfig(roomConfig); + if (Prefab != null && Prefab.TryGetComponent(out var room)) { Room = room; @@ -73,7 +75,18 @@ public CustomRoom(AssetBundle assetBundle, string assetName, bool fixReference, Room = Prefab.AddComponent(); } FixReference = fixReference; - ApplyConfig(roomConfig); + + // DungeonGenerator.PlaceRoom*() utilize soft references directly, thus registering the assets here. + RoomData = new DungeonDB.RoomData() + { + m_prefab = new SoftReference(AssetManager.Instance.AddAsset(Prefab)), + m_loadedRoom = Room, + m_prefabData = new RoomPrefabData() + { + m_enabled = Room.m_enabled, + m_theme = Theme + } + }; } @@ -97,6 +110,8 @@ public CustomRoom(GameObject prefab, bool fixReference, RoomConfig roomConfig) : { Prefab = prefab; Name = prefab.name; + Room = roomConfig.ApplyConfig(roomConfig); + if (prefab != null && prefab.TryGetComponent(out var room)) { Room = room; @@ -106,44 +121,7 @@ public CustomRoom(GameObject prefab, bool fixReference, RoomConfig roomConfig) : Room = prefab.AddComponent(); } FixReference = fixReference; - ApplyConfig(roomConfig); - } - - /// - /// Helper method to determine if a prefab with a given name is a custom room created with Jötunn. - /// - /// Name of the prefab to test. - /// true if the prefab is added as a custom item to the . - public static bool IsCustomRoom(string prefabName) - { - return DungeonManager.Instance.Rooms.ContainsKey(prefabName); - } - - private void ApplyConfig(RoomConfig roomConfig) - { - // Ensure Room values are overwritten only when a value's present. - if (roomConfig.Enabled != null) Room.m_enabled = roomConfig.Enabled.Value; - if (roomConfig.Entrance != null) Room.m_entrance = roomConfig.Entrance.Value; - if (roomConfig.Endcap != null) Room.m_endCap = roomConfig.Endcap.Value; - if (roomConfig.Divider != null) Room.m_divider = roomConfig.Divider.Value; - if (roomConfig.EndcapPrio != null) Room.m_endCapPrio = roomConfig.EndcapPrio.Value; - if (roomConfig.MinPlaceOrder != null) Room.m_minPlaceOrder = roomConfig.MinPlaceOrder.Value; - if (roomConfig.Weight != null) Room.m_weight = roomConfig.Weight.Value; - if (roomConfig.FaceCenter != null) Room.m_faceCenter = roomConfig.FaceCenter.Value; - if (roomConfig.Perimeter != null) Room.m_perimeter = roomConfig.Perimeter.Value; - - // Room can be matched by either a Room.Theme flag, or a ThemeName string. - if (roomConfig.Theme == 0) - { - ThemeName = roomConfig.ThemeName; - Theme = 0; - } - else - { - Theme = roomConfig.Theme; - ThemeName = string.Empty; - } - + // DungeonGenerator.PlaceRoom*() utilize soft references directly, thus registering the assets here. RoomData = new DungeonDB.RoomData() { @@ -156,5 +134,15 @@ private void ApplyConfig(RoomConfig roomConfig) } }; } + + /// + /// Helper method to determine if a prefab with a given name is a custom room created with Jötunn. + /// + /// Name of the prefab to test. + /// true if the prefab is added as a custom item to the . + public static bool IsCustomRoom(string prefabName) + { + return DungeonManager.Instance.Rooms.ContainsKey(prefabName); + } } } From 9338dc963c4127a7e81e3f7f8bdfc267c6ffe323 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:26:46 -0700 Subject: [PATCH 19/36] Refactor DungeonManager prefab loading and instantiation --- JotunnLib/Managers/DungeonManager.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 617b207bd..e3e4363f4 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -38,7 +38,7 @@ public class DungeonManager : IManager private readonly Dictionary hashToName = new Dictionary(); private readonly List themeList = new List(); private readonly Dictionary prefabNames = new Dictionary(); - private readonly Dictionary envNames = new Dictionary(); + private readonly Dictionary loadedEnvironments = new Dictionary(); /// /// Container for Jötunn's DungeonRooms in the DontDestroyOnLoad scene. @@ -209,7 +209,8 @@ public void RegisterEnvironment(AssetBundle assetBundle, string prefabName) { throw new ArgumentException("Cannot be null or empty", nameof(prefabName)); } - envNames.Add(prefabName, assetBundle); + var env = assetBundle.LoadAsset(prefabName); + loadedEnvironments.Add(prefabName, env); } /// @@ -254,15 +255,15 @@ private void OnZoneSystemSetupLocations() // TODO - unsure if cache clearing is still necessary for resolving mocks of these assets //ClearPrefabCache(typeof(Material)); - if (envNames.Count > 0) + if (loadedEnvironments.Count > 0) { - foreach (var kvp in envNames) + foreach (var kvp in loadedEnvironments) { Logger.LogDebug($"Registering environment {kvp.Key}."); - var env = kvp.Value.LoadAsset(kvp.Key); + var env = kvp.Value; env.FixReferences(true); - UnityEngine.Object.Instantiate(env); + UnityEngine.Object.Instantiate(env, DungeonRoomContainer.transform); } } From 611bdfd2bb0fe75b69950e0b8df0c224834ba0f3 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:28:53 -0700 Subject: [PATCH 20/36] Add OnRoomsRegistered event, invoke in InvokeOnVanillaRoomsAvailable method --- JotunnLib/Managers/DungeonManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index e3e4363f4..457e88c6e 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -29,6 +29,8 @@ public class DungeonManager : IManager /// If you want to execute just once you will need to unregister from the event after execution. /// public static event Action OnVanillaRoomsAvailable; + + public static event Action OnRoomsRegistered; /// /// Internal dictionary of all custom rooms @@ -363,6 +365,7 @@ private void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator self) private void InvokeOnVanillaRoomsAvailable() { OnVanillaRoomsAvailable?.SafeInvoke(); + OnRoomsRegistered?.SafeInvoke(); } private void RegisterRoomInDungeonDB(CustomRoom room) From f515abe679c8ca82112bb2ff4c435246aca2ed8d Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:30:10 -0700 Subject: [PATCH 21/36] Remove RegisterPrefab method. Devs should use PrefabManager.Instance.AddPrefab instead --- JotunnLib/Managers/DungeonManager.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 457e88c6e..f244c7c02 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -215,25 +215,6 @@ public void RegisterEnvironment(AssetBundle assetBundle, string prefabName) loadedEnvironments.Add(prefabName, env); } - /// - /// Adds a new prefab to be registered when runs.
- /// If you intend to use a custom door, this method enables you provide that prefab here. - ///
- /// The containing the prefab. - /// The name of the prefab to register. - public void RegisterPrefab(AssetBundle assetBundle, string prefabName) - { - if (assetBundle == null) - { - throw new ArgumentException("Cannot be null", nameof(assetBundle)); - } - if (string.IsNullOrEmpty(prefabName)) - { - throw new ArgumentException("Cannot be null or empty", nameof(prefabName)); - } - prefabNames.Add(prefabName, assetBundle); - } - private void GenerateHashes() { hashToName.Clear(); From 7c88287485744eb216693d087402bc1139bde7d6 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 12:24:14 -0700 Subject: [PATCH 22/36] Add InvokeOnRoomsRegistered method. Invoke as the last statement in OnDungeonDBStarted. --- JotunnLib/Managers/DungeonManager.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index f244c7c02..63919c79e 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -307,6 +307,7 @@ private void OnDungeonDBStarted() DungeonDB.instance.GenerateHashList(); GenerateHashes(); + InvokeOnRoomsRegistered(); } } @@ -344,6 +345,11 @@ private void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator self) private void InvokeOnVanillaRoomsAvailable() + { + OnVanillaRoomsAvailable?.SafeInvoke(); + } + + private void InvokeOnRoomsRegistered() { OnVanillaRoomsAvailable?.SafeInvoke(); OnRoomsRegistered?.SafeInvoke(); From 2d3bb465b3a467152e8f9e8d137fbed2cedb4d1c Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 12:38:20 -0700 Subject: [PATCH 23/36] Add null check for room retrieval in OnDungeonDBGetRoom method --- JotunnLib/Managers/DungeonManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 63919c79e..10acf7d90 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -367,9 +367,8 @@ private void RegisterRoomInDungeonDB(CustomRoom room) private DungeonDB.RoomData OnDungeonDBGetRoom(int hash) { - if (hashToName.TryGetValue(hash, out var roomName)) + if (hashToName.TryGetValue(hash, out var roomName) && Rooms.TryGetValue(roomName, out var room)) { - CustomRoom room = Rooms[roomName]; return room.RoomData; } return null; From 19fad19f47d473bfc5f4e86696359412a77e02b3 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 12:40:30 -0700 Subject: [PATCH 24/36] Removing obsolete code related to adding prefabs --- JotunnLib/Managers/DungeonManager.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 10acf7d90..0b7c4f491 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -39,7 +39,6 @@ public class DungeonManager : IManager private readonly Dictionary hashToName = new Dictionary(); private readonly List themeList = new List(); - private readonly Dictionary prefabNames = new Dictionary(); private readonly Dictionary loadedEnvironments = new Dictionary(); /// @@ -249,18 +248,6 @@ private void OnZoneSystemSetupLocations() UnityEngine.Object.Instantiate(env, DungeonRoomContainer.transform); } } - - if (prefabNames.Count > 0) - { - foreach (var kvp in prefabNames) - { - Logger.LogDebug($"Registering prefab {kvp.Key}."); - - var env = kvp.Value.LoadAsset(kvp.Key); - env.FixReferences(true); - PrefabManager.Instance.AddPrefab(env); - } - } } private void OnDungeonDBStarted() From 98905482002e29a1e4d24363206a1298f9ffeeec Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 12:42:21 -0700 Subject: [PATCH 25/36] Add doc string to OnRoomsRegistered --- JotunnLib/Managers/DungeonManager.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 0b7c4f491..216fd535c 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -30,6 +30,11 @@ public class DungeonManager : IManager /// public static event Action OnVanillaRoomsAvailable; + /// + /// Event that gets fired when the vanilla registers rooms. Your code will execute + /// every time a main scene is started (on joining a game).
+ /// If you want to execute just once you will need to unregister from the event after execution. + ///
public static event Action OnRoomsRegistered; /// From 5084fd2a92b2de5a89d7cc25436781cc7e8ea6b8 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 13:28:10 -0700 Subject: [PATCH 26/36] Remove Room.Theme Theme. Mirror GetInternalName approach as used in Piececonfig.cs --- JotunnLib/Entities/CustomRoom.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs index cf5a47794..ee3b8c7d0 100644 --- a/JotunnLib/Entities/CustomRoom.cs +++ b/JotunnLib/Entities/CustomRoom.cs @@ -40,17 +40,18 @@ public class CustomRoom : CustomEntity /// /// Theme name of this room. /// - public string ThemeName { get; private set; } - - /// - /// of this room. - /// - public Room.Theme Theme { get; private set; } + public string ThemeName + { + get => themeName; + set => themeName = CraftingStations.GetInternalName(value); + } /// /// Associated holding data used during generation. /// public DungeonDB.RoomData RoomData { get; private set; } + + private string themeName = string.Empty; /// /// Custom room from a prefab loaded from an with a made from a .
From 0bc84b4710439a19153ae4cfbc3ceaed9f577f86 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 13:31:24 -0700 Subject: [PATCH 27/36] Remove OnVanillaRoomsAvailable from InvokeRoomsRegistered --- JotunnLib/Managers/DungeonManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 216fd535c..3f8de21a4 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -343,7 +343,6 @@ private void InvokeOnVanillaRoomsAvailable() private void InvokeOnRoomsRegistered() { - OnVanillaRoomsAvailable?.SafeInvoke(); OnRoomsRegistered?.SafeInvoke(); } From 6f261f6c49bbed7783ded25753357dde67a45de8 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:50:57 -0700 Subject: [PATCH 28/36] Refactor ThemeName and associated methods. ThemeName set constructor will parse a custom Theme value to string or attempt to parse vanilla Theme value to string --- JotunnLib/Entities/CustomRoom.cs | 40 +++++++++++++++++++++++++--- JotunnLib/Managers/DungeonManager.cs | 8 +++--- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs index ee3b8c7d0..bf6fc6c07 100644 --- a/JotunnLib/Entities/CustomRoom.cs +++ b/JotunnLib/Entities/CustomRoom.cs @@ -42,8 +42,27 @@ public class CustomRoom : CustomEntity ///
public string ThemeName { - get => themeName; - set => themeName = CraftingStations.GetInternalName(value); + get => themeName; + set + { + if (string.IsNullOrEmpty(value)) + { + themeName = Room.Theme.None.ToString(); + _theme = Room.Theme.None; + return; + } + + if (Enum.TryParse(value, true, out var result)) + { + themeName = result.ToString(); + _theme = result; + } + else + { + themeName = value; + _theme = Room.Theme.None; + } + } } /// @@ -52,6 +71,7 @@ public string ThemeName public DungeonDB.RoomData RoomData { get; private set; } private string themeName = string.Empty; + private Room.Theme _theme = Room.Theme.None; /// /// Custom room from a prefab loaded from an with a made from a .
@@ -131,7 +151,7 @@ public CustomRoom(GameObject prefab, bool fixReference, RoomConfig roomConfig) : m_prefabData = new RoomPrefabData() { m_enabled = Room.m_enabled, - m_theme = Theme + m_theme = Room.Theme } }; } @@ -145,5 +165,19 @@ public static bool IsCustomRoom(string prefabName) { return DungeonManager.Instance.Rooms.ContainsKey(prefabName); } + + public Room.Theme GetVanillaRoomTheme(string roomTheme) + { + if (Enum.TryParse(roomTheme, false, out Room.Theme theme)) + { + return theme; + } + return Room.Theme.None; + } + + private bool IsVanillaRoom(string roomTheme) + { + return roomTheme == "None" || _theme == Room.Theme.None; + } } } diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 3f8de21a4..91c23caf8 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -269,14 +269,14 @@ private void OnDungeonDBStarted() { try { - Logger.LogDebug(string.Format("Adding custom room {0} with {1} theme", customRoom.Name, customRoom.Theme == 0 ? customRoom.ThemeName : customRoom.Theme.ToString())); + Logger.LogDebug(string.Format("Adding custom room {0} with {1} theme", customRoom.Name, customRoom.ThemeName)); if (customRoom.FixReference) { customRoom.Prefab.FixReferences(true); customRoom.FixReference = false; } - if (customRoom.Theme != 0) + if (customRoom.ThemeName != "None") { RegisterRoomInDungeonDB(customRoom); } @@ -321,10 +321,10 @@ private void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator self) else { Logger.LogDebug($"Adding additional rooms of type {self.m_themes} to available rooms"); - + DungeonGenerator.m_availableRooms.AddRange(Rooms.Values .Where(r => r.Room.m_enabled) - .Where(r => self.m_themes.HasFlag(r.Theme)) + .Where(r => self.m_themes.HasFlag(r.GetVanillaRoomTheme(r.ThemeName))) .Select(r => r.RoomData)); } From 0f39537c288eeba355bb1cf1916a013a8fa160de Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 16:33:40 -0700 Subject: [PATCH 29/36] Remove RoomPrefabData, sub-class was removed in valheimAssembly v0.217. Add method GetCustomRoomTheme to retrieve and return a new Room Theme, which was added to list of Room Themes. --- JotunnLib/Entities/CustomRoom.cs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs index bf6fc6c07..60b79ae5f 100644 --- a/JotunnLib/Entities/CustomRoom.cs +++ b/JotunnLib/Entities/CustomRoom.cs @@ -102,11 +102,8 @@ public CustomRoom(AssetBundle assetBundle, string assetName, bool fixReference, { m_prefab = new SoftReference(AssetManager.Instance.AddAsset(Prefab)), m_loadedRoom = Room, - m_prefabData = new RoomPrefabData() - { - m_enabled = Room.m_enabled, - m_theme = Theme - } + m_enabled = Room.m_enabled, + m_theme = GetCustomRoomTheme(roomConfig.ThemeName) }; } @@ -148,11 +145,8 @@ public CustomRoom(GameObject prefab, bool fixReference, RoomConfig roomConfig) : { m_prefab = new SoftReference(AssetManager.Instance.AddAsset(Prefab)), m_loadedRoom = Room, - m_prefabData = new RoomPrefabData() - { - m_enabled = Room.m_enabled, - m_theme = Room.Theme - } + m_enabled = Room.m_enabled, + m_theme = GetCustomRoomTheme(roomConfig.ThemeName) }; } @@ -170,8 +164,21 @@ public Room.Theme GetVanillaRoomTheme(string roomTheme) { if (Enum.TryParse(roomTheme, false, out Room.Theme theme)) { + Logger.LogDebug($"Found vanilla Room Theme with name {roomTheme}"); + return theme; + } + Logger.LogError($"Failed to find vanilla Room Theme with name {roomTheme}"); + return Room.Theme.None; + } + + public Room.Theme GetCustomRoomTheme(string roomTheme) + { + if (Enum.TryParse(roomTheme, false, out Room.Theme theme)) + { + Logger.LogDebug($"Found custom Room Theme with name {roomTheme}"); return theme; } + Logger.LogError($"Failed to find custom Room Theme with name {roomTheme}"); return Room.Theme.None; } From 52951f2f7596192d9c75616ff7880e921f0669bd Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 16:34:19 -0700 Subject: [PATCH 30/36] Remove IsVanillaRoom function, not used --- JotunnLib/Entities/CustomRoom.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs index 60b79ae5f..cc586e92d 100644 --- a/JotunnLib/Entities/CustomRoom.cs +++ b/JotunnLib/Entities/CustomRoom.cs @@ -182,9 +182,5 @@ public Room.Theme GetCustomRoomTheme(string roomTheme) return Room.Theme.None; } - private bool IsVanillaRoom(string roomTheme) - { - return roomTheme == "None" || _theme == Room.Theme.None; - } } } From 7d618e683c07926be78df614455142129dd05b72 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 20:12:58 -0700 Subject: [PATCH 31/36] Add constructor for RoomConfig class --- JotunnLib/Configs/RoomConfig.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/JotunnLib/Configs/RoomConfig.cs b/JotunnLib/Configs/RoomConfig.cs index 518c7d56c..b8a8f0e5e 100644 --- a/JotunnLib/Configs/RoomConfig.cs +++ b/JotunnLib/Configs/RoomConfig.cs @@ -84,6 +84,11 @@ public RoomConfig(string themeName) ThemeName = themeName; } + /// + /// Create a new + /// + public RoomConfig() { } + /// /// Converts the RoomConfig to a Valheim style . From 10b3bc28a603b71cf5ce93cc9acb46408336ab89 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Thu, 18 Jul 2024 20:45:04 -0700 Subject: [PATCH 32/36] Remove Room.Theme Theme from RoomConfig. Dev must use ThemeName instead. Add IsCustomTheme flag. Combine GetCustomRoomTheme and GetVanillaRoomTheme functions. --- JotunnLib/Configs/RoomConfig.cs | 29 +++++++++++++++++----------- JotunnLib/Entities/CustomRoom.cs | 21 +++++--------------- JotunnLib/Managers/DungeonManager.cs | 2 +- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/JotunnLib/Configs/RoomConfig.cs b/JotunnLib/Configs/RoomConfig.cs index b8a8f0e5e..f811b1a67 100644 --- a/JotunnLib/Configs/RoomConfig.cs +++ b/JotunnLib/Configs/RoomConfig.cs @@ -1,3 +1,4 @@ +using System; using Jotunn.Entities; namespace Jotunn.Configs @@ -12,11 +13,11 @@ public class RoomConfig /// Theme name of this room. /// public string ThemeName { get; set; } - + /// - /// of this room. + /// Flag indicated if this room uses a custom theme /// - public Room.Theme Theme { get; set; } + public bool IsCustomTheme { get; set; } /// /// If set to false, room will not be added to , thus @@ -70,7 +71,6 @@ public class RoomConfig /// public RoomConfig(Room.Theme theme) { - Theme = theme; ThemeName = string.Empty; } @@ -80,7 +80,6 @@ public RoomConfig(Room.Theme theme) /// public RoomConfig(string themeName) { - Theme = 0; ThemeName = themeName; } @@ -109,19 +108,27 @@ public Room ApplyConfig(RoomConfig roomConfig) if (roomConfig.FaceCenter != null) room.m_faceCenter = roomConfig.FaceCenter.Value; if (roomConfig.Perimeter != null) room.m_perimeter = roomConfig.Perimeter.Value; - // Room can be matched by either a Room.Theme flag, or a ThemeName string. - if (roomConfig.Theme == 0) + if (roomConfig.IsCustomTheme) { - ThemeName = roomConfig.ThemeName; - Theme = 0; + if (roomConfig.ThemeName != null) room.m_theme = GetRoomTheme(roomConfig.ThemeName); } else { - Theme = roomConfig.Theme; - ThemeName = string.Empty; + if (roomConfig.ThemeName != null) room.m_theme = GetRoomTheme(roomConfig.ThemeName); } return room; } + + public Room.Theme GetRoomTheme(string roomTheme) + { + if (Enum.TryParse(roomTheme, false, out Room.Theme theme)) + { + Logger.LogDebug($"Found Room Theme with name {roomTheme}"); + return theme; + } + Logger.LogError($"Failed to find Room Theme with name {roomTheme}"); + return Room.Theme.None; + } } } diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs index cc586e92d..57931b9f0 100644 --- a/JotunnLib/Entities/CustomRoom.cs +++ b/JotunnLib/Entities/CustomRoom.cs @@ -103,7 +103,7 @@ public CustomRoom(AssetBundle assetBundle, string assetName, bool fixReference, m_prefab = new SoftReference(AssetManager.Instance.AddAsset(Prefab)), m_loadedRoom = Room, m_enabled = Room.m_enabled, - m_theme = GetCustomRoomTheme(roomConfig.ThemeName) + m_theme = GetRoomTheme(roomConfig.ThemeName) }; } @@ -146,7 +146,7 @@ public CustomRoom(GameObject prefab, bool fixReference, RoomConfig roomConfig) : m_prefab = new SoftReference(AssetManager.Instance.AddAsset(Prefab)), m_loadedRoom = Room, m_enabled = Room.m_enabled, - m_theme = GetCustomRoomTheme(roomConfig.ThemeName) + m_theme = GetRoomTheme(roomConfig.ThemeName) }; } @@ -160,25 +160,14 @@ public static bool IsCustomRoom(string prefabName) return DungeonManager.Instance.Rooms.ContainsKey(prefabName); } - public Room.Theme GetVanillaRoomTheme(string roomTheme) + public Room.Theme GetRoomTheme(string roomTheme) { if (Enum.TryParse(roomTheme, false, out Room.Theme theme)) { - Logger.LogDebug($"Found vanilla Room Theme with name {roomTheme}"); + Logger.LogDebug($"Found Room Theme with name {roomTheme}"); return theme; } - Logger.LogError($"Failed to find vanilla Room Theme with name {roomTheme}"); - return Room.Theme.None; - } - - public Room.Theme GetCustomRoomTheme(string roomTheme) - { - if (Enum.TryParse(roomTheme, false, out Room.Theme theme)) - { - Logger.LogDebug($"Found custom Room Theme with name {roomTheme}"); - return theme; - } - Logger.LogError($"Failed to find custom Room Theme with name {roomTheme}"); + Logger.LogError($"Failed to find Room Theme with name {roomTheme}"); return Room.Theme.None; } diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 91c23caf8..48eead4b3 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -324,7 +324,7 @@ private void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator self) DungeonGenerator.m_availableRooms.AddRange(Rooms.Values .Where(r => r.Room.m_enabled) - .Where(r => self.m_themes.HasFlag(r.GetVanillaRoomTheme(r.ThemeName))) + .Where(r => self.m_themes.HasFlag(r.GetRoomTheme(r.ThemeName))) .Select(r => r.RoomData)); } From b2faaa2c34d65ce4d9fdb5a9f0b13043f8c1a7ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Fri, 19 Jul 2024 08:36:27 +0200 Subject: [PATCH 33/36] docs: improved OnRoomsRegistered --- JotunnLib/Managers/DungeonManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 48eead4b3..b32e3f183 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -31,7 +31,7 @@ public class DungeonManager : IManager public static event Action OnVanillaRoomsAvailable; /// - /// Event that gets fired when the vanilla registers rooms. Your code will execute + /// Event that gets fired after all custom rooms are registered to the . Your code will execute /// every time a main scene is started (on joining a game).
/// If you want to execute just once you will need to unregister from the event after execution. ///
From c0d348fe603c683fdee84a655caf4c6e5c795222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Schm=C3=B6cker?= Date: Fri, 19 Jul 2024 08:37:30 +0200 Subject: [PATCH 34/36] fix: always invoke OnRoomsRegistered, even if no rooms are added --- JotunnLib/Managers/DungeonManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index b32e3f183..48b070072 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -299,8 +299,9 @@ private void OnDungeonDBStarted() DungeonDB.instance.GenerateHashList(); GenerateHashes(); - InvokeOnRoomsRegistered(); } + + InvokeOnRoomsRegistered(); } private void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator self) From 4d4ae9abcaa5a8397fb7b45081e60a30e6162a88 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Sat, 20 Jul 2024 14:29:46 -0700 Subject: [PATCH 35/36] Add logging statements to OnDungeonGeneratorSetupAvailableRooms. --- JotunnLib/Managers/DungeonManager.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 48eead4b3..be7bd78a8 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -100,6 +100,7 @@ private static bool OnDungeonDBGetRoom(int hash, ref DungeonDB.RoomData __result [HarmonyPatch(typeof(DungeonGenerator), nameof(DungeonGenerator.SetupAvailableRooms)), HarmonyPostfix] private static void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator __instance) => Instance.OnDungeonGeneratorSetupAvailableRooms(__instance); + } /// @@ -311,15 +312,22 @@ private void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator self) { if (proxy != null) { + Logger.LogDebug($"Found DungeonGeneratorTheme component in prefab with name {self.gameObject}"); Logger.LogDebug($"This dungeon generator has a custom theme = {proxy.m_themeName}, adding available rooms"); DungeonGenerator.m_availableRooms.AddRange(Rooms.Values .Where(r => r.Room.m_enabled) .Where(r => r.ThemeName == proxy.m_themeName) .Select(r => r.RoomData)); + + foreach (var room in Rooms) + { + Logger.LogDebug($"Attempting to add Room with name {room.Value.Name} and theme {room.Value.ThemeName}"); + } } else { + Logger.LogDebug($"Failed to find DungeonGeneratorTheme component in prefab with name {self.gameObject}"); Logger.LogDebug($"Adding additional rooms of type {self.m_themes} to available rooms"); DungeonGenerator.m_availableRooms.AddRange(Rooms.Values @@ -335,7 +343,6 @@ private void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator self) } } - private void InvokeOnVanillaRoomsAvailable() { OnVanillaRoomsAvailable?.SafeInvoke(); From f554df8da973fd0fe059fc1eb0303001bc4965e9 Mon Sep 17 00:00:00 2001 From: jneb802 <73610029+jneb802@users.noreply.github.com> Date: Sat, 20 Jul 2024 14:39:42 -0700 Subject: [PATCH 36/36] Refactor of ThemeName and Room.Theme in CustomRoom, RoomConfig, and DungeonManager --- JotunnLib/Configs/RoomConfig.cs | 40 +++----------- JotunnLib/Entities/CustomRoom.cs | 78 +++++++++++++++------------- JotunnLib/Managers/DungeonManager.cs | 4 +- 3 files changed, 51 insertions(+), 71 deletions(-) diff --git a/JotunnLib/Configs/RoomConfig.cs b/JotunnLib/Configs/RoomConfig.cs index f811b1a67..437920657 100644 --- a/JotunnLib/Configs/RoomConfig.cs +++ b/JotunnLib/Configs/RoomConfig.cs @@ -1,5 +1,6 @@ using System; using Jotunn.Entities; +using UnityEngine; namespace Jotunn.Configs { @@ -13,11 +14,11 @@ public class RoomConfig /// Theme name of this room. /// public string ThemeName { get; set; } - + /// - /// Flag indicated if this room uses a custom theme + /// of this room. /// - public bool IsCustomTheme { get; set; } + public Room.Theme Theme { get; set; } /// /// If set to false, room will not be added to , thus @@ -71,6 +72,7 @@ public class RoomConfig /// public RoomConfig(Room.Theme theme) { + Theme = theme; ThemeName = string.Empty; } @@ -80,6 +82,7 @@ public RoomConfig(Room.Theme theme) /// public RoomConfig(string themeName) { + Theme = 0; ThemeName = themeName; } @@ -89,37 +92,6 @@ public RoomConfig(string themeName) public RoomConfig() { } - /// - /// Converts the RoomConfig to a Valheim style . - /// - public Room ApplyConfig(RoomConfig roomConfig) - { - // Create a new Room instance - Room room = new Room(); - - // Ensure Room values are overwritten only when a value's present. - if (roomConfig.Enabled != null) room.m_enabled = roomConfig.Enabled.Value; - if (roomConfig.Entrance != null) room.m_entrance = roomConfig.Entrance.Value; - if (roomConfig.Endcap != null) room.m_endCap = roomConfig.Endcap.Value; - if (roomConfig.Divider != null) room.m_divider = roomConfig.Divider.Value; - if (roomConfig.EndcapPrio != null) room.m_endCapPrio = roomConfig.EndcapPrio.Value; - if (roomConfig.MinPlaceOrder != null) room.m_minPlaceOrder = roomConfig.MinPlaceOrder.Value; - if (roomConfig.Weight != null) room.m_weight = roomConfig.Weight.Value; - if (roomConfig.FaceCenter != null) room.m_faceCenter = roomConfig.FaceCenter.Value; - if (roomConfig.Perimeter != null) room.m_perimeter = roomConfig.Perimeter.Value; - - if (roomConfig.IsCustomTheme) - { - if (roomConfig.ThemeName != null) room.m_theme = GetRoomTheme(roomConfig.ThemeName); - } - else - { - if (roomConfig.ThemeName != null) room.m_theme = GetRoomTheme(roomConfig.ThemeName); - } - - return room; - } - public Room.Theme GetRoomTheme(string roomTheme) { if (Enum.TryParse(roomTheme, false, out Room.Theme theme)) diff --git a/JotunnLib/Entities/CustomRoom.cs b/JotunnLib/Entities/CustomRoom.cs index 57931b9f0..631a208d1 100644 --- a/JotunnLib/Entities/CustomRoom.cs +++ b/JotunnLib/Entities/CustomRoom.cs @@ -40,38 +40,17 @@ public class CustomRoom : CustomEntity /// /// Theme name of this room. /// - public string ThemeName - { - get => themeName; - set - { - if (string.IsNullOrEmpty(value)) - { - themeName = Room.Theme.None.ToString(); - _theme = Room.Theme.None; - return; - } - - if (Enum.TryParse(value, true, out var result)) - { - themeName = result.ToString(); - _theme = result; - } - else - { - themeName = value; - _theme = Room.Theme.None; - } - } - } + public string ThemeName { get; set; } + + /// + /// of this room. + /// + public Room.Theme Theme { get; set; } /// /// Associated holding data used during generation. /// public DungeonDB.RoomData RoomData { get; private set; } - - private string themeName = string.Empty; - private Room.Theme _theme = Room.Theme.None; /// /// Custom room from a prefab loaded from an with a made from a .
@@ -85,16 +64,21 @@ public CustomRoom(AssetBundle assetBundle, string assetName, bool fixReference, { Prefab = assetBundle.LoadAsset(assetName); Name = Prefab.name; - Room = roomConfig.ApplyConfig(roomConfig); + + ThemeName = roomConfig.ThemeName; + Theme = roomConfig.Theme; if (Prefab != null && Prefab.TryGetComponent(out var room)) { - Room = room; + var existingRoom = room; + Room = ApplyConfig(roomConfig, existingRoom); } else { - Room = Prefab.AddComponent(); + var newRoom = Prefab.AddComponent(); + Room = ApplyConfig(roomConfig, newRoom); } + FixReference = fixReference; // DungeonGenerator.PlaceRoom*() utilize soft references directly, thus registering the assets here. @@ -103,7 +87,7 @@ public CustomRoom(AssetBundle assetBundle, string assetName, bool fixReference, m_prefab = new SoftReference(AssetManager.Instance.AddAsset(Prefab)), m_loadedRoom = Room, m_enabled = Room.m_enabled, - m_theme = GetRoomTheme(roomConfig.ThemeName) + m_theme = roomConfig.Theme }; } @@ -128,16 +112,21 @@ public CustomRoom(GameObject prefab, bool fixReference, RoomConfig roomConfig) : { Prefab = prefab; Name = prefab.name; - Room = roomConfig.ApplyConfig(roomConfig); + + ThemeName = roomConfig.ThemeName; + Theme = roomConfig.Theme; if (prefab != null && prefab.TryGetComponent(out var room)) { - Room = room; + var existingRoom = room; + Room = ApplyConfig(roomConfig, existingRoom); } else { - Room = prefab.AddComponent(); + var newRoom = prefab.AddComponent(); + Room = ApplyConfig(roomConfig, newRoom); } + FixReference = fixReference; // DungeonGenerator.PlaceRoom*() utilize soft references directly, thus registering the assets here. @@ -146,9 +135,28 @@ public CustomRoom(GameObject prefab, bool fixReference, RoomConfig roomConfig) : m_prefab = new SoftReference(AssetManager.Instance.AddAsset(Prefab)), m_loadedRoom = Room, m_enabled = Room.m_enabled, - m_theme = GetRoomTheme(roomConfig.ThemeName) + m_theme = roomConfig.Theme }; } + + /// + /// Converts the RoomConfig to a Valheim style . + /// + public Room ApplyConfig(RoomConfig roomConfig, Room room) + { + // Ensure Room values are overwritten only when a value's present. + if (roomConfig.Enabled != null) room.m_enabled = roomConfig.Enabled.Value; + if (roomConfig.Entrance != null) room.m_entrance = roomConfig.Entrance.Value; + if (roomConfig.Endcap != null) room.m_endCap = roomConfig.Endcap.Value; + if (roomConfig.Divider != null) room.m_divider = roomConfig.Divider.Value; + if (roomConfig.EndcapPrio != null) room.m_endCapPrio = roomConfig.EndcapPrio.Value; + if (roomConfig.MinPlaceOrder != null) room.m_minPlaceOrder = roomConfig.MinPlaceOrder.Value; + if (roomConfig.Weight != null) room.m_weight = roomConfig.Weight.Value; + if (roomConfig.FaceCenter != null) room.m_faceCenter = roomConfig.FaceCenter.Value; + if (roomConfig.Perimeter != null) room.m_perimeter = roomConfig.Perimeter.Value; + + return room; + } /// /// Helper method to determine if a prefab with a given name is a custom room created with Jötunn. diff --git a/JotunnLib/Managers/DungeonManager.cs b/JotunnLib/Managers/DungeonManager.cs index 34b9b3d2b..324035810 100644 --- a/JotunnLib/Managers/DungeonManager.cs +++ b/JotunnLib/Managers/DungeonManager.cs @@ -277,7 +277,7 @@ private void OnDungeonDBStarted() customRoom.FixReference = false; } - if (customRoom.ThemeName != "None") + if (customRoom.Theme != 0) { RegisterRoomInDungeonDB(customRoom); } @@ -333,7 +333,7 @@ private void OnDungeonGeneratorSetupAvailableRooms(DungeonGenerator self) DungeonGenerator.m_availableRooms.AddRange(Rooms.Values .Where(r => r.Room.m_enabled) - .Where(r => self.m_themes.HasFlag(r.GetRoomTheme(r.ThemeName))) + .Where(r => self.m_themes.HasFlag(r.Theme)) .Select(r => r.RoomData)); }