

using 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+185a0f39c4b3d300dea0a9a7bc277dc0938d8ec6")]
[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 sealed 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 static 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_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Expected O, but got Unknown
TypeDefinition type = assembly.MainModule.GetType("RoR2.Projectile.FireProjectileInfo");
if (type == null)
{
_log.Error("Failed to find type: FireProjectileInfo");
return;
}
TypeReference val = assembly.MainModule.ImportReference(typeof(float));
addField(type, new FieldDefinition("roc_procCoefficientOverridePlusOne", (FieldAttributes)6, val));
}
private static void addField(TypeDefinition declaringType, FieldDefinition field)
{
declaringType.Fields.Add(field);
}
}
}
[CompilerGenerated]
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();
}
}
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 AK.Wwise;
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.Loader;
using EntityStates.Merc;
using EntityStates.Toolbot;
using EntityStates.VoidInfestor;
using HG;
using HG.Coroutines;
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.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.Logbook;
using RiskOfChaos.Content.Orbs;
using RiskOfChaos.EffectDefinitions;
using RiskOfChaos.EffectDefinitions.Character;
using RiskOfChaos.EffectDefinitions.Character.Buff;
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.PatcherInterop;
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 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.Audio;
using RoR2.CameraModes;
using RoR2.CharacterAI;
using RoR2.ConVar;
using RoR2.ContentManagement;
using RoR2.EntitlementManagement;
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+6e0465f6f074660b5b26433765a42c05415c18bb")]
[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
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class ParamCollectionAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
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;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
[Microsoft.CodeAnalysis.Embedded]
[CompilerGenerated]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class ScopedRefAttribute : Attribute
{
}
[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; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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_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_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Expected O, but got Unknown
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
ConfigFactory<int> configFactory = ConfigFactory<int>.CreateConfig("Effect List Size", Math.Min(50, ChaosEffectCatalog.EffectCount / 2)).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 timer-based 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;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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 = 20u;
public static readonly 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 < 20)
{
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 = 20u;
}
}
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();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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 FileInfo findFileInParentDirectories(DirectoryInfo startDir, string searchPattern)
{
DirectoryInfo directoryInfo = startDir;
while (directoryInfo != null && !string.Equals(directoryInfo.FullName, Paths.PluginPath, StringComparison.OrdinalIgnoreCase))
{
FileInfo fileInfo = directoryInfo.EnumerateFiles(searchPattern, SearchOption.TopDirectoryOnly).FirstOrDefault();
if (fileInfo != null)
{
return fileInfo;
}
directoryInfo = directoryInfo.Parent;
}
return null;
}
private static Sprite generateIcon()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
FileInfo fileInfo = findFileInParentDirectories(new DirectoryInfo(RiskOfChaosPlugin.ModDirectory), "icon.png");
if (fileInfo == null)
{
return null;
}
Texture2D val = new Texture2D(256, 256);
((Object)val).name = "texRiskOfChaosIcon";
if (!ImageConversion.LoadImage(val, File.ReadAllBytes(fileInfo.FullName)))
{
Object.Destroy((Object)(object)val);
return null;
}
Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
((Object)obj).name = "RiskOfChaosIcon";
return obj;
}
internal static void Init(ConfigFile file)
{
General.Bind(file);
EffectSelection.Bind(file);
UI.Bind(file);
ChatVoting.Bind(file);
ChatVotingUI.Bind(file);
Metadata.Bind(file);
if (!Object.op_Implicit((Object)(object)GenericIcon))
{
GenericIcon = generateIcon();
}
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(RiskOfChaosPlugin.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);
}
}
}
internal static class MidRunArtifactsHandler
{
[CompilerGenerated]
private static class <>O
{
public static ArtifactStateChangeDelegate <0>__RunArtifactManager_onArtifactEnabledGlobal;
public static ArtifactStateChangeDelegate <1>__RunArtifactManager_onArtifactDisabledGlobal;
}
[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
//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;
}
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 (enabled)
{
foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
{
if (readOnlyLocalUsers != null)
{
CharacterMaster cachedMaster = readOnlyLocalUsers.cachedMaster;
if (Object.op_Implicit((Object)(object)cachedMaster))
{
CharacterMasterNotificationQueue.PushArtifactNotification(cachedMaster, artifactDef);
}
}
}
}
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();
}
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", 175);
val2 = new DirectorCard
{
spawnCard = (SpawnCard)(object)AddressableUtil.LoadTempAssetAsync<InteractableSpawnCard>("234cc71a82b0e82468900be4c544c1c8").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", 185);
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)
{
if (((NetworkBehaviour)readOnlyInstances).isLocalPlayer)
{
LocalUser localUser = readOnlyInstances.localUser;
UserProfile val = ((localUser != null) ? localUser.userProfile : null);
if (val != null && !string.IsNullOrEmpty(val.RebirthItem))
{
val.RebirthItem = null;
val.RequestEventualSave();
}
}
}
}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("Gorakh.RiskOfChaos", "RiskOfChaos", "2.7.1")]
[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.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class RiskOfChaosPlugin : BaseUnityPlugin
{
public const string PluginGUID = "Gorakh.RiskOfChaos";
public const string PluginAuthor = "Gorakh";
public const string PluginName = "RiskOfChaos";
public const string PluginVersion = "2.7.1";
private Harmony _harmonyInstance;
private static RiskOfChaosPlugin _instance;
public static RiskOfChaosPlugin Instance => _instance;
public static string ModDirectory { get; private set; }
public RoCContent ContentPackProvider { get; private set; }
private void Awake()
{
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Expected O, but got Unknown
SingletonHelper.Assign<RiskOfChaosPlugin>(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();
}
ProcTypeAPICompat.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<RiskOfChaosPlugin>(ref _instance, this);
TaskExceptionHandler.Cleanup();
if (ProperSaveCompat.Active)
{
ProperSaveCompat.Cleanup();
}
Harmony harmonyInstance = _harmonyInstance;
if (harmonyInstance != null)
{
harmonyInstance.UnpatchSelf();
}
}
}
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 AddressableUtil
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AsyncOperationHandle<T> LoadAssetAsync<T>(string assetGuid, AsyncReferenceHandleUnloadType unloadType = 2) where T : Object
{
//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)
return AssetAsyncReferenceManager<T>.LoadAsset(new AssetReferenceT<T>(assetGuid), unloadType);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AsyncOperationHandle<T> LoadAssetAsync<T>(AssetReferenceT<T> assetReference, AsyncReferenceHandleUnloadType unloadType = 2) where T : Object
{
//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)
return AssetAsyncReferenceManager<T>.LoadAsset(assetReference, unloadType);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AsyncOperationHandle<T> LoadTempAssetAsync<T>(string assetGuid) where T : Object
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
return LoadTempAssetAsync<T>(new AssetReferenceT<T>(assetGuid));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AsyncOperationHandle<T> LoadTempAssetAsync<T>(AssetReferenceT<T> assetReference) where T : Object
{
//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_002d: Unknown result type (might be due to invalid IL or missing references)
AsyncOperationHandle<T> result = AssetAsyncReferenceManager<T>.LoadAsset(assetReference, (AsyncReferenceHandleUnloadType)2);
result.Completed += delegate
{
AssetAsyncReferenceManager<T>.UnloadAsset(assetReference);
};
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void UnloadAsset<T>(AssetReferenceT<T> assetReference) where T : Object
{
AssetAsyncReferenceManager<T>.UnloadAsset(assetReference);
}
}
public readonly struct AsyncOperationCoroutineProgressReporter : IEnumerator
{
private readonly IAsyncOperationCoroutine _coroutine;
private readonly IProgress<float> _progressReceiver;
object IEnumerator.Current => _coroutine.Current;
public AsyncOperationCoroutineProgressReporter(IAsyncOperationCoroutine asyncOperationHandle, IProgress<float> progressReceiver)
{
_coroutine = asyncOperationHandle;
_progressReceiver = progressReceiver;
}
bool IEnumerator.MoveNext()
{
_progressReceiver.Report(_coroutine.Progress);
return _coroutine.MoveNext();
}
void IEnumerator.Reset()
{
_coroutine.Reset();
}
}
public readonly struct AsyncOperationCoroutineWrapper : IAsyncOperationCoroutine, IEnumerator
{
private readonly AsyncOperationHandle _asyncOperationHandle;
public float Progress
{
get
{
//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)
AsyncOperationHandle asyncOperationHandle = _asyncOperationHandle;
return ((AsyncOperationHandle)(ref asyncOperationHandle)).PercentComplete;
}
}
object IEnumerator.Current => ((IEnumerator)_asyncOperationHandle).Current;
public AsyncOperationCoroutineWrapper(AsyncOperationHandle asyncOperationHandle)
{
//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)
_asyncOperationHandle = asyncOperationHandle;
}
bool IEnumerator.MoveNext()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return ((IEnumerator)_asyncOperationHandle).MoveNext();
}
void IEnumerator.Reset()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
((IEnumerator)_asyncOperationHandle).Reset();
}
}
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 BuffUtils
{
private static string[] _buffNameTokenLookup = Array.Empty<string>();
[SystemInitializer(new Type[] { typeof(BuffCatalog) })]
private static void Init()
{
_buffNameTokenLookup = new string[BuffCatalog.buffCount];
Array.Fill(_buffNameTokenLookup, string.Empty);
StringBuilder stringBuilder = StringBuilderPool.RentStringBuilder();
for (int i = 0; i < BuffCatalog.buffCount; i++)
{
BuffDef buffDef = BuffCatalog.GetBuffDef((BuffIndex)i);
if (!Object.op_Implicit((Object)(object)buffDef))
{
continue;
}
string name = ((Object)buffDef).name;
if (string.IsNullOrWhiteSpace(name))
{
continue;
}
name = name.Trim();
int num = 0;
if (name.StartsWith("bd"))
{
num += 2;
}
stringBuilder.Clear();
stringBuilder.EnsureCapacity(name.Length + 15);
stringBuilder.Append("ROC_BUFF_");
for (int j = num; j < name.Length; j++)
{
char c = name[j];
if (j > num && char.IsUpper(c))
{
stringBuilder.Append('_');
}
stringBuilder.Append(char.ToUpper(c));
}
stringBuilder.Append("_NAME");
_buffNameTokenLookup[i] = stringBuilder.ToString();
}
stringBuilder = StringBuilderPool.ReturnStringBuilder(stringBuilder);
}
public static string GetBuffNameToken(BuffIndex buffIndex)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected I4, but got Unknown
return ArrayUtils.GetSafe<string>(_buffNameTokenLookup, (int)buffIndex, ref string.Empty);
}
public static string GetBuffNameToken(BuffDef buffDef)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
return GetBuffNameToken((BuffIndex)((!Object.op_Implicit((Object)(object)buffDef)) ? (-1) : ((int)buffDef.buffIndex)));
}
public static string GetLocalizedBuffName(BuffDef buffDef)
{
if (!Object.op_Implicit((Object)(object)buffDef))
{
return string.Empty;
}
if (buffDef.isElite)
{
string modifierToken = buffDef.eliteDef.modifierToken;
if (!string.IsNullOrEmpty(modifierToken) && !Language.IsTokenInvalid(modifierToken))
{
return Language.GetStringFormatted(modifierToken, new object[1] { string.Empty }).Trim();
}
}
string buffNameToken = GetBuffNameToken(buffDef);
if (!string.IsNullOrEmpty(buffNameToken) && !Language.IsTokenInvalid(buffNameToken))
{
return Language.GetString(buffNameToken);
}
return string.Empty;
}
[ConCommand(/*Could not decode attribute arguments.*/)]
private static void CCPrintUnnamedBuffs(ConCommandArgs args)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
bool argBool = ((ConCommandArgs)(ref args)).GetArgBool(0);
for (int i = 0; i < BuffCatalog.buffCount; i++)
{
BuffIndex val = (BuffIndex)i;
BuffDef buffDef = BuffCatalog.GetBuffDef(val);
if (Object.op_Implicit((Object)(object)buffDef) && (!argBool || !buffDef.isHidden))
{
string buffNameToken = GetBuffNameToken(val);
if (string.IsNullOrEmpty(buffNameToken) || Language.IsTokenInvalid(buffNameToken))
{
Debug.Log((object)(((Object)buffDef).name + ": " + buffNameToken));
}
}
}
}
}
public static class CharacterBodyUtils
{
public static void MarkAllBodyStatsDirty()
{
foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
{
readOnlyInstances.MarkAllStatsDirty();
}
}
}
public static class CharacterMasterNotificationQueueUtils
{
[SystemInitializer(new Type[] { })]
private static void Init()
{
InventoryExtensions.PickupTransformation.OnPickupTransformedServerGlobal += onPickupTransformedServerGlobal;
}
private static void onPickupTransformedServerGlobal(InventoryExtensions.PickupTransformation.TryTransformResult transformResult)
{
//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_0009: Invalid comparison between Unknown and I4
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: 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_0061: 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)
//IL_0071: Expected O, but got Unknown
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Expected O, but got Unknown
TransformationType transformationType = (TransformationType)transformResult.TransformationType;
CharacterMaster val = default(CharacterMaster);
if ((int)transformationType == -1 || !Object.op_Implicit((Object)(object)transformResult.Inventory) || !((Component)transformResult.Inventory).TryGetComponent<CharacterMaster>(ref val) || !Object.op_Implicit((Object)(object)val.playerCharacterMasterController))
{
return;
}
if (Util.HasEffectiveAuthority(((Component)val).gameObject))
{
CharacterMasterNotificationQueue notificationQueueForMaster = CharacterMasterNotificationQueue.GetNotificationQueueForMaster(val);
if (Object.op_Implicit((Object)(object)notificationQueueForMaster))
{
TransformationInfo val2 = new TransformationInfo(transformationType, (object)PickupCatalog.GetPickupDef(transformResult.TakenPickup.PickupIndex));
NotificationInfo val3 = new NotificationInfo((object)PickupCatalog.GetPickupDef(transformResult.GivenPickup.PickupIndex), val2, (CustomOverrideInfo)null, false, transformResult.GivenPickup.StackValues.temporaryStacksValue > 0f, 0);
notificationQueueForMaster.PushNotification(val3, 6f);
}
}
else
{
NetMessageExtensions.Send((INetMessage)(object)new PickupTransformationNotificationMessage(val, transformResult.TakenPickup.PickupIndex, transformResult.GivenPickup.PickupIndex, transformationType), ((NetworkBehaviour)val).connectionToClient);
}
}
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", 50);
}
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 component = ((Component)viewerMaster).GetComponent<CharacterMasterNotificationQueue>();
if (Object.op_Implicit((Object)(object)component))
{
return component.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 EffectCatalogUtils
{
private static readonly Dictionary<string, EffectIndex> _effectIndexByPrefabName = new Dictionary<string, EffectIndex>();
[SystemInitializer(new Type[] { typeof(EffectCatalog) })]
private static void Init()
{
//IL_001b: 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: Invalid comparison between Unknown and I4
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: 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_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
_effectIndexByPrefabName.Clear();
_effectIndexByPrefabName.EnsureCapacity(EffectCatalog.effectCount);
for (EffectIndex val = (EffectIndex)0; (int)val < EffectCatalog.effectCount; val = (EffectIndex)(val + 1))
{
EffectDef effectDef = EffectCatalog.GetEffectDef(val);
if (effectDef != null && !string.IsNullOrWhiteSpace(effectDef.prefabName))
{
if (_effectIndexByPrefabName.ContainsKey(effectDef.prefabName))
{
Log.Warning("Duplicate effect prefab name '" + effectDef.prefabName + "'", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\EffectCatalogUtils.cs", "Init", 23);
}
_effectIndexByPrefabName[effectDef.prefabName] = val;
}
}
}
public static EffectIndex FindEffectIndex(string effectPrefabName)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return System.Collections.Generic.CollectionExtensions.GetValueOrDefault(_effectIndexByPrefabName, effectPrefabName, (EffectIndex)(-1));
}
}
public static class EliteUtils
{
private static EliteIndex[] _validEliteIndices = Array.Empty<EliteIndex>();
private static EquipmentIndex[] _validEliteEquipmentIndices = Array.Empty<EquipmentIndex>();
private static EquipmentIndex[] _allEliteEquipmentIndices = 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_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_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Invalid comparison between Unknown and I4
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
int count = EliteCatalog.eliteList.Count;
HashSet<EliteIndex> hashSet = new HashSet<EliteIndex>(count);
HashSet<EquipmentIndex> hashSet2 = new HashSet<EquipmentIndex>(count);
HashSet<EquipmentIndex> hashSet3 = new HashSet<EquipmentIndex>(count);
foreach (EliteIndex elite in EliteCatalog.eliteList)
{
EliteDef eliteDef = EliteCatalog.GetEliteDef(elite);
if (!Object.op_Implicit((Object)(object)eliteDef))
{
continue;
}
EquipmentDef eliteEquipmentDef = eliteDef.eliteEquipmentDef;
if (!Object.op_Implicit((Object)(object)eliteEquipmentDef) || (int)eliteEquipmentDef.equipmentIndex == -1)
{
continue;
}
hashSet3.Add(eliteEquipmentDef.equipmentIndex);
if (!string.IsNullOrWhiteSpace(eliteDef.modifierToken) && !Language.IsTokenInvalid(eliteDef.modifierToken) && !((Object)eliteDef).name.EndsWith("Honor", StringComparison.OrdinalIgnoreCase))
{
bool flag = ((eliteEquipmentDef.pickupModelReference == null || !((AssetReference)eliteEquipmentDef.pickupModelReference).RuntimeKeyIsValid()) ? (!Object.op_Implicit((Object)(object)eliteEquipmentDef.pickupModelPrefab) || ((Object)eliteEquipmentDef.pickupModelPrefab).name == "NullModel") : (((AssetReference)eliteEquipmentDef.pickupModelReference).RuntimeKey as string == "56b77f2cfa2f8d743ae18780a672ecb7"));
if (!flag && hashSet2.Add(eliteEquipmentDef.equipmentIndex))
{
hashSet.Add(elite);
}
}
}
_validEliteIndices = hashSet.ToArray();
Array.Sort(_validEliteIndices);
_validEliteEquipmentIndices = hashSet2.ToArray();
Array.Sort(_validEliteEquipmentIndices);
_allEliteEquipmentIndices = hashSet3.ToArray();
Array.Sort(_allEliteEquipmentIndices);
if (_validEliteIndices.Length != 0)
{
Run.onRunStartGlobal += onRunStartGlobal;
Run.onRunDestroyGlobal += onRunDestroyGlobal;
}
}
private static void onRunStartGlobal(Run run)
{
//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> list = new List<EliteIndex>(_validEliteIndices.Length);
EliteIndex[] validEliteIndices = _validEliteIndices;
foreach (EliteIndex val in validEliteIndices)
{
EliteDef eliteDef = EliteCatalog.GetEliteDef(val);
if (Object.op_Implicit((Object)(object)eliteDef) && eliteDef.IsAvailable())
{
list.Add(val);
}
}
_runAvailableEliteIndices = list.ToArray();
}
private static void onRunDestroyGlobal(Run run)
{
_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(_validEliteIndices, 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 IReadOnlyList<EliteIndex> GetRunAvailableElites(bool ignoreEliteTierAvailability)
{
if (!ignoreEliteTierAvailability)
{
return GetAllCombatDirectorElites();
}
return Array.AsReadOnly(_runAvailableEliteIndices);
}
public static IReadOnlyList<EliteIndex> GetAllCombatDirectorElites()
{
//IL_0043: 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_0061: 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 (!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.AsReadOnly();
}
public static bool IsEliteEquipment(EquipmentIndex equipmentIndex)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
return Array.BinarySearch(_allEliteEquipmentIndices, equipmentIndex) >= 0;
}
}
public record struct EquipmentLocation(uint Slot, uint Set);
public sealed 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 ResourceAvailability Availability = default(ResourceAvailability);
public static ExpansionIndex DLC1 { get; private set; } = (ExpansionIndex)(-1);
public static ExpansionIndex DLC2 { get; private set; } = (ExpansionIndex)(-1);
public static ExpansionIndex DLC3 { get; private set; } = (ExpansionIndex)(-1);
public static bool DLC1Enabled
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return IsExpansionEnabled(DLC1);
}
}
public static bool DLC2Enabled
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return IsExpansionEnabled(DLC2);
}
}
public static bool DLC3Enabled
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return IsExpansionEnabled(DLC3);
}
}
[SystemInitializer(new Type[] { typeof(ExpansionCatalog) })]
private unsafe static void Init()
{
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: 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_0045: 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_005f: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < ExpansionCatalog.expansionDefs.Length; i++)
{
ExpansionDef val = (ExpansionDef)Unsafe.Read<object>((void*)ExpansionCatalog.expansionDefs[i]);
switch (((Object)val).name)
{
case "DLC1":
DLC1 = val.expansionIndex;
break;
case "DLC2":
DLC2 = val.expansionIndex;
break;
case "DLC3":
DLC3 = val.expansionIndex;
break;
}
}
((ResourceAvailability)(ref Availability)).MakeAvailable();
}
public unsafe static ExpansionDef GetExpansionDef(ExpansionIndex index)
{
//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_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_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected I4, but got Unknown
if ((long)(ulong)index >= (long)ExpansionCatalog.expansionDefs.Length)
{
return null;
}
return (ExpansionDef)Unsafe.Read<object>((void*)ExpansionCatalog.expansionDefs[(int)index]);
}
public static bool IsExpansionEnabled(ExpansionIndex expansionIndex)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return IsExpansionEnabled(GetExpansionDef(expansionIndex));
}
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<ExpansionIndex> expansions)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
foreach (ExpansionIndex expansion in expansions)
{
if (!IsExpansionEnabled(expansion))
{
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 IReadOnlyList<ExpansionIndex> GetObjectRequiredExpansionIndices(GameObject obj)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Expected I4, but got Unknown
if (!Object.op_Implicit((Object)(object)obj))
{
return Array.Empty<ExpansionIndex>();
}
List<ExpansionDef> list = new List<ExpansionDef>();
addAllRequiredExpansions(obj, list);
if (list.Count <= 0)
{
return Array.Empty<ExpansionIndex>();
}
ExpansionIndex[] array = (ExpansionIndex[])(object)new ExpansionIndex[list.Count];
for (int i = 0; i < array.Length; i++)
{
array[i] = (ExpansionIndex)(int)list[i].expansionIndex;
}
return array;
}
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 interface IAsyncOperationCoroutine : IEnumerator
{
float Progress { get; }
}
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 sealed 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 r
using 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.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+185a0f39c4b3d300dea0a9a7bc277dc0938d8ec6")]
[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 InteropUtils
{
public static float? DecodePackedOverrideValue(float overridePlusOne)
{
float num = overridePlusOne - 1f;
if (num < 0f)
{
return null;
}
return num;
}
public static float EncodePackedOverrideValue(float? overrideValue)
{
if (!overrideValue.HasValue)
{
return 0f;
}
return overrideValue.Value + 1f;
}
}
internal static class ProjectileInteropExtensions
{
public static float GetProcCoefficientOverridePlusOne(this in FireProjectileInfo fireProjectileInfo)
{
return fireProjectileInfo.roc_procCoefficientOverridePlusOne;
}
public static float? GetProcCoefficientOverride(this in FireProjectileInfo fireProjectileInfo)
{
return InteropUtils.DecodePackedOverrideValue(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 = InteropUtils.EncodePackedOverrideValue(value);
}
}
}
using 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+185a0f39c4b3d300dea0a9a7bc277dc0938d8ec6")]
[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 static 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 sealed 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 sealed class GetUsersResponse
{
public static GetUsersResponse Empty { get; } = new GetUsersResponse
{
Users = Array.Empty<TwitchUserData>()
};
[JsonProperty("data")]
public TwitchUserData[] Users { get; set; } = Array.Empty<TwitchUserData>();
}
public sealed 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 sealed 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 sealed class ConnectionErrorEventArgs : EventArgs
{
public ConnectionErrorType Type { get; }
public ConnectionErrorEventArgs(ConnectionErrorType type)
{
Type = type;
}
}
internal interface ITwitchEventSubMessageHandler
{
Task HandleEventAsync(JToken deserializedEvent, CancellationToken cancellationToken);
}
public sealed class TokenAccessRevokedEventData
{
public readonly string SubscriptionType;
public readonly string Status;
public TokenAccessRevokedEventData(string subscriptionType, string status)
{
SubscriptionType = subscriptionType;
Status = status;
}
}
public sealed 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 sealed 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 sealed 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 sealed 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 sealed 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 sealed 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 sealed 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 sealed 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 sealed class ChannelChatAnnouncementNotificationData
{
[JsonProperty("color")]
public string Color { get; set; }
}
public sealed class ChannelChatBitsBadgeTierNotificationData
{
[JsonProperty("tier")]
public int Tier { get; set; }
}
public sealed 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 sealed class ChannelChatCharityDonationNotificationData
{
[JsonProperty("charity_name")]
public string CharityName { get; set; }
[JsonProperty("amount")]
public ChannelChatCharityDonationAmountData Amount { get; set; }
}
public sealed 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 sealed 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 sealed 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 sealed 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 sealed class ChannelChatPrimePaidUpgradeNotificationData
{
[JsonProperty("sub_tier")]
public string Tier { get; set; }
}
public sealed 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 sealed 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 sealed 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 sealed 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 sealed class ChannelChatUnraidNotificationData
{
}
}
namespace RiskOfTwitch.Chat.Message
{
public sealed class ChannelChatMessageData
{
[JsonProperty("text")]
public string FullText { get; set; }
[JsonProperty("fragments")]
public ChatMessageFragment[] Fragments { get; set; }
}
public sealed 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 sealed class ChatMessageCheerData
{
[JsonProperty("bits")]
public int TotalBits { get; set; }
}
public sealed class ChatMessageCheermoteData
{
[JsonProperty("prefix")]
public string Prefix { get; set; }
[JsonProperty("bits")]
public int BitAmount { get; set; }
[JsonProperty("tier")]
public int Tier { get; set; }
}
public sealed 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 sealed 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 sealed 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 sealed 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; }
}
}