using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using R2API; using RoR2; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PartialCommand")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("PartialCommand")] [assembly: AssemblyTitle("PartialCommand")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PartialCommand { [HarmonyPatch] internal static class CommandChancePatch { private static readonly List Enabled = new List(3); private static Xoroshiro128Plus rng; private static string lastDescription; internal static void Init() { Run.onRunStartGlobal += OnRunStart; } internal static void Dispose() { Run.onRunStartGlobal -= OnRunStart; rng = null; lastDescription = null; Enabled.Clear(); } private static void OnRunStart(Run run) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown rng = new Xoroshiro128Plus(run.seed ^ 0x9E3779B97F4A7C15uL); lastDescription = null; } [HarmonyPrefix] [HarmonyPatch(typeof(PickupDropletController), "CreatePickupDroplet", new Type[] { typeof(CreatePickupInfo), typeof(Vector3), typeof(Vector3) })] private static void MaybeMakeChoosable(ref CreatePickupInfo pickupInfo) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { return; } PickupArtifactFlag artifactFlag = pickupInfo.artifactFlag; if (((Enum)artifactFlag).HasFlag((Enum)(object)(PickupArtifactFlag)1) || ((Enum)artifactFlag).HasFlag((Enum)(object)(PickupArtifactFlag)2)) { return; } RunArtifactManager instance = RunArtifactManager.instance; if (!Object.op_Implicit((Object)(object)instance)) { return; } if (instance.IsArtifactEnabled(Artifacts.commandArtifactDef)) { Describe("Artifact of Command is enabled, so every drop is already choosable. PartialCommand is standing down for this run."); return; } float num = ChanceForCurrentRun(instance); if (Enabled.Count != 0) { Describe(Summarise(num)); if (!(num <= 0f) && (!(num < 100f) || !(NextPercent() >= num))) { ref PickupArtifactFlag artifactFlag2 = ref pickupInfo.artifactFlag; artifactFlag2 = (PickupArtifactFlag)((uint)artifactFlag2 | 1u); } } } private static float ChanceForCurrentRun(RunArtifactManager artifacts) { Enabled.Clear(); float num = 0f; float num2 = 1f; foreach (PartialArtifact item in PartialArtifacts.All) { if (!((Object)(object)item.Def == (Object)null) && artifacts.IsArtifactEnabled(item.Def)) { float num3 = ModConfig.Percent(item.Chance); Enabled.Add(item); if (num3 > num) { num = num3; } num2 *= 1f - num3 / 100f; } } if (Enabled.Count == 0) { return 0f; } return Mathf.Clamp((ModConfig.MultipleArtifacts.Value == ModConfig.StackMode.Independent) ? ((1f - num2) * 100f) : num, 0f, ModConfig.Percent(ModConfig.MaximumChance)); } private static string Summarise(float chance) { List list = new List(Enabled.Count); foreach (PartialArtifact item in Enabled) { list.Add(item.DisplayName + " " + Format(ModConfig.Percent(item.Chance)) + "%"); } string text = string.Join(" + ", list.ToArray()); if (Enabled.Count > 1) { text = text + " [" + ModConfig.MultipleArtifacts.Value.ToString() + "]"; } text = text + " -> " + Format(chance) + "% of drops choosable this run."; float num = ModConfig.Percent(ModConfig.MaximumChance); if (num < 100f) { text = text + " (MaximumChance ceiling: " + Format(num) + "%)"; } if (chance <= 0f) { text += " That is zero, so nothing will be choosable - check the Chances values and MaximumChance in the config."; } return text; } private static string Format(float value) { return value.ToString("0.##", CultureInfo.InvariantCulture); } private static void Describe(string message) { if (!(message == lastDescription)) { lastDescription = message; Plugin.Log.LogInfo((object)message); } } private static float NextPercent() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (rng == null) { rng = new Xoroshiro128Plus((ulong)DateTime.UtcNow.Ticks); } return rng.nextNormalizedFloat * 100f; } } internal static class IconFactory { private const int Size = 128; private const int Supersample = 3; internal static string IconDirectory; internal static Sprite Build(string key, float fraction, bool selected) { Sprite val = TryLoadFromDisk(key, selected); if (!((Object)(object)val != (Object)null)) { return Generate(key, fraction, selected); } return val; } private static Sprite TryLoadFromDisk(string key, bool selected) { if (string.IsNullOrEmpty(IconDirectory)) { return null; } string text = Path.Combine(IconDirectory, key.ToLowerInvariant() + (selected ? "_on.png" : "_off.png")); if (!File.Exists(text)) { return null; } Texture2D val = NewTexture(key + (selected ? "_on" : "_off")); if (!ImageConversion.LoadImage(val, File.ReadAllBytes(text), false)) { Object.Destroy((Object)(object)val); Plugin.Log.LogWarning((object)("Could not decode icon at " + text + "; falling back to the generated one.")); return null; } return MakeSprite(val); } private static Sprite Generate(string key, float fraction, bool selected) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) Color val = (selected ? new Color(1f, 0.8f, 0.38f) : new Color(0.4f, 0.41f, 0.45f)); Color val2 = (selected ? new Color(1f, 0.56f, 0.2f) : new Color(0.29f, 0.3f, 0.33f)); Color val3 = (selected ? new Color(0.26f, 0.2f, 0.13f) : new Color(0.16f, 0.16f, 0.18f)); float num = Mathf.Clamp01(fraction) * MathF.PI * 2f; float num2 = 1f / 9f; Color[] array = (Color[])(object)new Color[16384]; for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float num3 = 0f; float num4 = 0f; float num5 = 0f; float num6 = 0f; for (int k = 0; k < 3; k++) { for (int l = 0; l < 3; l++) { float num7 = (float)j + ((float)l + 0.5f) / 3f - 0.5f - 63.5f; float num8 = (float)i + ((float)k + 0.5f) / 3f - 0.5f - 63.5f; float num9 = Mathf.Sqrt(num7 * num7 + num8 * num8); Color val4; if (num9 >= 50.56f && num9 <= 60.16f) { val4 = val; } else { if (!(num9 <= 42.24f)) { continue; } float num10 = Mathf.Atan2(num7, num8); if (num10 < 0f) { num10 += MathF.PI * 2f; } val4 = ((num10 < num) ? val2 : val3); } num3 += val4.r; num4 += val4.g; num5 += val4.b; num6 += 1f; } } array[i * 128 + j] = (Color)((num6 > 0f) ? new Color(num3 / num6, num4 / num6, num5 / num6, num6 * num2) : Color.clear); } } Texture2D obj = NewTexture(key + (selected ? "_on" : "_off")); obj.SetPixels(array); obj.Apply(false, false); return MakeSprite(obj); } private static Texture2D NewTexture(string name) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown return new Texture2D(128, 128, (TextureFormat)4, false) { name = "PartialCommand_" + name, wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1, hideFlags = (HideFlags)32 }; } private static Sprite MakeSprite(Texture2D texture) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Sprite obj = Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f), 100f); ((Object)obj).name = ((Object)texture).name; ((Object)obj).hideFlags = (HideFlags)32; return obj; } } internal static class ModConfig { internal enum StackMode { Highest, Independent } internal static ConfigEntry DirectChance; internal static ConfigEntry SuggestChance; internal static ConfigEntry AskChance; internal static ConfigEntry MultipleArtifacts; internal static ConfigEntry MaximumChance; internal static void Init(ConfigFile file) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown DirectChance = file.Bind("Chances", "Direct", 75f, new ConfigDescription("Percent of dropped items that become choosable under Artifact of Direct.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); SuggestChance = file.Bind("Chances", "Suggest", 50f, new ConfigDescription("Percent of dropped items that become choosable under Artifact of Suggest.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); AskChance = file.Bind("Chances", "Ask", 25f, new ConfigDescription("Percent of dropped items that become choosable under Artifact of Ask.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); MultipleArtifacts = file.Bind("Behaviour", "MultipleArtifacts", StackMode.Highest, "What happens when several of these artifacts are enabled at once. Highest: only the biggest chance applies. Independent: each one rolls on its own, so 75 + 50 lands at 87.5%."); MaximumChance = file.Bind("Behaviour", "MaximumChance", 100f, new ConfigDescription("Hard ceiling on the combined chance, applied after the artifacts and the stacking mode are worked out. A safety valve for odd combinations; 100 disables it.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); } internal static float Percent(ConfigEntry entry) { float value = entry.Value; if (float.IsNaN(value)) { return 0f; } return Mathf.Clamp(value, 0f, 100f); } } internal sealed class PartialArtifact { internal string Key { get; } internal string DisplayName { get; } internal ConfigEntry Chance { get; } internal ArtifactDef Def { get; set; } internal PartialArtifact(string key, string displayName, ConfigEntry chance) { Key = key; DisplayName = displayName; Chance = chance; } } internal static class PartialArtifacts { internal static readonly List All = new List(); internal static void Register() { All.Clear(); Add(new PartialArtifact("Direct", "Artifact of Direct", ModConfig.DirectChance)); Add(new PartialArtifact("Suggest", "Artifact of Suggest", ModConfig.SuggestChance)); Add(new PartialArtifact("Ask", "Artifact of Ask", ModConfig.AskChance)); } private static void Add(PartialArtifact artifact) { string text = "PARTIALCOMMAND_" + artifact.Key.ToUpperInvariant(); string text2 = text + "_NAME"; string text3 = text + "_DESCRIPTION"; float num = ModConfig.Percent(artifact.Chance); LanguageAPI.Add(text2, artifact.DisplayName); LanguageAPI.Add(text3, "" + num.ToString("0.##", CultureInfo.InvariantCulture) + "% of dropped items let you pick what they become. The rest drop as normal."); ArtifactDef val = ScriptableObject.CreateInstance(); val.cachedName = "PARTIALCOMMAND_" + artifact.Key; val.nameToken = text2; val.descriptionToken = text3; val.unlockableDef = null; val.requiredExpansion = null; val.smallIconSelectedSprite = IconFactory.Build(artifact.Key, num / 100f, selected: true); val.smallIconDeselectedSprite = IconFactory.Build(artifact.Key, num / 100f, selected: false); if (!ContentAddition.AddArtifactDef(val)) { Plugin.Log.LogError((object)("R2API rejected " + artifact.DisplayName + "; it will not appear in the lobby.")); return; } artifact.Def = val; All.Add(artifact); Plugin.Log.LogInfo((object)("Registered " + artifact.DisplayName + " at " + num + "%.")); } } [BepInPlugin("com.zackman.partialcommand", "PartialCommand", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("Risk of Rain 2.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.zackman.partialcommand"; public const string Name = "PartialCommand"; public const string Version = "0.1.0"; private Harmony harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Init(((BaseUnityPlugin)this).Config); IconFactory.IconDirectory = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? string.Empty, "icons"); PartialArtifacts.Register(); CommandChancePatch.Init(); harmony = new Harmony("com.zackman.partialcommand"); harmony.PatchAll(typeof(CommandChancePatch)); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } CommandChancePatch.Dispose(); } } }