From 68165481dc258a514db298c7a125a5ae966dcf37 Mon Sep 17 00:00:00 2001 From: Metious <71298690+Metious@users.noreply.github.com> Date: Mon, 18 Dec 2023 02:02:00 +0330 Subject: [PATCH 1/6] Fixed tech category display names not getting applied (#500) * Fixed tech category display names not applied --- .../Enums/Extensions/EnumExtensions_TechCategory.cs | 9 ++++----- .../Enums/Extensions/EnumExtensions_TechGroup.cs | 5 +++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Nautilus/Handlers/Enums/Extensions/EnumExtensions_TechCategory.cs b/Nautilus/Handlers/Enums/Extensions/EnumExtensions_TechCategory.cs index 65473cf1..c43f5662 100644 --- a/Nautilus/Handlers/Enums/Extensions/EnumExtensions_TechCategory.cs +++ b/Nautilus/Handlers/Enums/Extensions/EnumExtensions_TechCategory.cs @@ -17,23 +17,22 @@ public static EnumBuilder WithPdaInfo(this EnumBuilder WithPdaInfo(this EnumBuilder bui { var techGroup = (TechGroup)builder; var name = builder.ToString(); + var fullName = "Group" + name; if (!string.IsNullOrEmpty(displayName)) { - LanguageHandler.SetLanguageLine("Group" + name, displayName, language); + LanguageHandler.SetLanguageLine(fullName, displayName, language); } - else if (string.IsNullOrEmpty(Language.main.Get("Group" + name))) + else if (string.IsNullOrEmpty(Language.main.Get(fullName))) { InternalLogger.Warn($"Display name was not specified and no existing language line has been found for TechGroup '{name}'."); } From 718fb56cbbe0544065b365b6433354db8c2bf4cb Mon Sep 17 00:00:00 2001 From: MrPurple6411 Date: Sun, 17 Dec 2023 15:33:16 -0700 Subject: [PATCH 2/6] Correct set analysis tech entry behavior breaking change (#504) * Correct functionalities change to SetAnalysisTechEntry * Change Lists to HashSets to prevent useless duplicates being added. * Correct Timing issue that would remove the items AnalysisTech if the item had a CompoundTech. * Reimplement lost functionality removed by my failure to properly review ALL aspects of the ScannerGadget PR. * Change require analysistech causing fail to auto create one instead like before. Fix: Corrected removals timing Doc: Added more notes to describe the why things are where they are. Doc: Added notes on methods that modify instead of replace even if the name is horrible and makes you think they should replace. --- Nautilus/Assets/Gadgets/ScanningGadget.cs | 12 +-- Nautilus/Handlers/KnownTechHandler.cs | 59 +++++++++--- Nautilus/Patchers/KnownTechPatcher.cs | 105 +++++++++++++--------- 3 files changed, 117 insertions(+), 59 deletions(-) diff --git a/Nautilus/Assets/Gadgets/ScanningGadget.cs b/Nautilus/Assets/Gadgets/ScanningGadget.cs index 367a66ad..49c0e4e1 100644 --- a/Nautilus/Assets/Gadgets/ScanningGadget.cs +++ b/Nautilus/Assets/Gadgets/ScanningGadget.cs @@ -381,17 +381,17 @@ protected internal override void Build() PDAHandler.AddEncyclopediaEntry(EncyclopediaEntryData); } - if (AnalysisTech is { }) - { - KnownTechHandler.SetAnalysisTechEntry(AnalysisTech); - } - if (CompoundTechsForUnlock is { Count: > 0 }) { KnownTechHandler.RemoveAllCurrentAnalysisTechEntry(prefab.Info.TechType); KnownTechHandler.SetCompoundUnlock(prefab.Info.TechType, CompoundTechsForUnlock); } + if (AnalysisTech is { }) + { + KnownTechHandler.SetAnalysisTechEntry(AnalysisTech); + } + if (ScannerEntryData is { }) { PDAHandler.AddCustomScannerEntry(ScannerEntryData); @@ -399,7 +399,7 @@ protected internal override void Build() if (RequiredForUnlock != TechType.None) { - KnownTechHandler.AddRequirementForUnlock(prefab.Info.TechType, RequiredForUnlock); + KnownTechHandler.SetAnalysisTechEntry(RequiredForUnlock, new TechType[] { prefab.Info.TechType }); } if (CompoundTechsForUnlock is { Count: > 0 } || RequiredForUnlock != TechType.None) diff --git a/Nautilus/Handlers/KnownTechHandler.cs b/Nautilus/Handlers/KnownTechHandler.cs index afc0acb9..19dc13d2 100644 --- a/Nautilus/Handlers/KnownTechHandler.cs +++ b/Nautilus/Handlers/KnownTechHandler.cs @@ -24,6 +24,27 @@ private static void Reinitialize() public static void UnlockOnStart(TechType techType) { KnownTechPatcher.UnlockedAtStart.Add(techType); + + bool removed = false; + var removalList = new List(); + KnownTechPatcher.DefaultRemovalTechs.ForEach((x) => + { + if (x.Value.Remove(techType)) + { + removed = true; + InternalLogger.Debug($"Removed {techType.AsString()} from {x.Key}'s DefaultRemovalTechs"); + if (x.Value.Count > 0 ) + { + removalList.Add(x.Key); + } + } + }); + + foreach (string key in removalList) + KnownTechPatcher.DefaultRemovalTechs.Remove(key); + + if (removed) + InternalLogger.Debug($"Set {techType.AsString()} to Unlock On Start "); Reinitialize(); } @@ -48,7 +69,7 @@ public static void AddRequirementForUnlock(TechType blueprint, TechType requirem public static void SetHardLocked(TechType techType) { KnownTechPatcher.HardLocked.Add(techType); - KnownTechPatcher.UnlockedAtStart.Remove(techType); + RemoveDefaultUnlock(techType); Reinitialize(); } @@ -140,17 +161,13 @@ internal static void RemoveAnalysisSpecific(TechType targetTechType, List types)) - { - if (!types.Contains(targetTechType)) - { - types.Add(targetTechType); - } - } + if (KnownTechPatcher.AnalysisTech.TryGetValue(techType, out var analysisTech) && analysisTech.unlockTechTypes.Remove(targetTechType)) + InternalLogger.Debug($"Removed unlock for {targetTechType.AsString()} from {techType} that was added by another mod."); + + if (KnownTechPatcher.RemoveFromSpecificTechs.TryGetValue(techType, out HashSet types)) + types.Add(targetTechType); else - { - KnownTechPatcher.RemoveFromSpecificTechs[techType] = new List() { targetTechType }; - } + KnownTechPatcher.RemoveFromSpecificTechs[techType] = new HashSet() { targetTechType }; } Reinitialize(); @@ -158,6 +175,11 @@ internal static void RemoveAnalysisSpecific(TechType targetTechType, List before calling this method. /// /// This TechType is the criteria for all of the "unlock TechTypes"; when this TechType is unlocked, so are all the ones in that list /// The TechTypes that will be unlocked when "techTypeToSet" is unlocked. @@ -198,6 +221,7 @@ public static void SetAnalysisTechEntry(TechType techTypeToBeAnalysed, IEnumerab /// Allows you to define which TechTypes are unlocked when a certain TechType is unlocked, i.e., "analysed". /// If there is already an existing AnalysisTech entry for a TechType, all the TechTypes in "techTypesToUnlock" will be /// added to the existing AnalysisTech entry unlocks. + /// ***Note: This will not remove any original unlock and if you need to do so you should use before calling this method. /// /// This TechType is the criteria for all of the "unlock TechTypes"; when this TechType is unlocked, so are all the ones in that list /// The TechTypes that will be unlocked when "techTypeToSet" is unlocked. @@ -211,6 +235,7 @@ public static void SetAnalysisTechEntry(TechType techTypeToBeAnalysed, IEnumerab /// Allows you to define which TechTypes are unlocked when a certain TechType is unlocked, i.e., "analysed". /// If there is already an existing AnalysisTech entry for a TechType, all the TechTypes in "techTypesToUnlock" will be /// added to the existing AnalysisTech entry unlocks. + /// ***Note: This will not remove any original unlock and if you need to do so you should use before calling this method. /// /// This TechType is the criteria for all of the "unlock TechTypes"; when this TechType is unlocked, so are all the ones in that list /// The TechTypes that will be unlocked when "techTypeToSet" is unlocked. @@ -224,6 +249,7 @@ public static void SetAnalysisTechEntry(TechType techTypeToBeAnalysed, IEnumerab /// Allows you to define which TechTypes are unlocked when a certain TechType is unlocked, i.e., "analysed". /// If there is already an exisitng AnalysisTech entry for a TechType, all the TechTypes in "techTypesToUnlock" will be /// added to the existing AnalysisTech entry unlocks. + /// ***Note: This will not remove any original unlock and if you need to do so you should use before calling this method. /// /// This TechType is the criteria for all of the "unlock TechTypes"; when this TechType is unlocked, so are all the ones in that list /// The TechTypes that will be unlocked when "techTypeToSet" is unlocked. @@ -237,6 +263,7 @@ public static void SetAnalysisTechEntry(TechType techTypeToBeAnalysed, IEnumerab /// Allows you to define which TechTypes are unlocked when a certain TechType is unlocked, i.e., "analysed". /// If there is already an existing AnalysisTech entry for a TechType, all the TechTypes in "techTypesToUnlock" will be /// added to the existing AnalysisTech entry unlocks. + /// ***Note: This will not remove any original unlock and if you need to do so you should use before calling this method. /// /// This TechType is the criteria for all of the "unlock TechTypes"; when this TechType is unlocked, so are all the ones in that list /// The TechTypes that will be unlocked when "techTypeToSet" is unlocked. @@ -251,6 +278,7 @@ public static void SetAnalysisTechEntry(TechType techTypeToBeAnalysed, IEnumerab /// Allows you to define which TechTypes are unlocked when a certain TechType is unlocked, i.e., "analysed". /// If there is already an existing AnalysisTech entry for a TechType, all the TechTypes in "techTypesToUnlock" will be /// added to the existing AnalysisTech entry unlocks. + /// ***Note: This will not remove any original unlock and if you need to do so you should use before calling this method. /// /// This TechType is the criteria for all of the "unlock TechTypes"; when this TechType is unlocked, so are all the ones in that list /// The TechTypes that will be unlocked when "techTypeToSet" is unlocked. @@ -265,6 +293,7 @@ public static void SetAnalysisTechEntry(TechType techTypeToBeAnalysed, IEnumerab /// Allows you to define which TechTypes are unlocked when a certain TechType is unlocked, i.e., "analysed". /// If there is already an existing AnalysisTech entry for a TechType, all the TechTypes in "techTypesToUnlock" will be /// added to the existing AnalysisTech entry unlocks. + /// ***Note: This will not remove any original unlock and if you need to do so you should use before calling this method. /// /// This TechType is the criteria for all of the "unlock TechTypes"; when this TechType is unlocked, so are all the ones in that list /// The TechTypes that will be unlocked when "techTypeToSet" is unlocked. @@ -279,6 +308,7 @@ public static void SetAnalysisTechEntry(TechType techTypeToBeAnalysed, IEnumerab /// Allows you to define which TechTypes are unlocked when a certain TechType is unlocked, i.e., "analysed". /// If there is already an existing AnalysisTech entry for a TechType, all the TechTypes in will be /// added to the existing AnalysisTech entry unlocks. + /// ***Note: This will not remove any original unlock and if you need to do so you should use before calling this method. /// /// The analysis tech entry to add. public static void SetAnalysisTechEntry(KnownTech.AnalysisTech analysisTech) @@ -290,6 +320,7 @@ public static void SetAnalysisTechEntry(KnownTech.AnalysisTech analysisTech) /// Allows you to define which TechTypes are unlocked when a certain TechType is unlocked, i.e., "analysed". /// If there is already an existing AnalysisTech entry for a TechType, all the TechTypes in "techTypesToUnlock" will be /// added to the existing AnalysisTech entry unlocks. + /// ***Note: This will not remove any original unlock and if you need to do so you should use before calling this method. /// /// This TechType is the criteria for all of the "unlock TechTypes"; when this TechType is unlocked, so are all the ones in that list /// The TechTypes that will be unlocked when "techTypeToSet" is unlocked. @@ -303,7 +334,7 @@ public static void SetAnalysisTechEntry(TechType techTypeToBeAnalysed, IEnumerab /// /// Allows you to set up a custom Compound Unlock requiring multiple techtypes to be unlocked before 1 is. - /// ***Note: This will not remove any original unlock and if you need to do so you should use or + /// ***Note: This will not remove any original unlock and if you need to do so you should use before calling this method. /// /// /// @@ -344,10 +375,12 @@ public static void RemoveDefaultUnlock(TechType techType) { var modName = ReflectionHelper.CallingAssemblyByStackTrace().GetName().Name; if (!KnownTechPatcher.DefaultRemovalTechs.TryGetValue(modName, out var techTypes)) - techTypes = new List(); + techTypes = new HashSet(); techTypes.Add(techType); KnownTechPatcher.DefaultRemovalTechs[modName] = techTypes; + if (KnownTechPatcher.UnlockedAtStart.Remove(techType)) + InternalLogger.Debug($"Removed Default unlock for {techType} that was added by another mod."); Reinitialize(); } diff --git a/Nautilus/Patchers/KnownTechPatcher.cs b/Nautilus/Patchers/KnownTechPatcher.cs index f9fec628..6c40ee11 100644 --- a/Nautilus/Patchers/KnownTechPatcher.cs +++ b/Nautilus/Patchers/KnownTechPatcher.cs @@ -14,11 +14,11 @@ internal class KnownTechPatcher internal static HashSet LockedWithNoUnlocks = new(); internal static HashSet HardLocked = new(); internal static HashSet RemovalTechs = new(); - internal static Dictionary> DefaultRemovalTechs = new(); + internal static Dictionary> DefaultRemovalTechs = new(); internal static IDictionary AnalysisTech = new SelfCheckingDictionary("AnalysisTech", AsStringFunction); - internal static IDictionary> BlueprintRequirements = new SelfCheckingDictionary>("BlueprintRequirements", AsStringFunction); + internal static IDictionary> BlueprintRequirements = new SelfCheckingDictionary>("BlueprintRequirements", AsStringFunction); internal static IDictionary CompoundTech = new SelfCheckingDictionary("CompoundTech", AsStringFunction); - internal static IDictionary> RemoveFromSpecificTechs = new SelfCheckingDictionary>("RemoveFromSpecificTechs", AsStringFunction); + internal static IDictionary> RemoveFromSpecificTechs = new SelfCheckingDictionary>("RemoveFromSpecificTechs", AsStringFunction); public static void Patch(Harmony harmony) { @@ -50,15 +50,46 @@ internal static void Reinitialize() private static void InitializePrefix(PDAData data) { - foreach (var unlockedTech in UnlockedAtStart) + // This needs to be done first as this list was supposed to be only for game unlocks. + // Mod unlocks requesting removal are already processed in the KnownTechHandler at the time of the request. + // Mods trying to remove other mods unlocks must make sure to run after the original mod has already added them. + foreach (var removalTech in RemovalTechs) { - if (!data.defaultTech.Contains(unlockedTech)) + if (data.compoundTech.RemoveAll((x)=> x.techType == removalTech) > 0) + InternalLogger.Debug($"RemovalTechs: Removed compoundTech for '{removalTech}'"); + + if (data.analysisTech.RemoveAll((x) => x.techType == removalTech) > 0) + InternalLogger.Debug($"RemovalTechs: Removed analysisTech for '{removalTech}'"); + + foreach (var analysisTech in data.analysisTech) { - data.defaultTech.Add(unlockedTech); - InternalLogger.Debug($"Setting {unlockedTech.AsString()} to be unlocked at start."); + if (analysisTech.unlockTechTypes.Remove(removalTech)) + { + InternalLogger.Debug($"RemovalTechs: Removed unlockTechType '{removalTech}' from '{analysisTech.techType}' AnalysisTech."); + } + } + } + + // Process removals of specific game unlocks as requested by mods. + // Mod unlocks requesting removal are already processed in the KnownTechHandler at the time of the request. + // Mods trying to remove other mods unlocks must make sure to run after the original mod has already added them. + foreach (var analysisTech in data.analysisTech) + { + if (RemoveFromSpecificTechs.TryGetValue(analysisTech.techType, out var techsToRemove)) + { + foreach (var removalTech in techsToRemove) + { + if (analysisTech.unlockTechTypes.Remove(removalTech)) + { + InternalLogger.Debug($"RemoveFromSpecificTechs: Removed unlockTechType '{removalTech}' from '{analysisTech.techType}' AnalysisTech."); + } + } } } + // remove all default unlocks specified by mods. + // Mod unlocks requesting removal are already processed in the KnownTechHandler at the time of the request. + // Mods trying to remove other mods unlocks must make sure to run after the original mod has already added them. foreach (var removalTechsByMod in DefaultRemovalTechs) { foreach (var removalTech in removalTechsByMod.Value) @@ -70,26 +101,46 @@ private static void InitializePrefix(PDAData data) } } + // Add all default unlocks set by mods. + foreach (var unlockedTech in UnlockedAtStart) + { + if (!data.defaultTech.Contains(unlockedTech)) + { + data.defaultTech.Add(unlockedTech); + InternalLogger.Debug($"Setting {unlockedTech.AsString()} to be unlocked at start."); + } + } + + // Add or modify analysisTechs as requested by mods. foreach (var tech in AnalysisTech.Values) { var index = data.analysisTech.FindIndex(analysisTech => analysisTech.techType == tech.techType); if (index == -1) { InternalLogger.Debug($"Adding analysisTech for {tech.techType}"); + + if (tech.unlockSound == null) + tech.unlockSound = KnownTechHandler.DefaultUnlockData.BlueprintUnlockSound; + data.analysisTech.Add(tech); } else { - InternalLogger.Debug($"Replacing analysisTech for {tech.techType}"); - data.analysisTech[index] = tech; - } + InternalLogger.Debug($"Altering original analysisTech for {tech.techType}"); + var existingEntry = data.analysisTech[index]; - if (tech.unlockSound == null) - { - tech.unlockSound = KnownTechHandler.DefaultUnlockData.BlueprintUnlockSound; + existingEntry.unlockMessage = tech.unlockMessage ?? existingEntry.unlockMessage; + existingEntry.unlockSound = tech.unlockSound ?? existingEntry.unlockSound; + existingEntry.unlockPopup = tech.unlockPopup ?? existingEntry.unlockPopup; + existingEntry.unlockTechTypes.AddRange(tech.unlockTechTypes); +#if SUBNAUTICA + existingEntry.storyGoals.AddRange(tech.storyGoals); +#endif } } + // Set unlocks for already existing analysis techs where a AnalysisTech is not created by the mod. + // tbh I don't know why this was added as we used to just make an analysis tech with the data given by the modder if they did not specify one. foreach (var blueprintRequirements in BlueprintRequirements) { var index = data.analysisTech.FindIndex(tech => tech.techType == blueprintRequirements.Key); @@ -103,6 +154,7 @@ private static void InitializePrefix(PDAData data) data.analysisTech[index].unlockTechTypes.AddRange(blueprintRequirements.Value); } + // Add or Replace CompoundTechs as requested by mods. foreach (var tech in CompoundTech.Values) { var index = data.compoundTech.FindIndex(compoundTech => compoundTech.techType == tech.techType); @@ -117,33 +169,6 @@ private static void InitializePrefix(PDAData data) data.compoundTech[index] = tech; } } - - foreach (var analysisTech in data.analysisTech) - { - foreach (var removalTech in RemovalTechs) - { - if (analysisTech.techType == removalTech) - { - continue; - } - - if (analysisTech.unlockTechTypes.Remove(removalTech)) - { - InternalLogger.Debug($"RemovalTechs: Removed unlockTechType '{removalTech}' from '{analysisTech.techType}' AnalysisTech."); - } - } - - if (RemoveFromSpecificTechs.TryGetValue(analysisTech.techType, out var techsToRemove)) - { - foreach (var removalTech in techsToRemove) - { - if (analysisTech.unlockTechTypes.Remove(removalTech)) - { - InternalLogger.Debug($"RemoveFromSpecificTechs: Removed unlockTechType '{removalTech}' from '{analysisTech.techType}' AnalysisTech."); - } - } - } - } } private static void GetAllUnlockablesPostfix(HashSet __result) From 73202da76099c16d4c6835087096cb64edee957a Mon Sep 17 00:00:00 2001 From: Lee23 <31892011+LeeTwentyThree@users.noreply.github.com> Date: Sun, 17 Dec 2023 17:34:02 -0500 Subject: [PATCH 3/6] Change crafting gadget tree failure log level to Debug (#506) Change gadget tree failure log level to Debug --- Nautilus/Assets/Gadgets/CraftingGadget.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nautilus/Assets/Gadgets/CraftingGadget.cs b/Nautilus/Assets/Gadgets/CraftingGadget.cs index 30eea3e3..b8ae8229 100644 --- a/Nautilus/Assets/Gadgets/CraftingGadget.cs +++ b/Nautilus/Assets/Gadgets/CraftingGadget.cs @@ -104,7 +104,7 @@ protected internal override void Build() } else if (!prefab.TryGetGadget(out ScanningGadget scanningGadget) || !scanningGadget.IsBuildable) { - InternalLogger.Log($"Prefab '{prefab.Info.ClassID}' was not automatically registered into a crafting tree."); + InternalLogger.Debug($"Prefab '{prefab.Info.ClassID}' was not automatically registered into a crafting tree."); } if (CraftingTime >= 0f) From f006d4e5b296304d4cc2e3a3875fff56f6e318f7 Mon Sep 17 00:00:00 2001 From: MrPurple6411 Date: Sun, 17 Dec 2023 15:34:32 -0700 Subject: [PATCH 4/6] Fix CC3 1.0.0.2 bug. (#507) Fix: Correct Invalid Cast exception when trying to remove a node from a custom fabricator. --- Nautilus/Crafting/ModCraftTreeLinkingNode.cs | 13 ++++----- Nautilus/Handlers/CraftTreeHandler.cs | 29 ++++++++------------ 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/Nautilus/Crafting/ModCraftTreeLinkingNode.cs b/Nautilus/Crafting/ModCraftTreeLinkingNode.cs index d1c84bb2..32e9700a 100644 --- a/Nautilus/Crafting/ModCraftTreeLinkingNode.cs +++ b/Nautilus/Crafting/ModCraftTreeLinkingNode.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Nautilus.Handlers; +using Nautilus.Utility; using UnityEngine; using UnityEngine.Assertions; @@ -83,16 +84,15 @@ public ModCraftTreeTab AddTabNode(string nameID) /// public ModCraftTreeTab GetTabNode(string nameID) { - foreach (ModCraftTreeTab node in ChildNodes) + foreach (var node in ChildNodes) { if (node == null) { continue; } - if (node.Name == nameID && node.Action == TreeAction.Expand) + if (node.Name == nameID && node.Action == TreeAction.Expand && node is ModCraftTreeTab tab) { - ModCraftTreeTab tab = node; return tab; } } @@ -107,16 +107,15 @@ public ModCraftTreeTab GetTabNode(string nameID) /// public ModCraftTreeCraft GetCraftingNode(TechType techType) { - foreach (ModCraftTreeNode node in ChildNodes) + foreach (var node in ChildNodes) { if (node == null) { continue; } - if (node.TechType == techType && node.Action == TreeAction.Craft) + if (node.TechType == techType && node.Action == TreeAction.Craft && node is ModCraftTreeCraft craftNode) { - ModCraftTreeCraft craftNode = (ModCraftTreeCraft)node; return craftNode; } } @@ -131,7 +130,7 @@ public ModCraftTreeCraft GetCraftingNode(TechType techType) /// public ModCraftTreeNode GetNode(string nameID) { - foreach (ModCraftTreeNode node in ChildNodes) + foreach (var node in ChildNodes) { if (node == null) { diff --git a/Nautilus/Handlers/CraftTreeHandler.cs b/Nautilus/Handlers/CraftTreeHandler.cs index c16a6ca4..e086faf7 100644 --- a/Nautilus/Handlers/CraftTreeHandler.cs +++ b/Nautilus/Handlers/CraftTreeHandler.cs @@ -1,14 +1,13 @@ +namespace Nautilus.Handlers; + using System.Linq; using Nautilus.Crafting; using Nautilus.Patchers; -using Nautilus.Utility; - -namespace Nautilus.Handlers; /// /// A handler class for creating and modifying crafting trees. /// -public static class CraftTreeHandler +public static class CraftTreeHandler { /// /// Adds a new crafting node to the root of the specified crafting tree, at the provided tab location. @@ -23,7 +22,7 @@ public static class CraftTreeHandler /// public static void AddCraftingNode(CraftTree.Type craftTree, TechType craftingItem, params string[] stepsToTab) { - if(CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) + if (CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) { root.AddCraftNode(craftingItem, stepsToTab.LastOrDefault()); return; @@ -40,7 +39,7 @@ public static void AddCraftingNode(CraftTree.Type craftTree, TechType craftingIt public static void AddCraftingNode(CraftTree.Type craftTree, TechType craftingItem) { - if(CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) + if (CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) { root.AddCraftNode(craftingItem); return; @@ -58,7 +57,7 @@ public static void AddCraftingNode(CraftTree.Type craftTree, TechType craftingIt /// The sprite of the tab. public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, Atlas.Sprite sprite) { - if(CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) + if (CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) { root.AddTabNode(name, displayName, sprite); return; @@ -76,7 +75,7 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, UnityEngine.Sprite sprite) { - if(CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) + if (CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) { root.AddTabNode(name, displayName, sprite); return; @@ -99,7 +98,7 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp /// public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, Atlas.Sprite sprite, params string[] stepsToTab) { - if(CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) + if (CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) { root.AddTabNode(name, displayName, sprite, "English", stepsToTab.LastOrDefault()); return; @@ -122,7 +121,7 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp /// public static void AddTabNode(CraftTree.Type craftTree, string name, string displayName, UnityEngine.Sprite sprite, params string[] stepsToTab) { - if(CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) + if (CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) { root.AddTabNode(name, displayName, sprite, "English", stepsToTab.LastOrDefault()); return; @@ -188,15 +187,9 @@ public static void AddTabNode(CraftTree.Type craftTree, string name, string disp public static void RemoveNode(CraftTree.Type craftTree, params string[] stepsToNode) { - if(CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) + if (CraftTreePatcher.CustomTrees.TryGetValue(craftTree, out var root)) { - var tab = root.GetTabNode(stepsToNode); - if(tab == null) - { - root.GetNode(stepsToNode)?.RemoveNode(); - return; - } - tab.RemoveNode(); + root.GetNode(stepsToNode)?.RemoveNode(); return; } CraftTreePatcher.NodesToRemove.Add(new Node(stepsToNode, craftTree)); From 62fc980ddcb763b945dd729fe0a97375e8287a2c Mon Sep 17 00:00:00 2001 From: MrPurple6411 Date: Sun, 17 Dec 2023 15:34:52 -0700 Subject: [PATCH 5/6] Overhaul ModPrefabRequest and PrefabHandler to fix multi request bug (#508) * Overhaul ModPrefabRequest and PrefabHandler to fix multi request bug --- Nautilus/Assets/ModPrefabCache.cs | 1 + Nautilus/Assets/ModPrefabRequest.cs | 29 ++++++++++++---------- Nautilus/Handlers/PrefabHandler.cs | 12 ++++----- Nautilus/Patchers/PrefabDatabasePatcher.cs | 7 +----- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/Nautilus/Assets/ModPrefabCache.cs b/Nautilus/Assets/ModPrefabCache.cs index 933c546d..78412c3b 100644 --- a/Nautilus/Assets/ModPrefabCache.cs +++ b/Nautilus/Assets/ModPrefabCache.cs @@ -125,6 +125,7 @@ public void RemoveCachedPrefab(string classId) { if(!prefab.IsPrefab()) Destroy(prefab); + InternalLogger.Debug($"ModPrefabCache: removed prefab {classId}"); Entries.Remove(classId); } } diff --git a/Nautilus/Assets/ModPrefabRequest.cs b/Nautilus/Assets/ModPrefabRequest.cs index c3154ca5..84f1d28d 100644 --- a/Nautilus/Assets/ModPrefabRequest.cs +++ b/Nautilus/Assets/ModPrefabRequest.cs @@ -25,7 +25,7 @@ public ModPrefabRequest(PrefabInfo prefabInfo) private void Init() { - if (task != null) + if ((task != null && !Done) || (Done && TryGetPrefab(out _))) { return; } @@ -45,34 +45,37 @@ public object Current get { Init(); - return task; + return task.Current; } } public bool TryGetPrefab(out GameObject result) { - result = taskResult.Get(); - if (!Done) - { - Done = result; - } - return result != null; + return ModPrefabCache.TryGetPrefabFromCache(prefabInfo.ClassID, out result) && result != null; } public bool MoveNext() { Init(); - if (task == null) + if (!task.MoveNext()) { - return false; + Done = true; } - - return !TryGetPrefab(out _); + return !Done; } - public void Reset() {} + public void Reset() + { + Init(); + task.Reset(); + Done = false; + } public void Release() { + ModPrefabCache.RemovePrefabFromCache(prefabInfo.ClassID); + taskResult = null; + task = null; + Done = false; } } \ No newline at end of file diff --git a/Nautilus/Handlers/PrefabHandler.cs b/Nautilus/Handlers/PrefabHandler.cs index f3f0f49f..c2665fed 100644 --- a/Nautilus/Handlers/PrefabHandler.cs +++ b/Nautilus/Handlers/PrefabHandler.cs @@ -26,19 +26,20 @@ internal static IEnumerator GetPrefabAsync(TaskResult gameObject, Pr yield break; } - yield return prefabFactory(gameObject); - - yield return ProcessPrefabAsync(gameObject, info, prefabFactory); + yield return InitPrefabAsync(gameObject, info, prefabFactory); } - private static IEnumerator ProcessPrefabAsync(TaskResult gameObject, PrefabInfo info, PrefabFactoryAsync prefabFactory) + private static IEnumerator InitPrefabAsync(TaskResult gameObject, PrefabInfo info, PrefabFactoryAsync prefabFactory) { + yield return prefabFactory(gameObject); + var obj = gameObject.Get(); if(obj == null) { - InternalLogger.Error($"PrefabHandler: Tried to process a null prefab."); + InternalLogger.Error($"PrefabHandler: PrefabFactory returned null for {info.ClassID}"); yield break; } + obj.SetActive(false); var techType = info.TechType; var classId = info.ClassID; @@ -76,7 +77,6 @@ private static IEnumerator ProcessPrefabAsync(TaskResult gameObject, if (Prefabs.TryGetPostProcessorForInfo(info, out var postProcessor)) yield return postProcessor?.Invoke(obj); - gameObject.Set(obj); ModPrefabCache.AddPrefab(obj); } diff --git a/Nautilus/Patchers/PrefabDatabasePatcher.cs b/Nautilus/Patchers/PrefabDatabasePatcher.cs index 172f2251..93e05e59 100644 --- a/Nautilus/Patchers/PrefabDatabasePatcher.cs +++ b/Nautilus/Patchers/PrefabDatabasePatcher.cs @@ -80,12 +80,7 @@ private static IPrefabRequest GetModPrefabAsync(string classId) } if(ModPrefabCache.Requests.TryGetValue(prefabInfo.ClassID, out var request)) - { - if (request.Done && !request.TryGetPrefab(out _)) - { - return new ModPrefabRequest(prefabInfo); - } - + { return request; } From 83b68744d4292be8b34206f8bdde315725960c2a Mon Sep 17 00:00:00 2001 From: MrPurple6411 Date: Sun, 17 Dec 2023 15:35:43 -0700 Subject: [PATCH 6/6] Survival Handler Fixes and Improvements. (#509) Fix: Setting negative oxygen did not work right. Fix: Setting Negative Health would never kill and could glitch the player if reaching 0. Fix: InventoryUsables was list instead of HashSet Improvement: Added RunActionOnConsume(TechType techType, Action customAction, bool isEdible) to allow mods to send their own custom action to be performed when item is consumed. --- Nautilus/Handlers/SurvivalHandler.cs | 83 ++++++++++++++++++---------- Nautilus/Patchers/SurvivalPatcher.cs | 2 +- 2 files changed, 55 insertions(+), 30 deletions(-) diff --git a/Nautilus/Handlers/SurvivalHandler.cs b/Nautilus/Handlers/SurvivalHandler.cs index f71dd280..0b477069 100644 --- a/Nautilus/Handlers/SurvivalHandler.cs +++ b/Nautilus/Handlers/SurvivalHandler.cs @@ -7,7 +7,7 @@ namespace Nautilus.Handlers; /// /// Handler class that relates to the component. Allows the defining of oxygen or health gains when consuming specific items. /// -public static class SurvivalHandler +public static class SurvivalHandler { /// /// makes the item gives oxygen on use. @@ -15,56 +15,81 @@ public static class SurvivalHandler /// the TechType that you want to make it give oxygen on use /// the oxygen amount the item gives /// set it to if the item is edible and has the component attached to it. - /// defaults to /// public static void GiveOxygenOnConsume(TechType techType, float oxygenGiven, bool isEdible) { - if (SurvivalPatcher.CustomSurvivalInventoryAction.TryGetValue(techType, out List action)) + if (!isEdible) { - action.Add(() => { Player.main.GetComponent().AddOxygen(oxygenGiven); }); // add an action to the list - return; + SurvivalPatcher.InventoryUseables.Add(techType); // add it to the HashSet of useables if its not edible } - // if we reach to this point then the techtype doesn't exist in the dictionary so we add it - SurvivalPatcher.CustomSurvivalInventoryAction[techType] = new List() - { - () => - { - Player.main.GetComponent().AddOxygen(oxygenGiven); - } - }; - if (!isEdible) + if (!SurvivalPatcher.CustomSurvivalInventoryAction.TryGetValue(techType, out List actions)) + actions = new List(); + + // add an action to the list + actions.Add(() => { - SurvivalPatcher.InventoryUseables.Add(techType); - } + var oxygenManager = Player.main.GetComponent(); + if (oxygenGiven > 0f) + oxygenManager.AddOxygen(oxygenGiven); + else + oxygenManager.RemoveOxygen(-oxygenGiven); + }); + + SurvivalPatcher.CustomSurvivalInventoryAction[techType] = actions; } + /// /// makes the item Heal the player on consume. /// /// the TechType that you want it to heal back /// amount to heal the player /// set it to if the item is edible and has the component attached to it. - /// defaults to /// public static void GiveHealthOnConsume(TechType techType, float healthBack, bool isEdible) { - if (SurvivalPatcher.CustomSurvivalInventoryAction.TryGetValue(techType, out List action)) + if (!isEdible) { - action.Add(() => { Player.main.GetComponent().AddHealth(healthBack); }); // add an action to the list - return; + SurvivalPatcher.InventoryUseables.Add(techType); // add it to the HashSet of useables if its not edible } - // if we reach to this point then the techtype doesn't exist in the dictionary so we add it - SurvivalPatcher.CustomSurvivalInventoryAction[techType] = new List() - { - () => - { - Player.main.GetComponent().AddHealth(healthBack); - } - }; + if (!SurvivalPatcher.CustomSurvivalInventoryAction.TryGetValue(techType, out List actions)) + actions = new List(); + + actions.Add(() => { + var liveMixin = Player.main.GetComponent(); + if (healthBack > 0) + liveMixin.AddHealth(healthBack); + else + liveMixin.TakeDamage(-healthBack, default, DamageType.Poison); + }); + + SurvivalPatcher.CustomSurvivalInventoryAction[techType] = actions; + } + + /// + /// runs a custom action on consume. + /// + /// the TechType that you want it to heal back + /// the Action to perform. + /// set it to if the item is edible and has the component attached to it. + /// + public static void RunActionOnConsume(TechType techType, Action customAction, bool isEdible) + { + if (techType == TechType.None) + throw new ArgumentNullException(nameof(techType), "TechType cannot be None."); + if (customAction == null) + throw new ArgumentNullException(nameof(customAction), "Action cannot be null."); + if (!isEdible) { - SurvivalPatcher.InventoryUseables.Add(techType); + SurvivalPatcher.InventoryUseables.Add(techType); // add it to the HashSet of useables if its not edible } + + if (!SurvivalPatcher.CustomSurvivalInventoryAction.TryGetValue(techType, out List actions)) + actions = new List(); + + actions.Add(customAction); + SurvivalPatcher.CustomSurvivalInventoryAction[techType] = actions; } } \ No newline at end of file diff --git a/Nautilus/Patchers/SurvivalPatcher.cs b/Nautilus/Patchers/SurvivalPatcher.cs index 00ae3f77..62ec5dcd 100644 --- a/Nautilus/Patchers/SurvivalPatcher.cs +++ b/Nautilus/Patchers/SurvivalPatcher.cs @@ -10,7 +10,7 @@ namespace Nautilus.Patchers; internal class SurvivalPatcher { internal static IDictionary> CustomSurvivalInventoryAction = new SelfCheckingDictionary>("CustomSurvivalInventoryAction", TechTypeExtensions.sTechTypeComparer); - internal static List InventoryUseables = new(); + internal static HashSet InventoryUseables = new(); internal static void Patch(Harmony harmony) {