Decompiled source of The Archive UNSTABLE TEST ONLY v0.0.7

BepInEx/plugins/TheArchive.Core/plugins/TheArchive.Core.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using AK;
using Agents;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Hook;
using BepInEx.Unity.IL2CPP.Utils;
using CellMenu;
using Clonesoft.Json;
using Clonesoft.Json.Converters;
using Clonesoft.Json.Serialization;
using CullingSystem;
using Enemies;
using GameData;
using GameEvent;
using Gear;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.Runtime;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.IO;
using Il2CppSystem.Reflection;
using InControl;
using JetBrains.Annotations;
using LevelGeneration;
using Localization;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Player;
using SNetwork;
using SemanticVersioning;
using TMPro;
using TheArchive.Core;
using TheArchive.Core.Attributes;
using TheArchive.Core.Attributes.Feature;
using TheArchive.Core.Attributes.Feature.Members;
using TheArchive.Core.Attributes.Feature.Patches;
using TheArchive.Core.Attributes.Feature.Settings;
using TheArchive.Core.Bootstrap;
using TheArchive.Core.Definitions;
using TheArchive.Core.Definitions.Data;
using TheArchive.Core.Exceptions;
using TheArchive.Core.FeaturesAPI;
using TheArchive.Core.FeaturesAPI.Components;
using TheArchive.Core.FeaturesAPI.Groups;
using TheArchive.Core.FeaturesAPI.Settings;
using TheArchive.Core.Interop;
using TheArchive.Core.Localization;
using TheArchive.Core.Localization.Data;
using TheArchive.Core.Localization.Services;
using TheArchive.Core.Managers;
using TheArchive.Core.Models;
using TheArchive.Core.ModulesAPI;
using TheArchive.Core.Settings;
using TheArchive.Interfaces;
using TheArchive.Loader;
using TheArchive.Utilities;
using UnityEngine;
using UnityEngine.Analytics;
using UnityEngine.CrashReportHandler;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("0.0.838")]
[assembly: AssemblyInformationalVersion("0.0.838-doing-things+a4eb55a")]
[assembly: ModSettingsDisplayName("TheArchive")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TheArchive.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyProduct("TheArchive.Core")]
[assembly: AssemblyTitle("TheArchive.Core")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.838.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
internal class ThisAssembly
{
	public class Git
	{
		public class BaseVersion
		{
			public const string Major = "0";

			public const string Minor = "0";

			public const string Patch = "0";
		}

		public class SemVer
		{
			public const string Major = "0";

			public const string Minor = "0";

			public const string Patch = "838";

			public const string Label = "";

			public const string DashLabel = "";

			public const string Source = "Default";
		}

		public const bool IsDirty = false;

		public const string IsDirtyString = "false";

		public const string RepositoryUrl = "https://github.com/Tuesday1028/GTFO_TheArchive";

		public const string Branch = "doing-things";

		public const string Commit = "a4eb55a";

		public const string Sha = "a4eb55a7e97569a44df6831acc6074b0f084b6eb";

		public const string CommitDate = "2026-05-07T19:14:52+08:00";

		public const string Commits = "838";

		public const string Tag = "";

		public const string BaseTag = "";
	}
}
internal class ManifestInfo
{
	internal const string TSName = "TheArchive_Core";

	internal const string TSDescription = "The main Archive mod, adds the ModSettings menu.";

	internal const string TSVersion = "";

	internal const string TSAuthor = "AuriRex";

	internal const string TSWebsite = "https://github.com/AuriRex/GTFO_TheArchive";
}
namespace JetBrains.Annotations
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Delegate | AttributeTargets.GenericParameter)]
	internal sealed class CanBeNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Delegate | AttributeTargets.GenericParameter)]
	internal sealed class NotNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Delegate)]
	internal sealed class ItemNotNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Delegate)]
	internal sealed class ItemCanBeNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Delegate)]
	internal sealed class StringFormatMethodAttribute : Attribute
	{
		[NotNull]
		public string FormatParameterName { get; }

		public StringFormatMethodAttribute([NotNull] string formatParameterName)
		{
			FormatParameterName = formatParameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class StructuredMessageTemplateAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true)]
	internal sealed class ValueProviderAttribute : Attribute
	{
		[NotNull]
		public string Name { get; }

		public ValueProviderAttribute([NotNull] string name)
		{
			Name = name;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Delegate, AllowMultiple = true)]
	internal sealed class ValueRangeAttribute : Attribute
	{
		public object From { get; }

		public object To { get; }

		public ValueRangeAttribute(long from, long to)
		{
			From = from;
			To = to;
		}

		public ValueRangeAttribute(ulong from, ulong to)
		{
			From = from;
			To = to;
		}

		public ValueRangeAttribute(long value)
		{
			From = (To = value);
		}

		public ValueRangeAttribute(ulong value)
		{
			From = (To = value);
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Delegate)]
	internal sealed class NonNegativeValueAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class InvokerParameterNameAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class NotifyPropertyChangedInvocatorAttribute : Attribute
	{
		[CanBeNull]
		public string ParameterName { get; }

		public NotifyPropertyChangedInvocatorAttribute()
		{
		}

		public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName)
		{
			ParameterName = parameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
	internal sealed class ContractAnnotationAttribute : Attribute
	{
		[NotNull]
		public string Contract { get; }

		public bool ForceFullStates { get; }

		public ContractAnnotationAttribute([NotNull] string contract)
			: this(contract, forceFullStates: false)
		{
		}

		public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates)
		{
			Contract = contract;
			ForceFullStates = forceFullStates;
		}
	}
	[AttributeUsage(AttributeTargets.All)]
	internal sealed class LocalizationRequiredAttribute : Attribute
	{
		public bool Required { get; }

		public LocalizationRequiredAttribute()
			: this(required: true)
		{
		}

		public LocalizationRequiredAttribute(bool required)
		{
			Required = required;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface)]
	internal sealed class CannotApplyEqualityOperatorAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter)]
	internal sealed class DefaultEqualityUsageAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
	[BaseTypeRequired(typeof(Attribute))]
	internal sealed class BaseTypeRequiredAttribute : Attribute
	{
		[NotNull]
		public Type BaseType { get; }

		public BaseTypeRequiredAttribute([NotNull] Type baseType)
		{
			BaseType = baseType;
		}
	}
	[AttributeUsage(AttributeTargets.All)]
	internal sealed class UsedImplicitlyAttribute : Attribute
	{
		public ImplicitUseKindFlags UseKindFlags { get; }

		public ImplicitUseTargetFlags TargetFlags { get; }

		public string Reason { get; set; }

		public UsedImplicitlyAttribute()
			: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)
		{
		}

		public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags)
			: this(useKindFlags, ImplicitUseTargetFlags.Default)
		{
		}

		public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags)
			: this(ImplicitUseKindFlags.Default, targetFlags)
		{
		}

		public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
		{
			UseKindFlags = useKindFlags;
			TargetFlags = targetFlags;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter | AttributeTargets.GenericParameter)]
	internal sealed class MeansImplicitUseAttribute : Attribute
	{
		[UsedImplicitly]
		public ImplicitUseKindFlags UseKindFlags { get; }

		[UsedImplicitly]
		public ImplicitUseTargetFlags TargetFlags { get; }

		public MeansImplicitUseAttribute()
			: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)
		{
		}

		public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags)
			: this(useKindFlags, ImplicitUseTargetFlags.Default)
		{
		}

		public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags)
			: this(ImplicitUseKindFlags.Default, targetFlags)
		{
		}

		public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
		{
			UseKindFlags = useKindFlags;
			TargetFlags = targetFlags;
		}
	}
	[Flags]
	internal enum ImplicitUseKindFlags
	{
		Default = 7,
		Access = 1,
		Assign = 2,
		InstantiatedWithFixedConstructorSignature = 4,
		InstantiatedNoFixedConstructorSignature = 8
	}
	[Flags]
	internal enum ImplicitUseTargetFlags
	{
		Default = 1,
		Itself = 1,
		Members = 2,
		WithInheritors = 4,
		WithMembers = 3
	}
	[MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)]
	[AttributeUsage(AttributeTargets.All, Inherited = false)]
	internal sealed class PublicAPIAttribute : Attribute
	{
		[CanBeNull]
		public string Comment { get; }

		public PublicAPIAttribute()
		{
		}

		public PublicAPIAttribute([NotNull] string comment)
		{
			Comment = comment;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class InstantHandleAttribute : Attribute
	{
		public bool RequireAwait { get; set; }
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class PureAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class MustUseReturnValueAttribute : Attribute
	{
		[CanBeNull]
		public string Justification { get; }

		public bool IsFluentBuilderMethod { get; set; }

		public MustUseReturnValueAttribute()
		{
		}

		public MustUseReturnValueAttribute([NotNull] string justification)
		{
			Justification = justification;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Parameter)]
	internal sealed class MustDisposeResourceAttribute : Attribute
	{
		public bool Value { get; }

		public MustDisposeResourceAttribute()
		{
			Value = true;
		}

		public MustDisposeResourceAttribute(bool value)
		{
			Value = value;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class HandlesResourceDisposalAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class RequireStaticDelegateAttribute : Attribute
	{
		public bool IsError { get; set; }
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.GenericParameter)]
	internal sealed class ProvidesContextAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class PathReferenceAttribute : Attribute
	{
		[CanBeNull]
		public string BasePath { get; }

		public PathReferenceAttribute()
		{
		}

		public PathReferenceAttribute([NotNull][PathReference] string basePath)
		{
			BasePath = basePath;
		}
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class SourceTemplateAttribute : Attribute
	{
		public SourceTemplateTargetExpression Target { get; set; }
	}
	internal enum SourceTemplateTargetExpression
	{
		Inner,
		Outer
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true)]
	internal sealed class MacroAttribute : Attribute
	{
		[CanBeNull]
		public string Expression { get; set; }

		public int Editable { get; set; }

		[CanBeNull]
		public string Target { get; set; }
	}
	[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.ReturnValue)]
	internal sealed class CollectionAccessAttribute : Attribute
	{
		public CollectionAccessType CollectionAccessType { get; }

		public CollectionAccessAttribute(CollectionAccessType collectionAccessType)
		{
			CollectionAccessType = collectionAccessType;
		}
	}
	[Flags]
	internal enum CollectionAccessType
	{
		None = 0,
		Read = 1,
		ModifyExistingContent = 2,
		UpdatedContent = 6
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class AssertionMethodAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class AssertionConditionAttribute : Attribute
	{
		public AssertionConditionType ConditionType { get; }

		public AssertionConditionAttribute(AssertionConditionType conditionType)
		{
			ConditionType = conditionType;
		}
	}
	internal enum AssertionConditionType
	{
		IS_TRUE,
		IS_FALSE,
		IS_NULL,
		IS_NOT_NULL
	}
	[Obsolete("Use [ContractAnnotation('=> halt')] instead")]
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class TerminatesProgramAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class LinqTunnelAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class NoEnumerationAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class RegexPatternAttribute : Attribute
	{
	}
	internal enum InjectedLanguage
	{
		CSS,
		HTML,
		JAVASCRIPT,
		JSON,
		XML
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
	internal sealed class LanguageInjectionAttribute : Attribute
	{
		public InjectedLanguage InjectedLanguage { get; }

		[CanBeNull]
		public string InjectedLanguageName { get; }

		[CanBeNull]
		public string Prefix { get; set; }

		[CanBeNull]
		public string Suffix { get; set; }

		public LanguageInjectionAttribute(InjectedLanguage injectedLanguage)
		{
			InjectedLanguage = injectedLanguage;
		}

		public LanguageInjectionAttribute([NotNull] string injectedLanguage)
		{
			InjectedLanguageName = injectedLanguage;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface, AllowMultiple = true)]
	internal sealed class NoReorderAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
	internal sealed class CodeTemplateAttribute : Attribute
	{
		public string SearchTemplate { get; }

		public string Message { get; set; }

		public string ReplaceTemplate { get; set; }

		public string ReplaceMessage { get; set; }

		public bool FormatAfterReplace { get; set; } = true;


		public bool MatchSimilarConstructs { get; set; }

		public bool ShortenReferences { get; set; }

		public string SuppressionKey { get; set; }

		public CodeTemplateAttribute(string searchTemplate)
		{
			SearchTemplate = searchTemplate;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class IgnoreSpellingAndGrammarErrorsAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
	internal sealed class AspChildControlTypeAttribute : Attribute
	{
		[NotNull]
		public string TagName { get; }

		[NotNull]
		public Type ControlType { get; }

		public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType)
		{
			TagName = tagName;
			ControlType = controlType;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
	internal sealed class AspDataFieldAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
	internal sealed class AspDataFieldsAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property)]
	internal sealed class AspMethodPropertyAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
	internal sealed class AspRequiredAttributeAttribute : Attribute
	{
		[NotNull]
		public string Attribute { get; }

		public AspRequiredAttributeAttribute([NotNull] string attribute)
		{
			Attribute = attribute;
		}
	}
	[AttributeUsage(AttributeTargets.Property)]
	internal sealed class AspTypePropertyAttribute : Attribute
	{
		public bool CreateConstructorReferences { get; }

		public AspTypePropertyAttribute(bool createConstructorReferences)
		{
			CreateConstructorReferences = createConstructorReferences;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
	internal sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute
	{
		[NotNull]
		public string Format { get; }

		public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format)
		{
			Format = format;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
	internal sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute
	{
		[NotNull]
		public string Format { get; }

		public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format)
		{
			Format = format;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
	internal sealed class AspMvcAreaViewComponentViewLocationFormatAttribute : Attribute
	{
		[NotNull]
		public string Format { get; }

		public AspMvcAreaViewComponentViewLocationFormatAttribute([NotNull] string format)
		{
			Format = format;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
	internal sealed class AspMvcAreaViewLocationFormatAttribute : Attribute
	{
		[NotNull]
		public string Format { get; }

		public AspMvcAreaViewLocationFormatAttribute([NotNull] string format)
		{
			Format = format;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
	internal sealed class AspMvcMasterLocationFormatAttribute : Attribute
	{
		[NotNull]
		public string Format { get; }

		public AspMvcMasterLocationFormatAttribute([NotNull] string format)
		{
			Format = format;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
	internal sealed class AspMvcPartialViewLocationFormatAttribute : Attribute
	{
		[NotNull]
		public string Format { get; }

		public AspMvcPartialViewLocationFormatAttribute([NotNull] string format)
		{
			Format = format;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
	internal sealed class AspMvcViewComponentViewLocationFormatAttribute : Attribute
	{
		[NotNull]
		public string Format { get; }

		public AspMvcViewComponentViewLocationFormatAttribute([NotNull] string format)
		{
			Format = format;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
	internal sealed class AspMvcViewLocationFormatAttribute : Attribute
	{
		[NotNull]
		public string Format { get; }

		public AspMvcViewLocationFormatAttribute([NotNull] string format)
		{
			Format = format;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcActionAttribute : Attribute
	{
		[CanBeNull]
		public string AnonymousProperty { get; }

		public AspMvcActionAttribute()
		{
		}

		public AspMvcActionAttribute([NotNull] string anonymousProperty)
		{
			AnonymousProperty = anonymousProperty;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcAreaAttribute : Attribute
	{
		[CanBeNull]
		public string AnonymousProperty { get; }

		public AspMvcAreaAttribute()
		{
		}

		public AspMvcAreaAttribute([NotNull] string anonymousProperty)
		{
			AnonymousProperty = anonymousProperty;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcControllerAttribute : Attribute
	{
		[CanBeNull]
		public string AnonymousProperty { get; }

		public AspMvcControllerAttribute()
		{
		}

		public AspMvcControllerAttribute([NotNull] string anonymousProperty)
		{
			AnonymousProperty = anonymousProperty;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcMasterAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class AspMvcModelTypeAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcPartialViewAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	internal sealed class AspMvcSuppressViewErrorAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcDisplayTemplateAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcEditorTemplateAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcTemplateAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcViewAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcViewComponentAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class AspMvcViewComponentViewAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)]
	internal sealed class AspMvcActionSelectorAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class RouteTemplateAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class)]
	internal sealed class RouteParameterConstraintAttribute : Attribute
	{
		[NotNull]
		public string ConstraintName { get; }

		[CanBeNull]
		public Type ProposedType { get; set; }

		public RouteParameterConstraintAttribute([NotNull] string constraintName)
		{
			ConstraintName = constraintName;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class UriStringAttribute : Attribute
	{
		[CanBeNull]
		public string HttpVerb { get; }

		public UriStringAttribute()
		{
		}

		public UriStringAttribute(string httpVerb)
		{
			HttpVerb = httpVerb;
		}
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class AspRouteConventionAttribute : Attribute
	{
		[CanBeNull]
		public string PredefinedPattern { get; }

		public AspRouteConventionAttribute()
		{
		}

		public AspRouteConventionAttribute(string predefinedPattern)
		{
			PredefinedPattern = predefinedPattern;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class AspDefaultRouteValuesAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class AspRouteValuesConstraintsAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)]
	internal sealed class AspRouteOrderAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)]
	internal sealed class AspRouteVerbsAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class)]
	internal sealed class AspAttributeRoutingAttribute : Attribute
	{
		public string HttpVerb { get; set; }
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class AspMinimalApiDeclarationAttribute : Attribute
	{
		public string HttpVerb { get; set; }
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class AspMinimalApiGroupAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class AspMinimalApiHandlerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
	internal sealed class AspMinimalApiImplicitEndpointDeclarationAttribute : Attribute
	{
		public string HttpVerb { get; set; }

		public string RouteTemplate { get; set; }

		public Type BodyType { get; set; }

		public string QueryParameters { get; set; }
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class HtmlElementAttributesAttribute : Attribute
	{
		[CanBeNull]
		public string Name { get; }

		public HtmlElementAttributesAttribute()
		{
		}

		public HtmlElementAttributesAttribute([NotNull] string name)
		{
			Name = name;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
	internal sealed class HtmlAttributeValueAttribute : Attribute
	{
		[NotNull]
		public string Name { get; }

		public HtmlAttributeValueAttribute([NotNull] string name)
		{
			Name = name;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)]
	internal sealed class RazorSectionAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class RazorImportNamespaceAttribute : Attribute
	{
		[NotNull]
		public string Name { get; }

		public RazorImportNamespaceAttribute([NotNull] string name)
		{
			Name = name;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class RazorInjectionAttribute : Attribute
	{
		[NotNull]
		public string Type { get; }

		[NotNull]
		public string FieldName { get; }

		public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName)
		{
			Type = type;
			FieldName = fieldName;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class RazorDirectiveAttribute : Attribute
	{
		[NotNull]
		public string Directive { get; }

		public RazorDirectiveAttribute([NotNull] string directive)
		{
			Directive = directive;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class RazorPageBaseTypeAttribute : Attribute
	{
		[NotNull]
		public string BaseType { get; }

		[CanBeNull]
		public string PageName { get; }

		public RazorPageBaseTypeAttribute([NotNull] string baseType)
		{
			BaseType = baseType;
		}

		public RazorPageBaseTypeAttribute([NotNull] string baseType, string pageName)
		{
			BaseType = baseType;
			PageName = pageName;
		}
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class RazorHelperCommonAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property)]
	internal sealed class RazorLayoutAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class RazorWriteLiteralMethodAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	internal sealed class RazorWriteMethodAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter)]
	internal sealed class RazorWriteMethodParameterAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class)]
	internal sealed class XamlItemsControlAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property)]
	internal sealed class XamlItemBindingOfItemsControlAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property)]
	internal sealed class XamlItemStyleOfItemsControlAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
	internal sealed class XamlOneWayBindingModeByDefaultAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
	internal sealed class XamlTwoWayBindingModeByDefaultAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Interface, AllowMultiple = true)]
	internal sealed class TestSubjectAttribute : Attribute
	{
		[NotNull]
		public Type Subject { get; }

		public TestSubjectAttribute([NotNull] Type subject)
		{
			Subject = subject;
		}
	}
	[AttributeUsage(AttributeTargets.GenericParameter)]
	internal sealed class MeansTestSubjectAttribute : Attribute
	{
	}
}
namespace TheArchive
{
	[HideInModSettings]
	[DisallowInGameToggle]
	[DoNotSaveToConfig]
	[EnableFeatureByDefault]
	internal class ArchiveBootstrap : Feature
	{
		[ArchivePatch(typeof(GameDataInit), "Initialize", null, ArchivePatch.PatchMethodType.Method, -1)]
		internal static class GameDataInit__Initialize__Patch
		{
			public static void Postfix()
			{
				try
				{
					InvokeGameDataInitialized();
				}
				catch (ReflectionTypeLoadException ex)
				{
					ArchiveLogger.Error("Exception thrown in ArchiveBootstrap");
					ArchiveLogger.Msg(ConsoleColor.Green, "Oh no, seems like someone's referencing game types from an older/newer game version that do not exist anymore! :c");
					ArchiveLogger.Exception(ex);
					ArchiveLogger.Warning($"{ex.Types.Length} Types loaded.");
					ArchiveLogger.Notice("Exceptions:");
					Exception[] loaderExceptions = ex.LoaderExceptions;
					foreach (Exception ex2 in loaderExceptions)
					{
						if (ex2 != null)
						{
							ArchiveLogger.Error(ex2.Message);
						}
					}
				}
				catch (Exception ex3)
				{
					ArchiveLogger.Error("Exception thrown in ArchiveBootstrap");
					ArchiveLogger.Exception(ex3);
					if (ex3.InnerException != null)
					{
						ArchiveLogger.Exception(ex3?.InnerException);
					}
				}
			}
		}

		[RundownConstraint(Utils.RundownFlags.RundownSix, Utils.RundownFlags.Latest)]
		[ArchivePatch("Setup", null, ArchivePatch.PatchMethodType.Method, -1)]
		internal static class LocalizationManager__Setup__Patch
		{
			public static Type Type()
			{
				return typeof(LocalizationManager);
			}

			public static void Postfix()
			{
				InvokeDataBlocksReady();
			}
		}

		[ArchivePatch(typeof(GameStateManager), "ChangeState", null, ArchivePatch.PatchMethodType.Method, -1)]
		internal static class GameStateManager__ChangeState__Patch
		{
			public static void Postfix(eGameStateName nextState)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Expected I4, but got Unknown
				ArchiveMod.InvokeGameStateChanged((int)nextState);
			}
		}

		[RundownConstraint(Utils.RundownFlags.RundownAltOne, Utils.RundownFlags.Latest)]
		[ArchivePatch("OnBtnPress", null, ArchivePatch.PatchMethodType.Method, -1)]
		internal static class CM_RundownSelection__OnBtnPress__Patch
		{
			public static Type Type()
			{
				return typeof(CM_RundownSelection);
			}

			public static void Postfix(CM_RundownSelection __instance)
			{
				ArchiveMod.CurrentlySelectedRundownKey = __instance.RundownKey;
			}
		}

		[RundownConstraint(Utils.RundownFlags.RundownAltOne, Utils.RundownFlags.Latest)]
		[ArchivePatch(typeof(CM_PageRundown_New), "Setup", null, ArchivePatch.PatchMethodType.Method, -1)]
		internal static class CM_PageRundown_New__Setup__Patch
		{
			public static void Postfix(CM_PageRundown_New __instance)
			{
				__instance.m_selectRundownButton.AddCMItemEvents(delegate
				{
					ArchiveMod.CurrentlySelectedRundownKey = string.Empty;
				});
			}
		}

		[ArchivePatch(typeof(InControlManager), "OnApplicationFocus", null, ArchivePatch.PatchMethodType.Method, -1)]
		internal static class EventSystem__OnApplicationFocus__Patch
		{
			public static void Postfix(bool focusState)
			{
				ArchiveMod.InvokeApplicationFocusChanged(focusState);
			}
		}

		public override string Name => "ArchiveBootstrap";

		public override GroupBase Group => GroupManager.Dev;

		public override string Description => "Hooks into a bunch of important game code in order for this mod to work.";

		public override bool RequiresRestart => true;

		private static void InvokeGameDataInitialized()
		{
			ArchiveMod.InvokeGameDataInitialized();
			if (ArchiveMod.CurrentRundown.IsIncludedIn(Utils.RundownFlags.RundownFour | Utils.RundownFlags.RundownFive))
			{
				InvokeDataBlocksReady();
			}
		}

		private static void InvokeDataBlocksReady()
		{
			if (SharedUtils.TryGetRundownDataBlock(out var block))
			{
				ArchiveMod.CurrentlySelectedRundownKey = $"Local_{((GameDataBlockBase<RundownDataBlock>)(object)block).persistentID}";
			}
			ArchiveMod.InvokeDataBlocksReady();
		}
	}
	public static class ArchiveMod
	{
		public const string GUID = "dev.AuriRex.gtfo.TheArchive";

		public const string MOD_NAME = "TheArchive";

		public const string ABBREVIATION = "Ar";

		public const string AUTHOR = "AuriRex";

		public const string VERSION_STRING = "0.0.838";

		public const string GITHUB_REPOSITORY_NAME = "GTFO_TheArchive";

		public const string GITHUB_OWNER_NAME = "AuriRex";

		public const string GITHUB_LINK = "https://github.com/AuriRex/GTFO_TheArchive";

		public static readonly bool GIT_IS_DIRTY = false;

		public const string GIT_COMMIT_SHORT_HASH = "a4eb55a";

		public const string GIT_COMMIT_DATE = "2026-05-07T19:14:52+08:00";

		public const string GIT_BASE_TAG = "";

		public const uint GTFO_STEAM_APPID = 493520u;

		public const string MTFO_GUID = "com.dak.MTFO";

		public static readonly string CORE_PATH = Assembly.GetAssembly(typeof(ArchiveMod)).Location;

		private static JsonSerializerSettings _jsonSerializerSettings = null;

		private static string _currentlySelectedRundownKey = string.Empty;

		private static IArchiveModule _mainModule;

		private static readonly HashSet<Type> _typesToInitOnDataBlocksReady = new HashSet<Type>();

		private static readonly HashSet<Type> _typesToInitOnGameDataInit = new HashSet<Type>();

		private static readonly HashSet<Assembly> _moduleAssemblies = new HashSet<Assembly>();

		private static readonly List<Type> _moduleTypes = new List<Type>();

		private const string ARCHIVE_SETTINGS_FILE = "TheArchive_Settings.json";

		private static Harmony _harmonyInstance;

		internal static ArchiveSettings Settings { get; private set; } = new ArchiveSettings();


		internal static JsonSerializerSettings JsonSerializerSettings
		{
			get
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Expected O, but got Unknown
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Expected O, but got Unknown
				if (_jsonSerializerSettings != null)
				{
					return _jsonSerializerSettings;
				}
				_jsonSerializerSettings = new JsonSerializerSettings
				{
					Formatting = (Formatting)1
				};
				_jsonSerializerSettings.Converters.Add((JsonConverter)new StringEnumConverter());
				_jsonSerializerSettings.ContractResolver = (IContractResolver)(object)ArchiveContractResolver.Instance;
				return _jsonSerializerSettings;
			}
		}

		public static bool IsPlayingModded { get; private set; } = false;


		public static Utils.RundownID CurrentRundown { get; private set; } = Utils.RundownID.RundownUnitialized;


		public static GameBuildInfo CurrentBuildInfo { get; private set; }

		public static int CurrentGameState { get; private set; }

		public static bool IsOnALTBuild { get; private set; }

		private static bool IsInitialized { get; set; }

		public static string CurrentlySelectedRundownKey
		{
			get
			{
				return _currentlySelectedRundownKey;
			}
			internal set
			{
				_currentlySelectedRundownKey = value;
				ArchiveLogger.Debug($"Setting {"CurrentlySelectedRundownKey"} to \"{_currentlySelectedRundownKey}\".");
				if (string.IsNullOrEmpty(_currentlySelectedRundownKey))
				{
					CurrentlySelectedRundownPersistentID = 0u;
					return;
				}
				try
				{
					CurrentlySelectedRundownPersistentID = uint.Parse(_currentlySelectedRundownKey.Replace("Local_", ""));
				}
				catch (Exception ex)
				{
					ArchiveLogger.Error($"Failed to parse selected rundown persistentId from {"CurrentlySelectedRundownKey"} \"{CurrentlySelectedRundownKey}\"!");
					ArchiveLogger.Exception(ex);
				}
			}
		}

		public static uint CurrentlySelectedRundownPersistentID { get; set; } = 0u;


		public static HashSet<IArchiveModule> Modules { get; } = new HashSet<IArchiveModule>();


		public static Type IL2CPP_BaseType { get; private set; } = null;


		public static event Action<Utils.RundownID> GameDataInitialized;

		public static event Action DataBlocksReady;

		public static event Action<int> GameStateChanged;

		public static event Action<bool> ApplicationFocusStateChanged;

		internal static event Action<IArchiveModule> OnNewModuleRegistered;

		internal static void OnApplicationStart(IArchiveLogger logger, Harmony harmonyInstance)
		{
			ArchiveLogger.Logger = logger;
			_harmonyInstance = harmonyInstance;
			if (GIT_IS_DIRTY)
			{
				ArchiveLogger.Warning("Git is dirty, this is a development build!");
			}
			if (LoaderWrapper.IsGameIL2CPP())
			{
				IL2CPP_BaseType = ImplementationManager.FindTypeInCurrentAppDomain("Il2CppSystem.Object", exactMatch: true);
				ArchiveLogger.Debug("IL2CPP_BaseType: " + IL2CPP_BaseType?.FullName);
				if (IL2CPP_BaseType == null)
				{
					ArchiveLogger.Error("IL2CPP base type \"Il2CppSystem.Object\" could not be resolved!");
				}
			}
			LoadConfig();
			if (LoaderWrapper.IsModInstalled("com.dak.MTFO"))
			{
				IsPlayingModded = true;
			}
			GTFOLogger.Logger = LoaderWrapper.CreateLoggerInstance("GTFO-Internals", ConsoleColor.DarkGray);
			CurrentRundown = BuildDB.GetCurrentRundownID(BuildDB.BuildNumber);
			ArchiveLogger.Msg(ConsoleColor.DarkMagenta, $"Current game revision determined to be {BuildDB.BuildNumber}! ({CurrentRundown})");
			GameBuildInfo currentBuildInfo = default(GameBuildInfo);
			currentBuildInfo.BuildNumber = BuildDB.BuildNumber;
			currentBuildInfo.Rundown = CurrentRundown;
			CurrentBuildInfo = currentBuildInfo;
			IsOnALTBuild = CurrentRundown.IsIncludedIn(Utils.RundownFlags.RundownAltOne.ToLatest());
			string path = Path.Combine(LoaderWrapper.GameDirectory, "steam_appid.txt");
			if (!File.Exists(path))
			{
				ArchiveLogger.Notice("Creating \"steam_appid.txt\" in GTFO folder ...");
				File.WriteAllText(path, $"{493520}");
			}
			AddInternalAttribution();
			FeatureManager.Internal_Init();
			try
			{
				_mainModule = CreateAndInitModule(typeof(MainArchiveModule));
			}
			catch (ReflectionTypeLoadException ex)
			{
				ArchiveLogger.Error("Failed loading main module!!");
				ArchiveLogger.Exception(ex);
				ArchiveLogger.Notice($"Loader Exceptions ({ex.LoaderExceptions.Length}):");
				Exception[] loaderExceptions = ex.LoaderExceptions;
				foreach (Exception ex2 in loaderExceptions)
				{
					if (ex2 != null)
					{
						ArchiveLogger.Warning(ex2.Message);
						ArchiveLogger.Debug(ex2.StackTrace);
					}
				}
				ArchiveLogger.Info("-------------");
			}
			InitializeArchiveModuleChainloader();
		}

		internal static void OnApplicationQuit()
		{
			InitSingletonBase<FeatureManager>.Instance.OnApplicationQuit();
			CustomSettingManager.OnApplicationQuit();
		}

		private static void LoadConfig()
		{
			LoadConfig(Path.Combine(LocalFiles.ModLocalLowPath, "TheArchive_Settings.json"));
		}

		private static void LoadConfig(string path)
		{
			try
			{
				ArchiveLogger.Info("Loading config file ... [" + path + "]");
				if (File.Exists(path))
				{
					Settings = JsonConvert.DeserializeObject<ArchiveSettings>(File.ReadAllText(path), JsonSerializerSettings);
				}
				SaveConfig(path);
			}
			catch (Exception ex)
			{
				ArchiveLogger.Exception(ex);
			}
		}

		private static void SaveConfig(string path)
		{
			ArchiveLogger.Debug("Saving config file ... [" + path + "]");
			File.WriteAllText(path, JsonConvert.SerializeObject((object)Settings, JsonSerializerSettings));
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static bool RegisterArchiveModule(Assembly asm)
		{
			return RegisterArchiveModule(asm.GetTypes().FirstOrDefault((Type t) => typeof(IArchiveModule).IsAssignableFrom(t)));
		}

		public static bool RegisterArchiveModule(Type moduleType)
		{
			if (moduleType == null)
			{
				throw new ArgumentException("Module can't be null!");
			}
			if (_moduleTypes.Contains(moduleType))
			{
				throw new ArgumentException("Module \"" + moduleType.Name + "\" is already registered!");
			}
			if (!typeof(IArchiveModule).IsAssignableFrom(moduleType))
			{
				throw new ArgumentException($"Type \"{moduleType.Name}\" does not implement {"IArchiveModule"}!");
			}
			IArchiveModule archiveModule = CreateAndInitModule(moduleType);
			Utils.SafeInvoke(ArchiveMod.OnNewModuleRegistered, archiveModule);
			if (CurrentRundown != Utils.RundownID.RundownUnitialized)
			{
				return true;
			}
			return false;
		}

		private static void InitializeArchiveModuleChainloader()
		{
			((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Finished += ArchiveModuleChainloader.Initialize;
		}

		internal static void InvokeGameDataInitialized()
		{
			if (IsInitialized)
			{
				ArchiveLogger.Info("Reload triggered, skipping init.");
				return;
			}
			IsInitialized = true;
			ArchiveLogger.Info("GameData has been initialized, invoking event.");
			foreach (Type item in _typesToInitOnGameDataInit)
			{
				try
				{
					InitInitializables(item, out var _);
				}
				catch (Exception ex)
				{
					ArchiveLogger.Error("Trying to Init \"" + item.FullName + "\" threw an exception:");
					ArchiveLogger.Exception(ex);
				}
			}
			InitSingletonBase<FeatureManager>.Instance.OnGameDataInitialized();
			Utils.SafeInvoke(ArchiveMod.GameDataInitialized, CurrentRundown);
		}

		internal static void InvokeDataBlocksReady()
		{
			try
			{
				DataBlockManager.Setup();
			}
			catch (Exception ex)
			{
				ArchiveLogger.Exception(ex);
			}
			ArchiveLogger.Info("DataBlocks should be ready to be interacted with, invoking event.");
			foreach (Type item in _typesToInitOnDataBlocksReady)
			{
				try
				{
					InitInitializables(item, out var _);
				}
				catch (Exception ex2)
				{
					ArchiveLogger.Error("Trying to Init \"" + item.FullName + "\" threw an exception:");
					ArchiveLogger.Exception(ex2);
				}
			}
			InitSingletonBase<FeatureManager>.Instance.OnDatablocksReady();
			CustomSettingManager.OnGameDataInited();
			Interop.OnDataBlocksReady();
			Utils.SafeInvoke(ArchiveMod.DataBlocksReady);
		}

		internal static void InvokeGameStateChanged(int eGameState_state)
		{
			CurrentGameState = eGameState_state;
			Utils.SafeInvoke(ArchiveMod.GameStateChanged, eGameState_state);
		}

		internal static void InvokeApplicationFocusChanged(bool focus)
		{
			Utils.SafeInvoke(ArchiveMod.ApplicationFocusStateChanged, focus);
		}

		private static void InitInitializables(Type type, out IInitializable initializable)
		{
			ArchiveLogger.Debug("Creating instance of: \"" + type.FullName + "\".");
			IInitializable initializable2 = (initializable = (IInitializable)Activator.CreateInstance(type));
			bool flag = true;
			Type type2 = typeof(InitSingletonBase<>).MakeGenericType(type);
			bool flag2 = type2.IsAssignableFrom(type);
			if (flag2)
			{
				type2.GetProperty("Instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).SetValue(null, initializable2);
			}
			if (typeof(IInitCondition).IsAssignableFrom(type))
			{
				IInitCondition initCondition = (IInitCondition)initializable2;
				try
				{
					flag = initCondition.InitCondition();
				}
				catch (Exception ex)
				{
					ArchiveLogger.Error("InitCondition method on Type \"" + type.FullName + "\" failed!");
					ArchiveLogger.Warning("This IInitializable won't be initialized.");
					ArchiveLogger.Exception(ex);
					flag = false;
				}
			}
			if (!flag)
			{
				return;
			}
			try
			{
				initializable2.Init();
				if (flag2)
				{
					type2.GetProperty("HasBeenInitialized", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).SetValue(null, true);
				}
			}
			catch (Exception ex2)
			{
				ArchiveLogger.Error("Init method on Type \"" + type.FullName + "\" failed!");
				ArchiveLogger.Exception(ex2);
			}
		}

		private static void InspectType(Type type, IArchiveModule module)
		{
			if (typeof(Feature).IsAssignableFrom(type) && type != typeof(Feature))
			{
				InitSingletonBase<FeatureManager>.Instance.InitFeature(type, module);
				return;
			}
			if (typeof(IInitImmediately).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
			{
				try
				{
					InitInitializables(type, out var _);
					return;
				}
				catch (Exception ex)
				{
					ArchiveLogger.Error("Trying to Init \"" + type.FullName + "\" (immediately) threw an exception:");
					ArchiveLogger.Exception(ex);
					return;
				}
			}
			if (typeof(IInitAfterGameDataInitialized).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
			{
				_typesToInitOnGameDataInit.Add(type);
			}
			else if (typeof(IInitAfterDataBlocksReady).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
			{
				_typesToInitOnDataBlocksReady.Add(type);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		internal static IArchiveModule CreateAndInitModule(Type moduleType)
		{
			if (moduleType == null)
			{
				throw new ArgumentException("Parameter moduleType can not be null!");
			}
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			_moduleTypes.Add(moduleType);
			ArchiveLogger.Info("Initializing module \"" + moduleType.FullName + "\" ...");
			IArchiveModule archiveModule = (IArchiveModule)Activator.CreateInstance(moduleType);
			DefinitionManager.LoadModuleDefinitions(archiveModule);
			IArchiveLogger archiveLogger2 = (archiveModule.Logger = LoaderWrapper.CreateLoggerInstance(moduleType.Assembly.GetName().Name, ConsoleColor.DarkMagenta));
			IArchiveLogger logger = archiveLogger2;
			ModuleLocalizationService moduleLocalizationService = (ModuleLocalizationService)(archiveModule.LocalizationService = new ModuleLocalizationService(archiveModule, moduleType, logger));
			try
			{
				moduleLocalizationService.Setup();
			}
			catch (Exception ex)
			{
				ArchiveLogger.Error("Error while trying to setup module localization for \"" + moduleType.FullName + "\"!");
				ArchiveLogger.Exception(ex);
			}
			try
			{
				archiveModule.Init();
			}
			catch (Exception ex2)
			{
				ArchiveLogger.Error("Error while trying to init \"" + moduleType.FullName + "\"!");
				ArchiveLogger.Exception(ex2);
			}
			Type[] types = moduleType.Assembly.GetTypes();
			for (int i = 0; i < types.Length; i++)
			{
				InspectType(types[i], archiveModule);
			}
			_moduleAssemblies.Add(moduleType.Assembly);
			Modules.Add(archiveModule);
			stopwatch.Stop();
			ArchiveLogger.Debug($"Creation of \"{moduleType.FullName}\" took {stopwatch.Elapsed:ss\\.fff} seconds.");
			return archiveModule;
		}

		internal static void OnUpdate()
		{
			InitSingletonBase<FeatureManager>.Instance.OnUpdate();
		}

		internal static void OnLateUpdate()
		{
			InitSingletonBase<FeatureManager>.Instance.OnLateUpdate();
		}

		private static void AddInternalAttribution()
		{
			try
			{
				string @string = Encoding.UTF8.GetString(Utils.LoadFromResource("TheArchive.Resources.LICENSE"));
				Attribution.Add(new Attribution.AttributionInfo("TheArchive License", @string ?? "")
				{
					Origin = "TheArchive.Core",
					Comment = "<color=orange><b>Huge thanks to everyone that has contributed!</b> - Check out the repo on GitHub!</color>"
				});
				string string2 = Encoding.UTF8.GetString(Utils.LoadFromResource("TheArchive.Resources.LICENSE_BepInEx"));
				Attribution.Add(new Attribution.AttributionInfo("BepInEx Info + License", ("This project contains parts of BepInEx code, denoted in source files.\n\nLICENSE (Truncated, see repository):\n\n" + string2).Substring(0, 619) + "\n\n[...]")
				{
					Origin = "TheArchive.Core"
				});
				string content = "<color=orange>Material Symbols</color> used in ThunderStore mod icons licensed under <color=orange>Apache License Version 2.0</color>\n\n> https://github.com/google/material-design-icons\n> https://www.apache.org/licenses/LICENSE-2.0.txt";
				Attribution.Add(new Attribution.AttributionInfo("Mod Icon(s) Info + License", content)
				{
					Origin = "TheArchive.Core"
				});
				string string3 = Encoding.UTF8.GetString(Utils.LoadFromResource("TheArchive.Resources.LICENSE_JBA"));
				Attribution.Add(new Attribution.AttributionInfo("JetBrains.Annotations License", string3 ?? "")
				{
					Origin = "TheArchive.Core"
				});
			}
			catch (Exception ex)
			{
				ArchiveLogger.Error("Error while trying to add internal AttributionInfos");
				ArchiveLogger.Exception(ex);
			}
		}
	}
	[ArchiveModule("dev.AuriRex.gtfo.TheArchive", "TheArchive", "0.0.838")]
	internal class MainArchiveModule : IArchiveModule
	{
		public ILocalizationService LocalizationService { get; set; }

		public IArchiveLogger Logger { get; set; }

		static MainArchiveModule()
		{
			ImplementationManagerExtensions.RegisterSelf(typeof(EnemyDataBlock));
			ImplementationManagerExtensions.RegisterSelf(typeof(GameDataBlockBase<>));
			ImplementationManagerExtensions.RegisterSelf(typeof(GameDataBlockWrapper<>));
			ImplementationManagerExtensions.RegisterSelf(typeof(eGameStateName));
			ImplementationManagerExtensions.RegisterSelf(typeof(LG_Area));
			typeof(List<>).RegisterForIdentifier("GenericList");
		}

		public void Init()
		{
			ArchiveLocalizationService.Setup(LocalizationService);
			CrashReportHandler.SetUserMetadata("Modded", "true");
			CrashReportHandler.enableCaptureExceptions = false;
		}
	}
}
namespace TheArchive.Utilities
{
	public static class AccessorExtensions
	{
		public static IValueAccessor<T, MT> OrAlternative<T, MT>(this IValueAccessor<T, MT> self, Func<IValueAccessor<T, MT>> func)
		{
			if (self != null && self.HasMember)
			{
				return self;
			}
			if (func == null)
			{
				throw new NullReferenceException("Parameter func may not be null!");
			}
			return func();
		}
	}
	public interface IValueAccessor<T, MT>
	{
		bool CanGet { get; }

		bool CanSet { get; }

		bool HasMember { get; }

		MT Get(T instance);

		void Set(T instance, MT value);
	}
	public interface IStaticValueAccessor<T, MT> : IValueAccessor<T, MT>
	{
		bool IsStatic { get; }

		MT GetStaticValue();

		void SetStaticValue(MT value);
	}
	public abstract class AccessorBase
	{
		protected static readonly Dictionary<string, AccessorBase> Accessors = new Dictionary<string, AccessorBase>();

		protected static object[] NoParams { get; } = Array.Empty<object>();


		protected static BindingFlags AnyBindingFlags => BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		public string Identifier { get; private set; }

		public bool IgnoreErrors { get; private set; }

		public abstract bool HasMemberBeenFound { get; }

		protected AccessorBase(string identifier, bool ignoreErrors)
		{
			Identifier = identifier;
			IgnoreErrors = ignoreErrors;
		}

		public static IValueAccessor<T, MT> GetValueAccessor<T, MT>(string memberName, bool throwOnError = false)
		{
			if (LoaderWrapper.IsGameIL2CPP() && LoaderWrapper.IsIL2CPPType(typeof(T)))
			{
				return PropertyAccessor<T, MT>.GetAccessor(memberName, !throwOnError);
			}
			MemberInfo memberInfo = typeof(T).GetMember(memberName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault();
			if (!(memberInfo is PropertyInfo))
			{
				if (memberInfo is FieldInfo)
				{
					return FieldAccessor<T, MT>.GetAccessor(memberName, !throwOnError);
				}
				if (throwOnError)
				{
					throw new ArgumentException($"Member with name \"{memberName}\" could not be found in type \"{typeof(T).Name}\" or isn't {"IValueAccessor"} compatible.", "memberName");
				}
				return null;
			}
			return PropertyAccessor<T, MT>.GetAccessor(memberName, !throwOnError);
		}

		public static IStaticValueAccessor<T, MT> GetStaticValueAccessor<T, MT>(string memberName, bool throwOnError = false)
		{
			IValueAccessor<T, MT> valueAccessor = GetValueAccessor<T, MT>(memberName, throwOnError);
			if (valueAccessor != null)
			{
				IStaticValueAccessor<T, MT> staticValueAccessor = valueAccessor as IStaticValueAccessor<T, MT>;
				if (throwOnError && !staticValueAccessor.IsStatic)
				{
					throw new ArgumentException("Member with name \"" + memberName + "\" is not static!", "memberName");
				}
				return staticValueAccessor;
			}
			return null;
		}
	}
	public class FieldAccessor<T, FT> : AccessorBase, IValueAccessor<T, FT>, IStaticValueAccessor<T, FT>
	{
		private readonly FieldInfo _field;

		public override bool HasMemberBeenFound => _field != null;

		public bool CanGet => true;

		public bool CanSet => true;

		public bool HasMember => HasMemberBeenFound;

		public bool IsStatic => _field?.IsStatic ?? false;

		public static FieldAccessor<T, FT> GetAccessor(string fieldName, bool ignoreErrors = false)
		{
			string text = "Field_" + typeof(T).FullName + "_" + fieldName;
			if (AccessorBase.Accessors.TryGetValue(text, out var value))
			{
				return (FieldAccessor<T, FT>)value;
			}
			value = new FieldAccessor<T, FT>(text, fieldName, ignoreErrors);
			AccessorBase.Accessors.Add(text, value);
			return (FieldAccessor<T, FT>)value;
		}

		private FieldAccessor(string identifier, string fieldName, bool ignoreErrors = false)
			: base(identifier, ignoreErrors)
		{
			_field = typeof(T).GetField(fieldName, AccessorBase.AnyBindingFlags);
		}

		public FT Get(T instance)
		{
			try
			{
				return (FT)_field.GetValue(instance);
			}
			catch (NullReferenceException)
			{
				if (!base.IgnoreErrors)
				{
					if (!HasMemberBeenFound)
					{
						ArchiveLogger.Warning($"NullReferenceException while getting {"FieldAccessor"} field \"{base.Identifier}\"! If this is intentional consider setting {"IgnoreErrors"} to true.");
						return default(FT);
					}
					ArchiveLogger.Error($"NullReferenceException while getting {"FieldAccessor"} field \"{base.Identifier}\"!");
					throw;
				}
			}
			catch (Exception ex2)
			{
				ArchiveLogger.Error($"Exception while getting {"FieldAccessor"} field \"{base.Identifier}\"!");
				ArchiveLogger.Exception(ex2);
			}
			return default(FT);
		}

		public void Set(T instance, FT value)
		{
			try
			{
				_field.SetValue(instance, value);
			}
			catch (NullReferenceException)
			{
				if (!base.IgnoreErrors)
				{
					if (HasMemberBeenFound)
					{
						ArchiveLogger.Error($"NullReferenceException while setting {"FieldAccessor"} field \"{base.Identifier}\"!");
						throw;
					}
					ArchiveLogger.Warning($"NullReferenceException while setting {"FieldAccessor"} field \"{base.Identifier}\"! If this is intentional consider setting {"IgnoreErrors"} to true.");
				}
			}
			catch (Exception ex2)
			{
				ArchiveLogger.Error($"Exception while setting {"FieldAccessor"} field \"{base.Identifier}\"!");
				ArchiveLogger.Exception(ex2);
			}
		}

		public FT GetStaticValue()
		{
			return Get(default(T));
		}

		public void SetStaticValue(FT value)
		{
			Set(default(T), value);
		}
	}
	public class PropertyAccessor<T, PT> : AccessorBase, IValueAccessor<T, PT>, IStaticValueAccessor<T, PT>
	{
		private readonly PropertyInfo _property;

		public override bool HasMemberBeenFound => _property != null;

		public bool CanGet => _property?.GetGetMethod(nonPublic: true) != null;

		public bool CanSet => _property?.GetSetMethod(nonPublic: true) != null;

		public bool HasMember => HasMemberBeenFound;

		public bool IsStatic => (_property?.GetGetMethod(nonPublic: true) ?? _property?.GetSetMethod(nonPublic: true))?.IsStatic ?? false;

		public static PropertyAccessor<T, PT> GetAccessor(string propertyName, bool ignoreErrors = false)
		{
			string text = "Property_" + typeof(T).FullName + "_" + propertyName;
			if (AccessorBase.Accessors.TryGetValue(text, out var value))
			{
				return (PropertyAccessor<T, PT>)value;
			}
			value = new PropertyAccessor<T, PT>(text, propertyName, ignoreErrors);
			AccessorBase.Accessors.Add(text, value);
			return (PropertyAccessor<T, PT>)value;
		}

		private PropertyAccessor(string identifier, string propertyName, bool ignoreErrors = false)
			: base(identifier, ignoreErrors)
		{
			_property = typeof(T).GetProperty(propertyName, AccessorBase.AnyBindingFlags);
		}

		public PT Get(T instance)
		{
			try
			{
				return (PT)_property.GetValue(instance);
			}
			catch (NullReferenceException)
			{
				if (!base.IgnoreErrors)
				{
					if (!HasMemberBeenFound)
					{
						ArchiveLogger.Warning($"NullReferenceException while getting {"PropertyAccessor"} property \"{base.Identifier}\"! If this is intentional consider setting {"IgnoreErrors"} to true.");
						return default(PT);
					}
					ArchiveLogger.Error($"NullReferenceException while getting {"PropertyAccessor"} property \"{base.Identifier}\"!");
					throw;
				}
			}
			catch (Exception ex2)
			{
				ArchiveLogger.Error($"Exception while getting {"PropertyAccessor"} property \"{base.Identifier}\"!");
				ArchiveLogger.Exception(ex2);
			}
			return default(PT);
		}

		public void Set(T instance, PT value)
		{
			try
			{
				_property.SetValue(instance, value);
			}
			catch (NullReferenceException)
			{
				if (!base.IgnoreErrors)
				{
					if (HasMemberBeenFound)
					{
						ArchiveLogger.Error($"NullReferenceException while setting {"PropertyAccessor"} property \"{base.Identifier}\"!");
						throw;
					}
					ArchiveLogger.Warning($"NullReferenceException while setting {"PropertyAccessor"} property \"{base.Identifier}\"! If this is intentional consider setting {"IgnoreErrors"} to true.");
				}
			}
			catch (Exception ex2)
			{
				ArchiveLogger.Error($"Exception while setting {"PropertyAccessor"} property \"{base.Identifier}\"!");
				ArchiveLogger.Exception(ex2);
			}
		}

		public PT GetStaticValue()
		{
			return Get(default(T));
		}

		public void SetStaticValue(PT value)
		{
			Set(default(T), value);
		}
	}
	public class MethodAccessor<T, RT> : AccessorBase
	{
		private readonly MethodInfo _method;

		public bool IsMethodStatic => _method.IsStatic;

		public override bool HasMemberBeenFound => _method != null;

		public static MethodAccessor<T, RT> GetAccessor(string methodName, Type[] parameterTypes = null, bool ignoreErrors = false)
		{
			string text = $"Method_{typeof(T).FullName}_{typeof(RT)}_{methodName}";
			if (parameterTypes != null)
			{
				text = text + "_" + string.Join("_", parameterTypes.Select((Type pt) => pt.Name));
			}
			if (AccessorBase.Accessors.TryGetValue(text, out var value))
			{
				return (MethodAccessor<T, RT>)value;
			}
			value = new MethodAccessor<T, RT>(text, methodName, parameterTypes, ignoreErrors);
			AccessorBase.Accessors.Add(text, value);
			return (MethodAccessor<T, RT>)value;
		}

		private MethodAccessor(string identifier, string methodName, Type[] parameterTypes, bool ignoreErrors = false)
			: base(identifier, ignoreErrors)
		{
			try
			{
				if (parameterTypes == null)
				{
					_method = typeof(T).GetMethod(methodName, AccessorBase.AnyBindingFlags);
				}
				else
				{
					_method = typeof(T).GetMethod(methodName, AccessorBase.AnyBindingFlags, null, parameterTypes, null);
				}
			}
			catch (Exception ex)
			{
				ArchiveLogger.Error($"Method \"{methodName}\" in Type {typeof(T).FullName} could not be resolved on {ex.Source}!");
				ArchiveLogger.Exception(ex);
			}
		}

		public RT Invoke(T instance, params object[] parameters)
		{
			try
			{
				object obj = _method.Invoke(instance, parameters ?? AccessorBase.NoParams);
				if (obj == null)
				{
					return default(RT);
				}
				return (RT)obj;
			}
			catch (NullReferenceException)
			{
				if (!base.IgnoreErrors)
				{
					if (!HasMemberBeenFound)
					{
						ArchiveLogger.Warning($"NullReferenceException while calling {"MethodAccessor"} method \"{base.Identifier}\"! If this is intentional consider setting {"IgnoreErrors"} to true.");
						return default(RT);
					}
					ArchiveLogger.Error($"NullReferenceException while calling {"MethodAccessor"} method \"{base.Identifier}\"!");
					throw;
				}
			}
			catch (Exception ex2)
			{
				ArchiveLogger.Error($"Exception while calling {"MethodAccessor"} method \"{base.Identifier}\"!");
				ArchiveLogger.Exception(ex2);
			}
			return default(RT);
		}

		public RT Invoke(T instance)
		{
			return Invoke(instance, null);
		}
	}
	public class MethodAccessor<T> : AccessorBase
	{
		private readonly MethodInfo _method;

		public bool IsMethodStatic => _method.IsStatic;

		public override bool HasMemberBeenFound => _method != null;

		public int ParameterCount { get; private set; }

		public static MethodAccessor<T> GetAccessor(string methodName, Type[] parameterTypes = null, bool ignoreErrors = false)
		{
			string text = "Method_" + typeof(T).FullName + "_void_" + methodName;
			if (parameterTypes != null && parameterTypes != Array.Empty<Type>())
			{
				text = text + "_" + string.Join("_", parameterTypes.Select((Type pt) => pt.Name));
			}
			if (AccessorBase.Accessors.TryGetValue(text, out var value))
			{
				return (MethodAccessor<T>)value;
			}
			value = new MethodAccessor<T>(text, methodName, parameterTypes, ignoreErrors);
			AccessorBase.Accessors.Add(text, value);
			return (MethodAccessor<T>)value;
		}

		private MethodAccessor(string identifier, string methodName, Type[] parameterTypes, bool ignoreErrors = false)
			: base(identifier, ignoreErrors)
		{
			try
			{
				if (parameterTypes == null)
				{
					_method = typeof(T).GetMethod(methodName, AccessorBase.AnyBindingFlags);
				}
				else
				{
					_method = typeof(T).GetMethod(methodName, AccessorBase.AnyBindingFlags, null, parameterTypes, null);
				}
				if (!ignoreErrors && _method == null)
				{
					throw new Exception("Method not found!");
				}
				if (_method != null)
				{
					ParameterCount = _method.GetParameters().Length;
				}
			}
			catch (Exception ex)
			{
				if (parameterTypes == null)
				{
					parameterTypes = Array.Empty<Type>();
				}
				ArchiveLogger.Error($"Method \"{methodName}\" in Type {typeof(T).FullName} could not be resolved on {ex.Source}!");
				ArchiveLogger.Exception(ex);
				ArchiveLogger.Debug($"Constructor debug data:\nidentifier:{identifier}\nmethodName:{methodName}\nparameterTypes:{string.Join(", ", parameterTypes.Select((Type p) => p.FullName))}");
				StackFrame frame = new StackTrace().GetFrame(2);
				ArchiveLogger.Debug($"FileName:{frame.GetFileName()} {frame.GetFileLineNumber()}\nMethod:{frame.GetMethod()?.DeclaringType?.FullName ?? "Unknown"}:{frame.GetMethod()?.Name ?? "Unknown"}");
				PrintDebug();
			}
		}

		private void PrintDebug()
		{
			if (!(_method == null))
			{
				ArchiveLogger.Debug($"Method debug data:\nName:{_method.Name}\nDeclaringType:{_method.DeclaringType?.FullName ?? "Unknown"}\nReturnType:{_method.ReturnType}\nParameter Count:{_method.GetParameters().Length}\nParameters:{string.Join(", ", from p in _method.GetParameters()
					select p.ParameterType.FullName)}");
			}
		}

		public void Invoke(T instance, params object[] parameters)
		{
			try
			{
				if (parameters != null && parameters.Length > ParameterCount)
				{
					parameters = parameters.Take(ParameterCount).ToArray();
				}
				_method.Invoke(instance, parameters ?? AccessorBase.NoParams);
			}
			catch (NullReferenceException)
			{
				if (!base.IgnoreErrors)
				{
					if (HasMemberBeenFound)
					{
						ArchiveLogger.Error($"NullReferenceException while calling {"MethodAccessor"} method \"{base.Identifier}\"!");
						throw;
					}
					ArchiveLogger.Warning($"NullReferenceException while calling {"MethodAccessor"} method \"{base.Identifier}\"! If this is intentional consider setting {"IgnoreErrors"} to true.");
				}
			}
			catch (Exception ex2)
			{
				ArchiveLogger.Error($"Exception while calling {"MethodAccessor"} method \"{base.Identifier}\"!");
				ArchiveLogger.Exception(ex2);
				PrintDebug();
			}
		}

		public void Invoke(T instance)
		{
			Invoke(instance, null);
		}
	}
	internal static class ArchiveLogger
	{
		internal static IArchiveLogger Logger;

		public static void Success(string msg)
		{
			Logger.Msg(ConsoleColor.Green, msg);
		}

		public static void Notice(string msg)
		{
			Logger.Msg(ConsoleColor.Cyan, msg);
		}

		public static void Msg(ConsoleColor col, string msg)
		{
			Logger.Msg(col, msg);
		}

		public static void Debug(string msg)
		{
			Logger.Msg(ConsoleColor.DarkGray, msg);
		}

		public static void Info(string msg)
		{
			Logger.Info(msg);
		}

		public static void Warning(string msg)
		{
			Logger.Msg(ConsoleColor.DarkYellow, msg);
		}

		public static void Error(string msg)
		{
			Logger.Error(msg);
		}

		public static void Msg(string v)
		{
			Info(v);
		}

		public static void Exception(Exception ex)
		{
			Error($"{ex}: {ex.Message}\n{ex.StackTrace}");
		}
	}
	public static class EnumExtensions
	{
		[CompilerGenerated]
		private sealed class <GetFlags>d__2<T> : IEnumerable<T>, IEnumerable, IEnumerator<T>, IEnumerator, IDisposable where T : struct, Enum
		{
			private int <>1__state;

			private T <>2__current;

			private int <>l__initialThreadId;

			private T value;

			public T <>3__value;

			private ulong <enumValue>5__2;

			private IEnumerator <>7__wrap2;

			T IEnumerator<T>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetFlags>d__2(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<enumValue>5__2 = Convert.ToUInt64(value);
						<>7__wrap2 = Enum.GetValues(typeof(T)).GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					}
					while (<>7__wrap2.MoveNext())
					{
						T val = (T)<>7__wrap2.Current;
						ulong num = Convert.ToUInt64(val);
						if (num != 0L && (<enumValue>5__2 & num) == num)
						{
							<>2__current = val;
							<>1__state = 1;
							return true;
						}
					}
					<>m__Finally1();
					<>7__wrap2 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>7__wrap2 is IDisposable disposable)
				{
					disposable.Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<T> IEnumerable<T>.GetEnumerator()
			{
				<GetFlags>d__2<T> <GetFlags>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<GetFlags>d__ = this;
				}
				else
				{
					<GetFlags>d__ = new <GetFlags>d__2<T>(0);
				}
				<GetFlags>d__.value = <>3__value;
				return <GetFlags>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<T>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <GetFlags>d__3 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private int <>l__initialThreadId;

			private object value;

			public object <>3__value;

			private ulong <enumValue>5__2;

			private IEnumerator <>7__wrap2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetFlags>d__3(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
					{
						<>1__state = -1;
						if (value == null)
						{
							throw new ArgumentNullException("value");
						}
						<enumValue>5__2 = Convert.ToUInt64(value);
						Type type = value.GetType();
						<>7__wrap2 = Enum.GetValues(type).GetEnumerator();
						<>1__state = -3;
						break;
					}
					case 1:
						<>1__state = -3;
						break;
					}
					while (<>7__wrap2.MoveNext())
					{
						object current = <>7__wrap2.Current;
						ulong num = Convert.ToUInt64(current);
						if (num != 0L && (<enumValue>5__2 & num) == num)
						{
							<>2__current = current;
							<>1__state = 1;
							return true;
						}
					}
					<>m__Finally1();
					<>7__wrap2 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>7__wrap2 is IDisposable disposable)
				{
					disposable.Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<object> IEnumerable<object>.GetEnumerator()
			{
				<GetFlags>d__3 <GetFlags>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<GetFlags>d__ = this;
				}
				else
				{
					<GetFlags>d__ = new <GetFlags>d__3(0);
				}
				<GetFlags>d__.value = <>3__value;
				return <GetFlags>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<object>)this).GetEnumerator();
			}
		}

		public static T ToFlags<T>(this List<T> enums) where T : struct, Enum
		{
			ulong num = 0uL;
			foreach (T @enum in enums)
			{
				num |= Convert.ToUInt64(@enum);
			}
			return (T)Enum.ToObject(typeof(T), num);
		}

		public static T GetHighestLevel<T>(this T value) where T : struct, Enum
		{
			ulong num = Convert.ToUInt64(value);
			if (num == 0L)
			{
				return value;
			}
			ulong value2 = 0uL;
			for (ulong num2 = num; num2 != 0L; num2 &= num2 - 1)
			{
				value2 = num2 & (~num2 + 1);
			}
			return (T)Enum.ToObject(typeof(T), value2);
		}

		[IteratorStateMachine(typeof(<GetFlags>d__2<>))]
		public static IEnumerable<T> GetFlags<T>(this T value) where T : struct, Enum
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetFlags>d__2<T>(-2)
			{
				<>3__value = value
			};
		}

		[IteratorStateMachine(typeof(<GetFlags>d__3))]
		public static IEnumerable<object> GetFlags(object value)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetFlags>d__3(-2)
			{
				<>3__value = value
			};
		}
	}
	internal static class GTFOLogger
	{
		private static readonly HashSet<string> _ignoreListExact = new HashSet<string> { "show crosshair", "Setting and getting Body Position/Rotation, IK Goals, Lookat and BoneLocalRotation should only be done in OnAnimatorIK or OnStateIK" };

		private static readonly HashSet<string> _ignoreListStartsWith = new HashSet<string> { "Wielding new item in slot", "Backend.", "BE.OnGameEvent" };

		internal static IArchiveLogger Logger { private get; set; }

		public static void Ignore(string str)
		{
			_ignoreListExact.Add(str);
		}

		public static void Log(string message)
		{
			if (!_ignoreListExact.Contains(message) && !_ignoreListStartsWith.Any((string s) => message.StartsWith(s)))
			{
				Logger.Info(message);
			}
		}

		public static void Warn(string message)
		{
			if (!_ignoreListExact.Contains(message) && !_ignoreListStartsWith.Any((string s) => message.StartsWith(s)))
			{
				Logger.Warning(message);
			}
		}

		public static void Error(string message)
		{
			if (!_ignoreListExact.Contains(message) && !_ignoreListStartsWith.Any((string s) => message.StartsWith(s)))
			{
				Logger.Error(message);
			}
		}
	}
	internal static class ImplementationManagerExtensions
	{
		public static void RegisterForIdentifier(this Type type, string identifier)
		{
			ImplementationManager.RegisterGameType(identifier, type);
		}

		public static void RegisterSelf<T>(this T type) where T : Type
		{
			if (type.IsGenericTypeDefinition)
			{
				type.RegisterForIdentifier(type.Name.Split('`')[0] + "<" + ((type.GenericTypeArguments.Length > 1) ? string.Join(",", new string[type.GenericTypeArguments.Length - 1]) : string.Empty) + ">");
			}
			else
			{
				type.RegisterForIdentifier(type.Name);
			}
		}
	}
	public static class LocalFiles
	{
		public const string GTFO_SETTINGS_JSON = "GTFO_Settings.json";

		public const string GTFO_FAVORITES_JSON = "GTFO_Favorites.json";

		public const string GTFO_BOT_FAVORITES_JSON = "GTFO_BotFavorites.json";

		private static string _modLocalLowPath;

		private static string _modDefaultGameLogsAndCachePath;

		private static string _modDefaultSaveDataPath;

		private static string _dataBlockDumpPath;

		private static string _savePath;

		private static string _gameLogsAndCacheSavePath;

		private static string _versionSpecificLogsAndCachePath;

		private static string _versionSpecificSavePath;

		private static string _otherConfigsPath;

		private static string _featureConfigsPath;

		private static string _filesPath;

		private static string _settingsPath;

		private static string _favoritesPath;

		private static string _botFavoritesPath;

		private static readonly FileStreamOptions Options = new FileStreamOptions
		{
			Access = FileAccess.Write,
			Mode = FileMode.Create,
			Options = FileOptions.WriteThrough
		};

		public static string ModLocalLowPath
		{
			get
			{
				if (_modLocalLowPath != null)
				{
					return _modLocalLowPath;
				}
				_modLocalLowPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "AppData", "LocalLow", "GTFO_TheArchive");
				if (!Directory.Exists(_modLocalLowPath))
				{
					Directory.CreateDirectory(_modLocalLowPath);
				}
				return _modLocalLowPath;
			}
		}

		public static string ModDefaultGameLogsAndCachePath
		{
			get
			{
				if (_modDefaultGameLogsAndCachePath != null)
				{
					return _modDefaultGameLogsAndCachePath;
				}
				_modDefaultGameLogsAndCachePath = Path.Combine(ModLocalLowPath, "GameLogsAndCache");
				if (!Directory.Exists(_modDefaultGameLogsAndCachePath))
				{
					Directory.CreateDirectory(_modDefaultGameLogsAndCachePath);
				}
				return _modDefaultGameLogsAndCachePath;
			}
		}

		public static string ModDefaultSaveDataPath
		{
			get
			{
				if (_modDefaultSaveDataPath != null)
				{
					return _modDefaultSaveDataPath;
				}
				_modDefaultSaveDataPath = Path.Combine(ModLocalLowPath, "SaveData");
				if (!Directory.Exists(_modLocalLowPath))
				{
					Directory.CreateDirectory(_modLocalLowPath);
				}
				return _modDefaultSaveDataPath;
			}
		}

		public static string DataBlockDumpPath
		{
			get
			{
				if (!string.IsNullOrEmpty(_dataBlockDumpPath))
				{
					return _dataBlockDumpPath;
				}
				_dataBlockDumpPath = Path.Combine(SaveDirectoryPath, "DataBlocks", $"Build_{BuildDB.BuildNumber}_{ArchiveMod.CurrentRundown}");
				if (!Directory.Exists(_dataBlockDumpPath))
				{
					Directory.CreateDirectory(_dataBlockDumpPath);
				}
				return _dataBlockDumpPath;
			}
		}

		public static string SaveDirectoryPath
		{
			get
			{
				if (!string.IsNullOrEmpty(_savePath))
				{
					return _savePath;
				}
				_savePath = (string.IsNullOrWhiteSpace(ArchiveMod.Settings.CustomFileSaveLocation) ? ModDefaultSaveDataPath : ArchiveMod.Settings.CustomFileSaveLocation);
				if (!Directory.Exists(_savePath))
				{
					Directory.CreateDirectory(_savePath);
				}
				return _savePath;
			}
		}

		public static string GameLogsAndCachePath
		{
			get
			{
				if (_gameLogsAndCacheSavePath != null)
				{
					return _gameLogsAndCacheSavePath;
				}
				_gameLogsAndCacheSavePath = (string.IsNullOrWhiteSpace(ArchiveMod.Settings.CustomLogsAndCacheLocation) ? ModDefaultGameLogsAndCachePath : ArchiveMod.Settings.CustomLogsAndCacheLocation);
				if (!Directory.Exists(_gameLogsAndCacheSavePath))
				{
					Directory.CreateDirectory(_gameLogsAndCacheSavePath);
				}
				return _gameLogsAndCacheSavePath;
			}
		}

		public static string VersionSpecificLogsAndCachePath
		{
			get
			{
				if (!string.IsNullOrEmpty(_versionSpecificLogsAndCachePath))
				{
					return _versionSpecificLogsAndCachePath;
				}
				_versionSpecificLogsAndCachePath = Path.Combine(GameLogsAndCachePath, $"{((int)ArchiveMod.CurrentRundown).ToString().PadLeft(2, '0')}_{ArchiveMod.CurrentRundown}_Data", "appdata");
				if (!Directory.Exists(_versionSpecificLogsAndCachePath))
				{
					Directory.CreateDirectory(_versionSpecificLogsAndCachePath);
				}
				return _versionSpecificLogsAndCachePath;
			}
		}

		public static string VersionSpecificSaveDirectoryPath
		{
			get
			{
				if (!string.IsNullOrEmpty(_versionSpecificSavePath))
				{
					return _versionSpecificSavePath;
				}
				_versionSpecificSavePath = GetVersionSpecificSaveDirectoryPath(ArchiveMod.CurrentRundown);
				if (Directory.Exists(_versionSpecificSavePath))
				{
					return _versionSpecificSavePath;
				}
				Directory.CreateDirectory(_versionSpecificSavePath);
				try
				{
					if (!CopyMostRecentSaveFiles(ArchiveMod.CurrentRundown - 1, ArchiveMod.CurrentRundown))
					{
						ArchiveLogger.Notice("Creating new game settings file(s)!");
					}
				}
				catch (Exception ex)
				{
					ArchiveLogger.Warning($"Caught an exception while trying to copy over older settings files: {ex}: {ex.Message}");
					ArchiveLogger.Debug(ex.StackTrace);
				}
				return _versionSpecificSavePath;
			}
		}

		public static string OtherConfigsDirectoryPath
		{
			get
			{
				if (!string.IsNullOrEmpty(_otherConfigsPath))
				{
					return _otherConfigsPath;
				}
				_otherConfigsPath = Path.Combine(SaveDirectoryPath, "OtherConfigs");
				if (!Directory.Exists(_otherConfigsPath))
				{
					Directory.CreateDirectory(_otherConfigsPath);
				}
				return _otherConfigsPath;
			}
		}

		public static string FeatureConfigsDirectoryPath
		{
			get
			{
				if (!string.IsNullOrEmpty(_featureConfigsPath))
				{
					return _featureConfigsPath;
				}
				_featureConfigsPath = Path.Combine(SaveDirectoryPath, "FeatureSettings");
				if (!Directory.Exists(_featureConfigsPath))
				{
					Directory.CreateDirectory(_featureConfigsPath);
				}
				return _featureConfigsPath;
			}
		}

		[Obsolete("Legacy path.")]
		public static string FilesDirectoryPath
		{
			get
			{
				if (!string.IsNullOrEmpty(_filesPath))
				{
					return _filesPath;
				}
				_filesPath = Path.Combine(VersionSpecificSaveDirectoryPath, "Files");
				if (!Directory.Exists(_filesPath))
				{
					Directory.CreateDirectory(_filesPath);
				}
				return _filesPath;
			}
		}

		public static string SettingsPath
		{
			get
			{
				if (!string.IsNullOrEmpty(_settingsPath))
				{
					return _settingsPath;
				}
				_settingsPath = Path.Combine(VersionSpecificSaveDirectoryPath, "GTFO_Settings.json");
				return _settingsPath;
			}
		}

		public static string FavoritesPath
		{
			get
			{
				if (string.IsNullOrEmpty(_favoritesPath))
				{
					_favoritesPath = Path.Combine(VersionSpecificSaveDirectoryPath, "GTFO_Favorites.json");
				}
				return _favoritesPath;
			}
		}

		public static string BotFavoritesPath
		{
			get
			{
				if (string.IsNullOrEmpty(_botFavoritesPath))
				{
					_botFavoritesPath = Path.Combine(VersionSpecificSaveDirectoryPath, "GTFO_BotFavorites.json");
				}
				return _botFavoritesPath;
			}
		}

		private static bool CopyFromBaseGameLocation(Utils.RundownID copyTo)
		{
			string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "AppData", "LocalLow", "10 Chambers Collective", "GTFO");
			string text = Path.Combine(path, "GTFO_Settings.txt");
			string text2 = Path.Combine(path, "GTFO_Favorites.txt");
			string text3 = Path.Combine(path, "GTFO_BotFavorites.txt");
			if (!File.Exists(text))
			{
				return false;
			}
			string settingsPath = GetSettingsPath(copyTo);
			ArchiveLogger.Debug($"Copying vanilla game settings file! (\"{text}\" -> \"{settingsPath}\")");
			File.Copy(text, settingsPath);
			string favoritesPath = GetFavoritesPath(copyTo);
			string botFavoritesPath = GetBotFavoritesPath(copyTo);
			if (File.Exists(text2))
			{
				ArchiveLogger.Debug($"Copying vanilla game favorites file! (\"{text2}\" -> \"{favoritesPath}\")");
				File.Copy(text2, favoritesPath);
			}
			if (File.Exists(text3))
			{
				ArchiveLogger.Debug($"Copying vanilla game bot favorites file! (\"{text3}\" -> \"{botFavoritesPath}\")");
				File.Copy(text3, botFavoritesPath);
			}
			return true;
		}

		private static bool CopyMostRecentSaveFiles(Utils.RundownID copyFrom, Utils.RundownID copyTo, int maxStep = 3)
		{
			if (copyFrom < Utils.RundownID.RundownOne)
			{
				return CopyFromBaseGameLocation(copyTo);
			}
			string settingsPath = GetSettingsPath(copyFrom);
			if (!File.Exists(settingsPath))
			{
				if (maxStep <= 1)
				{
					return CopyFromBaseGameLocation(copyTo);
				}
				return CopyMostRecentSaveFiles(copyFrom - 1, copyTo, maxStep - 1);
			}
			string settingsPath2 = GetSettingsPath(copyTo);
			ArchiveLogger.Debug($"Copying most recent settings file! (\"{settingsPath}\" -> \"{settingsPath2}\")");
			File.Copy(settingsPath, settingsPath2);
			if (ArchiveMod.IsPlayingModded)
			{
				return true;
			}
			string favoritesPath = GetFavoritesPath(copyTo);
			string favoritesPath2 = GetFavoritesPath(copyFrom);
			if (File.Exists(favoritesPath2))
			{
				ArchiveLogger.Debug($"Copying most recent favorites file! (\"{favoritesPath2}\" -> \"{favoritesPath}\")");
				File.Copy(favoritesPath2, favoritesPath);
			}
			string botFavoritesPath = GetBotFavoritesPath(copyTo);
			string botFavoritesPath2 = GetBotFavoritesPath(copyFrom);
			if (File.Exists(botFavoritesPath2))
			{
				ArchiveLogger.Debug($"Copying most recent bot favorites file! (\"{botFavoritesPath2}\" -> \"{botFavoritesPath}\")");
				File.Copy(botFavoritesPath2, botFavoritesPath);
			}
			return true;
		}

		public static string GetVersionSpecificSaveDirectoryPath(Utils.RundownID rundown)
		{
			string saveDirectoryPath = SaveDirectoryPath;
			DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(6, 2);
			int num = (int)rundown;
			defaultInterpolatedStringHandler.AppendFormatted(num.ToString().PadLeft(2, '0'));
			defaultInterpolatedStringHandler.AppendLiteral("_");
			defaultInterpolatedStringHandler.AppendFormatted(rundown);
			defaultInterpolatedStringHandler.AppendLiteral("_Data");
			return Path.Combine(saveDirectoryPath, defaultInterpolatedStringHandler.ToStringAndClear());
		}

		public static string GetSettingsPath(Utils.RundownID rundown)
		{
			return Path.Combine(GetVersionSpecificSaveDirectoryPath(rundown), "GTFO_Settings.json");
		}

		public static string GetFavoritesPath(Utils.RundownID rundown)
		{
			return Path.Combine(GetVersionSpecificSaveDirectoryPath(rundown), "GTFO_Favorites.json");
		}

		public static string GetBotFavoritesPath(Utils.RundownID rundown)
		{
			return Path.Combine(GetVersionSpecificSaveDirectoryPath(rundown), "GTFO_BotFavorites.json");
		}

		public static T LoadConfig<T>(out bool fileExists, bool saveIfNonExistent = true) where T : new()
		{
			string path = Path.Combine(OtherConfigsDirectoryPath, typeof(T).Name + ".json");
			try
			{
				if (!File.Exists(path))
				{
					T val = new T();
					if (saveIfNonExistent)
					{
						SaveConfig(val);
					}
					fileExists = false;
					return val;
				}
				fileExists = true;
				return JsonConvert.DeserializeObject<T>(File.ReadAllText(path), ArchiveMod.JsonSerializerSettings);
			}
			catch (Exception ex)
			{
				ArchiveLogger.Error("An error occured while loading config file " + typeof(T).Name + ".json");
				ArchiveLogger.Exception(ex);
			}
			fileExists = false;
			return new T();
		}

		public static T LoadConfig<T>(bool saveIfNonExistent = true) where T : new()
		{
			bool fileExists;
			return LoadConfig<T>(out fileExists, saveIfNonExistent);
		}

		public static void SaveConfig<T>(T config)
		{
			try
			{
				File.WriteAllText(Path.Combine(OtherConfigsDirectoryPath, typeof(T).Name + ".json"), JsonConvert.SerializeObject((object)config, ArchiveMod.JsonSerializerSettings));
			}
			catch (Exception ex)
			{
				ArchiveLogger.Error("An error occured while saving config file " + typeof(T).Name + ".json");
				ArchiveLogger.Exception(ex);
			}
		}

		private static object LoadFeatureConfig(string moduleIdentifier, string featureIdentifier, Type configType, out bool fileExists, bool saveIfNonExistent = true)
		{
			if (string.IsNullOrWhiteSpace(featureIdentifier))
			{
				throw new ArgumentException("Parameter featureIdentifier may not be null or whitespace.");
			}
			if (configType == null)
			{
				throw new ArgumentNullException("configType");
			}
			string text = Path.Combine(FeatureConfigsDirectoryPath, moduleIdentifier);
			if (!Directory.Exists(text))
			{
				if (moduleIdentifier == "TheArchive.Essentials")
				{
					string text2 = Path.Combine(FeatureConfigsDirectoryPath, "TheArchive.IL2CPP");
					if (Directory.Exists(text2))
					{
						ArchiveLogger.Msg(ConsoleColor.Green, $"Migrating old config path from \"{text2}\" to \"{text}\"");
						Directory.Move(text2, text);
					}
					else
					{
						Directory.CreateDirectory(text);
						ArchiveLogger.Msg(ConsoleColor.Green, $"Migrating old config files from \"{FeatureConfigsDirectoryPath}\" to \"{text}\"");
						foreach (string item in Directory.EnumerateFiles(FeatureConfigsDirectoryPath, "*.json", SearchOption.TopDirectoryOnly))
						{
							string text3 = Path.Combine(text, Path.GetFileName(item));
							ArchiveLogger.Debug($"Copying \"{item}\" -> \"{text3}\"");
							File.Copy(item, text3);
						}
					}
				}
				else
				{
					Directory.CreateDirectory(text);
				}
			}
			string path = Path.Combine(text, featureIdentifier + "_" + configType.Name + ".json");
			if (!File.Exists(path))
			{
				object obj = Activator.CreateInstance(configType);
				if (saveIfNonExistent)
				{
					SaveFeatureConfig(moduleIdentifier, featureIdentifier, configType, obj);
				}
				fileExists = false;
				return obj;
			}
			fileExists = true;
			try
			{
				return JsonConvert.DeserializeObject(File.ReadAllText(path), configType, ArchiveMod.JsonSerializerSettings);
			}
			catch
			{
				object obj2 = Activator.CreateInstance(configType);
				if (saveIfNonExistent)
				{
					SaveFeatureConfig(moduleIdentifier, featureIdentifier, configType, obj2);
				}
				fileExists = false;
				return obj2;
			}
		}

		internal static object LoadFeatureConfig(string moduleIdentifier, string featureIdentifier, Type configType, bool saveIfNonExistent = true)
		{
			bool fileExists;
			return LoadFeatureConfig(moduleIdentifier, featureIdentifier, configType, out fileExists, saveIfNonExistent);
		}

		internal static void SaveFeatureConfig(string moduleIdentifier, string featureIdentifier, Type configType, object configInstance)
		{
			if (string.IsNullOrWhiteSpace(featureIdentifier))
			{
				throw new ArgumentException("Parameter featureIdentifier may not be null or whitespace.");
			}
			if (configType == null)
			{
				throw new ArgumentNullException("configType");
			}
			if (configInstance == null)
			{
				throw new ArgumentNullException("configInstance");
			}
			string text = Path.Combine(FeatureConfigsDirectoryPath, moduleIdentifier);
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
			}
			string text2 = Path.Combine(text, featureIdentifier + "_" + configType.Name + ".json");
			ArchiveLogger.Debug("Saving Feature Setting to: " + text2);
			string value = JsonConvert.SerializeObject(configInstance, ArchiveMod.JsonSerializerSettings);
			try
			{
				using StreamWriter streamWriter = new StreamWriter(text2, Encoding.UTF8, Options);
				streamWriter.Write(value);
				streamWriter.Flush();
			}
			catch (Exception ex)
			{
				ArchiveLogger.Error("Threw an exception while trying to save file '" + text2 + "'.");
				ArchiveLogger.Exception(ex);
			}
		}
	}
	public static class MetadataHelper
	{
		internal static IEnumerable<CustomAttribute> GetCustomAttributes<T>(TypeDefinition td, bool inherit) where T : Attribute
		{
			List<CustomAttribute> list = new List<CustomAttribute>();
			Type type = typeof(T);
			TypeDefinition val = td;
			do
			{
				list.AddRange(((IEnumerable<CustomAttribute>)val.CustomAttributes).Where((CustomAttribute ca) => ((MemberReference)ca.AttributeType).FullName == type.FullName));
				TypeReference baseType = val.BaseType;
				val = ((baseType != null) ? baseType.Resolve() : null);
			}
			while (inherit && ((val != null) ? ((MemberReference)val).FullName : null) != typeof(object).FullName);
			return list;
		}

		public static ArchiveModule GetMetadata(Type moduleType)
		{
			object[] customAttributes = moduleType.GetCustomAttributes(typeof(ArchiveModule), inherit: false);
			if (customAttributes.Length == 0)
			{
				return null;
			}
			return (ArchiveModule)customAttributes[0];
		}

		public static ArchiveModule GetMetadata(object module)
		{
			return GetMetadata(module.GetType());
		}

		public static T[] GetAttributes<T>(Type moduleType) where T : Attribute
		{
			return (T[])moduleType.GetCustomAttributes(typeof(T), inherit: true);
		}

		public static T[] GetAttributes<T>(Assembly assembly) where T : Attribute
		{
			return (T[])assembly.GetCustomAttributes(typeof(T), inherit: true);
		}

		public static IEnumerable<T> GetAttributes<T>(object module) where T : Attribute
		{
			return GetAttributes<T>(module.GetType());
		}

		public static T[] GetAttributes<T>(MemberInfo member) where T : Attribute
		{
			return (T[])member.GetCustomAttributes(typeof(T), inherit: true);
		}

		public static IEnumerable<ArchiveDependency> GetDependencies(Type module)
		{
			return module.GetCustomAttributes(typeof(ArchiveDependency), inherit: true).Cast<ArchiveDependency>();
		}
	}
	public static class PresenceFormatter
	{
		[AttributeUsage(AttributeTargets.Property)]
		public class PresenceFormatProvider : Attribute
		{
			private PropertyInfo _propertyInfo;

			public string Identifier { get; private set; }

			public bool IsValid => _propertyInfo != null;

			public Type PropertyType => PropertyInfo.PropertyType;

			public string DebugIdentifier => $"{PropertyInfo.DeclaringType.Name}.{PropertyInfo.Name} (ASM:{PropertyInfo.DeclaringType.Assembly.GetName().Name})";

			internal PropertyInfo PropertyInfo => _propertyInfo ?? throw new Exception($"PropertyInfo not set on {"PresenceFormatProvider"} with ID \"{Identifier}\"!");

			public PresenceFormatProvider([CallerMemberName] string identifier = "")
			{
				Identifier = identifier;
			}

			internal void SetPropertyInfo(PropertyInfo propertyInfo)
			{
				if (propertyInfo == null)
				{
					throw new ArgumentException($"Provided {"PresenceFormatProvider"} {"PropertyInfo"} may not be null! (ID:{Identifier})");
				}
				MethodInfo? getMethod = propertyInfo.GetGetMethod();
				if ((object)getMethod == null || !getMethod.IsStatic)
				{
					throw new ArgumentException($"Provided {"PresenceFormatProvider"} {"PropertyInfo"} has to implement a static get method! (ID:{Identifier})");
				}
				_propertyInfo = propertyInfo;
			}

			public object GetValue()
			{
				return PropertyInfo.GetValue(null);
			}
		}

		[AttributeUsage(AttributeTargets.Property)]
		public class FallbackPresenceFormatProvider : PresenceFormatProvider
		{
			public bool NoNotImplementedWarning { get; }

			public FallbackPresenceFormatProvider(string identifier, bool noNotImplementedWarning = false)
				: base(identifier)
			{
				NoNotImplementedWarning = noNotImplementedWarning;
			}
		}

		private static readonly Dictionary<string, PresenceFormatProvider> _formatters = new Dictionary<string, PresenceFormatProvider>();

		private static readonly List<Type> _typesToCheckForProviders = new List<Type>();

		private static IArchiveLogger _logger;

		private static IArchiveLogger Logger => _logger ?? (_logger = LoaderWrapper.CreateArSubLoggerInstance("PresenceFormatter", ConsoleColor.DarkMagenta));

		public static void Setup()
		{
			Logger.Debug("Setting up providers ...");
			foreach (Type typesToCheckForProvider in _typesToCheckForProviders)
			{
				CheckTypeForProviders(typesToCheckForProvider);
			}
			foreach (KeyValuePair<string, PresenceFormatProvider> item in _formatters.Where((KeyValuePair<string, PresenceFormatProvider> kvp) => kvp.Value is FallbackPresenceFormatProvider fallbackPresenceFormatProvider && !fallbackPresenceFormatProvider.NoNotImplementedWarning))
			{
				Logger.Warning("Identifier \"" + item.Key + "\" has not been implemented! Using Fallback default values!");
			}
		}

		private static void CheckTypeForProviders(Type type)
		{
			PropertyInfo[] properties = type.GetProperties();
			foreach (PropertyInfo propertyInfo in properties)
			{
				try
				{
					PresenceFormatProvider customAttribute = propertyInfo.GetCustomAttribute<PresenceFormatProvider>();
					if (customAttribute != null)
					{
						customAttribute.SetPropertyInfo(propertyInfo);
						RegisterFormatter(customAttribute);
					}
				}
				catch (Exception ex)
				{
					Logger.Exception(ex);
				}
			}
		}

		public static void RegisterAllPresenceFormatProviders(this Type type, bool throwOnDuplicate = true)
		{
			if (type == null)
			{
				throw new ArgumentException("Type must not be null!");
			}
			if (_typesToCheckForProviders.Contains(type))
			{
				if (throwOnDuplicate)
				{
					throw new ArgumentException("Duplicate Type registered: \"" + type.FullName + "\"");
				}
				return;
			}
			_typesToCheckForProviders.Add(type);
			if (_formatters.Count > 0)
			{
				Logger.Debug($"Late call of {"RegisterAllPresenceFormatProviders"} for {type.FullName} - running checks now.");
				CheckTypeForProviders(type);
			}
		}

		private static void RegisterFormatter(PresenceFormatProvider pfp)
		{
			if (!pfp.IsValid)
			{
				return;
			}
			bool flag = false;
			if (_formatters.TryGetValue(pfp.Identifier, out var value))
			{
				if (pfp is FallbackPresenceFormatProvider)
				{
					return;
				}
				if (!(value is FallbackPresenceFormatProvider))
				{
					throw new ArgumentException($"Duplicate formatter identifier: \"{pfp.Identifier}\" (\"{pfp.DebugIdentifier}\")");
				}
				_formatters.Remove(pfp.Identifier);
				flag = true;
			}
			_formatters.Add(pfp.Identifier, pfp);
			Logger.Debug($"{(flag ? " (Fallback Overridden)" : ((pfp is FallbackPresenceFormatProvider) ? " (Fallback)" : string.Empty))} Registered: \"{pfp.Identifier}\" => {pfp.DebugIdentifier}");
		}

		public static object Get(string identifier)
		{
			_formatters.TryGetValue(identifier, out var value);
			return value?.GetValue();
		}

		public static T Get<T>(string identifier)
		{
			_formatters.TryGetValue(identifier, out var value);
			if (value == null)
			{
				return default(T);
			}
			if (!value.PropertyType.IsAssignableFrom(typeof(T)) && typeof(T) != typeof(string))
			{
				throw new ArgumentException($"The property at identifier \"{identifier}\" is not declared as Type \"{typeof(T).Name}\"!");
			}
			return (T)value.GetValue();
		}

		public static string Format(this string formatString, params (string search, string replace)[] extraFormatters)
		{
			return FormatPresenceString(formatString, extraFormatters);
		}

		public static string FormatPresenceString(string formatString)
		{
			return FormatPresenceString(formatString, null);
		}

		public static string FormatPresenceString(string formatString, params (string search, string replace)[] extraFormatters)
		{
			return FormatPresenceString(formatString, stripAllTMPTags: true, extraFormatters);
		}

		public static string FormatPresenceString(string formatString, bool stripAllTMPTags = true, params (string search, string replace)[] extraFormatters)
		{
			string text = formatString;
			foreach (KeyValuePair<string, PresenceFormatProvider> formatter in _formatters)
			{
				if (text.Contains("%" + formatter.Key + "%"))
				{
					text = text.ReplaceCaseInsensitive("%" + formatter.Key + "%", formatter.Value.GetValue()?.ToString() ?? "null");
				}
			}
			if (extraFormatters != null)
			{
				for (int i = 0; i < extraFormatters.Length; i++)
				{
					(string, string) tuple = extraFormatters[i];
					if (text.Contains("%" + tuple.Item1 + "%"))
					{
						text = text.ReplaceCaseInsensitive("%" + tuple.Item1 + "%", tuple.Item2);
					}
				}
			}
			if (stripAllTMPTags)
			{
				return Utils.StripTMPTagsRegex(text.Trim());
			}
			return text.Trim();
		}
	}
	public static class RundownFlagsExtensions
	{
		private static IEnumerable<Utils.RundownFlags> _allFlagsOrdered;

		public static IEnumerable<Utils.RundownFlags> AllFlagsOrdered
		{
			get
			{
				if (_allFlagsOrdered == null)
				{
					_allFlagsOrdered = (from Utils.RundownFlags x in Enum.GetValues(typeof(Utils.RundownFlags))
						orderby x
						select x).Skip(2);
				}
				return _allFlagsOrdered;
			}
		}

		public static bool IsIncludedIn(this Utils.RundownID rundownID, Utils.RundownFlags flags)
		{
			return Utils.FlagsContain(flags, r

BepInEx/plugins/TheArchive.Essentials/plugins/TheArchive.Essentials.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using AK;
using Agents;
using AirParticleSystem;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using BoosterImplants;
using CellMenu;
using ChainedPuzzles;
using Clonesoft.Json;
using Clonesoft.Json.Linq;
using Enemies;
using FX_EffectSystem;
using GameData;
using Gear;
using HarmonyLib;
using IRF;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.Runtime;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using LevelGeneration;
using Localization;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using StateMachines;
using Steamworks;
using TMPro;
using TheArchive.Core;
using TheArchive.Core.Attributes;
using TheArchive.Core.Attributes.Feature;
using TheArchive.Core.Attributes.Feature.Members;
using TheArchive.Core.Attributes.Feature.Patches;
using TheArchive.Core.Attributes.Feature.Settings;
using TheArchive.Core.FeaturesAPI;
using TheArchive.Core.FeaturesAPI.Components;
using TheArchive.Core.FeaturesAPI.Groups;
using TheArchive.Core.FeaturesAPI.Settings;
using TheArchive.Core.Localization;
using TheArchive.Core.Managers;
using TheArchive.Core.Models;
using TheArchive.Features.Accessibility;
using TheArchive.Features.Dev;
using TheArchive.Interfaces;
using TheArchive.Loader;
using TheArchive.Utilities;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("2025.2.0")]
[assembly: AssemblyInformationalVersion("2025.2.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TheArchive.Essentials")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyProduct("TheArchive.Essentials")]
[assembly: AssemblyTitle("TheArchive.Essentials")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2025.2.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
internal class ThisAssembly
{
	public class Git
	{
		public class BaseVersion
		{
			public const string Major = "0";

			public const string Minor = "0";

			public const string Patch = "0";
		}

		public class SemVer
		{
			public const string Major = "0";

			public const string Minor = "0";

			public const string Patch = "838";

			public const string Label = "";

			public const string DashLabel = "";

			public const string Source = "Default";
		}

		public const bool IsDirty = false;

		public const string IsDirtyString = "false";

		public const string RepositoryUrl = "https://github.com/Tuesday1028/GTFO_TheArchive";

		public const string Branch = "doing-things";

		public const string Commit = "a4eb55a";

		public const string Sha = "a4eb55a7e97569a44df6831acc6074b0f084b6eb";

		public const string CommitDate = "2026-05-07T19:14:52+08:00";

		public const string Commits = "838";

		public const string Tag = "";

		public const string BaseTag = "";
	}
}
internal class ManifestInfo
{
	internal const string TSName = "TheArchive_Essentials";

	internal const string TSDescription = "That one massive GTFO Quality of Life mod.";

	internal const string TSVersion = "2025.2.0";

	internal const string TSAuthor = "AuriRex";

	internal const string TSWebsite = "https://github.com/AuriRex/GTFO_TheArchive";
}
namespace TheArchive
{
	[ArchiveModule("dev.AuriRex.gtfo.TheArchive.Essentials", "TheArchive_Essentials", "2025.2.0")]
	public class ArchiveEssentialsModule : IArchiveModule
	{
		public const string GUID = "dev.AuriRex.gtfo.TheArchive.Essentials";

		public const string MOD_NAME = "TheArchive_Essentials";

		public const string VERSION = "2025.2.0";

		public ILocalizationService LocalizationService { get; set; }

		public IArchiveLogger Logger { get; set; }

		public void Init()
		{
		}
	}
}
namespace TheArchive.Features.Special
{
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class AdBlock : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class CM_PageRundown_New_ABC_Patch
		{
			public static void Postfix(CM_PageRundown_New __instance)
			{
				ToggleDOWImage(__instance);
			}
		}

		public override string Name => "AdBlock";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Special;

		public override string Description => "Removes the Den of Wolves button from the rundown screen.";

		public static bool IsEnabled { get; set; }

		public override void OnEnable()
		{
			if (Feature.DataBlocksReady)
			{
				ToggleDOWImage(MainMenuGuiLayer.Current.PageRundownNew);
			}
		}

		public override void OnDisable()
		{
			if (!Feature.IsApplicationQuitting)
			{
				ToggleDOWImage(MainMenuGuiLayer.Current.PageRundownNew, setActive: true);
			}
		}

		private static void ToggleDOWImage(CM_PageRundown_New __instance, bool setActive = false)
		{
			RectTransform movingContentHolder = ((CM_PageBase)__instance).m_movingContentHolder;
			object obj;
			if (movingContentHolder == null)
			{
				obj = null;
			}
			else
			{
				Transform childWithExactName = SharedUtils.GetChildWithExactName((Transform)(object)movingContentHolder, "PasteAndJoinOnLobbyID");
				if (childWithExactName == null)
				{
					obj = null;
				}
				else
				{
					Transform childWithExactName2 = SharedUtils.GetChildWithExactName(childWithExactName, "ButtonGIF");
					obj = ((childWithExactName2 != null) ? ((Component)childWithExactName2).gameObject : null);
				}
			}
			GameObject val = (GameObject)obj;
			if (!((Object)(object)val == (Object)null))
			{
				OnEnabledListener component = val.GetComponent<OnEnabledListener>();
				if ((Object)(object)component != (Object)null && setActive)
				{
					Object.Destroy((Object)(object)component);
				}
				else if ((Object)(object)component == (Object)null)
				{
					component = val.AddComponent<OnEnabledListener>();
					OnEnabledListener obj2 = component;
					obj2.OnEnabledSelf = (Action<GameObject>)Delegate.Combine(obj2.OnEnabledSelf, new Action<GameObject>(OnButtonEnabled));
				}
				val.SetActive(setActive);
			}
		}

		private static void OnButtonEnabled(GameObject go)
		{
			if (IsEnabled)
			{
				go.SetActive(false);
			}
		}
	}
	[EnableFeatureByDefault]
	internal class AltTabCounter : Feature
	{
		public class AltTabCounterSettings
		{
			public class AltTabCounterSettingsForReal
			{
				[FSHeader("ALT + TABs <3", true)]
				[FSReadOnly(true)]
				[FSDisplayName("Total Count")]
				[FSDescription("All time total of ALT + TABs")]
				public int TotalCount { get; set; }

				[FSReadOnly(true)]
				[FSDisplayName("This Session Count")]
				[FSDescription("ALT + TABs accumulated this session")]
				public int CurrentSessionCount { get; set; }

				[FSReadOnly(true)]
				[FSDisplayName("This Level Count")]
				[FSDescription("ALT + TABs accumulated this level")]
				public int CurrentWhileInLevelCount { get; set; }
			}

			[FSUseDynamicSubmenu]
			[FSDisplayName("ALT + TAB Counts")]
			public AltTabCounterSettingsForReal AltTabCounts { get; set; } = new AltTabCounterSettingsForReal();

		}

		public override string Name => "Alt Tab Counter";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Special;

		public override string Description => "Counts the amount of times that the game went out of focus. (ALT + TAB)";

		[FeatureConfig]
		public static AltTabCounterSettings Settings { get; set; }

		public static bool InLevel { get; private set; }

		public override void Init()
		{
			Settings.AltTabCounts.CurrentSessionCount = 0;
		}

		public override void OnApplicationFocusChanged(bool focus)
		{
			if (!focus)
			{
				Settings.AltTabCounts.TotalCount++;
				Settings.AltTabCounts.CurrentSessionCount++;
				if (InLevel)
				{
					Settings.AltTabCounts.CurrentWhileInLevelCount++;
				}
				Feature.MarkSettingsAsDirty<AltTabCounterSettings>(Settings);
			}
		}

		public void OnGameStateChanged(eGameStateName state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			InLevel = (int)state == 10;
			if (InLevel)
			{
				Settings.AltTabCounts.CurrentWhileInLevelCount = 0;
				Feature.MarkSettingsAsDirty<AltTabCounterSettings>(Settings);
			}
		}
	}
	public class HideFirstPersonItem : Feature
	{
		public class HideFirstPersonItemSettings
		{
			[FSDisplayName("Model Toggle Key")]
			[FSDescription("Key used to toggle the model.")]
			public KeyCode Key { get; set; } = (KeyCode)283;

		}

		public override string Name => "Weapon Model Toggle";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Special;

		public override string Description => "Forces the held item to be hidden.\nIntended for taking pictures.\n<color=orange>(Warning! This makes you unable to use or switch items until unhidden!)</color>";

		[FeatureConfig]
		public static HideFirstPersonItemSettings Settings { get; set; }

		public override void Update()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if ((int)FocusStateManager.CurrentState == 4 && Input.GetKeyDown(Settings.Key))
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				if ((Object)(object)localPlayerAgent != (Object)null && (Object)(object)localPlayerAgent.FPItemHolder != (Object)null)
				{
					localPlayerAgent.FPItemHolder.ForceItemHidden = !localPlayerAgent.FPItemHolder.ForceItemHidden;
				}
			}
		}
	}
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class MuteSpeak : Feature
	{
		private static PlayerAgent _localPlayerAgent;

		public override string Name => "Mute Speak";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Special;

		public override string Description => "Binds a few voice lines to keyboard keys.\n\nArrow keys\n[P, L, K, J, H] toggleable by hitting F8; off by default\nHold [Right Control] for alternate lines";

		public static IArchiveLogger FeatureLogger { get; set; }

		public static bool EnableOtherVoiceBinds { get; set; }

		public static void IfKeySay(KeyCode key, uint soundId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(key))
			{
				PlayerVoiceManager.WantToSay(_localPlayerAgent.CharacterID, soundId);
			}
		}

		public static void IfKeySay(KeyCode key, uint soundId, int characterID)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(key))
			{
				PlayerVoiceManager.WantToSay(characterID, soundId);
			}
		}

		public override void Update()
		{
			if (Input.GetKeyDown((KeyCode)289))
			{
				EnableOtherVoiceBinds = !EnableOtherVoiceBinds;
				FeatureLogger.Notice($"Voice binds enabled: {EnableOtherVoiceBinds}");
			}
			if (PlayerChatManager.InChatMode || SharedUtils.LocalPlayerIsInTerminal || !PlayerManager.TryGetLocalPlayerAgent(ref _localPlayerAgent) || (Object)(object)_localPlayerAgent == (Object)null)
			{
				return;
			}
			if (Input.GetKey((KeyCode)305))
			{
				IfKeySay((KeyCode)303, SoundEventCache.Resolve("PLAY_BIGSPACEENTER01", false));
				IfKeySay((KeyCode)273, SoundEventCache.Resolve("PLAY_CL_NORTH", false));
				IfKeySay((KeyCode)275, SoundEventCache.Resolve("PLAY_CL_EAST", false));
				IfKeySay((KeyCode)274, SoundEventCache.Resolve("PLAY_CL_SOUTH", false));
				IfKeySay((KeyCode)276, SoundEventCache.Resolve("PLAY_CL_WEST", false));
				if (EnableOtherVoiceBinds)
				{
					IfKeySay((KeyCode)112, SoundEventCache.Resolve("PLAY_CL_WELLDONE", false));
					IfKeySay((KeyCode)108, SoundEventCache.Resolve("PLAY_CL_SHH", false));
					IfKeySay((KeyCode)107, SoundEventCache.Resolve("PLAY_CL_WILLDO", false));
					IfKeySay((KeyCode)106, SoundEventCache.Resolve("PLAY_CL_YOUTAKE", false));
					IfKeySay((KeyCode)104, SoundEventCache.Resolve("PLAY_FALLDAMAGEGRUNT02_5A", false), 2);
				}
			}
			else
			{
				IfKeySay((KeyCode)276, SoundEventCache.Resolve("PLAY_CL_LEFT", false));
				IfKeySay((KeyCode)275, SoundEventCache.Resolve("PLAY_CL_RIGHT", false));
				IfKeySay((KeyCode)273, SoundEventCache.Resolve("PLAY_CL_YES", false));
				IfKeySay((KeyCode)274, SoundEventCache.Resolve("PLAY_CL_NO", false));
				if (EnableOtherVoiceBinds)
				{
					IfKeySay((KeyCode)112, SoundEventCache.Resolve("PLAY_CL_SORRY", false));
					IfKeySay((KeyCode)108, SoundEventCache.Resolve("PLAY_CL_HURRY", false));
					IfKeySay((KeyCode)106, SoundEventCache.Resolve("PLAY_CL_THREETWOONEGO", false));
					IfKeySay((KeyCode)107, SoundEventCache.Resolve("PLAY_CL_SYNCHRONIZE", false));
					IfKeySay((KeyCode)104, SoundEventCache.Resolve("PLAY_FALLDAMAGEGRUNT02_5A", false));
				}
			}
		}
	}
	[EnableFeatureByDefault]
	public class ProcessPriority : Feature
	{
		public class ProcessPrioritySettings
		{
			[Localized]
			public enum PriorityClass
			{
				High,
				AboveNormal,
				Normal,
				BelowNormal
			}

			[FSDisplayName("Priority")]
			public PriorityClass Priority { get; set; } = PriorityClass.AboveNormal;

		}

		private static readonly Dictionary<ProcessPrioritySettings.PriorityClass, ProcessPriorityClass> _prioMap = new Dictionary<ProcessPrioritySettings.PriorityClass, ProcessPriorityClass>
		{
			{
				ProcessPrioritySettings.PriorityClass.High,
				ProcessPriorityClass.High
			},
			{
				ProcessPrioritySettings.PriorityClass.AboveNormal,
				ProcessPriorityClass.AboveNormal
			},
			{
				ProcessPrioritySettings.PriorityClass.Normal,
				ProcessPriorityClass.Normal
			},
			{
				ProcessPrioritySettings.PriorityClass.BelowNormal,
				ProcessPriorityClass.BelowNormal
			}
		};

		public override string Name => "Process Priority";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Special;

		public override string Description => $"Set the games process priority.\n\nThis does the same thing as opening up <color=orange>Taskmanager</color>, going into the 'Details' tab and right clicking on GTFO.exe > [Set Priority]\n\nWarning! Your system might lag / stutter while the game is loading if set to <color=orange>{1}</color> or higher!";

		[FeatureConfig]
		public static ProcessPrioritySettings Settings { get; set; }

		public override void OnEnable()
		{
			SetPriority(Settings.Priority);
		}

		public override void OnDisable()
		{
			SetPriority(ProcessPrioritySettings.PriorityClass.Normal);
		}

		public override void OnFeatureSettingChanged(FeatureSetting setting)
		{
			SetPriority(Settings.Priority);
		}

		public void SetPriority(ProcessPrioritySettings.PriorityClass settingsPriority)
		{
			if (_prioMap.TryGetValue(settingsPriority, out var value))
			{
				using (Process process = Process.GetCurrentProcess())
				{
					process.PriorityClass = value;
				}
				((Feature)this).FeatureLogger.Success($"Set ProcessPriority to {settingsPriority}!");
			}
		}
	}
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class RemoveChatRestrictions : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class PlayerChatManager_SetupPatch
		{
			public static void Postfix(ref PlayerChatManager __instance)
			{
				try
				{
					SetValues(__instance);
				}
				catch (Exception ex)
				{
					FeatureLogger.Exception(ex);
				}
			}
		}

		private static PropertyAccessor<PlayerChatManager, Il2CppStructArray<int>> A_PlayerChatManager_m_forbiddenChars;

		private readonly int[] _forbiddenChars = new int[3] { 60, 61, 62 };

		public override string Name => "Remove Chat Restrictions";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Special;

		public override string Description => "Allows the usage of '>' and '<' characters in chat.\n\n(Also enables TextMeshPro RichText tags to be used in chat, don't do stupid things!)";

		public static IArchiveLogger FeatureLogger { get; set; }

		public override void OnEnable()
		{
			SetValues(PlayerChatManager.Current);
		}

		public override void OnDisable()
		{
			SetValues(PlayerChatManager.Current, _forbiddenChars);
		}

		public override void Init()
		{
			A_PlayerChatManager_m_forbiddenChars = PropertyAccessor<PlayerChatManager, Il2CppStructArray<int>>.GetAccessor("m_forbiddenChars", false);
		}

		public static void SetValues(PlayerChatManager instance, int[] values = null)
		{
			if (!((Object)(object)instance == (Object)null))
			{
				A_PlayerChatManager_m_forbiddenChars.Set(instance, Il2CppStructArray<int>.op_Implicit(values ?? Array.Empty<int>()));
			}
		}
	}
}
namespace TheArchive.Features.Security
{
	[EnableFeatureByDefault]
	public class AntiBoosterHack : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		private class BoosterImplantManager__OnSyncBoosterImplants__Patch
		{
			private static void Postfix(SNet_Player player, pBoosterImplantsWithOwner pBoosterImplantsWithOwner)
			{
				SNet_Player player2 = default(SNet_Player);
				if (SNet.IsMaster && pBoosterImplantsWithOwner != null && (player == null || !player.IsLocal) && SNet.Replication.TryGetLastSender(ref player2, false) && ((pBoosterImplantsWithOwner.BasicImplant.BoosterEffectCount != 0 && !BoosterImplantTemplateManager.TryGetBoosterImplantTemplate(pBoosterImplantsWithOwner.BasicImplant, (BoosterImplantCategory)0)) || (pBoosterImplantsWithOwner.AdvancedImplant.BoosterEffectCount != 0 && !BoosterImplantTemplateManager.TryGetBoosterImplantTemplate(pBoosterImplantsWithOwner.AdvancedImplant, (BoosterImplantCategory)1)) || (pBoosterImplantsWithOwner.SpecializedImplant.BoosterEffectCount != 0 && !BoosterImplantTemplateManager.TryGetBoosterImplantTemplate(pBoosterImplantsWithOwner.SpecializedImplant, (BoosterImplantCategory)2))))
				{
					PunishPlayer(player2);
				}
			}
		}

		public static class BoosterImplantTemplateManager
		{
			public class LocalizedTextJsonConverter : JsonConverter
			{
				public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
				{
					writer.WriteValue(string.Empty);
				}

				public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
				{
					return BoosterImplantTemplateDataBlock.UNKNOWN_BLOCK.PublicName;
				}

				public override bool CanConvert(Type objectType)
				{
					return objectType == typeof(LocalizedText);
				}
			}

			public class ListOfTConverter<T> : JsonConverter<List<T>>
			{
				public override List<T> ReadJson(JsonReader reader, Type objectType, List<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
				{
					//IL_0008: Unknown result type (might be due to invalid IL or missing references)
					//IL_000e: Invalid comparison between Unknown and I4
					JToken val = JToken.Load(reader);
					if ((int)val.Type == 2)
					{
						return SharedUtils.ToIL2CPPListIfNecessary<T>(val.ToObject<List<T>>(serializer));
					}
					return null;
				}

				public override void WriteJson(JsonWriter writer, List<T> value, JsonSerializer serializer)
				{
					JToken.FromObject((object)value).WriteTo(writer, Array.Empty<JsonConverter>());
				}

				public ListOfTConverter()
				{
					((JsonConverter<List<List<T>>>)(object)this)..ctor();
				}
			}

			public class ListOfListOfTConverter<T> : JsonConverter<List<List<T>>>
			{
				public override List<List<T>> ReadJson(JsonReader reader, Type objectType, List<List<T>> existingValue, bool hasExistingValue, JsonSerializer serializer)
				{
					//IL_000e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0014: Invalid comparison between Unknown and I4
					//IL_001a: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: 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_003a: Invalid comparison between Unknown and I4
					//IL_0045: Unknown result type (might be due to invalid IL or missing references)
					//IL_004a: Unknown result type (might be due to invalid IL or missing references)
					JToken val = JToken.Load(reader);
					List<List<T>> val2 = (List<List<T>>)(object)new List<List<List<T>>>();
					if ((int)val.Type == 2)
					{
						foreach (JToken item in val.Children())
						{
							if ((int)item.Type != 2)
							{
								continue;
							}
							List<T> val3 = new List<T>();
							foreach (JToken item2 in item.Children())
							{
								T val4 = item2.ToObject<T>(serializer);
								val3.Add(val4);
							}
							((List<List<List<T>>>)(object)val2).Add((List<List<T>>)(object)val3);
						}
					}
					return val2;
				}

				public override void WriteJson(JsonWriter writer, List<List<T>> value, JsonSerializer serializer)
				{
					JToken.FromObject((object)value).WriteTo(writer, Array.Empty<JsonConverter>());
				}

				public ListOfListOfTConverter()
				{
					((JsonConverter<List<List<List<List<T>>>>>)(object)this)..ctor();
				}
			}

			public class BoosterImplantEffectTemplate
			{
				public uint BoosterImplantEffect { get; set; }

				public float EffectMaxValue { get; set; }

				public float EffectMinValue { get; set; }

				public BoosterImplantEffectTemplate(BoosterImplantEffectInstance effect)
				{
					EffectMaxValue = effect.MaxValue;
					EffectMinValue = effect.MinValue;
					BoosterImplantEffect = effect.BoosterImplantEffect;
				}
			}

			public class BoosterImplantTemplate
			{
				public uint BoosterImplantID { get; set; }

				public BoosterImplantCategory ImplantCategory { get; set; }

				[JsonIgnore]
				public List<BoosterImplantEffectTemplate> Effects { get; set; } = new List<BoosterImplantEffectTemplate>();


				[JsonIgnore]
				public List<List<BoosterImplantEffectTemplate>> RandomEffects { get; set; } = new List<List<BoosterImplantEffectTemplate>>();


				[JsonIgnore]
				public List<uint> Conditions { get; set; } = new List<uint>();


				[JsonIgnore]
				public List<uint> RandomConditions { get; set; } = new List<uint>();


				[JsonIgnore]
				public BoosterImplantTemplateDataBlock TemplateDataBlock { get; private set; }

				public List<List<BoosterImplantEffectTemplate>> EffectGroups { get; set; } = new List<List<BoosterImplantEffectTemplate>>();


				public List<List<uint>> ConditionGroups { get; set; } = new List<List<uint>>();


				public BoosterImplantTemplate(BoosterImplantTemplateDataBlock block)
				{
					//IL_005d: Unknown result type (might be due to invalid IL or missing references)
					TemplateDataBlock = block;
					BoosterImplantID = ((GameDataBlockBase<BoosterImplantTemplateDataBlock>)(object)block).persistentID;
					ImplantCategory = block.ImplantCategory;
					for (int i = 0; i < block.Effects.Count; i++)
					{
						Effects.Add(new BoosterImplantEffectTemplate(block.Effects[i]));
					}
					for (int j = 0; j < block.RandomEffects.Count; j++)
					{
						List<BoosterImplantEffectTemplate> list = new List<BoosterImplantEffectTemplate>();
						for (int k = 0; k < block.RandomEffects[j].Count; k++)
						{
							list.Add(new BoosterImplantEffectTemplate(block.RandomEffects[j][k]));
						}
						RandomEffects.Add(list);
					}
					Conditions.AddRange((IEnumerable<uint>)block.Conditions.ToArray());
					RandomConditions.AddRange((IEnumerable<uint>)block.RandomConditions.ToArray());
					EffectGroups = GenerateEffectGroups();
					ConditionGroups = GenerateConditionGroups();
				}

				private List<List<BoosterImplantEffectTemplate>> GenerateEffectGroups()
				{
					List<List<BoosterImplantEffectTemplate>> list = new List<List<BoosterImplantEffectTemplate>>();
					List<List<BoosterImplantEffectTemplate>> nElementCombinations = GetNElementCombinations(RandomEffects);
					for (int i = 0; i < nElementCombinations.Count; i++)
					{
						List<BoosterImplantEffectTemplate> list2 = Effects.ToList();
						list2.AddRange(nElementCombinations[i]);
						list.Add(list2);
					}
					return list;
				}

				private List<List<uint>> GenerateConditionGroups()
				{
					return GetNElementCombinations(new List<List<uint>> { Conditions, RandomConditions });
				}
			}

			private static string _r5BoosterTemplatesJson;

			private static List<BoosterImplantTemplateDataBlock> OldBoosterImplantTemplateDataBlocks = new List<BoosterImplantTemplateDataBlock>();

			public static List<BoosterImplantTemplate> BoosterImplantTemplates { get; } = new List<BoosterImplantTemplate>();


			private static string R5BoosterTemplatesJson
			{
				get
				{
					if (!string.IsNullOrWhiteSpace(_r5BoosterTemplatesJson))
					{
						return _r5BoosterTemplatesJson;
					}
					byte[] bytes = Utils.LoadFromResource("TheArchive.Resources.RundownFiveBoosterTemplates.json");
					_r5BoosterTemplatesJson = Encoding.UTF8.GetString(bytes);
					return _r5BoosterTemplatesJson;
				}
			}

			public static void LoadTemplateData()
			{
				OldBoosterImplantTemplateDataBlocks.Clear();
				OldBoosterImplantTemplateDataBlocks.AddRange(JsonConvert.DeserializeObject<List<BoosterImplantTemplateDataBlock>>(R5BoosterTemplatesJson, (JsonConverter[])(object)new JsonConverter[4]
				{
					new LocalizedTextJsonConverter(),
					(JsonConverter)new ListOfTConverter<uint>(),
					(JsonConverter)new ListOfTConverter<BoosterImplantEffectInstance>(),
					(JsonConverter)new ListOfListOfTConverter<BoosterImplantEffectInstance>()
				}));
				BoosterImplantTemplates.Clear();
				Il2CppArrayBase<BoosterImplantTemplateDataBlock> allBlocksForEditor = GameDataBlockBase<BoosterImplantTemplateDataBlock>.GetAllBlocksForEditor();
				for (int i = 0; i < allBlocksForEditor.Count; i++)
				{
					BoosterImplantTemplates.Add(new BoosterImplantTemplate(allBlocksForEditor[i]));
				}
				for (int j = 0; j < OldBoosterImplantTemplateDataBlocks.Count; j++)
				{
					BoosterImplantTemplates.Add(new BoosterImplantTemplate(OldBoosterImplantTemplateDataBlocks[j]));
				}
			}

			public static bool TryGetBoosterImplantTemplate(pBoosterImplantData boosterImplant, BoosterImplantCategory category)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
				if (boosterImplant == null)
				{
					return false;
				}
				uint persistenID = boosterImplant.BoosterImplantID;
				List<BoosterImplantTemplate> list = BoosterImplantTemplates.FindAll((BoosterImplantTemplate p) => p.BoosterImplantID == persistenID && p.ImplantCategory == category);
				for (int k = 0; k < list.Count; k++)
				{
					BoosterImplantTemplate boosterImplantTemplate = list[k];
					if (boosterImplantTemplate == null || boosterImplantTemplate.TemplateDataBlock == null)
					{
						continue;
					}
					List<List<uint>> conditionGroups = boosterImplantTemplate.ConditionGroups;
					int conditionCount = boosterImplant.ConditionCount;
					bool flag = false;
					IEnumerable<uint> conditions = ((IEnumerable<uint>)boosterImplant.Conditions).Take(conditionCount);
					int j;
					for (j = 0; j < conditionGroups.Count; j++)
					{
						if (conditionCount != conditionGroups[j].Count)
						{
							continue;
						}
						bool num = conditions.All((uint p) => conditionGroups[j].Any((uint q) => q == p));
						bool flag2 = conditionGroups[j].All((uint p) => conditions.Any((uint q) => q == p));
						if (num && flag2)
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						continue;
					}
					int boosterEffectCount = boosterImplant.BoosterEffectCount;
					bool flag3 = false;
					List<List<BoosterImplantEffectTemplate>> effectGroups = boosterImplantTemplate.EffectGroups;
					IEnumerable<pBoosterEffectData> effects = ((IEnumerable<pBoosterEffectData>)boosterImplant.BoosterEffectDatas).Take(boosterEffectCount);
					int i;
					for (i = 0; i < effectGroups.Count; i++)
					{
						if (effectGroups[i].Count != boosterEffectCount)
						{
							continue;
						}
						for (int l = 0; l < effectGroups[i].Count; l++)
						{
							bool num2 = effects.All((pBoosterEffectData p) => effectGroups[i].Any((BoosterImplantEffectTemplate q) => q.BoosterImplantEffect == p.BoosterEffectID && p.EffectValue >= q.EffectMinValue && p.EffectValue <= q.EffectMaxValue));
							bool flag4 = effectGroups[i].All((BoosterImplantEffectTemplate p) => effects.Any((pBoosterEffectData q) => q.BoosterEffectID == p.BoosterImplantEffect && q.EffectValue >= p.EffectMinValue && q.EffectValue <= p.EffectMaxValue));
							if (num2 && flag4)
							{
								flag3 = true;
								break;
							}
						}
						if (flag3)
						{
							break;
						}
					}
					if (flag3)
					{
						bool flag5 = boosterImplant.UseCount <= (int)boosterImplantTemplate.TemplateDataBlock.DurationRange.y && boosterImplant.UseCount >= 0;
						if (flag && flag3 && flag5)
						{
							return true;
						}
					}
				}
				return false;
			}

			private static List<List<T>> GetNElementCombinations<T>(List<List<T>> lists)
			{
				List<List<T>> list = new List<List<T>>();
				GetNElementCombinationsHelper(lists, new List<T>(), 0, list);
				return list;
			}

			private static void GetNElementCombinationsHelper<T>(List<List<T>> lists, List<T> currentCombination, int currentIndex, List<List<T>> combinations)
			{
				if (currentIndex == lists.Count)
				{
					combinations.Add(new List<T>(currentCombination));
					return;
				}
				List<T> list = lists[currentIndex];
				if (list.Count == 0)
				{
					GetNElementCombinationsHelper(lists, currentCombination, currentIndex + 1, combinations);
					return;
				}
				foreach (T item in list)
				{
					currentCombination.Add(item);
					GetNElementCombinationsHelper(lists, currentCombination, currentIndex + 1, combinations);
					currentCombination.RemoveAt(currentCombination.Count - 1);
				}
			}
		}

		public override string Name => "Anti Booster Hack";

		public override string Description => "Prevents clients from using modified boosters.";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Security;

		public override Type[] ExternalLocalizedTypes => new Type[1] { typeof(BasicPunishmentSettings) };

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static BasicPunishmentSettings Settings { get; set; }

		public override bool ShouldInit()
		{
			if (ArchiveMod.IsPlayingModded)
			{
				((Feature)this).RequestDisable("Playing Modded");
				return false;
			}
			return true;
		}

		public override void OnGameDataInitialized()
		{
			BoosterImplantTemplateManager.LoadTemplateData();
		}

		public static bool PunishPlayer(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return true;
			}
			if (SharedUtils.IsFriend(player) && !Settings.PunishFriends)
			{
				FeatureLogger.Notice($"Friend \"{player.NickName}\" \"{player.Lookup}\" is using modified boosters!");
				return false;
			}
			switch (Settings.Punishment)
			{
			case BasicPunishmentSettings.PunishmentMode.KickAndBan:
				PlayerLobbyManagement.BanPlayer(player);
				break;
			case BasicPunishmentSettings.PunishmentMode.Kick:
				PlayerLobbyManagement.KickPlayer(player);
				break;
			}
			FeatureLogger.Notice($"Player \"{player.NickName}\" \"{player.Lookup}\" is using modified boosters! ({Settings.Punishment})");
			return true;
		}
	}
	[EnableFeatureByDefault]
	public class AntiGearHack : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		private class PlayerBackpackManager__ReceiveInventorySync__Patch
		{
			private static void Prefix(pInventorySync data)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Expected O, but got Unknown
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Expected O, but got Unknown
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Expected O, but got Unknown
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Expected O, but got Unknown
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Expected O, but got Unknown
				if (!SNet.IsMaster)
				{
					return;
				}
				pPlayer sourcePlayer = data.sourcePlayer;
				SNet_Player val = default(SNet_Player);
				SNet_Player val2 = default(SNet_Player);
				if (!((pPlayer)(ref sourcePlayer)).TryGetPlayer(ref val) || val.IsLocal || val.IsBot || !SNet.Replication.TryGetLastSender(ref val2, false) || val2.IsLocal || val2.IsBot)
				{
					return;
				}
				foreach (GearIDRange item in new List<GearIDRange>
				{
					new GearIDRange(data.gearStandard),
					new GearIDRange(data.gearSpecial),
					new GearIDRange(data.gearMelee),
					new GearIDRange(data.gearClass),
					new GearIDRange(data.gearHacking)
				})
				{
					if (!CheckGearIDRange(item))
					{
						PunishPlayer(val2);
						break;
					}
				}
			}
		}

		private static Dictionary<string, string> GearCompsHashLookup = new Dictionary<string, string>();

		public override string Name => "Anti Gear Hack";

		public override string Description => "Prevents clients from using modified gear.";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Security;

		public override Type[] ExternalLocalizedTypes => new Type[1] { typeof(BasicPunishmentSettings) };

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static BasicPunishmentSettings Settings { get; set; }

		public override bool ShouldInit()
		{
			if (ArchiveMod.IsPlayingModded)
			{
				((Feature)this).RequestDisable("Playing Modded");
				return false;
			}
			return true;
		}

		public override void OnGameDataInitialized()
		{
			LoadData();
		}

		public static bool PunishPlayer(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return true;
			}
			if (SharedUtils.IsFriend(player) && !Settings.PunishFriends)
			{
				FeatureLogger.Notice($"Friend \"{player.NickName}\" \"{player.Lookup}\" is using modified gears!");
				return false;
			}
			switch (Settings.Punishment)
			{
			case BasicPunishmentSettings.PunishmentMode.KickAndBan:
				PlayerLobbyManagement.BanPlayer(player);
				break;
			case BasicPunishmentSettings.PunishmentMode.Kick:
				PlayerLobbyManagement.KickPlayer(player);
				break;
			}
			FeatureLogger.Notice($"Player \"{player.NickName}\" \"{player.Lookup}\" is using modified gears! ({Settings.Punishment})");
			return true;
		}

		public static bool CheckIsValidWeaponGearIDRangeDataForPlayer(SNet_Player player)
		{
			if (!player.HasCharacterSlot)
			{
				return false;
			}
			Enumerator<GearIDRange> enumerator = ((Il2CppArrayBase<List<GearIDRange>>)(object)GearManager.Current.m_gearPerSlot)[player.PlayerSlotIndex()].GetEnumerator();
			while (enumerator.MoveNext())
			{
				if (CheckGearIDRange(enumerator.Current))
				{
					return false;
				}
			}
			return true;
		}

		public static bool CheckGearIDRange(GearIDRange gearIDRange)
		{
			string input = gearIDRange.ToJSON();
			string pattern = "(?<=Comps\":)(.*?)(?=,\"MatTrans\")";
			string key = Utils.HashString(Regex.Match(input, pattern).Value);
			return GearCompsHashLookup.ContainsKey(key);
		}

		public static void LoadData()
		{
			GearCompsHashLookup.Clear();
			foreach (PlayerOfflineGearDataBlock allBlock in GameDataBlockBase<PlayerOfflineGearDataBlock>.GetAllBlocks())
			{
				string gearJSON = allBlock.GearJSON;
				string pattern = "(?<=Comps\":)(.*?)(?=,\"MatTrans\")";
				string key = Utils.HashString(Regex.Match(gearJSON, pattern).Value);
				GearCompsHashLookup[key] = gearJSON;
			}
		}
	}
	[EnableFeatureByDefault]
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class AntiSpawn : Feature
	{
		public unsafe delegate void Original_InternalSpawnRequestFromSlaveCallback(IntPtr self, IntPtr spawnData, Il2CppMethodInfo* methodInfo);

		private static bool _hasBeenPatched = false;

		private static Original_InternalSpawnRequestFromSlaveCallback _originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData;

		private unsafe static Original_InternalSpawnRequestFromSlaveCallback _detourMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData = InternalSpawnRequestFromSlaveCallback_pEnemySpawnData_Replacement;

		private static Original_InternalSpawnRequestFromSlaveCallback _originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData;

		private unsafe static Original_InternalSpawnRequestFromSlaveCallback _detourMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData = InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData_Replacement;

		public override string Name => "Anti Spawn";

		public override string Description => "Prevents clients from spawning in enemies.";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Security;

		public override Type[] ExternalLocalizedTypes => new Type[1] { typeof(BasicPunishmentSettings) };

		public static IArchiveLogger FeatureLogger { get; set; }

		public static bool IsEnabled { get; set; }

		[FeatureConfig]
		public static BasicPunishmentSettings Settings { get; set; }

		public override void OnEnable()
		{
			OneTimePatch();
		}

		private static void OneTimePatch()
		{
			if (!_hasBeenPatched)
			{
				LoaderWrapper.ApplyNativeHook<SNet_ReplicationManager<pEnemySpawnData, EnemyReplicator>, Original_InternalSpawnRequestFromSlaveCallback>("InternalSpawnRequestFromSlaveCallback", typeof(void).FullName, new string[1] { typeof(pEnemySpawnData).FullName }, _detourMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData, ref _originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData);
				LoaderWrapper.ApplyNativeHook<SNet_ReplicationManager<pEnemyGroupSpawnData, SNet_DynamicReplicator<pEnemyGroupSpawnData>>, Original_InternalSpawnRequestFromSlaveCallback>("InternalSpawnRequestFromSlaveCallback", typeof(void).FullName, new string[1] { typeof(pEnemyGroupSpawnData).FullName }, _detourMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData, ref _originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData);
				_hasBeenPatched = true;
			}
		}

		public unsafe static void InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData_Replacement(IntPtr self, IntPtr spawnData, Il2CppMethodInfo* methodInfo)
		{
			if (IsEnabled && SNet.IsMaster && !SNet.Capture.IsCheckpointRecall)
			{
				bool flag = true;
				SNet_Player player = default(SNet_Player);
				if (SNet.Replication.TryGetLastSender(ref player, false))
				{
					flag = PunishPlayer(player);
				}
				if (flag)
				{
					FeatureLogger.Fail("Cancelled enemy spawn!");
					return;
				}
			}
			_originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData(self, spawnData, methodInfo);
		}

		public unsafe static void InternalSpawnRequestFromSlaveCallback_pEnemySpawnData_Replacement(IntPtr self, IntPtr spawnData, Il2CppMethodInfo* methodInfo)
		{
			if (IsEnabled && SNet.IsMaster && !SNet.Capture.IsCheckpointRecall)
			{
				bool flag = true;
				SNet_Player player = default(SNet_Player);
				if (SNet.Replication.TryGetLastSender(ref player, false))
				{
					flag = PunishPlayer(player);
				}
				if (flag)
				{
					FeatureLogger.Fail("Cancelled enemy spawn!");
					return;
				}
			}
			_originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData(self, spawnData, methodInfo);
		}

		public static bool PunishPlayer(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return true;
			}
			if (SharedUtils.IsFriend(player) && !Settings.PunishFriends)
			{
				FeatureLogger.Notice("Friend \"" + player.NickName + "\" is spawning something in!");
				return false;
			}
			switch (Settings.Punishment)
			{
			case BasicPunishmentSettings.PunishmentMode.KickAndBan:
				PlayerLobbyManagement.BanPlayer(player);
				break;
			case BasicPunishmentSettings.PunishmentMode.Kick:
				PlayerLobbyManagement.KickPlayer(player);
				break;
			}
			FeatureLogger.Notice($"Player \"{player.NickName}\" tried to spawn something! ({Settings.Punishment})");
			return true;
		}
	}
	public class BasicPunishmentSettings
	{
		[Localized]
		public enum PunishmentMode
		{
			NoneAndLog,
			Kick,
			KickAndBan
		}

		[FSDisplayName("Punish Friends")]
		[FSDescription("If (Steam) Friends should be affected as well.")]
		public bool PunishFriends { get; set; }

		[FSDisplayName("Punishment")]
		[FSDescription("What to do with griefers.")]
		public PunishmentMode Punishment { get; set; } = PunishmentMode.Kick;

	}
	[EnableFeatureByDefault]
	public class PlayerLobbyManagement : Feature
	{
		public class LobbyManagementSettings
		{
			public class LobbyColorSettings
			{
				[FSDisplayName("Color the Square")]
				[FSDescription("Use the colors/settings below to color the square on the loadout screen next to the player names.")]
				public bool ColorizeLobbyBullet { get; set; } = true;


				[FSDisplayName("Use Nickname Color for Self")]
				public bool UseNicknameColorForSelf { get; set; } = true;


				[FSDisplayName("Random Colors for Self")]
				public bool RainbowPukeSelf { get; set; }

				[FSDisplayName("Random Colors for Others")]
				public bool RainbowPukeFriends { get; set; }

				[FSHeader("Colors", true)]
				[FSDisplayName("Default")]
				public SColor Default { get; set; } = new SColor(1f, 1f, 1f, (float?)null);


				[FSDisplayName("Friends")]
				public SColor Friends { get; set; } = new SColor(0.964f, 0.921f, 0.227f, (float?)null);


				[FSDisplayName("Bots")]
				public SColor Bots { get; set; } = new SColor(0.949f, 0.58f, 0f, (float?)null);


				[FSDisplayName("Banned")]
				public SColor Banned { get; set; } = new SColor(0.545f, 0f, 0f, (float?)null);


				[FSDisplayName("Self")]
				public SColor Self { get; set; } = new SColor(1f, 1f, 1f, (float?)null);

			}

			public class BanListEntry
			{
				[FSSeparator]
				[FSReadOnly(true)]
				[FSDisplayName("Name")]
				public string Name { get; set; }

				[FSReadOnly(true)]
				[FSDisplayName("SteamID")]
				public ulong SteamID { get; set; }

				[FSReadOnly(true)]
				[FSTimestamp("U")]
				[FSDisplayName("Banned on:")]
				public long Timestamp { get; set; }
			}

			public class RecentlyPlayedWithEntry
			{
				[FSSeparator]
				[FSReadOnly(true)]
				[FSDisplayName("Name")]
				public string Name { get; set; }

				[FSReadOnly(true)]
				[FSDisplayName("SteamID")]
				public ulong SteamID { get; set; }

				[FSReadOnly(true)]
				[FSTimestamp("U")]
				[FSDisplayName("First time played with:")]
				public long TimestampFirst { get; set; }

				[FSReadOnly(true)]
				[FSTimestamp("U")]
				[FSDisplayName("Last time played with:")]
				public long TimestampLast { get; set; }
			}

			[FSDisplayName("Names on Map open Steam Profile")]
			[FSDescription("If clicking a players name on the map screen should open their Steam Profile in your default browser.")]
			public bool NamesOnMapOpenSteamProfile { get; set; }

			[FSDisplayName("Open Profiles in Steam Overlay")]
			[FSDescription("Wheter to open profile links in the overlay or in the default OS browser.")]
			public bool PreferOpeningProfileLinksInSteamOverlay { get; set; } = true;


			[FSHeader("Lobby Color Settings", true)]
			[FSDisplayName("Lobby Colors")]
			public LobbyColorSettings LobbyColors { get; set; } = new LobbyColorSettings();


			[FSHeader("Other", true)]
			[FSDisplayName("Recently Played With")]
			public List<RecentlyPlayedWithEntry> RecentlyPlayedWith { get; set; } = new List<RecentlyPlayedWithEntry>();


			[FSDisplayName("Banned Players")]
			[FSDescription("Players who are on this list will not be able to join any games <b>you host</b>.")]
			public List<BanListEntry> BanList { get; set; } = new List<BanListEntry>();

		}

		[Localized]
		public enum PlayerRelationShip
		{
			None,
			Self,
			Friend,
			Banned,
			Bot
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class SNet_SessionHub_SlaveWantsToJoin_Patch
		{
			public static bool Prefix(SNet_Player player)
			{
				if (SNet.IsMaster && IsPlayerBanned(player.Lookup))
				{
					FeatureLogger.Notice("Banned player \"" + player.GetName() + "\" tried to join, their join request has been ignored!");
					KickPlayer(player);
					return false;
				}
				return true;
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class SNet_OnPlayerJoinedSessionHub_Patch
		{
			public static void Postfix(SNet_Player player)
			{
				AddRecentlyPlayedWith(player, joined: true);
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class SNet_OnPlayerLeftSessionHub_Patch
		{
			public static void Prefix(SNet_Player player)
			{
				AddRecentlyPlayedWith(player, joined: false);
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class CM_PlayerLobbyBar_UpdatePlayer_Patch
		{
			internal static Dictionary<int, BoxCollider2D> colliderMap = new Dictionary<int, BoxCollider2D>();

			private static MethodAccessor<GUIX_ElementSprite> A_Unregister;

			private static MethodAccessor<GUIX_ElementSprite> A_Start;

			private static IValueAccessor<GUIX_ElementSprite, GUIX_Layer> A_layer;

			public static void Init()
			{
				A_Start = MethodAccessor<GUIX_ElementSprite>.GetAccessor("Start", (Type[])null, false);
				A_Unregister = MethodAccessor<GUIX_ElementSprite>.GetAccessor("Unregister", (Type[])null, false);
				A_layer = AccessorBase.GetValueAccessor<GUIX_ElementSprite, GUIX_Layer>("layer", false);
			}

			public static void ColorizeNickNameGUIX(GameObject nickNameGuix, PlayerRelationShip rel = PlayerRelationShip.None)
			{
				//IL_0051: 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_00d1: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)nickNameGuix == (Object)null)
				{
					return;
				}
				foreach (Transform item in SharedUtils.DirectChildren(nickNameGuix.transform))
				{
					GUIX_ElementSprite component = ((Component)item).GetComponent<GUIX_ElementSprite>();
					SpriteRenderer component2 = ((Component)item).GetComponent<SpriteRenderer>();
					if ((Object)(object)component2 != (Object)null)
					{
						if (!Settings.LobbyColors.ColorizeLobbyBullet)
						{
							component2.color = Color.white;
						}
						else if (rel != PlayerRelationShip.Self)
						{
							if (rel != PlayerRelationShip.Friend || !Settings.LobbyColors.RainbowPukeFriends)
							{
								goto IL_00cf;
							}
							component2.color = Random.ColorHSV();
						}
						else if (Settings.LobbyColors.RainbowPukeSelf)
						{
							component2.color = Random.ColorHSV();
						}
						else
						{
							if (!Settings.LobbyColors.UseNicknameColorForSelf || !FeatureManager.IsFeatureEnabled<Nickname>() || !Nickname.IsNicknameColorEnabled)
							{
								goto IL_00cf;
							}
							component2.color = Nickname.CurrentNicknameColor;
						}
					}
					goto IL_00db;
					IL_00cf:
					component2.color = GetRelationshipColor(rel);
					goto IL_00db;
					IL_00db:
					if (!((Object)(object)A_layer.Get(component) == (Object)null) && ((Component)component).gameObject.activeInHierarchy)
					{
						A_Unregister.Invoke(component);
						component.DynamicIndex = -1;
						A_layer.Set(component, (GUIX_Layer)null);
						A_Start.Invoke(component);
					}
				}
			}

			public static void Postfix(CM_PlayerLobbyBar __instance, SNet_Player player)
			{
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				if (player == null)
				{
					return;
				}
				SNet_Slot characterSlot = player.CharacterSlot;
				if (characterSlot == null)
				{
					return;
				}
				_ = characterSlot.index;
				if (false)
				{
					return;
				}
				int playerLobbyBarIndex = SharedUtils.GetPlayerLobbyBarIndex(__instance);
				GameObject gameObject = ((Component)__instance.m_nickText).gameObject;
				CM_Item CM_Item = gameObject.GetComponent<CM_Item>();
				if ((Object)(object)CM_Item == (Object)null)
				{
					FeatureLogger.Debug($"Setting up player name button for slot index {playerLobbyBarIndex}");
					BoxCollider2D val = gameObject.AddComponent<BoxCollider2D>();
					val.size = new Vector2(447.2f, 52.8f);
					((Collider2D)val).offset = new Vector2(160f, 1.6f);
					if (colliderMap.ContainsKey(playerLobbyBarIndex))
					{
						colliderMap.Remove(playerLobbyBarIndex);
					}
					colliderMap.Add(playerLobbyBarIndex, val);
					CM_Item = gameObject.AddComponent<CM_Item>();
					CM_Item.ID = playerLobbyBarIndex + 1;
					SharedUtils.SetCMItemEvents(CM_Item, (Action<int>)delegate(int id)
					{
						if (!((RectTransformComp)PopupWindow).IsVisible || ((CM_PopupOverlay)PopupWindow).ID != id)
						{
							SetupAndPlaceWindow(id, ((Component)CM_Item).transform);
						}
						else
						{
							((RectTransformComp)PopupWindow).SetVisible(false);
						}
					}, (Action<int, bool>)null);
				}
				ColorizeNickNameGUIX(__instance.m_nickNameGuix, GetRelationship(player));
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class PUI_Inventory_UpdateAllSlots_Patch
		{
			internal static Dictionary<int, BoxCollider2D> colliderMap = new Dictionary<int, BoxCollider2D>();

			public static void Postfix(PUI_Inventory __instance, SNet_Player player)
			{
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				if (player == null)
				{
					return;
				}
				SNet_Slot characterSlot = player.CharacterSlot;
				if (characterSlot == null)
				{
					return;
				}
				_ = characterSlot.index;
				if (false)
				{
					return;
				}
				int index = player.CharacterSlot.index;
				GameObject headerRoot = __instance.m_headerRoot;
				if ((Object)(object)headerRoot.GetComponent<CM_Item>() == (Object)null)
				{
					FeatureLogger.Debug($"Setting up player name button (map) for index {player.CharacterSlot.index}");
					BoxCollider2D val = headerRoot.AddComponent<BoxCollider2D>();
					val.size = new Vector2(400f, 40f);
					((Collider2D)val).offset = new Vector2(-200f, 0f);
					if (colliderMap.ContainsKey(index))
					{
						colliderMap.Remove(index);
					}
					colliderMap.Add(index, val);
					CM_Item obj = headerRoot.AddComponent<CM_Item>();
					obj.ID = player.CharacterSlot.index + 1;
					SharedUtils.SetCMItemEvents(obj, (Action<int>)OnMapNameButtonPressed, (Action<int, bool>)null);
				}
			}
		}

		private static Dictionary<PlayerRelationShip, Color> _colorMap = new Dictionary<PlayerRelationShip, Color>();

		private static CM_ScrollWindow _popupWindow = null;

		public override string Name => "Player Lobby Management";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Security;

		public override string Description => "Allows you to open a players steam profile by clicking on their name as well as kick and ban players as host.";

		public static ILocalizationService Localization { get; set; }

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static LobbyManagementSettings Settings { get; set; }

		private static CM_ScrollWindow PopupWindow
		{
			get
			{
				//IL_0083: 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_0145: Unknown result type (might be due to invalid IL or missing references)
				//IL_0194: Unknown result type (might be due to invalid IL or missing references)
				//IL_0269: Unknown result type (might be due to invalid IL or missing references)
				//IL_0287: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_popupWindow == (Object)null)
				{
					FeatureLogger.Debug("Creating PopupWindow ...");
					_popupWindow = Object.Instantiate<CM_ScrollWindow>(PageSettingsData.PopupWindow, (Transform)(object)((CM_PageBase)CM_PageLoadout.Current).m_movingContentHolder);
					Object.DontDestroyOnLoad((Object)(object)_popupWindow);
					((Object)_popupWindow).name = "PlayerLobbyManagement_PopupWindow_PlayerManagement";
					((RectTransformComp)PopupWindow).Setup();
					OpenSteamItem = CreatePopupItem(Localization.GetById(1u, (string)null), OnNameButtonPressed);
					SharedUtils.ChangeColorCMItem(OpenSteamItem, ModSettings.GREEN, (Color?)null);
					SharedUtils.SetHoldDuration(SharedUtils.TryCastTo<CM_TimedButton>((Il2CppObjectBase)(object)OpenSteamItem), 0.5f);
					IsFriendItem = CreatePopupItem(Localization.GetById(2u, (string)null), delegate
					{
					});
					SharedUtils.ChangeColorCMItem(IsFriendItem, GetRelationshipColor(PlayerRelationShip.Friend), (Color?)null);
					SharedUtils.SetHoldDuration(SharedUtils.TryCastTo<CM_TimedButton>((Il2CppObjectBase)(object)IsFriendItem), 100f);
					((Behaviour)((Component)IsFriendItem).GetComponent<Collider2D>()).enabled = false;
					KickPlayerItem = CreatePopupItem(Localization.GetById(3u, (string)null), KickPlayerButtonPressed);
					SharedUtils.ChangeColorCMItem(KickPlayerItem, ModSettings.ORANGE, (Color?)null);
					SharedUtils.SetHoldDuration(SharedUtils.TryCastTo<CM_TimedButton>((Il2CppObjectBase)(object)KickPlayerItem), 2f);
					BanPlayerItem = CreatePopupItem(Localization.GetById(4u, (string)null), BanPlayerButtonPressed);
					SharedUtils.ChangeColorCMItem(BanPlayerItem, ModSettings.RED, (Color?)null);
					SharedUtils.SetHoldDuration(SharedUtils.TryCastTo<CM_TimedButton>((Il2CppObjectBase)(object)BanPlayerItem), 4f);
					CM_Item val = CreatePopupItem("Spacer, should not be visible", delegate
					{
					});
					List<iScrollWindowContent> val2 = SharedUtils.NewListForGame<iScrollWindowContent>();
					val2.Add(((Component)OpenSteamItem).GetComponentInChildren<iScrollWindowContent>());
					val2.Add(((Component)IsFriendItem).GetComponentInChildren<iScrollWindowContent>());
					val2.Add(((Component)val).GetComponentInChildren<iScrollWindowContent>());
					val2.Add(((Component)KickPlayerItem).GetComponentInChildren<iScrollWindowContent>());
					val2.Add(((Component)BanPlayerItem).GetComponentInChildren<iScrollWindowContent>());
					PopupWindow.SetContentItems(val2, 5f);
					((Component)val).gameObject.SetActive(false);
					((Component)val).transform.position = new Vector3(-5000f, 0f, 0f);
					((RectTransformComp)PopupWindow).SetSize(new Vector2(350f, (float)(58 * val2.Count)));
					((RectTransformComp)PopupWindow).SetVisible(false);
					PopupWindow.SetHeader("Player options");
				}
				return _popupWindow;
			}
		}

		internal static CM_Item OpenSteamItem { get; set; }

		internal static CM_Item IsFriendItem { get; set; }

		internal static CM_Item KickPlayerItem { get; set; }

		internal static CM_Item BanPlayerItem { get; set; }

		public override void OnEnable()
		{
			foreach (BoxCollider2D value in CM_PlayerLobbyBar_UpdatePlayer_Patch.colliderMap.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					((Behaviour)value).enabled = true;
				}
			}
			foreach (BoxCollider2D value2 in PUI_Inventory_UpdateAllSlots_Patch.colliderMap.Values)
			{
				if ((Object)(object)value2 != (Object)null)
				{
					((Behaviour)value2).enabled = true;
				}
			}
			SetupColorMap();
		}

		public override void OnDisable()
		{
			foreach (BoxCollider2D value in CM_PlayerLobbyBar_UpdatePlayer_Patch.colliderMap.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					((Behaviour)value).enabled = false;
				}
			}
			foreach (BoxCollider2D value2 in PUI_Inventory_UpdateAllSlots_Patch.colliderMap.Values)
			{
				if ((Object)(object)value2 != (Object)null)
				{
					((Behaviour)value2).enabled = false;
				}
			}
		}

		public override void OnFeatureSettingChanged(FeatureSetting setting)
		{
			SetupColorMap();
		}

		public static void SetupColorMap()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			_colorMap.Clear();
			PlayerRelationShip[] array = Enum.GetValues(typeof(PlayerRelationShip)) as PlayerRelationShip[];
			foreach (PlayerRelationShip playerRelationShip in array)
			{
				_colorMap.Add(playerRelationShip, GetRelationshipColor(playerRelationShip));
			}
		}

		public static PlayerRelationShip GetRelationship(PlayerAgent player)
		{
			return GetRelationship((player != null) ? player.Owner : null);
		}

		public static PlayerRelationShip GetRelationship(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return PlayerRelationShip.None;
			}
			if (SharedUtils.SafeIsBot(player))
			{
				return PlayerRelationShip.Bot;
			}
			if (player.IsLocal)
			{
				return PlayerRelationShip.Self;
			}
			if (IsPlayerBanned(player.Lookup))
			{
				return PlayerRelationShip.Banned;
			}
			if (SharedUtils.IsFriend(player))
			{
				return PlayerRelationShip.Friend;
			}
			return PlayerRelationShip.None;
		}

		public static Color GetRelationshipColor(PlayerRelationShip rel)
		{
			//IL_000f: 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)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0079: 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_008e: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			if (_colorMap.TryGetValue(rel, out var value))
			{
				return value;
			}
			return (Color)(rel switch
			{
				PlayerRelationShip.Self => SColorExtensions.ToUnityColor(Settings.LobbyColors.Self), 
				PlayerRelationShip.Bot => SColorExtensions.ToUnityColor(Settings.LobbyColors.Bots), 
				PlayerRelationShip.Friend => SColorExtensions.ToUnityColor(Settings.LobbyColors.Friends), 
				PlayerRelationShip.Banned => SColorExtensions.ToUnityColor(Settings.LobbyColors.Banned), 
				_ => SColorExtensions.ToUnityColor(Settings.LobbyColors.Default), 
			});
		}

		public static bool IsPlayerBanned(ulong lookup)
		{
			return Settings.BanList.Any((LobbyManagementSettings.BanListEntry bp) => bp.SteamID == lookup);
		}

		internal static void OnMapNameButtonPressed(int id)
		{
			if (Settings.NamesOnMapOpenSteamProfile)
			{
				SNet_Player player = default(SNet_Player);
				if (!SharedUtils.TryGetPlayerByCharacterIndex(id, ref player))
				{
					FeatureLogger.Debug($"No player found for character index {id - 1}.");
				}
				else
				{
					OpenSteamProfileFor(player);
				}
			}
		}

		internal static void OnNameButtonPressed(int id)
		{
			((RectTransformComp)PopupWindow).SetVisible(false);
			SNet_Player player = default(SNet_Player);
			if (!SharedUtils.TryGetPlayerByPlayerLobbyBarIndex(id - 1, ref player))
			{
				FeatureLogger.Debug($"No player found for index {id - 1}.");
			}
			else
			{
				OpenSteamProfileFor(player);
			}
		}

		public static void OpenSteamProfileFor(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				FeatureLogger.Debug("Player was null!");
				return;
			}
			if (SharedUtils.SafeIsBot(player))
			{
				FeatureLogger.Notice("The Bot has no steam profile!");
				return;
			}
			FeatureLogger.Info($"Opening Steam profile for player \"{player.NickName}\" ({player.Lookup})");
			string text = $"https://steamcommunity.com/profiles/{player.Lookup}";
			if (Settings.PreferOpeningProfileLinksInSteamOverlay && SteamUtils.IsOverlayEnabled())
			{
				SteamFriends.ActivateGameOverlayToWebPage(text, (EActivateGameOverlayToWebPageMode)0);
			}
			else
			{
				Application.OpenURL(text);
			}
		}

		internal static void KickPlayerButtonPressed(int playerID)
		{
			((RectTransformComp)PopupWindow).SetVisible(false);
			SNet_Player val = default(SNet_Player);
			if (SNet.IsMaster && SharedUtils.TryGetPlayerByPlayerLobbyBarIndex(playerID - 1, ref val))
			{
				if (SharedUtils.SafeIsBot(val))
				{
					FeatureLogger.Notice("Use the built in button below to remove bots!");
					return;
				}
				FeatureLogger.Notice($"Kicking player \"{val.GetName()}\" Nick:\"{val.NickName}\" ...");
				KickPlayer(val);
			}
		}

		internal static void BanPlayerButtonPressed(int playerID)
		{
			SNet_Player val = default(SNet_Player);
			if (!SharedUtils.TryGetPlayerByPlayerLobbyBarIndex(playerID - 1, ref val))
			{
				return;
			}
			if (val.IsLocal)
			{
				BanPlayerItem.SetText(" You can't ban yourself, silly!");
				return;
			}
			((RectTransformComp)PopupWindow).SetVisible(false);
			if (SharedUtils.SafeIsBot(val))
			{
				FeatureLogger.Notice("You can't ban a bot!");
			}
			else if (!IsPlayerBanned(val.Lookup))
			{
				BanPlayer(val);
			}
			else
			{
				UnbanPlayer(val);
			}
		}

		public static bool BanPlayer(SNet_Player player, bool kickPlayer = true)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (!IsPlayerBanned(player.Lookup))
			{
				Settings.BanList.Add(new LobbyManagementSettings.BanListEntry
				{
					Name = player.GetName(),
					SteamID = player.Lookup,
					Timestamp = DateTime.UtcNow.Ticks
				});
				FeatureLogger.Fail($"Player has been added to list of banned players: Name:\"{player.GetName()}\" SteamID:\"{player.Lookup}\"");
				Feature.MarkSettingsAsDirty<LobbyManagementSettings>(Settings);
				if (kickPlayer)
				{
					KickPlayer(player);
				}
				return true;
			}
			return false;
		}

		public static bool UnbanPlayer(SNet_Player player)
		{
			return UnbanPlayer((player != null) ? player.Lookup : ulong.MaxValue);
		}

		public static bool UnbanPlayer(ulong playerID)
		{
			if (playerID == ulong.MaxValue)
			{
				return false;
			}
			LobbyManagementSettings.BanListEntry banListEntry = Settings.BanList.FirstOrDefault((LobbyManagementSettings.BanListEntry entry) => entry.SteamID == playerID);
			if (banListEntry != null)
			{
				Settings.BanList.Remove(banListEntry);
				FeatureLogger.Success($"Player has been removed from the list of banned players: Name:\"{banListEntry.Name}\" SteamID:\"{banListEntry.SteamID}\"");
				Feature.MarkSettingsAsDirty<LobbyManagementSettings>(Settings);
				return true;
			}
			return false;
		}

		public static void KickPlayer(SNet_Player player)
		{
			if (SNet.IsMaster)
			{
				SNet.Sync.KickPlayer(player, (SNet_PlayerEventReason)2);
			}
		}

		private static CM_Item CreatePopupItem(string text, Action<int> onClick, int id = 0)
		{
			CM_Item val = SharedUtils.TryCastTo<CM_Item>((Il2CppObjectBase)(object)GOUtil.SpawnChildAndGetComp<iScrollWindowContent>(UIHelper.PopupItemPrefab, ((Component)_popupWindow).transform));
			val.SetupCMItem();
			if (id != 0)
			{
				val.ID = id;
			}
			val.SetText(text);
			SharedUtils.SetCMItemEvents(val, onClick, (Action<int, bool>)null);
			((RectTransformComp)val).ForcePopupLayer(true, (GameObject)null);
			return val;
		}

		public static void SetupAndPlaceWindow(int playerID, Transform pos)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			SNet_Player val = default(SNet_Player);
			if (!SharedUtils.TryGetPlayerByPlayerLobbyBarIndex(playerID - 1, ref val))
			{
				return;
			}
			string name = val.GetName();
			bool flag = SharedUtils.SafeIsBot(val);
			((Component)KickPlayerItem).gameObject.SetActive(!flag);
			((Component)BanPlayerItem).gameObject.SetActive(!flag);
			((Component)OpenSteamItem).gameObject.SetActive(!flag);
			if (flag)
			{
				((Component)IsFriendItem).gameObject.SetActive(true);
				IsFriendItem.SetText(Localization.GetById(6u, (string)null));
				SharedUtils.ChangeColorCMItem(IsFriendItem, GetRelationshipColor(PlayerRelationShip.Bot), (Color?)null);
				ShowWindow(name, pos, playerID);
				return;
			}
			((CM_PopupOverlay)PopupWindow).SetupFromButton(new iCellMenuPopupController(((Il2CppObjectBase)CM_PageLoadout.Current).Pointer), (CM_PageBase)(object)CM_PageLoadout.Current);
			SNet_Friend val2 = default(SNet_Friend);
			bool flag2 = SNet.Friends.TryGetFriend(val.Lookup, ref val2);
			bool flag3 = IsPlayerBanned(val.Lookup);
			((Component)IsFriendItem).gameObject.SetActive(flag2 || flag3);
			if (flag3)
			{
				IsFriendItem.SetText(Localization.GetById(5u, (string)null));
				SharedUtils.ChangeColorCMItem(IsFriendItem, GetRelationshipColor(PlayerRelationShip.Banned), (Color?)null);
			}
			else if (flag2)
			{
				IsFriendItem.SetText(Localization.GetById(2u, (string)null));
				SharedUtils.ChangeColorCMItem(IsFriendItem, GetRelationshipColor(PlayerRelationShip.Friend), (Color?)null);
			}
			KickPlayerItem.SetText(Localization.Format(7u, " Kick {0}", new object[1] { name }));
			if (val.IsMaster || !SNet.IsMaster)
			{
				((Behaviour)((Component)KickPlayerItem).GetComponent<Collider2D>()).enabled = false;
				SharedUtils.ChangeColorCMItem(KickPlayerItem, ModSettings.DISABLED, (Color?)null);
				BanPlayerItem.SetText(Localization.Format(8u, " Ban {0}", new object[1] { name }));
			}
			else
			{
				((Behaviour)((Component)KickPlayerItem).GetComponent<Collider2D>()).enabled = true;
				SharedUtils.ChangeColorCMItem(KickPlayerItem, ModSettings.ORANGE, (Color?)null);
				BanPlayerItem.SetText(Localization.Format(9u, " Ban and kick {0}", new object[1] { name }));
			}
			if (val.IsLocal)
			{
				SharedUtils.ChangeColorCMItem(BanPlayerItem, ModSettings.DISABLED, (Color?)null);
			}
			else if (flag3)
			{
				BanPlayerItem.SetText(Localization.Format(10u, " Unban {0}", new object[1] { name }));
				SharedUtils.ChangeColorCMItem(BanPlayerItem, ModSettings.GREEN, (Color?)null);
			}
			else
			{
				SharedUtils.ChangeColorCMItem(BanPlayerItem, ModSettings.RED, (Color?)null);
			}
			ShowWindow(name, pos, playerID);
		}

		private static void ShowWindow(string header, Transform pos, int playerID)
		{
			//IL_0021: 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)
			PopupWindow.SetHeader(header);
			((CM_PopupOverlay)PopupWindow).ID = playerID;
			((Component)PopupWindow).transform.position = pos.position + new Vector3(200f, 0f, 0f);
			OpenSteamItem.ID = playerID;
			KickPlayerItem.ID = playerID;
			BanPlayerItem.ID = playerID;
			((RectTransformComp)PopupWindow).SetVisible(true);
		}

		private static void AddRecentlyPlayedWith(SNet_Player player, bool joined)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			LobbyManagementSettings.RecentlyPlayedWithEntry recentlyPlayedWithEntry = Settings.RecentlyPlayedWith.FirstOrDefault((LobbyManagementSettings.RecentlyPlayedWithEntry entry) => entry.SteamID == player.Lookup);
			if (recentlyPlayedWithEntry != null)
			{
				if (joined)
				{
					if (!player.IsBot)
					{
						SteamFriends.SetPlayedWith(new CSteamID(player.Lookup));
					}
					FeatureLogger.Notice($"{player.NickName} joined Session, last time played with them {DateTime.UtcNow - new DateTime(recentlyPlayedWithEntry.TimestampLast):d' day(s) and 'hh':'mm':'ss} ago.");
				}
				else
				{
					FeatureLogger.Debug(player.NickName + " left Session, saving Timestamp.");
				}
				recentlyPlayedWithEntry.TimestampLast = DateTime.UtcNow.Ticks;
				Feature.MarkSettingsAsDirty<LobbyManagementSettings>(Settings);
			}
			else
			{
				long ticks = DateTime.UtcNow.Ticks;
				Settings.RecentlyPlayedWith.Add(new LobbyManagementSettings.RecentlyPlayedWithEntry
				{
					Name = player.NickName,
					SteamID = player.Lookup,
					TimestampFirst = ticks,
					TimestampLast = ticks
				});
				Feature.MarkSettingsAsDirty<LobbyManagementSettings>(Settings);
			}
		}
	}
}
namespace TheArchive.Features.QoL
{
	public class IntroSkip : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class CM_PageIntro_Update_Patch
		{
			private static bool _injectPressed;

			private static MethodAccessor<CM_PageIntro> _onSkip;

			public static void Init()
			{
				_onSkip = MethodAccessor<CM_PageIntro>.GetAccessor("OnSkip", (Type[])null, false);
			}

			[IsPostfix]
			[RundownConstraint(/*Could not decode attribute arguments.*/)]
			public static void PostfixR4OrLater(CM_PageIntro __instance)
			{
				CheckAndSkipIfReady(__instance, __instance.m_startupLoaded, __instance.m_enemiesLoaded, __instance.m_sharedLoaded);
			}

			public static void CheckAndSkipIfReady(CM_PageIntro __instance, bool ___m_startupLoaded, bool ___m_enemiesLoaded, bool ___m_sharedLoaded)
			{
				if (___m_startupLoaded && ___m_enemiesLoaded && ___m_sharedLoaded && ItemSpawnManager.ReadyToSpawnItems && IsProgressionFileReady() && !_injectPressed)
				{
					FeatureLogger.Notice("Automatically pressing the Inject button ...");
					_onSkip.Invoke(__instance);
					__instance.EXT_PressInject(-1);
					_injectPressed = true;
				}
			}
		}

		public override string Name => "Skip Intro";

		public override GroupBase Group => (GroupBase)(object)GroupManager.QualityOfLife;

		public override string Description => "Automatically presses inject at the start of the game";

		public static IArchiveLogger FeatureLogger { get; set; }

		public static bool IsProgressionFileReady()
		{
			return RundownManager.RundownProgressionReady;
		}
	}
	public class L4DStylePacks : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class ResourcePackFirstPerson_UpdateInteraction_Patch
		{
			private static MethodAccessor<ResourcePackFirstPerson> A_UpdateInteractionActionName;

			private static IValueAccessor<Interact_Timed, PlayerAgent> A_m_interactionSourceAgent;

			private static IValueAccessor<Interact_Timed, float> A_m_interactionTimer;

			public static void Init()
			{
				A_UpdateInteractionActionName = MethodAccessor<ResourcePackFirstPerson>.GetAccessor("UpdateInteractionActionName", (Type[])null, false);
				if (!Is.R6OrLater)
				{
					A_m_interactionSourceAgent = AccessorBase.GetValueAccessor<Interact_Timed, PlayerAgent>("m_interactionSourceAgent", false);
					A_m_interactionTimer = AccessorBase.GetValueAccessor<Interact_Timed, float>("m_interactionTimer", false);
				}
			}

			public static bool Prefix(ResourcePackFirstPerson __instance)
			{
				//IL_000f: 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_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0127: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
				//IL_0173: Unknown result type (might be due to invalid IL or missing references)
				//IL_026c: Unknown result type (might be due to invalid IL or missing references)
				iResourcePackReceiver val = __instance.m_actionReceiver;
				iResourcePackReceiver lastActionReceiver = __instance.m_lastActionReceiver;
				eResourceContainerSpawnType packType = __instance.m_packType;
				Interact_ManualTimedWithCallback interactApplyResource = __instance.m_interactApplyResource;
				bool flag = false;
				bool flag2 = false;
				InputAction input = (InputAction)0;
				if (InputMapper.GetButtonDown.Invoke((InputAction)8, ((Item)__instance).Owner.InputFilter))
				{
					flag = true;
					if (!((Interact_Timed)interactApplyResource).TimerIsActive)
					{
						val = (__instance.m_actionReceiver = SharedUtils.CastTo<iResourcePackReceiver>((Il2CppObjectBase)(object)((Item)__instance).Owner));
					}
					input = (InputAction)8;
				}
				if (InputMapper.GetButton.Invoke((InputAction)7, ((Item)__instance).Owner.InputFilter))
				{
					flag2 = true;
					flag = true;
					RaycastHit val3 = default(RaycastHit);
					if (!((Interact_Timed)interactApplyResource).TimerIsActive && Physics.Raycast(((Item)__instance).Owner.FPSCamera.Position, ((Item)__instance).Owner.FPSCamera.Forward, ref val3, 2.4f, LayerManager.MASK_GIVE_RESOURCE_PACK))
					{
						iResourcePackReceiver componentInParent = ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<iResourcePackReceiver>();
						if (componentInParent != null)
						{
							val = (__instance.m_actionReceiver = componentInParent);
						}
					}
					input = ((!val.IsLocallyOwned) ? ((InputAction)7) : ((InputAction)8));
				}
				if (val == null || (!((Interact_Timed)interactApplyResource).TimerIsActive && !flag))
				{
					val = (__instance.m_actionReceiver = SharedUtils.CastTo<iResourcePackReceiver>((Il2CppObjectBase)(object)((Item)__instance).Owner));
					if (Is.R6OrLater)
					{
						OnInteractorStateChangedR6Plus(interactApplyResource, ((Item)__instance).Owner, state: false);
					}
					((Interact_Base)interactApplyResource).PlayerSetSelected(false, ((Item)__instance).Owner);
				}
				bool flag3 = NeedsResource(val, packType);
				if (!((Interact_Timed)interactApplyResource).TimerIsActive && val != lastActionReceiver)
				{
					if (val.IsLocallyOwned)
					{
						A_UpdateInteractionActionName.Invoke(__instance, new object[2]
						{
							Localization.GetById(7u, (string)null),
							true
						});
						interactApplyResource.m_input = input;
					}
					else
					{
						A_UpdateInteractionActionName.Invoke(__instance, new object[2] { val.InteractionName, false });
						interactApplyResource.m_input = input;
						if (flag3)
						{
							if (Is.R6OrLater)
							{
								OnInteractorStateChangedR6Plus(interactApplyResource, ((Item)__instance).Owner, state: true);
							}
							else
							{
								ActivateTimerR5AndBelow(interactApplyResource, ((Item)__instance).Owner);
							}
						}
					}
					__instance.m_lastActionReceiver = val;
				}
				bool timerIsActive = ((Interact_Timed)interactApplyResource).TimerIsActive;
				interactApplyResource.ManualUpdateWithCondition(flag3, ((Item)__instance).Owner, flag3 && !val.IsLocallyOwned);
				bool timerIsActive2 = ((Interact_Timed)interactApplyResource).TimerIsActive;
				if (!timerIsActive && timerIsActive2 && Is.R6OrLater)
				{
					SendGenericInteractR6Plus(__instance, val);
				}
				if (timerIsActive && !timerIsActive2)
				{
					PlayerAgent owner = ((Item)__instance).Owner;
					__instance.m_actionReceiver = ((owner != null) ? SharedUtils.CastTo<iResourcePackReceiver>((Il2CppObjectBase)(object)owner) : null);
				}
				if (!flag3 && flag && __instance.m_lastButtonDown != flag && (!flag2 || !val.IsLocallyOwned))
				{
					SharedUtils.SafePost(((ItemEquippable)__instance).Sound, EVENTS.BUTTONGENERICBLIPDENIED, true);
					ShowDoesNotNeedResourcePrompt(val, packType);
				}
				__instance.m_lastButtonDown = flag;
				return false;
			}

			private static void ActivateTimerR5AndBelow(Interact_ManualTimedWithCallback timer, PlayerAgent agent)
			{
				A_m_interactionSourceAgent.Set((Interact_Timed)(object)timer, agent);
				((Interact_Timed)timer).SetTimerActive(true);
				A_m_interactionTimer.Set((Interact_Timed)(object)timer, Clock.Delta);
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			private static void SendGenericInteractR6Plus(ResourcePackFirstPerson __instance, iResourcePackReceiver packReceiver)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				TypeEnum val = (TypeEnum)(packReceiver.IsLocallyOwned ? 6 : 5);
				((Item)__instance).Owner.Sync.SendGenericInteract(val, false);
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			private static void OnInteractorStateChangedR6Plus(Interact_ManualTimedWithCallback timer, PlayerAgent sourceAgent, bool state)
			{
				((Interact_Timed)timer).OnInteractorStateChanged(sourceAgent, state);
			}
		}

		private static MethodAccessor<InteractionGuiLayer> A_SetTimedMessage;

		public override string Name => "L4D Style Resource Packs";

		public override GroupBase Group => (GroupBase)(object)GroupManager.QualityOfLife;

		public override string Description => "Use left and right mouse buttons to apply resource packs instead of E.\n\nLeft mouse = yourself\nRight mouse = other players\n\n<color=orange>[R4+]</color> You're able to hold down M2 and it will start applying to a receiver under your croshair if in range automatically\n\n<#f00><u>/!\\</u> Make sure to <color=orange><u>disable</u></color> the vanilla game setting <color=orange>Gameplay > Separate Use Keybinds</color> for this Feature to work!</color>";

		public static ILocalizationService Localization { get; set; }

		public static IArchiveLogger FeatureLogger { get; set; }

		public override void Init()
		{
			if (!Is.R2OrLater)
			{
				A_SetTimedMessage = MethodAccessor<InteractionGuiLayer>.GetAccessor("SetTimedMessage", (Type[])null, false);
			}
		}

		public static bool NeedsResource(iResourcePackReceiver receiver, eResourceContainerSpawnType packType)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected I4, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (receiver == null)
			{
				return false;
			}
			switch ((int)packType)
			{
			default:
				if ((int)packType == 9)
				{
					if (Is.R2OrLater)
					{
						return NeedsDisinfect(receiver);
					}
					return false;
				}
				return false;
			case 0:
				return receiver.NeedHealth();
			case 1:
				return receiver.NeedWeaponAmmo();
			case 2:
				return receiver.NeedToolAmmo();
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool NeedsDisinfect(iResourcePackReceiver receiver)
		{
			return receiver.NeedDisinfection();
		}

		public static void ShowDoesNotNeedResourcePrompt(iResourcePackReceiver receiver, eResourceContainerSpawnType packType)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected I4, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			string text = (receiver.IsLocallyOwned ? Localization.GetById(1u, (string)null) : Localization.Format(2u, "{0} DOES", new object[1] { receiver.InteractionName }));
			switch ((int)packType)
			{
			default:
				if ((int)packType == 9)
				{
					text += Localization.GetById(6u, (string)null);
				}
				break;
			case 1:
				text += Localization.GetById(3u, (string)null);
				break;
			case 2:
				text += Localization.GetById(4u, (string)null);
				break;
			case 0:
				text += Localization.GetById(5u, (string)null);
				break;
			}
			SetTimedInteractionPrompt(text, 1.4f);
		}

		private static void SetTimedInteractionPrompt(string text, float time)
		{
			if (Is.R2OrLater)
			{
				TimedInteractionPromptR2Plus(text, time);
				return;
			}
			A_SetTimedMessage.Invoke(GuiManager.InteractionLayer, new object[3]
			{
				text,
				time,
				(object)(ePUIMessageStyle)1
			});
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void TimedInteractionPromptR2Plus(string text, float time)
		{
			GuiManager.InteractionLayer.SetTimedInteractionPrompt(text, time, (ePUIMessageStyle)0);
		}
	}
	public class LastUsedGearSwitcher : Feature
	{
		public class LastUsedGearSwitcherSettings
		{
			[FSDisplayName("Quick Swap Key")]
			[FSDescription("Press this key to switch to the previously wielded gear.")]
			public KeyCode QuickSwitchKey { get; set; } = (KeyCode)120;


			[FSHide]
			[FSDisplayName("Prints Debug Info")]
			[FSDescription("Prints debug info to the console")]
			public bool DebugLog { get; set; }
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class PlayerSync_WantsToWieldSlot_Patch
		{
			public static void Prefix(PlayerSync __instance, InventorySlot slot)
			{
				//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_00ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: 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_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
				IReplicator replicator = __instance.Replicator;
				bool? obj;
				if (replicator == null)
				{
					obj = null;
				}
				else
				{
					SNet_Player owningPlayer = replicator.OwningPlayer;
					obj = ((owningPlayer != null) ? new bool?(owningPlayer.IsLocal) : null);
				}
				bool? flag = obj;
				if (flag.GetValueOrDefault())
				{
					InventorySlot wieldedSlot = __instance.GetWieldedSlot();
					if (Settings.DebugLog)
					{
						FeatureLogger.Debug($"PlayerSync.WantsToWieldSlot: currentSlot:{wieldedSlot} -> slot:{slot} | _previousInventorySlot:{_previousInventorySlot}");
					}
					if (wieldedSlot != slot)
					{
						_previousInventorySlot = wieldedSlot;
					}
				}
			}
		}

		private static readonly eFocusState _eFocusState_FPS = Utils.GetEnumFromName<eFocusState>("FPS");

		private static eFocusState _eFocusState_FPS_CommunicationDialog;

		private static InventorySlot _previousInventorySlot = (InventorySlot)10;

		public override string Name => "Last Used Gear Switcher";

		public override GroupBase Group => (GroupBase)(object)GroupManager.QualityOfLife;

		public override string Description => "Allows you to swap between the last two used weapons via a keypress";

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static LastUsedGearSwitcherSettings Settings { get; set; }

		public override void Init()
		{
			if (Is.R6OrLater)
			{
				Utils.TryGetEnumFromName<eFocusState>("FPS_CommunicationDialog", ref _eFocusState_FPS_CommunicationDialog);
			}
		}

		public override void Update()
		{
			//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_0026: 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)
			if ((FocusStateManager.CurrentState == _eFocusState_FPS || (Is.R6OrLater && FocusStateManager.CurrentState == _eFocusState_FPS_CommunicationDialog)) && Input.GetKeyDown(Settings.QuickSwitchKey))
			{
				SwitchToPreviousSlot();
			}
		}

		public static void SwitchToPreviousSlot()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
			InventorySlot previousInventorySlot = _previousInventorySlot;
			InventorySlot wieldedSlot = localPlayerAgent.Inventory.WieldedSlot;
			if (Settings.DebugLog)
			{
				FeatureLogger.Debug($"Switching to previous slot: {wieldedSlot} -> {previousInventorySlot}");
			}
			localPlayerAgent.Sync.WantsToWieldSlot(previousInventorySlot, false);
		}
	}
	public class LoadoutRandomizer : Feature
	{
		public class LoadoutRandomizerSettings
		{
			[Localized]
			public enum InventorySlots
			{
				Primary,
				Special,
				Tool,
				Melee
			}

			[Localized]
			public enum RandomizerMode
			{
				True,
				NoDuplicate
			}

			[FSDisplayName("Do not randomize")]
			public List<InventorySlots> ExcludedSlots { get; set; } = new List<InventorySlots>();


			[FSDisplayName("Mode")]
			public RandomizerMode Mode { get; set; } = RandomizerMode.NoDuplicate;

		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		public static class CM_PageLoadout_SetupPatch
		{
			public static void Postfix(CM_PageLoadout __instance)
			{
				SetupViaInstance(__instance);
			}
		}

		private static CM_TimedButton _loadoutRandomizerButton;

		private static bool _hasBeenSetup = false;

		private static eGameStateName _eGameStateName_Lobby;

		private static readonly Dictionary<InventorySlot, LoadoutRandomizerSettings.InventorySlots> _invSlotMap = new Dictionary<InventorySlot, LoadoutRandomizerSettings.InventorySlots>
		{
			{
				Utils.GetEnumFromName<InventorySlot>("GearMelee"),
				LoadoutRandomizerSettings.InventorySlots.Melee
			},
			{
				Utils.GetEnumFromName<InventorySlot>("GearStandard"),
				LoadoutRandomizerSettings.InventorySlots.Primary
			},
			{
				Utils.GetEnumFromName<InventorySlot>("GearSpecial"),
				LoadoutRandomizerSettings.InventorySlots.Special
			},
			{
				Utils.GetEnumFromName<InventorySlot>("GearClass"),
				LoadoutRandomizerSettings.InventorySlots.Tool
			}
		};

		public override string Name => "Loadout Randomizer";

		public override GroupBase Group => (GroupBase)(object)GroupManager.QualityOfLife;

		public override string Description => "Adds a Loadout Randomizer button onto the loadout screen.\nSelect which gear to randomize via the settings below.";

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static LoadoutRandomizerSettings Config { get; set; }

		public static bool IsEnabled { get; set; }

		public override void Init()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			_eGameStateName_Lobby = Utils.GetEnumFromName<eGameStateName>("Lobby");
		}

		public override void OnEnable()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between I4 and Unknown
			if (!_hasBeenSetup)
			{
				SetupViaInstance(CM_PageLoadout.Current);
			}
			if ((byte)Feature.CurrentGameState == (int)_eGameStateName_Lobby)
			{
				SetButtonActive();
			}
		}

		public override void OnDisable()
		{
			CM_TimedButton loadoutRandomizerButton = _loadoutRandomizerButton;
			if (loadoutRandomizerButton != null)
			{
				GameObject gameObject = ((Component)loadoutRandomizerButton).gameObject;
				if (gameObject != null)
				{
					gameObject.SetActive(false);
				}
			}
		}

		public void OnGameStateChanged(eGameStateName state)
		{
			//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)
			if (state == _eGameStateName_Lobby)
			{
				SetButtonActive();
			}
			else
			{
				SetButtonInactive();
			}
		}

		public static void SetupViaInstance(CM_PageLoadout pageLoadout)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)pageLoadout == (Object)null))
			{
				CM_TimedButton readyButton = pageLoadout.m_readyButton;
				CM_Item changeLoadoutButton = null;
				GameBuildInfo buildInfo = Feature.BuildInfo;
				if (RundownFlagsExtensions.IsIncludedIn(((GameBuildInfo)(ref buildInfo)).Rundown, RundownFlagsExtensions.ToLatest((RundownFlags)32)))
				{
					GetChangeLoadoutButtonR6Plus(pageLoadout, out changeLoadoutButton);
				}
				SetupButton(readyButton, changeLoadoutButton);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		public static void GetChangeLoadoutButtonR6Plus(CM_PageLoadout pageLoadout, out CM_Item changeLoadoutButton)
		{
			changeLoadoutButton = pageLoadout.m_changeLoadoutButton;
		}

		private static void SetupButton(CM_TimedButton readyUpButton, CM_Item changeLoadoutButton = null)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (_hasBeenSetup)
			{
				return;
			}
			GameBuildInfo buildInfo = Feature.BuildInfo;
			if (RundownFlagsExtensions.IsIncludedIn(((GameBuildInfo)(ref buildInfo)).Rundown, RundownFlagsExtensions.ToLatest((RundownFlags)32)))
			{
				SharedUtils.AddCMItemEvents((CM_Item)(object)readyUpButton, (Action<int>)SetButtonInactive, (Action<int, bool>)null);
				if (changeLoadoutButton != null)
				{
					SharedUtils.AddCMItemEvents(changeLoadoutButton, (Action<int>)SetButtonActive, (Action<int, bool>)null);
				}
			}
			CreateButton(readyUpButton);
			_hasBeenSetup = true;
		}

		private static CM_TimedButton CreateButton(CM_TimedButton prefab)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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)
			_loadoutRandomizerButton = Object.Instantiate<GameObject>(((Component)prefab).gameObject, ((Component)prefab).transform.parent).GetComponent<CM_TimedButton>();
			SharedUtils.SetCMItemEvents((CM_Item)(object)_loadoutRandomizerButton, (Action<int>)OnRandomizeLoadoutButtonPressed, (Action<int, bool>)OnButtonHoverChanged);
			((Component)_loadoutRandomizerButton).gameObject.transform.Translate(new Vector3(-500f, 0f, 0f));
			BoxCollider2D component = ((Component)_loadoutRandomizerButton).GetComponent<BoxCollider2D>();
			if ((Object)(object)component != (Object)null)
			{
				((Collider2D)component).offset = new Vector2(0f, -40f);
			}
			((CM_Item)_loadoutRandomizerButton).SetText("Randomize Loadout");
			SharedUtils.ChangeColorTimedExpeditionButton(_loadoutRandomizerButton, new Color(1f, 1f, 1f, 0.5f));
			SetButtonActive();
			return _loadoutRandomizerButton;
		}

		private static void SetButtonActive(int _ = 0)
		{
			CM_TimedButton loadoutRandomizerButton = _loadoutRandomizerButton;
			if (loadoutRandomizerButton != null)
			{
				GameObject gameObject = ((Component)loadoutRandomizerButton).gameObject;
				if (gameObject != null)
				{
					gameObject.SetActive(IsEnabled);
				}
			}
		}

		public static void SetButtonInactive(int _ = 0)
		{
			CM_TimedButton loadoutRandomizerButton = _loadoutRandomizerButton;
			if (loadoutRandomizerButton != null)
			{
				GameObject gameObject = ((Component)loadoutRandomizerButton).gameObject;
				if (gameObject != null)
				{
					gameObject.SetActive(false);
				}
			}
		}

		public static void OnRandomizeLoadoutButtonPressed(int _)
		{
			//IL_007b: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			FeatureLogger.Notice("Randomizer Button has been pressed!");
			CM_PlayerLobbyBar val = null;
			val = ((IEnumerable<CM_PlayerLobbyBar>)((IEnumerable<CM_PlayerLobbyBar>)CM_PageLoadout.Current.m_playerLobbyBars).ToArray()).FirstOrDefault((Func<CM_PlayerLobbyBar, bool>)delegate(CM_PlayerLobbyBar plb)
			{
				SNet_Player player = plb.m_player;
				int? num = ((player != null) ? new int?(player.CharacterIndex) : null);
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				return num == ((localPlayerAgent != null) ? new int?(localPlayerAgent.CharacterID) : null);
			});
			if ((Object)(object)val == (Object)null)
			{
				FeatureLogger.Error("Couldn't find the local players CM_PlayerLobbyBar, aborting randomization of loadout!");
				return;
			}
			Enumerator<InventorySlot, CM_InventorySlotItem> enumerator = val.m_inventorySlotItems.GetEnumerator();
			BackpackItem val2 = default(BackpackItem);
			while (enumerator.MoveNext())
			{
				KeyValuePair<InventorySlot, CM_InventorySlotItem> current = enumerator.Current;
				InventorySlot key = current.Key;
				if (!_invSlotMap.TryGetValue(key, out var value) || !Config.ExcludedSlots.Contains(value))
				{
					GearIDRange[] array = Il2CppArrayBase<GearIDRange>.op_Implicit((Il2CppArrayBase<GearIDRange>)(object)GearManager.GetAllGearForSlot(key));
					PlayerBackpackManager.LocalBackpack.TryGetBackpackItem(key, ref val2);
					GearIDRange currentGearIdForSlot = val2.GearIDRange;
					LoadoutRandomizerSettings.RandomizerMode mode = Config.Mode;
					GearIDRange val3 = ((mode == LoadoutRandomizerSettings.RandomizerMode.True || mode != LoadoutRandomizerSettings.RandomizerMode.NoDuplicate) ? Utils.PickRandom<GearIDRange>(array) : Utils.PickRandomExcept<GearIDRange>(array, (Func<GearIDRange, bool>)((GearIDRange random) => !currentGearIdForSlot.GetChecksum().Equals(random.GetChecksum()))));
					if (val3 == null)
					{
						FeatureLogger.Error($"Tried to randomize Gear for slot {key} but received null!");
						continue;
					}
					FeatureLogger.Notice($"Picked random gear \"{val3.PublicGearName}\" for slot {key}!");
					PlayerBackpackManager.ResetLocalAmmoStorage(false);
					PlayerBackpackManager.EquipLocalGear(val3);
					GearManager.RegisterGearInSlotAsEquipped(val3.PlayfabItemInstanceId, key);
				}
			}
		}

		public static void OnButtonHoverChanged(int i, bool b)
		{
		}
	}
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	internal class NoDroppedMagazineSounds : Feature
	{
		public override string Name => "No Magazine Drop Sound";

		public override GroupBase Group => (GroupBase)(object)GroupManager.QualityOfLife;

		public override string Description => "Removes the <i>globally audible</i> sound whenever a magazine drops on the floor after a reload.";

		public override bool RequiresRestart => true;

		public override void OnGameDataInitialized()
		{
			if (!((Feature)this).Enabled)
			{
				return;
			}
			foreach (GearMagPartDataBlock allBlock in GameDataBlockBase<GearMagPartDataBlock>.GetAllBlocks())
			{
				allBlock.DropSoundType = (MagazineDropSoundType)0;
			}
		}
	}
	[EnableFeatureByDefault]
	public class NoNavMarkerHideInChat : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class GuiManager_OnFocusStateChanged_Patch
		{
			private static eFocusState _eFocusState_FPS_TypingInChat;

			public static void Init()
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				_eFocusState_FPS_TypingInChat = Utils.GetEnumFromName<eFocusState>("FPS_TypingInChat");
			}

			public static void Postfix(eFocusState state)
			{
				//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)
				if (state == _eFocusState_FPS_TypingInChat)
				{
					((GuiLayer)GuiManager.NavMarkerLayer).SetVisible(true);
				}
			}
		}

		public override string Name => "See NavMarkers in Chat";

		public override GroupBase Group => (GroupBase)(object)GroupManager.QualityOfLife;

		public override string Description => "Prevent enemy pings from hiding whenever the chat is open.";
	}
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class NoStoryDialog : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class WardenObjectiveManager_CheckAndExecuteEventsOnTrigger_Patch
		{
			[IsPrefix]
			[RundownConstraint(/*Could not decode attribute arguments.*/)]
			public static void PrefixR7(WardenObjectiveEventData eventToTrigger)
			{
				if (eventToTrigger.SoundSubtitle.HasValue)
				{
					FeatureLogger.Notice($"SoundEvent about to execute was: {eventToTrigger.SoundID} ({SoundEventCache.ReverseResolve(eventToTrigger.SoundID, false)})");
					eventToTrigger.SoundID = 0u;
				}
			}

			[IsPrefix]
			[RundownConstraint(/*Could not decode attribute arguments.*/)]
			public static void PrefixR6(WardenObjectiveEventData eventToTrigger)
			{
				if (eventToTrigger.SoundID != 0)
				{
					FeatureLogger.Notice($"SoundEvent about to execute was: {eventToTrigger.SoundID} ({SoundEventCache.ReverseResolve(eventToTrigger.SoundID, false)})");
					eventToTrigger.SoundID = 0u;
				}
			}
		}

		public override string Name => "Remove Story Dialog";

		public override GroupBase Group => (GroupBase)(object)GroupManager.QualityOfLife;

		public override string Description => "Removes all level-based voice events that come with subtitles.\naka Schaeffer-be-gone";

		public static IArchiveLogger FeatureLogger { get; set; }
	}
	public class ReloadSoundCue : Feature
	{
		public class ReloadSoundCueSettings
		{
			[FSDisplayName("Test Sound Event")]
			[FSDescription("Plays the sound event below,\nit's a little janky and might not work depending on the sound, sorry!")]
			public FButton TestSoundButton { get; set; } = new FButton("Play Sound", (string)null, (Action)null, false);


			[FSDisplayName

BepInEx/plugins/TheArchive.RichPresence/plugins/DiscordRPC.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using Clonesoft.Json;
using Clonesoft.Json.Linq;
using DiscordRPC.Converters;
using DiscordRPC.Events;
using DiscordRPC.Exceptions;
using DiscordRPC.Helper;
using DiscordRPC.IO;
using DiscordRPC.Logging;
using DiscordRPC.Message;
using DiscordRPC.RPC;
using DiscordRPC.RPC.Commands;
using DiscordRPC.RPC.Payload;
using DiscordRPC.Registry;
using Microsoft.Win32;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Discord RPC")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Discord RPC")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("819d20d6-8d88-45c1-a4d2-aa21f10abd19")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace DiscordRPC
{
	public class Configuration
	{
		[JsonProperty("api_endpoint")]
		public string ApiEndpoint { get; set; }

		[JsonProperty("cdn_host")]
		public string CdnHost { get; set; }

		[JsonProperty("environment")]
		public string Environment { get; set; }
	}
	public sealed class DiscordRpcClient : IDisposable
	{
		private ILogger _logger;

		private RpcConnection connection;

		private bool _shutdownOnly = true;

		private object _sync = new object();

		public bool HasRegisteredUriScheme { get; private set; }

		public string ApplicationID { get; private set; }

		public string SteamID { get; private set; }

		public int ProcessID { get; private set; }

		public int MaxQueueSize { get; private set; }

		public bool IsDisposed { get; private set; }

		public ILogger Logger
		{
			get
			{
				return _logger;
			}
			set
			{
				_logger = value;
				if (connection != null)
				{
					connection.Logger = value;
				}
			}
		}

		public bool AutoEvents { get; private set; }

		public bool SkipIdenticalPresence { get; set; }

		public int TargetPipe { get; private set; }

		public RichPresence CurrentPresence { get; private set; }

		public EventType Subscription { get; private set; }

		public User CurrentUser { get; private set; }

		public Configuration Configuration { get; private set; }

		public bool IsInitialized { get; private set; }

		public bool ShutdownOnly
		{
			get
			{
				return _shutdownOnly;
			}
			set
			{
				_shutdownOnly = value;
				if (connection != null)
				{
					connection.ShutdownOnly = value;
				}
			}
		}

		public event OnReadyEvent OnReady;

		public event OnCloseEvent OnClose;

		public event OnErrorEvent OnError;

		public event OnPresenceUpdateEvent OnPresenceUpdate;

		public event OnSubscribeEvent OnSubscribe;

		public event OnUnsubscribeEvent OnUnsubscribe;

		public event OnJoinEvent OnJoin;

		public event OnSpectateEvent OnSpectate;

		public event OnJoinRequestedEvent OnJoinRequested;

		public event OnConnectionEstablishedEvent OnConnectionEstablished;

		public event OnConnectionFailedEvent OnConnectionFailed;

		public event OnRpcMessageEvent OnRpcMessage;

		public DiscordRpcClient(string applicationID)
			: this(applicationID, -1, null, autoEvents: true, null)
		{
		}

		public DiscordRpcClient(string applicationID, int pipe = -1, ILogger logger = null, bool autoEvents = true, INamedPipeClient client = null)
		{
			if (string.IsNullOrEmpty(applicationID))
			{
				throw new ArgumentNullException("applicationID");
			}
			ApplicationID = applicationID.Trim();
			TargetPipe = pipe;
			ProcessID = Process.GetCurrentProcess().Id;
			HasRegisteredUriScheme = false;
			AutoEvents = autoEvents;
			SkipIdenticalPresence = true;
			_logger = logger ?? new NullLogger();
			connection = new RpcConnection(ApplicationID, ProcessID, TargetPipe, client ?? new ManagedNamedPipeClient(), (!autoEvents) ? 128u : 0u)
			{
				ShutdownOnly = _shutdownOnly,
				Logger = _logger
			};
			connection.OnRpcMessage += delegate(object sender, IMessage msg)
			{
				if (this.OnRpcMessage != null)
				{
					this.OnRpcMessage(this, msg);
				}
				if (AutoEvents)
				{
					ProcessMessage(msg);
				}
			};
		}

		public IMessage[] Invoke()
		{
			if (AutoEvents)
			{
				Logger.Error("Cannot Invoke client when AutomaticallyInvokeEvents has been set.");
				return new IMessage[0];
			}
			IMessage[] array = connection.DequeueMessages();
			foreach (IMessage message in array)
			{
				ProcessMessage(message);
			}
			return array;
		}

		private void ProcessMessage(IMessage message)
		{
			if (message == null)
			{
				return;
			}
			switch (message.Type)
			{
			case MessageType.PresenceUpdate:
				lock (_sync)
				{
					if (message is PresenceMessage presenceMessage)
					{
						if (presenceMessage.Presence == null)
						{
							CurrentPresence = null;
						}
						else if (CurrentPresence == null)
						{
							CurrentPresence = new RichPresence().Merge(presenceMessage.Presence);
						}
						else
						{
							CurrentPresence.Merge(presenceMessage.Presence);
						}
						presenceMessage.Presence = CurrentPresence;
					}
				}
				if (this.OnPresenceUpdate != null)
				{
					this.OnPresenceUpdate(this, message as PresenceMessage);
				}
				break;
			case MessageType.Ready:
				if (message is ReadyMessage readyMessage)
				{
					lock (_sync)
					{
						Configuration = readyMessage.Configuration;
						CurrentUser = readyMessage.User;
					}
					SynchronizeState();
				}
				if (this.OnReady != null)
				{
					this.OnReady(this, message as ReadyMessage);
				}
				break;
			case MessageType.Close:
				if (this.OnClose != null)
				{
					this.OnClose(this, message as CloseMessage);
				}
				break;
			case MessageType.Error:
				if (this.OnError != null)
				{
					this.OnError(this, message as ErrorMessage);
				}
				break;
			case MessageType.JoinRequest:
				if (Configuration != null && message is JoinRequestMessage joinRequestMessage)
				{
					joinRequestMessage.User.SetConfiguration(Configuration);
				}
				if (this.OnJoinRequested != null)
				{
					this.OnJoinRequested(this, message as JoinRequestMessage);
				}
				break;
			case MessageType.Subscribe:
				lock (_sync)
				{
					SubscribeMessage subscribeMessage = message as SubscribeMessage;
					Subscription |= subscribeMessage.Event;
				}
				if (this.OnSubscribe != null)
				{
					this.OnSubscribe(this, message as SubscribeMessage);
				}
				break;
			case MessageType.Unsubscribe:
				lock (_sync)
				{
					UnsubscribeMessage unsubscribeMessage = message as UnsubscribeMessage;
					Subscription &= ~unsubscribeMessage.Event;
				}
				if (this.OnUnsubscribe != null)
				{
					this.OnUnsubscribe(this, message as UnsubscribeMessage);
				}
				break;
			case MessageType.Join:
				if (this.OnJoin != null)
				{
					this.OnJoin(this, message as JoinMessage);
				}
				break;
			case MessageType.Spectate:
				if (this.OnSpectate != null)
				{
					this.OnSpectate(this, message as SpectateMessage);
				}
				break;
			case MessageType.ConnectionEstablished:
				if (this.OnConnectionEstablished != null)
				{
					this.OnConnectionEstablished(this, message as ConnectionEstablishedMessage);
				}
				break;
			case MessageType.ConnectionFailed:
				if (this.OnConnectionFailed != null)
				{
					this.OnConnectionFailed(this, message as ConnectionFailedMessage);
				}
				break;
			default:
				Logger.Error("Message was queued with no appropriate handle! {0}", message.Type);
				break;
			}
		}

		public void Respond(JoinRequestMessage request, bool acceptRequest)
		{
			if (IsDisposed)
			{
				throw new ObjectDisposedException("Discord IPC Client");
			}
			if (connection == null)
			{
				throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
			}
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			connection.EnqueueCommand(new RespondCommand
			{
				Accept = acceptRequest,
				UserID = request.User.ID.ToString()
			});
		}

		public void SetPresence(RichPresence presence)
		{
			if (IsDisposed)
			{
				throw new ObjectDisposedException("Discord IPC Client");
			}
			if (connection == null)
			{
				throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
			}
			if (!IsInitialized)
			{
				Logger.Warning("The client is not yet initialized, storing the presence as a state instead.");
			}
			if (presence == null)
			{
				if (!SkipIdenticalPresence || CurrentPresence != null)
				{
					connection.EnqueueCommand(new PresenceCommand
					{
						PID = ProcessID,
						Presence = null
					});
				}
			}
			else
			{
				if (presence.HasSecrets() && !HasRegisteredUriScheme)
				{
					throw new BadPresenceException("Cannot send a presence with secrets as this object has not registered a URI scheme. Please enable the uri scheme registration in the DiscordRpcClient constructor.");
				}
				if (presence.HasParty() && presence.Party.Max < presence.Party.Size)
				{
					throw new BadPresenceException("Presence maximum party size cannot be smaller than the current size.");
				}
				if (presence.HasSecrets() && !presence.HasParty())
				{
					Logger.Warning("The presence has set the secrets but no buttons will show as there is no party available.");
				}
				if (!SkipIdenticalPresence || !presence.Matches(CurrentPresence))
				{
					connection.EnqueueCommand(new PresenceCommand
					{
						PID = ProcessID,
						Presence = presence.Clone()
					});
				}
			}
			lock (_sync)
			{
				CurrentPresence = presence?.Clone();
			}
		}

		public RichPresence Update(Action<RichPresence> func)
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			RichPresence richPresence;
			lock (_sync)
			{
				richPresence = ((CurrentPresence == null) ? new RichPresence() : CurrentPresence.Clone());
			}
			func(richPresence);
			SetPresence(richPresence);
			return richPresence;
		}

		public RichPresence UpdateType(ActivityType type)
		{
			return Update(delegate(RichPresence p)
			{
				p.Type = type;
			});
		}

		public RichPresence UpdateButtons(Button[] buttons = null)
		{
			return Update(delegate(RichPresence p)
			{
				p.Buttons = buttons;
			});
		}

		public RichPresence SetButton(Button button, int index = 0)
		{
			return Update(delegate(RichPresence p)
			{
				p.Buttons[index] = button;
			});
		}

		public RichPresence UpdateDetails(string details)
		{
			return Update(delegate(RichPresence p)
			{
				p.Details = details;
			});
		}

		public RichPresence UpdateState(string state)
		{
			return Update(delegate(RichPresence p)
			{
				p.State = state;
			});
		}

		public RichPresence UpdateParty(Party party)
		{
			return Update(delegate(RichPresence p)
			{
				p.Party = party;
			});
		}

		public RichPresence UpdatePartySize(int size)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Party == null)
				{
					throw new BadPresenceException("Cannot set the size of the party if the party does not exist");
				}
				p.Party.Size = size;
			});
		}

		public RichPresence UpdatePartySize(int size, int max)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Party == null)
				{
					throw new BadPresenceException("Cannot set the size of the party if the party does not exist");
				}
				p.Party.Size = size;
				p.Party.Max = max;
			});
		}

		public RichPresence UpdateLargeAsset(string key = null, string tooltip = null)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Assets == null)
				{
					p.Assets = new Assets();
				}
				p.Assets.LargeImageKey = key ?? p.Assets.LargeImageKey;
				p.Assets.LargeImageText = tooltip ?? p.Assets.LargeImageText;
			});
		}

		public RichPresence UpdateSmallAsset(string key = null, string tooltip = null)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Assets == null)
				{
					p.Assets = new Assets();
				}
				p.Assets.SmallImageKey = key ?? p.Assets.SmallImageKey;
				p.Assets.SmallImageText = tooltip ?? p.Assets.SmallImageText;
			});
		}

		public RichPresence UpdateSecrets(Secrets secrets)
		{
			return Update(delegate(RichPresence p)
			{
				p.Secrets = secrets;
			});
		}

		public RichPresence UpdateStartTime()
		{
			return UpdateStartTime(DateTime.UtcNow);
		}

		public RichPresence UpdateStartTime(DateTime time)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Timestamps == null)
				{
					p.Timestamps = new Timestamps();
				}
				p.Timestamps.Start = time;
			});
		}

		public RichPresence UpdateEndTime()
		{
			return UpdateEndTime(DateTime.UtcNow);
		}

		public RichPresence UpdateEndTime(DateTime time)
		{
			return Update(delegate(RichPresence p)
			{
				if (p.Timestamps == null)
				{
					p.Timestamps = new Timestamps();
				}
				p.Timestamps.End = time;
			});
		}

		public RichPresence UpdateClearTime()
		{
			return Update(delegate(RichPresence p)
			{
				p.Timestamps = null;
			});
		}

		public void ClearPresence()
		{
			if (IsDisposed)
			{
				throw new ObjectDisposedException("Discord IPC Client");
			}
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			if (connection == null)
			{
				throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
			}
			SetPresence(null);
		}

		public bool RegisterUriScheme(string steamAppID = null, string executable = null)
		{
			UriSchemeRegister uriSchemeRegister = new UriSchemeRegister(_logger, ApplicationID, steamAppID, executable);
			return HasRegisteredUriScheme = uriSchemeRegister.RegisterUriScheme();
		}

		public void Subscribe(EventType type)
		{
			SetSubscription(Subscription | type);
		}

		[Obsolete("Replaced with Unsubscribe", true)]
		public void Unubscribe(EventType type)
		{
			SetSubscription(Subscription & ~type);
		}

		public void Unsubscribe(EventType type)
		{
			SetSubscription(Subscription & ~type);
		}

		public void SetSubscription(EventType type)
		{
			if (IsInitialized)
			{
				SubscribeToTypes(Subscription & ~type, isUnsubscribe: true);
				SubscribeToTypes(~Subscription & type, isUnsubscribe: false);
			}
			else
			{
				Logger.Warning("Client has not yet initialized, but events are being subscribed too. Storing them as state instead.");
			}
			lock (_sync)
			{
				Subscription = type;
			}
		}

		private void SubscribeToTypes(EventType type, bool isUnsubscribe)
		{
			if (type != 0)
			{
				if (IsDisposed)
				{
					throw new ObjectDisposedException("Discord IPC Client");
				}
				if (!IsInitialized)
				{
					throw new UninitializedException();
				}
				if (connection == null)
				{
					throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
				}
				if (!HasRegisteredUriScheme)
				{
					throw new InvalidConfigurationException("Cannot subscribe/unsubscribe to an event as this application has not registered a URI Scheme. Call RegisterUriScheme().");
				}
				if ((type & EventType.Spectate) == EventType.Spectate)
				{
					connection.EnqueueCommand(new SubscribeCommand
					{
						Event = ServerEvent.ActivitySpectate,
						IsUnsubscribe = isUnsubscribe
					});
				}
				if ((type & EventType.Join) == EventType.Join)
				{
					connection.EnqueueCommand(new SubscribeCommand
					{
						Event = ServerEvent.ActivityJoin,
						IsUnsubscribe = isUnsubscribe
					});
				}
				if ((type & EventType.JoinRequest) == EventType.JoinRequest)
				{
					connection.EnqueueCommand(new SubscribeCommand
					{
						Event = ServerEvent.ActivityJoinRequest,
						IsUnsubscribe = isUnsubscribe
					});
				}
			}
		}

		public void SynchronizeState()
		{
			if (!IsInitialized)
			{
				throw new UninitializedException();
			}
			SetPresence(CurrentPresence);
			if (HasRegisteredUriScheme)
			{
				SubscribeToTypes(Subscription, isUnsubscribe: false);
			}
		}

		public bool Initialize()
		{
			if (IsDisposed)
			{
				throw new ObjectDisposedException("Discord IPC Client");
			}
			if (IsInitialized)
			{
				throw new UninitializedException("Cannot initialize a client that is already initialized");
			}
			if (connection == null)
			{
				throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
			}
			return IsInitialized = connection.AttemptConnection();
		}

		public void Deinitialize()
		{
			if (!IsInitialized)
			{
				throw new UninitializedException("Cannot deinitialize a client that has not been initalized.");
			}
			connection.Close();
			IsInitialized = false;
		}

		public void Dispose()
		{
			if (!IsDisposed)
			{
				if (IsInitialized)
				{
					Deinitialize();
				}
				IsDisposed = true;
			}
		}
	}
	[Flags]
	public enum EventType
	{
		None = 0,
		Spectate = 1,
		Join = 2,
		JoinRequest = 4
	}
	[Serializable]
	[JsonObject(/*Could not decode attribute arguments.*/)]
	public class BaseRichPresence
	{
		protected internal string _state;

		protected internal string _details;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string State
		{
			get
			{
				return _state;
			}
			set
			{
				if (!ValidateString(value, out _state, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException("State", 0, 128);
				}
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string Details
		{
			get
			{
				return _details;
			}
			set
			{
				if (!ValidateString(value, out _details, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Timestamps Timestamps { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Assets Assets { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Party Party { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Secrets Secrets { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public ActivityType Type { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		[Obsolete("This was going to be used, but was replaced by JoinSecret instead")]
		private bool Instance { get; set; }

		public bool HasTimestamps()
		{
			return Timestamps != null && (Timestamps.Start.HasValue || Timestamps.End.HasValue);
		}

		public bool HasAssets()
		{
			return Assets != null;
		}

		public bool HasParty()
		{
			return Party != null && Party.ID != null;
		}

		public bool HasSecrets()
		{
			return Secrets != null && (Secrets.JoinSecret != null || Secrets.SpectateSecret != null);
		}

		internal static bool ValidateString(string str, out string result, int bytes, Encoding encoding)
		{
			result = str;
			if (str == null)
			{
				return true;
			}
			string str2 = str.Trim();
			if (!str2.WithinLength(bytes, encoding))
			{
				return false;
			}
			result = str2.GetNullOrString();
			return true;
		}

		public static implicit operator bool(BaseRichPresence presesnce)
		{
			return presesnce != null;
		}

		internal virtual bool Matches(RichPresence other)
		{
			if (other == null)
			{
				return false;
			}
			if (State != other.State || Details != other.Details || Type != other.Type)
			{
				return false;
			}
			if (Timestamps != null)
			{
				if (other.Timestamps == null || other.Timestamps.StartUnixMilliseconds != Timestamps.StartUnixMilliseconds || other.Timestamps.EndUnixMilliseconds != Timestamps.EndUnixMilliseconds)
				{
					return false;
				}
			}
			else if (other.Timestamps != null)
			{
				return false;
			}
			if (Secrets != null)
			{
				if (other.Secrets == null || other.Secrets.JoinSecret != Secrets.JoinSecret || other.Secrets.MatchSecret != Secrets.MatchSecret || other.Secrets.SpectateSecret != Secrets.SpectateSecret)
				{
					return false;
				}
			}
			else if (other.Secrets != null)
			{
				return false;
			}
			if (Party != null)
			{
				if (other.Party == null || other.Party.ID != Party.ID || other.Party.Max != Party.Max || other.Party.Size != Party.Size || other.Party.Privacy != Party.Privacy)
				{
					return false;
				}
			}
			else if (other.Party != null)
			{
				return false;
			}
			if (Assets != null)
			{
				if (other.Assets == null || other.Assets.LargeImageKey != Assets.LargeImageKey || other.Assets.LargeImageText != Assets.LargeImageText || other.Assets.SmallImageKey != Assets.SmallImageKey || other.Assets.SmallImageText != Assets.SmallImageText)
				{
					return false;
				}
			}
			else if (other.Assets != null)
			{
				return false;
			}
			return Instance == other.Instance;
		}

		public RichPresence ToRichPresence()
		{
			RichPresence richPresence = new RichPresence();
			richPresence.State = State;
			richPresence.Details = Details;
			richPresence.Type = Type;
			richPresence.Party = ((!HasParty()) ? Party : null);
			richPresence.Secrets = ((!HasSecrets()) ? Secrets : null);
			if (HasAssets())
			{
				richPresence.Assets = new Assets
				{
					SmallImageKey = Assets.SmallImageKey,
					SmallImageText = Assets.SmallImageText,
					LargeImageKey = Assets.LargeImageKey,
					LargeImageText = Assets.LargeImageText
				};
			}
			if (HasTimestamps())
			{
				richPresence.Timestamps = new Timestamps();
				if (Timestamps.Start.HasValue)
				{
					richPresence.Timestamps.Start = Timestamps.Start;
				}
				if (Timestamps.End.HasValue)
				{
					richPresence.Timestamps.End = Timestamps.End;
				}
			}
			return richPresence;
		}
	}
	[Serializable]
	public class Secrets
	{
		private string _matchSecret;

		private string _joinSecret;

		private string _spectateSecret;

		[Obsolete("This feature has been deprecated my Mason in issue #152 on the offical library. Was originally used as a Notify Me feature, it has been replaced with Join / Spectate.")]
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string MatchSecret
		{
			get
			{
				return _matchSecret;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _matchSecret, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string JoinSecret
		{
			get
			{
				return _joinSecret;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _joinSecret, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string SpectateSecret
		{
			get
			{
				return _spectateSecret;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _spectateSecret, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		public static Encoding Encoding => Encoding.UTF8;

		public static int SecretLength => 128;

		public static string CreateSecret(Random random)
		{
			byte[] array = new byte[SecretLength];
			random.NextBytes(array);
			return Encoding.GetString(array);
		}

		public static string CreateFriendlySecret(Random random)
		{
			string text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < SecretLength; i++)
			{
				stringBuilder.Append(text[random.Next(text.Length)]);
			}
			return stringBuilder.ToString();
		}
	}
	[Serializable]
	public class Assets
	{
		private string _largeimagekey;

		private bool _islargeimagekeyexternal;

		private string _largeimagetext;

		private string _smallimagekey;

		private bool _issmallimagekeyexternal;

		private string _smallimagetext;

		private ulong? _largeimageID;

		private ulong? _smallimageID;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string LargeImageKey
		{
			get
			{
				return _largeimagekey;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _largeimagekey, 256, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(256);
				}
				_islargeimagekeyexternal = _largeimagekey?.StartsWith("mp:external/") ?? false;
				_largeimageID = null;
			}
		}

		[JsonIgnore]
		public bool IsLargeImageKeyExternal => _islargeimagekeyexternal;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string LargeImageText
		{
			get
			{
				return _largeimagetext;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _largeimagetext, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string SmallImageKey
		{
			get
			{
				return _smallimagekey;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _smallimagekey, 256, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(256);
				}
				_issmallimagekeyexternal = _smallimagekey?.StartsWith("mp:external/") ?? false;
				_smallimageID = null;
			}
		}

		[JsonIgnore]
		public bool IsSmallImageKeyExternal => _issmallimagekeyexternal;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string SmallImageText
		{
			get
			{
				return _smallimagetext;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _smallimagetext, 128, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(128);
				}
			}
		}

		[JsonIgnore]
		public ulong? LargeImageID => _largeimageID;

		[JsonIgnore]
		public ulong? SmallImageID => _smallimageID;

		internal void Merge(Assets other)
		{
			_smallimagetext = other._smallimagetext;
			_largeimagetext = other._largeimagetext;
			if (ulong.TryParse(other._largeimagekey, out var result))
			{
				_largeimageID = result;
			}
			else
			{
				_largeimagekey = other._largeimagekey;
				_largeimageID = null;
			}
			if (ulong.TryParse(other._smallimagekey, out var result2))
			{
				_smallimageID = result2;
				return;
			}
			_smallimagekey = other._smallimagekey;
			_smallimageID = null;
		}
	}
	[Serializable]
	public class Timestamps
	{
		public static Timestamps Now => new Timestamps(DateTime.UtcNow);

		[JsonIgnore]
		public DateTime? Start { get; set; }

		[JsonIgnore]
		public DateTime? End { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public ulong? StartUnixMilliseconds
		{
			get
			{
				return Start.HasValue ? new ulong?(ToUnixMilliseconds(Start.Value)) : null;
			}
			set
			{
				Start = (value.HasValue ? new DateTime?(FromUnixMilliseconds(value.Value)) : null);
			}
		}

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public ulong? EndUnixMilliseconds
		{
			get
			{
				return End.HasValue ? new ulong?(ToUnixMilliseconds(End.Value)) : null;
			}
			set
			{
				End = (value.HasValue ? new DateTime?(FromUnixMilliseconds(value.Value)) : null);
			}
		}

		public static Timestamps FromTimeSpan(double seconds)
		{
			return FromTimeSpan(TimeSpan.FromSeconds(seconds));
		}

		public static Timestamps FromTimeSpan(TimeSpan timespan)
		{
			return new Timestamps
			{
				Start = DateTime.UtcNow,
				End = DateTime.UtcNow + timespan
			};
		}

		public Timestamps()
		{
			Start = null;
			End = null;
		}

		public Timestamps(DateTime start)
		{
			Start = start;
			End = null;
		}

		public Timestamps(DateTime start, DateTime end)
		{
			Start = start;
			End = end;
		}

		public static DateTime FromUnixMilliseconds(ulong unixTime)
		{
			return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(Convert.ToDouble(unixTime));
		}

		public static ulong ToUnixMilliseconds(DateTime date)
		{
			DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
			return Convert.ToUInt64((date - dateTime).TotalMilliseconds);
		}
	}
	[Serializable]
	public class Party
	{
		public enum PrivacySetting
		{
			Private,
			Public
		}

		private string _partyid;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string ID
		{
			get
			{
				return _partyid;
			}
			set
			{
				_partyid = value.GetNullOrString();
			}
		}

		[JsonIgnore]
		public int Size { get; set; }

		[JsonIgnore]
		public int Max { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public PrivacySetting Privacy { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		private int[] _size
		{
			get
			{
				int num = Math.Max(1, Size);
				return new int[2]
				{
					num,
					Math.Max(num, Max)
				};
			}
			set
			{
				if (value.Length != 2)
				{
					Size = 0;
					Max = 0;
				}
				else
				{
					Size = value[0];
					Max = value[1];
				}
			}
		}
	}
	public class Button
	{
		private string _label;

		private string _url;

		[JsonProperty("label")]
		public string Label
		{
			get
			{
				return _label;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _label, 32, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(32);
				}
			}
		}

		[JsonProperty("url")]
		public string Url
		{
			get
			{
				return _url;
			}
			set
			{
				if (!BaseRichPresence.ValidateString(value, out _url, 512, Encoding.UTF8))
				{
					throw new StringOutOfRangeException(512);
				}
				if (!Uri.TryCreate(_url, UriKind.Absolute, out Uri _))
				{
					throw new ArgumentException("Url must be a valid URI");
				}
			}
		}
	}
	public enum ActivityType
	{
		Playing = 0,
		Listening = 2,
		Watching = 3,
		Competing = 5
	}
	public sealed class RichPresence : BaseRichPresence
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Button[] Buttons { get; set; }

		public bool HasButtons()
		{
			return Buttons != null && Buttons.Length != 0;
		}

		public RichPresence WithState(string state)
		{
			base.State = state;
			return this;
		}

		public RichPresence WithDetails(string details)
		{
			base.Details = details;
			return this;
		}

		public RichPresence WithType(ActivityType type)
		{
			base.Type = type;
			return this;
		}

		public RichPresence WithTimestamps(Timestamps timestamps)
		{
			base.Timestamps = timestamps;
			return this;
		}

		public RichPresence WithAssets(Assets assets)
		{
			base.Assets = assets;
			return this;
		}

		public RichPresence WithParty(Party party)
		{
			base.Party = party;
			return this;
		}

		public RichPresence WithSecrets(Secrets secrets)
		{
			base.Secrets = secrets;
			return this;
		}

		public RichPresence Clone()
		{
			RichPresence richPresence = new RichPresence();
			richPresence.State = ((_state != null) ? (_state.Clone() as string) : null);
			richPresence.Details = ((_details != null) ? (_details.Clone() as string) : null);
			richPresence.Type = base.Type;
			richPresence.Buttons = ((!HasButtons()) ? null : (Buttons.Clone() as Button[]));
			richPresence.Secrets = ((!HasSecrets()) ? null : new Secrets
			{
				JoinSecret = ((base.Secrets.JoinSecret != null) ? (base.Secrets.JoinSecret.Clone() as string) : null),
				SpectateSecret = ((base.Secrets.SpectateSecret != null) ? (base.Secrets.SpectateSecret.Clone() as string) : null)
			});
			richPresence.Timestamps = ((!HasTimestamps()) ? null : new Timestamps
			{
				Start = base.Timestamps.Start,
				End = base.Timestamps.End
			});
			richPresence.Assets = ((!HasAssets()) ? null : new Assets
			{
				LargeImageKey = ((base.Assets.LargeImageKey != null) ? (base.Assets.LargeImageKey.Clone() as string) : null),
				LargeImageText = ((base.Assets.LargeImageText != null) ? (base.Assets.LargeImageText.Clone() as string) : null),
				SmallImageKey = ((base.Assets.SmallImageKey != null) ? (base.Assets.SmallImageKey.Clone() as string) : null),
				SmallImageText = ((base.Assets.SmallImageText != null) ? (base.Assets.SmallImageText.Clone() as string) : null)
			});
			richPresence.Party = ((!HasParty()) ? null : new Party
			{
				ID = base.Party.ID,
				Size = base.Party.Size,
				Max = base.Party.Max,
				Privacy = base.Party.Privacy
			});
			return richPresence;
		}

		internal RichPresence Merge(BaseRichPresence presence)
		{
			_state = presence.State;
			_details = presence.Details;
			base.Type = presence.Type;
			base.Party = presence.Party;
			base.Timestamps = presence.Timestamps;
			base.Secrets = presence.Secrets;
			if (presence.HasAssets())
			{
				if (!HasAssets())
				{
					base.Assets = presence.Assets;
				}
				else
				{
					base.Assets.Merge(presence.Assets);
				}
			}
			else
			{
				base.Assets = null;
			}
			return this;
		}

		internal override bool Matches(RichPresence other)
		{
			if (!base.Matches(other))
			{
				return false;
			}
			if ((Buttons == null) ^ (other.Buttons == null))
			{
				return false;
			}
			if (Buttons != null)
			{
				if (Buttons.Length != other.Buttons.Length)
				{
					return false;
				}
				for (int i = 0; i < Buttons.Length; i++)
				{
					Button button = Buttons[i];
					Button button2 = other.Buttons[i];
					if (button.Label != button2.Label || button.Url != button2.Url)
					{
						return false;
					}
				}
			}
			return true;
		}

		public static implicit operator bool(RichPresence presesnce)
		{
			return presesnce != null;
		}
	}
	internal sealed class RichPresenceResponse : BaseRichPresence
	{
		[JsonProperty("application_id")]
		public string ClientID { get; private set; }

		[JsonProperty("name")]
		public string Name { get; private set; }
	}
	public class User
	{
		public enum AvatarFormat
		{
			PNG,
			JPEG,
			WebP,
			GIF
		}

		public enum AvatarSize
		{
			x16 = 0x10,
			x32 = 0x20,
			x64 = 0x40,
			x128 = 0x80,
			x256 = 0x100,
			x512 = 0x200,
			x1024 = 0x400,
			x2048 = 0x800
		}

		[Flags]
		public enum Flag
		{
			None = 0,
			Employee = 1,
			Partner = 2,
			HypeSquad = 4,
			BugHunter = 8,
			HouseBravery = 0x40,
			HouseBrilliance = 0x80,
			HouseBalance = 0x100,
			EarlySupporter = 0x200,
			TeamUser = 0x400
		}

		public enum PremiumType
		{
			None,
			NitroClassic,
			Nitro
		}

		[JsonProperty("id")]
		public ulong ID { get; private set; }

		[JsonProperty("username")]
		public string Username { get; private set; }

		[JsonProperty("discriminator")]
		[Obsolete("Discord no longer uses discriminators.")]
		public int Discriminator { get; private set; }

		[JsonProperty("global_name")]
		public string DisplayName { get; private set; }

		[JsonProperty("avatar")]
		public string Avatar { get; private set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public Flag Flags { get; private set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public PremiumType Premium { get; private set; }

		public string CdnEndpoint { get; private set; }

		internal User()
		{
			CdnEndpoint = "cdn.discordapp.com";
		}

		internal void SetConfiguration(Configuration configuration)
		{
			CdnEndpoint = configuration.CdnHost;
		}

		public string GetAvatarURL(AvatarFormat format)
		{
			return GetAvatarURL(format, AvatarSize.x128);
		}

		public string GetAvatarURL(AvatarFormat format, AvatarSize size)
		{
			string text = $"/avatars/{ID}/{Avatar}";
			if (string.IsNullOrEmpty(Avatar))
			{
				if (format != 0)
				{
					throw new BadImageFormatException("The user has no avatar and the requested format " + format.ToString() + " is not supported. (Only supports PNG).");
				}
				int value = (int)((ID >> 22) % 6);
				if (Discriminator > 0)
				{
					value = Discriminator % 5;
				}
				text = $"/embed/avatars/{value}";
			}
			return $"https://{CdnEndpoint}{text}{GetAvatarExtension(format)}?size={(int)size}";
		}

		public string GetAvatarExtension(AvatarFormat format)
		{
			return "." + format.ToString().ToLowerInvariant();
		}

		public override string ToString()
		{
			if (!string.IsNullOrEmpty(DisplayName))
			{
				return DisplayName;
			}
			if (Discriminator != 0)
			{
				return Username + "#" + Discriminator.ToString("D4");
			}
			return Username;
		}
	}
}
namespace DiscordRPC.RPC
{
	internal class RpcConnection : IDisposable
	{
		public static readonly int VERSION = 1;

		public static readonly int POLL_RATE = 1000;

		private static readonly bool CLEAR_ON_SHUTDOWN = true;

		private static readonly bool LOCK_STEP = false;

		private ILogger _logger;

		private RpcState _state;

		private readonly object l_states = new object();

		private Configuration _configuration = null;

		private readonly object l_config = new object();

		private volatile bool aborting = false;

		private volatile bool shutdown = false;

		private string applicationID;

		private int processID;

		private long nonce;

		private Thread thread;

		private INamedPipeClient namedPipe;

		private int targetPipe;

		private readonly object l_rtqueue = new object();

		private readonly uint _maxRtQueueSize;

		private Queue<ICommand> _rtqueue;

		private readonly object l_rxqueue = new object();

		private readonly uint _maxRxQueueSize;

		private Queue<IMessage> _rxqueue;

		private AutoResetEvent queueUpdatedEvent = new AutoResetEvent(initialState: false);

		private BackoffDelay delay;

		public ILogger Logger
		{
			get
			{
				return _logger;
			}
			set
			{
				_logger = value;
				if (namedPipe != null)
				{
					namedPipe.Logger = value;
				}
			}
		}

		public RpcState State
		{
			get
			{
				lock (l_states)
				{
					return _state;
				}
			}
		}

		public Configuration Configuration
		{
			get
			{
				Configuration result = null;
				lock (l_config)
				{
					result = _configuration;
				}
				return result;
			}
		}

		public bool IsRunning => thread != null;

		public bool ShutdownOnly { get; set; }

		public event OnRpcMessageEvent OnRpcMessage;

		public RpcConnection(string applicationID, int processID, int targetPipe, INamedPipeClient client, uint maxRxQueueSize = 128u, uint maxRtQueueSize = 512u)
		{
			this.applicationID = applicationID;
			this.processID = processID;
			this.targetPipe = targetPipe;
			namedPipe = client;
			ShutdownOnly = true;
			Logger = new ConsoleLogger();
			delay = new BackoffDelay(500, 60000);
			_maxRtQueueSize = maxRtQueueSize;
			_rtqueue = new Queue<ICommand>((int)(_maxRtQueueSize + 1));
			_maxRxQueueSize = maxRxQueueSize;
			_rxqueue = new Queue<IMessage>((int)(_maxRxQueueSize + 1));
			nonce = 0L;
		}

		private long GetNextNonce()
		{
			nonce++;
			return nonce;
		}

		internal void EnqueueCommand(ICommand command)
		{
			Logger.Trace("Enqueue Command: {0}", command.GetType().FullName);
			if (aborting || shutdown)
			{
				return;
			}
			lock (l_rtqueue)
			{
				if (_rtqueue.Count == _maxRtQueueSize)
				{
					Logger.Error("Too many enqueued commands, dropping oldest one. Maybe you are pushing new presences to fast?");
					_rtqueue.Dequeue();
				}
				_rtqueue.Enqueue(command);
			}
		}

		private void EnqueueMessage(IMessage message)
		{
			try
			{
				if (this.OnRpcMessage != null)
				{
					this.OnRpcMessage(this, message);
				}
			}
			catch (Exception ex)
			{
				Logger.Error("Unhandled Exception while processing event: {0}", ex.GetType().FullName);
				Logger.Error(ex.Message);
				Logger.Error(ex.StackTrace);
			}
			if (_maxRxQueueSize == 0)
			{
				Logger.Trace("Enqueued Message, but queue size is 0.");
				return;
			}
			Logger.Trace("Enqueue Message: {0}", message.Type);
			lock (l_rxqueue)
			{
				if (_rxqueue.Count == _maxRxQueueSize)
				{
					Logger.Warning("Too many enqueued messages, dropping oldest one.");
					_rxqueue.Dequeue();
				}
				_rxqueue.Enqueue(message);
			}
		}

		internal IMessage DequeueMessage()
		{
			lock (l_rxqueue)
			{
				if (_rxqueue.Count == 0)
				{
					return null;
				}
				return _rxqueue.Dequeue();
			}
		}

		internal IMessage[] DequeueMessages()
		{
			lock (l_rxqueue)
			{
				IMessage[] result = _rxqueue.ToArray();
				_rxqueue.Clear();
				return result;
			}
		}

		private void MainLoop()
		{
			Logger.Info("RPC Connection Started");
			if (Logger.Level <= LogLevel.Trace)
			{
				Logger.Trace("============================");
				Logger.Trace("Assembly:             " + Assembly.GetAssembly(typeof(RichPresence)).FullName);
				Logger.Trace("Pipe:                 " + namedPipe.GetType().FullName);
				Logger.Trace("Platform:             " + Environment.OSVersion.ToString());
				Logger.Trace("applicationID:        " + applicationID);
				Logger.Trace("targetPipe:           " + targetPipe);
				Logger.Trace("POLL_RATE:            " + POLL_RATE);
				Logger.Trace("_maxRtQueueSize:      " + _maxRtQueueSize);
				Logger.Trace("_maxRxQueueSize:      " + _maxRxQueueSize);
				Logger.Trace("============================");
			}
			while (!aborting && !shutdown)
			{
				try
				{
					if (namedPipe == null)
					{
						Logger.Error("Something bad has happened with our pipe client!");
						aborting = true;
						return;
					}
					Logger.Trace("Connecting to the pipe through the {0}", namedPipe.GetType().FullName);
					if (namedPipe.Connect(targetPipe))
					{
						Logger.Trace("Connected to the pipe. Attempting to establish handshake...");
						EnqueueMessage(new ConnectionEstablishedMessage
						{
							ConnectedPipe = namedPipe.ConnectedPipe
						});
						EstablishHandshake();
						Logger.Trace("Connection Established. Starting reading loop...");
						bool flag = true;
						while (flag && !aborting && !shutdown && namedPipe.IsConnected)
						{
							if (namedPipe.ReadFrame(out var frame))
							{
								Logger.Trace("Read Payload: {0}", frame.Opcode);
								switch (frame.Opcode)
								{
								case Opcode.Close:
								{
									ClosePayload @object = frame.GetObject<ClosePayload>();
									Logger.Warning("We have been told to terminate by discord: ({0}) {1}", @object.Code, @object.Reason);
									EnqueueMessage(new CloseMessage
									{
										Code = @object.Code,
										Reason = @object.Reason
									});
									flag = false;
									break;
								}
								case Opcode.Ping:
									Logger.Trace("PING");
									frame.Opcode = Opcode.Pong;
									namedPipe.WriteFrame(frame);
									break;
								case Opcode.Pong:
									Logger.Trace("PONG");
									break;
								case Opcode.Frame:
								{
									if (shutdown)
									{
										Logger.Warning("Skipping frame because we are shutting down.");
										break;
									}
									if (frame.Data == null)
									{
										Logger.Error("We received no data from the frame so we cannot get the event payload!");
										break;
									}
									EventPayload eventPayload = null;
									try
									{
										eventPayload = frame.GetObject<EventPayload>();
									}
									catch (Exception ex)
									{
										Logger.Error("Failed to parse event! {0}", ex.Message);
										Logger.Error("Data: {0}", frame.Message);
									}
									try
									{
										if (eventPayload != null)
										{
											ProcessFrame(eventPayload);
										}
									}
									catch (Exception ex2)
									{
										Logger.Error("Failed to process event! {0}", ex2.Message);
										Logger.Error("Data: {0}", frame.Message);
									}
									break;
								}
								default:
									Logger.Error("Invalid opcode: {0}", frame.Opcode);
									flag = false;
									break;
								}
							}
							if (!aborting && namedPipe.IsConnected)
							{
								ProcessCommandQueue();
								queueUpdatedEvent.WaitOne(POLL_RATE);
							}
						}
						Logger.Trace("Left main read loop for some reason. Aborting: {0}, Shutting Down: {1}", aborting, shutdown);
					}
					else
					{
						Logger.Error("Failed to connect for some reason.");
						EnqueueMessage(new ConnectionFailedMessage
						{
							FailedPipe = targetPipe
						});
					}
					if (!aborting && !shutdown)
					{
						long num = delay.NextDelay();
						Logger.Trace("Waiting {0}ms before attempting to connect again", num);
						Thread.Sleep(delay.NextDelay());
					}
				}
				catch (Exception ex3)
				{
					Logger.Error("Unhandled Exception: {0}", ex3.GetType().FullName);
					Logger.Error(ex3.Message);
					Logger.Error(ex3.StackTrace);
				}
				finally
				{
					if (namedPipe.IsConnected)
					{
						Logger.Trace("Closing the named pipe.");
						namedPipe.Close();
					}
					SetConnectionState(RpcState.Disconnected);
				}
			}
			Logger.Trace("Left Main Loop");
			if (namedPipe != null)
			{
				namedPipe.Dispose();
			}
			Logger.Info("Thread Terminated, no longer performing RPC connection.");
		}

		private void ProcessFrame(EventPayload response)
		{
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Expected O, but got Unknown
			Logger.Info("Handling Response. Cmd: {0}, Event: {1}", response.Command, response.Event);
			if (response.Event.HasValue && response.Event.Value == ServerEvent.Error)
			{
				Logger.Error("Error received from the RPC");
				ErrorMessage @object = response.GetObject<ErrorMessage>();
				Logger.Error("Server responded with an error message: ({0}) {1}", @object.Code.ToString(), @object.Message);
				EnqueueMessage(@object);
			}
			else if (State == RpcState.Connecting && response.Command == Command.Dispatch && response.Event.HasValue && response.Event.Value == ServerEvent.Ready)
			{
				Logger.Info("Connection established with the RPC");
				SetConnectionState(RpcState.Connected);
				delay.Reset();
				ReadyMessage object2 = response.GetObject<ReadyMessage>();
				lock (l_config)
				{
					_configuration = object2.Configuration;
					object2.User.SetConfiguration(_configuration);
				}
				EnqueueMessage(object2);
			}
			else if (State == RpcState.Connected)
			{
				switch (response.Command)
				{
				case Command.Dispatch:
					ProcessDispatch(response);
					break;
				case Command.SetActivity:
				{
					if (response.Data == null)
					{
						EnqueueMessage(new PresenceMessage());
						break;
					}
					RichPresenceResponse object3 = response.GetObject<RichPresenceResponse>();
					EnqueueMessage(new PresenceMessage(object3));
					break;
				}
				case Command.Subscribe:
				case Command.Unsubscribe:
				{
					JsonSerializer val = new JsonSerializer();
					((Collection<JsonConverter>)(object)val.Converters).Add((JsonConverter)(object)new EnumSnakeCaseConverter());
					ServerEvent value = response.GetObject<EventPayload>().Event.Value;
					if (response.Command == Command.Subscribe)
					{
						EnqueueMessage(new SubscribeMessage(value));
					}
					else
					{
						EnqueueMessage(new UnsubscribeMessage(value));
					}
					break;
				}
				case Command.SendActivityJoinInvite:
					Logger.Trace("Got invite response ack.");
					break;
				case Command.CloseActivityJoinRequest:
					Logger.Trace("Got invite response reject ack.");
					break;
				default:
					Logger.Error("Unkown frame was received! {0}", response.Command);
					break;
				}
			}
			else
			{
				Logger.Trace("Received a frame while we are disconnected. Ignoring. Cmd: {0}, Event: {1}", response.Command, response.Event);
			}
		}

		private void ProcessDispatch(EventPayload response)
		{
			if (response.Command == Command.Dispatch && response.Event.HasValue)
			{
				switch (response.Event.Value)
				{
				case ServerEvent.ActivitySpectate:
				{
					SpectateMessage object3 = response.GetObject<SpectateMessage>();
					EnqueueMessage(object3);
					break;
				}
				case ServerEvent.ActivityJoin:
				{
					JoinMessage object2 = response.GetObject<JoinMessage>();
					EnqueueMessage(object2);
					break;
				}
				case ServerEvent.ActivityJoinRequest:
				{
					JoinRequestMessage @object = response.GetObject<JoinRequestMessage>();
					EnqueueMessage(@object);
					break;
				}
				default:
					Logger.Warning("Ignoring {0}", response.Event.Value);
					break;
				}
			}
		}

		private void ProcessCommandQueue()
		{
			if (State != RpcState.Connected)
			{
				return;
			}
			if (aborting)
			{
				Logger.Warning("We have been told to write a queue but we have also been aborted.");
			}
			bool flag = true;
			ICommand command = null;
			while (flag && namedPipe.IsConnected)
			{
				lock (l_rtqueue)
				{
					flag = _rtqueue.Count > 0;
					if (!flag)
					{
						break;
					}
					command = _rtqueue.Peek();
				}
				if (shutdown || (!aborting && LOCK_STEP))
				{
					flag = false;
				}
				IPayload payload = command.PreparePayload(GetNextNonce());
				Logger.Trace("Attempting to send payload: {0}", payload.Command);
				PipeFrame frame = default(PipeFrame);
				if (command is CloseCommand)
				{
					SendHandwave();
					Logger.Trace("Handwave sent, ending queue processing.");
					lock (l_rtqueue)
					{
						_rtqueue.Dequeue();
						break;
					}
				}
				if (aborting)
				{
					Logger.Warning("- skipping frame because of abort.");
					lock (l_rtqueue)
					{
						_rtqueue.Dequeue();
					}
					continue;
				}
				frame.SetObject(Opcode.Frame, payload);
				Logger.Trace("Sending payload: {0}", payload.Command);
				if (namedPipe.WriteFrame(frame))
				{
					Logger.Trace("Sent Successfully.");
					lock (l_rtqueue)
					{
						_rtqueue.Dequeue();
					}
					continue;
				}
				Logger.Warning("Something went wrong during writing!");
				break;
			}
		}

		private void EstablishHandshake()
		{
			Logger.Trace("Attempting to establish a handshake...");
			if (State != 0)
			{
				Logger.Error("State must be disconnected in order to start a handshake!");
				return;
			}
			Logger.Trace("Sending Handshake...");
			if (!namedPipe.WriteFrame(new PipeFrame(Opcode.Handshake, new Handshake
			{
				Version = VERSION,
				ClientID = applicationID
			})))
			{
				Logger.Error("Failed to write a handshake.");
			}
			else
			{
				SetConnectionState(RpcState.Connecting);
			}
		}

		private void SendHandwave()
		{
			Logger.Info("Attempting to wave goodbye...");
			if (State == RpcState.Disconnected)
			{
				Logger.Error("State must NOT be disconnected in order to send a handwave!");
			}
			else if (!namedPipe.WriteFrame(new PipeFrame(Opcode.Close, new Handshake
			{
				Version = VERSION,
				ClientID = applicationID
			})))
			{
				Logger.Error("failed to write a handwave.");
			}
		}

		public bool AttemptConnection()
		{
			Logger.Info("Attempting a new connection");
			if (thread != null)
			{
				Logger.Error("Cannot attempt a new connection as the previous connection thread is not null!");
				return false;
			}
			if (State != 0)
			{
				Logger.Warning("Cannot attempt a new connection as the previous connection hasn't changed state yet.");
				return false;
			}
			if (aborting)
			{
				Logger.Error("Cannot attempt a new connection while aborting!");
				return false;
			}
			thread = new Thread(MainLoop);
			thread.Name = "Discord IPC Thread";
			thread.IsBackground = true;
			thread.Start();
			return true;
		}

		private void SetConnectionState(RpcState state)
		{
			Logger.Trace("Setting the connection state to {0}", state.ToString().ToSnakeCase().ToUpperInvariant());
			lock (l_states)
			{
				_state = state;
			}
		}

		public void Shutdown()
		{
			Logger.Trace("Initiated shutdown procedure");
			shutdown = true;
			lock (l_rtqueue)
			{
				_rtqueue.Clear();
				if (CLEAR_ON_SHUTDOWN)
				{
					_rtqueue.Enqueue(new PresenceCommand
					{
						PID = processID,
						Presence = null
					});
				}
				_rtqueue.Enqueue(new CloseCommand());
			}
			queueUpdatedEvent.Set();
		}

		public void Close()
		{
			if (thread == null)
			{
				Logger.Error("Cannot close as it is not available!");
				return;
			}
			if (aborting)
			{
				Logger.Error("Cannot abort as it has already been aborted");
				return;
			}
			if (ShutdownOnly)
			{
				Shutdown();
				return;
			}
			Logger.Trace("Updating Abort State...");
			aborting = true;
			queueUpdatedEvent.Set();
		}

		public void Dispose()
		{
			ShutdownOnly = false;
			Close();
		}
	}
	internal enum RpcState
	{
		Disconnected,
		Connecting,
		Connected
	}
}
namespace DiscordRPC.RPC.Payload
{
	internal class ClosePayload : IPayload
	{
		[JsonProperty("code")]
		public int Code { get; set; }

		[JsonProperty("message")]
		public string Reason { get; set; }

		[JsonConstructor]
		public ClosePayload()
		{
			Code = -1;
			Reason = "";
		}
	}
	internal enum Command
	{
		[EnumValue("DISPATCH")]
		Dispatch,
		[EnumValue("SET_ACTIVITY")]
		SetActivity,
		[EnumValue("SUBSCRIBE")]
		Subscribe,
		[EnumValue("UNSUBSCRIBE")]
		Unsubscribe,
		[EnumValue("SEND_ACTIVITY_JOIN_INVITE")]
		SendActivityJoinInvite,
		[EnumValue("CLOSE_ACTIVITY_JOIN_REQUEST")]
		CloseActivityJoinRequest,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		Authorize,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		Authenticate,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetGuild,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetGuilds,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetChannel,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetChannels,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		SetUserVoiceSettings,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		SelectVoiceChannel,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetSelectedVoiceChannel,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		SelectTextChannel,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		GetVoiceSettings,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		SetVoiceSettings,
		[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
		CaptureShortcut
	}
	internal abstract class IPayload
	{
		[JsonProperty("cmd")]
		[JsonConverter(typeof(EnumSnakeCaseConverter))]
		public Command Command { get; set; }

		[JsonProperty("nonce")]
		public string Nonce { get; set; }

		protected IPayload()
		{
		}

		protected IPayload(long nonce)
		{
			Nonce = nonce.ToString();
		}

		public override string ToString()
		{
			return $"Payload || Command: {Command}, Nonce: {Nonce}";
		}
	}
	internal class ArgumentPayload : IPayload
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public JObject Arguments { get; set; }

		public ArgumentPayload()
		{
			Arguments = null;
		}

		public ArgumentPayload(long nonce)
			: base(nonce)
		{
			Arguments = null;
		}

		public ArgumentPayload(object args, long nonce)
			: base(nonce)
		{
			SetObject(args);
		}

		public void SetObject(object obj)
		{
			Arguments = JObject.FromObject(obj);
		}

		public T GetObject<T>()
		{
			return ((JToken)Arguments).ToObject<T>();
		}

		public override string ToString()
		{
			return "Argument " + base.ToString();
		}
	}
	internal class EventPayload : IPayload
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public JObject Data { get; set; }

		[JsonProperty("evt")]
		[JsonConverter(typeof(EnumSnakeCaseConverter))]
		public ServerEvent? Event { get; set; }

		public EventPayload()
		{
			Data = null;
		}

		public EventPayload(long nonce)
			: base(nonce)
		{
			Data = null;
		}

		public T GetObject<T>()
		{
			if (Data == null)
			{
				return default(T);
			}
			return ((JToken)Data).ToObject<T>();
		}

		public override string ToString()
		{
			return "Event " + base.ToString() + ", Event: " + (Event.HasValue ? Event.ToString() : "N/A");
		}
	}
	internal enum ServerEvent
	{
		[EnumValue("READY")]
		Ready,
		[EnumValue("ERROR")]
		Error,
		[EnumValue("ACTIVITY_JOIN")]
		ActivityJoin,
		[EnumValue("ACTIVITY_SPECTATE")]
		ActivitySpectate,
		[EnumValue("ACTIVITY_JOIN_REQUEST")]
		ActivityJoinRequest
	}
}
namespace DiscordRPC.RPC.Commands
{
	internal class CloseCommand : ICommand
	{
		[JsonProperty("close_reason")]
		public string value = "Unity 5.5 doesn't handle thread aborts. Can you please close me discord?";

		[JsonProperty("pid")]
		public int PID { get; set; }

		public IPayload PreparePayload(long nonce)
		{
			return new ArgumentPayload
			{
				Command = Command.Dispatch,
				Nonce = null,
				Arguments = null
			};
		}
	}
	internal interface ICommand
	{
		IPayload PreparePayload(long nonce);
	}
	internal class PresenceCommand : ICommand
	{
		[JsonProperty("pid")]
		public int PID { get; set; }

		[JsonProperty("activity")]
		public RichPresence Presence { get; set; }

		public IPayload PreparePayload(long nonce)
		{
			return new ArgumentPayload(this, nonce)
			{
				Command = Command.SetActivity
			};
		}
	}
	internal class RespondCommand : ICommand
	{
		[JsonProperty("user_id")]
		public string UserID { get; set; }

		[JsonIgnore]
		public bool Accept { get; set; }

		public IPayload PreparePayload(long nonce)
		{
			return new ArgumentPayload(this, nonce)
			{
				Command = (Accept ? Command.SendActivityJoinInvite : Command.CloseActivityJoinRequest)
			};
		}
	}
	internal class SubscribeCommand : ICommand
	{
		public ServerEvent Event { get; set; }

		public bool IsUnsubscribe { get; set; }

		public IPayload PreparePayload(long nonce)
		{
			return new EventPayload(nonce)
			{
				Command = (IsUnsubscribe ? Command.Unsubscribe : Command.Subscribe),
				Event = Event
			};
		}
	}
}
namespace DiscordRPC.Registry
{
	internal interface IUriSchemeCreator
	{
		bool RegisterUriScheme(UriSchemeRegister register);
	}
	internal class MacUriSchemeCreator : IUriSchemeCreator
	{
		private ILogger logger;

		public MacUriSchemeCreator(ILogger logger)
		{
			this.logger = logger;
		}

		public bool RegisterUriScheme(UriSchemeRegister register)
		{
			string executablePath = register.ExecutablePath;
			if (string.IsNullOrEmpty(executablePath))
			{
				logger.Error("Failed to register because the application could not be located.");
				return false;
			}
			logger.Trace("Registering Steam Command");
			string text = executablePath;
			if (register.UsingSteamApp)
			{
				text = "steam://rungameid/" + register.SteamAppID;
			}
			else
			{
				logger.Warning("This library does not fully support MacOS URI Scheme Registration.");
			}
			string text2 = "~/Library/Application Support/discord/games";
			DirectoryInfo directoryInfo = Directory.CreateDirectory(text2);
			if (!directoryInfo.Exists)
			{
				logger.Error("Failed to register because {0} does not exist", text2);
				return false;
			}
			string text3 = text2 + "/" + register.ApplicationID + ".json";
			File.WriteAllText(text3, "{ \"command\": \"" + text + "\" }");
			logger.Trace("Registered {0}, {1}", text3, text);
			return true;
		}
	}
	internal class UnixUriSchemeCreator : IUriSchemeCreator
	{
		private ILogger logger;

		public UnixUriSchemeCreator(ILogger logger)
		{
			this.logger = logger;
		}

		public bool RegisterUriScheme(UriSchemeRegister register)
		{
			string environmentVariable = Environment.GetEnvironmentVariable("HOME");
			if (string.IsNullOrEmpty(environmentVariable))
			{
				logger.Error("Failed to register because the HOME variable was not set.");
				return false;
			}
			string executablePath = register.ExecutablePath;
			if (string.IsNullOrEmpty(executablePath))
			{
				logger.Error("Failed to register because the application was not located.");
				return false;
			}
			string text = null;
			text = ((!register.UsingSteamApp) ? executablePath : ("xdg-open steam://rungameid/" + register.SteamAppID));
			string format = "[Desktop Entry]\r\nName=Game {0}\r\nExec={1} %u\r\nType=Application\r\nNoDisplay=true\r\nCategories=Discord;Games;\r\nMimeType=x-scheme-handler/discord-{2}";
			string text2 = string.Format(format, register.ApplicationID, text, register.ApplicationID);
			string text3 = "/discord-" + register.ApplicationID + ".desktop";
			string text4 = environmentVariable + "/.local/share/applications";
			DirectoryInfo directoryInfo = Directory.CreateDirectory(text4);
			if (!directoryInfo.Exists)
			{
				logger.Error("Failed to register because {0} does not exist", text4);
				return false;
			}
			File.WriteAllText(text4 + text3, text2);
			if (!RegisterMime(register.ApplicationID))
			{
				logger.Error("Failed to register because the Mime failed.");
				return false;
			}
			logger.Trace("Registered {0}, {1}, {2}", text4 + text3, text2, text);
			return true;
		}

		private bool RegisterMime(string appid)
		{
			string format = "default discord-{0}.desktop x-scheme-handler/discord-{0}";
			string arguments = string.Format(format, appid);
			Process process = Process.Start("xdg-mime", arguments);
			process.WaitForExit();
			return process.ExitCode >= 0;
		}
	}
	internal class UriSchemeRegister
	{
		private ILogger _logger;

		public string ApplicationID { get; set; }

		public string SteamAppID { get; set; }

		public bool UsingSteamApp => !string.IsNullOrEmpty(SteamAppID) && SteamAppID != "";

		public string ExecutablePath { get; set; }

		public UriSchemeRegister(ILogger logger, string applicationID, string steamAppID = null, string executable = null)
		{
			_logger = logger;
			ApplicationID = applicationID.Trim();
			SteamAppID = steamAppID?.Trim();
			ExecutablePath = executable ?? GetApplicationLocation();
		}

		public bool RegisterUriScheme()
		{
			IUriSchemeCreator uriSchemeCreator = null;
			switch (Environment.OSVersion.Platform)
			{
			case PlatformID.Win32S:
			case PlatformID.Win32Windows:
			case PlatformID.Win32NT:
			case PlatformID.WinCE:
				_logger.Trace("Creating Windows Scheme Creator");
				uriSchemeCreator = new WindowsUriSchemeCreator(_logger);
				break;
			case PlatformID.Unix:
				_logger.Trace("Creating Unix Scheme Creator");
				uriSchemeCreator = new UnixUriSchemeCreator(_logger);
				break;
			case PlatformID.MacOSX:
				_logger.Trace("Creating MacOSX Scheme Creator");
				uriSchemeCreator = new MacUriSchemeCreator(_logger);
				break;
			default:
				_logger.Error("Unkown Platform: {0}", Environment.OSVersion.Platform);
				throw new PlatformNotSupportedException("Platform does not support registration.");
			}
			if (uriSchemeCreator.RegisterUriScheme(this))
			{
				_logger.Info("URI scheme registered.");
				return true;
			}
			return false;
		}

		public static string GetApplicationLocation()
		{
			return Process.GetCurrentProcess().MainModule.FileName;
		}
	}
	internal class WindowsUriSchemeCreator : IUriSchemeCreator
	{
		private ILogger logger;

		public WindowsUriSchemeCreator(ILogger logger)
		{
			this.logger = logger;
		}

		public bool RegisterUriScheme(UriSchemeRegister register)
		{
			if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX)
			{
				throw new PlatformNotSupportedException("URI schemes can only be registered on Windows");
			}
			string executablePath = register.ExecutablePath;
			if (executablePath == null)
			{
				logger.Error("Failed to register application because the location was null.");
				return false;
			}
			string scheme = "discord-" + register.ApplicationID;
			string friendlyName = "Run game " + register.ApplicationID + " protocol";
			string defaultIcon = executablePath;
			string command = executablePath;
			if (register.UsingSteamApp)
			{
				string steamLocation = GetSteamLocation();
				if (steamLocation != null)
				{
					command = $"\"{steamLocation}\" steam://rungameid/{register.SteamAppID}";
				}
			}
			CreateUriScheme(scheme, friendlyName, defaultIcon, command);
			return true;
		}

		private void CreateUriScheme(string scheme, string friendlyName, string defaultIcon, string command)
		{
			using (RegistryKey registryKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("SOFTWARE\\Classes\\" + scheme))
			{
				registryKey.SetValue("", "URL:" + friendlyName);
				registryKey.SetValue("URL Protocol", "");
				using (RegistryKey registryKey2 = registryKey.CreateSubKey("DefaultIcon"))
				{
					registryKey2.SetValue("", defaultIcon);
				}
				using RegistryKey registryKey3 = registryKey.CreateSubKey("shell\\open\\command");
				registryKey3.SetValue("", command);
			}
			logger.Trace("Registered {0}, {1}, {2}", scheme, friendlyName, command);
		}

		public string GetSteamLocation()
		{
			using RegistryKey registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Valve\\Steam");
			if (registryKey == null)
			{
				return null;
			}
			return registryKey.GetValue("SteamExe") as string;
		}
	}
}
namespace DiscordRPC.Message
{
	public class CloseMessage : IMessage
	{
		public override MessageType Type => MessageType.Close;

		public string Reason { get; internal set; }

		public int Code { get; internal set; }

		internal CloseMessage()
		{
		}

		internal CloseMessage(string reason)
		{
			Reason = reason;
		}
	}
	public class ConnectionEstablishedMessage : IMessage
	{
		public override MessageType Type => MessageType.ConnectionEstablished;

		public int ConnectedPipe { get; internal set; }
	}
	public class ConnectionFailedMessage : IMessage
	{
		public override MessageType Type => MessageType.ConnectionFailed;

		public int FailedPipe { get; internal set; }
	}
	public class ErrorMessage : IMessage
	{
		public override MessageType Type => MessageType.Error;

		[JsonProperty("code")]
		public ErrorCode Code { get; internal set; }

		[JsonProperty("message")]
		public string Message { get; internal set; }
	}
	public enum ErrorCode
	{
		Success = 0,
		PipeException = 1,
		ReadCorrupt = 2,
		NotImplemented = 10,
		UnkownError = 1000,
		InvalidPayload = 4000,
		InvalidCommand = 4002,
		InvalidEvent = 4004
	}
	public abstract class IMessage
	{
		private DateTime _timecreated;

		public abstract MessageType Type { get; }

		public DateTime TimeCreated => _timecreated;

		public IMessage()
		{
			_timecreated = DateTime.Now;
		}
	}
	public class JoinMessage : IMessage
	{
		public override MessageType Type => MessageType.Join;

		[JsonProperty("secret")]
		public string Secret { get; internal set; }
	}
	public class JoinRequestMessage : IMessage
	{
		public override MessageType Type => MessageType.JoinRequest;

		[JsonProperty("user")]
		public User User { get; internal set; }
	}
	public enum MessageType
	{
		Ready,
		Close,
		Error,
		PresenceUpdate,
		Subscribe,
		Unsubscribe,
		Join,
		Spectate,
		JoinRequest,
		ConnectionEstablished,
		ConnectionFailed
	}
	public class PresenceMessage : IMessage
	{
		public override MessageType Type => MessageType.PresenceUpdate;

		public BaseRichPresence Presence { get; internal set; }

		public string Name { get; internal set; }

		public string ApplicationID { get; internal set; }

		internal PresenceMessage()
			: this(null)
		{
		}

		internal PresenceMessage(RichPresenceResponse rpr)
		{
			if (rpr == null)
			{
				Presence = null;
				Name = "No Rich Presence";
				ApplicationID = "";
			}
			else
			{
				Presence = rpr;
				Name = rpr.Name;
				ApplicationID = rpr.ClientID;
			}
		}
	}
	public class ReadyMessage : IMessage
	{
		public override MessageType Type => MessageType.Ready;

		[JsonProperty("config")]
		public Configuration Configuration { get; set; }

		[JsonProperty("user")]
		public User User { get; set; }

		[JsonProperty("v")]
		public int Version { get; set; }
	}
	public class SpectateMessage : JoinMessage
	{
		public override MessageType Type => MessageType.Spectate;
	}
	public class SubscribeMessage : IMessage
	{
		public override MessageType Type => MessageType.Subscribe;

		public EventType Event { get; internal set; }

		internal SubscribeMessage(ServerEvent evt)
		{
			switch (evt)
			{
			default:
				Event = EventType.Join;
				break;
			case ServerEvent.ActivityJoinRequest:
				Event = EventType.JoinRequest;
				break;
			case ServerEvent.ActivitySpectate:
				Event = EventType.Spectate;
				break;
			}
		}
	}
	public class UnsubscribeMessage : IMessage
	{
		public override MessageType Type => MessageType.Unsubscribe;

		public EventType Event { get; internal set; }

		internal UnsubscribeMessage(ServerEvent evt)
		{
			switch (evt)
			{
			default:
				Event = EventType.Join;
				break;
			case ServerEvent.ActivityJoinRequest:
				Event = EventType.JoinRequest;
				break;
			case ServerEvent.ActivitySpectate:
				Event = EventType.Spectate;
				break;
			}
		}
	}
}
namespace DiscordRPC.Logging
{
	public class ConsoleLogger : ILogger
	{
		public LogLevel Level { get; set; }

		public bool Coloured { get; set; }

		[Obsolete("Use Coloured")]
		public bool Colored
		{
			get
			{
				return Coloured;
			}
			set
			{
				Coloured = value;
			}
		}

		public ConsoleLogger()
		{
			Level = LogLevel.Info;
			Coloured = false;
		}

		public ConsoleLogger(LogLevel level)
			: this()
		{
			Level = level;
		}

		public ConsoleLogger(LogLevel level, bool coloured)
		{
			Level = level;
			Coloured = coloured;
		}

		public void Trace(string message, params object[] args)
		{
			if (Level <= LogLevel.Trace)
			{
				if (Coloured)
				{
					Console.ForegroundColor = ConsoleColor.Gray;
				}
				string text = "TRACE: " + message;
				if (args.Length != 0)
				{
					Console.WriteLine(text, args);
				}
				else
				{
					Console.WriteLine(text);
				}
			}
		}

		public void Info(string message, params object[] args)
		{
			if (Level <= LogLevel.Info)
			{
				if (Coloured)
				{
					Console.ForegroundColor = ConsoleColor.White;
				}
				string text = "INFO: " + message;
				if (args.Length != 0)
				{
					Console.WriteLine(text, args);
				}
				else
				{
					Console.WriteLine(text);
				}
			}
		}

		public void Warning(string message, params object[] args)
		{
			if (Level <= LogLevel.Warning)
			{
				if (Coloured)
				{
					Console.ForegroundColor = ConsoleColor.Yellow;
				}
				string text = "WARN: " + message;
				if (args.Length != 0)
				{
					Console.WriteLine(text, args);
				}
				else
				{
					Console.WriteLine(text);
				}
			}
		}

		public void Error(string message, params object[] args)
		{
			if (Level <= LogLevel.Error)
			{
				if (Coloured)
				{
					Console.ForegroundColor = ConsoleColor.Red;
				}
				string text = "ERR : " + message;
				if (args.Length != 0)
				{
					Console.WriteLine(text, args);
				}
				else
				{
					Console.WriteLine(text);
				}
			}
		}
	}
	public class FileLogger : ILogger
	{
		private object filelock;

		public LogLevel Level { get; set; }

		public string File { get; set; }

		public FileLogger(string path)
			: this(path, LogLevel.Info)
		{
		}

		public FileLogger(string path, LogLevel level)
		{
			Level = level;
			File = path;
			filelock = new object();
		}

		public void Trace(string message, params object[] args)
		{
			if (Level > LogLevel.Trace)
			{
				return;
			}
			lock (filelock)
			{
				System.IO.File.AppendAllText(File, "\r\nTRCE: " + ((args.Length != 0) ? string.Format(message, args) : message));
			}
		}

		public void Info(string message, params object[] args)
		{
			if (Level > LogLevel.Info)
			{
				return;
			}
			lock (filelock)
			{
				System.IO.File.AppendAllText(File, "\r\nINFO: " + ((args.Length != 0) ? string.Format(message, args) : message));
			}
		}

		public void Warning(string message, params object[] args)
		{
			if (Level > LogLevel.Warning)
			{
				return;
			}
			lock (filelock)
			{
				System.IO.File.AppendAllText(File, "\r\nWARN: " + ((args.Length != 0) ? string.Format(message, args) : message));
			}
		}

		public void Error(string message, params object[] args)
		{
			if (Level > LogLevel.Error)
			{
				return;
			}
			lock (filelock)
			{
				System.IO.File.AppendAllText(File, "\r\nERR : " + ((args.Length != 0) ? string.Format(message, args) : message));
			}
		}
	}
	public interface ILogger
	{
		LogLevel Level { get; set; }

		void Trace(string message, params object[] args);

		void Info(string message, params object[] args);

		void Warning(string message, params object[] args);

		void Error(string message, params object[] args);
	}
	public enum LogLevel
	{
		Trace = 1,
		Info = 2,
		Warning = 3,
		Error = 4,
		None = 256
	}
	public class NullLogger : ILogger
	{
		public LogLevel Level { get; set; }

		public void Trace(string message, params object[] args)
		{
		}

		public void Info(string message, params object[] args)
		{
		}

		public void Warning(string message, params object[] args)
		{
		}

		public void Error(string message, params object[] args)
		{
		}
	}
}
namespace DiscordRPC.IO
{
	internal class Handshake
	{
		[JsonProperty("v")]
		public int Version { get; set; }

		[JsonProperty("client_id")]
		public string ClientID { get; set; }
	}
	public interface INamedPipeClient : IDisposable
	{
		ILogger Logger { get; set; }

		bool IsConnected { get; }

		int ConnectedPipe { get; }

		bool Connect(int pipe);

		bool ReadFrame(out PipeFrame frame);

		bool WriteFrame(PipeFrame frame);

		void Close();
	}
	public sealed class ManagedNamedPipeClient : INamedPipeClient, IDisposable
	{
		private const string PIPE_NAME = "discord-ipc-{0}";

		private int _connectedPipe;

		private NamedPipeClientStream _stream;

		private byte[] _buffer = new byte[PipeFrame.MAX_SIZE];

		private Queue<PipeFrame> _framequeue = new Queue<PipeFrame>();

		private object _framequeuelock = new object();

		private volatile bool _isDisposed = false;

		private volatile bool _isClosed = true;

		private object l_stream = new object();

		public ILogger Logger { get; set; }

		public bool IsConnected
		{
			get
			{
				if (_isClosed)
				{
					return false;
				}
				lock (l_stream)
				{
					return _stream != null && _stream.IsConnected;
				}
			}
		}

		public int ConnectedPipe => _connectedPipe;

		public ManagedNamedPipeClient()
		{
			_buffer = new byte[PipeFrame.MAX_SIZE];
			Logger = new NullLogger();
			_stream = null;
		}

		public bool Connect(int pipe)
		{
			Logger.Trace("ManagedNamedPipeClient.Connection({0})", pipe);
			if (_isDisposed)
			{
				throw new ObjectDisposedException("NamedPipe");
			}
			if (pipe > 9)
			{
				throw new ArgumentOutOfRangeException("pipe", "Argument cannot be greater than 9");
			}
			if (pipe < 0)
			{
				for (int i = 0; i < 10; i++)
				{
					if (AttemptConnection(i) || AttemptConnection(i, isSandbox: true))
					{
						BeginReadStream();
						return true;
					}
				}
			}
			else if (AttemptConnection(pipe) || AttemptConnection(pipe, isSandbox: true))
			{
				BeginReadStream();
				return true;
			}
			return false;
		}

		private bool AttemptConnection(int pipe, bool isSandbox = false)
		{
			if (_isDisposed)
			{
				throw new ObjectDisposedException("_stream");
			}
			string text = (isSandbox ? GetPipeSandbox() : "");
			if (isSandbox && text == null)
			{
				Logger.Trace("Skipping sandbox connection.");
				return false;
			}
			Logger.Trace("Connection Attempt {0} ({1})", pipe, text);
			string pipeName = GetPipeName(pipe, text);
			try
			{
				lock (l_stream)
				{
					Logger.Info("Attempting to connect to '{0}'", pipeName);
					_stream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
					_stream.Connect(0);
					Logger.Trace("Waiting for connection...");
					do
					{
						Thread.Sleep(10);
					}
					while (!_stream.IsConnected);
				}
				Logger.Info("Connected to '{0}'", pipeName);
				_connectedPipe = pipe;
				_isClosed = false;
			}
			catch (Exception ex)
			{
				Logger.Error("Failed connection to {0}. {1}", pipeName, ex.Message);
				Close();
			}
			Logger.Trace("Done. Result: {0}", _isClosed);
			return !_isClosed;
		}

		private void BeginReadStream()
		{
			if (_isClosed)
			{
				return;
			}
			try
			{
				lock (l_stream)
				{
					if (_stream != null && _stream.IsConnected)
					{
						Logger.Trace("Begining Read of {0} bytes", _buffer.Length);
						_stream.BeginRead(_buffer, 0, _buffer.Length, EndReadStream, _stream.IsConnected);
					}
				}
			}
			catch (ObjectDisposedException)
			{
				Logger.Warning("Attempted to start reading from a disposed pipe");
			}
			catch (InvalidOperationException)
			{
				Logger.Warning("Attempted to start reading from a closed pipe");
			}
			catch (Exception ex3)
			{
				Logger.Error("An exception occured while starting to read a stream: {0}", ex3.Message);
				Logger.Error(ex3.StackTrace);
			}
		}

		private void EndReadStream(IAsyncResult callback)
		{
			Logger.Trace("Ending Read");
			int num = 0;
			try
			{
				lock (l_stream)
				{
					if (_stream == null || !_stream.IsConnected)
					{
						return;
					}
					num = _stream.EndRead(callback);
				}
			}
			catch (IOException)
			{
				Logger.Warning("Attempted to end reading from a closed pipe");
				return;
			}
			catch (NullReferenceException)
			{
				Logger.Warning("Attempted to read from a null pipe");
				return;
			}
			catch (ObjectDisposedException)
			{
				Logger.Warning("Attemped to end reading from a disposed pipe");
				return;
			}
			catch (Exception ex4)
			{
				Logger.Error("An exception occured while ending a read of a stream: {0}", ex4.Message);
				Logger.Error(ex4.StackTrace);
				return;
			}
			Logger.Trace("Read {0} bytes", num);
			if (num > 0)
			{
				using MemoryStream stream = new MemoryStream(_buffer, 0, num);
				try
				{
					PipeFrame item = default(PipeFrame);
					if (item.ReadStream(stream))
					{
						Logger.Trace("Read a frame: {0}", item.Opcode);
						lock (_framequeuelock)
						{
							_framequeue.Enqueue(item);
						}
					}
					else
					{
						Logger.Error("Pipe failed to read from the data received by the stream.");
						Close();
					}
				}
				catch (Exception ex5)
				{
					Logger.Error("A exception has occured while trying to parse the pipe data: {0}", ex5.Message);
					Close();
				}
			}
			else if (IsUnix())
			{
				Logger.Error("Empty frame was read on {0}, aborting.", Environment.OSVersion);
				Close();
			}
			else
			{
				Logger.Warning("Empty frame was read. Please send report to Lachee.");
			}
			if (!_isClosed && IsConnected)
			{
				Logger.Trace("Starting another read");
				BeginReadStream();
			}
		}

		public bool ReadFrame(out PipeFrame frame)
		{
			if (_isDisposed)
			{
				throw new ObjectDisposedException("_stream");
			}
			lock (_framequeuelock)
			{
				if (_framequeue.Count == 0)
				{
					frame = default(PipeFrame);
					return false;
				}
				frame = _framequeue.Dequeue();
				return true;
			}
		}

		public bool WriteFrame(PipeFrame frame)
		{
			if (_isDisposed)
			{
				throw new ObjectDisposedException("_stream");
			}
			if (_isClosed || !IsConnected)
			{
				Logger.Error("Failed to write frame because the stream is closed");
				return false;
			}
			try
			{
				frame.WriteStream(_stream);
				return true;
			}
			catch (IOException ex)
			{
				Logger.Error("Failed to write frame because of a IO Exception: {0}", ex.Message);
			}
			catch (ObjectDisposedException)
			{
				Logger.Warning("Failed to write frame as the stream was already disposed");
			}
			catch (InvalidOperationException)
			{
				Logger.Warning("Failed to write frame because of a invalid operation");
			}
			return false;
		}

		public void Close()
		{
			if (_isClosed)
			{
				Logger.Warning("Tried to close a already closed pipe.");
				return;
			}
			try
			{
				lock (l_stream)
				{
					if (_stream != null)
					{
						try
						{
							_stream.Flush();
							_stream.Dispose();
						}
						catch (Exception)
						{
						}
						_stream = null;
						_isClosed = true;
					}
					else
					{
						Logger.Warning("Stream was closed, but no stream was available to begin with!");
					}
				}
			}
			catch (ObjectDisposedException)
			{
				Logger.Warning("Tried to dispose already disposed stream");
			}
			finally
			{
				_isClosed = true;
				_connectedPipe = -1;
			}
		}

		public void Dispose()
		{
			if (_isDisposed)
			{
				return;
			}
			if (!_isClosed)
			{
				Close();
			}
			lock (l_stream)
			{
				if (_stream != null)
				{
					_stream.Dispose();
					_stream = null;
				}
			}
			_isDisposed = true;
		}

		public static string GetPipeName(int pipe, string sandbox)
		{
			if (!IsUnix())
			{
				return sandbox + $"discord-ipc-{pipe}";
			}
			return Path.Combine(GetTemporaryDirectory(), sandbox + $"discord-ipc-{pipe}");
		}

		public static string GetPipeName(int pipe)
		{
			return GetPipeName(pipe, "");
		}

		public static string GetPipeSandbox()
		{
			PlatformID platform = Environment.OSVersion.Platform;
			PlatformID platformID = platform;
			if (platformID != PlatformID.Unix)
			{
				return null;
			}
			return "snap.discord/";
		}

		private static string GetTemporaryDirectory()
		{
			string text = null;
			text = text ?? Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR");
			text = text ?? Environment.GetEnvironmentVariable("TMPDIR");
			text = text ?? Environment.GetEnvironmentVariable("TMP");
			text = text ?? Environment.GetEnvironmentVariable("TEMP");
			return text ?? "/tmp";
		}

		public static bool IsUnix()
		{
			PlatformID platform = Environment.OSVersion.Platform;
			PlatformID platformID = platform;
			if (platformID != PlatformID.Unix && platformID != PlatformID.MacOSX)
			{
				return false;
			}
			return true;
		}
	}
	public enum Opcode : uint
	{
		Handshake,
		Frame,
		Close,
		Ping,
		Pong
	}
	public struct PipeFrame : IEquatable<PipeFrame>
	{
		public static readonly int MAX_SIZE = 16384;

		public Opcode Opcode { get; set; }

		public uint Length => (uint)Data.Length;

		public byte[] Data { get; set; }

		public string Message
		{
			get
			{
				return GetMessage();
			}
			set
			{
				SetMessage(value);
			}
		}

		public Encoding MessageEncoding => Encoding.UTF8;

		public PipeFrame(Opcode opcode, object data)
		{
			Opcode = opcode;
			Data = null;
			SetObject(data);
		}

		private void SetMessage(string str)
		{
			Data = MessageEncoding.GetBytes(str);
		}

		private string GetMessage()
		{
			return MessageEncoding.GetString(Data);
		}

		public void SetObject(object obj)
		{
			string message = JsonConvert.SerializeObject(obj);
			SetMessage(message);
		}

		public void SetObject(Opcode opcode, object obj)
		{
			Opcode = opcode;
			SetObject(obj);
		}

		public T GetObject<T>()
		{
			string message = GetMessage();
			return JsonConvert.DeserializeObject<T>(message);
		}

		public bool ReadStream(Stream stream)
		{
			if (!TryReadUInt32(stream, out var value))
			{
				return false;
			}
			if (!TryReadUInt32(stream, out var value2))
			{
				return false;
			}
			uint num = value2;
			using MemoryStream memoryStream = new MemoryStream();
			uint num2 = (uint)Min(2048, value2);
			byte[] array = new byte[num2];
			int count;
			while ((count = stream.Read(array, 0, Min(array.Length, num))) > 0)
			{
				num -= num2;
				memoryStream.Write(array, 0, count);
			}
			byte[] array2 = memoryStream.ToArray();
			if (array2.LongLength != value2)
			{
				return false;
			}
			Opcode = (Opcode)value;
			Data = array2;
			return true;
		}

		private int Min(int a, uint b)
		{
			if (b >= a)
			{
				return a;
			}
			return (int)b;
		}

		private bool TryReadUInt32(Stream stream, out uint value)
		{
			byte[] array = new byte[4];
			int num = stream.Read(array, 0, array.Length);
			if (num != 4)
			{
				value = 0u;
				return false;
			}
			value = BitConverter.ToUInt32(array, 0);
			return true;
		}

		public void WriteStream(Stream stream)
		{
			byte[] bytes = BitConverter.GetBytes((uint)Opcode);
			byte[] bytes2 = BitConverter.GetBytes(Length);
			byte[] array = new byte[bytes.Length + bytes2.Length + Data.Length];
			bytes.CopyTo(array, 0);
			bytes2.CopyTo(array, bytes.Length);
			Data.CopyTo(array, bytes.Length + bytes2.Length);
			stream.Write(array, 0, array.Length);
		}

		public bool Equals(PipeFrame other)
		{
			return Opcode == other.Opcode && Length == other.Length && Data == other.Data;
		}
	}
}
namespace DiscordRPC.Helper
{
	internal class BackoffDelay
	{
		private int _current;

		private int _fails;

		public int Maximum { get; private set; }

		public int Minimum { get; private set; }

		public int Current => _current;

		public int Fails => _fails;

		public Random Random { get; set; }

		private BackoffDelay()
		{
		}

		public BackoffDelay(int min, int max)
			: this(min, max, new Random())
		{
		}

		public BackoffDelay(int min, int max, Random random)
		{
			Minimum = min;
			Maximum = max;
			_current = min;
			_fails = 0;
			Random = random;
		}

		public void Reset()
		{
			_fails = 0;
			_current = Minimum;
		}

		public int NextDelay()
		{
			_fails++;
			double num = (float)(Maximum - Minimum) / 100f;
			_current = (int)Math.Floor(num * (double)_fails) + Minimum;
			return Math.Min(Math.Max(_current, Minimum), Maximum);
		}
	}
	public static class StringTools
	{
		public static string GetNullOrString(this string str)
		{
			return (str.Length == 0 || string.IsNullOrEmpty(str.Trim())) ? null : str;
		}

		public static bool WithinLength(this string str, int bytes)
		{
			return str.WithinLength(bytes, Encoding.UTF8);
		}

		public static bool WithinLength(this string str, int bytes, Encoding encoding)
		{
			return encoding.GetByteCount(str) <= bytes;
		}

		public static string ToCamelCase(this string str)
		{
			return (from s in str?.ToLowerInvariant().Split(new string[2] { "_", " " }, StringSplitOptions.RemoveEmptyEntries)
				select char.ToUpper(s[0]) + s.Substring(1, s.Length - 1)).Aggregate(string.Empty, (string s1, string s2) => s1 + s2);
		}

		public static string ToSnakeCase(this string str)
		{
			if (str == null)
			{
				return null;
			}
			string text = string.Concat(str.Select((char x, int i) => (i > 0 && char.IsUpper(x)) ? ("_" + x) : x.ToString()).ToArray());
			return text.ToUpperInvariant();
		}
	}
}
namespace DiscordRPC.Exceptions
{
	public class BadPresenceException : Exception
	{
		internal BadPresenceException(string message)
			: base(message)
		{
		}
	}
	public class InvalidConfigurationException : Exception
	{
		internal InvalidConfigurationException(string message)
			: base(message)
		{
		}
	}
	[Obsolete("Not actually used anywhere")]
	public class InvalidPipeException : Exception
	{
		internal InvalidPipeException(string message)
			: base(message)
		{
		}
	}
	public class StringOutOfRangeException : Exception
	{
		public int MaximumLength { get; private set; }

		public int MinimumLength { get; private set; }

		internal StringOutOfRangeException(string message, int min, int max)
			: base(message)
		{
			MinimumLength = min;
			MaximumLength = max;
		}

		internal StringOutOfRangeException(int minumum, int max)
			: this($"Length of string is out of range. Expected a value between {minumum} and {max}", minumum, max)
		{
		}

		internal StringOutOfRangeException(int max)
			: this($"Length of string is out of range. Expected a value with a maximum length of {max}", 0, max)
		{
		}
	}
	public class UninitializedException : Exception
	{
		internal UninitializedException(string message)
			: base(message)
		{
		}

		internal UninitializedException()
			: this("Cannot perform action because the client has not been initialized yet or has been deinitialized.")
		{
		}
	}
}
namespace DiscordRPC.Events
{
	public delegate void OnReadyEvent(object sender, ReadyMessage args);
	public delegate void OnCloseEvent(object sender, CloseMessage args);
	public delegate void OnErrorEvent(object sender, ErrorMessage args);
	public delegate void OnPresenceUpdateEvent(object sender, PresenceMessage args);
	public delegate void OnSubscribeEvent(object sender, SubscribeMessage args);
	public delegate void OnUnsubscribeEvent(object sender, UnsubscribeMessage args);
	public delegate void OnJoinEvent(object sender, JoinMessage args);
	public delegate void OnSpectateEvent(object sender, SpectateMessage args);
	public delegate void OnJoinRequestedEvent(object sender, JoinRequestMessage args);
	public delegate void OnConnectionEstablishedEvent(object sender, ConnectionEstablishedMessage args);
	public delegate void OnConnectionFailedEvent(object sender, ConnectionFailedMessage args);
	public delegate void OnRpcMessageEvent(object sender, IMessage msg);
}
namespace DiscordRPC.Converters
{
	internal class EnumSnakeCaseConverter : JsonConverter
	{
		public override bool CanConvert(Type objectType)
		{
			return objectType.IsEnum;
		}

		public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
		{
			if (reader.Value == null)
			{
				return null;
			}
			object obj = null;
			if (TryParseEnum(objectType, (string)reader.Value, out obj))
			{
				return obj;
			}
			return existingValue;
		}

		public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
		{
			Type type = value.GetType();
			string text = Enum.GetName(type, value);
			MemberInfo[] members = type.GetMembers(BindingFlags.Static | BindingFlags.Public);
			MemberInfo[] array = members;
			foreach (MemberInfo memberInfo in array)
			{
				if (memberInfo.Name.Equals(text))
				{
					object[] customAttributes = memberInfo.GetCustomAttributes(typeof(EnumValueAttribute), inherit: true);
					if (customAttributes.Length != 0)
					{
						text = ((EnumValueAttribute)customAttributes[0]).Value;
					}
				}
			}
			writer.WriteValue(text);
		}

		public bool TryParseEnum(Type enumType, string str, out object obj)
		{
			if (str == null)
			{
				obj = null;
				return false;
			}
			Type type = enumType;
			if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
			{
				type = type.GetGenericArguments().First();
			}
			if (!type.IsEnum)
			{
				obj = null;
				return false;
			}
			MemberInfo[] members = type.GetMembers(BindingFlags.Static | BindingFlags.Public);
			MemberInfo[] array = members;
			foreach (MemberInfo memberInfo in array)
			{
				object[] customAttributes = memberInfo.GetCustomAttributes(typeof(EnumValueAttribute), inherit: true);
				object[] array2 = customAttributes;
				foreach (object obj2 in array2)
				{
					EnumValueAttribute enumValueAttribute = (EnumValueAttribute)obj2;
					if (str.Equals(enumValueAttribute.Value))
					{
						obj = Enum.Parse(type, memberInfo.Name, ignoreCase: true);
						return true;
					}
				}
			}
			obj = null;
			return false;
		}
	}
	internal class EnumValueAttribute : Attribute
	{
		public string Value { get; set; }

		public EnumValueAttribute(string value)
		{
			Value = value;
		}
	}
}

BepInEx/plugins/TheArchive.RichPresence/plugins/TheArchive.RichPresence.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using AIGraph;
using Agents;
using CellMenu;
using Clonesoft.Json;
using DiscordRPC;
using DiscordRPC.Events;
using DiscordRPC.IO;
using DiscordRPC.Logging;
using DiscordRPC.Message;
using GameData;
using Gear;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Player;
using SNetwork;
using TheArchive.Core;
using TheArchive.Core.Attributes;
using TheArchive.Core.Attributes.Feature;
using TheArchive.Core.Attributes.Feature.Members;
using TheArchive.Core.Attributes.Feature.Patches;
using TheArchive.Core.Attributes.Feature.Settings;
using TheArchive.Core.FeaturesAPI;
using TheArchive.Core.FeaturesAPI.Groups;
using TheArchive.Core.Localization;
using TheArchive.Core.Managers;
using TheArchive.Core.Models;
using TheArchive.Core.Settings;
using TheArchive.Interfaces;
using TheArchive.Loader;
using TheArchive.Utilities;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("2025.2.0")]
[assembly: AssemblyInformationalVersion("2025.2.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TheArchive.RichPresence")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyProduct("TheArchive.RichPresence")]
[assembly: AssemblyTitle("TheArchive.RichPresence")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2025.2.0.0")]
[module: UnverifiableCode]
internal class ThisAssembly
{
	public class Git
	{
		public class BaseVersion
		{
			public const string Major = "0";

			public const string Minor = "0";

			public const string Patch = "0";
		}

		public class SemVer
		{
			public const string Major = "0";

			public const string Minor = "0";

			public const string Patch = "838";

			public const string Label = "";

			public const string DashLabel = "";

			public const string Source = "Default";
		}

		public const bool IsDirty = false;

		public const string IsDirtyString = "false";

		public const string RepositoryUrl = "https://github.com/Tuesday1028/GTFO_TheArchive";

		public const string Branch = "doing-things";

		public const string Commit = "a4eb55a";

		public const string Sha = "a4eb55a7e97569a44df6831acc6074b0f084b6eb";

		public const string CommitDate = "2026-05-07T19:14:52+08:00";

		public const string Commits = "838";

		public const string Tag = "";

		public const string BaseTag = "";
	}
}
internal class ManifestInfo
{
	internal const string TSName = "TheArchive_RichPresence";

	internal const string TSDescription = "Custom Discord Rich Presence Add-on for TheArchive.";

	internal const string TSVersion = "2025.2.0";

	internal const string TSAuthor = "AuriRex";

	internal const string TSWebsite = "https://github.com/AuriRex/GTFO_TheArchive";
}
namespace TheArchive
{
	[ArchiveModule("dev.AuriRex.gtfo.TheArchive.RichPresence", "TheArchive_RichPresence", "2025.2.0")]
	public class ArchiveRichPresenceModule : IArchiveModule
	{
		public const string GUID = "dev.AuriRex.gtfo.TheArchive.RichPresence";

		public const string MOD_NAME = "TheArchive_RichPresence";

		public const string VERSION = "2025.2.0";

		public ILocalizationService LocalizationService { get; set; }

		public IArchiveLogger Logger { get; set; }

		public void Init()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			ArchiveMod.GameDataInitialized += OnGameDataInitialized;
			try
			{
				string @string = Encoding.UTF8.GetString(Utils.GetResource(Assembly.GetExecutingAssembly(), "TheArchive.DiscordGameSDK.LICENSE_DiscordRPC"));
				AttributionInfo val = new AttributionInfo("DiscordRPC License", @string, "", "");
				val.set_Comment("<#fff18e>Huge shoutouts to <#88e2e9>Lachee</color> for her re-implementation of the discord_game_sdks functions in C#!</color>");
				val.set_Origin("TheArchive_RichPresence".Replace("_", "."));
				Attribution.Add(val);
			}
			catch (Exception ex)
			{
				Logger.Error("Something went wrong while trying to add Attribution.");
				Logger.Exception(ex);
			}
		}

		private void OnGameDataInitialized(RundownID _)
		{
			try
			{
				PresenceFormatter.RegisterAllPresenceFormatProviders(typeof(PresenceManager), false);
				PresenceFormatter.Setup();
			}
			catch (Exception ex)
			{
				Logger.Exception(ex);
			}
		}
	}
}
namespace TheArchive.Features.Presence
{
	[EnableFeatureByDefault]
	public class CustomLobbyCodeString : Feature
	{
		public class CustomLobbyCodeStringConfig
		{
			[FSMaxLength(120)]
			[FSDisplayName("Format")]
			public string Format { get; set; } = "LF%OpenSlots% %Rundown%%Expedition% \"%ExpeditionName%\": `%LobbyID%`";

		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class CM_PageSettings_SetupPatch
		{
			public static void Postfix(CM_PageSettings __instance)
			{
				SetupViaInstance(__instance);
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class CM_PageLoadout_SetupPatch
		{
			public static void Postfix(CM_PageLoadout __instance)
			{
				SetupViaInstance(__instance);
			}
		}

		public const string DefaultFormat = "LF%OpenSlots% %Rundown%%Expedition% \"%ExpeditionName%\": `%LobbyID%`";

		private static CM_Item _CM_PageLoadout_coppyLobbyIDButton;

		private static CM_Item _CM_PageSettings_coppyLobbyIDButton;

		public override string Name => "Copy Lobby ID Format";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Presence;

		public override string Description => "Customize copied lobby code from the 'Copy Lobby ID'-Button on the loadout and settings screens with a custom format.";

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static CustomLobbyCodeStringConfig Config { get; set; }

		[SetEnabledStatus]
		public static bool IsEnabled { get; set; }

		public override void OnEnable()
		{
			if ((Object)(object)_CM_PageLoadout_coppyLobbyIDButton == (Object)null)
			{
				SetupViaInstance(CM_PageLoadout.Current);
			}
		}

		public static void CopyLobbyIdToClipboard(int _)
		{
			//IL_002e: 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_0036: 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)
			if (!IsEnabled)
			{
				string text2 = (GUIUtility.systemCopyBuffer = PresenceFormatter.FormatPresenceString("%LobbyID%"));
				FeatureLogger.Notice("Copied lobby id to clipboard: " + text2);
				return;
			}
			GameBuildInfo buildInfo = Feature.BuildInfo;
			if ((!RundownFlagsExtensions.IsIncludedIn(((GameBuildInfo)(ref buildInfo)).Rundown, RundownFlagsExtensions.ToLatest((RundownFlags)16)) || !IsExternalMatchMakingActive()) && SNet.IsInLobby)
			{
				if (string.IsNullOrWhiteSpace(Config.Format))
				{
					Config.Format = "LF%OpenSlots% %Rundown%%Expedition% \"%ExpeditionName%\": `%LobbyID%`";
				}
				string text4 = (GUIUtility.systemCopyBuffer = PresenceFormatter.FormatPresenceString(Config.Format));
				FeatureLogger.Notice("Copied lobby id to clipboard: " + text4);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool IsExternalMatchMakingActive()
		{
			return SNet.IsExternalMatchMakingActive;
		}

		public static void SetupViaInstance(CM_PageSettings pageSettings)
		{
			if (!((Object)(object)pageSettings == (Object)null))
			{
				_CM_PageSettings_coppyLobbyIDButton = pageSettings.m_copyLobbyIdButton;
				if ((Object)(object)_CM_PageSettings_coppyLobbyIDButton != (Object)null)
				{
					FeatureLogger.Info("Hooking CM_PageSettings Copy Lobby ID Button ...");
					SharedUtils.SetCMItemEvents(SharedUtils.RemoveCMItemEvents(_CM_PageSettings_coppyLobbyIDButton, true), (Action<int>)CopyLobbyIdToClipboard, (Action<int, bool>)null);
				}
				else
				{
					FeatureLogger.Warning("[CustomLobbyCodeString] copy lobby id button in CM_PageSettings wasn't found!!!");
				}
			}
		}

		public static void SetupViaInstance(CM_PageLoadout pageLoadout)
		{
			if (!((Object)(object)pageLoadout == (Object)null))
			{
				_CM_PageLoadout_coppyLobbyIDButton = pageLoadout.m_copyLobbyIdButton;
				if ((Object)(object)_CM_PageLoadout_coppyLobbyIDButton != (Object)null)
				{
					FeatureLogger.Info("Hooking CM_PageLoadout Copy Lobby ID Button ...");
					SharedUtils.SetCMItemEvents(SharedUtils.RemoveCMItemEvents(_CM_PageLoadout_coppyLobbyIDButton, true), (Action<int>)CopyLobbyIdToClipboard, (Action<int, bool>)null);
				}
				else
				{
					FeatureLogger.Warning("[CustomLobbyCodeString] copy lobby id button in CM_PageLoadout wasn't found!!!");
				}
			}
		}
	}
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class DisableBasePresence : Feature
	{
		private bool _firstTime = true;

		public override string Name => "Disable Built-in Rich Presence";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Presence;

		public override string Description => "Disables the Discord Rich Presence added to the game in Rundown 8.";

		public override void OnEnable()
		{
			if (Feature.DataBlocksReady)
			{
				DisableBaseDiscord();
			}
		}

		public void OnGameStateChanged(eGameStateName state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)state == 4 && _firstTime)
			{
				DisableBaseDiscord();
				_firstTime = false;
			}
		}

		public override void OnDisable()
		{
			if (!Feature.IsApplicationQuitting && Feature.DataBlocksReady)
			{
				EnableBaseDiscord();
			}
		}

		public static void DisableBaseDiscord()
		{
			DiscordManager.Current.ToggleDiscord(false);
		}

		public static void EnableBaseDiscord()
		{
			DiscordManager.Current.ToggleDiscord(true);
		}
	}
	[EnableFeatureByDefault]
	public class DiscordRichPresence : Feature
	{
		public override string Name => "Archive Discord Rich Presence";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Presence;

		public override string Description => "Show the current game state in detail on discord.";

		public static IArchiveLogger FeatureLogger { get; set; }

		public override bool InlineSettingsIntoParentMenu => true;

		public override bool SkipInitialOnEnable => true;

		public override Type[] ExternalLocalizedTypes => new Type[1] { typeof(RichPresenceSettings) };

		[FeatureConfig]
		public static RichPresenceSettings DiscordRPCSettings { get; set; }

		public override void Init()
		{
			DiscordRPCSettings = DiscordRPCSettings?.FillDefaultDictValues();
			PresenceManager.UpdateGameState((PresenceGameState)0);
		}

		public override void OnEnable()
		{
			if (!Feature.DataBlocksReady || ArchiveDiscordManager.IsEnabled)
			{
				return;
			}
			try
			{
				ArchiveDiscordManager.RenewPartyGuid();
				ArchiveDiscordManager.OnActivityJoin += DiscordManager_OnActivityJoin;
				ArchiveDiscordManager.Enable(DiscordRPCSettings);
			}
			catch (Exception ex)
			{
				FeatureLogger.Exception(ex);
			}
		}

		public void OnGameStateChanged(eGameStateName state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)state == 4)
			{
				FeatureLogger.Debug("Creating a new Party GUID.");
				ArchiveDiscordManager.RenewPartyGuid();
			}
		}

		public override void OnDatablocksReady()
		{
			((Feature)this).OnEnable();
		}

		private static void DiscordManager_OnActivityJoin(string secret)
		{
			if (ulong.TryParse(secret, out var result) && result != 0L)
			{
				CM_Utils.JoinLobby(result, Action.op_Implicit((Action)delegate
				{
					FeatureLogger.Success("Successfully joined lobby \"" + secret + "\"!");
				}), Action.op_Implicit((Action)delegate
				{
					FeatureLogger.Fail("Failed to join lobby \"" + secret + "\".");
				}));
			}
		}

		public override void OnDisable()
		{
			if (!ArchiveDiscordManager.IsEnabled)
			{
				return;
			}
			try
			{
				ArchiveDiscordManager.OnActivityJoin -= DiscordManager_OnActivityJoin;
				ArchiveDiscordManager.Disable();
			}
			catch (Exception ex)
			{
				FeatureLogger.Exception(ex);
			}
		}

		public override void Update()
		{
			ArchiveDiscordManager.Update();
		}
	}
	[EnableFeatureByDefault]
	[HideInModSettings]
	public class ReactorDiscordRPC : Feature
	{
		public enum ReactorTypes
		{
			Error,
			Startup,
			Shutdown
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class LG_WardenObjective_Reactor_Start_Patch
		{
			public static void Postfix(LG_WardenObjective_Reactor __instance)
			{
				ReactorsInLevel.Add(__instance);
				FeatureLogger.Debug("Added Reactor to Set: " + GetReactorItemKey(__instance));
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class LG_WardenObjective_Reactor_OnDestroy_Patch
		{
			public static void Postfix(LG_WardenObjective_Reactor __instance)
			{
				LG_WardenObjective_Reactor val = ((IEnumerable<LG_WardenObjective_Reactor>)ReactorsInLevel).FirstOrDefault((Func<LG_WardenObjective_Reactor, bool>)((LG_WardenObjective_Reactor reactor) => GetReactorItemKey(reactor) == GetReactorItemKey(__instance)));
				ReactorsInLevel.Remove(val);
				FeatureLogger.Debug("Removed Reactor from Set: " + GetReactorItemKey(val));
			}
		}

		private static IValueAccessor<LG_WardenObjective_Reactor, float> A_m_currentWaveProgress;

		private static IValueAccessor<LG_WardenObjective_Reactor, float> A_m_currentDuration;

		private static IValueAccessor<LG_WardenObjective_Reactor, int> A_m_currentWaveCount;

		private static IValueAccessor<LG_WardenObjective_Reactor, int> A_m_waveCountMax;

		private static IValueAccessor<LG_WardenObjective_Reactor, string> A_m_itemKey;

		private static IValueAccessor<LG_WardenObjective_Reactor, ReactorWaveData> A_m_currentWaveData;

		private static IValueAccessor<LG_WardenObjective_Reactor, pReactorState> A_m_currentState;

		private static readonly HashSet<eReactorStatus> _idleReactorStatuses = new HashSet<eReactorStatus>
		{
			Utils.GetEnumFromName<eReactorStatus>("Inactive_Idle"),
			Utils.GetEnumFromName<eReactorStatus>("Active_Idle")
		};

		private static int _lastFrameCount = 0;

		private static LG_WardenObjective_Reactor _lastReturnedActiveReactor;

		public override string Name => "ReactorDiscordRPC";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Presence;

		public static IArchiveLogger FeatureLogger { get; set; }

		[PresenceFormatProvider("ReactorWaveCountMax")]
		public static int ReactorWaveCountMax => GetWaveCountMax(GetActiveReactor());

		[PresenceFormatProvider("ReactorWaveCountCurrent")]
		public static int ReactorWaveCountCurrent => GetCurrentWaveCount(GetActiveReactor());

		[PresenceFormatProvider("ReactorWaveSecondsRemaining")]
		public static float ReactorWaveSecondsRemaining => GetWaveSecondsRemaining(GetActiveReactor());

		[PresenceFormatProvider("ReactorType")]
		public static string ReactorType => GetReactorType(GetActiveReactor()).ToString();

		[PresenceFormatProvider("ReactorWaveEndTime")]
		public static long ReactorWaveEndTime => DateTimeOffset.UtcNow.ToUnixTimeSeconds() + (long)GetWaveSecondsRemaining(GetActiveReactor());

		[PresenceFormatProvider("IsReactorActive")]
		public static bool IsReactorActive
		{
			get
			{
				LG_WardenObjective_Reactor activeReactor;
				return TryGetActiveReactor(out activeReactor);
			}
		}

		[PresenceFormatProvider("IsReactorInIntro")]
		public static bool IsReactorInIntro => IsReactorInStatus(GetActiveReactor(), (eReactorStatus)2, (eReactorStatus)6);

		[PresenceFormatProvider("IsReactorWaveOrChaosActive")]
		public static bool IsReactorWaveOrChaosActive => IsReactorInStatus(GetActiveReactor(), (eReactorStatus)3, (eReactorStatus)8);

		[PresenceFormatProvider("IsReactorAwaitingVerify")]
		public static bool IsReactorAwaitingVerify => IsReactorInStatus(GetActiveReactor(), (eReactorStatus)4, (eReactorStatus)7);

		[PresenceFormatProvider("IsReactorCompleted")]
		public static bool IsReactorCompleted => IsReactorInStatus(GetActiveReactor(), (eReactorStatus)5, (eReactorStatus)9);

		[PresenceFormatProvider("IsReactorTypeStartup")]
		public static bool IsReactorTypeStartup => GetReactorType(GetActiveReactor()) == ReactorTypes.Startup;

		[PresenceFormatProvider("IsReactorInVerifyFailState")]
		public static bool IsReactorInVerifyFailState
		{
			get
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if (!TryGetReactorState(GetActiveReactor(), out var state))
				{
					return false;
				}
				return state.verifyFailed;
			}
		}

		[PresenceFormatProvider("ReactorVerificationString")]
		public static string ReactorVerificationString
		{
			get
			{
				bool isTerminal;
				string nextCodeOrTerminalSerial = GetNextCodeOrTerminalSerial(GetActiveReactor(), out isTerminal);
				if (isTerminal)
				{
					return "LOG in " + nextCodeOrTerminalSerial;
				}
				return "Free Code: " + nextCodeOrTerminalSerial.ToUpper();
			}
		}

		public static HashSet<LG_WardenObjective_Reactor> ReactorsInLevel { get; } = new HashSet<LG_WardenObjective_Reactor>();


		public override 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_0008: Unknown result type (might be due to invalid IL or missing references)
			GameBuildInfo buildInfo = Feature.BuildInfo;
			if (RundownFlagsExtensions.IsIncludedIn(((GameBuildInfo)(ref buildInfo)).Rundown, (RundownFlags)1))
			{
				A_m_currentWaveProgress = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, float>("m_currentStateProgress", false);
				A_m_currentDuration = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, float>("m_currentStateDuration", false);
				A_m_currentWaveCount = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, int>("m_currentStateCount", false);
				A_m_waveCountMax = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, int>("m_stateCountMax", false);
			}
			else
			{
				A_m_currentWaveProgress = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, float>("m_currentWaveProgress", false);
				A_m_currentDuration = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, float>("m_currentDuration", false);
				A_m_currentWaveCount = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, int>("m_currentWaveCount", false);
				A_m_waveCountMax = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, int>("m_waveCountMax", false);
			}
			A_m_itemKey = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, string>("m_itemKey", false);
			A_m_currentWaveData = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, ReactorWaveData>("m_currentWaveData", false);
			A_m_currentState = AccessorBase.GetValueAccessor<LG_WardenObjective_Reactor, pReactorState>("m_currentState", false);
			PresenceFormatter.RegisterAllPresenceFormatProviders(typeof(ReactorDiscordRPC), true);
		}

		public static string GetNextCodeOrTerminalSerial(LG_WardenObjective_Reactor reactor, out bool isTerminal)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			isTerminal = false;
			if ((Object)(object)reactor == (Object)null)
			{
				return "Error";
			}
			GameBuildInfo buildInfo = Feature.BuildInfo;
			if (RundownFlagsExtensions.IsIncludedIn(((GameBuildInfo)(ref buildInfo)).Rundown, RundownFlagsExtensions.ToLatest((RundownFlags)2)))
			{
				return GetNextCodeOrTerminalR2(reactor, out isTerminal);
			}
			return reactor.CurrentStateOverrideCode;
		}

		public static string GetNextCodeOrTerminalR2(LG_WardenObjective_Reactor reactor, out bool isTerminal)
		{
			isTerminal = false;
			if ((Object)(object)reactor == (Object)null)
			{
				return "Error";
			}
			ReactorWaveData val = A_m_currentWaveData.Get(reactor);
			if (val.HasVerificationTerminal)
			{
				isTerminal = true;
				return val.VerificationTerminalSerial;
			}
			return reactor.CurrentStateOverrideCode;
		}

		public static bool IsReactorInStatus(LG_WardenObjective_Reactor reactor, params eReactorStatus[] statuses)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between I4 and Unknown
			if (!TryGetReactorStatus(reactor, out var status))
			{
				return false;
			}
			for (int i = 0; i < statuses.Length; i++)
			{
				if ((int)statuses[i] == (int)status)
				{
					return true;
				}
			}
			return false;
		}

		public static bool TryGetReactorStatus(LG_WardenObjective_Reactor reactor, out eReactorStatus status)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected I4, but got Unknown
			if ((Object)(object)reactor == (Object)null || !TryGetReactorState(reactor, out var state))
			{
				status = (eReactorStatus)0;
				return false;
			}
			status = (eReactorStatus)(int)state.status;
			return true;
		}

		public static int GetCurrentWaveCount(LG_WardenObjective_Reactor reactor)
		{
			if ((Object)(object)reactor == (Object)null)
			{
				return -1;
			}
			return A_m_currentWaveCount.Get(reactor);
		}

		public static int GetWaveCountMax(LG_WardenObjective_Reactor reactor)
		{
			if ((Object)(object)reactor == (Object)null)
			{
				return -1;
			}
			return A_m_waveCountMax.Get(reactor);
		}

		public static float GetWaveSecondsRemaining(LG_WardenObjective_Reactor reactor)
		{
			if ((Object)(object)reactor == (Object)null)
			{
				return -1f;
			}
			return (1f - A_m_currentWaveProgress.Get(reactor)) * A_m_currentDuration.Get(reactor);
		}

		public static ReactorTypes GetReactorType(LG_WardenObjective_Reactor reactor)
		{
			if (TryGetReactorState(reactor, out var state))
			{
				if (((object)(eReactorStatus)(ref state.status)).ToString().StartsWith("Start"))
				{
					return ReactorTypes.Startup;
				}
				if (((object)(eReactorStatus)(ref state.status)).ToString().StartsWith("Shut"))
				{
					return ReactorTypes.Shutdown;
				}
			}
			return ReactorTypes.Error;
		}

		public static bool TryGetReactorState(LG_WardenObjective_Reactor reactor, out pReactorState state)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)reactor == (Object)null)
			{
				state = default(pReactorState);
				return false;
			}
			state = A_m_currentState.Get(reactor);
			return true;
		}

		public static LG_WardenObjective_Reactor GetActiveReactor()
		{
			int frameCount = Time.frameCount;
			if (_lastFrameCount == frameCount)
			{
				return _lastReturnedActiveReactor;
			}
			pReactorState state;
			LG_WardenObjective_Reactor? obj = ((IEnumerable<LG_WardenObjective_Reactor>)ReactorsInLevel).FirstOrDefault((Func<LG_WardenObjective_Reactor, bool>)((LG_WardenObjective_Reactor reactor) => TryGetReactorState(reactor, out state) && !_idleReactorStatuses.Contains(state.status)));
			_lastFrameCount = frameCount;
			_lastReturnedActiveReactor = obj;
			return obj;
		}

		public static bool TryGetActiveReactor(out LG_WardenObjective_Reactor activeReactor)
		{
			activeReactor = GetActiveReactor();
			return (Object)(object)activeReactor != (Object)null;
		}

		public static string GetReactorItemKey(LG_WardenObjective_Reactor reactor)
		{
			return A_m_itemKey.Get(reactor);
		}
	}
	[EnableFeatureByDefault]
	[HideInModSettings]
	public class RichPresenceCore : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class RundownManager__GetUniqueExpeditionKey__Patch
		{
			public static void Postfix(string rundownKey, eRundownTier tier, int expIndex)
			{
				ExpeditionNumber = expIndex + 1;
			}
		}

		public override string Name => "Rich Presence Core";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Presence;

		public override string Description => "Updates the Presence Game State and provides some values via patches.";

		[PresenceFormatProvider("EquippedMeleeWeaponName")]
		public static string EquippedMeleeWeaponName => ItemNameForSlot((InventorySlot)10);

		[PresenceFormatProvider("EquippedMeleeWeaponID")]
		public static string EquippedMeleeWeaponID => ItemIDForSlot((InventorySlot)10);

		[PresenceFormatProvider("EquippedToolName")]
		public static string EquippedToolName => ItemNameForSlot((InventorySlot)3);

		[PresenceFormatProvider("EquippedToolID")]
		public static string EquippedToolID => ItemIDForSlot((InventorySlot)3);

		private static PlayerAmmoStorage LocalAmmo
		{
			get
			{
				PlayerBackpack localBackpack = PlayerBackpackManager.LocalBackpack;
				if (localBackpack == null)
				{
					return null;
				}
				return localBackpack.AmmoStorage;
			}
		}

		[PresenceFormatProvider("HealthRaw")]
		public static float HealthRaw
		{
			get
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				float? obj;
				if (localPlayerAgent == null)
				{
					obj = null;
				}
				else
				{
					Dam_PlayerDamageBase damage = localPlayerAgent.Damage;
					obj = ((damage != null) ? new float?(((Dam_SyncedDamageBase)damage).Health) : null);
				}
				float? num = obj;
				return num.GetValueOrDefault(-1f);
			}
		}

		[PresenceFormatProvider("MaxHealthRaw")]
		public static float MaxHealthRaw
		{
			get
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				float? obj;
				if (localPlayerAgent == null)
				{
					obj = null;
				}
				else
				{
					Dam_PlayerDamageBase damage = localPlayerAgent.Damage;
					obj = ((damage != null) ? new float?(((Dam_SyncedDamageBase)damage).HealthMax) : null);
				}
				float? num = obj;
				return num.GetValueOrDefault(-1f);
			}
		}

		[PresenceFormatProvider("ToolAmmo")]
		public static int ToolAmmo
		{
			get
			{
				PlayerAmmoStorage localAmmo = LocalAmmo;
				int? obj;
				if (localAmmo == null)
				{
					obj = null;
				}
				else
				{
					InventorySlotAmmo classAmmo = localAmmo.ClassAmmo;
					obj = ((classAmmo != null) ? new int?(classAmmo.BulletsInPack) : null);
				}
				int? num = obj;
				return num.GetValueOrDefault(-1);
			}
		}

		[PresenceFormatProvider("MaxToolAmmo")]
		public static int MaxToolAmmo
		{
			get
			{
				PlayerAmmoStorage localAmmo = LocalAmmo;
				int? obj;
				if (localAmmo == null)
				{
					obj = null;
				}
				else
				{
					InventorySlotAmmo classAmmo = localAmmo.ClassAmmo;
					obj = ((classAmmo != null) ? new int?(classAmmo.BulletsMaxCap) : null);
				}
				int? num = obj;
				return num.GetValueOrDefault(-1);
			}
		}

		[PresenceFormatProvider("PrimaryAmmo")]
		public static int PrimaryAmmo
		{
			get
			{
				PlayerAmmoStorage localAmmo = LocalAmmo;
				int? obj;
				if (localAmmo == null)
				{
					obj = null;
				}
				else
				{
					InventorySlotAmmo standardAmmo = localAmmo.StandardAmmo;
					obj = ((standardAmmo != null) ? new int?(standardAmmo.BulletsInPack) : null);
				}
				int? num = obj;
				return num.GetValueOrDefault(-1) + GetClip((InventorySlot)1);
			}
		}

		[PresenceFormatProvider("MaxPrimaryAmmo")]
		public static int MaxPrimaryAmmo
		{
			get
			{
				PlayerAmmoStorage localAmmo = LocalAmmo;
				int? obj;
				if (localAmmo == null)
				{
					obj = null;
				}
				else
				{
					InventorySlotAmmo standardAmmo = localAmmo.StandardAmmo;
					obj = ((standardAmmo != null) ? new int?(standardAmmo.BulletsMaxCap) : null);
				}
				int? num = obj;
				return num.GetValueOrDefault(-1);
			}
		}

		[PresenceFormatProvider("SpecialAmmo")]
		public static int SpecialAmmo
		{
			get
			{
				PlayerAmmoStorage localAmmo = LocalAmmo;
				int? obj;
				if (localAmmo == null)
				{
					obj = null;
				}
				else
				{
					InventorySlotAmmo specialAmmo = localAmmo.SpecialAmmo;
					obj = ((specialAmmo != null) ? new int?(specialAmmo.BulletsInPack) : null);
				}
				int? num = obj;
				return num.GetValueOrDefault(-1) + GetClip((InventorySlot)2);
			}
		}

		[PresenceFormatProvider("MaxSpecialAmmo")]
		public static int MaxSpecialAmmo
		{
			get
			{
				PlayerAmmoStorage localAmmo = LocalAmmo;
				int? obj;
				if (localAmmo == null)
				{
					obj = null;
				}
				else
				{
					InventorySlotAmmo specialAmmo = localAmmo.SpecialAmmo;
					obj = ((specialAmmo != null) ? new int?(specialAmmo.BulletsMaxCap) : null);
				}
				int? num = obj;
				return num.GetValueOrDefault(-1);
			}
		}

		[PresenceFormatProvider("HasLobby")]
		public static bool HasLobby
		{
			get
			{
				SNet_Lobby lobby = SNet.Lobby;
				if (lobby == null)
				{
					return false;
				}
				SNet_LobbyIdentifier identifier = lobby.Identifier;
				if (identifier == null)
				{
					return false;
				}
				_ = identifier.ID;
				return true;
			}
		}

		[PresenceFormatProvider("LobbyID")]
		public static string LobbyID
		{
			get
			{
				SNet_Lobby lobby = SNet.Lobby;
				object obj;
				if (lobby == null)
				{
					obj = null;
				}
				else
				{
					SNet_LobbyIdentifier identifier = lobby.Identifier;
					obj = ((identifier != null) ? identifier.ID.ToString() : null);
				}
				if (obj == null)
				{
					obj = "0123456789";
				}
				return (string)obj;
			}
		}

		[PresenceFormatProvider("LocalCharacterID")]
		public static int LocalCharacterID
		{
			get
			{
				try
				{
					PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
					return (localPlayerAgent != null) ? localPlayerAgent.CharacterID : 0;
				}
				catch (Exception)
				{
					return 0;
				}
			}
		}

		[PresenceFormatProvider("OpenSlots")]
		public static int OpenSlots => MaxPlayerSlots - GetPlayerCount();

		[PresenceFormatProvider("MaxPlayerSlots")]
		public static int MaxPlayerSlots => GetMaxPlayers();

		[PresenceFormatProvider("ExpeditionTier")]
		public static string ExpeditionTier
		{
			get
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: 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)
				ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
				object obj;
				if (activeExpedition == null)
				{
					obj = null;
				}
				else
				{
					DescriptiveData descriptive = activeExpedition.Descriptive;
					obj = ((descriptive != null) ? descriptive.Prefix : null);
				}
				if (obj == null)
				{
					obj = "?";
				}
				string text = (string)obj;
				GameBuildInfo buildInfo = Feature.BuildInfo;
				if (RundownFlagsExtensions.IsIncludedIn(((GameBuildInfo)(ref buildInfo)).Rundown, (RundownFlags)6) && text.Length > 2)
				{
					return text.Substring(2);
				}
				return text;
			}
		}

		[PresenceFormatProvider("ExpeditionTierIsSpecial")]
		public static bool ExpeditionTierIsSpecial
		{
			get
			{
				if (Is.R6OrLater)
				{
					return IsActiveExpeditionSpecial();
				}
				return false;
			}
		}

		[PresenceFormatProvider("ExpeditionSkipExpNumberInName")]
		public static bool ExpeditionSkipExpNumberInName
		{
			get
			{
				try
				{
					if (Is.R6OrLater)
					{
						return ShouldSkipExpNumberInName();
					}
				}
				catch
				{
				}
				return false;
			}
		}

		[PresenceFormatProvider("ExpeditionNumber")]
		public static int ExpeditionNumber { get; set; }

		[PresenceFormatProvider("ExpeditionName")]
		public static string ExpeditionName
		{
			get
			{
				ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
				object obj;
				if (activeExpedition == null)
				{
					obj = null;
				}
				else
				{
					DescriptiveData descriptive = activeExpedition.Descriptive;
					obj = ((descriptive != null) ? descriptive.PublicName : null);
				}
				if (obj == null)
				{
					obj = "???";
				}
				return (string)obj;
			}
		}

		[PresenceFormatProvider("ZonePrefix")]
		public static string ZonePrefix
		{
			get
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				object obj;
				if (localPlayerAgent == null)
				{
					obj = null;
				}
				else
				{
					AIG_CourseNode courseNode = ((Agent)localPlayerAgent).CourseNode;
					if (courseNode == null)
					{
						obj = null;
					}
					else
					{
						LG_Zone zone = courseNode.m_zone;
						if (zone == null)
						{
							obj = null;
						}
						else
						{
							LG_NavInfo navInfo = zone.NavInfo;
							obj = ((navInfo != null) ? navInfo.PrefixShort : null);
						}
					}
				}
				if (obj == null)
				{
					obj = "?";
				}
				return (string)obj;
			}
		}

		[PresenceFormatProvider("ZonePrefixLong")]
		public static string ZonePrefixLong
		{
			get
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				object obj;
				if (localPlayerAgent == null)
				{
					obj = null;
				}
				else
				{
					AIG_CourseNode courseNode = ((Agent)localPlayerAgent).CourseNode;
					if (courseNode == null)
					{
						obj = null;
					}
					else
					{
						LG_Zone zone = courseNode.m_zone;
						if (zone == null)
						{
							obj = null;
						}
						else
						{
							LG_NavInfo navInfo = zone.NavInfo;
							obj = ((navInfo != null) ? navInfo.PrefixLong : null);
						}
					}
				}
				if (obj == null)
				{
					obj = "?";
				}
				return (string)obj;
			}
		}

		[PresenceFormatProvider("ZoneAlias")]
		public static string ZoneAlias
		{
			get
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				object obj;
				if (localPlayerAgent == null)
				{
					obj = null;
				}
				else
				{
					AIG_CourseNode courseNode = ((Agent)localPlayerAgent).CourseNode;
					if (courseNode == null)
					{
						obj = null;
					}
					else
					{
						LG_Zone zone = courseNode.m_zone;
						if (zone == null)
						{
							obj = null;
						}
						else
						{
							LG_NavInfo navInfo = zone.NavInfo;
							obj = ((navInfo != null) ? navInfo.Number.ToString() : null);
						}
					}
				}
				if (obj == null)
				{
					obj = "?";
				}
				return (string)obj;
			}
		}

		[PresenceFormatProvider("AreaSuffix")]
		public static string AreaSuffix
		{
			get
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				object obj;
				if (localPlayerAgent == null)
				{
					obj = null;
				}
				else
				{
					AIG_CourseNode courseNode = ((Agent)localPlayerAgent).CourseNode;
					if (courseNode == null)
					{
						obj = null;
					}
					else
					{
						LG_Area area = courseNode.m_area;
						if (area == null)
						{
							obj = null;
						}
						else
						{
							LG_NavInfo navInfo = area.m_navInfo;
							obj = ((navInfo != null) ? navInfo.Suffix : null);
						}
					}
				}
				if (obj == null)
				{
					obj = "?";
				}
				return (string)obj;
			}
		}

		[PresenceFormatProvider("RundownTitleFromDataBlocks")]
		public static string RundownTitleFromDataBlocks => SharedUtils.GetDataBlockRundownTitle();

		public override void Init()
		{
			PresenceFormatter.RegisterAllPresenceFormatProviders(typeof(RichPresenceCore), true);
		}

		public void OnGameStateChanged(eGameStateName nextState)
		{
			//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_003c: Expected I4, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			switch (nextState - 4)
			{
			case 0:
				PresenceManager.UpdateGameState((PresenceGameState)1, (int)PresenceManager.CurrentState == 0);
				break;
			case 1:
			case 12:
				PresenceManager.UpdateGameState((PresenceGameState)2);
				break;
			case 2:
				PresenceManager.UpdateGameState((PresenceGameState)3);
				break;
			case 3:
				PresenceManager.UpdateGameState((PresenceGameState)4, keepTimer: true);
				break;
			case 6:
				PresenceManager.UpdateGameState((PresenceGameState)5, (int)PresenceManager.CurrentState == 6);
				break;
			case 11:
				PresenceManager.UpdateGameState((PresenceGameState)6, keepTimer: true);
				break;
			case 10:
				PresenceManager.UpdateGameState((PresenceGameState)7, keepTimer: true);
				break;
			case 4:
			case 5:
			case 7:
			case 8:
			case 9:
				break;
			}
		}

		public static string ItemNameForSlot(InventorySlot slot)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			BackpackItem val = null;
			PlayerBackpack localBackpack = PlayerBackpackManager.LocalBackpack;
			if (localBackpack != null && localBackpack.TryGetBackpackItem(slot, ref val))
			{
				if (val == null)
				{
					return null;
				}
				GearIDRange gearIDRange = val.GearIDRange;
				if (gearIDRange == null)
				{
					return null;
				}
				return gearIDRange.PublicGearName;
			}
			return null;
		}

		public static string ItemIDForSlot(InventorySlot slot)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			BackpackItem val = null;
			PlayerBackpack localBackpack = PlayerBackpackManager.LocalBackpack;
			if (localBackpack != null && localBackpack.TryGetBackpackItem(slot, ref val))
			{
				if (val == null)
				{
					return null;
				}
				GearIDRange gearIDRange = val.GearIDRange;
				if (gearIDRange == null)
				{
					return null;
				}
				return gearIDRange.PlayfabItemId;
			}
			return null;
		}

		private static int GetClip(InventorySlot slot)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			BackpackItem val = null;
			PlayerBackpack localBackpack = PlayerBackpackManager.LocalBackpack;
			if (localBackpack != null && localBackpack.TryGetBackpackItem(slot, ref val))
			{
				int? obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					Item instance = val.Instance;
					if (instance == null)
					{
						obj = null;
					}
					else
					{
						ItemEquippable obj2 = ((Il2CppObjectBase)instance).TryCast<ItemEquippable>();
						obj = ((obj2 != null) ? new int?(obj2.GetCurrentClip()) : null);
					}
				}
				int? num = obj;
				return num.GetValueOrDefault(-1);
			}
			return -1;
		}

		private static int GetPlayerCount()
		{
			if (Is.R6OrLater)
			{
				return GetPlayerCountR6Plus();
			}
			SNet_Lobby lobby = SNet.Lobby;
			return ((lobby == null) ? null : lobby.Players?.Count).GetValueOrDefault(1);
		}

		private static int GetPlayerCountR6Plus()
		{
			SNet_Lobby lobby = SNet.Lobby;
			int? obj;
			if (lobby == null)
			{
				obj = null;
			}
			else
			{
				List<SNet_Player> players = lobby.Players;
				obj = ((players == null) ? null : SharedUtils.ToSystemList<SNet_Player>(players)?.Where((SNet_Player ply) => !ply.IsBot)?.Count());
			}
			int? num = obj;
			return num.GetValueOrDefault(1);
		}

		private static int GetMaxPlayers()
		{
			if (Is.R6OrLater)
			{
				return GetMaxPlayersR6Plus();
			}
			return ((Il2CppArrayBase<SNet_Slot>)(object)SNet.Slots.PlayerSlots).Count;
		}

		private static int GetMaxPlayersR6Plus()
		{
			int num = 0;
			int count = ((Il2CppArrayBase<SNet_Slot>)(object)SNet.Slots.PlayerSlots).Count;
			for (int i = 0; i < count; i++)
			{
				if (SNet.Slots.IsBotPermittedInSlot(i) || SNet.Slots.IsHumanPermittedInSlot(i))
				{
					num++;
				}
			}
			if (num != 0)
			{
				return num;
			}
			return count;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		public static bool IsActiveExpeditionSpecial()
		{
			ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
			bool? obj;
			if (activeExpedition == null)
			{
				obj = null;
			}
			else
			{
				DescriptiveData descriptive = activeExpedition.Descriptive;
				obj = ((descriptive != null) ? new bool?(descriptive.IsExtraExpedition) : null);
			}
			bool? flag = obj;
			return flag.GetValueOrDefault();
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		public static bool ShouldSkipExpNumberInName()
		{
			ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
			bool? obj;
			if (activeExpedition == null)
			{
				obj = null;
			}
			else
			{
				DescriptiveData descriptive = activeExpedition.Descriptive;
				obj = ((descriptive != null) ? new bool?(descriptive.SkipExpNumberInName) : null);
			}
			bool? flag = obj;
			return flag.GetValueOrDefault();
		}
	}
	[EnableFeatureByDefault]
	public class SteamRichPresenceTweaks : Feature
	{
		public class SteamRPCSettings
		{
			[FSDisplayName("Disable <color=orange>ALL</color> of Steam RPC")]
			[FSDescription("Enabling this will completely disable relaying your current in-game status as well as <b>prevent anyone from joining on you via steam</b>.")]
			public bool DisableSteamRPC { get; set; }

			[FSDisplayName("Custom Status Format")]
			public string CustomSteamRPCFormat { get; set; } = "%Rundown%%Expedition% \"%ExpeditionName%\"";

		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class SNet_Core_STEAM_SetFriendsDataPatch
		{
			public static void Prefix(FriendsDataType type, ref string data)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Invalid comparison between Unknown and I4
				if (Config.DisableSteamRPC)
				{
					data = string.Empty;
				}
				else if ((int)type == 1)
				{
					data = PresenceFormatter.FormatPresenceString(Config.CustomSteamRPCFormat) ?? "";
				}
			}
		}

		public override string Name => "Steam Rich Presence Tweaks";

		public override GroupBase Group => (GroupBase)(object)GroupManager.Presence;

		public override string Description => "Set a custom text for Steams' presence system.";

		[FeatureConfig]
		public static SteamRPCSettings Config { get; set; }
	}
}
namespace TheArchive.Core
{
	public static class DRPIcons
	{
		public static class Weapons
		{
			private static string WeaponPrefix => "weapon_";

			public static string HeavyDutyHammer => WeaponPrefix + "hammer";

			public static string Knife => WeaponPrefix + "knife";

			public static string Bat => WeaponPrefix + "bat";

			public static string Spear => WeaponPrefix + "spear";

			public static string Maul => WeaponPrefix + "maul";

			public static string Sledge => WeaponPrefix + "sledge";

			public static string Gavel => WeaponPrefix + "gavel";

			public static string Mallet => WeaponPrefix + "mallet";
		}

		public static class Tools
		{
			private static string ToolPrefix => "tool_";

			public static string Biotracker => ToolPrefix + "bio";

			public static string CFoamLauncher => ToolPrefix + "glue";

			public static string MineDeployer => ToolPrefix + "mine";

			public static string SentryGun => ToolPrefix + "sentry";
		}

		public static class Resources
		{
			private static string ResourcePrefix => "res_";

			public static string Ammo => ResourcePrefix + "ammo";

			public static string Tool => ResourcePrefix + "tool";

			public static string Meds => ResourcePrefix + "meds";
		}

		public static class Expedition
		{
			public static string ElevatorDropping => "icon_dropping";

			public static string Failed => "icon_failed";

			public static string Survived => "icon_survived";

			public static string Lobby => "icon_lobby";

			public static string Reactor => "icon_reactor";
		}

		public static class Characters
		{
			private static string CharacterPrefix => "char_";

			public static string Woods => CharacterPrefix + "woods";

			public static string Dauda => CharacterPrefix + "dauda";

			public static string Hackett => CharacterPrefix + "hackett";

			public static string Bishop => CharacterPrefix + "bishop";
		}

		public static string GTFOIcon => "gtfo_icon";

		public static string Debug => "please_just_work";

		public static string EnemyPing => "icon_enemy";
	}
}
namespace TheArchive.Core.Settings
{
	public class RichPresenceSettings
	{
		public class GSTopActivity : GSActivity
		{
			public List<GSSubActivity> SubActivities = new List<GSSubActivity>();

			[JsonIgnore]
			public bool HasSubActivities => (SubActivities?.Count ?? 0) > 0;

			public GSTopActivity FillDefaultDictValues(PresenceGameState state)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				RichPresenceSettings @default = Default;
				if (!base.HasActivities)
				{
					@default.DiscordRPCFormat.TryGetValue(state, out var value);
					Formats = value.Formats;
					if (!HasSubActivities && value.HasSubActivities)
					{
						foreach (GSSubActivity subActivity in value.SubActivities)
						{
							SubActivities.Add(subActivity);
						}
					}
				}
				return this;
			}
		}

		public class GSSubActivity : GSActivity
		{
			public List<string> DisplayConditions = new List<string>();

			public bool DisplayConditionsAnyMode;
		}

		public class GSActivity
		{
			public List<GSActivityFormat> Formats = new List<GSActivityFormat>();

			[JsonIgnore]
			public bool HasActivities
			{
				get
				{
					List<GSActivityFormat> formats = Formats;
					if (formats == null)
					{
						return false;
					}
					return formats.Count > 0;
				}
			}

			[JsonIgnore]
			public bool IsMultiFormat
			{
				get
				{
					List<GSActivityFormat> formats = Formats;
					if (formats == null)
					{
						return false;
					}
					return formats.Count > 1;
				}
			}

			[JsonIgnore]
			public int Count => Formats?.Count ?? 0;

			[JsonIgnore]
			public int MultiIndex { get; private set; }

			[JsonIgnore]
			public int CurrentMultiCycleCurrency { get; private set; } = 10;


			public int MultiFormatCycleTime { get; set; } = 10;


			public GSActivityFormat GetNext()
			{
				if (!IsMultiFormat)
				{
					return Formats[0];
				}
				if (MultiIndex >= Count)
				{
					MultiIndex = 0;
				}
				GSActivityFormat result = Formats[MultiIndex];
				CurrentMultiCycleCurrency -= 5;
				if (CurrentMultiCycleCurrency <= 0)
				{
					MultiIndex++;
					CurrentMultiCycleCurrency = MultiFormatCycleTime;
				}
				return result;
			}
		}

		public class GSActivityFormat
		{
			public string Details { get; set; } = "DefaultDetailsFormatString";


			public string Status { get; set; } = "DefaultStatusFormatString";


			public GSActivityAssets Assets { get; set; }

			public bool DisplayStateTimeElapsed { get; set; } = true;


			public string CustomTimeProvider { get; set; } = "";


			public bool CustomProviderIsEndTime { get; set; } = true;


			public bool DisplayPartyInfo { get; set; }
		}

		public class GSActivityAssets
		{
			public string LargeImageKey { get; set; } = "please_just_work";


			public string LargeTooltip { get; set; } = "Default Large Tooltip";


			public string SmallImageKey { get; set; }

			public string SmallTooltip { get; set; }
		}

		public Dictionary<PresenceGameState, GSTopActivity> DiscordRPCFormat = new Dictionary<PresenceGameState, GSTopActivity>
		{
			{
				(PresenceGameState)0,
				new GSTopActivity
				{
					Formats = new List<GSActivityFormat>
					{
						new GSActivityFormat
						{
							Details = "Initializing ...",
							Status = "Waking prisoners ...",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "gtfo_icon",
								LargeTooltip = "GTFO"
							}
						}
					}
				}
			},
			{
				(PresenceGameState)1,
				new GSTopActivity
				{
					Formats = new List<GSActivityFormat>
					{
						new GSActivityFormat
						{
							Details = "%RundownWithNumberOrModdedPrefix%: \"%RundownTitle%\"",
							Status = "Deciding what to do",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "gtfo_icon",
								LargeTooltip = "GTFO"
							}
						}
					}
				}
			},
			{
				(PresenceGameState)2,
				new GSTopActivity
				{
					Formats = new List<GSActivityFormat>
					{
						new GSActivityFormat
						{
							Details = "%Rundown% %Expedition% \"%ExpeditionName%\"",
							Status = "In Lobby",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "icon_lobby",
								LargeTooltip = "GTFO %Rundown% \"%RundownTitle%\"",
								SmallImageKey = "%CharacterImageKey%",
								SmallTooltip = "Playing as %CharacterName%"
							},
							DisplayPartyInfo = true
						}
					}
				}
			},
			{
				(PresenceGameState)3,
				new GSTopActivity
				{
					MultiFormatCycleTime = 5,
					Formats = new List<GSActivityFormat>
					{
						new GSActivityFormat
						{
							Details = "%Rundown% %Expedition% \"%ExpeditionName%\"",
							Status = "Dropping .",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "icon_dropping",
								LargeTooltip = "Riding the elevator to hell ..."
							},
							DisplayPartyInfo = true
						},
						new GSActivityFormat
						{
							Details = "%Rundown% %Expedition% \"%ExpeditionName%\"",
							Status = "Dropping ..",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "icon_dropping",
								LargeTooltip = "Riding the elevator to hell ..."
							},
							DisplayPartyInfo = true
						},
						new GSActivityFormat
						{
							Details = "%Rundown% %Expedition% \"%ExpeditionName%\"",
							Status = "Dropping ...",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "icon_dropping",
								LargeTooltip = "Riding the elevator to hell ..."
							},
							DisplayPartyInfo = true
						}
					}
				}
			},
			{
				(PresenceGameState)4,
				new GSTopActivity
				{
					Formats = new List<GSActivityFormat>
					{
						new GSActivityFormat
						{
							Details = "%Rundown% %Expedition% \"%ExpeditionName%\"",
							Status = "Engaging brakes ...",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "icon_dropping",
								LargeTooltip = "Next stop: Hell"
							},
							DisplayPartyInfo = true
						}
					}
				}
			},
			{
				(PresenceGameState)5,
				new GSTopActivity
				{
					Formats = new List<GSActivityFormat>
					{
						new GSActivityFormat
						{
							Details = "%Rundown% %Expedition% \"%ExpeditionName%\"",
							Status = "In Expedition",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "gtfo_icon",
								LargeTooltip = "Exploring %CurrentZoneShort% Area %AreaSuffix%",
								SmallImageKey = "%MeleeWeaponKey%",
								SmallTooltip = "%EquippedMeleeWeaponName%"
							},
							DisplayPartyInfo = true
						},
						new GSActivityFormat
						{
							Details = "Health: %HealthPercent%%",
							Status = "In Expedition",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "gtfo_icon",
								LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\"",
								SmallImageKey = "res_meds",
								SmallTooltip = "Prisoner vitals"
							},
							DisplayPartyInfo = true
						},
						new GSActivityFormat
						{
							Details = "Primary: %PrimaryAmmoPercent%% Special: %SpecialAmmoPercent%%",
							Status = "In Expedition",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "gtfo_icon",
								LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\"",
								SmallImageKey = "res_ammo",
								SmallTooltip = "Ammo levels"
							},
							DisplayPartyInfo = true
						},
						new GSActivityFormat
						{
							Details = "Tool: %ToolAmmoPercentOrStatus%",
							Status = "In Expedition",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "%ToolKey%",
								LargeTooltip = "%EquippedToolName%",
								SmallImageKey = "res_tool",
								SmallTooltip = "Resource level"
							},
							DisplayPartyInfo = true
						}
					},
					SubActivities = new List<GSSubActivity>
					{
						new GSSubActivity
						{
							DisplayConditions = new List<string> { "%IsReactorActive%", "%IsReactorInIntro%", "%IsReactorTypeStartup%", "!%IsReactorInVerifyFailState%" },
							Formats = new List<GSActivityFormat>
							{
								new GSActivityFormat
								{
									Details = "Reactor %ReactorType% (%ReactorWaveCountCurrent%/%ReactorWaveCountMax%)",
									Status = "Warming Up!",
									Assets = new GSActivityAssets
									{
										LargeImageKey = DRPIcons.Expedition.Reactor,
										LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\""
									},
									DisplayPartyInfo = true,
									DisplayStateTimeElapsed = false,
									CustomTimeProvider = "%ReactorWaveEndTime%"
								}
							}
						},
						new GSSubActivity
						{
							DisplayConditions = new List<string> { "%IsReactorActive%", "%IsReactorInIntro%", "%IsReactorTypeStartup%", "%IsReactorInVerifyFailState%" },
							Formats = new List<GSActivityFormat>
							{
								new GSActivityFormat
								{
									Details = "%ReactorType% Sequence Failed! (%ReactorWaveCountCurrent%/%ReactorWaveCountMax%)",
									Status = "Warming Up!",
									Assets = new GSActivityAssets
									{
										LargeImageKey = DRPIcons.Expedition.Reactor,
										LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\""
									},
									DisplayPartyInfo = true,
									DisplayStateTimeElapsed = false,
									CustomTimeProvider = "%ReactorWaveEndTime%"
								}
							}
						},
						new GSSubActivity
						{
							DisplayConditions = new List<string> { "%IsReactorActive%", "%IsReactorInIntro%", "!%IsReactorTypeStartup%" },
							Formats = new List<GSActivityFormat>
							{
								new GSActivityFormat
								{
									Details = "Reactor %ReactorType% Sequence",
									Status = "Warning!",
									Assets = new GSActivityAssets
									{
										LargeImageKey = DRPIcons.Expedition.Reactor,
										LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\""
									},
									DisplayPartyInfo = true
								}
							}
						},
						new GSSubActivity
						{
							DisplayConditions = new List<string> { "%IsReactorActive%", "%IsReactorWaveOrChaosActive%", "%IsReactorTypeStartup%" },
							Formats = new List<GSActivityFormat>
							{
								new GSActivityFormat
								{
									Details = "Reactor Wave (%ReactorWaveCountCurrent%/%ReactorWaveCountMax%)",
									Status = "High Intensive Test",
									Assets = new GSActivityAssets
									{
										LargeImageKey = DRPIcons.Expedition.Reactor,
										LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\"",
										SmallImageKey = DRPIcons.EnemyPing,
										SmallTooltip = "Heavy Reactor Load"
									},
									DisplayPartyInfo = true,
									DisplayStateTimeElapsed = false,
									CustomTimeProvider = "%ReactorWaveEndTime%"
								}
							}
						},
						new GSSubActivity
						{
							DisplayConditions = new List<string> { "%IsReactorActive%", "%IsReactorWaveOrChaosActive%", "!%IsReactorTypeStartup%" },
							Formats = new List<GSActivityFormat>
							{
								new GSActivityFormat
								{
									Details = "Reactor Shutdown Failure!",
									Status = "Alarm triggered!",
									Assets = new GSActivityAssets
									{
										LargeImageKey = DRPIcons.Expedition.Reactor,
										LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\"",
										SmallImageKey = DRPIcons.EnemyPing,
										SmallTooltip = "Security System Malfunctioning"
									},
									DisplayPartyInfo = true
								}
							}
						},
						new GSSubActivity
						{
							DisplayConditions = new List<string> { "%IsReactorActive%", "%IsReactorAwaitingVerify%", "%IsReactorTypeStartup%" },
							Formats = new List<GSActivityFormat>
							{
								new GSActivityFormat
								{
									Details = "%ReactorVerificationString% (%ReactorWaveCountCurrent%/%ReactorWaveCountMax%)",
									Status = "Verification Required!",
									Assets = new GSActivityAssets
									{
										LargeImageKey = DRPIcons.Expedition.Reactor,
										LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\""
									},
									DisplayPartyInfo = true,
									DisplayStateTimeElapsed = false,
									CustomTimeProvider = "%ReactorWaveEndTime%"
								}
							}
						},
						new GSSubActivity
						{
							DisplayConditions = new List<string> { "%IsReactorActive%", "%IsReactorAwaitingVerify%", "!%IsReactorTypeStartup%" },
							Formats = new List<GSActivityFormat>
							{
								new GSActivityFormat
								{
									Details = "Initiating Shutdown Sequence ...",
									Status = "Verification Required!",
									Assets = new GSActivityAssets
									{
										LargeImageKey = DRPIcons.Expedition.Reactor,
										LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\""
									},
									DisplayPartyInfo = true
								}
							}
						},
						new GSSubActivity
						{
							DisplayConditions = new List<string> { "%IsReactorActive%", "%IsReactorCompleted%" },
							Formats = new List<GSActivityFormat>
							{
								new GSActivityFormat
								{
									Details = "Reactor %ReactorType% Sequence",
									Status = "Complete!",
									Assets = new GSActivityAssets
									{
										LargeImageKey = DRPIcons.Expedition.Reactor,
										LargeTooltip = "%Rundown% %Expedition% \"%ExpeditionName%\""
									},
									DisplayPartyInfo = true
								}
							}
						}
					}
				}
			},
			{
				(PresenceGameState)6,
				new GSTopActivity
				{
					Formats = new List<GSActivityFormat>
					{
						new GSActivityFormat
						{
							Details = "%Rundown% %Expedition% \"%ExpeditionName%\"",
							Status = "EXPD FAILED",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "icon_failed",
								LargeTooltip = "Beep, Beep, Beeeeeeeeeeep",
								SmallImageKey = "%CharacterImageKey%",
								SmallTooltip = "\"%CharacterName%\", Status: DECEASED"
							},
							DisplayPartyInfo = true
						}
					}
				}
			},
			{
				(PresenceGameState)7,
				new GSTopActivity
				{
					Formats = new List<GSActivityFormat>
					{
						new GSActivityFormat
						{
							Details = "%Rundown% %Expedition% \"%ExpeditionName%\"",
							Status = "EXPD SURVIVED",
							Assets = new GSActivityAssets
							{
								LargeImageKey = "icon_survived",
								LargeTooltip = "Hydrostasis awaits ...",
								SmallImageKey = "%CharacterImageKey%",
								SmallTooltip = "\"%CharacterName%\", Status: ALIVE"
							},
							DisplayPartyInfo = true
						}
					}
				}
			}
		};

		[FSHide]
		[FSDisplayName("DEBUG Use Default Settings")]
		public bool DEBUG_UseDefaultSettings { get; set; }

		[FSIgnore]
		public bool DEBUG_RichPresenceLogSpam { get; set; }

		[JsonIgnore]
		[FSIgnore]
		internal static RichPresenceSettings Default => new RichPresenceSettings();

		public RichPresenceSettings FillDefaultDictValues()
		{
			//IL_0022: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<PresenceGameState, GSTopActivity> item in new RichPresenceSettings().DiscordRPCFormat)
			{
				if (!DiscordRPCFormat.TryGetValue(item.Key, out var value) || value == null)
				{
					DiscordRPCFormat.Add(item.Key, item.Value.FillDefaultDictValues(item.Key));
				}
				else
				{
					value.FillDefaultDictValues(item.Key);
				}
			}
			return this;
		}
	}
}
namespace TheArchive.Core.Managers
{
	public class ArchiveDiscordManager
	{
		public static class DiscordClient
		{
			public const long DEFAULT_CLIENT_ID = 946141176338190346L;

			private static DiscordRpcClient _discordClient;

			private static ILogger _clientLogger;

			private static string _lastLobbyId;

			private static string _lastPartyHash;

			private static readonly RichPresence DefaultFallbackActivity = new RichPresence
			{
				Details = "???",
				State = "err:// no c0nnec7ion",
				Assets = new Assets
				{
					LargeImageKey = "gtfo_icon",
					LargeImageText = "GTFO"
				}
			};

			public static long UsedClientID { get; private set; }

			public static void Initialize(long clientId = 946141176338190346L)
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Expected O, but got Unknown
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Expected O, but got Unknown
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Expected O, but got Unknown
				UsedClientID = clientId;
				_clientLogger = (ILogger)(object)new DiscordLogger(LoaderWrapper.CreateLoggerInstance("DiscordClient", ConsoleColor.Magenta), (LogLevel)3);
				_discordClient = new DiscordRpcClient(clientId.ToString(), -1, _clientLogger, false, (INamedPipeClient)null);
				_discordClient.RegisterUriScheme(493520u.ToString(), (string)null);
				_discordClient.OnReady += new OnReadyEvent(OnReady);
				_discordClient.OnJoin += new OnJoinEvent(OnJoin);
				_discordClient.Subscribe((EventType)2);
				_discordClient.Initialize();
			}

			private static void OnJoin(object sender, JoinMessage args)
			{
				Logger.Notice("OnJoin received! (" + args.Secret + ")");
				ArchiveDiscordManager.OnActivityJoin?.Invoke(args.Secret);
			}

			private static void OnReady(object sender, ReadyMessage args)
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				Logger.Notice("Discord is ready!");
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (!(realtimeSinceStartup < _lastCheckedTime + 5f))
				{
					_lastCheckedTime = realtimeSinceStartup;
					RichPresence val = BuildActivity(PresenceManager.CurrentState, PresenceManager.CurrentStateStartTime);
					if (TryUpdateActivity(val))
					{
						_lastActivity = val;
					}
				}
			}

			private static Party GetParty(string partyId = null)
			{
				//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_000c: 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_0038: Expected O, but got Unknown
				return new Party
				{
					ID = partyId,
					Size = PresenceFormatter.Get<int>("MaxPlayerSlots") - PresenceFormatter.Get<int>("OpenSlots"),
					Max = PresenceFormatter.Get<int>("MaxPlayerSlots")
				};
			}

			private static Secrets GetSecrets(string joinSecret = null)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Expected O, but got Unknown
				if (joinSecret == null)
				{
					return null;
				}
				return new Secrets
				{
					JoinSecret = joinSecret
				};
			}

			private static Timestamps GetTimestamp(ulong? startTime = null, ulong? endTime = null)
			{
				//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_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0068: Expected O, but got Unknown
				return new Timestamps
				{
					StartUnixMilliseconds = startTime * 1000,
					EndUnixMilliseconds = endTime * 1000
				};
			}

			internal static RichPresence BuildActivity(PresenceGameState state, DateTimeOffset startTime)
			{
				//IL_000a: 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_0138: Unknown result type (might be due to invalid IL or missing references)
				if (!_settings.DiscordRPCFormat.TryGetValue(state, out var value))
				{
					return DefaultFallbackActivity;
				}
				RichPresenceSettings.GSActivity gSActivity = value;
				if (!value.HasSubActivities)
				{
					return ActivityFromFormat(gSActivity.GetNext(), state, startTime);
				}
				foreach (RichPresenceSettings.GSSubActivity subActivity in value.SubActivities)
				{
					try
					{
						if (subActivity.DisplayConditionsAnyMode)
						{
							bool flag = false;
							foreach (string displayCondition in subActivity.DisplayConditions)
							{
								string text = PresenceFormatter.Format(displayCondition, Array.Empty<(string, string)>());
								if (text == "True" || text == "!False")
								{
									flag = true;
								}
							}
							if (!flag)
							{
								throw null;
							}
						}
						else
						{
							foreach (string displayCondition2 in subActivity.DisplayConditions)
							{
								string text2 = PresenceFormatter.Format(displayCondition2, Array.Empty<(string, string)>());
								if (text2 != "True" && text2 != "!False")
								{
									throw null;
								}
							}
						}
						gSActivity = subActivity;
					}
					catch
					{
						continue;
					}
					break;
				}
				return ActivityFromFormat(gSActivity.GetNext(), state, startTime);
			}

			private static RichPresence ActivityFromFormat(RichPresenceSettings.GSActivityFormat format, PresenceGameState state, DateTimeOffset startTime)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Expected O, but got Unknown
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Expected O, but got Unknown
				if (format == null)
				{
					return DefaultFallbackActivity;
				}
				(string, string) tuple = ("state", ((object)(PresenceGameState)(ref state)).ToString());
				RichPresence val = new RichPresence();
				string details = format.Details;
				((BaseRichPresence)val).Details = ((details != null) ? PresenceFormatter.Format(details, new(string, string)[1] { tuple }) : null);
				string status = format.Status;
				((BaseRichPresence)val).State = ((status != null) ? PresenceFormatter.Format(status, new(string, string)[1] { tuple }) : null);
				RichPresence val2 = val;
				Assets val3 = new Assets();
				string largeImageKey = format.Assets.LargeImageKey;
				val3.LargeImageKey = ((largeImageKey != null) ? PresenceFormatter.Format(largeImageKey, new(string, string)[1] { tuple }) : null);
				string largeTooltip = format.Assets.LargeTooltip;
				val3.LargeImageText = ((largeTooltip != null) ? PresenceFormatter.Format(largeTooltip, new(string, string)[1] { tuple }) : null);
				string smallImageKey = format.Assets.SmallImageKey;
				val3.SmallImageKey = ((smallImageKey != null) ? PresenceFormatter.Format(smallImageKey, new(string, string)[1] { tuple }) : null);
				string smallTooltip = format.Assets.SmallTooltip;
				val3.SmallImageText = ((smallTooltip != null) ? PresenceFormatter.Format(smallTooltip, new(string, string)[1] { tuple }) : null);
				((BaseRichPresence)val2).Assets = val3;
				ulong result;
				if (format.DisplayStateTimeElapsed)
				{
					((BaseRichPresence)val2).Timestamps = GetTimestamp((ulong)startTime.ToUnixTimeSeconds());
				}
				else if (!string.IsNullOrWhiteSpace(format.CustomTimeProvider) && ulong.TryParse(PresenceFormatter.Format(format.CustomTimeProvider, Array.Empty<(string, string)>()), out result))
				{
					if (format.CustomProviderIsEndTime)
					{
						ulong? endTime = result;
						((BaseRichPresence)val2).Timestamps = GetTimestamp(null, endTime);
					}
					else
					{
						((BaseRichPresence)val2).Timestamps = GetTimestamp(result);
					}
				}
				if (format.DisplayPartyInfo)
				{
					if (PresenceFormatter.Get<bool>("HasLobby"))
					{
						string text = PresenceFormatter.Get("LobbyID").ToString();
						((BaseRichPresence)val2).Party = GetParty(GetPartyID(text));
						((BaseRichPresence)val2).Secrets = GetSecrets(text);
					}
					else
					{
						((BaseRichPresence)val2).Party = GetParty(PartyGuid.ToString());
					}
				}
				return val2;
			}

			private static string GetPartyID(string lobbyId)
			{
				bool flag = _lastLobbyId != lobbyId;
				_lastLobbyId = lobbyId;
				if (string.IsNullOrWhiteSpace(lobbyId))
				{
					return PartyGuid.ToString();
				}
				if (!flag)
				{
					return _lastPartyHash;
				}
				string text = Convert.ToBase64String(SHA256.HashData(Encoding.UTF8.GetBytes(lobbyId)));
				if (text.Length > 128)
				{
					text = text.Substring(0, 128);
				}
				_lastPartyHash = text;
				return text;
			}

			internal static bool TryUpdateActivity(RichPresence activity)
			{
				if (_discordClient == null)
				{
					return false;
				}
				if (_settings.DEBUG_RichPresenceLogSpam)
				{
					Logger.Notice("Activity updated: Details:" + ((BaseRichPresence)activity).Details + " State:" + ((BaseRichPresence)activity).State);
				}
				_discordClient.SetPresence(activity);
				return true;
			}

			public static void Dispose()
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Expected O, but got Unknown
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Expected O, but got Unknown
				if (_discordClient != null)
				{
					_discordClient.OnReady += new OnReadyEvent(OnReady);
					_discordClient.OnJoin += new OnJoinEvent(OnJoin);
					_discordClient.Dispose();
				}
				_discordClient = null;
			}

			public static void RunCallbacks()
			{
				_discordClient.Invoke();
			}
		}

		private static RichPresence _lastActivity;

		private static float _lastCheckedTime;

		private static RichPresenceSettings _settings;

		private static IArchiveLogger _logger;

		public static bool HasBeenSetup => _settings != null;

		public static bool IsEnabled { get; private set; }

		public static Guid PartyGuid { get; private set; } = Guid.NewGuid();


		private static IArchiveLogger Logger => _logger ?? (_logger = LoaderWrapper.CreateLoggerInstance("ArchiveDiscordManager", ConsoleColor.Magenta));

		public static event Action<string> OnActivityJoin;

		public static void Enable(RichPresenceSettings rpcSettings)
		{
			if (rpcSettings == null)
			{
				throw new ArgumentNullException("rpcSettings");
			}
			if (rpcSettings.DEBUG_UseDefaultSettings)
			{
				_settings = RichPresenceSettings.Default;
			}
			else
			{
				_settings = rpcSettings;
			}
			try
			{
				DiscordClient.Initialize();
				DiscordClient.RunCallbacks();
				IsEnabled = true;
			}
			catch (Exception ex)
			{
				Logger.Error($"Exception has been thrown in {"ArchiveDiscordManager"}. {ex}: {ex.Message}");
				Logger.Exception(ex);
			}
		}

		public static void Disable()
		{
			if (IsEnabled)
			{
				DiscordClient.Dispose();
				IsEnabled = false;
			}
		}

		public static void Update()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!IsEnabled)
			{
				return;
			}
			float time = Time.time;
			if (_lastCheckedTime + 5f <= time)
			{
				_lastCheckedTime = time;
				RichPresence val = DiscordClient.BuildActivity(PresenceManager.CurrentState, PresenceManager.CurrentStateStartTime);
				if (!((object)val).Equals((object?)_lastActivity) && DiscordClient.TryUpdateActivity(val))
				{
					_lastActivity = val;
				}
			}
			DiscordClient.RunCallbacks();
		}

		public static void RenewPartyGuid()
		{
			PartyGuid = Guid.NewGuid();
		}
	}
	public class DiscordLogger : ILogger
	{
		private readonly IArchiveLogger _logger;

		public LogLevel Level { get; set; }

		public DiscordLogger(IArchiveLogger archiveLogger, LogLevel logLevel)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			_logger = archiveLogger;
			Level = logLevel;
		}

		public void Trace(string message, params object[] args)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level <= 1)
			{
				string text = message;
				if (args.Length != 0)
				{
					text = string.Format(message, args);
				}
				_logger.Debug(text);
			}
		}

		public void Info(string message, params object[] args)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level <= 2)
			{
				string text = message;
				if (args.Length != 0)
				{
					text = string.Format(message, args);
				}
				_logger.Msg(ConsoleColor.DarkMagenta, text);
			}
		}

		public void Warning(string message, params object[] args)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level <= 3)
			{
				string text = message;
				if (args.Length != 0)
				{
					text = string.Format(message, args);
				}
				_logger.Warning(text);
			}
		}

		public void Error(string message, params object[] args)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level <= 4)
			{
				string text = message;
				if (args.Length != 0)
				{
					text = string.Format(message, args);
				}
				_logger.Error(text);
			}
		}
	}
	public class PresenceManager
	{
		private static IArchiveLogger _logger;

		public static PresenceGameState LastState { get; private set; } = (PresenceGameState)0;


		public static PresenceGameState CurrentState { get; private set; } = (PresenceGameState)0;


		public static DateTimeOffset CurrentStateStartTime { get; private set; } = DateTimeOffset.UtcNow;


		private static IArchiveLogger Logger => _logger ?? (_logger = LoaderWrapper.CreateLoggerInstance("PresenceManager", ConsoleColor.DarkMagenta));

		[FallbackPresenceFormatProvider("EquippedMeleeWeaponName", false)]
		public static string EquippedMeleeWeaponName => "None";

		[FallbackPresenceFormatProvider("EquippedMeleeWeaponID", false)]
		public static string EquippedMeleeWeaponID => "None";

		[PresenceFormatProvider("MeleeWeaponKey")]
		public static string MeleeWeaponKey
		{
			get
			{
				string text = PresenceFormatter.Get<string>("EquippedMeleeWeaponID")?.ToLower();
				switch (text)
				{
				case "heavydutyhammer":
					text = "hammer";
					goto default;
				case "sledgehammer":
					text = "sledge";
					goto default;
				default:
					return "weapon_" + text;
				case null:
					return "please_just_work";
				}
			}
		}

		[FallbackPresenceFormatProvider("EquippedToolName", false)]
		public static string EquippedToolName => "None";

		[FallbackPresenceFormatProvider("EquippedToolID", false)]
		public static string EquippedToolID => "None";

		[PresenceFormatProvider("ToolKey")]
		public static string ToolKey
		{
			get
			{
				string text = PresenceFormatter.Get<string>("EquippedToolID")?.ToLower();
				if (text != null)
				{
					if (text.Contains("sentry"))
					{
						return "tool_sentry";
					}
					if (text.Contains("bio"))
					{
						return "tool_bio";
					}
					if (text.Contains("mine"))
					{
						return "tool_mine";
					}
					if (text.Contains("glue"))
					{
						return "tool_glue";
					}
				}
				return "please_just_work";
			}
		}

		[FallbackPresenceFormatProvider("PrimaryAmmo", false)]
		public static int PrimaryAmmo => -1;

		[FallbackPresenceFormatProvider("MaxPrimaryAmmo", false)]
		public static int MaxPrimaryAmmo => -1;

		[PresenceFormatProvider("PrimaryAmmoPercent")]
		public static int PrimaryAmmoPercent => GetPercentFromInts("PrimaryAmmo", "MaxPrimaryAmmo");

		[FallbackPresenceFormatProvider("SpecialAmmo", false)]
		public static int SpecialAmmo => -1;

		[FallbackPresenceFormatProvider("MaxSpecialAmmo", false)]
		public static int MaxSpecialAmmo => -1;

		[PresenceFormatProvider("SpecialAmmoPercent")]
		public static int SpecialAmmoPercent => GetPercentFromInts("SpecialAmmo", "MaxSpecialAmmo");

		[FallbackPresenceFormatProvider("ToolAmmo", false)]
		public static int ToolAmmo => -1;

		[FallbackPresenceFormatProvider("MaxToolAmmo", false)]
		public static int MaxToolAmmo => -1;

		[PresenceFormatProvider("ToolAmmoOrStatus")]
		public static string ToolAmmoOrStatus
		{
			get
			{
				string text = PresenceFormatter.Get<string>("ToolKey");
				int num = PresenceFormatter.Get<int>("ToolAmmo");
				int value = PresenceFormatter.Get<int>("MaxToolAmmo");
				if (!(text == "tool_bio"))
				{
					if (text == "tool_sentry")
					{
						if (num > 0)
						{
							return $"{num}/{value}";
						}
						return "Deployed/Empty";
					}
					if (num > 0)
					{
						return $"{num}/{value}";
					}
					return "Empty";
				}
				return "Infinite";
			}
		}

		[PresenceFormatProvider("ToolAmmoPercent")]
		public static int ToolAmmoPercent => GetPercentFromInts("ToolAmmo", "MaxToolAmmo");

		[PresenceFormatProvider("ToolAmmoPercentOrStatus")]
		public static string ToolAmmoPercentOrStatus
		{
			get
			{
				string text = PresenceFormatter.Get<string>("ToolKey");
				float num = PresenceFormatter.Get<int>("ToolAmmo");
				float max = PresenceFormatter.Get<int>("MaxToolAmmo");
				if (!(text == "tool_bio"))
				{
					if (text == "tool_sentry")
					{
						if (num > 0f)
						{
							return $"{GetPercent(num, max)}%";
						}
						return "Deployed/Empty";
					}
					if (num > 0f)
					{
						return $"{GetPercent(num, max)}%";
					}
					return "Empty";
				}
				return "∞";
			}
		}

		[FallbackPresenceFormatProvider("LocalCharacterID", false)]
		public static int LocalCharacterID { get; set; } = 0;


		[PresenceFormatProvider("CharacterImageKey")]
		public static string CharacterImageKey => PresenceFormatter.Get<int>("LocalCharacterID") switch
		{
			0 => "char_woods", 
			1 => "char_dauda", 
			2 => "char_hackett", 
			3 => "char_bishop", 
			_ => "please_just_work", 
		};

		[PresenceFormatProvider("CharacterName")]
		public static string CharacterName
		{
			get
			{
				int num = PresenceFormatter.Get<int>("LocalCharacterID");
				return SNet.Core.GetBotNickname(num);
			}
		}

		[FallbackPresenceFormatProvider("HealthRaw", false)]
		public static float HealthRaw => -1f;

		[FallbackPresenceFormatProvider("MaxHealthRaw", false)]
		public static float MaxHealthRaw => 25f;

		[PresenceFormatProvider("HealthPercent")]
		public static int HealthPercent => GetPercentFromFloats("HealthRaw", "MaxHealthRaw");

		[FallbackPresenceFormatProvider("HasLobby", false)]
		public static bool HasLobby => false;

		[FallbackPresenceFormatProvider("LobbyID", false)]
		public static string LobbyID => "0123456789";

		[FallbackPresenceFormatProvider("OpenSlots", false)]
		public static int OpenSlots { get; set; } = 0;


		[FallbackPresenceFormatProvider("MaxPlayerSlots", true)]
		public static int MaxPlayerSlots { get; set; } = 4;


		[FallbackPresenceFormatProvider("ExpeditionTier", false)]
		public static string ExpeditionTier { get; set; } = string.Empty;


		[FallbackPresenceFormatProvider("ExpeditionTierIsSpecial", true)]
		public static bool ExpeditionTierIsSpecial { get; set; } = false;


		[FallbackPresenceFormatProvider("ExpeditionSkipExpNumberInName", true)]
		public static bool ExpeditionSkipExpNumberInName { get; set; } = false;


		[FallbackPresenceFormatProvider("ExpeditionNumber", false)]
		public static string ExpeditionNumber { get; set; } = string.Empty;


		[FallbackPresenceFormatProvider("ExpeditionName", false)]
		public static string ExpeditionName { get; set; } = string.Empty;


		[FallbackPresenceFormatProvider("ZonePrefix", false)]
		public static string ZonePrefix { get; set; } = string.Empty;


		[FallbackPresenceFormatProvider("ZonePrefixLong", false)]
		public static string ZonePrefixLong { get; set; } = string.Empty;


		[FallbackPresenceFormatProvider("ZoneAlias", false)]
		public static string ZoneAlias { get; set; } = string.Empty;


		[FallbackPresenceFormatProvider("AreaSuffix", false)]
		public static string AreaSuffix { get; set; } = string.Empty;


		[FallbackPresenceFormatProvider("RundownTitleFromDataBlocks", false)]
		public static string RundownTitleFromDataBlocks { get; set; } = "Unknown";


		[PresenceFormatProvider("CurrentZoneShort")]
		public static string CurrentZoneShort => $"{PresenceFormatter.Get("ZonePrefix")}_{PresenceFormatter.Get("ZoneAlias")}";

		[PresenceFormatProvider("CurrentZoneLong")]
		public static string CurrentZoneLong => $"{PresenceFormatter.Get("ZonePrefixLong")} {PresenceFormatter.Get("ZoneAlias")}";

		[PresenceFormatProvider("CurrentArea")]
		public static string CurrentArea => $"Area {PresenceFormatter.Get("AreaSuffix")}";

		[PresenceFormatProvider("ExpeditionWithNumber")]
		public static string ExpeditionWithNumber => $"{PresenceFormatter.Get("ExpeditionTier")}{PresenceFormatter.Get("ExpeditionNumber")}";

		[PresenceFormatProvider("Expedition")]
		public static string Expedition
		{
			get
			{
				if (PresenceFormatter.Get<bool>("ExpeditionSkipExpNumberInName"))
				{
					return $"{PresenceFormatter.Get("ExpeditionTier")}";
				}
				return ExpeditionWithNumber ?? "";
			}
		}

		[PresenceFormatProvider("Rundown")]
		public static string Rundown
		{
			get
			{
				if (ArchiveMod.IsPlayingModded)
				{
					return "Mod";
				}
				if (ArchiveMod.IsOnALTBuild)
				{
					string text = PresenceFormatter.Get("ExpeditionTier").ToString();
					if (text.StartsWith("R7") || text.StartsWith("R8"))
					{
						return string.Empty;
					}
					return "Alt";
				}
				return $"R{RundownNumber}";
			}
		}

		[PresenceFormatProvider("RundownNumber")]
		public static int RundownNumber => (int)ArchiveMod.CurrentRundown;

		[PresenceFormatProvider("RundownName")]
		public static string RundownName => RundownTitle;

		[PresenceFormatProvider("RundownTitle")]
		public static string RundownTitle
		{
			get
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				if (ArchiveMod.IsPlayingModded || ArchiveMod.IsOnALTBuild)
				{
					return $"{PresenceFormatter.Get("RundownTitleFromDataBlocks")}";
				}
				return Utils.GetRundownTitle(ArchiveMod.CurrentRundown);
			}
		}

		[PresenceFormatProvider("RundownWithNumberOrModdedPrefix")]
		public static string RundownWithNumberOrModdedPrefix
		{
			get
			{
				if (ArchiveMod.IsPlayingModded)
				{
					return "Modded";
				}
				if (ArchiveMod.IsOnALTBuild)
				{
					return "GTFO";
				}
				return $"Rundown {PresenceFormatter.Get("RundownNumber")}";
			}
		}

		public static void UpdateGameState(PresenceGameState state, bool keepTimer = false)
		{
			//IL_001e: 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)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			Logger.Msg(ConsoleColor.DarkMagenta, $"GameState has been updated: {CurrentState} --> {state}, keepTimer: {keepTimer}");
			LastState = CurrentState;
			CurrentState = state;
			if (!keepTimer)
			{
				CurrentStateStartTime = DateTimeOffset.UtcNow;
			}
		}

		public static int GetPercentFromInts(string val, string max)
		{
			float val2 = PresenceFormatter.Get<int>(val);
			float max2 = PresenceFormatter.Get<int>(max);
			return GetPercent(val2, max2);
		}

		public static int GetPercentFromFloats(string val, string max)
		{
			float val2 = PresenceFormatter.Get<float>(val);
			float max2 = PresenceFormatter.Get<float>(max);
			return GetPercent(val2, max2);
		}

		public static int GetPercent(float val, float max)
		{
			return (int)Math.Round(val / max * 100f);
		}
	}
}