diff --git a/R2API.MonoMod/SurvivorAPI.cs b/R2API.MonoMod/NoInlinePatches.cs similarity index 57% rename from R2API.MonoMod/SurvivorAPI.cs rename to R2API.MonoMod/NoInlinePatches.cs index dd5b108c..575d3d0b 100644 --- a/R2API.MonoMod/SurvivorAPI.cs +++ b/R2API.MonoMod/NoInlinePatches.cs @@ -7,4 +7,9 @@ internal class patch_SurvivorCatalog { [MonoModIgnore] [NoInlining] public static extern SurvivorDef GetSurvivorDef(SurvivorIndex survivorIndex); } + + internal class patch_DifficultyCatalog { + [MonoModIgnore] [NoInlining] + public static extern DifficultyDef GetDifficultyDef(DifficultyIndex difficultyIndex); + } } diff --git a/R2API/DifficultyAPI.cs b/R2API/DifficultyAPI.cs new file mode 100644 index 00000000..511690ea --- /dev/null +++ b/R2API/DifficultyAPI.cs @@ -0,0 +1,86 @@ +using R2API.Utils; +using RoR2; +using System; +using System.Collections.ObjectModel; +using UnityEngine; + +namespace R2API { + [R2APISubmodule] + public class DifficultyAPI{ + + private static bool difficultyAlreadyAdded = false; + + public static event EventHandler difficultyCatalogReady; + + private const DifficultyIndex VanillaFinalIndex = DifficultyIndex.Hard;//We want to replace this + + public static ObservableCollection difficultyDefinitions = new ObservableCollection(); + /// + /// Add a DifficultyDef to the list of available difficulties. + /// This must be called before the DifficultyCatalog inits, so before plugin.Start() + /// You'll get your new index returned that you can work with for comparing to Run.Instance.selectedDifficulty. + /// If this is called after the DifficultyCatalog inits then this will return -1/DifficultyIndex.Invalid and ignore the difficulty + /// + /// The difficulty to add. + /// DifficultyIndex.Invalid if it fails. Your index otherwise. + public static DifficultyIndex AddDifficulty(DifficultyDef difficulty) { + if (difficultyAlreadyAdded) { + R2API.Logger.LogError($"Tried to add difficulty: {difficulty.nameToken} after difficulty list was created"); + return DifficultyIndex.Invalid; + } + difficultyDefinitions.Add(difficulty); + + return VanillaFinalIndex + difficultyDefinitions.Count; + } + + + [R2APISubmoduleInit(Stage = InitStage.SetHooks)] + internal static void SetHooks() { + difficultyCatalogReady?.Invoke(null, null); + On.RoR2.DifficultyCatalog.GetDifficultyDef += GetExtendedDifficultyDef; + On.RoR2.RuleDef.FromDifficulty += InitialiseRuleBookAndFinalizeList; + } + + [R2APISubmoduleInit(Stage = InitStage.UnsetHooks)] + internal static void UnsetHooks() { + On.RoR2.DifficultyCatalog.GetDifficultyDef -= GetExtendedDifficultyDef; + On.RoR2.RuleDef.FromDifficulty -= InitialiseRuleBookAndFinalizeList; + } + + private static DifficultyDef GetExtendedDifficultyDef(On.RoR2.DifficultyCatalog.orig_GetDifficultyDef orig, DifficultyIndex difficultyIndex) + { + if(difficultyAlreadyAdded) + return difficultyDefinitions[(int) difficultyIndex]; + return orig(difficultyIndex); + } + private static RuleDef InitialiseRuleBookAndFinalizeList(On.RoR2.RuleDef.orig_FromDifficulty orig) + { + RuleDef ruleChoices = orig(); + var vanillaDefs = DifficultyCatalog.difficultyDefs; + if (difficultyAlreadyAdded == false) {//Technically this function we are hooking is only called once, but in the weird case it's called multiple times, we don't want to add the definitions again. + difficultyAlreadyAdded = true; + for (int i = 0; i < vanillaDefs.Length; i++) { + difficultyDefinitions.Insert(i, vanillaDefs[i]); + } + } + + for ( int i=vanillaDefs.Length; i