From c068196ca23074e16c3537f8cd3a664c1fac90a8 Mon Sep 17 00:00:00 2001
From: Abbysssal <55982389+Abbysssal@users.noreply.github.com>
Date: Sat, 12 Sep 2020 22:53:42 +0700
Subject: [PATCH] Fix a null reference error, start working on
RogueLibs.Interactions
---
RogueLibs.Interactions/CustomInteraction.cs | 69 ++++++++++++++++
RogueLibs.Interactions/InteractionTemplate.cs | 80 +++++++++++++++++++
.../Properties/AssemblyInfo.cs | 36 +++++++++
.../RogueLibs.Interactions.csproj | 68 ++++++++++++++++
.../RogueLibsInteractions.cs | 52 ++++++++++++
.../RogueLibsInteractionsPlugin.cs | 27 +++++++
RogueLibs.sln | 6 ++
RogueLibs/Properties/AssemblyInfo.cs | 4 +-
RogueLibs/RogueLibs.cs | 2 +-
RogueLibs/RogueLibsPlugin.cs | 4 +-
md/4. Changelog.md | 3 +
11 files changed, 346 insertions(+), 5 deletions(-)
create mode 100644 RogueLibs.Interactions/CustomInteraction.cs
create mode 100644 RogueLibs.Interactions/InteractionTemplate.cs
create mode 100644 RogueLibs.Interactions/Properties/AssemblyInfo.cs
create mode 100644 RogueLibs.Interactions/RogueLibs.Interactions.csproj
create mode 100644 RogueLibs.Interactions/RogueLibsInteractions.cs
create mode 100644 RogueLibs.Interactions/RogueLibsInteractionsPlugin.cs
diff --git a/RogueLibs.Interactions/CustomInteraction.cs b/RogueLibs.Interactions/CustomInteraction.cs
new file mode 100644
index 000000000..a76a82b99
--- /dev/null
+++ b/RogueLibs.Interactions/CustomInteraction.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+
+namespace RogueLibsCore.Interactions
+{
+ public class CustomInteraction
+ {
+ internal CustomInteraction(string id, InteractionType type, CustomName name)
+ {
+ Id = id;
+ Type = type;
+ ButtonName = name;
+ }
+
+ ///
+ /// Identifier of this .
+ ///
+ public string Id { get; }
+ ///
+ /// of this .
+ ///
+ public InteractionType Type { get; set; }
+
+ ///
+ /// Localizable name of this 's button.
+ ///
+ public CustomName ButtonName { get; }
+
+ ///
+ /// Method that will determine when this will be active for an object.
+ /// arg1 is the interacting player;
arg2 is the object that is being interacted with.
+ ///
+ public Func Condition { get; set; }
+ ///
+ /// Method that will determine the cost and the extra text for this 's button. Return to not add anything.
+ /// arg1 is the interacting player;
arg2 is the object that is being interacted with;
result is a structure containing the cost and the extra text values.
+ ///
+ public Func GetButtonInfo { get; set; }
+ ///
+ /// Method that will invoked when interacted with an object directly or via a button.
+ /// arg1 is the interacting player;
arg2 is the object that is being interacted with;
result determines whether the interaction should be stopped after interacting.
+ ///
+ public Func Action { get; set; }
+
+
+
+ }
+ public struct InteractionButtonInfo
+ {
+ public InteractionButtonInfo(int cost)
+ {
+ Cost = cost;
+ ExtraText = string.Empty;
+ }
+ public InteractionButtonInfo(string extraText)
+ {
+ Cost = 0;
+ ExtraText = extraText;
+ }
+ public InteractionButtonInfo(int cost, string extraText)
+ {
+ Cost = cost;
+ ExtraText = extraText;
+ }
+
+ public int Cost { get; set; }
+ public string ExtraText { get; set; }
+ }
+}
diff --git a/RogueLibs.Interactions/InteractionTemplate.cs b/RogueLibs.Interactions/InteractionTemplate.cs
new file mode 100644
index 000000000..7c2fc72cf
--- /dev/null
+++ b/RogueLibs.Interactions/InteractionTemplate.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using UnityEngine;
+using HarmonyLib;
+
+namespace RogueLibsCore.Interactions
+{
+ internal class Interaction
+ where T : PlayfieldObject
+ {
+ public void Patch()
+ {
+ RoguePatcher patcher = new RoguePatcher(RogueLibsInteractions.PluginInstance, GetType());
+ patcher.Prefix(typeof(T), "DetermineButtons");
+ patcher.Prefix(typeof(T), "Interact");
+ patcher.Prefix(typeof(T), "PressedButton");
+ }
+ public virtual bool DetermineButtons(T __instance)
+ {
+ while (__instance.buttonPrices.Count < __instance.buttons.Count)
+ __instance.buttonPrices.Add(0);
+ while (__instance.buttonsExtra.Count < __instance.buttons.Count)
+ __instance.buttonsExtra.Add(string.Empty);
+
+ List allInteractions = RogueLibsInteractions.CustomInteractions.FindAll(i => i.Condition?.Invoke(__instance.interactingAgent, __instance) ?? false);
+ foreach (CustomInteraction interaction in allInteractions)
+ {
+ if ((interaction.Type & InteractionType.Button) != 0)
+ {
+ InteractionButtonInfo? info = interaction.GetButtonInfo(__instance.interactingAgent, __instance);
+ __instance.buttons.Add(interaction.Id);
+ __instance.buttonPrices.Add(info?.Cost ?? 0);
+ __instance.buttonsExtra.Add(info?.ExtraText ?? string.Empty);
+ }
+ }
+ return false;
+ }
+ public virtual bool Interact(T __instance, Agent agent)
+ {
+ MethodInfo baseMethod = AccessTools.Method(__instance.GetType().BaseType, "Interact");
+ baseMethod.Invoke(__instance, new object[] { agent });
+
+ List allInteractions = RogueLibsInteractions.CustomInteractions.FindAll(i => i.Condition?.Invoke(__instance.interactingAgent, __instance) ?? false);
+ List actionsOnly = allInteractions.FindAll(i => i.Type == InteractionType.Interact);
+ List possibleButtons = allInteractions.FindAll(i => i.Type == InteractionType.InteractOrButton);
+ List buttonsOnly = allInteractions.FindAll(i => i.Type == InteractionType.Button);
+ __instance.DetermineButtons();
+ List origButtons = __instance.buttons;
+
+ foreach (CustomInteraction action in actionsOnly)
+ {
+ action.Action?.Invoke(__instance.interactingAgent, __instance);
+ __instance.StopInteraction();
+ }
+ if (possibleButtons.Count == 1 && (buttonsOnly.Count == 0 && origButtons.Count == 0))
+ {
+ possibleButtons[0].Action?.Invoke(__instance.interactingAgent, __instance);
+ __instance.StopInteraction();
+ }
+ else if (possibleButtons.Count > 0 || (buttonsOnly.Count > 0 || origButtons.Count > 0))
+ {
+ __instance.ShowObjectButtons();
+ }
+ return false;
+
+ }
+ public virtual bool PressedButton(T __instance, string buttonText, int buttonPrice)
+ {
+ CustomInteraction interaction = RogueLibsInteractions.GetCustomInteraction(buttonText);
+ if (interaction == null) return true;
+ bool stopInteracting = interaction.Action?.Invoke(__instance.interactingAgent, __instance) ?? false;
+ if (stopInteracting) __instance.StopInteraction();
+ else __instance.RefreshButtons();
+ return false;
+ }
+ }
+}
diff --git a/RogueLibs.Interactions/Properties/AssemblyInfo.cs b/RogueLibs.Interactions/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..2f72af056
--- /dev/null
+++ b/RogueLibs.Interactions/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("RogueLibs.Interactions")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("RogueLibs.Interactions")]
+[assembly: AssemblyCopyright("Copyright © 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c933c4df-e3b1-48a5-8c82-a6c53cb56020")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("2.1.1.0")]
+[assembly: AssemblyFileVersion("2.1.1.0")]
diff --git a/RogueLibs.Interactions/RogueLibs.Interactions.csproj b/RogueLibs.Interactions/RogueLibs.Interactions.csproj
new file mode 100644
index 000000000..b070c19a0
--- /dev/null
+++ b/RogueLibs.Interactions/RogueLibs.Interactions.csproj
@@ -0,0 +1,68 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {C933C4DF-E3B1-48A5-8C82-A6C53CB56020}
+ Library
+ Properties
+ RogueLibsCore.Interactions
+ RogueLibs.Interactions
+ v3.5
+ 512
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\Libraries\0Harmony.dll
+
+
+ ..\Libraries\Assembly-CSharp.dll
+
+
+ ..\Libraries\BepInEx.dll
+
+
+
+ ..\Libraries\UnityEngine.dll
+
+
+ ..\Libraries\UnityEngine.CoreModule.dll
+
+
+
+
+
+
+
+
+
+
+
+ {a1764685-f31f-4864-aab6-99870b10c239}
+ RogueLibs
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RogueLibs.Interactions/RogueLibsInteractions.cs b/RogueLibs.Interactions/RogueLibsInteractions.cs
new file mode 100644
index 000000000..df7ea449a
--- /dev/null
+++ b/RogueLibs.Interactions/RogueLibsInteractions.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using BepInEx;
+using BepInEx.Logging;
+using UnityEngine;
+
+namespace RogueLibsCore.Interactions
+{
+ public static class RogueLibsInteractions
+ {
+ public const string pluginGuid = "abbysssal.streetsofrogue.roguelibs.interactions";
+ public const string pluginName = "RogueLibs Interactions";
+ public const string pluginVersion = "2.1.1";
+
+ public static RogueLibsInteractionsPlugin PluginInstance;
+ internal static ManualLogSource Logger;
+
+ public static List CustomInteractions { get; } = new List();
+
+ public static CustomInteraction GetCustomInteraction(string id) => CustomInteractions.Find(i => i.Id == id);
+ public static CustomInteraction CreateCustomInteraction(string id, InteractionType type, CustomNameInfo? buttonName, Func condition)
+ {
+ CustomInteraction customInteraction = GetCustomInteraction(id);
+ if (customInteraction != null)
+ {
+ string message = string.Concat("A CustomInteraction with Id \"", id, "\" already exists!");
+ Logger.LogError(message);
+ throw new ArgumentException(message, nameof(id));
+ }
+ CustomInteractions.Add(customInteraction = new CustomInteraction(id, type,
+ buttonName.HasValue ? RogueLibs.CreateCustomName(id, "Interface", buttonName.Value) : null));
+ customInteraction.Condition = condition;
+
+ Logger.LogDebug(string.Concat("A CustomInteraction with Id \"", id, "\" (", type.ToString(), ") was created."));
+
+ return customInteraction;
+ }
+
+
+
+
+ }
+ [Flags] public enum InteractionType
+ {
+ // Interact only
+ Interact = 0b_01,
+ // Button only
+ Button = 0b_10,
+ // Button if Interact is not possible; otherwise, Interact
+ InteractOrButton = 0b_11
+ }
+}
diff --git a/RogueLibs.Interactions/RogueLibsInteractionsPlugin.cs b/RogueLibs.Interactions/RogueLibsInteractionsPlugin.cs
new file mode 100644
index 000000000..7cd2cd646
--- /dev/null
+++ b/RogueLibs.Interactions/RogueLibsInteractionsPlugin.cs
@@ -0,0 +1,27 @@
+using System;
+using BepInEx;
+using BepInEx.Logging;
+
+namespace RogueLibsCore.Interactions
+{
+ [BepInPlugin(RogueLibsInteractions.pluginGuid, RogueLibsInteractions.pluginName, RogueLibsInteractions.pluginVersion)]
+ [BepInDependency(RogueLibs.pluginGuid, RogueLibsInteractions.pluginVersion)]
+ public partial class RogueLibsInteractionsPlugin : BaseUnityPlugin
+ {
+ protected static ManualLogSource MyLogger;
+
+ public void Awake()
+ {
+ RogueLibsInteractions.PluginInstance = this;
+ RogueLibsInteractions.Logger = MyLogger = Logger;
+
+ RoguePatcher patcher = new RoguePatcher(this, GetType());
+
+
+
+
+
+ }
+
+ }
+}
diff --git a/RogueLibs.sln b/RogueLibs.sln
index 79661f596..1c301009e 100644
--- a/RogueLibs.sln
+++ b/RogueLibs.sln
@@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RogueLibs", "RogueLibs\Rogu
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RogueLibs.Test", "RogueLibs.Test\RogueLibs.Test.csproj", "{D4A59C1A-DCDA-4DE8-80DF-7B802707000F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RogueLibs.Interactions", "RogueLibs.Interactions\RogueLibs.Interactions.csproj", "{C933C4DF-E3B1-48A5-8C82-A6C53CB56020}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +23,10 @@ Global
{D4A59C1A-DCDA-4DE8-80DF-7B802707000F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4A59C1A-DCDA-4DE8-80DF-7B802707000F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4A59C1A-DCDA-4DE8-80DF-7B802707000F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C933C4DF-E3B1-48A5-8C82-A6C53CB56020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C933C4DF-E3B1-48A5-8C82-A6C53CB56020}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C933C4DF-E3B1-48A5-8C82-A6C53CB56020}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C933C4DF-E3B1-48A5-8C82-A6C53CB56020}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/RogueLibs/Properties/AssemblyInfo.cs b/RogueLibs/Properties/AssemblyInfo.cs
index 9677b4894..395f2b514 100644
--- a/RogueLibs/Properties/AssemblyInfo.cs
+++ b/RogueLibs/Properties/AssemblyInfo.cs
@@ -31,5 +31,5 @@
// Можно задать все значения или принять номера сборки и редакции по умолчанию
// используя "*", как показано ниже:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.1.0.0")]
-[assembly: AssemblyFileVersion("2.1.0.0")]
+[assembly: AssemblyVersion("2.1.1.0")]
+[assembly: AssemblyFileVersion("2.1.1.0")]
diff --git a/RogueLibs/RogueLibs.cs b/RogueLibs/RogueLibs.cs
index f71cd6a33..105b1e25c 100644
--- a/RogueLibs/RogueLibs.cs
+++ b/RogueLibs/RogueLibs.cs
@@ -22,7 +22,7 @@ public static class RogueLibs
///
/// ' version. Do not use this value in your attribute!
///
- public const string pluginVersion = "2.1";
+ public const string pluginVersion = "2.1.1";
///
/// Main instance.
diff --git a/RogueLibs/RogueLibsPlugin.cs b/RogueLibs/RogueLibsPlugin.cs
index 18a2420e7..110f6bbb0 100644
--- a/RogueLibs/RogueLibsPlugin.cs
+++ b/RogueLibs/RogueLibsPlugin.cs
@@ -465,7 +465,7 @@ protected static bool ScrollingMenu_Setup(ScrollingMenu __instance, ButtonData m
myButtonData.scrollingHighlighted4 = (__instance.menuType == "Items" || __instance.menuType == "TraitUnlocks") && myUnlock.notActive; // gray 'not active' highlight
myButtonData.highlightedSprite = __instance.solidObjectButton;
}
- else if ((custom == null && myUnlock.cost != 0) || custom.UnlockCost != null)
+ else if ((custom == null && myUnlock.cost != 0) || custom?.UnlockCost != null)
{ // not unlocked, original mutator OR custom and can be purchased
myButtonData.buttonText += " - $" + myUnlock.cost;
myButtonData.scrollingHighlighted2 = true; // blue 'purchasable' highlight
@@ -865,7 +865,7 @@ protected static bool CharacterCreation_Setup(CharacterCreation __instance, Butt
myButtonData.scrollingHighlighted4 = false;
myButtonData.highlightedSprite = __instance.solidObjectButton;
}
- else if ((custom == null && myUnlock.cost != 0) || custom.UnlockCost != null) // not unlocked, original mutator OR custom and can be purchased
+ else if ((custom == null && myUnlock.cost != 0) || custom?.UnlockCost != null) // not unlocked, original mutator OR custom and can be purchased
{
myButtonData.buttonText = __instance.gc.nameDB.GetName(myUnlock.unlockName, myUnlock.unlockNameType) + " - $" + myUnlock.cost;
myButtonData.scrollingHighlighted2 = true; // blue 'purchasable' highlight
diff --git a/md/4. Changelog.md b/md/4. Changelog.md
index d9a734ffe..b12b3ea73 100644
--- a/md/4. Changelog.md
+++ b/md/4. Changelog.md
@@ -16,6 +16,9 @@
## Changelog ##
+#### RogueLibs v2.1.1 ####
+- Fixed an error, when Mutator Menu didn't open because of a null reference;
+
#### RogueLibs v2.1 ####
- Added `OnEnabled`, `OnDisabled` and `OnChangedState` events to `CustomMutator`;