Decompiled source of TheArchive Core v2025.2.2
plugins/TheArchive.Core.dll
Decompiled 7 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.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.Exceptions; using TheArchive.Core.FeaturesAPI; using TheArchive.Core.FeaturesAPI.Components; using TheArchive.Core.FeaturesAPI.Settings; using TheArchive.Core.Interop; using TheArchive.Core.Localization; 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("2025.2.2")] [assembly: AssemblyInformationalVersion("2025.2.0-main+4d4129b")] [assembly: ModDefaultFeatureGroupName("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("2025.2.2.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 = "2025"; public const string Minor = "2"; public const string Patch = "2"; } public class SemVer { public const string Major = "2025"; public const string Minor = "2"; public const string Patch = "2"; public const string Label = ""; public const string DashLabel = ""; public const string Source = "Tag"; } public const bool IsDirty = false; public const string IsDirtyString = "false"; public const string RepositoryUrl = "https://github.com/AuriRex/GTFO_TheArchive.git"; public const string Branch = "main"; public const string Commit = "4d4129b"; public const string Sha = "4d4129be4c259cc16f30184668f950dc26ddb0dc"; public const string CommitDate = "2025-09-03T13:28:17+02:00"; public const string Commits = "0"; public const string Tag = "v2025.2.2"; public const string BaseTag = "v2025.2.2"; } } 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 FeatureGroup Group => FeatureGroups.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 = "2025.2.2"; 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 = "4d4129b"; public const string GIT_COMMIT_DATE = "2025-09-03T13:28:17+02:00"; public const string GIT_BASE_TAG = "v2025.2.2"; public const uint GTFO_STEAM_APPID = 493520u; public const string MTFO_GUID = "com.dak.MTFO"; public const string ARCHIVE_CORE_FEATUREGROUP = "Archive Core"; 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); 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); } FeatureGroups.GetOrCreateModuleGroup(moduleType.Assembly.GetName().Name + ".ModuleGroup"); 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", "2025.2.2")] 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() { 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}"); } } 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 FeatureLocalizationData LoadFeatureLocalizationText(Feature feature) { string location = feature.FeatureInternal.OriginAssembly.Location; if (string.IsNullOrWhiteSpace(location)) { ArchiveLogger.Warning($"Feature \"{feature.Name}\"'s OriginAssembly.Location is null or whitespace. (ID:{feature.Identifier})"); ArchiveLogger.Warning("Localization on dynamic assemblies is not supported currently!"); return new FeatureLocalizationData(); } string text = Path.Combine(Path.GetDirectoryName(location), "Localization"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } string path = Path.Combine(text, feature.Identifier + "_Localization.json"); if (!File.Exists(path)) { FeatureLocalizationData featureLocalizationData = FeatureInternal.GenerateFeatureLocalization(feature); File.WriteAllText(path, JsonConvert.SerializeObject((object)featureLocalizationData, ArchiveMod.JsonSerializerSettings)); return featureLocalizationData; } FeatureLocalizationData featureLocalizationData2 = JsonConvert.DeserializeObject<FeatureLocalizationData>(File.ReadAllText(path), ArchiveMod.JsonSerializerSettings); string input = JsonConvert.SerializeObject((object)featureLocalizationData2, ArchiveMod.JsonSerializerSettings); FeatureLocalizationData featureLocalizationData3 = FeatureInternal.GenerateFeatureLocalization(feature, featureLocalizationData2); string text2 = JsonConvert.SerializeObject((object)featureLocalizationData3, ArchiveMod.JsonSerializerSettings); if (text2.HashString() != input.HashString()) { File.WriteAllText(path, text2); } return featureLocalizationData3; } 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, rundownID); } public static Utils.RundownFlags To(this Utils.RundownFlags flags, Utils.RundownFlags to) { if (to == Utils.RundownFlags.Latest) { return flags.ToLatest(); } if (flags > to) { return Utils.FlagsFromTo(to, flags); } return Utils.FlagsFromTo(flags, to); } public static Utils.RundownFlags ToLatest(this Utils.RundownFlags flags) { return Utils.FlagsFromTo(flags, Utils.RundownFlags.Latest); } public static Utils.RundownFlags LowestRundownFlag(this Utils.RundownFlags flags) { return AllFlagsOrdered.FirstOrDefault((Utils.RundownFlags x) => flags.HasFlag(x)); } public static Utils.RundownFlags HighestRundownFlag(this Utils.RundownFlags flags) { return AllFlagsOrdered.LastOrDefault((Utils.RundownFlags x) => flags.HasFlag(x)); } } public static class SColorExtensions { public static Color ToUnityColor(this SColor col) { //IL_0002: 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) Color result = default(Color); result.r = col.R; result.g = col.G; result.b = col.B; result.a = col.A; return result; } public static Color? ToUnityColor(this SColor? col) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) return col?.ToUnityColor(); } public static SColor ToSColor(this Color col) { //IL_000a: 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_0024: 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) SColor result = default(SColor); result.R = col.r; result.G = col.g; result.B = col.b; result.A = col.a; return result; } public static SColor FromHexString(string col) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) col = EnsureLeadingHash(col); Color col2 = default(Color); if (ColorUtility.TryParseHtmlString(col, ref col2)) { return col2.ToSColor(); } return SColor.WHITE; } public static string EnsureLeadingHash(string hexString) { if (!hexString.StartsWith("#")) { hexString = "#" + hexString; } return hexString; } public static string ToHexString(this SColor col) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return col.ToUnityColor().ToHexString(); } public static string ToHexString(this Color col) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return "#" + ColorUtility.ToHtmlStringRGB(col); } public static string ToShortHexString(this SColor col) { return "#" + ComponentToHex(col.R) + ComponentToHex(col.G) + ComponentToHex(col.B); } public static string ToShortHexString(this Color col) { //IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references) return "#" + ComponentToHex(col.r) + ComponentToHex(col.g) + ComponentToHex(col.b); } public static string ComponentToHex(float component) { return $"{Mathf.Clamp((int)(component * 16f), 0, 15):X1}"; } } public static class SharedUtils { public enum IgnoreMode { Match, StartsWith, EndsWith } [CompilerGenerated] private sealed class <DirectChildren>d__16 : IEnumerable<Transform>, IEnumerable, IEnumerator<Transform>, IEnumerator, IDisposable { private int <>1__state; private Transform <>2__current; private int <>l__initialThreadId; private Transform trans; public Transform <>3__trans; private int <i>5__2; Transform IEnumerator<Transform>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DirectChildren>d__16(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <i>5__2 = 0; break; case 1: <>1__state = -1; <i>5__2++; break; } if (<i>5__2 < trans.childCount) { <>2__current = trans.GetChild(<i>5__2); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<Transform> IEnumerable<Transform>.GetEnumerator() { <DirectChildren>d__16 <Direct