Decompiled source of RiskOfChaos v2.3.1
patchers/RiskOfChaos/RiskOfChaosPatcher.dll
Decompiled 3 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Mono.Cecil; [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("RiskOfChaosPatcher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c158cf629270665c915140fc70b979c1b9cb1479")] [assembly: AssemblyProduct("RiskOfChaosPatcher")] [assembly: AssemblyTitle("RiskOfChaosPatcher")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 RiskOfChaosPatcher { internal static class AssemblyNames { public const string RoR2 = "RoR2.dll"; } internal class LogWriter { private ManualLogSource _logSource; public LogWriter(ManualLogSource logSource) { _logSource = logSource; } public LogWriter() : this(null) { } public void SetLogSource(ManualLogSource logSource) { _logSource = logSource; } public void Fatal(object message) { ManualLogSource logSource = _logSource; if (logSource != null) { logSource.LogFatal(message); } } public void Error(object message) { ManualLogSource logSource = _logSource; if (logSource != null) { logSource.LogError(message); } } public void Warning(object message) { ManualLogSource logSource = _logSource; if (logSource != null) { logSource.LogWarning(message); } } public void Message(object message) { ManualLogSource logSource = _logSource; if (logSource != null) { logSource.LogMessage(message); } } public void Info(object message) { ManualLogSource logSource = _logSource; if (logSource != null) { logSource.LogInfo(message); } } [Conditional("DEBUG")] public void Debug(object message) { ManualLogSource logSource = _logSource; if (logSource != null) { logSource.LogDebug(message); } } } public class ProjectilePatcher { private static readonly LogWriter _log = new LogWriter(); public static IEnumerable<string> TargetDLLs { get; } = new <>z__ReadOnlySingleElementList<string>("RoR2.dll"); public static void Initialize() { _log.SetLogSource(Logger.CreateLogSource("ProjectilePatcher")); } public static void Patch(AssemblyDefinition assembly) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown TypeDefinition type = assembly.MainModule.GetType("RoR2.Projectile.FireProjectileInfo"); if (type == null) { _log.Error("Failed to find type: FireProjectileInfo"); return; } TypeDefinition type2 = assembly.MainModule.GetType("RoR2.Projectile.ProjectileManager/PlayerFireProjectileMessage"); if (type2 == null) { _log.Error("Failed to find type: PlayerFireProjectileMessage"); return; } TypeDefinition type3 = assembly.MainModule.GetType("RoR2.ProcChainMask"); if (type3 == null) { _log.Error("Failed to find type: ProcChainMask"); return; } TypeReference val = assembly.MainModule.ImportReference(typeof(float)); addField(type, new FieldDefinition("roc_procCoefficientOverridePlusOne", (FieldAttributes)6, val)); addField(type2, new FieldDefinition("roc_procCoefficientOverridePlusOne", (FieldAttributes)6, val)); addField(type2, new FieldDefinition("roc_procChainMask", (FieldAttributes)6, (TypeReference)(object)type3)); } private static void addField(TypeDefinition declaringType, FieldDefinition field) { declaringType.Fields.Add(field); } } } internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T> { object IEnumerator.Current => _item; T IEnumerator<T>.Current => _item; public Enumerator(T item) { _item = item; } bool IEnumerator.MoveNext() { if (!_moveNextCalled) { return _moveNextCalled = true; } return false; } void IEnumerator.Reset() { _moveNextCalled = false; } void IDisposable.Dispose() { } } int ICollection.Count => 1; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => 1; T IReadOnlyList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection<T>.Count => 1; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } public <>z__ReadOnlySingleElementList(T item) { _item = item; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.CopyTo(Array array, int index) { array.SetValue(_item, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return EqualityComparer<T>.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { if (!EqualityComparer<T>.Default.Equals(_item, (T)value)) { return -1; } return 0; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return new Enumerator(_item); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return EqualityComparer<T>.Default.Equals(_item, item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { if (!EqualityComparer<T>.Default.Equals(_item, item)) { return -1; } return 0; } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } }
plugins/RiskOfChaos/RiskOfChaos.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Barrel; using EntityStates.Captain.Weapon; using EntityStates.Croco; using EntityStates.GoldGat; using EntityStates.GolemMonster; using EntityStates.Interactables.GoldBeacon; using EntityStates.Merc; using EntityStates.VoidInfestor; using HG; using HG.Reflection; using HarmonyLib; using IL.EntityStates; using IL.EntityStates.Bandit2.Weapon; using IL.EntityStates.Geode; using IL.EntityStates.GoldGat; using IL.EntityStates.GolemMonster; using IL.EntityStates.Merc; using IL.EntityStates.Railgunner.Scope; using IL.EntityStates.ShrineHalcyonite; using IL.EntityStates.Toolbot; using IL.EntityStates.VoidSurvivor.Weapon; using IL.RoR2; using IL.RoR2.CharacterAI; using IL.RoR2.Items; using IL.RoR2.Orbs; using IL.RoR2.Projectile; using IL.RoR2.Skills; using IL.RoR2.UI; using KinematicCharacterController; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using MonoMod.Cil; using MonoMod.RuntimeDetour; using MonoMod.Utils; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using On.RoR2; using On.RoR2.CameraModes; using On.RoR2.CharacterAI; using On.RoR2.Orbs; using On.RoR2.Projectile; using On.RoR2.UI; using On.RoR2.UI.LogBook; using On.RoR2.UI.MainMenu; using ProperSave; using R2API; using R2API.Networking; using R2API.Networking.Interfaces; using R2API.Utils; using Rewired; using Rewired.ComponentControls.Effects; using RiskOfChaos.ChatMessages; using RiskOfChaos.Collections; using RiskOfChaos.Collections.CatalogIndex; using RiskOfChaos.Collections.ParsedValue; using RiskOfChaos.Components; using RiskOfChaos.Components.CostProviders; using RiskOfChaos.Components.MaterialInterpolation; using RiskOfChaos.ConfigHandling; using RiskOfChaos.ConfigHandling.AcceptableValues; using RiskOfChaos.Content; using RiskOfChaos.Content.AssetCollections; using RiskOfChaos.Content.Logbook; using RiskOfChaos.Content.Orbs; using RiskOfChaos.EffectDefinitions; using RiskOfChaos.EffectDefinitions.Character; using RiskOfChaos.EffectDefinitions.Character.Equipment; using RiskOfChaos.EffectDefinitions.UI; using RiskOfChaos.EffectDefinitions.World; using RiskOfChaos.EffectDefinitions.World.Items; using RiskOfChaos.EffectDefinitions.World.Knockback; using RiskOfChaos.EffectDefinitions.World.RunTimer; using RiskOfChaos.EffectHandling; using RiskOfChaos.EffectHandling.Controllers; using RiskOfChaos.EffectHandling.Controllers.ChatVoting; using RiskOfChaos.EffectHandling.Controllers.ChatVoting.Twitch; using RiskOfChaos.EffectHandling.EffectClassAttributes; using RiskOfChaos.EffectHandling.EffectClassAttributes.Data; using RiskOfChaos.EffectHandling.EffectClassAttributes.Methods; using RiskOfChaos.EffectHandling.EffectComponents; using RiskOfChaos.EffectHandling.EffectComponents.SubtitleProviders; using RiskOfChaos.EffectHandling.Formatting; using RiskOfChaos.EffectUtils.Character.AllSkillsAgile; using RiskOfChaos.EffectUtils.Character.Player.Items; using RiskOfChaos.EffectUtils.World; using RiskOfChaos.EffectUtils.World.AllChanceShrines; using RiskOfChaos.EffectUtils.World.Items; using RiskOfChaos.EffectUtils.World.Spawn; using RiskOfChaos.ModCompatibility; using RiskOfChaos.ModificationController; using RiskOfChaos.ModificationController.AttackDelay; using RiskOfChaos.ModificationController.Camera; using RiskOfChaos.ModificationController.Cost; using RiskOfChaos.ModificationController.Director; using RiskOfChaos.ModificationController.Effect; using RiskOfChaos.ModificationController.Gravity; using RiskOfChaos.ModificationController.HoldoutZone; using RiskOfChaos.ModificationController.Knockback; using RiskOfChaos.ModificationController.Pickups; using RiskOfChaos.ModificationController.Projectile; using RiskOfChaos.ModificationController.SkillSlots; using RiskOfChaos.ModificationController.TimeScale; using RiskOfChaos.ModificationController.UI; using RiskOfChaos.Networking; using RiskOfChaos.Networking.Components; using RiskOfChaos.Networking.SyncList; using RiskOfChaos.Patches; using RiskOfChaos.Patches.AttackHooks; using RiskOfChaos.SaveHandling; using RiskOfChaos.SaveHandling.DataContainers; using RiskOfChaos.SaveHandling.DataContainers.EffectHandlerControllers; using RiskOfChaos.ScreenEffect; using RiskOfChaos.Serialization.Converters; using RiskOfChaos.Trackers; using RiskOfChaos.Twitch; using RiskOfChaos.UI.ActiveEffectsPanel; using RiskOfChaos.UI.ChatVoting; using RiskOfChaos.UI.NextEffectDisplay; using RiskOfChaos.Utilities; using RiskOfChaos.Utilities.Assets; using RiskOfChaos.Utilities.BodySnapshots; using RiskOfChaos.Utilities.Comparers; using RiskOfChaos.Utilities.DropTables; using RiskOfChaos.Utilities.Extensions; using RiskOfChaos.Utilities.Interpolation; using RiskOfChaos.Utilities.ParsedValueHolders; using RiskOfChaos.Utilities.PersistentSaveData; using RiskOfChaos.Utilities.Pickup; using RiskOfChaos.Utilities.Pool; using RiskOfChaos.Utilities.Reflection; using RiskOfChaos_PatcherInterop; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RiskOfTwitch; using RiskOfTwitch.Chat.Message; using RiskOfTwitch.Chat.Notification; using RiskOfTwitch.EventSub; using RiskOfTwitch.Logging; using RiskOfTwitch.User; using RoR2; using RoR2.Artifacts; using RoR2.CameraModes; using RoR2.CharacterAI; using RoR2.ConVar; using RoR2.ContentManagement; using RoR2.ExpansionManagement; using RoR2.Hologram; using RoR2.Items; using RoR2.Navigation; using RoR2.Networking; using RoR2.Orbs; using RoR2.Projectile; using RoR2.Skills; using RoR2.Stats; using RoR2.UI; using RoR2.UI.LogBook; using RoR2.UI.MainMenu; using RoR2.UI.SkinControllers; using RoR2BepInExPack.Utilities; using TMPro; using Unity; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: NetworkCompatibility(/*Could not decode attribute arguments.*/)] [assembly: OptIn] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyInformationalVersion("1.0.0+0bc92c17cfeb39ad8e315081998979773a7d698c")] [assembly: AssemblyProduct("RiskOfChaos")] [assembly: AssemblyTitle("RiskOfChaos")] [assembly: AssemblyCompany("RiskOfChaos")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("2.0.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] [Microsoft.CodeAnalysis.Embedded] [CompilerGenerated] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [Microsoft.CodeAnalysis.Embedded] [CompilerGenerated] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } internal sealed class IsExternalInit { } } namespace RiskOfChaos { public static class Configs { public static class ChatVoting { public enum ChatVotingMode { Disabled, Twitch } [CompilerGenerated] private static class <>O { public static UnityAction <0>__AuthenticateNewToken; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__12_1; internal void <Bind>b__12_1() { ChatVoting.OnReconnectButtonPressed?.Invoke(); } } public const string SECTION_NAME = "Streamer Integration"; public static readonly ConfigHolder<ChatVotingMode> VotingMode = ConfigFactory<ChatVotingMode>.CreateConfig("Voting Mode", ChatVotingMode.Disabled).OptionConfig((BaseOptionConfig)new ChoiceConfig()).Build(); public static readonly ConfigHolder<string> OverrideChannelName = ConfigFactory<string>.CreateConfig("Override Channel Name", string.Empty).Description("Used to specify a different channel the mod will connect to, leave empty to use the channel of the account that you authenticated with").OptionConfig((BaseOptionConfig)new InputFieldConfig { lineType = (LineType)0, richText = false, submitOn = (SubmitEnum)6, checkIfDisabled = new IsDisabledDelegate(isVotingDisabled) }) .Build(); private const int NUM_EFFECT_OPTIONS_MIN_VALUE = 2; public static readonly ConfigHolder<int> NumEffectOptions; public static readonly ConfigHolder<bool> IncludeRandomEffectInVote; public static readonly ConfigHolder<VoteWinnerSelectionMode> WinnerSelectionMode; public static event Action OnReconnectButtonPressed; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool isVotingDisabled() { return VotingMode.Value == ChatVotingMode.Disabled; } internal static void Bind(ConfigFile file) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown bindConfig(VotingMode); object obj = <>O.<0>__AuthenticateNewToken; if (obj == null) { UnityAction val = TwitchAuthenticationManager.AuthenticateNewToken; <>O.<0>__AuthenticateNewToken = val; obj = (object)val; } ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("Authenticate (Twitch)", "Streamer Integration", "Authenticate your account with Risk of Chaos (Opens browser tab)", "Open", (UnityAction)obj), "RoC_Config_General", "Risk of Chaos: General"); bindConfig(OverrideChannelName); object obj2 = <>c.<>9__12_1; if (obj2 == null) { UnityAction val2 = delegate { ChatVoting.OnReconnectButtonPressed?.Invoke(); }; <>c.<>9__12_1 = val2; obj2 = (object)val2; } ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("Manual reconnect", "Streamer Integration", "Use this to manually reconnect the mod to your channel if connection is lost", "Reconnect", (UnityAction)obj2), "RoC_Config_General", "Risk of Chaos: General"); bindConfig(NumEffectOptions); bindConfig(IncludeRandomEffectInVote); bindConfig(WinnerSelectionMode); void bindConfig(ConfigHolderBase configHolder) { configHolder.Bind(file, "Streamer Integration", "RoC_Config_General", "Risk of Chaos: General"); } } static ChatVoting() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0069: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00b6: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown //IL_00f1: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown //IL_012c: Expected O, but got Unknown ConfigFactory<int> configFactory = ConfigFactory<int>.CreateConfig("Num Effect Options", 3).Description("The number of effects viewers can pick from during voting").AcceptableValues((AcceptableValueBase)(object)new AcceptableValueMin<int>(2)); IntFieldConfig val = new IntFieldConfig(); ((NumericFieldConfig<int>)val).Min = 2; ((BaseOptionConfig)val).checkIfDisabled = new IsDisabledDelegate(isVotingDisabled); NumEffectOptions = configFactory.OptionConfig((BaseOptionConfig)val).Build(); IncludeRandomEffectInVote = ConfigFactory<bool>.CreateConfig("Include Random Effect In Vote", defaultValue: true).Description("If this is enabled, an additional option will be added to the effect vote list, which will activate a random effect instead of a specific one").OptionConfig((BaseOptionConfig)new CheckBoxConfig { checkIfDisabled = new IsDisabledDelegate(isVotingDisabled) }) .Build(); WinnerSelectionMode = ConfigFactory<VoteWinnerSelectionMode>.CreateConfig("Vote Winner Selection Mode", VoteWinnerSelectionMode.MostVotes).Description("How the winner of any vote should be selected.\r\n\r\nMostVotes (Default): The vote with the most votes will be selected, if there is a tie, a random tied option is selected\r\nRandomProportional: Every option has a chance to be selected, weighted by the number of votes. Ex. an option with 70% of the votes will have a 70% chance to be selected.").OptionConfig((BaseOptionConfig)new ChoiceConfig { checkIfDisabled = new IsDisabledDelegate(isVotingDisabled) }) .Build(); } } public static class ChatVotingUI { public enum VoteDisplayScalingMode { Disabled, Smooth, Immediate } public const string SECTION_NAME = "Streamer Integration: UI"; public static readonly ConfigHolder<float> VoteDisplayScaleMultiplier; public static readonly ConfigHolder<Color> VoteDisplayTextColor; public static readonly ConfigHolder<Color> VoteDisplayBackgroundColor; public static readonly ConfigHolder<VoteDisplayScalingMode> VoteDisplayScalingModeConfig; internal static void Bind(ConfigFile file) { bindConfig(VoteDisplayScaleMultiplier); bindConfig(VoteDisplayTextColor); bindConfig(VoteDisplayBackgroundColor); bindConfig(VoteDisplayScalingModeConfig); void bindConfig(ConfigHolderBase configHolder) { configHolder.Bind(file, "Streamer Integration: UI", "RoC_Config_General", "Risk of Chaos: General"); } } static ChatVotingUI() { //IL_0028: 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_0038: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0048: Expected O, but got Unknown //IL_0075: 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_0093: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown ConfigFactory<float> configFactory = ConfigFactory<float>.CreateConfig("Vote Display UI Scale", 1f).Description("The scale multiplier of the effect vote options display").AcceptableValues((AcceptableValueBase)(object)new AcceptableValueMin<float>(0f)); FloatFieldConfig val = new FloatFieldConfig(); ((NumericFieldConfig<float>)val).FormatString = "{0}X"; ((NumericFieldConfig<float>)val).Min = 0f; VoteDisplayScaleMultiplier = configFactory.OptionConfig((BaseOptionConfig)val).MovedFrom("Streamer Integration").Build(); VoteDisplayTextColor = ConfigFactory<Color>.CreateConfig("Vote Display Text Color", new Color(1f, 1f, 1f, 1f)).Description("The color of the effect voting options text").OptionConfig((BaseOptionConfig)new ColorOptionConfig()) .MovedFrom("Streamer Integration") .Build(); VoteDisplayBackgroundColor = ConfigFactory<Color>.CreateConfig("Vote Display Background Color", new Color(0.0943f, 0.0943f, 0.0943f, 0.3373f)).Description("The color of the effect voting options backdrop").OptionConfig((BaseOptionConfig)new ColorOptionConfig()) .MovedFrom("Streamer Integration") .Build(); VoteDisplayScalingModeConfig = ConfigFactory<VoteDisplayScalingMode>.CreateConfig("Vote Display Text Scaling Mode", VoteDisplayScalingMode.Smooth).Description("Controls how the vote options text will be scaled depending on how many votes that option has\r\n\r\nDisabled: No scaling is done, all options are always displayed exactly the same\r\n\r\nSmooth: Scaling is done, and interpolated to smoothly approach the target scale\r\n\r\nImmediate: Scaling is done, and applied immediately instead of smoothly interpolating").OptionConfig((BaseOptionConfig)new ChoiceConfig()) .Build(); } } public static class EffectSelection { [CompilerGenerated] private static class <>O { public static IsDisabledDelegate <0>__perStageEffectListDisabled; } public const string SECTION_NAME = "Effect Selection"; public static readonly ConfigHolder<bool> SeededEffectSelection = ConfigFactory<bool>.CreateConfig("Seeded Effect Selection", defaultValue: false).Description("If the effects should be consistent with the run seed, only really changes anything if you're setting run seeds manually").OptionConfig((BaseOptionConfig)new CheckBoxConfig()) .MovedFrom("General") .Build(); public static readonly ConfigHolder<bool> PerStageEffectListEnabled = ConfigFactory<bool>.CreateConfig("Per-Stage Effect List", defaultValue: false).Description("If enabled, a subsection of all effects is generated each stage and only effects from this list are activated.\r\nNot supported in any chat voting mode").OptionConfig((BaseOptionConfig)new CheckBoxConfig()) .Build(); public static ConfigHolder<int> PerStageEffectListSize { get; private set; } private static bool perStageEffectListDisabled() { return !PerStageEffectListEnabled.Value; } internal static void Bind(ConfigFile file) { bindConfig(SeededEffectSelection); bindConfig(PerStageEffectListEnabled); ((ResourceAvailability)(ref ChaosEffectCatalog.Availability)).CallWhenAvailable((Action)delegate { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown ConfigFactory<int> configFactory = ConfigFactory<int>.CreateConfig("Effect List Size", 50).Description("The size of the per-stage effect list\r\nNot supported in any chat voting mode").AcceptableValues((AcceptableValueBase)(object)new AcceptableValueRange<int>(1, ChaosEffectCatalog.EffectCount)); IntSliderConfig val = new IntSliderConfig { min = 1, max = ChaosEffectCatalog.EffectCount }; object obj = <>O.<0>__perStageEffectListDisabled; if (obj == null) { IsDisabledDelegate val2 = perStageEffectListDisabled; <>O.<0>__perStageEffectListDisabled = val2; obj = (object)val2; } ((BaseOptionConfig)val).checkIfDisabled = (IsDisabledDelegate)obj; PerStageEffectListSize = configFactory.OptionConfig((BaseOptionConfig)val).Build(); bindConfig(PerStageEffectListSize); }); void bindConfig(ConfigHolderBase config) { config.Bind(file, "Effect Selection", "RoC_Config_General", "Risk of Chaos: General"); } } } public static class General { public const string SECTION_NAME = "General"; public static readonly ConfigHolder<bool> DisableEffectDispatching = ConfigFactory<bool>.CreateConfig("Disable Effect Activation", defaultValue: false).Description("If effect activation should be disabled completely").OptionConfig((BaseOptionConfig)new CheckBoxConfig()) .Networked() .Build(); private const float TIME_BETWEEN_EFFECTS_MIN_VALUE = 5f; public static readonly ConfigHolder<float> TimeBetweenEffects; public static readonly ConfigHolder<bool> RunEffectsTimerWhileRunTimerPaused; private static bool effectDispatchingDisabled() { return DisableEffectDispatching.LocalValue; } internal static void Bind(ConfigFile file) { bindConfig(DisableEffectDispatching); bindConfig(TimeBetweenEffects); bindConfig(RunEffectsTimerWhileRunTimerPaused); void bindConfig(ConfigHolderBase config) { config.Bind(file, "General", "RoC_Config_General", "Risk of Chaos: General"); } } static General() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0056: 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_0066: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_0088: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00c3: Expected O, but got Unknown ConfigFactory<float> configFactory = ConfigFactory<float>.CreateConfig("Effect Timer", 60f).Description("How often new effects should happen").AcceptableValues((AcceptableValueBase)(object)new AcceptableValueMin<float>(5f)); FloatFieldConfig val = new FloatFieldConfig(); ((NumericFieldConfig<float>)val).FormatString = "{0}s"; ((NumericFieldConfig<float>)val).Min = 5f; ((BaseOptionConfig)val).checkIfDisabled = new IsDisabledDelegate(effectDispatchingDisabled); TimeBetweenEffects = configFactory.OptionConfig((BaseOptionConfig)val).Build(); RunEffectsTimerWhileRunTimerPaused = ConfigFactory<bool>.CreateConfig("Dispatch Effects While Timer Paused", defaultValue: true).Description("If the mod should activate effects while the run timer is paused (in Bazaar, Gilded Coast, etc.)").OptionConfig((BaseOptionConfig)new CheckBoxConfig { checkIfDisabled = new IsDisabledDelegate(effectDispatchingDisabled) }) .Networked() .Build(); } } internal static class Metadata { public const string SECTION_NAME = "META"; public const uint CONFIG_FILE_VERSION_LEGACY = 0u; public const uint CURRENT_CONFIG_FILE_VERSION = 10u; public static ConfigHolder<uint> ConfigFileVersion = ConfigFactory<uint>.CreateConfig("VERSION", 0u).Description("Used internally by the mod\r\nDO NOT MODIFY MANUALLY").Build(); internal static void Bind(ConfigFile file) { bindConfig(ConfigFileVersion); void bindConfig(ConfigHolderBase config) { config.Bind(file, "META", "RoC_Config_General", "Risk of Chaos: General"); } } private static bool isOutdatedVersion() { if (ConfigFileVersion.Value < 10) { return ConfigManager.AllConfigs.Any((ConfigHolderBase c) => !c.IsDefaultValue); } return false; } internal static void CheckVersion() { if (isOutdatedVersion()) { PopupAlertQueue.EnqueueAlert(delegate(SimpleDialogBox dialogBox) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) dialogBox.headerToken = new TokenParamsPair("POPUP_CONFIG_UPDATE_HEADER", Array.Empty<object>()); dialogBox.descriptionToken = new TokenParamsPair("POPUP_CONFIG_UPDATE_DESCRIPTION", Array.Empty<object>()); dialogBox.AddCommandButton("roc_delete_config", "POPUP_CONFIG_UPDATE_RESET", Array.Empty<object>()); dialogBox.AddCancelButton("POPUP_CONFIG_UPDATE_IGNORE", Array.Empty<object>()); }); } ConfigFileVersion.LocalValue = 10u; } } public static class UI { public enum NextEffectTimerDisplayType : byte { Never, WhenRunTimerUnavailable, Always } public const string SECTION_NAME = "UI"; public static readonly ConfigHolder<bool> HideActiveEffectsPanel = ConfigFactory<bool>.CreateConfig("Hide Active Effects Panel", defaultValue: false).Description("Hides the active effects list under the Objectives display").OptionConfig((BaseOptionConfig)new CheckBoxConfig()) .Build(); public static readonly ConfigHolder<bool> DisplayAlwaysActiveEffects = ConfigFactory<bool>.CreateConfig("Display Permanently Active Effects", defaultValue: false).Description("If effects configured to always be active should be displayed in the active effects panel").OptionConfig((BaseOptionConfig)new CheckBoxConfig { checkIfDisabled = new IsDisabledDelegate(activeEffectsPanelHidden) }) .Build(); public static readonly ConfigHolder<Color> ActiveEffectsTextColor = ConfigFactory<Color>.CreateConfig("Active Effect Text Color", Color.white).Description("The color of the effect names in the \"Active Effects\" list").OptionConfig((BaseOptionConfig)new ColorOptionConfig { checkIfDisabled = new IsDisabledDelegate(activeEffectsPanelHidden) }) .MovedFrom("General") .Build(); public static readonly ConfigHolder<bool> DisplayNextEffect = ConfigFactory<bool>.CreateConfig("Display Next Effect", defaultValue: true).Description("Displays the next effect that will happen.\r\nOnly works if chat voting is disabled and seeded mode is enabled").OptionConfig((BaseOptionConfig)new CheckBoxConfig()) .Build(); public static readonly ConfigHolder<NextEffectTimerDisplayType> NextEffectTimerDisplayMode = ConfigFactory<NextEffectTimerDisplayType>.CreateConfig("Next Effect Timer Display Mode", NextEffectTimerDisplayType.WhenRunTimerUnavailable).Description("Displays how much time is left until the next effect.\r\n\r\nNever: The time remaining is never displayed.\r\nWhenRunTimerUnavailable: Displays time remaining only when the regular run timer is paused or otherwise not visible.\r\nAlways: Time remaining is always displayed").OptionConfig((BaseOptionConfig)new ChoiceConfig()) .Build(); private static bool activeEffectsPanelHidden() { return HideActiveEffectsPanel.Value; } public static bool ShouldShowNextEffectTimer(HUD hud) { switch (NextEffectTimerDisplayMode.Value) { case NextEffectTimerDisplayType.Never: return false; case NextEffectTimerDisplayType.WhenRunTimerUnavailable: { Run instance = Run.instance; if (Object.op_Implicit((Object)(object)instance)) { if (!instance.isRunStopwatchPaused || !General.RunEffectsTimerWhileRunTimerPaused.Value) { return !RunTimerUITracker.IsAnyTimerVisibleForHUD(hud); } return true; } return false; } case NextEffectTimerDisplayType.Always: return true; default: throw new NotImplementedException(); } } internal static void Bind(ConfigFile file) { bindConfig(HideActiveEffectsPanel); bindConfig(DisplayAlwaysActiveEffects); bindConfig(ActiveEffectsTextColor); bindConfig(DisplayNextEffect); bindConfig(NextEffectTimerDisplayMode); void bindConfig(ConfigHolderBase config) { config.Bind(file, "UI", "RoC_Config_General", "Risk of Chaos: General"); } } } private const string CONFIG_GUID = "RoC_Config_General"; private const string CONFIG_NAME = "Risk of Chaos: General"; public static Sprite GenericIcon { get; private set; } private static void findIcon() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) FileInfo fileInfo = null; DirectoryInfo directoryInfo = new DirectoryInfo(Main.ModDirectory); do { FileInfo[] files = directoryInfo.GetFiles("icon.png", SearchOption.TopDirectoryOnly); if (files != null && files.Length != 0) { fileInfo = files[0]; break; } directoryInfo = directoryInfo.Parent; } while (directoryInfo != null && !string.Equals(directoryInfo.Name, "plugins", StringComparison.OrdinalIgnoreCase)); if (fileInfo != null) { Texture2D val = new Texture2D(256, 256); ((Object)val).name = "texRiskOfChaosIcon"; if (ImageConversion.LoadImage(val, File.ReadAllBytes(fileInfo.FullName))) { GenericIcon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); ((Object)GenericIcon).name = "RiskOfChaosIcon"; } } if (!Object.op_Implicit((Object)(object)GenericIcon)) { Log.Error("Failed to load config icon", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Config\\Configs.cs", "findIcon", 47); } } internal static void Init(ConfigFile file) { General.Bind(file); EffectSelection.Bind(file); UI.Bind(file); ChatVoting.Bind(file); ChatVotingUI.Bind(file); Metadata.Bind(file); findIcon(); if (Object.op_Implicit((Object)(object)GenericIcon)) { ModSettingsManager.SetModIcon(GenericIcon, "RoC_Config_General", "Risk of Chaos: General"); } ModSettingsManager.SetModDescription("General config options for Risk of Chaos", "RoC_Config_General", "Risk of Chaos: General"); } } internal static class LanguageFileHandler { internal static void Init() { Language.collectLanguageRootFolders += delegate(List<string> folders) { string text = Path.Combine(Main.ModDirectory, "lang"); if (Directory.Exists(text)) { folders.Add(text); } else { Log.Warning("Unable to find lang folder at " + text, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\LanguageFileHandler.cs", "Init", 20); } }; } } internal static class Log { private static readonly object _stringBuilderLock; private static readonly StringBuilder _sharedStringBuilder; private static readonly int _cachedCallerPathPrefixLength; private static ManualLogSource _logSource; static Log() { _stringBuilderLock = new object(); _sharedStringBuilder = new StringBuilder(256); _cachedCallerPathPrefixLength = getCallerPathPrefixLength("D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Log.cs"); static int getCallerPathPrefixLength([CallerFilePath] string callerPath = null) { int num = callerPath.LastIndexOf("RiskOfChaos\\"); if (num >= 0) { return num + "RiskOfChaos\\".Length; } Debug.LogError((object)"[RiskOfChaos] Logger failed to determine caller path prefix length"); return 0; } } internal static void Init(ManualLogSource logSource) { _logSource = logSource; } private static StringBuilder AppendCallerPrefix(this StringBuilder stringBuilder, string callerPath, string callerMemberName, int callerLineNumber) { return stringBuilder.Append(callerPath, _cachedCallerPathPrefixLength, callerPath.Length - _cachedCallerPathPrefixLength).Append(':').Append(callerLineNumber) .Append(" (") .Append(callerMemberName) .Append("):"); } private static StringBuilder buildCallerLogString(string callerPath, string callerMemberName, int callerLineNumber, object data) { lock (_stringBuilderLock) { return _sharedStringBuilder.Clear().AppendCallerPrefix(callerPath, callerMemberName, callerLineNumber).Append(' ') .Append(data); } } [Conditional("DEBUG")] internal static void Debug(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogDebug((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Conditional("DEBUG")] internal static void Debug_NoCallerPrefix(object data) { _logSource.LogDebug(data); } internal static void Error(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogError((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Error_NoCallerPrefix(object data) { _logSource.LogError(data); } internal static void Fatal(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogFatal((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Fatal_NoCallerPrefix(object data) { _logSource.LogFatal(data); } internal static void Info(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogInfo((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Info_NoCallerPrefix(object data) { _logSource.LogInfo(data); } internal static void Message(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogMessage((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Message_NoCallerPrefix(object data) { _logSource.LogMessage(data); } internal static void Warning(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogWarning((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Warning_NoCallerPrefix(object data) { _logSource.LogWarning(data); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool ShouldLog(LogLevel logLevel) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if ((logLevel & 0x20) != 0) { return false; } return (int)logLevel > 0; } internal static void LogType(LogLevel logLevel, object data) { //IL_0000: 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) if (ShouldLog(logLevel)) { _logSource.Log(logLevel, data); } } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("Gorakh.RiskOfChaos", "RiskOfChaos", "2.3.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Main : BaseUnityPlugin { public const string PluginGUID = "Gorakh.RiskOfChaos"; public const string PluginAuthor = "Gorakh"; public const string PluginName = "RiskOfChaos"; public const string PluginVersion = "2.3.1"; private Harmony _harmonyInstance; private static Main _instance; public static Main Instance => _instance; public static string ModDirectory { get; private set; } public RoCContent ContentPackProvider { get; private set; } private void Awake() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown SingletonHelper.Assign<Main>(ref _instance, this); Stopwatch stopwatch = Stopwatch.StartNew(); Log.Init(((BaseUnityPlugin)this).Logger); TaskExceptionHandler.Initialize(); Log.LogSource = (ILogSource)(object)new TwitchLibLogSource(); ModDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); ContentPackProvider = new RoCContent(); ContentPackProvider.Register(); LanguageFileHandler.Init(); NetworkMessageManager.RegisterMessages(); AdditionalResourceAvailability.InitHooks(); if (ProperSaveCompat.Active) { ProperSaveCompat.Init(); } _harmonyInstance = new Harmony("com.Gorakh.RiskOfChaos"); _harmonyInstance.PatchAll(Assembly.GetExecutingAssembly()); initConfigs(); Log.Message_NoCallerPrefix($"Initialized in {stopwatch.Elapsed.TotalSeconds:F2} seconds"); stopwatch.Stop(); } private void initConfigs() { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; Configs.Init(((BaseUnityPlugin)this).Config); ChaosEffectCatalog.InitConfig(((BaseUnityPlugin)this).Config); RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, (Action)delegate { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; ((BaseUnityPlugin)this).Config.Save(); Configs.Metadata.CheckVersion(); }); } private void OnDestroy() { SingletonHelper.Unassign<Main>(ref _instance, this); TaskExceptionHandler.Cleanup(); if (ProperSaveCompat.Active) { ProperSaveCompat.Cleanup(); } Harmony harmonyInstance = _harmonyInstance; if (harmonyInstance != null) { harmonyInstance.UnpatchSelf(); } } } internal static class MidRunArtifactsHandler { [CompilerGenerated] private static class <>O { public static ArtifactStateChangeDelegate <0>__RunArtifactManager_onArtifactEnabledGlobal; public static ArtifactStateChangeDelegate <1>__RunArtifactManager_onArtifactDisabledGlobal; public static Action <2>__MarkDirty; } [SystemInitializer(new Type[] { })] private static void InitListeners() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown object obj = <>O.<0>__RunArtifactManager_onArtifactEnabledGlobal; if (obj == null) { ArtifactStateChangeDelegate val = RunArtifactManager_onArtifactEnabledGlobal; <>O.<0>__RunArtifactManager_onArtifactEnabledGlobal = val; obj = (object)val; } RunArtifactManager.onArtifactEnabledGlobal += (ArtifactStateChangeDelegate)obj; object obj2 = <>O.<1>__RunArtifactManager_onArtifactDisabledGlobal; if (obj2 == null) { ArtifactStateChangeDelegate val2 = RunArtifactManager_onArtifactDisabledGlobal; <>O.<1>__RunArtifactManager_onArtifactDisabledGlobal = val2; obj2 = (object)val2; } RunArtifactManager.onArtifactDisabledGlobal += (ArtifactStateChangeDelegate)obj2; SingleMonsterTypeChangedHook.OnSingleMonsterTypeChanged += EnemyInfoPanel.MarkDirty; } private static void RunArtifactManager_onArtifactEnabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef) { onArtifactStateChanged(artifactDef, enabled: true); } private static void RunArtifactManager_onArtifactDisabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef) { onArtifactStateChanged(artifactDef, enabled: false); } private static void onArtifactStateChanged(ArtifactDef artifactDef, bool enabled) { if (!Object.op_Implicit((Object)(object)Stage.instance)) { return; } if ((Object)(object)artifactDef == (Object)(object)Artifacts.Sacrifice) { if (enabled) { onSacrificeEnabled(); } } else if ((Object)(object)artifactDef == (Object)(object)Artifacts.RandomSurvivorOnRespawn) { if (enabled) { onMetamorphosisEnabled(); } } else if ((Object)(object)artifactDef == (Object)(object)Artifacts.SingleMonsterType) { if (!enabled) { onKinDisabled(); } } else if ((Object)(object)artifactDef == (Object)(object)Artifacts.Enigma) { if (enabled) { onEnigmaEnabled(); } } else if ((Object)(object)artifactDef == (Object)(object)Artifacts.Devotion) { if (enabled) { onDevotionEnabled(); } } else if ((Object)(object)artifactDef == (Object)(object)Artifacts.Delusion) { onDelusionEnabledOrDisabled(enabled); } else if ((Object)(object)artifactDef == (Object)(object)Artifacts.Rebirth && enabled) { onRebirthEnabled(); } CharacterBodyUtils.MarkAllBodyStatsDirty(); if (!enabled) { return; } foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList) { if (readOnlyLocalUsers != null) { CharacterMaster cachedMaster = readOnlyLocalUsers.cachedMaster; if (Object.op_Implicit((Object)(object)cachedMaster)) { CharacterMasterNotificationQueue.PushArtifactNotification(cachedMaster, artifactDef); } } } } private static void onKinDisabled() { if (NetworkServer.active && Object.op_Implicit((Object)(object)Stage.instance)) { Stage.instance.singleMonsterTypeBodyIndex = (BodyIndex)(-1); } } private static void onSacrificeEnabled() { if (!NetworkServer.active) { return; } List<ObjectSpawnCardTracker> instancesList = InstanceTracker.GetInstancesList<ObjectSpawnCardTracker>(); for (int num = instancesList.Count - 1; num >= 0; num--) { ObjectSpawnCardTracker objectSpawnCardTracker = instancesList[num]; if (Object.op_Implicit((Object)(object)objectSpawnCardTracker)) { SpawnCard spawnCard = objectSpawnCardTracker.SpawnCard; InteractableSpawnCard val = (InteractableSpawnCard)(object)((spawnCard is InteractableSpawnCard) ? spawnCard : null); if (val != null && val.skipSpawnWhenSacrificeArtifactEnabled) { NetworkServer.Destroy(((Component)objectSpawnCardTracker).gameObject); } } } } private static void onMetamorphosisEnabled() { if (!NetworkServer.active) { return; } foreach (CharacterBody allPlayerBody in PlayerUtils.GetAllPlayerBodies(requireAlive: true)) { allPlayerBody.master.Respawn(CharacterRespawnFlags.KeepState); } } private static void onEnigmaEnabled() { if (!NetworkServer.active) { return; } foreach (CharacterBody allPlayerBody in PlayerUtils.GetAllPlayerBodies(requireAlive: true)) { EnigmaArtifactManager.OnPlayerCharacterBodyStartServer(allPlayerBody); } } private static void onDevotionEnabled() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { return; } SceneDirector val = null; if (Object.op_Implicit((Object)(object)DirectorCore.instance)) { val = ((Component)DirectorCore.instance).GetComponent<SceneDirector>(); } DirectorCard val2; if (Object.op_Implicit((Object)(object)val)) { val2 = val.lumerianEgg; } else { Log.Warning("Failed to find SceneDirector", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\MidRunArtifactsHandler.cs", "onDevotionEnabled", 181); val2 = new DirectorCard { spawnCard = (SpawnCard)(object)Addressables.LoadAssetAsync<InteractableSpawnCard>((object)"RoR2/CU8/LemurianEgg/iscLemurianEgg.asset").WaitForCompletion() }; } if (val2 == null || !Object.op_Implicit((Object)(object)val2.spawnCard)) { Log.Error("Failed to find valid egg spawn card", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\MidRunArtifactsHandler.cs", "onDevotionEnabled", 191); return; } Xoroshiro128Plus val3 = new Xoroshiro128Plus(RoR2Application.rng.nextUlong); List<ObjectSpawnCardTracker> instancesList = InstanceTracker.GetInstancesList<ObjectSpawnCardTracker>(); for (int num = instancesList.Count - 1; num >= 0; num--) { ObjectSpawnCardTracker objectSpawnCardTracker = instancesList[num]; if (Object.op_Implicit((Object)(object)objectSpawnCardTracker)) { SpawnCard spawnCard = objectSpawnCardTracker.SpawnCard; InteractableSpawnCard val4 = (InteractableSpawnCard)(object)((spawnCard is InteractableSpawnCard) ? spawnCard : null); if (val4 != null && val4.skipSpawnWhenDevotionArtifactEnabled) { DirectorPlacementRule val5 = new DirectorPlacementRule { placementMode = (PlacementMode)0, spawnOnTarget = ((Component)objectSpawnCardTracker).transform }; DirectorSpawnRequest val6 = new DirectorSpawnRequest(val2.spawnCard, val5, val3); val6.spawnCard.DoSpawn(((Component)objectSpawnCardTracker).transform.position, ((Component)objectSpawnCardTracker).transform.rotation, val6); NetworkServer.Destroy(((Component)objectSpawnCardTracker).gameObject); } } } } private static void onDelusionEnabledOrDisabled(bool enabled) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown TeleporterInteraction instance = TeleporterInteraction.instance; bool flag = Object.op_Implicit((Object)(object)instance) && instance.isCharged; EntityStateMachine val2 = default(EntityStateMachine); foreach (DelusionChestControllerTracker instances in InstanceTracker.GetInstancesList<DelusionChestControllerTracker>()) { DelusionChestController delusionChestController = instances.DelusionChestController; if (!Object.op_Implicit((Object)(object)delusionChestController)) { continue; } if (enabled) { if (!delusionChestController.hasBeenReset) { ((Behaviour)delusionChestController).enabled = true; PickupIndex val = instances.TakePendingDelusionPickupIndex(); if (((PickupIndex)(ref val)).isValid) { delusionChestController.delusionChest.CallRpcSetDelusionPickupIndex(val); } if (flag) { delusionChestController.delusionChest.CallRpcResetChests(); } } } else if (delusionChestController.hasBeenReset) { ((Behaviour)delusionChestController).enabled = false; NetworkUIPromptController netUIPromptController = delusionChestController._netUIPromptController; if (Object.op_Implicit((Object)(object)netUIPromptController)) { ((Behaviour)netUIPromptController).enabled = false; } PickupPickerController pickupPickerController = delusionChestController._pickupPickerController; if (Object.op_Implicit((Object)(object)pickupPickerController)) { ((Behaviour)pickupPickerController).enabled = false; pickupPickerController.SetAvailable(false); } if (((Component)delusionChestController).TryGetComponent<EntityStateMachine>(ref val2)) { val2.SetNextState((EntityState)new Opening()); } } } } private static void onRebirthEnabled() { if (NetworkServer.active && Object.op_Implicit((Object)(object)Run.instance)) { Run.instance.ServerGiveRebirthItems(); } if (!NetworkClient.active) { return; } foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { LocalUser localUser = readOnlyInstances.localUser; UserProfile val = ((localUser != null) ? localUser.userProfile : null); if (val != null && !string.IsNullOrEmpty(val.RebirthItem)) { val.RebirthItem = null; val.RequestEventualSave(); } } } } internal sealed class TwitchLibLogSource : ILogSource { public void Log(object message, LogType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected I4, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) RiskOfChaos.Log.LogType((LogLevel)((int)type switch { 0 => 32, 1 => 16, 2 => 8, 3 => 4, 4 => 2, 5 => 1, _ => throw new NotImplementedException($"Log type {type} is not implemented"), }), message); } } } namespace RiskOfChaos.Utilities { public static class AdditionalResourceAvailability { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static hook_Init <>9__3_0; public static hook_Init <>9__3_1; public static hook_SetEntries <>9__3_2; internal void <InitHooks>b__3_0(orig_Init orig) { orig.Invoke(); ((ResourceAvailability)(ref BuffCatalog)).MakeAvailable(); } internal void <InitHooks>b__3_1(orig_Init orig) { orig.Invoke(); ((ResourceAvailability)(ref MasterCatalog)).MakeAvailable(); } internal void <InitHooks>b__3_2(orig_SetEntries orig, PickupDef[] entries) { orig.Invoke(entries); ((ResourceAvailability)(ref PickupCatalog)).MakeAvailable(); } } public static ResourceAvailability BuffCatalog; public static ResourceAvailability MasterCatalog; public static ResourceAvailability PickupCatalog; internal static void InitHooks() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown object obj = <>c.<>9__3_0; if (obj == null) { hook_Init val = delegate(orig_Init orig) { orig.Invoke(); ((ResourceAvailability)(ref BuffCatalog)).MakeAvailable(); }; <>c.<>9__3_0 = val; obj = (object)val; } BuffCatalog.Init += (hook_Init)obj; object obj2 = <>c.<>9__3_1; if (obj2 == null) { hook_Init val2 = delegate(orig_Init orig) { orig.Invoke(); ((ResourceAvailability)(ref MasterCatalog)).MakeAvailable(); }; <>c.<>9__3_1 = val2; obj2 = (object)val2; } MasterCatalog.Init += (hook_Init)obj2; object obj3 = <>c.<>9__3_2; if (obj3 == null) { hook_SetEntries val3 = delegate(orig_SetEntries orig, PickupDef[] entries) { orig.Invoke(entries); ((ResourceAvailability)(ref PickupCatalog)).MakeAvailable(); }; <>c.<>9__3_2 = val3; obj3 = (object)val3; } PickupCatalog.SetEntries += (hook_SetEntries)obj3; } } public static class AttackUtils { public static BulletAttack Clone(BulletAttack src) { return src.ShallowCopy<BulletAttack>(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } public static BlastAttack Clone(BlastAttack src) { return src.ShallowCopy<BlastAttack>(); } public static OverlapAttack Clone(OverlapAttack src) { return src.ShallowCopy<OverlapAttack>(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } } public readonly record struct BodySkillPair(BodyIndex BodyIndex, SkillSlot SkillSlot) { public BodySkillPair(BodyIndex BodyIndex, SkillSlot SkillSlot) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) this.BodyIndex = BodyIndex; this.SkillSlot = SkillSlot; } public BodySkillPair(string bodyName, SkillSlot slot) : this(BodyCatalog.FindBodyIndex(bodyName), slot) { }//IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) builder.Append("BodyIndex = "); BodyIndex bodyIndex = BodyIndex; builder.Append(((object)(BodyIndex)(ref bodyIndex)).ToString()); builder.Append(", SkillSlot = "); SkillSlot skillSlot = SkillSlot; builder.Append(((object)(SkillSlot)(ref skillSlot)).ToString()); return true; } [CompilerGenerated] public void Deconstruct(out BodyIndex BodyIndex, out SkillSlot SkillSlot) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected I4, but got Unknown //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected I4, but got Unknown BodyIndex = (BodyIndex)(int)this.BodyIndex; SkillSlot = (SkillSlot)(int)this.SkillSlot; } } public static class BossUtils { public static void TryRefreshBossTitleFor(CharacterMaster master) { if (Object.op_Implicit((Object)(object)master)) { CharacterBody body = master.GetBody(); if (Object.op_Implicit((Object)(object)body)) { TryRefreshBossTitleFor(body); } } } public static void TryRefreshBossTitleFor(CharacterBody characterBody) { BossGroup val = BossGroup.FindBossGroup(characterBody); if (Object.op_Implicit((Object)(object)val)) { RefreshBossTitle(val); } } public static void RefreshBossTitle(BossGroup bossGroup) { bossGroup.bestObservedName = string.Empty; bossGroup.bestObservedSubtitle = string.Empty; } } public static class CharacterBodyUtils { public static void MarkAllBodyStatsDirty() { foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { readOnlyInstances.MarkAllStatsDirty(); } } } public static class CharacterMasterNotificationQueueUtils { public static void SendPickupTransformNotification(CharacterMaster characterMaster, PickupIndex fromPickupIndex, PickupIndex toPickupIndex, TransformationType transformationType) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { Log.Error("Called on client", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\CharacterMasterNotificationQueueUtils.cs", "SendPickupTransformNotification", 15); } else { NetMessageExtensions.Send((INetMessage)(object)new PickupTransformationNotificationMessage(characterMaster, fromPickupIndex, toPickupIndex, transformationType), (NetworkDestination)3); } } public static bool IsAnyNotificationQueued(CharacterMaster viewerMaster) { if (!Object.op_Implicit((Object)(object)viewerMaster) || !((NetworkBehaviour)viewerMaster).hasAuthority) { return false; } CharacterMasterNotificationQueue val = (Object.op_Implicit((Object)(object)viewerMaster) ? ((Component)viewerMaster).GetComponent<CharacterMasterNotificationQueue>() : null); if (Object.op_Implicit((Object)(object)val)) { return val.GetCurrentNotification() != (NotificationInfo)null; } return false; } } public static class ClampedConversion { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Int32(uint value) { if (value > int.MaxValue) { return int.MaxValue; } return (int)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Int32(long value) { if (value > int.MaxValue) { return int.MaxValue; } if (value < int.MinValue) { return int.MinValue; } return (int)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UInt32(int value) { if ((long)value < 0L) { return 0u; } return (uint)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UInt32(long value) { if (value > uint.MaxValue) { return uint.MaxValue; } if (value < 0) { return 0u; } return (uint)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint UInt32(ulong value) { if (value > uint.MaxValue) { return uint.MaxValue; } return (uint)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static sbyte Int8(int value) { if (value > 127) { return sbyte.MaxValue; } if (value < -128) { return sbyte.MinValue; } return (sbyte)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte UInt8(int value) { if (value > 255) { return byte.MaxValue; } if (value < 0) { return 0; } return (byte)value; } } public static class ConVarFlagUtil { public const ConVarFlags SERVER = 2; } public static class CostUtils { public static bool AllowsZeroCost(CostTypeIndex costType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if ((int)costType <= 3 || costType - 14 <= 1) { return true; } return false; } public static int GetMaxCost(CostTypeIndex costType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)costType != 2) { if (costType - 7 <= 1) { return 1; } if ((int)costType != 15) { return int.MaxValue; } } return 99; } public static int GetMinCost(CostTypeIndex costType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)costType != 0) { if ((int)costType == 15) { return 10; } return 1; } return 0; } public static float ConvertCost(float cost, CostTypeIndex from, CostTypeIndex to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_0026: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (from == to) { return cost; } if ((int)to <= 0 || (int)to >= 16) { return 0f; } if ((int)from <= 0 || (int)from >= 16) { return GetMinCost(to); } int minCost = GetMinCost(from); int maxCost = GetMaxCost(from); int maxCost2 = GetMaxCost(to); int minCost2 = GetMinCost(to); if (maxCost < int.MaxValue && minCost != maxCost) { float num = Mathf.Clamp01(Mathf.InverseLerp((float)minCost, (float)maxCost, cost)); cost = (float)minCost - (50f - (float)minCost) * (1f + 1f / (num - 1f)); } cost *= getConversionRate(from) / getConversionRate(to); if (maxCost2 < int.MaxValue && minCost2 != maxCost2) { float num2 = 1f + 1f / (((float)minCost2 - cost) / (50f - (float)minCost2) - 1f); cost = Mathf.Lerp((float)minCost2, (float)maxCost2, num2); } cost = Mathf.Clamp(cost, (float)minCost2, (float)maxCost2); return cost; static float getConversionRate(CostTypeIndex costType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected I4, but got Unknown switch (costType - 3) { case 1: return 25f; case 0: case 2: case 4: case 5: case 11: return 50f; case 9: return 75f; case 6: return 100f; case 3: case 7: case 8: case 10: return 150f; default: return 1f; } } } } public static class Ease { public static float InQuad(float t) { return t * t; } public static float OutQuad(float t) { return 1f - (1f - t) * (1f - t); } public static float InOutQuad(float t) { if (t < 0.5f) { return 2f * t * t; } float num = -2f * t + 2f; return 1f - num * num / 2f; } public static float InCubic(float t) { return t * t * t; } public static float OutCubic(float t) { float num = 1f - t; return 1f - num * num * num; } public static float InOutCubic(float t) { if (t < 0.5f) { return 4f * t * t * t; } float num = -2f * t + 2f; return 1f - num * num * num / 2f; } } public static class EliteUtils { private static EliteIndex[] _baseEliteIndices = Array.Empty<EliteIndex>(); private static EquipmentIndex[] _baseEliteEquipmentIndices = Array.Empty<EquipmentIndex>(); private static EliteIndex[] _runAvailableEliteIndices = Array.Empty<EliteIndex>(); public static bool HasAnyRunAvailableElites => _runAvailableEliteIndices.Length != 0; [SystemInitializer(new Type[] { typeof(EquipmentCatalog), typeof(EliteCatalog) })] private static void Init() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) List<EliteIndex> list = new List<EliteIndex>(EliteCatalog.eliteList.Count); List<EquipmentIndex> list2 = new List<EquipmentIndex>(EliteCatalog.eliteList.Count); foreach (EliteIndex elite in EliteCatalog.eliteList) { EliteDef eliteDef = EliteCatalog.GetEliteDef(elite); if (!Object.op_Implicit((Object)(object)eliteDef) || ((Object)eliteDef).name.EndsWith("Honor", StringComparison.OrdinalIgnoreCase)) { continue; } EquipmentDef eliteEquipmentDef = eliteDef.eliteEquipmentDef; if (Object.op_Implicit((Object)(object)eliteEquipmentDef) && Object.op_Implicit((Object)(object)eliteEquipmentDef.pickupModelPrefab) && !string.Equals(((Object)eliteEquipmentDef.pickupModelPrefab).name, "NullModel", StringComparison.OrdinalIgnoreCase) && !(eliteEquipmentDef.dropOnDeathChance <= 0f)) { if (!list.Contains(elite)) { list.Add(elite); } if (!list2.Contains(eliteEquipmentDef.equipmentIndex)) { list2.Add(eliteEquipmentDef.equipmentIndex); } } } list.Sort(); _baseEliteIndices = list.ToArray(); list2.Sort(); _baseEliteEquipmentIndices = list2.ToArray(); Run.onRunStartGlobal += delegate { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) List<EliteIndex> list3 = new List<EliteIndex>(_baseEliteIndices.Length); EliteIndex[] baseEliteIndices = _baseEliteIndices; foreach (EliteIndex val in baseEliteIndices) { EliteDef eliteDef2 = EliteCatalog.GetEliteDef(val); if (Object.op_Implicit((Object)(object)eliteDef2) && eliteDef2.IsAvailable()) { list3.Add(val); } } _runAvailableEliteIndices = list3.ToArray(); }; Run.onRunDestroyGlobal += delegate { _runAvailableEliteIndices = Array.Empty<EliteIndex>(); }; } public static bool IsAvailable(EliteIndex eliteIndex) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Array.BinarySearch(_baseEliteIndices, eliteIndex) >= 0; } public static bool IsRunAvailable(EliteIndex eliteIndex) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Array.BinarySearch(_runAvailableEliteIndices, eliteIndex) >= 0; } public static EliteIndex[] GetRunAvailableElites(bool ignoreEliteTierAvailability) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) List<EliteIndex> list = new List<EliteIndex>(_runAvailableEliteIndices.Length); EliteTierDef[] eliteTiers = CombatDirector.eliteTiers; foreach (EliteTierDef val in eliteTiers) { if (!ignoreEliteTierAvailability && !val.CanSelect((EliteRules)0)) { continue; } EliteDef[] eliteTypes = val.eliteTypes; foreach (EliteDef val2 in eliteTypes) { if (Object.op_Implicit((Object)(object)val2) && IsRunAvailable(val2.eliteIndex) && !list.Contains(val2.eliteIndex)) { list.Add(val2.eliteIndex); } } } return list.ToArray(); } public static bool IsEliteEquipment(EquipmentIndex equipmentIndex) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Array.BinarySearch(_baseEliteEquipmentIndices, equipmentIndex) >= 0; } } public class EventWaiter { private record struct EventInfo(bool HasInvoked); private bool _allEventsInvoked; public bool ResetAfterAllEventsInvoked; private readonly List<EventInfo> _events = new List<EventInfo>(); public event Action OnAnyEventInvoked; public event Action OnAllEventsInvoked; public Action GetListener() { _events.Add(new EventInfo(HasInvoked: false)); int eventIndex = _events.Count - 1; return delegate { if (eventIndex >= 0 && eventIndex < _events.Count && !_events[eventIndex].HasInvoked) { setHasEventInvoked(eventIndex, isInvoked: true); onEventInvoked(); } }; } private void setHasEventInvoked(int index, bool isInvoked) { if (index >= 0 && index < _events.Count) { EventInfo value = _events[index]with { HasInvoked = isInvoked }; _events[index] = value; } } private void onEventInvoked() { this.OnAnyEventInvoked?.Invoke(); if (_allEventsInvoked || !_events.All((EventInfo e) => e.HasInvoked)) { return; } this.OnAllEventsInvoked?.Invoke(); if (ResetAfterAllEventsInvoked) { for (int i = 0; i < _events.Count; i++) { setHasEventInvoked(i, isInvoked: false); } } else { _allEventsInvoked = true; } } } public static class ExpansionUtils { public static ExpansionDef DLC1 { get; private set; } public static ExpansionDef DLC2 { get; private set; } public static bool DLC1Enabled { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (Object.op_Implicit((Object)(object)DLC1)) { return IsExpansionEnabled(DLC1); } return false; } } public static bool DLC2Enabled { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (Object.op_Implicit((Object)(object)DLC2)) { return IsExpansionEnabled(DLC2); } return false; } } [SystemInitializer(new Type[] { })] private static IEnumerator Init() { List<AsyncOperationHandle> list = new List<AsyncOperationHandle>(2); AsyncOperationHandle<ExpansionDef> handle = Addressables.LoadAssetAsync<ExpansionDef>((object)"RoR2/DLC1/Common/DLC1.asset"); handle.OnSuccess(delegate(ExpansionDef dlc1) { DLC1 = dlc1; }); list.Add(AsyncOperationHandle<ExpansionDef>.op_Implicit(handle)); AsyncOperationHandle<ExpansionDef> handle2 = Addressables.LoadAssetAsync<ExpansionDef>((object)"RoR2/DLC2/Common/DLC2.asset"); handle2.OnSuccess(delegate(ExpansionDef dlc2) { DLC2 = dlc2; }); list.Add(AsyncOperationHandle<ExpansionDef>.op_Implicit(handle2)); yield return list.WaitForAllLoaded(); } public static bool IsExpansionEnabled(ExpansionDef expansionDef) { if (Object.op_Implicit((Object)(object)expansionDef)) { if (Object.op_Implicit((Object)(object)Run.instance)) { return Run.instance.IsExpansionEnabled(expansionDef); } return false; } return true; } public static bool AllExpansionsEnabled(IEnumerable<ExpansionDef> expansions) { foreach (ExpansionDef expansion in expansions) { if (!IsExpansionEnabled(expansion)) { return false; } } return true; } private static void addAllRequiredExpansions(GameObject obj, List<ExpansionDef> dest) { if (!Object.op_Implicit((Object)(object)obj)) { return; } ExpansionRequirementComponent[] components = obj.GetComponents<ExpansionRequirementComponent>(); ListExtensions.EnsureCapacity(dest, dest.Count + components.Length); ExpansionRequirementComponent[] array = components; foreach (ExpansionRequirementComponent val in array) { if (Object.op_Implicit((Object)(object)val.requiredExpansion)) { dest.Add(val.requiredExpansion); } } CharacterMaster val2 = default(CharacterMaster); if (obj.TryGetComponent<CharacterMaster>(ref val2) && Object.op_Implicit((Object)(object)val2.bodyPrefab)) { addAllRequiredExpansions(val2.bodyPrefab, dest); } } public static IReadOnlyList<ExpansionDef> GetObjectRequiredExpansions(GameObject obj) { if (!Object.op_Implicit((Object)(object)obj)) { return Array.Empty<ExpansionDef>(); } List<ExpansionDef> list = new List<ExpansionDef>(); addAllRequiredExpansions(obj, list); list.TrimExcess(); return list.AsReadOnly(); } public static bool IsObjectExpansionAvailable(GameObject obj) { return AllExpansionsEnabled(GetObjectRequiredExpansions(obj)); } } public static class FormatUtils { public static string GetBestBodyName(CharacterBody body) { if (!Object.op_Implicit((Object)(object)body)) { return "null"; } string bestBodyName = Util.GetBestBodyName(((Component)body).gameObject); if (!string.IsNullOrWhiteSpace(bestBodyName)) { return bestBodyName; } return ((object)body).ToString(); } public static string GetBestItemDisplayName(ItemIndex item) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) if ((int)item == -1) { return "None"; } return GetBestItemDisplayName(ItemCatalog.GetItemDef(item)); } public static string GetBestItemDisplayName(ItemDef item) { if (!Object.op_Implicit((Object)(object)item)) { return "null"; } if (!string.IsNullOrWhiteSpace(item.nameToken) && !Language.IsTokenInvalid(item.nameToken)) { string @string = Language.GetString(item.nameToken); if (!string.IsNullOrWhiteSpace(@string)) { return @string; } } return ((Object)item).name; } public static string GetBestEquipmentDisplayName(EquipmentIndex equipmentIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) if ((int)equipmentIndex == -1) { return "None"; } return GetBestEquipmentDisplayName(EquipmentCatalog.GetEquipmentDef(equipmentIndex)); } public static string GetBestEquipmentDisplayName(EquipmentDef equipmentDef) { if (!Object.op_Implicit((Object)(object)equipmentDef)) { return "null"; } if (!string.IsNullOrEmpty(equipmentDef.nameToken) && !Language.IsTokenInvalid(equipmentDef.nameToken)) { string @string = Language.GetString(equipmentDef.nameToken); if (!string.IsNullOrWhiteSpace(@string)) { return @string; } } return ((Object)equipmentDef).name; } public static string GetBestDifficultyDisplayName(DifficultyIndex difficultyIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return GetBestDifficultyDisplayName(DifficultyCatalog.GetDifficultyDef(difficultyIndex)); } public static string GetBestDifficultyDisplayName(DifficultyDef difficultyDef) { if (difficultyDef == null) { return "null"; } return Language.GetString(difficultyDef.nameToken); } public static string FormatTimeSeconds(float seconds) { if (seconds < 120.5f) { return seconds.ToString((seconds >= 9.95f) ? "F0" : "F1") + "s"; } int num = Mathf.FloorToInt(seconds / 60f); int num2 = Mathf.RoundToInt(seconds % 60f); return $"{num}:{num2:D2}"; } } public static class InputUtils { private static MemoizedGetComponent<TMP_InputField> _currentSelectedObjectTMPInputField; private static MemoizedGetComponent<InputField> _currentSelectedObjectInputField; public static bool IsUsingInputField() { EventSystem val = (EventSystem)(object)MPEventSystemManager.FindEventSystem(ReInput.players.GetPlayer(0)); if (Object.op_Implicit((Object)(object)val)) { GameObject currentSelectedGameObject = val.currentSelectedGameObject; if (Object.op_Implicit((Object)(object)_currentSelectedObjectTMPInputField.Get(currentSelectedGameObject)) || Object.op_Implicit((Object)(object)_currentSelectedObjectInputField.Get(currentSelectedGameObject))) { return true; } } return false; } } public static class InstanceUtils { public static void DestroyAllTrackedInstances<T>(bool destroyGameObject = false) where T : MonoBehaviour { List<T> instancesList = InstanceTracker.GetInstancesList<T>(); for (int num = instancesList.Count - 1; num >= 0; num--) { T val = instancesList[num]; if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(destroyGameObject ? ((Component)(object)val).gameObject : ((object)val))); } } } } public readonly record struct ItemStack(ItemIndex ItemIndex, int ItemCount) { [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) builder.Append("ItemIndex = "); ItemIndex itemIndex = ItemIndex; builder.Append(((object)(ItemIndex)(ref itemIndex)).ToString()); builder.Append(", ItemCount = "); builder.Append(ItemCount.ToString()); return true; } [CompilerGenerated] public void Deconstruct(out ItemIndex ItemIndex, out int ItemCount) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected I4, but got Unknown ItemIndex = (ItemIndex)(int)this.ItemIndex; ItemCount = this.ItemCount; } } public class ItemTierPickupRulesOverride : IDisposable { private static PickupRules[] _originalPickupRules = Array.Empty<PickupRules>(); private static readonly List<ItemTierPickupRulesOverride> _activeRuleOverrides = new List<ItemTierPickupRulesOverride>(); private PickupRules _overrideRules; public PickupRules OverrideRules { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return _overrideRules; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (_overrideRules != value) { _overrideRules = value; refreshPickupRules(); } } } [SystemInitializer(new Type[] { typeof(ItemTierCatalog) })] private unsafe static void Init() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected I4, but got Unknown ReadOnlyArray<ItemTierDef> allItemTierDefs = ItemTierCatalog.allItemTierDefs; _originalPickupRules = (PickupRules[])(object)new PickupRules[allItemTierDefs.Length]; for (int i = 0; i < allItemTierDefs.Length; i++) { _originalPickupRules[i] = (PickupRules)(int)((ItemTierDef)Unsafe.Read<object>((void*)allItemTierDefs[i])).pickupRules; } } private static void refreshPickupRules() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (_activeRuleOverrides.Count > 0) { List<ItemTierPickupRulesOverride> activeRuleOverrides = _activeRuleOverrides; setOverridePickupRules(activeRuleOverrides[activeRuleOverrides.Count - 1].OverrideRules); } else { restorePickupRules(); } } private unsafe static void setOverridePickupRules(PickupRules overridePickupRules) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < ItemTierCatalog.allItemTierDefs.Length; i++) { ((ItemTierDef)Unsafe.Read<object>((void*)ItemTierCatalog.allItemTierDefs[i])).pickupRules = overridePickupRules; } } private unsafe static void restorePickupRules() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (_originalPickupRules.Length == 0) { Log.Error("Original rules not initialized, cannot restore pickup rules", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\ItemTierPickupRulesOverride.cs", "restorePickupRules", 52); return; } for (int i = 0; i < ItemTierCatalog.allItemTierDefs.Length; i++) { if (i >= _originalPickupRules.Length) { Log.Error("Missing original pickup rules for " + ((Object)ItemTierCatalog.GetItemTierDef((ItemTier)i)).name, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\ItemTierPickupRulesOverride.cs", "restorePickupRules", 60); } else { ((ItemTierDef)Unsafe.Read<object>((void*)ItemTierCatalog.allItemTierDefs[i])).pickupRules = _originalPickupRules[i]; } } } public ItemTierPickupRulesOverride(PickupRules pickupRulesOverride) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) _overrideRules = pickupRulesOverride; _activeRuleOverrides.Add(this); refreshPickupRules(); } public void Dispose() { if (_activeRuleOverrides.Remove(this)) { refreshPickupRules(); } } } public static class LoadoutUtils { [Flags] public enum GeneratorFlags : byte { None = 0, Skills = 1, Skin = 2, All = byte.MaxValue } public static Loadout GetRandomLoadoutFor(BodyIndex bodyIndex, Xoroshiro128Plus rng, GeneratorFlags flags = GeneratorFlags.All) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) BodyInfo val = BodyLoadoutManager.allBodyInfos[bodyIndex]; Loadout val2 = new Loadout(); if ((flags & GeneratorFlags.Skills) != 0) { for (int i = 0; i < ((BodyInfo)(ref val)).skillSlotCount; i++) { Variant[] variants = val.prefabSkillSlots[i].skillFamily.variants; if (variants.Length != 0) { try { val2.bodyLoadoutManager.SetSkillVariant(bodyIndex, i, (uint)rng.RangeInt(0, variants.Length)); } catch (Exception arg) { Log.Error_NoCallerPrefix($"Failed to set {BodyCatalog.GetBodyName(bodyIndex)} {(object)(SkillSlot)(sbyte)i} skill: {arg}"); } } } } if ((flags & GeneratorFlags.Skin) != 0) { int num = BodyCatalog.GetBodySkins(bodyIndex).Length; if (num > 0) { try { val2.bodyLoadoutManager.SetSkinIndex(bodyIndex, (uint)rng.RangeInt(0, num)); } catch (Exception arg2) { Log.Error_NoCallerPrefix($"Failed to set {BodyCatalog.GetBodyName(bodyIndex)} skin: {arg2}"); } } } return val2; } public static Loadout GetRandomLoadoutFor(CharacterMaster master, Xoroshiro128Plus rng, GeneratorFlags flags = GeneratorFlags.All) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)master)) { GameObject val = master.GetBodyObject(); if (!Object.op_Implicit((Object)(object)val)) { val = master.bodyPrefab; } BodyIndex val2 = BodyCatalog.FindBodyIndex(val); if ((int)val2 != -1) { return GetRandomLoadoutFor(val2, rng, flags); } } return null; } public static Loadout GetRandomLoadoutFor(GameObject characterPrefab, Xoroshiro128Plus rng, GeneratorFlags flags = GeneratorFlags.All) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)characterPrefab)) { return null; } CharacterBody val = default(CharacterBody); if (characterPrefab.TryGetComponent<CharacterBody>(ref val)) { return GetRandomLoadoutFor(val.bodyIndex, rng, flags); } CharacterMaster master = default(CharacterMaster); if (characterPrefab.TryGetComponent<CharacterMaster>(ref master)) { return GetRandomLoadoutFor(master, rng, flags); } Log.Warning($"{characterPrefab} has no character related components", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\LoadoutUtils.cs", "GetRandomLoadoutFor", 99); return null; } public static Loadout GetRandomLoadoutFor(CharacterSpawnCard spawnCard, Xoroshiro128Plus rng, GeneratorFlags flags = GeneratorFlags.All) { if (!Object.op_Implicit((Object)(object)spawnCard)) { return null; } return GetRandomLoadoutFor(((SpawnCard)spawnCard).prefab, rng, flags); } } public static class OrbUtils { public static bool IsTransferOrb(Orb orb) { if (orb is ItemTransferOrb || orb is EquipmentTransferOrb) { return true; } return false; } public static Orb Clone(Orb src) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown Orb dest; try { ChainGunOrb val = (ChainGunOrb)(object)((src is ChainGunOrb) ? src : null); Orb val2 = (Orb)((val == null) ? ((object)(Orb)Activator.CreateInstance(((object)src).GetType())) : ((object)new ChainGunOrb(val.orbEffectPrefab))); dest = val2; } catch (Exception arg) { Log.Error_NoCallerPrefix($"Failed to create new orb from {src}: {arg}"); return null; } src.ShallowCopy(ref dest); return dest; } } public struct PickupPair : IEquatable<PickupPair> { public PickupIndex PickupA; public PickupIndex PickupB; public PickupPair(PickupIndex pickupA, PickupIndex pickupB) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) PickupA = pickupA; PickupB = pickupB; } public override readonly bool Equals(object obj) { if (obj is PickupPair other) { return Equals(other); } return false; } public readonly bool Equals(PickupPair other) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (PickupA == other.PickupA) { return PickupB == other.PickupB; } return false; } public override readonly int GetHashCode() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return HashCode.Combine<PickupIndex, PickupIndex>(PickupA, PickupB); } public static bool operator ==(PickupPair left, PickupPair right) { return left.Equals(right); } public static bool operator !=(PickupPair left, PickupPair right) { return !(left == right); } } public static class PlayerUtils { public static IEnumerable<CharacterMaster> GetAllPlayerMasters(bool requireAlive) { return from p in PlayerCharacterMasterController.instances where Object.op_Implicit((Object)(object)p) select p.master into m where Object.op_Implicit((Object)(object)m) && (!requireAlive || m.IsAlive()) select m; } public static IEnumerable<CharacterBody> GetAllPlayerBodies(bool requireAlive) { return from m in GetAllPlayerMasters(requireAlive) select m.GetBody() into b where Object.op_Implicit((Object)(object)b) select b; } } public static class PopupAlertQueue { public delegate void SetupDialogDelegate(SimpleDialogBox dialogBox); private readonly record struct Alert(SetupDialogDelegate SetupDialog); [CompilerGenerated] private static class <>O { public static hook_OnEnter <0>__BaseMainMenuScreen_OnEnter; public static Action <1>__fixedUpdate; } private static readonly Queue<Alert> _alertQueue = new Queue<Alert>(); private static SimpleDialogBox _currentDialogBox; [SystemInitializer(new Type[] { })] private static void Init() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown object obj = <>O.<0>__BaseMainMenuScreen_OnEnter; if (obj == null) { hook_OnEnter val = BaseMainMenuScreen_OnEnter; <>O.<0>__BaseMainMenuScreen_OnEnter = val; obj = (object)val; } BaseMainMenuScreen.OnEnter += (hook_OnEnter)obj; static void BaseMainMenuScreen_OnEnter(orig_OnEnter orig, BaseMainMenuScreen self, MainMenuController mainMenuController) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown orig.Invoke(self, mainMenuController); if ((Object)(object)self == (Object)(object)mainMenuController.titleMenuScreen) { object obj2 = <>O.<0>__BaseMainMenuScreen_OnEnter; if (obj2 == null) { hook_OnEnter val2 = BaseMainMenuScreen_OnEnter; <>O.<0>__BaseMainMenuScreen_OnEnter = val2; obj2 = (object)val2; } BaseMainMenuScreen.OnEnter -= (hook_OnEnter)obj2; startAlertQueue(); } } } public static void EnqueueAlert(SetupDialogDelegate setupDialog) { if (setupDialog == null) { throw new ArgumentNullException("setupDialog"); } _alertQueue.Enqueue(new Alert(setupDialog)); } private static void startAlertQueue() { RoR2Application.onFixedUpdate += fixedUpdate; } private static void fixedUpdate() { if (!Object.op_Implicit((Object)(object)_currentDialogBox) && _alertQueue.Count != 0) { Alert alert = _alertQueue.Dequeue(); SimpleDialogBox val = SimpleDialogBox.Create((MPEventSystem)null); alert.SetupDialog(val); _currentDialogBox = val; } } } public static class QuaternionUtils { public static Quaternion PointLocalDirectionAt(Vector3 localDirection, Vector3 targetDirection) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //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) return Util.QuaternionSafeLookRotation(targetDirection) * Quaternion.FromToRotation(localDirection, Vector3.forward); } public static Quaternion Spread(Vector3 direction, float minAngle, float maxAngle, Xoroshiro128Plus rng) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) direction = ((Vector3)(ref direction)).normalized; float num = rng.RangeFloat(minAngle, maxAngle); Vector3 val = Vector3.Cross(direction, RngExtensions.PointOnUnitSphere(rng)); Vector3 normalized = ((Vector3)(ref val)).normalized; return Quaternion.AngleAxis(num, normalized); } public static Quaternion Spread(Vector3 baseDirection, float maxAngle, Xoroshiro128Plus rng) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return Spread(baseDirection, 0f, maxAngle, rng); } } [Serializable] [JsonObject(/*Could not decode attribute arguments.*/)] public struct RunTimeStamp : IEquatable<RunTimeStamp>, IComparable<RunTimeStamp> { [JsonProperty("t")] public RunTimerType TimeType; [JsonProperty("v")] public float Time; private readonly float currentTime { get { Run instance = Run.instance; if (!Object.op_Implicit((Object)(object)instance)) { Log.Warning("no run instance", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\RunTimeStamp.cs", "currentTime", 27); return 0f; } return instance.GetRunTime(TimeType); } } public readonly float TimeUntil => Time - currentTime; public readonly float TimeSince => currentTime - Time; public readonly float TimeUntilClamped => Mathf.Max(0f, TimeUntil); public readonly float TimeSinceClamped => Mathf.Max(0f, TimeSince); public readonly bool HasPassed => currentTime >= Time; public readonly bool IsInfinity => float.IsInfinity(Time); public readonly bool IsPositiveInfinity => float.IsPositiveInfinity(Time); public readonly bool IsNegativeInfinity => float.IsNegativeInfinity(Time); public RunTimeStamp(RunTimerType timeType, float time) { TimeType = timeType; Time = time; } public static RunTimeStamp Now(RunTimerType timeType) { Run instance = Run.instance; float time; if (Object.op_Implicit((Object)(object)instance)) { time = instance.GetRunTime(timeType); } else { Log.Warning("no run instance", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\RunTimeStamp.cs", "Now", 68); time = 0f; } return new RunTimeStamp(timeType, time); } public readonly RunTimeStamp ConvertTo(RunTimerType timeType) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to inva
plugins/RiskOfChaos/RiskOfChaos_PatcherInterop.dll
Decompiled 3 days agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using Microsoft.CodeAnalysis; using RoR2; using RoR2.Projectile; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("RiskOfChaos")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("RiskOfChaos_PatcherInterop")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c158cf629270665c915140fc70b979c1b9cb1479")] [assembly: AssemblyProduct("RiskOfChaos_PatcherInterop")] [assembly: AssemblyTitle("RiskOfChaos_PatcherInterop")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 RiskOfChaos_PatcherInterop { internal static class ProjectileInteropExtensions { private static float? decodeProcCoefficientOverride(float overridePlusOne) { float num = overridePlusOne - 1f; if (num < 0f) { return null; } return num; } private static float encodeProcCoefficientOverride(float? overrideProcCoefficient) { if (!overrideProcCoefficient.HasValue) { return 0f; } return overrideProcCoefficient.Value + 1f; } public static float GetProcCoefficientOverridePlusOne(this in FireProjectileInfo fireProjectileInfo) { return fireProjectileInfo.roc_procCoefficientOverridePlusOne; } public static float? GetProcCoefficientOverride(this in FireProjectileInfo fireProjectileInfo) { return decodeProcCoefficientOverride(fireProjectileInfo.roc_procCoefficientOverridePlusOne); } public static void SetProcCoefficientOverridePlusOne(this ref FireProjectileInfo fireProjectileInfo, float value) { fireProjectileInfo.roc_procCoefficientOverridePlusOne = value; } public static void SetProcCoefficientOverride(this ref FireProjectileInfo fireProjectileInfo, float? value) { fireProjectileInfo.roc_procCoefficientOverridePlusOne = encodeProcCoefficientOverride(value); } public static float GetProcCoefficientOverridePlusOne(this PlayerFireProjectileMessage playerFireProjectileMessage) { return playerFireProjectileMessage.roc_procCoefficientOverridePlusOne; } public static float? GetProcCoefficientOverride(this PlayerFireProjectileMessage playerFireProjectileMessage) { return decodeProcCoefficientOverride(playerFireProjectileMessage.roc_procCoefficientOverridePlusOne); } public static void SetProcCoefficientOverridePlusOne(this PlayerFireProjectileMessage playerFireProjectileMessage, float value) { playerFireProjectileMessage.roc_procCoefficientOverridePlusOne = value; } public static void SetProcCoefficientOverride(this PlayerFireProjectileMessage playerFireProjectileMessage, float? value) { playerFireProjectileMessage.roc_procCoefficientOverridePlusOne = encodeProcCoefficientOverride(value); } public static ProcChainMask GetProcChainMask(this PlayerFireProjectileMessage playerFireProjectileMessage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return playerFireProjectileMessage.roc_procChainMask; } public static void SetProcChainMask(this PlayerFireProjectileMessage playerFireProjectileMessage, ProcChainMask procChainMask) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) playerFireProjectileMessage.roc_procChainMask = procChainMask; } } }
plugins/RiskOfChaos/RiskOfTwitch.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.WebSockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Authentication; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Web; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using RiskOfTwitch.Chat.Message; using RiskOfTwitch.Chat.Notification; using RiskOfTwitch.Logging; using RiskOfTwitch.User; using RiskOfTwitch.WebSockets; using UnityEngine; [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("RiskOfTwitch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c158cf629270665c915140fc70b979c1b9cb1479")] [assembly: AssemblyProduct("RiskOfTwitch")] [assembly: AssemblyTitle("RiskOfTwitch")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 RiskOfTwitch { public class Authentication { public const string CLIENT_ID = "2h96zmad9nhz11unv407c9ou6i6ofj"; public const string AUTH_REDIRECT_URL = "http://localhost:4000/roc/oauth/redirect"; private static readonly byte[] _authRedirectResponseBytes = Encoding.ASCII.GetBytes("<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n</head>\r\n<body>\r\nAuthentication complete. You may close this window.\r\n <script>\r\n var url = window.location;\r\n url.replace(window.location.hash, \"\");\r\n fetch(url, {\r\n method: 'GET',\r\n headers: {\r\n 'fragment': window.location.hash\r\n }\r\n });\r\n </script>\r\n</body>"); public static string CreateAuthorizeUrl(string scopes, out string authState) { using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create()) { byte[] array = new byte[16]; randomNumberGenerator.GetBytes(array); StringBuilder stringBuilder = new StringBuilder(32); for (int i = 0; i < 16; i++) { stringBuilder.Append(array[i].ToString("x2")); } authState = stringBuilder.ToString(); } return "https://id.twitch.tv/oauth2/authorize?response_type=token&client_id=2h96zmad9nhz11unv407c9ou6i6ofj&redirect_uri=http://localhost:4000/roc/oauth/redirect&scope=" + HttpUtility.UrlEncode(scopes) + "&state=" + authState; } public static async Task<Result<string>> AuthenticateUserAccessToken(string scopes, CancellationToken cancellationToken = default(CancellationToken)) { Application.OpenURL(CreateAuthorizeUrl(scopes, out var authState)); using HttpListener httpListener = new HttpListener(); httpListener.Prefixes.Add("http://localhost:4000/roc/oauth/redirect/"); httpListener.Start(); HttpListenerContext context2 = await httpListener.GetContextAsync().ConfigureAwait(continueOnCapturedContext: false); context2.Response.ContentType = "text/html"; context2.Response.ContentEncoding = Encoding.ASCII; context2.Response.ContentLength64 = _authRedirectResponseBytes.LongLength; await context2.Response.OutputStream.WriteAsync(_authRedirectResponseBytes, 0, _authRedirectResponseBytes.Length, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); context2.Response.Close(); context2 = await httpListener.GetContextAsync().ConfigureAwait(continueOnCapturedContext: false); string text = context2.Request.Headers["fragment"]; Uri url = context2.Request.Url; Dictionary<string, string> destination = new Dictionary<string, string>(); if (url != null) { string text2 = url.Query; if (!string.IsNullOrEmpty(text2)) { if (text2[0] == '?') { text2 = text2.Substring(1); } UrlUtils.SplitUrlQueries(text2, destination); } } Dictionary<string, string> dictionary = new Dictionary<string, string>(); if (!string.IsNullOrEmpty(text)) { if (text[0] == '#') { text = text.Substring(1); } UrlUtils.SplitUrlQueries(text, dictionary); } context2.Response.StatusCode = 200; context2.Response.KeepAlive = false; context2.Response.Close(); if (!dictionary.TryGetValue("state", out var value) || !string.Equals(authState, value)) { return new Result<string>(new AuthenticationException("Invalid authentication state")); } if (!dictionary.TryGetValue("access_token", out var value2)) { return new Result<string>(new AuthenticationException("No token received")); } return value2; } public static async Task<Result<AuthenticationTokenValidationResponse>> GetAccessTokenValidationAsync(string accessToken, CancellationToken cancellationToken = default(CancellationToken)) { using HttpClient client = new HttpClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken); using HttpResponseMessage validationResponse = await client.GetAsync("https://id.twitch.tv/oauth2/validate", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); string text = await validationResponse.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false); if (!validationResponse.IsSuccessStatusCode) { if (validationResponse.StatusCode == HttpStatusCode.Unauthorized && !string.IsNullOrEmpty(text) && text.Contains("invalid access token", StringComparison.OrdinalIgnoreCase)) { return new Result<AuthenticationTokenValidationResponse>(new InvalidAccessTokenException()); } return new Result<AuthenticationTokenValidationResponse>(new HttpResponseException(validationResponse)); } try { return JsonConvert.DeserializeObject<AuthenticationTokenValidationResponse>(text); } catch (Exception exception) { return new Result<AuthenticationTokenValidationResponse>(exception); } } } [Serializable] public class AuthenticationTokenValidationResponse { [JsonProperty("client_id")] public string ClientId { get; set; } = string.Empty; [JsonProperty("login")] public string Username { get; set; } = string.Empty; [JsonProperty("scopes")] public string[] Scopes { get; set; } = Array.Empty<string>(); [JsonProperty("user_id")] public string UserID { get; set; } = string.Empty; [JsonProperty("expires_in")] private int expiresInSeconds { get { return (int)Math.Round(ExpiryDate.TimeUntil.TotalSeconds); } set { ExpiryDate = DateTime.Now.AddSeconds(value); } } [JsonIgnore] public DateTimeStamp ExpiryDate { get; set; } } public readonly struct DateTimeStamp : IEquatable<DateTimeStamp> { public readonly DateTime Time; public static DateTimeStamp Now => new DateTimeStamp(DateTime.Now); public TimeSpan TimeSince => DateTime.Now - Time; public TimeSpan TimeUntil => Time - DateTime.Now; public bool IsFuture => TimeUntil.Ticks > 0; public bool HasPassed => TimeSince.Ticks > 0; public DateTimeStamp(DateTime time) { Time = time; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(Time.ToString()); if (IsFuture) { stringBuilder.Append($" (in {TimeUntil})"); } else { stringBuilder.Append($" ({TimeSince} ago)"); } return stringBuilder.ToString(); } public override bool Equals(object obj) { if (obj is DateTimeStamp other) { return Equals(other); } return false; } public bool Equals(DateTimeStamp other) { return Time == other.Time; } public override int GetHashCode() { return 615635108 + Time.GetHashCode(); } public static implicit operator DateTimeStamp(DateTime time) { return new DateTimeStamp(time); } public static bool operator ==(DateTimeStamp left, DateTimeStamp right) { return left.Equals(right); } public static bool operator !=(DateTimeStamp left, DateTimeStamp right) { return !(left == right); } public static bool operator <(DateTimeStamp left, DateTimeStamp right) { return left.Time < right.Time; } public static bool operator <(DateTimeStamp left, DateTime right) { return left.Time < right; } public static bool operator <(DateTime left, DateTimeStamp right) { return left < right.Time; } public static bool operator >(DateTimeStamp left, DateTimeStamp right) { return left.Time > right.Time; } public static bool operator >(DateTimeStamp left, DateTime right) { return left.Time > right; } public static bool operator >(DateTime left, DateTimeStamp right) { return left > right.Time; } public static bool operator <=(DateTimeStamp left, DateTimeStamp right) { return left.Time <= right.Time; } public static bool operator <=(DateTimeStamp left, DateTime right) { return left.Time <= right; } public static bool operator <=(DateTime left, DateTimeStamp right) { return left <= right.Time; } public static bool operator >=(DateTimeStamp left, DateTimeStamp right) { return left.Time >= right.Time; } public static bool operator >=(DateTimeStamp left, DateTime right) { return left.Time >= right; } public static bool operator >=(DateTime left, DateTimeStamp right) { return left >= right.Time; } } public sealed class HttpResponseException : Exception { public HttpStatusCode StatusCode { get; } public string ReasonPhrase { get; } public HttpResponseException(HttpStatusCode statusCode, string reasonPhrase) : base($"{statusCode} ({reasonPhrase})") { StatusCode = statusCode; ReasonPhrase = reasonPhrase; } public HttpResponseException(HttpResponseMessage responseMessage) : this(responseMessage.StatusCode, responseMessage.ReasonPhrase) { } } public sealed class InvalidAccessTokenException : Exception { public InvalidAccessTokenException() : base("The provided access token is not valid or has expired") { } } public static class Log { private static readonly object _stringBuilderLock; private static readonly StringBuilder _sharedStringBuilder; private static readonly int _cachedCallerPathPrefixLength; public static ILogSource LogSource { get; set; } static Log() { LogSource = new ConsoleLogSource(); _stringBuilderLock = new object(); _sharedStringBuilder = new StringBuilder(256); _cachedCallerPathPrefixLength = getCallerPathPrefixLength("D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\Log.cs"); static int getCallerPathPrefixLength([CallerFilePath] string callerPath = null) { int num = callerPath.LastIndexOf("RiskOfTwitch"); if (num >= 0) { return num; } Error_NoCallerPrefix("[RiskOfTwitch] Logger failed to determine caller path prefix length"); return 0; } } private static StringBuilder AppendCallerPrefix(this StringBuilder stringBuilder, string callerPath, string callerMemberName, int callerLineNumber) { return stringBuilder.Append(callerPath, _cachedCallerPathPrefixLength, callerPath.Length - _cachedCallerPathPrefixLength).Append(':').Append(callerLineNumber) .Append(" (") .Append(callerMemberName) .Append("):"); } private static StringBuilder buildCallerLogString(string callerPath, string callerMemberName, int callerLineNumber, object data) { lock (_stringBuilderLock) { return _sharedStringBuilder.Clear().AppendCallerPrefix(callerPath, callerMemberName, callerLineNumber).Append(' ') .Append(data); } } [Conditional("DEBUG")] internal static void Debug(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Debug); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Conditional("DEBUG")] internal static void Debug_NoCallerPrefix(object data) { LogSource.Log(data, LogType.Debug); } internal static void Error(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Error); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Error_NoCallerPrefix(object data) { LogSource.Log(data, LogType.Error); } internal static void Fatal(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Fatal); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Fatal_NoCallerPrefix(object data) { LogSource.Log(data, LogType.Fatal); } internal static void Info(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Info); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Info_NoCallerPrefix(object data) { LogSource.Log(data, LogType.Info); } internal static void Message(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Message); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Message_NoCallerPrefix(object data) { LogSource.Log(data, LogType.Message); } internal static void Warning(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Warning); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Warning_NoCallerPrefix(object data) { LogSource.Log(data, LogType.Warning); } } public sealed class Result<T> { private readonly T _value; public bool IsSuccess { get; } public Exception Exception { get; } public T Value { get { if (!IsSuccess) { throw new ArgumentException("Result is not success, cannot get value"); } return _value; } } private Result(T value, Exception exception, bool isSuccess) { _value = value; Exception = exception; IsSuccess = isSuccess; } public Result(T value) : this(value, (Exception)null, isSuccess: true) { } public Result(Exception exception) : this(default(T), exception, isSuccess: false) { } public static implicit operator Result<T>(T value) { return new Result<T>(value); } } public static class StaticTwitchAPI { public static async Task<Result<GetUsersResponse>> GetUsers(string accessToken, string[] userIds, string[] usernames, CancellationToken cancellationToken = default(CancellationToken)) { if (userIds == null) { userIds = Array.Empty<string>(); } if (usernames == null) { usernames = Array.Empty<string>(); } int num = userIds.Length + usernames.Length; if (num == 0) { return GetUsersResponse.Empty; } if (num > 100) { return new Result<GetUsersResponse>(new ArgumentOutOfRangeException("userIds, usernames", "Combined size of user ids and usernames cannot exceed 100")); } using HttpClient client = new HttpClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken); client.DefaultRequestHeaders.Add("Client-Id", "2h96zmad9nhz11unv407c9ou6i6ofj"); StringBuilder stringBuilder = new StringBuilder(num * 25); string[] array = userIds; foreach (string arg in array) { if (stringBuilder.Length > 0) { stringBuilder.Append('&'); } stringBuilder.AppendFormat("id={0}", arg); } array = usernames; foreach (string arg2 in array) { if (stringBuilder.Length > 0) { stringBuilder.Append('&'); } stringBuilder.AppendFormat("login={0}", arg2); } using HttpResponseMessage getUsersResponseMessage = await client.GetAsync($"https://api.twitch.tv/helix/users?{stringBuilder}", cancellationToken).ConfigureAwait(continueOnCapturedContext: false); if (!getUsersResponseMessage.IsSuccessStatusCode) { return new Result<GetUsersResponse>(new HttpResponseException(getUsersResponseMessage)); } GetUsersResponse getUsersResponse; try { getUsersResponse = JsonConvert.DeserializeObject<GetUsersResponse>(await getUsersResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false)); } catch (JsonException val) { return new Result<GetUsersResponse>((Exception)val); } return getUsersResponse; } } public static class UrlUtils { public static void SplitUrlQueries(string queries, IDictionary<string, string> destination) { if (destination == null) { throw new ArgumentNullException("destination"); } if (string.IsNullOrWhiteSpace(queries)) { return; } string[] array = queries.Split(new char[1] { '&' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split('='); if (array2.Length == 2) { string text = HttpUtility.UrlDecode(array2[0]).Trim(); string value = HttpUtility.UrlDecode(array2[1]).Trim(); if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(value) && !destination.ContainsKey(text)) { destination.Add(text, value); } } } } } } namespace RiskOfTwitch.WebSockets { internal abstract class ClientWebSocketConnection : IDisposable { private ClientWebSocket _client; private readonly CancellationTokenSource _objectDisposedTokenSource = new CancellationTokenSource(); private bool _isReconnecting; private bool _hasEverConnected; private bool _isDisposed; public Uri ConnectionUrl { get; set; } public bool AutoReconnect { get; set; } = true; public TimeSpan ConnectionTimeout { get; set; } = TimeSpan.FromSeconds(30.0); public WebSocketState? State => _client?.State; public ClientWebSocketConnection(Uri url) { ConnectionUrl = url; } public void Dispose() { if (_isDisposed) { return; } _isDisposed = true; _objectDisposedTokenSource.Cancel(); _objectDisposedTokenSource.Dispose(); if (_client != null) { try { Disconnect().Wait(TimeSpan.FromSeconds(2.0)); } catch (Exception data) { Log.Error(data, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "Dispose", 51); } _client?.Dispose(); _client = null; } } private void throwIfDisposed() { lock (this) { if (_isDisposed) { throw new ObjectDisposedException(string.Format("{0} ({1})", "ClientWebSocketConnection", ConnectionUrl)); } } } protected virtual ClientWebSocket createClient() { ClientWebSocket clientWebSocket = new ClientWebSocket(); clientWebSocket.Options.KeepAliveInterval = ConnectionTimeout; return clientWebSocket; } public async Task Connect(CancellationToken cancellationToken = default(CancellationToken)) { throwIfDisposed(); if (_client != null) { if (State.GetValueOrDefault() == WebSocketState.Connecting || State.GetValueOrDefault() == WebSocketState.Open) { Log.Error("Already connected", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "Connect", 87); return; } Log.Warning("Connecting while there is still an existing client instance, disposing old instance", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "Connect", 91); _client.Dispose(); } CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_objectDisposedTokenSource.Token, cancellationToken); _client = createClient(); await _client.ConnectAsync(ConnectionUrl, cancellationTokenSource.Token).ConfigureAwait(continueOnCapturedContext: false); if (!_hasEverConnected) { Task.Run(() => updateLoop(_objectDisposedTokenSource.Token)); _hasEverConnected = true; } } public virtual async Task Disconnect(CancellationToken cancellationToken = default(CancellationToken)) { if (_client != null) { if (State >= WebSocketState.CloseSent) { _client.Dispose(); _client = null; return; } CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_objectDisposedTokenSource.Token, cancellationToken); await _client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", cancellationTokenSource.Token).ConfigureAwait(continueOnCapturedContext: false); _client?.Dispose(); _client = null; } } public async Task Reconnect(TimeSpan delay = default(TimeSpan), CancellationToken cancellationToken = default(CancellationToken)) { _isReconnecting = true; try { await Disconnect(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); await Task.Delay(delay).ConfigureAwait(continueOnCapturedContext: false); await Connect(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } finally { _isReconnecting = false; } } private async Task updateLoop(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { if (_client == null) { if (AutoReconnect && !_isReconnecting) { await Connect(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } } else if (State.GetValueOrDefault() == WebSocketState.Open || State.GetValueOrDefault() == WebSocketState.CloseSent) { try { await handleNextMessageAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) when (!(ex is OperationCanceledException)) { Log.Error_NoCallerPrefix($"Unhandled exception handling web socket message: {ex}"); await Reconnect(TimeSpan.FromSeconds(1.0), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } } } } private async Task<WebSocketMessage> receiveMessageAsync(CancellationToken cancellationToken) { byte[] receivedData = new byte[1024]; int totalReceivedDataLength = 0; WebSocketReceiveResult webSocketReceiveResult; while (true) { if (totalReceivedDataLength >= receivedData.Length) { Array.Resize(ref receivedData, receivedData.Length + 1024); continue; } ArraySegment<byte> buffer = new ArraySegment<byte>(receivedData, totalReceivedDataLength, receivedData.Length - totalReceivedDataLength); webSocketReceiveResult = await _client.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); totalReceivedDataLength += webSocketReceiveResult.Count; if (webSocketReceiveResult.EndOfMessage) { break; } } return new WebSocketMessage(new ArraySegment<byte>(receivedData, 0, totalReceivedDataLength), webSocketReceiveResult); } private async Task handleNextMessageAsync(CancellationToken cancellationToken) { using CancellationTokenSource timeoutTokenSource = new CancellationTokenSource(ConnectionTimeout); using CancellationTokenSource cancelledOrTimedOutTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token); WebSocketMessage message; try { message = await receiveMessageAsync(cancelledOrTimedOutTokenSource.Token).ConfigureAwait(continueOnCapturedContext: false); } catch (OperationCanceledException) { if (timeoutTokenSource.Token.IsCancellationRequested) { Log.Info("WebSocket connection timed out, attempting reconnect...", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "handleNextMessageAsync", 212); await Reconnect(TimeSpan.FromSeconds(1.0), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); return; } throw; } if (message.MessageType == WebSocketMessageType.Close) { if (message.CloseStatus.GetValueOrDefault() != WebSocketCloseStatus.NormalClosure) { if (shouldReconnect(message)) { Log.Info($"WebSocket connection closed (status={message.CloseStatus}, description='{message.CloseStatusDescription}'), attempting reconnect...", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "handleNextMessageAsync", 227); await Reconnect(TimeSpan.FromSeconds(1.0), cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } else { Log.Info($"WebSocket connection closed (status={message.CloseStatus}, description='{message.CloseStatusDescription}'), not attempting reconnect", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "handleNextMessageAsync", 233); AutoReconnect = false; await Disconnect(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } } else { Log.Info("WebSocket connection closed", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "handleNextMessageAsync", 241); } } else { await handleSocketMessageAsync(message, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } } protected abstract Task handleSocketMessageAsync(WebSocketMessage message, CancellationToken cancellationToken); protected virtual bool shouldReconnect(WebSocketMessage closingMessage) { return true; } } internal readonly struct WebSocketMessage { public readonly ArraySegment<byte> MessageData; public readonly WebSocketCloseStatus? CloseStatus; public readonly string CloseStatusDescription; public readonly WebSocketMessageType MessageType; public WebSocketMessage(ArraySegment<byte> messageData, WebSocketReceiveResult result) { MessageData = messageData; CloseStatus = result.CloseStatus; CloseStatusDescription = result.CloseStatusDescription; MessageType = result.MessageType; } } } namespace RiskOfTwitch.User { public class GetUsersResponse { public static GetUsersResponse Empty { get; } = new GetUsersResponse { Users = Array.Empty<TwitchUserData>() }; [JsonProperty("data")] public TwitchUserData[] Users { get; set; } = Array.Empty<TwitchUserData>(); } public class TwitchUserData { [JsonProperty("id")] public string UserId { get; set; } [JsonProperty("login")] public string UserLoginName { get; set; } [JsonProperty("display_name")] public string UserDisplayName { get; set; } [JsonProperty("type")] public string UserType { get; set; } [JsonProperty("broadcaster_type")] public string BroadcasterType { get; set; } [JsonProperty("description")] public string UserDescription { get; set; } [JsonProperty("profile_image_url")] public string ProfileImageURL { get; set; } [JsonProperty("offline_image_url")] public string OfflineImageURL { get; set; } [JsonProperty("email")] public string UserEmail { get; set; } [JsonProperty("created_at")] public string UserCreatedAt { get; set; } } } namespace RiskOfTwitch.Logging { internal class ConsoleLogSource : ILogSource { public void Log(object message, LogType type) { if (type != 0) { Console.WriteLine(message); } } } public interface ILogSource { void Log(object message, LogType type); } public enum LogType { Debug, Info, Message, Warning, Error, Fatal } } namespace RiskOfTwitch.EventSub { public enum ConnectionErrorType { FailedRetrieveUser, FailedEventSubscribe, TokenAuthenticationFailed, TokenInvalid, Generic } public class ConnectionErrorEventArgs : EventArgs { public ConnectionErrorType Type { get; } public ConnectionErrorEventArgs(ConnectionErrorType type) { Type = type; } } internal interface ITwitchEventSubMessageHandler { Task HandleEventAsync(JToken deserializedEvent, CancellationToken cancellationToken); } public class TokenAccessRevokedEventData { public readonly string SubscriptionType; public readonly string Status; public TokenAccessRevokedEventData(string subscriptionType, string status) { SubscriptionType = subscriptionType; Status = status; } } public class TwitchEventSubClient : ITwitchEventSubMessageHandler { private readonly string _accessToken; private readonly string _overrideBroadcasterName; private readonly HashSet<string> _handledMessageIDs = new HashSet<string>(); private readonly HashSet<string> _activeSubscriptions = new HashSet<string>(); private CancellationTokenSource _disconnectedTokenSource = new CancellationTokenSource(); private TwitchEventSubConnection _mainConnection; private TwitchEventSubConnection _migratingConnection; private string _sessionID; public string ConnectedToChannel { get; private set; } public bool IsConnecting { get { if (_mainConnection != null) { return _mainConnection.State.GetValueOrDefault() == WebSocketState.Connecting; } return false; } } public bool HasConnection { get { if (_mainConnection != null) { return _mainConnection.State.GetValueOrDefault() == WebSocketState.Open; } return false; } } public bool IsFullyConnected { get { if (!string.IsNullOrEmpty(_sessionID)) { return _activeSubscriptions.Count > 0; } return false; } } public bool IsMigrating => _migratingConnection != null; public event EventHandler<ChannelChatMessageEvent> OnChannelChatMessage; public event EventHandler<ChannelChatNotificationEvent> OnChannelChatNotification; public event EventHandler<TokenAccessRevokedEventData> OnTokenAccessRevoked; public event EventHandler OnFullyConnected; public event EventHandler<ConnectionErrorEventArgs> OnConnectionError; public TwitchEventSubClient(string accessToken, string overrideBroadcasterName) { _accessToken = accessToken; _overrideBroadcasterName = overrideBroadcasterName; } public Task Connect(CancellationToken cancellationToken = default(CancellationToken)) { return Connect(new Uri("wss://eventsub.wss.twitch.tv/ws"), cancellationToken); } public async Task Connect(Uri uri, CancellationToken cancellationToken = default(CancellationToken)) { _disconnectedTokenSource?.Dispose(); _disconnectedTokenSource = new CancellationTokenSource(); using CancellationTokenSource cancelledOrDisconnectedSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _disconnectedTokenSource.Token); if (_mainConnection == null) { _mainConnection = new TwitchEventSubConnection(uri, this); await _mainConnection.Connect(cancelledOrDisconnectedSource.Token).ConfigureAwait(continueOnCapturedContext: false); } else { _mainConnection.ConnectionUrl = uri; await _mainConnection.Reconnect(TimeSpan.FromSeconds(0.5), cancelledOrDisconnectedSource.Token).ConfigureAwait(continueOnCapturedContext: false); } } public async Task Disconnect(CancellationToken cancellationToken = default(CancellationToken)) { _disconnectedTokenSource.Cancel(); if (_mainConnection != null) { await _mainConnection.Disconnect(cancellationToken); _mainConnection?.Dispose(); _mainConnection = null; } if (_migratingConnection != null) { await _migratingConnection.Disconnect(cancellationToken); _migratingConnection?.Dispose(); _migratingConnection = null; } if (_activeSubscriptions.Count <= 0) { return; } foreach (string subscriptionId in _activeSubscriptions) { using HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + _accessToken); httpClient.DefaultRequestHeaders.Add("Client-Id", "2h96zmad9nhz11unv407c9ou6i6ofj"); httpClient.DeleteAsync("https://api.twitch.tv/helix/eventsub/subscriptions?id=" + subscriptionId, cancellationToken).ContinueWith(delegate(Task<HttpResponseMessage> task) { if (!task.IsCanceled) { if (!task.IsFaulted) { using (HttpResponseMessage httpResponseMessage = task.Result) { if (!httpResponseMessage.IsSuccessStatusCode) { Log.Error($"Unable to delete subscription {subscriptionId}: {httpResponseMessage.StatusCode:D} {httpResponseMessage.ReasonPhrase}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "Disconnect", 126); } return; } } Log.Error(task.Exception, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "Disconnect", 118); } }); } _activeSubscriptions.Clear(); } private void beginMigration(string reconnectUrl) { _migratingConnection = new TwitchEventSubConnection(new Uri(reconnectUrl), this); _migratingConnection.Connect(); } public async Task HandleEventAsync(JToken jsonObject, CancellationToken cancellationToken) { JToken val = jsonObject.SelectToken("metadata.message_id", false); if (val == null) { Log.Error("Could not deserialize message_id property", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "HandleEventAsync", 153); } else { if (!_handledMessageIDs.Add(val.ToObject<string>())) { return; } JToken val2 = jsonObject.SelectToken("metadata.message_type", false); if (val2 != null) { using (CancellationTokenSource cancelledOrDisconnectedSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _disconnectedTokenSource.Token)) { string text = val2.ToObject<string>(); switch (text) { case "session_welcome": await handleSessionWelcomeMessage(jsonObject, cancelledOrDisconnectedSource.Token); break; case "notification": handleNotificationMessage(jsonObject); break; case "session_reconnect": handleSessionReconnectMessage(jsonObject); break; case "revocation": handleRevokeMessageAsync(jsonObject); break; default: Log.Warning("Unhandled message type: " + text, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "HandleEventAsync", 188); break; case "session_keepalive": break; } return; } } Log.Error("Could not deserialize message_type property", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "HandleEventAsync", 163); } } private void handleSessionReconnectMessage(JToken jsonObject) { //IL_0035: Expected O, but got Unknown JToken val = jsonObject.SelectToken("payload.session", false); if (val == null) { Log.Error("Could not deserialize session data", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionReconnectMessage", 198); return; } WebSocketSessionData webSocketSessionData; try { webSocketSessionData = val.ToObject<WebSocketSessionData>(); } catch (JsonException val2) { JsonException arg = val2; Log.Error_NoCallerPrefix($"Failed to deserialize session object: {arg}"); return; } beginMigration(webSocketSessionData.ReconnectUrl); } private void handleRevokeMessageAsync(JToken jsonObject) { string text = null; string text2 = null; JToken val = jsonObject.SelectToken("payload.subscription", false); if (val != null) { JToken val2 = val.SelectToken("type", false); if (val2 != null) { text = val2.ToObject<string>(); } JToken val3 = val.SelectToken("status", false); if (val3 != null) { text2 = val3.ToObject<string>(); } } this.OnTokenAccessRevoked?.Invoke(this, new TokenAccessRevokedEventData(text ?? string.Empty, text2 ?? string.Empty)); } private async Task handleSessionWelcomeMessage(JToken jsonObject, CancellationToken cancellationToken) { JToken val = jsonObject.SelectToken("payload.session", false); if (val == null) { Log.Error("Could not deserialize session data", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 247); this.OnConnectionError?.Invoke(this, new ConnectionErrorEventArgs(ConnectionErrorType.Generic)); return; } WebSocketSessionData webSocketSessionData; try { webSocketSessionData = val.ToObject<WebSocketSessionData>(); } catch (JsonException val2) { JsonException arg = val2; Log.Error_NoCallerPrefix($"Failed to deserialize session object: {arg}"); this.OnConnectionError?.Invoke(this, new ConnectionErrorEventArgs(ConnectionErrorType.Generic)); return; } if (IsMigrating) { if (_mainConnection != null) { _mainConnection.Dispose(); _mainConnection = null; } _mainConnection = _migratingConnection; return; } _sessionID = webSocketSessionData.SessionID; Result<AuthenticationTokenValidationResponse> result = await Authentication.GetAccessTokenValidationAsync(_accessToken, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); if (!result.IsSuccess) { ConnectionErrorType type = ConnectionErrorType.TokenAuthenticationFailed; if (result.Exception is InvalidAccessTokenException) { type = ConnectionErrorType.TokenInvalid; } this.OnConnectionError?.Invoke(this, new ConnectionErrorEventArgs(type)); return; } AuthenticationTokenValidationResponse value = result.Value; string userId = value.UserID; string broadcasterId = userId; string broadcasterName = value.Username; if (!string.IsNullOrEmpty(_overrideBroadcasterName)) { Result<GetUsersResponse> result2 = await StaticTwitchAPI.GetUsers(_accessToken, Array.Empty<string>(), new string[1] { _overrideBroadcasterName }, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); if (result2.IsSuccess) { broadcasterName = _overrideBroadcasterName; broadcasterId = result2.Value.Users[0].UserId; } else { Log.Error($"Failed to retrieve override broadcaster data {result2.Exception}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 366); } } ConnectedToChannel = broadcasterName; bool flag = true; bool flag2 = flag; flag = flag2 & await sendSubscription<<>f__AnonymousType0<string, string, <>f__AnonymousType1<string, string>, <>f__AnonymousType2<string, string>>>(new { type = "channel.chat.message", version = "1", condition = new { broadcaster_user_id = broadcasterId, user_id = userId }, transport = new { method = "websocket", session_id = _sessionID } }, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); flag2 = flag; if (flag2 & await sendSubscription<<>f__AnonymousType0<string, string, <>f__AnonymousType1<string, string>, <>f__AnonymousType2<string, string>>>(new { type = "channel.chat.notification", version = "1", condition = new { broadcaster_user_id = broadcasterId, user_id = userId }, transport = new { method = "websocket", session_id = _sessionID } }, cancellationToken).ConfigureAwait(continueOnCapturedContext: false)) { this.OnFullyConnected?.Invoke(this, EventArgs.Empty); } else { this.OnConnectionError?.Invoke(this, new ConnectionErrorEventArgs(ConnectionErrorType.FailedEventSubscribe)); } async Task<bool> sendSubscription<T>(T message, CancellationToken cancellationToken) { using HttpClient client = new HttpClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer " + _accessToken); client.DefaultRequestHeaders.Add("Client-Id", "2h96zmad9nhz11unv407c9ou6i6ofj"); StringContent stringContent = new StringContent(JsonConvert.SerializeObject((object)message)); stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); using HttpResponseMessage subscribeResponseMessage = await client.PostAsync("https://api.twitch.tv/helix/eventsub/subscriptions", stringContent, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); if (!subscribeResponseMessage.IsSuccessStatusCode) { Log.Error($"Subscribe failed: {subscribeResponseMessage.StatusCode:D} ({subscribeResponseMessage.StatusCode:G}) {subscribeResponseMessage.ReasonPhrase}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 309); return false; } using StreamReader responseReader = new StreamReader(await subscribeResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(continueOnCapturedContext: false), Encoding.UTF8); JsonReader responseJsonReader = (JsonReader)new JsonTextReader((TextReader)responseReader); try { _ = 2; JToken val3; try { val3 = await JToken.ReadFromAsync(responseJsonReader, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } catch (JsonException val4) { JsonException arg2 = val4; Log.Error($"Failed to deserialize subscribe response: {arg2}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 329); return false; } JToken obj = val3.SelectToken("data", false); JArray val5 = (JArray)(object)((obj is JArray) ? obj : null); if (val5 == null || ((JContainer)val5).Count <= 0) { Log.Error("Subscribe response contained invalid data", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 336); return false; } JToken val6 = val5[0].SelectToken("id"); if (val6 == null) { Log.Error("Could not find subscription id", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 343); return false; } _activeSubscriptions.Add(val6.ToObject<string>()); return true; } finally { ((IDisposable)responseJsonReader)?.Dispose(); } } } private void handleNotificationMessage(JToken jsonObject) { JToken val = jsonObject.SelectToken("payload.subscription.type", false); if (val == null) { Log.Error("Failed to find subscription type", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleNotificationMessage", 421); return; } string text = val.ToObject<string>(); if (!(text == "channel.chat.message")) { if (text == "channel.chat.notification") { handleChannelChatNotificationNotification(jsonObject); } else { Log.Warning("Unhandled notification message: " + text, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleNotificationMessage", 435); } } else { handleChannelChatMessageNotification(jsonObject); } } private void handleChannelChatMessageNotification(JToken jsonObject) { //IL_003d: Expected O, but got Unknown if (this.OnChannelChatMessage == null) { return; } JToken val = jsonObject.SelectToken("payload.event"); if (val == null) { Log.Error("Failed to find event object", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleChannelChatMessageNotification", 448); return; } ChannelChatMessageEvent e; try { e = val.ToObject<ChannelChatMessageEvent>(); } catch (JsonException val2) { JsonException arg = val2; Log.Error_NoCallerPrefix($"Failed to deserialize chat message: {arg}"); return; } this.OnChannelChatMessage?.Invoke(this, e); } private void handleChannelChatNotificationNotification(JToken jsonObject) { //IL_003d: Expected O, but got Unknown if (this.OnChannelChatNotification == null) { return; } JToken val = jsonObject.SelectToken("payload.event"); if (val == null) { Log.Error("Failed to find event object", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleChannelChatNotificationNotification", 474); return; } ChannelChatNotificationEvent e; try { e = val.ToObject<ChannelChatNotificationEvent>(); } catch (JsonException val2) { JsonException arg = val2; Log.Error_NoCallerPrefix($"Failed to deserialize chat notification: {arg}"); return; } this.OnChannelChatNotification?.Invoke(this, e); } } internal class TwitchEventSubConnection : ClientWebSocketConnection { private readonly ITwitchEventSubMessageHandler _eventHandler; public TwitchEventSubConnection(Uri url, ITwitchEventSubMessageHandler eventHandler) : base(url) { _eventHandler = eventHandler; } protected override async Task handleSocketMessageAsync(WebSocketMessage message, CancellationToken cancellationToken) { if (message.MessageType != 0) { Log.Warning($"Unhandled socket message type: {message.MessageType}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubConnection.cs", "handleSocketMessageAsync", 32); return; } using MemoryStream memoryStream = new MemoryStream(message.MessageData.Array, message.MessageData.Offset, message.MessageData.Count); using StreamReader streamReader = new StreamReader(memoryStream, Encoding.UTF8); JsonTextReader jsonReader = new JsonTextReader((TextReader)streamReader); try { JToken deserializedMessage; try { deserializedMessage = await JToken.ReadFromAsync((JsonReader)(object)jsonReader, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } catch (JsonException val) { JsonException arg = val; Log.Error_NoCallerPrefix($"Failed to deserialize web socket message: {arg}"); return; } Task.Run(async delegate { await _eventHandler.HandleEventAsync(deserializedMessage, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); }); } finally { ((IDisposable)jsonReader)?.Dispose(); } } protected override bool shouldReconnect(WebSocketMessage closingMessage) { if (closingMessage.CloseStatus.HasValue) { switch (closingMessage.CloseStatus.Value) { case (WebSocketCloseStatus)4003: case (WebSocketCloseStatus)4004: return false; } } return base.shouldReconnect(closingMessage); } } [Serializable] public class WebSocketSessionData { [JsonProperty("id")] public string SessionID { get; set; } [JsonProperty("status")] public string Status { get; set; } [JsonProperty("connected_at")] public string ConnectedAt { get; set; } [JsonProperty("keepalive_timeout_seconds")] public int? KeepaliveTimeoutSeconds { get; set; } [JsonProperty("reconnect_url")] public string ReconnectUrl { get; set; } } } namespace RiskOfTwitch.Emotes { public class EmoteSetEmoteData { [JsonProperty("id")] public string EmoteId { get; set; } [JsonProperty("name")] public string EmoteName { get; set; } [JsonProperty("images")] public EmoteSetEmoteImageData ImageData { get; set; } [JsonProperty("emote_type")] public string EmoteType { get; set; } [JsonProperty("emote_set_id")] public string EmoteSetId { get; set; } [JsonProperty("owner_id")] public string EmoteOwnerId { get; set; } [JsonProperty("format")] public string[] EmoteFormats { get; set; } [JsonProperty("scale")] public string[] Scales { get; set; } [JsonProperty("theme_mode")] public string[] ThemeModes { get; set; } } public class EmoteSetEmoteImageData { [JsonProperty("url_1x")] public string SmallUrl { get; set; } [JsonProperty("url_2x")] public string MediumUrl { get; set; } [JsonProperty("url_4x")] public string LargeUrl { get; set; } } public class GetEmoteSetResponse { public static GetEmoteSetResponse Empty { get; } = new GetEmoteSetResponse { Emotes = Array.Empty<EmoteSetEmoteData>(), UrlTemplate = string.Empty }; [JsonProperty("data")] public EmoteSetEmoteData[] Emotes { get; set; } [JsonProperty("template")] public string UrlTemplate { get; set; } public bool TryFindEmote(string emoteId, out EmoteSetEmoteData emote) { EmoteSetEmoteData[] emotes = Emotes; foreach (EmoteSetEmoteData emoteSetEmoteData in emotes) { if (string.Equals(emoteSetEmoteData.EmoteId, emoteId, StringComparison.Ordinal)) { emote = emoteSetEmoteData; return true; } } emote = null; return false; } public string GetEmoteFetchUrl(EmoteSetEmoteData emote, string format, string theme, string scale) { return UrlTemplate.Replace("{{id}}", emote.EmoteId).Replace("{{format}}", format).Replace("{{theme_mode}}", theme) .Replace("{{scale}}", scale); } } } namespace RiskOfTwitch.Chat { public class ChannelChatClearUserMessagesEvent { [JsonProperty("broadcaster_user_id")] public string BroadcasterUserId { get; set; } [JsonProperty("broadcaster_user_name")] public string BroadcasterDisplayName { get; set; } [JsonProperty("broadcaster_user_login")] public string BroadcasterLoginName { get; set; } [JsonProperty("target_user_id")] public string TargetUserId { get; set; } [JsonProperty("target_user_name")] public string TargetUserDisplayName { get; set; } [JsonProperty("target_user_login")] public string TargetUserLoginName { get; set; } } public class ChatterBadgeData { [JsonProperty("set_id")] public string BadgeSetID { get; set; } [JsonProperty("id")] public string BadgeID { get; set; } [JsonProperty("info")] public string BadgeMetadata { get; set; } } } namespace RiskOfTwitch.Chat.Notification { public class ChannelChatAnnouncementNotificationData { [JsonProperty("color")] public string Color { get; set; } } public class ChannelChatBitsBadgeTierNotificationData { [JsonProperty("tier")] public int Tier { get; set; } } public class ChannelChatCharityDonationAmountData { [JsonProperty("value")] public int Value { get; set; } [JsonProperty("decimal_place")] public int DecimalPlace { get; set; } [JsonProperty("currency")] public string CurrencyCode { get; set; } } public class ChannelChatCharityDonationNotificationData { [JsonProperty("charity_name")] public string CharityName { get; set; } [JsonProperty("amount")] public ChannelChatCharityDonationAmountData Amount { get; set; } } public class ChannelChatCommunitySubGiftNotificationData { [JsonProperty("id")] public string Id { get; set; } [JsonProperty("total")] public int Amount { get; set; } [JsonProperty("sub_tier")] public string SubTier { get; set; } [JsonProperty("cumulative_total")] public int? TotalGiftedByUser { get; set; } } public class ChannelChatGiftPaidUpgradeNotificationData { [JsonProperty("gifter_is_anonymous")] public bool GifterIsAnonymous { get; set; } [JsonProperty("gifter_user_id")] public string GifterUserId { get; set; } [JsonProperty("gifter_user_name")] public string GifterDisplayName { get; set; } [JsonProperty("gifter_user_login")] public string GifterLoginName { get; set; } } public class ChannelChatNotificationEvent { [JsonProperty("broadcaster_user_id")] public string BroadcasterUserId { get; set; } [JsonProperty("broadcaster_user_name")] public string BroadcasterDisplayName { get; set; } [JsonProperty("broadcaster_user_login")] public string BroadcasterLoginName { get; set; } [JsonProperty("chatter_user_id")] public string ChatterUserId { get; set; } [JsonProperty("chatter_user_name")] public string ChatterDisplayName { get; set; } [JsonProperty("chatter_user_login")] public string ChatterLoginName { get; set; } [JsonProperty("chatter_is_anonymous")] public bool AnonymousChatter { get; set; } [JsonProperty("color")] public string ChatterNameColor { get; set; } [JsonProperty("badges")] public ChatterBadgeData[] Badges { get; set; } [JsonProperty("system_message")] public string SystemMessage { get; set; } [JsonProperty("message_id")] public string MessageId { get; set; } [JsonProperty("message")] public ChannelChatMessageData MessageData { get; set; } [JsonProperty("notice_type")] public string NoticeType { get; set; } [JsonProperty("sub")] public ChannelChatSubNotificationData SubData { get; set; } [JsonProperty("resub")] public ChannelChatResubNotificationData ResubData { get; set; } [JsonProperty("sub_gift")] public ChannelChatSubGiftNotificationData SubGiftData { get; set; } [JsonProperty("community_sub_gift")] public ChannelChatCommunitySubGiftNotificationData CommunitySubGiftData { get; set; } [JsonProperty("gift_paid_upgrade")] public ChannelChatGiftPaidUpgradeNotificationData GiftPaidUpgradeData { get; set; } [JsonProperty("prime_paid_upgrade")] public ChannelChatPrimePaidUpgradeNotificationData PrimePaidUpgradeData { get; set; } [JsonProperty("raid")] public ChannelChatRaidNotificationData RaidData { get; set; } [JsonProperty("unraid")] public ChannelChatUnraidNotificationData UnraidData { get; set; } [JsonProperty("pay_it_forward")] public ChannelChatPayItForwardNotificationData PayItForwardData { get; set; } [JsonProperty("announcement")] public ChannelChatAnnouncementNotificationData AnnouncementData { get; set; } [JsonProperty("charity_donation")] public ChannelChatCharityDonationNotificationData CharityDonationData { get; set; } [JsonProperty("bits_badge_tier")] public ChannelChatBitsBadgeTierNotificationData ChatBitsBadgeTierData { get; set; } } public class ChannelChatPayItForwardNotificationData { [JsonProperty("gifter_is_anonymous")] public bool GifterIsAnonymous { get; set; } [JsonProperty("gifter_user_id")] public string GifterUserId { get; set; } [JsonProperty("gifter_user_name")] public string GifterDisplayName { get; set; } [JsonProperty("gifter_user_login")] public string GifterLoginName { get; set; } } public class ChannelChatPrimePaidUpgradeNotificationData { [JsonProperty("sub_tier")] public string Tier { get; set; } } public class ChannelChatRaidNotificationData { [JsonProperty("user_id")] public string RaiderUserId { get; set; } [JsonProperty("user_name")] public string RaiderDisplayName { get; set; } [JsonProperty("user_login")] public string RaiderLoginName { get; set; } [JsonProperty("viewer_count")] public int NumViewers { get; set; } [JsonProperty("profile_image_url")] public string RaiderProfileImageUrl { get; set; } } public class ChannelChatResubNotificationData { [JsonProperty("cumulative_months")] public int CumulativeMonths { get; set; } [JsonProperty("duration_months")] public int DurationMonths { get; set; } [JsonProperty("streak_months")] public int? StreakMonths { get; set; } [JsonProperty("sub_tier")] public string Tier { get; set; } [JsonProperty("is_prime")] public bool? IsPrime { get; set; } [JsonProperty("is_gift")] public bool IsGifted { get; set; } [JsonProperty("gifter_is_anonymous")] public bool? GifterIsAnonymous { get; set; } [JsonProperty("gifter_user_id")] public string GifterUserId { get; set; } [JsonProperty("gifter_user_name")] public string GifterDisplayName { get; set; } [JsonProperty("gifter_user_login")] public string GifterLoginName { get; set; } } public class ChannelChatSubGiftNotificationData { [JsonProperty("duration_months")] public int DurationMonths { get; set; } [JsonProperty("cumulative_total")] public int? TotalSubsGivenByUser { get; set; } [JsonProperty("recipient_user_id")] public string RecipientUserId { get; set; } [JsonProperty("recipient_user_name")] public string RecipientDisplayName { get; set; } [JsonProperty("recipient_user_login")] public string RecipientLoginName { get; set; } [JsonProperty("sub_tier")] public string SubTier { get; set; } [JsonProperty("community_gift_id")] public string CommunityGiftId { get; set; } } public class ChannelChatSubNotificationData { [JsonProperty("sub_tier")] public string Tier { get; set; } [JsonProperty("is_prime")] public bool IsPrime { get; set; } [JsonProperty("duration_months")] public int DurationMonths { get; set; } } public class ChannelChatUnraidNotificationData { } } namespace RiskOfTwitch.Chat.Message { public class ChannelChatMessageData { [JsonProperty("text")] public string FullText { get; set; } [JsonProperty("fragments")] public ChatMessageFragment[] Fragments { get; set; } } public class ChannelChatMessageEvent { [JsonProperty("broadcaster_user_id")] public string BroadcasterUserId { get; set; } [JsonProperty("broadcaster_user_name")] public string BroadcasterDisplayName { get; set; } [JsonProperty("broadcaster_user_login")] public string BroadcasterLoginName { get; set; } [JsonProperty("chatter_user_id")] public string ChatterUserId { get; set; } [JsonProperty("chatter_user_name")] public string ChatterDisplayName { get; set; } [JsonProperty("chatter_user_login")] public string ChatterLoginName { get; set; } [JsonProperty("message")] public ChannelChatMessageData MessageData { get; set; } [JsonProperty("message_type")] public string MessageType { get; set; } [JsonProperty("badges")] public ChatterBadgeData[] UserBadges { get; set; } [JsonProperty("cheer")] public ChatMessageCheerData CheerData { get; set; } [JsonProperty("color")] public string UserColor { get; set; } [JsonProperty("reply")] public ChatMessageReplyData ReplyData { get; set; } [JsonProperty("channel_points_custom_reward_id")] public string ChannelPointRedeemID { get; set; } } public class ChatMessageCheerData { [JsonProperty("bits")] public int TotalBits { get; set; } } public class ChatMessageCheermoteData { [JsonProperty("prefix")] public string Prefix { get; set; } [JsonProperty("bits")] public int BitAmount { get; set; } [JsonProperty("tier")] public int Tier { get; set; } } public class ChatMessageEmoteData { private static readonly string[] _emoteModificationSuffixes = new string[5] { "_BW", "_HF", "_SG", "_SQ", "_TK" }; private string _emoteID; [JsonProperty("id")] public string EmoteID { get { return _emoteID; } set { _emoteID = value; string text = _emoteID; string[] emoteModificationSuffixes = _emoteModificationSuffixes; foreach (string text2 in emoteModificationSuffixes) { if (text.EndsWith(text2)) { text = text.Remove(text.Length - text2.Length); break; } } BaseEmoteID = text; } } [JsonIgnore] public string BaseEmoteID { get; private set; } [JsonProperty("emote_set_id")] public string EmoteSetID { get; set; } [JsonProperty("owner_id")] public string EmoteOwnerUserID { get; set; } [JsonProperty("format")] public string[] EmoteTypes { get; set; } } public class ChatMessageFragment { [JsonProperty("type")] public string FragmentType { get; set; } [JsonProperty("text")] public string FragmentText { get; set; } [JsonProperty("cheermote")] public ChatMessageCheermoteData CheermoteData { get; set; } [JsonProperty("emote")] public ChatMessageEmoteData EmoteData { get; set; } [JsonProperty("mention")] public ChatMessageMentionData MentionData { get; set; } } public class ChatMessageMentionData { [JsonProperty("user_id")] public string MentionedUserID { get; set; } [JsonProperty("user_name")] public string MentionedUserDisplayName { get; set; } [JsonProperty("user_login")] public string MentionedUserLoginName { get; set; } } public class ChatMessageReplyData { [JsonProperty("parent_message_id")] public string ReplyingToMessageID { get; set; } [JsonProperty("parent_message_body")] public string ReplyingToMessageBody { get; set; } [JsonProperty("parent_user_id")] public string ReplyingToUserID { get; set; } [JsonProperty("parent_user_name")] public string ReplyingToUserDisplayName { get; set; } [JsonProperty("parent_user_login")] public string ReplyingToUserLoginName { get; set; } [JsonProperty("thread_message_id")] public string ThreadRootMessageID { get; set; } [JsonProperty("thread_user_id")] public string ThreadRootUserID { get; set; } [JsonProperty("thread_user_name")] public string ThreadRootUserDisplayName { get; set; } [JsonProperty("thread_user_login")] public string ThreadRootUserLoginName { get; set; } } }