using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; using AIGraph; using AssetShards; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using BepInEx.Unity.IL2CPP.Hook; using BepInEx.Unity.IL2CPP.Utils; using GTFO.API.Attributes; using GTFO.API.Components; using GTFO.API.Extensions; using GTFO.API.Impl; using GTFO.API.JSON; using GTFO.API.JSON.Converters; using GTFO.API.Native; using GTFO.API.Resources; using GTFO.API.Utilities; using GTFO.API.Utilities.Impl; using GTFO.API.Wrappers; using GameData; using Gear; using Globals; 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 Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using ItemSetup; using LevelGeneration; using Localization; using Microsoft.CodeAnalysis; using Player; using SNetwork; using UnityEngine; using UnityEngine.Analytics; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("GTFO-API")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.0")] [assembly: AssemblyInformationalVersion("0.5.0+gitcd77914-main.cd77914af9eee3a5d9106a4128c5fa3bc02d7ec0")] [assembly: AssemblyProduct("GTFO-API")] [assembly: AssemblyTitle("GTFO-API")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.5.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.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; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace GTFO.API { internal static class APILogger { private static readonly ManualLogSource _logger; static APILogger() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown _logger = new ManualLogSource("GTFO-API"); Logger.Sources.Add((ILogSource)(object)_logger); } private static string Format(string module, object msg) { return $"[{module}]: {msg}"; } public static void Info(string module, object data) { _logger.LogMessage((object)Format(module, data)); } public static void Verbose(string module, object data) { } public static void Debug(string module, object data) { _logger.LogDebug((object)Format(module, data)); } public static void Warn(string module, object data) { _logger.LogWarning((object)Format(module, data)); } public static void Error(string module, object data) { _logger.LogError((object)Format(module, data)); } } [API("Asset")] public static class AssetAPI { internal static ConcurrentDictionary s_RegistryCache = new ConcurrentDictionary(); public static ApiStatusInfo Status => APIStatus.Asset; public static event Action OnStartupAssetsLoaded; public static event Action OnAssetBundlesLoaded; public static event Action OnImplReady; public static bool ContainsAsset(string assetName) { string text = assetName.ToUpper(); if (!APIStatus.Asset.Ready) { return s_RegistryCache.ContainsKey(text); } return AssetShardManager.s_loadedAssetsLookup.ContainsKey(text); } public static Object GetLoadedAsset(string path) { string text = path.ToUpper(); APILogger.Verbose("Asset", "Requested Asset: " + text); try { if (!APIStatus.Asset.Ready && s_RegistryCache.TryGetValue(text, out var value)) { return value; } return AssetShardManager.GetLoadedAsset(text, false); } catch { return null; } } public static TAsset GetLoadedAsset(string path) where TAsset : Object { Object loadedAsset = GetLoadedAsset(path); if (loadedAsset == null) { return default(TAsset); } return ((Il2CppObjectBase)loadedAsset).Cast(); } public static void RegisterAsset(string name, Object gameObject) { string text = name.ToUpper(); if (!APIStatus.Asset.Ready) { if (s_RegistryCache.ContainsKey(text)) { throw new ArgumentException("The asset with " + text + " has already been registered.", "name"); } s_RegistryCache.TryAdd(text, gameObject); } else { AssetAPI_Impl.Instance.RegisterAsset(text, gameObject); } } public static void RegisterAssetBundle(AssetBundle bundle) { string[] array = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)bundle.AllAssetNames()); APILogger.Verbose("Asset", "Bundle names: [" + string.Join(", ", array) + "]"); string[] array2 = array; foreach (string text in array2) { Object val = bundle.LoadAsset(text); if (val != (Object)null) { RegisterAsset(text, val); } else { APILogger.Warn("Asset", "Skipping asset " + text); } } } public static void LoadAndRegisterAssetBundle(string pathToBundle) { AssetBundle obj = AssetBundle.LoadFromFile(pathToBundle); if ((Object)(object)obj == (Object)null) { throw new Exception("Failed to load asset bundle"); } RegisterAssetBundle(obj); } public static void LoadAndRegisterAssetBundle(byte[] bundleBytes) { AssetBundle obj = AssetBundle.LoadFromMemory(Il2CppStructArray.op_Implicit(bundleBytes)); if ((Object)(object)obj == (Object)null) { throw new Exception("Failed to load asset bundle"); } RegisterAssetBundle(obj); } public static Object InstantiateAsset(string assetName, string copyName) { if (ContainsAsset(copyName)) { throw new ArgumentException("The asset you're trying to copy into is already registered", "copyName"); } RegisterAsset(copyName, Object.Instantiate(GetLoadedAsset(assetName) ?? throw new ArgumentException("Couldn't find an asset with the name '" + assetName + "'", "assetName"))); return GetLoadedAsset(copyName); } public static TAsset InstantiateAsset(string assetName, string copyName) where TAsset : Object { Object obj = InstantiateAsset(assetName, copyName); if (obj == null) { return default(TAsset); } return ((Il2CppObjectBase)obj).Cast(); } public static bool TryInstantiateAsset(string assetName, string copyName, out TAsset clonedObj) where TAsset : Object { Object obj = InstantiateAsset(assetName, copyName); clonedObj = ((obj != null) ? ((Il2CppObjectBase)obj).TryCast() : default(TAsset)); return (Object)(object)clonedObj != (Object)null; } private static void OnAssetsLoaded() { if (!APIStatus.Asset.Created) { APIStatus.CreateApi("Asset"); } SafeInvoke.Invoke(AssetAPI.OnStartupAssetsLoaded); } internal static void InvokeImplReady() { SafeInvoke.Invoke(AssetAPI.OnImplReady); } internal static void Setup() { EventAPI.OnAssetsLoaded += OnAssetsLoaded; OnImplReady += LoadAssetBundles; } private static void LoadAssetBundles() { string assetBundlesDir = Path.Combine(Paths.BepInExRootPath, "Assets", "AssetBundles"); string assetBundlesDir2 = Path.Combine(Paths.ConfigPath, "Assets", "AssetBundles"); if (LoadAssetBundles(assetBundlesDir) | LoadAssetBundles(assetBundlesDir2, outdated: true)) { SafeInvoke.Invoke(AssetAPI.OnAssetBundlesLoaded); } } private static bool LoadAssetBundles(string assetBundlesDir, bool outdated = false) { if (outdated) { if (!Directory.Exists(assetBundlesDir)) { return false; } APILogger.Warn("AssetAPI", "Storing asset bundles in the config path is deprecated and will be removed in a future version of GTFO-API. The path has been moved to 'BepInEx\\Assets\\AssetBundles'."); } if (!Directory.Exists(assetBundlesDir)) { Directory.CreateDirectory(assetBundlesDir); return false; } string[] array = (from x in Directory.GetFiles(assetBundlesDir, "*", SearchOption.AllDirectories) where !x.EndsWith(".manifest", StringComparison.InvariantCultureIgnoreCase) select x).ToArray(); if (array.Length == 0) { return false; } for (int i = 0; i < array.Length; i++) { try { LoadAndRegisterAssetBundle(array[i]); } catch (Exception ex) { APILogger.Warn("AssetAPI", $"Failed to load asset bundle '{array[i]}' ({ex.Message})"); } } return true; } } [API("Event")] public static class EventAPI { public static ApiStatusInfo Status => APIStatus.Event; public static event Action OnManagersSetup; public static event Action OnExpeditionStarted; public static event Action OnAssetsLoaded; internal static void Setup() { Global.OnAllManagersSetup += Action.op_Implicit((Action)ManagersSetup); AssetShardManager.OnStartupAssetsLoaded += Action.op_Implicit((Action)AssetsLoaded); RundownManager.OnExpeditionGameplayStarted += Action.op_Implicit((Action)ExpeditionStarted); } private static void ManagersSetup() { SafeInvoke.Invoke(EventAPI.OnManagersSetup); } private static void ExpeditionStarted() { SafeInvoke.Invoke(EventAPI.OnExpeditionStarted); } private static void AssetsLoaded() { SafeInvoke.Invoke(EventAPI.OnAssetsLoaded); } } [API("GameData")] public class GameDataAPI { public static ApiStatusInfo Status => APIStatus.GameData; public static event Action OnGameDataInitialized; static GameDataAPI() { Status.Created = true; Status.Ready = true; } internal static void InvokeGameDataInit() { SafeInvoke.Invoke(GameDataAPI.OnGameDataInitialized); } } [API("Il2Cpp")] public static class Il2CppAPI { public static ApiStatusInfo Status => APIStatus.Il2Cpp; static Il2CppAPI() { Status.Created = true; Status.Ready = true; } public unsafe static void InjectWithInterface() where T : Il2CppObjectBase { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown List list = new List(); foreach (Il2CppInterfaceAttribute item in GetCustomAttributesInType()) { Il2CppClass* ptr = (Il2CppClass*)(void*)(IntPtr)typeof(Il2CppClassPointerStore<>).MakeGenericType(item.Type).GetField("NativeClassPtr").GetValue(null); IL2CPP.il2cpp_runtime_class_init((IntPtr)ptr); list.Add(UnityVersionHandler.Wrap(ptr)); } RegisterTypeOptions val = new RegisterTypeOptions(); val.set_LogSuccess(true); val.set_Interfaces(Il2CppInterfaceCollection.op_Implicit(list.ToArray())); ClassInjector.RegisterTypeInIl2Cpp(val); } public unsafe static void* GetIl2CppMethod(string methodName, string returnTypeName, bool isGeneric, params string[] argTypes) where T : Il2CppObjectBase { void** ptr = (void**)IL2CPP.GetIl2CppMethod(Il2CppClassPointerStore.NativeClassPtr, isGeneric, methodName, returnTypeName, argTypes).ToPointer(); if (ptr == null) { return ptr; } return *ptr; } public unsafe static TDelegate GetIl2CppMethod(string methodName, string returnTypeName, bool isGeneric, params string[] argTypes) where T : Il2CppObjectBase where TDelegate : Delegate { void* il2CppMethod = GetIl2CppMethod(methodName, returnTypeName, isGeneric, argTypes); if (il2CppMethod == null) { return null; } return Marshal.GetDelegateForFunctionPointer((IntPtr)il2CppMethod); } public unsafe static INativeDetour CreateGenericDetour(string methodName, string returnType, string[] paramTypes, Type[] genericArguments, TDelegate to, out TDelegate original) where TClass : Object where TDelegate : Delegate { //IL_0042: Unknown result type (might be due to invalid IL or missing references) IntPtr nativeClassPtr = Il2CppClassPointerStore.NativeClassPtr; if (nativeClassPtr == IntPtr.Zero) { throw new ArgumentException(typeof(TClass).Name + " does not exist in il2cpp domain"); } return INativeDetour.CreateAndApply(UnityVersionHandler.Wrap((Il2CppMethodInfo*)(void*)IL2CPP.il2cpp_method_get_from_reflection(((Il2CppObjectBase)new MethodInfo(IL2CPP.il2cpp_method_get_object(IL2CPP.GetIl2CppMethod(nativeClassPtr, true, methodName, returnType, paramTypes), nativeClassPtr)).MakeGenericMethod(((IEnumerable)genericArguments).Select((Func)Il2CppType.From).ToArray())).Pointer)).MethodPointer, to, ref original); } private static IEnumerable GetCustomAttributesInType() where TAttribute : Attribute { Type attributeType = typeof(TAttribute); return typeof(T).GetCustomAttributes(attributeType, inherit: true).Union(typeof(T).GetInterfaces().SelectMany((Type interfaceType) => interfaceType.GetCustomAttributes(attributeType, inherit: true))).Distinct() .Cast(); } } [API("Interop")] public static class InteropAPI { private static readonly Dictionary> s_CallLookup = new Dictionary>(); public static ApiStatusInfo Status => APIStatus.Interop; public static bool PluginExists(string pluginGUID, out PluginInfo pluginInfo) { return ((BaseChainloader)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue(pluginGUID, out pluginInfo); } public static void ExecuteWhenPluginExists(string pluginGUID, Action action) { if (action != null && PluginExists(pluginGUID, out var pluginInfo)) { action(pluginInfo); } } public static void ExecuteWhenPluginNotExists(string pluginGUID, Action action) { if (action != null && !PluginExists(pluginGUID, out var _)) { action(); } } public static void RegisterCall(string callName, Func callback) { Func value; if (callback == null) { APILogger.Warn("Interop", $"'{callName}' was requested to registed without valid {"callback"} parameter given! This will be ignored!"); } else if (s_CallLookup.TryGetValue(callName, out value)) { APILogger.Error("Interop", callName + " is already occupied by other mods!"); } else { s_CallLookup[callName] = callback; APILogger.Verbose("Interop", callName + " has successfully registered."); } } public static object Call(string callName, params object[] parameters) { if (s_CallLookup.TryGetValue(callName, out var value)) { return value?.Invoke(parameters) ?? null; } return null; } } public delegate void LevelDataUpdateEvent(ActiveExpedition activeExp, ExpeditionInTierData expData); public delegate void LevelSelectedEvent(eRundownTier expTier, int expIndexInTier, ExpeditionInTierData expData); [API("Level")] public static class LevelAPI { private static eRundownTier s_LatestExpTier = (eRundownTier)99; private static int s_LatestExpIndex = -1; public static ApiStatusInfo Status => APIStatus.Level; public static event LevelDataUpdateEvent OnLevelDataUpdated; public static event LevelSelectedEvent OnLevelSelected; public static event Action OnBuildStart; public static event Action OnBuildDone; public static event Action OnEnterLevel; public static event Action OnLevelCleanup; public static event Action OnFactoryStart; public static event Action OnFactoryDone; public static event Action OnBeforeBuildBatch; public static event Action OnAfterBuildBatch; internal static void Setup() { Status.Created = true; Status.Ready = true; EventAPI.OnExpeditionStarted += EnterLevel; } internal static void ExpeditionUpdated(pActiveExpedition activeExp, ExpeditionInTierData expData) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) ActiveExpedition activeExpData = ActiveExpedition.CreateFrom(activeExp); SafeInvoke.InvokeDelegate(LevelAPI.OnLevelDataUpdated, delegate(LevelDataUpdateEvent del) { del(activeExpData, expData); }); eRundownTier tier = activeExp.tier; int index = activeExp.expeditionIndex; if (tier != s_LatestExpTier || index != s_LatestExpIndex) { SafeInvoke.InvokeDelegate(LevelAPI.OnLevelSelected, delegate(LevelSelectedEvent del) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) del(tier, index, expData); }); s_LatestExpTier = tier; s_LatestExpIndex = index; } } internal static void BuildStart() { SafeInvoke.Invoke(LevelAPI.OnBuildStart); } internal static void BuildDone() { SafeInvoke.Invoke(LevelAPI.OnBuildDone); } internal static void EnterLevel() { SafeInvoke.Invoke(LevelAPI.OnEnterLevel); } internal static void LevelCleanup() { SafeInvoke.Invoke(LevelAPI.OnLevelCleanup); } internal static void FactoryStart() { SafeInvoke.Invoke(LevelAPI.OnFactoryStart); } internal static void FactoryFinished() { SafeInvoke.Invoke(LevelAPI.OnFactoryDone); } internal static void BeforeBuildBatch(BatchName batchName) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) SafeInvoke.Invoke(LevelAPI.OnBeforeBuildBatch, batchName); } internal static void AfterBuildBatch(BatchName batchName) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) SafeInvoke.Invoke(LevelAPI.OnAfterBuildBatch, batchName); } } public struct ActiveExpedition { public pPlayer player; public eRundownKey rundownType; public string rundownKey; public eRundownTier tier; public int expeditionIndex; public int hostIDSeed; public int sessionSeed; public static ActiveExpedition CreateFrom(pActiveExpedition pActiveExp) { ActiveExpedition result = default(ActiveExpedition); result.CopyFrom(pActiveExp); return result; } public void CopyFrom(pActiveExpedition pActiveExp) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) player = pActiveExp.player; rundownType = pActiveExp.rundownType; rundownKey = pActiveExp.rundownKey.data; tier = pActiveExp.tier; expeditionIndex = pActiveExp.expeditionIndex; hostIDSeed = pActiveExp.hostIDSeed; sessionSeed = pActiveExp.sessionSeed; } } [API("Localization")] public static class LocalizationAPI { private sealed class Entry { private readonly string?[] m_ValuesByLanguage = new string[12]; private TextDBOptions m_Options; public uint? TextBlockId { get; private set; } private bool TryGetStringInAnyLanguage([NotNullWhen(true)] out string? value) { for (int i = 0; i < m_ValuesByLanguage.Length; i++) { value = m_ValuesByLanguage[i]; if (value != null) { return true; } } value = null; return false; } private bool TryGetStringInLanguage(Language language, [NotNullWhen(true)] out string? value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Expected I4, but got Unknown int num = language - 1; value = m_ValuesByLanguage[num]; return value != null; } public bool TryGetString(Language language, FallbackValueOptions options, [NotNullWhen(true)] out string? value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (TryGetStringInLanguage(language, out value)) { return true; } if (options.UseFallbackLanguage && TryGetStringInLanguage(options.FallbackLanguage.Value, out value)) { return true; } if (options.UseAnyLanguage && TryGetStringInAnyLanguage(out value)) { return true; } value = null; return false; } private string GetStringForTextDB(Language language, string key, FallbackValueOptions options) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (TryGetString(language, options, out string value)) { return value; } ValidateUseKey(key, language, options, "GenerateTextDB"); return key; } [MemberNotNull("TextBlockId")] public void GenerateTextDataBlock(string key, TextDBOptions options, bool force = false) { m_Options = options; GenerateTextDataBlock(key, force); } [MemberNotNull("TextBlockId")] public void GenerateTextDataBlock(string key, bool force = false) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_018e: Expected O, but got Unknown if (!TextBlockId.HasValue || force) { FallbackValueOptions options = m_Options.FallbackOptions ?? FallbackValueOptions.AnyLangOrKey; TextDataBlock val = new TextDataBlock { CharacterMetaData = (m_Options.CharacterMetadataId ?? 1) }; ((GameDataBlockBase)val).internalEnabled = true; val.ExportVersion = 1; val.ImportVersion = 1; val.Description = string.Empty; val.English = GetStringForTextDB((Language)1, key, options); val.French = LanguageData.op_Implicit(GetStringForTextDB((Language)2, key, options)); val.Italian = LanguageData.op_Implicit(GetStringForTextDB((Language)3, key, options)); val.German = LanguageData.op_Implicit(GetStringForTextDB((Language)4, key, options)); val.Spanish = LanguageData.op_Implicit(GetStringForTextDB((Language)5, key, options)); val.Russian = LanguageData.op_Implicit(GetStringForTextDB((Language)6, key, options)); val.Portuguese_Brazil = LanguageData.op_Implicit(GetStringForTextDB((Language)7, key, options)); val.Polish = LanguageData.op_Implicit(GetStringForTextDB((Language)8, key, options)); val.Japanese = LanguageData.op_Implicit(GetStringForTextDB((Language)9, key, options)); val.Korean = LanguageData.op_Implicit(GetStringForTextDB((Language)10, key, options)); val.Chinese_Traditional = LanguageData.op_Implicit(GetStringForTextDB((Language)11, key, options)); val.Chinese_Simplified = LanguageData.op_Implicit(GetStringForTextDB((Language)12, key, options)); ((GameDataBlockBase)val).name = key; val.MachineTranslation = false; val.SkipLocalization = false; ((GameDataBlockBase)val).persistentID = 0u; TextDataBlock val2 = val; GameDataBlockBase.AddBlock(val2, -1); TextBlockId = ((GameDataBlockBase)(object)val2).persistentID; } } public bool TryGetString(Language language, string key, FallbackValueOptions options, out string? value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (TryGetString(language, options, out value)) { return true; } if (options.UseKey) { value = key; return true; } value = null; return false; } public string GetString(Language language, string key, FallbackValueOptions options) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (TryGetString(language, options, out string value)) { return value; } ValidateUseKey(key, language, options, "GetString"); return key; } public string FormatString(Language language, string key, FallbackValueOptions options, object?[] args) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (TryGetString(language, options, out string value)) { return string.Format(value, args); } ValidateUseKey(key, language, options, "FormatString"); return key; } public bool HasValueInLanguage(Language language) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) ValidateLanguage(language, "language"); return m_ValuesByLanguage[language - 1] != null; } public void AddValue(Language language, string value, bool force = false) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected I4, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) ArgumentNullException.ThrowIfNull(value, "value"); int num = language - 1; if (num < 0 || num >= m_ValuesByLanguage.Length) { throw new ArgumentOutOfRangeException("language"); } ref string reference = ref m_ValuesByLanguage[num]; if (reference != null && !force) { return; } reference = value; if (TextBlockId.HasValue) { TextDataBlock block = GameDataBlockBase.GetBlock(TextBlockId.Value); if (block != null) { UpdateTextDataBlock(block, language, reference); } } } } [Flags] public enum FallbackValueFlags { None = 0, FallbackLanguage = 1, AnyLanguage = 2, Key = 4, FallbackOrAnyLanguage = 3, FallbackLanguageOrKey = 5, AnyLanguageOrKey = 6, FallbackOrAnyLanguageOrKey = 7 } public readonly struct FallbackValueOptions : IEquatable { public static readonly FallbackValueOptions None = default(FallbackValueOptions); public static readonly FallbackValueOptions Key = new FallbackValueOptions(FallbackValueFlags.Key); public static readonly FallbackValueOptions AnyLang = new FallbackValueOptions(FallbackValueFlags.AnyLanguage); public static readonly FallbackValueOptions AnyLangOrKey = new FallbackValueOptions(FallbackValueFlags.AnyLanguageOrKey); public FallbackValueFlags Flags { get; } public Language? FallbackLanguage { get; } public bool UseKey => Flags.HasFlag(FallbackValueFlags.Key); [MemberNotNullWhen(true, "FallbackLanguage")] public bool UseFallbackLanguage { [MemberNotNullWhen(true, "FallbackLanguage")] get { return Flags.HasFlag(FallbackValueFlags.FallbackLanguage); } } public bool UseAnyLanguage => Flags.HasFlag(FallbackValueFlags.AnyLanguage); public FallbackValueOptions(FallbackValueFlags flags, Language? fallbackLanguage = null) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (flags.HasFlag(FallbackValueFlags.FallbackLanguage)) { if (!fallbackLanguage.HasValue) { throw new ArgumentNullException("fallbackLanguage", "A fallback language is required if specifying the flag FallbackLanguage"); } ValidateLanguage(fallbackLanguage.Value, "fallbackLanguage"); } Flags = flags; FallbackLanguage = fallbackLanguage; } public override int GetHashCode() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) return HashCode.Combine(Flags, FallbackLanguage.GetValueOrDefault()); } public override bool Equals([NotNullWhen(true)] object? obj) { if (obj is FallbackValueOptions other) { return Equals(other); } return false; } public bool Equals(FallbackValueOptions other) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (Flags == other.Flags) { return FallbackLanguage == other.FallbackLanguage; } return false; } public FallbackValueOptions IncludeKey() { return new FallbackValueOptions(Flags | FallbackValueFlags.Key, FallbackLanguage); } public FallbackValueOptions ExcludeKey() { return new FallbackValueOptions(Flags & ~FallbackValueFlags.Key, FallbackLanguage); } public FallbackValueOptions IncludeFallbackLanguage(Language language) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) ValidateLanguage(language, "language"); return new FallbackValueOptions(Flags | FallbackValueFlags.FallbackLanguage, language); } public FallbackValueOptions ExcludeFallbackLanguage() { return new FallbackValueOptions(Flags & ~FallbackValueFlags.FallbackLanguage); } public FallbackValueOptions IncludeAnyLanguage() { return new FallbackValueOptions(Flags | FallbackValueFlags.AnyLanguage, FallbackLanguage); } public FallbackValueOptions ExcludeAnyLanguage() { return new FallbackValueOptions(Flags & ~FallbackValueFlags.AnyLanguage, FallbackLanguage); } public FallbackValueOptions Combine(FallbackValueOptions other) { return new FallbackValueOptions(Flags | other.Flags, FallbackLanguage ?? other.FallbackLanguage); } public static bool operator ==(FallbackValueOptions left, FallbackValueOptions right) { return left.Equals(right); } public static bool operator !=(FallbackValueOptions left, FallbackValueOptions right) { return !(left == right); } public static FallbackValueOptions FallbackLang(Language fallbackLanguage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new FallbackValueOptions(FallbackValueFlags.FallbackLanguage, fallbackLanguage); } public static FallbackValueOptions FallbackOrAnyLang(Language fallbackLanguage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new FallbackValueOptions(FallbackValueFlags.FallbackOrAnyLanguage, fallbackLanguage); } public static FallbackValueOptions FallbackLangOrKey(Language fallbackLanguage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new FallbackValueOptions(FallbackValueFlags.FallbackLanguageOrKey, fallbackLanguage); } public static FallbackValueOptions FallbackOrAnyLangOrKey(Language fallbackLanguage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new FallbackValueOptions(FallbackValueFlags.FallbackOrAnyLanguageOrKey, fallbackLanguage); } } public struct TextDBOptions { private FallbackValueOptions? m_FallbackOptions; private uint? m_CharacterMetadataId; public uint? CharacterMetadataId { readonly get { return m_CharacterMetadataId; } set { m_CharacterMetadataId = value; } } public FallbackValueOptions? FallbackOptions { readonly get { return m_FallbackOptions; } set { m_FallbackOptions = value; } } } private static readonly Dictionary s_Entries = new Dictionary(); private static readonly List s_EntriesToGenerateTextDBs = new List(); private static bool s_GameDataInitialized = false; private static readonly string STR_NoValueFoundExceptionMsg = "No localization value exists for key '{1}' in language '{0}'."; private static readonly string STR_UseKeyGeneric = "{2}: No localization value exists for key '{1}' in language '{0}', defaulting to key."; public static ApiStatusInfo Status => APIStatus.Localization; public static Language CurrentLanguage => Text.TextLocalizationService.CurrentLanguage; public static event Action? OnLanguageChange; internal static void Setup() { GameDataAPI.OnGameDataInitialized += OnGameDataInitialized; EventAPI.OnAssetsLoaded += OnGameAssetsLoaded; Status.Created = true; } internal static void OnGameDataInitialized() { s_GameDataInitialized = true; foreach (string s_EntriesToGenerateTextDB in s_EntriesToGenerateTextDBs) { if (s_Entries.TryGetValue(s_EntriesToGenerateTextDB, out Entry value)) { value.GenerateTextDataBlock(s_EntriesToGenerateTextDB, force: true); } } } internal static void OnGameAssetsLoaded() { Status.Ready = true; } internal static void LanguageChanged() { SafeInvoke.Invoke(LocalizationAPI.OnLanguageChange); } public static string FormatString(string key, params object?[] args) { return FormatString(key, FallbackValueOptions.None, args); } public static string FormatString(string key, Language fallbackLanguage, params object?[] args) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return FormatString(key, FallbackValueOptions.FallbackLang(fallbackLanguage), args); } public static string FormatString(string key, FallbackValueOptions options, params object?[] args) { //IL_000b: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) ValidateLocalizationKey(key, "key"); Language currentLanguage = CurrentLanguage; if (!s_Entries.TryGetValue(key, out Entry value)) { ValidateUseKey(key, currentLanguage, options, "FormatString"); return key; } return value.FormatString(currentLanguage, key, options, args); } public static string GetString(string key) { return GetString(key, FallbackValueOptions.None); } public static string GetString(string key, Language fallbackLanguage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return GetString(key, FallbackValueOptions.FallbackLang(fallbackLanguage)); } public static string GetString(string key, FallbackValueOptions options) { //IL_000b: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) ValidateLocalizationKey(key, "key"); Language currentLanguage = CurrentLanguage; if (!s_Entries.TryGetValue(key, out Entry value)) { ValidateUseKey(key, currentLanguage, options, "GetString"); return key; } return value.GetString(currentLanguage, key, options); } public static bool TryGetString(string key, [NotNullWhen(true)] out string? value) { return TryGetString(key, FallbackValueOptions.None, out value); } public static bool TryGetString(string key, Language fallbackLanguage, [NotNullWhen(true)] out string? value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return TryGetString(key, FallbackValueOptions.FallbackLang(fallbackLanguage), out value); } public static bool TryGetString(string key, FallbackValueOptions options, [NotNullWhen(true)] out string? value) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) ValidateLocalizationKey(key, "key"); if (!s_Entries.TryGetValue(key, out Entry value2)) { if (options.UseKey) { value = key; return false; } value = null; return false; } return value2.TryGetString(CurrentLanguage, key, options, out value); } public static bool HasKey([NotNullWhen(true)] string? key) { if (!string.IsNullOrWhiteSpace(key)) { return s_Entries.ContainsKey(key); } return false; } public static bool HasLocalizedValue([NotNullWhen(true)] string? key, Language language) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrWhiteSpace(key) && s_Entries.TryGetValue(key, out Entry value)) { return value.HasValueInLanguage(language); } return false; } public static uint GenerateTextBlock(string key, TextDBOptions? textDataBlockOptions = null) { ValidateLocalizationKey(key, "key"); Entry entry = s_Entries[key]; if (entry.TextBlockId.HasValue) { return entry.TextBlockId.Value; } if (textDataBlockOptions.HasValue) { entry.GenerateTextDataBlock(key, textDataBlockOptions.Value); } else { entry.GenerateTextDataBlock(key); } s_EntriesToGenerateTextDBs.Add(key); return entry.TextBlockId.Value; } public static bool TryGetTextBlockId(string key, out uint blockId) { ValidateLocalizationKey(key, "key"); if (!s_Entries.TryGetValue(key, out Entry value) || !value.TextBlockId.HasValue) { blockId = 0u; return false; } blockId = value.TextBlockId.Value; return true; } public static void AddEntry(string key, Language language, string value, TextDBOptions? textDataBlockOptions = null) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) ValidateLocalizationKey(key, "key"); ValidateLanguage(language, "language"); if (value == null) { value = string.Empty; } bool exists; ref Entry valueRefOrAddDefault = ref CollectionsMarshal.GetValueRefOrAddDefault(s_Entries, key, out exists); if (valueRefOrAddDefault == null) { valueRefOrAddDefault = new Entry(); } valueRefOrAddDefault.AddValue(language, value); if (textDataBlockOptions.HasValue && !exists) { s_EntriesToGenerateTextDBs.Add(key); if (s_GameDataInitialized) { valueRefOrAddDefault.GenerateTextDataBlock(key, textDataBlockOptions.Value); } } } public static void LoadFromResources(string baseName, TextDBOptions? textDataBlockOptions = null) { LoadFromResources(baseName, Assembly.GetCallingAssembly(), textDataBlockOptions); } public static void LoadFromResources(string baseName, Assembly assembly, TextDBOptions? textDataBlockOptions = null) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) ResourceManager resourceManager = new ResourceManager(baseName, assembly); List list = new List(); CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures); foreach (CultureInfo cultureInfo in cultures) { bool isNeutralCulture = cultureInfo.IsNeutralCulture; Language language = GetLanguage(cultureInfo); if ((int)language == 0) { continue; } ResourceSet resourceSet; try { resourceSet = resourceManager.GetResourceSet(cultureInfo, createIfNotExists: true, tryParents: true); } catch (MissingManifestResourceException) { continue; } catch (Exception item) { list.Add(item); continue; } if (resourceSet == null) { continue; } foreach (DictionaryEntry item2 in resourceSet) { if (!(item2.Key is string text) || !(item2.Value is string value)) { continue; } bool exists; ref Entry valueRefOrAddDefault = ref CollectionsMarshal.GetValueRefOrAddDefault(s_Entries, text, out exists); if (valueRefOrAddDefault == null) { valueRefOrAddDefault = new Entry(); } valueRefOrAddDefault.AddValue(language, value, isNeutralCulture); if (textDataBlockOptions.HasValue && !exists) { s_EntriesToGenerateTextDBs.Add(text); if (s_GameDataInitialized) { valueRefOrAddDefault.GenerateTextDataBlock(text, textDataBlockOptions.Value); } } } } resourceManager.ReleaseAllResources(); if (list.Count > 0) { throw new AggregateException(list); } } private static void ValidateLocalizationKey([NotNull] string key, [CallerArgumentExpression("key")] string? paramName = null) { ArgumentNullException.ThrowIfNull(key, paramName); if (string.IsNullOrWhiteSpace(paramName)) { throw new ArgumentException("Localization key cannot be empty/whitespace", paramName ?? "key"); } } private static void ValidateLanguage(Language language, [CallerArgumentExpression("language")] string? paramName = null) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!Enum.IsDefined(language)) { throw new ArgumentException($"'{language}' is not a valid language", paramName ?? "language"); } } private static void ValidateUseKey(string key, Language language, FallbackValueOptions options, string useCategory) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!options.UseKey) { throw new KeyNotFoundException(string.Format(STR_NoValueFoundExceptionMsg, language, key)); } APILogger.Warn("LocalizationAPI", string.Format(STR_UseKeyGeneric, language, key, useCategory)); } private static Language GetLanguage(CultureInfo info) { //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) while (!info.IsNeutralCulture) { info = info.Parent; if (string.IsNullOrEmpty(info.Name)) { return (Language)0; } } return (Language)(info.Name switch { "en" => 1, "fr" => 2, "it" => 3, "de" => 4, "es" => 5, "ru" => 6, "pt" => 7, "pl" => 8, "ja" => 9, "ko" => 10, "zh-Hans" => 12, "zh-Hant" => 11, _ => 0, }); } private static void UpdateTextDataBlock(TextDataBlock block, Language language, string text) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected I4, but got Unknown switch (language - 1) { case 0: block.English = text; break; case 1: block.French = LanguageData.op_Implicit(text); break; case 2: block.Italian = LanguageData.op_Implicit(text); break; case 3: block.German = LanguageData.op_Implicit(text); break; case 4: block.Spanish = LanguageData.op_Implicit(text); break; case 5: block.Russian = LanguageData.op_Implicit(text); break; case 6: block.Portuguese_Brazil = LanguageData.op_Implicit(text); break; case 7: block.Polish = LanguageData.op_Implicit(text); break; case 8: block.Japanese = LanguageData.op_Implicit(text); break; case 9: block.Korean = LanguageData.op_Implicit(text); break; case 10: block.Chinese_Traditional = LanguageData.op_Implicit(text); break; case 11: block.Chinese_Simplified = LanguageData.op_Implicit(text); break; } } } [API("Network")] public static class NetworkAPI { internal class CachedEvent { public string EventName { get; set; } public Type PayloadType { get; set; } public object OnReceive { get; set; } public bool IsFreeSize { get; set; } } internal static ConcurrentDictionary s_EventCache = new ConcurrentDictionary(); public static ApiStatusInfo Status => APIStatus.Network; public static bool IsEventRegistered(string eventName) { return NetworkAPI_Impl.Instance.EventExists(eventName); } public static void RegisterEvent(string eventName, Action onReceive) where T : struct { if (!APIStatus.Network.Ready) { if (s_EventCache.ContainsKey(eventName)) { throw new ArgumentException("An event with the name " + eventName + " has already been registered.", "eventName"); } s_EventCache.TryAdd(eventName, new CachedEvent { EventName = eventName, PayloadType = typeof(T), OnReceive = onReceive, IsFreeSize = false }); } else { NetworkAPI_Impl.Instance.RegisterEvent(eventName, onReceive); } } public static void InvokeEvent(string eventName, T payload, SNet_ChannelType channelType = 2) where T : struct { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) SNet_SendGroup val = default(SNet_SendGroup); SNet_SendQuality val2 = default(SNet_SendQuality); int num = default(int); SNet.GetSendSettings(ref channelType, ref val, ref val2, ref num); SNet.Core.SendBytes(MakeBytes(eventName, payload), val, val2, num); } public static void InvokeEvent(string eventName, T payload, SNet_Player target, SNet_ChannelType channelType = 2) where T : struct { //IL_0019: Unknown result type (might be due to invalid IL or missing references) SNet_SendGroup val = default(SNet_SendGroup); SNet_SendQuality val2 = default(SNet_SendQuality); int num = default(int); SNet.GetSendSettings(ref channelType, ref val, ref val2, ref num); SNet.Core.SendBytes(MakeBytes(eventName, payload), val2, num, target); } public static void InvokeEvent(string eventName, T payload, List targets, SNet_ChannelType channelType = 2) where T : struct { //IL_0019: Unknown result type (might be due to invalid IL or missing references) SNet_SendGroup val = default(SNet_SendGroup); SNet_SendQuality val2 = default(SNet_SendQuality); int num = default(int); SNet.GetSendSettings(ref channelType, ref val, ref val2, ref num); SNet.Core.SendBytes(MakeBytes(eventName, payload), val2, num, targets.ToIl2Cpp()); } public static void RegisterFreeSizedEvent(string eventName, Action onReceiveBytes) { if (!APIStatus.Network.Ready) { if (s_EventCache.ContainsKey(eventName)) { throw new ArgumentException("An event with the name " + eventName + " has already been registered.", "eventName"); } s_EventCache.TryAdd(eventName, new CachedEvent { EventName = eventName, PayloadType = null, OnReceive = onReceiveBytes, IsFreeSize = true }); } else { NetworkAPI_Impl.Instance.RegisterFreeSizedEvent(eventName, onReceiveBytes); } } public static void InvokeFreeSizedEvent(string eventName, byte[] payload, SNet_ChannelType channelType = 2) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) SNet_SendGroup val = default(SNet_SendGroup); SNet_SendQuality val2 = default(SNet_SendQuality); int num = default(int); SNet.GetSendSettings(ref channelType, ref val, ref val2, ref num); SNet.Core.SendBytes(MakeBytes(eventName, payload), val, val2, num); } public static void InvokeFreeSizedEvent(string eventName, byte[] payload, SNet_Player target, SNet_ChannelType channelType = 2) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) SNet_SendGroup val = default(SNet_SendGroup); SNet_SendQuality val2 = default(SNet_SendQuality); int num = default(int); SNet.GetSendSettings(ref channelType, ref val, ref val2, ref num); SNet.Core.SendBytes(MakeBytes(eventName, payload), val2, num, target); } public static void InvokeFreeSizedEvent(string eventName, byte[] payload, IEnumerable targets, SNet_ChannelType channelType = 2) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) SNet_SendGroup val = default(SNet_SendGroup); SNet_SendQuality val2 = default(SNet_SendQuality); int num = default(int); SNet.GetSendSettings(ref channelType, ref val, ref val2, ref num); SNet.Core.SendBytes(MakeBytes(eventName, payload), val2, num, targets.ToList().ToIl2Cpp()); } private static Il2CppStructArray MakeBytes(string eventName, T payload) where T : struct { return Il2CppStructArray.op_Implicit(NetworkAPI_Impl.Instance.MakePacketBytes(eventName, payload)); } private static Il2CppStructArray MakeBytes(string eventName, byte[] payload) { return Il2CppStructArray.op_Implicit(NetworkAPI_Impl.Instance.MakeFreeSizedPacketBytes(eventName, payload)); } } [API("Prefab")] public static class PrefabAPI { private static Shader s_CustomGearShader; private static readonly Dictionary> s_SyringeActions = new Dictionary>(); public static ApiStatusInfo Status => APIStatus.Prefab; private static Shader CustomGearShader { get { if ((Object)(object)s_CustomGearShader == (Object)null) { s_CustomGearShader = Shader.Find("Cell/Player/CustomGearShader"); } return s_CustomGearShader; } } public static void CreateConsumable(string assetName, bool enableEmissive = false) { Object loadedAsset = AssetAPI.GetLoadedAsset(assetName); GameObject val = ((loadedAsset != null) ? ((Il2CppObjectBase)loadedAsset).TryCast() : null) ?? null; if ((Object)(object)val == (Object)null) { throw new ArgumentException("Couldn't find a game object asset with the name " + assetName, "assetName"); } ItemEquippable obj = val.AddComponent(); obj.m_isFirstPerson = false; ((Item)obj).m_itemModelHolder = val.transform; ReplaceShaderInAssetMaterials(val, CustomGearShader, enableEmissive ? "ENABLE_EMISSIVE" : null); } public static void CreateConsumablePickup(string assetName, bool enableEmissive = false) { Object loadedAsset = AssetAPI.GetLoadedAsset(assetName); GameObject val = ((loadedAsset != null) ? ((Il2CppObjectBase)loadedAsset).TryCast() : null) ?? null; if ((Object)(object)val == (Object)null) { throw new ArgumentException("Couldn't find a game object asset with the name " + assetName, "assetName"); } BoxCollider componentInChildren = val.GetComponentInChildren(); if ((Object)(object)componentInChildren == (Object)null) { throw new Exception("The Consumable Pickup prefab doesn't contain a BoxCollider for interaction"); } GameObject gameObject = ((Component)componentInChildren).gameObject; gameObject.layer = LayerMask.NameToLayer("Interaction"); Interact_Pickup_PickupItem val2 = gameObject.AddComponent(); ((Interact_Base)val2).m_colliderToOwn = (Collider)(object)componentInChildren; ConsumablePickup_Core obj = val.AddComponent(); obj.m_syncComp = (Component)(object)val.AddComponent(); obj.m_interactComp = (Component)(object)val2; ReplaceShaderInAssetMaterials(val, CustomGearShader, enableEmissive ? "ENABLE_EMISSIVE" : null); } public static void CreateConsumableInstance(string assetName) where T : ConsumableInstance { Object loadedAsset = AssetAPI.GetLoadedAsset(assetName); GameObject obj = ((loadedAsset != null) ? ((Il2CppObjectBase)loadedAsset).TryCast() : null) ?? null; if ((Object)(object)obj == (Object)null) { throw new ArgumentException("Couldn't find a game object asset with the name " + assetName, "assetName"); } if (!ClassInjector.IsTypeRegisteredInIl2Cpp()) { ClassInjector.RegisterTypeInIl2Cpp(); } obj.layer = LayerMask.NameToLayer("Debris"); Rigidbody component = obj.GetComponent(); obj.AddComponent().PhysicsBody = component ?? throw new Exception("The Consumable Instance prefab doesn't contain a Rigidbody"); obj.AddComponent(); } public static void CreateGearComponent(string assetName, bool enableEmissive = false) { Object loadedAsset = AssetAPI.GetLoadedAsset(assetName); GameObject obj = ((loadedAsset != null) ? ((Il2CppObjectBase)loadedAsset).TryCast() : null) ?? null; if ((Object)(object)obj == (Object)null) { throw new ArgumentException("Couldnt find a game object asset with the name " + assetName, "assetName"); } obj.layer = LayerMask.NameToLayer("FirstPersonItem"); ReplaceShaderInAssetMaterials(obj, CustomGearShader, "ENABLE_FPS_RENDERING", enableEmissive ? "ENABLE_EMISSIVE" : null); } public static void CreateSyringe(uint itemPersistentId, Action onUse) { if (s_SyringeActions.ContainsKey(itemPersistentId)) { throw new ArgumentException($"{itemPersistentId} is already registered with a syringe action."); } s_SyringeActions.Add(itemPersistentId, onUse); } internal static bool OnSyringeUsed(SyringeFirstPerson syringe) { if (s_SyringeActions.TryGetValue(((GameDataBlockBase)(object)((Item)syringe).ItemDataBlock).persistentID, out var value)) { value(syringe); return true; } return false; } private static void ReplaceShaderInAssetMaterials(GameObject asset, Shader newShader, params string[] addedKeywords) { addedKeywords = addedKeywords.Where((string x) => !string.IsNullOrEmpty(x)).ToArray(); foreach (MeshRenderer componentsInChild in asset.GetComponentsInChildren(true)) { foreach (Material item in (Il2CppArrayBase)(object)((Renderer)componentsInChild).materials) { item.shader = newShader; if (addedKeywords.Length != 0) { string[] array = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)item.shaderKeywords); int num = array.Length; Array.Resize(ref array, array.Length + addedKeywords.Length); for (int i = 0; i < addedKeywords.Length; i++) { array[num + i] = addedKeywords[i]; } item.shaderKeywords = Il2CppStringArray.op_Implicit(array); } } } } } [API("SoundBank")] public static class SoundBankAPI { public static ApiStatusInfo Status => APIStatus.SoundBank; public static event Action OnSoundBanksLoaded; internal static void Setup() { EventAPI.OnManagersSetup += OnLoadSoundBanks; } private static void OnLoadSoundBanks() { FileInfo[] array = (from file in Directory.CreateDirectory(Path.Combine(Paths.BepInExRootPath, "Assets", "SoundBank")).EnumerateFiles() where file.Extension.Contains(".bnk") select file).ToArray(); CollectionExtensions.Do((IEnumerable)array, (Action)LoadBank); if (array.Any()) { SafeInvoke.Invoke(SoundBankAPI.OnSoundBanksLoaded); } } private unsafe static void LoadBank(FileInfo file) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Invalid comparison between Unknown and I4 //IL_00e6: Unknown result type (might be due to invalid IL or missing references) using FileStream fileStream = file.OpenRead(); uint num = (uint)fileStream.Length; byte[] array = new byte[num]; if (fileStream.Read(array, 0, (int)num) != 0) { void* ptr = NativeMemory.AlignedAlloc(num, 16u); Unsafe.CopyBlock(ref Unsafe.AsRef(ptr), ref array[0], num); uint value = default(uint); AKRESULT val = AkSoundEngine.LoadBank((IntPtr)(nint)ptr, num, ref value); if ((int)val == 1) { APILogger.Info("SoundBankAPI", $"Loaded sound bank '{file.Name}' (bankId: {value:X2})"); } else { APILogger.Error("SoundBankAPI", $"Error while loading sound bank '{file.Name}' ({val})"); NativeMemory.AlignedFree(ptr); } } } } [BepInPlugin("dev.gtfomodding.gtfo-api", "GTFO-API", "0.5.0")] internal class EntryPoint : BasePlugin { private Harmony m_Harmony; public override void Load() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown APILogger.Verbose("Core", "Registering API Implementations"); ClassInjector.RegisterTypeInIl2Cpp(); ClassInjector.RegisterTypeInIl2Cpp(); APILogger.Verbose("Core", "Registering Wrappers"); ClassInjector.RegisterTypeInIl2Cpp(); APILogger.Verbose("Core", "Registering Utilities Implementations"); ClassInjector.RegisterTypeInIl2Cpp(); ClassInjector.RegisterTypeInIl2Cpp(); APILogger.Verbose("Core", "Applying Patches"); m_Harmony = new Harmony("dev.gtfomodding.gtfo-api"); m_Harmony.PatchAll(); EventAPI.Setup(); AssetAPI.Setup(); SoundBankAPI.Setup(); LevelAPI.Setup(); LocalizationAPI.Setup(); APILogger.Verbose("Core", "Plugin Load Complete"); APILogger.Warn("GTFO-API", "Syringes are currently disabled in this version"); } } [GeneratedCode("VersionInfoGenerator", "2.0.0+git50a4b1a-master")] [CompilerGenerated] internal static class VersionInfo { public const string RootNamespace = "GTFO.API"; public const string Version = "0.5.0"; public const string VersionPrerelease = null; public const string VersionMetadata = "gitcd77914-main"; public const string SemVer = "0.5.0+gitcd77914-main"; public const string GitRevShort = "cd77914"; public const string GitRevLong = "cd77914af9eee3a5d9106a4128c5fa3bc02d7ec0"; public const string GitBranch = "main"; public const string GitTag = "0.4.0"; public const bool GitIsDirty = false; } } namespace GTFO.API.Wrappers { public class ItemWrapped : Item { private static readonly Item__Get_pItemData Get_pItemDataBase = Il2CppAPI.GetIl2CppMethod("Get_pItemData", "Player.pItemData", isGeneric: false, Array.Empty()); private static readonly Item__Set_pItemData Set_pItemDataBase = Il2CppAPI.GetIl2CppMethod("Set_pItemData", "System.Void", isGeneric: false, new string[1] { "Player.pItemData" }); private static readonly Item__GetCustomData GetCustomDataBase = Il2CppAPI.GetIl2CppMethod("GetCustomData", "Player.pItemData_Custom", isGeneric: false, Array.Empty()); private static readonly Item__SetCustomData SetCustomDataBase = Il2CppAPI.GetIl2CppMethod("SetCustomData", "System.Void", isGeneric: false, new string[2] { "Player.pItemData_Custom", "System.Boolean" }); private static readonly Item__OnCustomDataUpdated OnCustomDataUpdatedBase = Il2CppAPI.GetIl2CppMethod("OnCustomDataUpdated", "System.Void", isGeneric: false, new string[1] { "Player.pItemData_Custom" }); private static readonly Item__Awake AwakeBase = Il2CppAPI.GetIl2CppMethod("Awake", "System.Void", isGeneric: false, Array.Empty()); private static readonly Item__OnDespawn OnDespawnBase = Il2CppAPI.GetIl2CppMethod("OnDespawn", "System.Void", isGeneric: false, Array.Empty()); private static readonly Item__Setup SetupBase = Il2CppAPI.GetIl2CppMethod("Setup", "System.Void", isGeneric: false, new string[1] { "GameData.ItemDataBlock" }); private static readonly Item__OnGearSpawnComplete OnGearSpawnCompleteBase = Il2CppAPI.GetIl2CppMethod("OnGearSpawnComplete", "System.Void", isGeneric: false, Array.Empty()); private static readonly Item__OnPickUp OnPickUpBase = Il2CppAPI.GetIl2CppMethod("OnPickUp", "System.Void", isGeneric: false, new string[1] { "Player.PlayerAgent" }); private static readonly Item__SetupBaseModel SetupBaseModelBase = Il2CppAPI.GetIl2CppMethod("SetupBaseModel", "System.Void", isGeneric: false, new string[1] { "ItemSetup.ItemModelSetup" }); private static readonly Item__SyncedTurnOn SyncedTurnOnBase = Il2CppAPI.GetIl2CppMethod("SyncedTurnOn", "System.Void", isGeneric: false, new string[2] { "Player.PlayerAgent", "AIGraph.AIG_CourseNode" }); private static readonly Item__SyncedTurnOff SyncedTurnOffBase = Il2CppAPI.GetIl2CppMethod("SyncedTurnOff", "System.Void", isGeneric: false, new string[1] { "Player.PlayerAgent" }); private static readonly Item__SyncedTrigger SyncedTriggerBase = Il2CppAPI.GetIl2CppMethod("SyncedTrigger", "System.Void", isGeneric: false, new string[1] { "Player.PlayerAgent" }); private static readonly Item__SyncedTriggerSecondary SyncedTriggerSecondaryBase = Il2CppAPI.GetIl2CppMethod("SyncedTriggerSecondary", "System.Void", isGeneric: false, new string[1] { "Player.PlayerAgent" }); private static readonly Item__SyncedThrow SyncedThrowBase = Il2CppAPI.GetIl2CppMethod("SyncedThrow", "System.Void", isGeneric: false, new string[1] { "Player.PlayerAgent" }); private static readonly Item__SyncedPickup SyncedPickupBase = Il2CppAPI.GetIl2CppMethod("SyncedPickup", "System.Void", isGeneric: false, new string[1] { "Player.PlayerAgent" }); private static readonly Item__SyncedSetKeyValue SyncedSetKeyValueBase = Il2CppAPI.GetIl2CppMethod("SyncedSetKeyValue", "System.Void", isGeneric: false, new string[2] { "System.Int32", "System.Single" }); private static readonly Item__GetPickupInteraction GetPickupInteractionBase = Il2CppAPI.GetIl2CppMethod("GetPickupInteraction", "Interact_Base", isGeneric: false, Array.Empty()); private static readonly Item__GetItem GetItemBase = Il2CppAPI.GetIl2CppMethod("GetItem", "Item", isGeneric: false, Array.Empty()); public ItemWrapped(IntPtr hdl) : base(hdl) { } public unsafe override pItemData Get_pItemData() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) pItemData* retstr = (pItemData*)stackalloc pItemData[1]; return *Get_pItemDataBase(retstr, ((Il2CppObjectBase)this).Pointer.ToPointer()); } public unsafe override void Set_pItemData(pItemData data) { Set_pItemDataBase(((Il2CppObjectBase)this).Pointer.ToPointer(), &data); } public unsafe override pItemData_Custom GetCustomData() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) return *GetCustomDataBase(((Il2CppObjectBase)this).Pointer.ToPointer()); } public unsafe override void SetCustomData(pItemData_Custom custom, bool sync) { SetCustomDataBase(((Il2CppObjectBase)this).Pointer.ToPointer(), &custom, sync); } public unsafe override void OnCustomDataUpdated(pItemData_Custom customDataCopy) { OnCustomDataUpdatedBase(((Il2CppObjectBase)this).Pointer.ToPointer(), &customDataCopy); } public unsafe override void Awake() { AwakeBase(((Il2CppObjectBase)this).Pointer.ToPointer()); } public unsafe override void OnDespawn() { OnDespawnBase(((Il2CppObjectBase)this).Pointer.ToPointer()); } public unsafe override void Setup(ItemDataBlock data) { SetupBase(((Il2CppObjectBase)this).Pointer.ToPointer(), ((Il2CppObjectBase)data).Pointer.ToPointer()); } public unsafe override void OnGearSpawnComplete() { OnGearSpawnCompleteBase(((Il2CppObjectBase)this).Pointer.ToPointer()); } public unsafe override void OnPickUp(PlayerAgent player) { OnPickUpBase(((Il2CppObjectBase)this).Pointer.ToPointer(), ((Il2CppObjectBase)player).Pointer.ToPointer()); } public unsafe override void SetupBaseModel(ItemModelSetup setup) { SetupBaseModelBase(((Il2CppObjectBase)this).Pointer.ToPointer(), ((Il2CppObjectBase)setup).Pointer.ToPointer()); } public unsafe override void SyncedTurnOn(PlayerAgent agent, AIG_CourseNode courseNode) { SyncedTurnOnBase(((Il2CppObjectBase)this).Pointer.ToPointer(), ((Il2CppObjectBase)agent).Pointer.ToPointer(), ((Il2CppObjectBase)courseNode).Pointer.ToPointer()); } public unsafe override void SyncedTurnOff(PlayerAgent agent) { SyncedTurnOffBase(((Il2CppObjectBase)this).Pointer.ToPointer(), ((Il2CppObjectBase)agent).Pointer.ToPointer()); } public unsafe override void SyncedTrigger(PlayerAgent agent) { SyncedTriggerBase(((Il2CppObjectBase)this).Pointer.ToPointer(), ((Il2CppObjectBase)agent).Pointer.ToPointer()); } public unsafe override void SyncedTriggerSecondary(PlayerAgent agent) { SyncedTriggerSecondaryBase(((Il2CppObjectBase)this).Pointer.ToPointer(), ((Il2CppObjectBase)agent).Pointer.ToPointer()); } public unsafe override void SyncedThrow(PlayerAgent agent) { SyncedThrowBase(((Il2CppObjectBase)this).Pointer.ToPointer(), ((Il2CppObjectBase)agent).Pointer.ToPointer()); } public unsafe override void SyncedPickup(PlayerAgent agent) { SyncedPickupBase(((Il2CppObjectBase)this).Pointer.ToPointer(), ((Il2CppObjectBase)agent).Pointer.ToPointer()); } public unsafe override void SyncedSetKeyValue(int key, float value) { SyncedSetKeyValueBase(((Il2CppObjectBase)this).Pointer.ToPointer(), key, value); } public unsafe override Interact_Base GetPickupInteraction() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown return new Interact_Base((IntPtr)GetPickupInteractionBase(((Il2CppObjectBase)this).Pointer.ToPointer())); } public unsafe override Item GetItem() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown return new Item((IntPtr)GetItemBase(((Il2CppObjectBase)this).Pointer.ToPointer())); } } public unsafe delegate pItemData* Item__Get_pItemData(pItemData* retstr, void* _this); public unsafe delegate void Item__Set_pItemData(void* _this, void* data); public unsafe delegate pItemData_Custom* Item__GetCustomData(void* _this); public unsafe delegate void Item__SetCustomData(void* _this, pItemData_Custom* custom, bool sync); public unsafe delegate void Item__OnCustomDataUpdated(void* _this, pItemData_Custom* customDataCopy); public unsafe delegate void Item__Awake(void* _this); public unsafe delegate void Item__OnDespawn(void* _this); public unsafe delegate void Item__Setup(void* _this, void* data); public unsafe delegate void Item__OnGearSpawnComplete(void* _this); public unsafe delegate void Item__OnPickUp(void* _this, void* player); public unsafe delegate void Item__SetupBaseModel(void* _this, void* setup); public unsafe delegate void Item__SyncedTurnOn(void* _this, void* agent, void* courseNode); public unsafe delegate void Item__SyncedTurnOff(void* _this, void* agent); public unsafe delegate void Item__SyncedTrigger(void* _this, void* agent); public unsafe delegate void Item__SyncedTriggerSecondary(void* _this, void* agent); public unsafe delegate void Item__SyncedThrow(void* _this, void* agent); public unsafe delegate void Item__SyncedPickup(void* _this, void* agent); public unsafe delegate void Item__SyncedSetKeyValue(void* _this, int key, float value); public unsafe delegate void* Item__GetPickupInteraction(void* _this); public unsafe delegate void* Item__GetItem(void* _this); [Il2CppInterface(typeof(iTerminalItem))] public interface iTerminalItemWrapper { uint TerminalItemId { get; set; } string TerminalItemKey { get; set; } string OverrideCode { get; set; } Vector3 LocatorBeaconPosition { get; set; } AIG_CourseNode SpawnNode { get; set; } bool ShowInFloorInventory { get; set; } string FloorItemLocation { get; set; } eFloorInventoryObjectType FloorItemType { get; set; } eFloorInventoryObjectStatus FloorItemStatus { get; set; } Func, List> OnWantDetailedInfo { get; set; } void Setup(string key); List GetDetailedInfo(List defaultDetails); void PlayPing(); } [Il2CppInterface(typeof(iResourcePackReceiver))] public interface iResourcePackReceiverWrapper { bool IsLocallyOwned { get; } string InteractionName { get; } bool NeedHealth(); bool NeedDisinfection(); bool NeedWeaponAmmo(); bool NeedToolAmmo(); void GiveAmmoRel(float ammoStandardRel, float ammoSpecialRel, float ammoClassRel); void GiveHealth(float health); void GiveDisinfection(float disinfection); } [Il2CppInterface(typeof(iPlayerPingTarget))] public interface iPlayerPingTargetWrapper { eNavMarkerStyle PingTargetStyle { get; set; } } [Il2CppInterface(typeof(iWardenObjectiveItem))] public interface iWardenObjectiveItemWrapper { LG_LayerType OriginLayer { get; } AIG_CourseNode SpawnNode { get; } string PublicName { get; } Transform transform { get; } bool ObjectiveItemSolved { get; } ePickupItemStatus PickupItemStatus { get; } PlayerAgent PickedUpByPlayer { get; } void ActivateWardenObjectiveItem(); void DeactivateWardenObjectiveItem(); } } namespace GTFO.API.Utilities { public static class CoroutineDispatcher { public static Coroutine StartCoroutine(IEnumerator routine) { return CoroutineDispatcher_Impl.Instance.RunCoroutine(routine); } public static Coroutine StartInLevelCoroutine(IEnumerator routine) { return CoroutineDispatcher_Impl.Instance.RunInLevelCoroutine(routine); } } public delegate void LiveEditEventHandler(LiveEditEventArgs e); public class LiveEditEventArgs { public LiveEditEventType Type { get; set; } public string FullPath { get; set; } public string FileName { get; set; } } public enum LiveEditEventType { Created, Deleted, Renamed, Changed } public static class LiveEdit { internal const int RETRY_COUNT = 5; internal const float RETRY_INTERVAL = 0.1f; internal static readonly List s_Listeners = new List(); public static LiveEditListener CreateListener(string path, string filter, bool includeSubDir) { LiveEditListener liveEditListener = new LiveEditListener(path, filter, includeSubDir); s_Listeners.Add(liveEditListener); return liveEditListener; } public static void TryReadFileContent(string filepath, Action onReaded) { CoroutineDispatcher.StartCoroutine(GetFileStream(filepath, 5, 0.1f, delegate(FileStream stream) { try { using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); onReaded?.Invoke(streamReader.ReadToEnd()); } catch { } })); } private static IEnumerator GetFileStream(string filepath, int retryCount, float retryInterval, Action onFileStreamOpened) { retryCount = Math.Max(retryCount, 1); retryInterval = Math.Max(retryInterval, 0f); WaitForSecondsRealtime wait = new WaitForSecondsRealtime(retryInterval); for (int i = 0; i < retryCount; i++) { try { FileStream fileStream = new FileStream(filepath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); onFileStreamOpened?.Invoke(fileStream); fileStream.Close(); break; } catch { } yield return wait; } } } public sealed class LiveEditListener : IDisposable { private FileSystemWatcher m_Watcher; private bool m_Allocated = true; private float m_ChangedCooldownTimer; public float FileChangedEventCooldown { get; set; } = 0.05f; public event LiveEditEventHandler FileChanged; public event LiveEditEventHandler FileDeleted; public event LiveEditEventHandler FileCreated; public event LiveEditEventHandler FileRenamed; private LiveEditListener() { } internal LiveEditListener(string path, string filter, bool includeSubDir) { LiveEditListener liveEditListener = this; m_Watcher = new FileSystemWatcher { Path = path, Filter = filter, IncludeSubdirectories = includeSubDir, NotifyFilter = (NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime) }; m_Watcher.Deleted += delegate(object sender, FileSystemEventArgs e) { FileSystemEventArgs e5 = e; ThreadDispatcher.Dispatch(delegate { liveEditListener.FileDeleted?.Invoke(CreateArgs(e5, LiveEditEventType.Deleted)); }); }; m_Watcher.Created += delegate(object sender, FileSystemEventArgs e) { FileSystemEventArgs e4 = e; ThreadDispatcher.Dispatch(delegate { liveEditListener.FileCreated?.Invoke(CreateArgs(e4, LiveEditEventType.Created)); }); }; m_Watcher.Renamed += delegate(object sender, RenamedEventArgs e) { RenamedEventArgs e3 = e; ThreadDispatcher.Dispatch(delegate { liveEditListener.FileRenamed?.Invoke(CreateArgs(e3, LiveEditEventType.Renamed)); }); }; m_Watcher.Changed += delegate(object sender, FileSystemEventArgs e) { FileSystemEventArgs e2 = e; ThreadDispatcher.Dispatch(delegate { float time = Time.time; if (!(liveEditListener.m_ChangedCooldownTimer > time)) { liveEditListener.m_ChangedCooldownTimer = time + liveEditListener.FileChangedEventCooldown; liveEditListener.FileChanged?.Invoke(CreateArgs(e2, LiveEditEventType.Changed)); } }); }; m_Watcher.Error += delegate(object sender, ErrorEventArgs e) { APILogger.Error("LiveEdit", $"Path: {path} error reported! - {e.GetException()}"); }; StartListen(); } private static LiveEditEventArgs CreateArgs(FileSystemEventArgs args, LiveEditEventType type) { return new LiveEditEventArgs { FullPath = args.FullPath, FileName = Path.GetFileName(args.FullPath), Type = type }; } public void Dispose() { if (m_Allocated) { LiveEdit.s_Listeners.Remove(this); m_Allocated = false; } if (m_Watcher != null) { StopListen(); this.FileChanged = null; this.FileDeleted = null; this.FileCreated = null; this.FileRenamed = null; m_Watcher.Dispose(); } m_Watcher = null; } public void StopListen() { if (m_Watcher != null) { m_Watcher.EnableRaisingEvents = false; } } public void StartListen() { if (m_Watcher != null) { m_Watcher.EnableRaisingEvents = true; } } } internal static class MemoryUtils { private static byte[] _trampolineShellcode = new byte[12] { 72, 184, 0, 0, 0, 0, 0, 0, 0, 0, 255, 208 }; public unsafe static void* FindSignatureInBlock(void* block, ulong blockSize, string pattern, string mask, ulong sigOffset = 0uL) { return FindSignatureInBlock(block, blockSize, pattern.ToCharArray(), mask.ToCharArray(), sigOffset); } public unsafe static void* FindSignatureInBlock(void* block, ulong blockSize, char[] pattern, char[] mask, ulong sigOffset = 0uL) { for (ulong num = 0uL; num < blockSize; num++) { bool flag = true; for (uint num2 = 0u; num2 < mask.Length; num2++) { if (*(byte*)((long)num + (long)block + num2) != (byte)pattern[num2] && mask[num2] != '?') { flag = false; break; } } if (flag) { return (void*)((ulong)((long)num + (long)block) + sigOffset); } } return null; } public unsafe static byte[] MakeTrampoline(void* destination) { byte[] array = new byte[_trampolineShellcode.Length]; Array.Copy(_trampolineShellcode, 0, array, 0, _trampolineShellcode.Length); fixed (byte* ptr = array) { *(long*)(ptr + 2) = (long)destination; } return array; } public unsafe static void CreateTrampolineBetween(void* start, void* end, void* destination) { ulong num = (ulong)end - (ulong)start; if (num < (ulong)_trampolineShellcode.Length) { throw new Exception("Trampoline block size is not enough to create."); } uint flNewProtect = default(uint); if (!Kernel32.VirtualProtect(start, num, 64u, &flNewProtect)) { throw new Exception("Failed to change protection of trampoline block."); } APILogger.Verbose("MemoryUtils", "NOPing trampoline block"); for (ulong num2 = 0uL; num2 < num; num2++) { *(sbyte*)((ulong)start + num2) = -112; } APILogger.Verbose("MemoryUtils", "Creating trampoline shellcode"); byte[] array = MakeTrampoline(destination); APILogger.Verbose("MemoryUtils", "Writing trampoline shellcode"); for (ulong num3 = 0uL; num3 < (ulong)array.Length; num3++) { *(byte*)((ulong)start + num3) = array[num3]; } if (!Kernel32.VirtualProtect(start, num, flNewProtect, &flNewProtect)) { throw new Exception("Failed to revert trampoline block protection."); } } } public class PersistentData where T : PersistentData, new() { private const string VERSION_REGEX = "\"PersistentDataVersion\": \"(.+?)\""; private static T s_CurrentData; public static T CurrentData { get { if (s_CurrentData != null) { return s_CurrentData; } s_CurrentData = Load(); return s_CurrentData; } set { s_CurrentData = value; } } protected static string persistentPath => Path.Combine(Paths.BepInExRootPath, "GameData", "PersistentData", typeof(T).Assembly.GetName().Name, typeof(T).Name + ".json"); public virtual string PersistentDataVersion { get; set; } = "1.0.0"; public static T Load() { return Load(persistentPath); } public static T Load(string path) { T val = new T(); if (File.Exists(path)) { string text = File.ReadAllText(path); T val2; try { val2 = GTFO.API.JSON.JsonSerializer.Deserialize(text); } catch (JsonException) { APILogger.Warn("JSON", "Failed to deserialize " + typeof(T).Name + ", replacing with default"); string text2 = "FAILED"; Match match = Regex.Match(text, "\"PersistentDataVersion\": \"(.+?)\""); if (match.Success) { text2 = match.Groups[1].Value + "-FAILED"; } File.WriteAllText(Path.ChangeExtension(path, null) + "-" + text2 + ".json", text); val2 = new T(); val2.Save(path); } if (val2.PersistentDataVersion != val.PersistentDataVersion) { val2.Save(Path.ChangeExtension(path, null) + "-" + val2.PersistentDataVersion + ".json"); val.Save(path); } else { val = val2; } } else { val.Save(path); } return val; } public void Save() { Save(persistentPath); } public void Save(string path) { string contents = GTFO.API.JSON.JsonSerializer.Serialize((T)this); string directoryName = Path.GetDirectoryName(path); if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } File.WriteAllText(path, contents); } } public static class RegexUtils { private static readonly Regex s_VectorRegex = new Regex("-?[0-9.]+"); public static bool TryParseVectorString(string input, out float[] vectorArray) { try { MatchCollection matchCollection = s_VectorRegex.Matches(input); int count = matchCollection.Count; if (count < 1) { throw new Exception(); } vectorArray = new float[count]; for (int i = 0; i < count; i++) { Match match = matchCollection[i]; vectorArray[i] = float.Parse(match.Value, CultureInfo.InvariantCulture); } return true; } catch { vectorArray = null; return false; } } } public static class SafeInvoke { public static void Invoke(Action actionToInvoke) { if (actionToInvoke == null) { return; } foreach (Action item in actionToInvoke.GetInvocationList().Cast()) { try { item(); } catch (Exception value) { APILogger.Error("GTFO-API", $"Exception occured while invoking events!\n{value}"); } } } public static void Invoke(Action actionToInvoke, T arg0) { if (actionToInvoke == null) { return; } foreach (Action item in actionToInvoke.GetInvocationList().Cast>()) { try { item(arg0); } catch (Exception value) { APILogger.Error("GTFO-API", $"Exception occured while invoking events!\n{value}"); } } } public static void Invoke(Action actionToInvoke, T0 arg0, T1 arg1) { if (actionToInvoke == null) { return; } foreach (Action item in actionToInvoke.GetInvocationList().Cast>()) { try { item(arg0, arg1); } catch (Exception value) { APILogger.Error("GTFO-API", $"Exception occured while invoking events!\n{value}"); } } } public static void Invoke(Action actionToInvoke, T0 arg0, T1 arg1, T2 arg2) { if (actionToInvoke == null) { return; } foreach (Action item in actionToInvoke.GetInvocationList().Cast>()) { try { item(arg0, arg1, arg2); } catch (Exception value) { APILogger.Error("GTFO-API", $"Exception occured while invoking events!\n{value}"); } } } public static void InvokeDelegate(Delegate delegateToInvoke, Action invoke) where D : Delegate { if ((object)delegateToInvoke == null) { return; } foreach (D item in delegateToInvoke.GetInvocationList().Cast()) { try { invoke(item); } catch (Exception value) { APILogger.Error("GTFO-API", $"Exception occured while invoking events!\n{value}"); } } } } public static class StringUtils { private static readonly uint[] _lookup32 = ((Func)delegate { uint[] array = new uint[256]; for (int i = 0; i < 256; i++) { string text = i.ToString("X2"); if (BitConverter.IsLittleEndian) { array[i] = text[0] + ((uint)text[1] << 16); } else { array[i] = text[1] + ((uint)text[0] << 16); } } return array; })(); private unsafe static readonly uint* _lookup32Ptr = (uint*)(void*)GCHandle.Alloc(_lookup32, GCHandleType.Pinned).AddrOfPinnedObject(); public unsafe static string FromByteArrayAsHex(byte[] bytes) { char[] array = new char[bytes.Length * 2]; fixed (byte* ptr3 = bytes) { fixed (char* ptr = array) { uint* ptr2 = (uint*)ptr; for (int i = 0; i < bytes.Length; i++) { ptr2[i] = _lookup32Ptr[(int)ptr3[i]]; } } } return new string(array); } } public static class ThreadDispatcher { public static void Dispatch(Action action) { ThreadDispatcher_Impl.Instance.EnqueueAction(action); } } } namespace GTFO.API.Utilities.Impl { internal class CoroutineDispatcher_Impl : MonoBehaviour { private bool m_HasInLevelCoroutines; private readonly List m_InLevelCoroutines = new List(); private static CoroutineDispatcher_Impl s_Instance; public static CoroutineDispatcher_Impl Instance { get { if ((Object)(object)s_Instance == (Object)null) { CoroutineDispatcher_Impl coroutineDispatcher_Impl = Object.FindObjectOfType(); if ((Object)(object)coroutineDispatcher_Impl != (Object)null) { s_Instance = coroutineDispatcher_Impl; } } return s_Instance; } } static CoroutineDispatcher_Impl() { AssetAPI.OnStartupAssetsLoaded += OnAssetsLoaded; } private static void OnAssetsLoaded() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if (!((Object)(object)s_Instance != (Object)null)) { GameObject val = new GameObject(); CoroutineDispatcher_Impl coroutineDispatcher_Impl = val.AddComponent(); ((Object)val).name = "GTFO-API Coroutine Dispatcher"; ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)val); s_Instance = coroutineDispatcher_Impl; } } private void Update() { if (m_HasInLevelCoroutines && !GameStateManager.IsInExpedition) { m_InLevelCoroutines.ForEach(delegate(Coroutine coroutine) { ((MonoBehaviour)this).StopCoroutine(coroutine); }); m_InLevelCoroutines.Clear(); m_HasInLevelCoroutines = false; } } [HideFromIl2Cpp] internal Coroutine RunCoroutine(IEnumerator routine) { return MonoBehaviourExtensions.StartCoroutine((MonoBehaviour)(object)this, routine); } [HideFromIl2Cpp] internal Coroutine RunInLevelCoroutine(IEnumerator routine) { if (!GameStateManager.IsInExpedition) { APILogger.Error("CoroutineDispatcher", "Cannot run InLevelCoroutine while you're not in level!"); return null; } Coroutine val = MonoBehaviourExtensions.StartCoroutine((MonoBehaviour)(object)this, routine); m_InLevelCoroutines.Add(val); m_HasInLevelCoroutines = true; return val; } } internal class ThreadDispatcher_Impl : MonoBehaviour { private readonly Queue s_ActionQueue = new Queue(); private static ThreadDispatcher_Impl s_Instance; public static ThreadDispatcher_Impl Instance { get { if ((Object)(object)s_Instance == (Object)null) { ThreadDispatcher_Impl threadDispatcher_Impl = Object.FindObjectOfType(); if ((Object)(object)threadDispatcher_Impl != (Object)null) { s_Instance = threadDispatcher_Impl; } } return s_Instance; } } public ThreadDispatcher_Impl(IntPtr intPtr) : base(intPtr) { } static ThreadDispatcher_Impl() { AssetAPI.OnStartupAssetsLoaded += OnAssetsLoaded; } private static void OnAssetsLoaded() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if (!((Object)(object)s_Instance != (Object)null)) { GameObject val = new GameObject(); ThreadDispatcher_Impl threadDispatcher_Impl = val.AddComponent(); ((Object)val).name = "GTFO-API Thread Dispatcher"; ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)val); s_Instance = threadDispatcher_Impl; } } [HideFromIl2Cpp] internal void EnqueueAction(Action action) { lock (s_ActionQueue) { s_ActionQueue.Enqueue(action); } } internal void Update() { lock (s_ActionQueue) { while (s_ActionQueue.Count > 0) { s_ActionQueue.Dequeue()?.Invoke(); } } } } } namespace GTFO.API.Resources { public class ApiStatusInfo { public bool Created { get; internal set; } public bool Ready { get; internal set; } } public static class APIStatus { private static GameObject s_ScriptHolder; public static ApiStatusInfo Asset { get; internal set; } = new ApiStatusInfo(); public static ApiStatusInfo Event { get; internal set; } = new ApiStatusInfo(); public static ApiStatusInfo GameData { get; internal set; } = new ApiStatusInfo(); public static ApiStatusInfo Localization { get; internal set; } = new ApiStatusInfo(); public static ApiStatusInfo Il2Cpp { get; internal set; } = new ApiStatusInfo(); public static ApiStatusInfo Level { get; internal set; } = new ApiStatusInfo(); public static ApiStatusInfo Network { get; internal set; } = new ApiStatusInfo(); public static ApiStatusInfo Prefab { get; internal set; } = new ApiStatusInfo(); public static ApiStatusInfo SoundBank { get; internal set; } = new ApiStatusInfo(); public static ApiStatusInfo Interop { get; internal set; } = new ApiStatusInfo(); internal static GameObject ScriptHolder { get { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown if ((Object)(object)s_ScriptHolder == (Object)null) { s_ScriptHolder = new GameObject(); ((Object)s_ScriptHolder).name = "GTFO-API Script Holder"; ((Object)s_ScriptHolder).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)s_ScriptHolder); } return s_ScriptHolder; } } internal static void CreateApi(string apiName) where T : Component { ApiStatusInfo apiStatusInfo = (ApiStatusInfo)(typeof(APIStatus).GetProperty(apiName)?.GetValue(null)); if (apiStatusInfo == null) { throw new ArgumentException("Couldn't find API status for " + apiName, "apiName"); } if (!apiStatusInfo.Created && !((Object)(object)ScriptHolder.GetComponent() != (Object)null)) { APILogger.Verbose("Core", "Creating API " + apiName); ScriptHolder.AddComponent(); apiStatusInfo.Created = true; } } } internal static class RuntimeData { public static Dictionary BotFavorites; } public static class ShaderConstants { public const string CUSTOM_GEAR_SHADER = "Cell/Player/CustomGearShader"; } public static class NetworkConstants { public const string Magic = "GAPI_KSQK"; public const byte MagicSize = 9; public const ulong VersionSignature = 18374688234229425498uL; } } namespace GTFO.API.Patches { [HarmonyPatch(typeof(CellSettingsApply), "ApplyLanguage")] internal static class ApplyLanguage_Patches { private static bool s_LanguageChanged; [HarmonyWrapSafe] public static void Prefix(int value) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 s_LanguageChanged = (int)Text.TextLocalizationService.CurrentLanguage != value; } [HarmonyWrapSafe] public static void Postfix() { if (s_LanguageChanged) { LocalizationAPI.LanguageChanged(); } } } [HarmonyPatch(typeof(AssetShardManager))] internal class AssetShardManager_Patches { [HarmonyPatch("Setup")] [HarmonyWrapSafe] [HarmonyPostfix] public static void Setup_Postfix() { if (!APIStatus.Asset.Created) { APIStatus.CreateApi("Asset"); } } } [HarmonyPatch(typeof(Builder))] internal class Builder_Patches { [HarmonyPatch("Build")] [HarmonyWrapSafe] [HarmonyPostfix] private static void BuildStart_Postfix() { LevelAPI.BuildStart(); } [HarmonyPatch("BuildDone")] [HarmonyWrapSafe] [HarmonyPostfix] private static void BuildDone_Postfix() { LevelAPI.BuildDone(); } } [HarmonyPatch(typeof(GameDataInit))] internal class GameDataInit_Patches { private struct PluginWhitelistInfo { public string GUID; public string Name; public string Version; public string Checksum; } private static PluginWhitelistInfo[] FetchPluginWhitelist() { using HttpClient httpClient = new HttpClient(); using Stream stream = httpClient.GetStreamAsync("https://raw.githubusercontent.com/GTFO-Modding/GTFO-API-PluginWhitelist/main/whitelist.txt").GetAwaiter().GetResult(); using StreamReader streamReader = new StreamReader(stream); string[] array = streamReader.ReadToEnd().Split('\n', StringSplitOptions.RemoveEmptyEntries); PluginWhitelistInfo[] array2 = new PluginWhitelistInfo[array.Length]; for (int i = 0; i < array2.Length; i++) { string[] array3 = array[i].Split(":"); array2[i] = new PluginWhitelistInfo { GUID = array3[0], Name = array3[1], Version = array3[2], Checksum = array3[3].TrimEnd('\r') }; } return array2; } [HarmonyPatch("Initialize")] [HarmonyWrapSafe] [HarmonyPostfix] public static void Initialize_Postfix() { Analytics.enabled = false; GameDataAPI.InvokeGameDataInit(); if (!APIStatus.Network.Created) { APIStatus.CreateApi("Network"); } } private static void RemoveRequirementFromList(List list) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 Enumerator enumerator = list.GetEnumerator(); while (enumerator.MoveNext()) { ExpeditionInTierData current = enumerator.Current; if (current.Enabled) { eExpeditionAccessibility accessibility = current.Accessibility; if ((int)accessibility == 0 || accessibility - 4 <= 1) { current.Accessibility = (eExpeditionAccessibility)2; } } } } } [HarmonyPatch(typeof(GearManager))] internal static class GearManager_Patches { private unsafe delegate IntPtr ReadFromDiskDelegate(IntPtr path, byte* createNew, Il2CppMethodInfo* methodInfo); private unsafe delegate void SaveToDiskDelegate(IntPtr path, IntPtr obj, Il2CppMethodInfo* methodInfo); private static bool m_PatchApplied; private static INativeDetour s_ReadFromDiskDetour; private static ReadFromDiskDelegate s_ReadFromDiskOriginal; private static INativeDetour s_SaveToDiskDetour; private static SaveToDiskDelegate s_SaveToDiskOriginal; private static string FavoritesDirectory => Path.Combine(Paths.BepInExRootPath, "GameData", "Favorites"); private static string FavoritePath => Path.Combine(FavoritesDirectory, "Gear.json"); private static string BotFavoritePath => Path.Combine(FavoritesDirectory, "BotGear.json"); [HarmonyPatch("Setup")] [HarmonyWrapSafe] [HarmonyPrefix] private unsafe static void Setup_Prefix() { if (!m_PatchApplied) { if (!Directory.Exists(FavoritesDirectory)) { Directory.CreateDirectory(FavoritesDirectory); } string methodName = "SaveToDisk"; APILogger.Verbose("GearManager_Patches", "Applying ReadFromDisk Patch"); s_ReadFromDiskDetour = Il2CppAPI.CreateGenericDetour("ReadFromDisk", "T", new string[2] { typeof(string).FullName, typeof(bool).MakeByRefType().FullName }, new Type[1] { typeof(GearFavoritesData) }, (ReadFromDiskDelegate)Patch_ReadFromDisk, out s_ReadFromDiskOriginal); APILogger.Verbose("GearManager_Patches", "Applying SaveToDisk Patch"); s_SaveToDiskDetour = Il2CppAPI.CreateGenericDetour(methodName, typeof(void).FullName, new string[2] { typeof(string).FullName, "T" }, new Type[1] { typeof(GearFavoritesData) }, (SaveToDiskDelegate)Patch_SaveToDisk, out s_SaveToDiskOriginal); m_PatchApplied = true; } } private unsafe static IntPtr Patch_ReadFromDisk(IntPtr path, byte* createNew, Il2CppMethodInfo* methodInfo) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown string text = String.op_Implicit(new String(path)); if (text.EndsWith("GTFO_Favorites.txt", StringComparison.OrdinalIgnoreCase)) { return s_ReadFromDiskOriginal(IL2CPP.ManagedStringToIl2Cpp(FavoritePath), createNew, methodInfo); } if (text.EndsWith("GTFO_BotFavorites.txt", StringComparison.OrdinalIgnoreCase)) { return s_ReadFromDiskOriginal(IL2CPP.ManagedStringToIl2Cpp(BotFavoritePath), createNew, methodInfo); } return s_ReadFromDiskOriginal(path, createNew, methodInfo); } private unsafe static void Patch_SaveToDisk(IntPtr path, IntPtr favData, Il2CppMethodInfo* methodInfo) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown string text = String.op_Implicit(new String(path)); if (text.EndsWith("GTFO_Favorites.txt", StringComparison.OrdinalIgnoreCase)) { s_SaveToDiskOriginal(IL2CPP.ManagedStringToIl2Cpp(FavoritePath), favData, methodInfo); } else if (text.EndsWith("GTFO_BotFavorites.txt", StringComparison.OrdinalIgnoreCase)) { s_SaveToDiskOriginal(IL2CPP.ManagedStringToIl2Cpp(BotFavoritePath), favData, methodInfo); if (File.Exists(text)) { File.Delete(text); } } else { s_SaveToDiskOriginal(path, favData, methodInfo); } } } [HarmonyPatch(typeof(Global))] internal class Global_Patches { [HarmonyPatch("OnLevelCleanup")] [HarmonyWrapSafe] [HarmonyPostfix] private static void LevelCleanup_Postfix() { LevelAPI.LevelCleanup(); } } [HarmonyPatch(typeof(LG_Factory))] internal static class LevelGen_Patches { [HarmonyPostfix] [HarmonyWrapSafe] [HarmonyPatch("OnStart")] private static void Post_Start() { LevelAPI.FactoryStart(); } [HarmonyPrefix] [HarmonyWrapSafe] [HarmonyPatch("NextBatch")] private static void Pre_Batch(LG_Factory __instance) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (__instance.m_batchStep > -1) { LevelAPI.AfterBuildBatch(__instance.m_currentBatchName); } } [HarmonyPostfix] [HarmonyWrapSafe] [HarmonyPatch("NextBatch")] private static void Post_Batch(LG_Factory __instance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) LevelAPI.BeforeBuildBatch(__instance.m_currentBatchName); } [HarmonyPostfix] [HarmonyWrapSafe] [HarmonyPatch("FactoryDone")] private static void Post_Finished() { LevelAPI.FactoryFinished(); } } [HarmonyPatch(typeof(RundownManager))] internal class RundownManager_Patches { [HarmonyPatch("SetActiveExpedition")] [HarmonyWrapSafe] [HarmonyPostfix] private static void SetActiveExpedition_Postfix(pActiveExpedition expPackage, ExpeditionInTierData expTierData) { LevelAPI.ExpeditionUpdated(expPackage, expTierData); } } [HarmonyPatch(typeof(SNet_Replication))] internal class SNet_Replication_Patches { [HarmonyPatch("RecieveBytes")] [HarmonyWrapSafe] [HarmonyPrefix] public static bool RecieveBytes_Prefix(Il2CppStructArray bytes, uint size, ulong messagerID) { if (size < 12) { return true; } byte[] array = Il2CppArrayBase.op_Implicit((Il2CppArrayBase)(object)bytes); ushort num = BitConverter.ToUInt16(array, 0); if (NetworkAPI_Impl.Instance.m_ReplicatorKey == num) { string @string = Encoding.ASCII.GetString(array, 2, 9); if (@string != "GAPI_KSQK") { APILogger.Verbose("NetworkApi", $"Received invalid magic from {messagerID} ({@string} != {9})."); return true; } ulong num2 = BitConverter.ToUInt64(array, 11); if ((num2 & 0xFF00000000000000uL) != 18374686479671623680uL) { APILogger.Verbose("NetworkApi", $"Received invalid version signature from {messagerID}."); return true; } if (num2 != NetworkAPI_Impl.Instance.m_Signature) { APILogger.Error("NetworkApi", $"Received incompatible version signature, cannot unmask packet. Is {messagerID} on the same version?. ({num2} != {NetworkAPI_Impl.Instance.m_Signature})"); return false; } ushort num3 = BitConverter.ToUInt16(array, 19); string string2 = Encoding.UTF8.GetString(array, 21, num3); if (!NetworkAPI.IsEventRegistered(string2)) { APILogger.Error("NetworkApi", $"{messagerID} invoked an event {string2} which isn't registered."); return false; } NetworkAPI_Impl.Instance.HandlePacket(string2, messagerID, array, 21 + num3); return false; } return true; } } } namespace GTFO.API.Patches.Native { internal class SyringeFirstPerson_Patch : NativePatch { [UnmanagedFunctionPointer(CallingConvention.FastCall)] public unsafe delegate eSyringeType SyringeUsedDelegate(void* pSyringe); public unsafe override void* MethodPtr => Il2CppAPI.GetIl2CppMethod<_ApplySyringe_d__18>("MoveNext", "System.Boolean", isGeneric: false, Array.Empty()); public override string JmpStartSig => "Æ\u0081\u00b4\0\0\0\u0001\u008b\u0087Ð\u0001\0\0\u0085À"; public override string JmpStartMask => "xxxxxxxxxxxxxxx"; public override byte[] CodeCave => new byte[10] { 198, 129, 180, 0, 0, 0, 1, 72, 137, 249 }; public override uint TrampolineSize => 13u; public unsafe override SyringeUsedDelegate To => OnSyringeApplyEffect; public unsafe static eSyringeType OnSyringeApplyEffect(void* pSyringe) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) SyringeFirstPerson val = new SyringeFirstPerson(new IntPtr(pSyringe)); if (PrefabAPI.OnSyringeUsed(val)) { return (eSyringeType)(-1); } return val.m_type; } } } namespace GTFO.API.Native { internal static class Kernel32 { [DllImport("kernel32.dll")] public unsafe static extern void* VirtualAlloc(void* lpAddress, ulong dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll")] public unsafe static extern bool VirtualProtect(void* lpAddress, ulong dwSize, uint flNewProtect, uint* lpflOldProtect); } internal static class MSVCRT { [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] public unsafe static extern void* memcpy(void* destination, void* source, long num); } public abstract class NativePatch where T : Delegate { private static readonly byte[] s_CodeCaveHeader = new byte[4] { 72, 131, 236, 40 }; private static readonly byte[] s_CodeCaveFooter = new byte[17] { 72, 184, 0, 0, 0, 0, 0, 0, 0, 0, 255, 208, 72, 131, 196, 40, 195 }; public abstract byte[] CodeCave { get; } public unsafe abstract void* MethodPtr { get; } public abstract string JmpStartSig { get; } public abstract string JmpStartMask { get; } public abstract uint TrampolineSize { get; } public abstract T To { get; } public unsafe virtual void Apply() { void* ptr = MemoryUtils.FindSignatureInBlock(MethodPtr, 4096uL, JmpStartSig, JmpStartMask, 0uL); void* end = (void*)((ulong)ptr + (ulong)TrampolineSize); void* ptr2 = Kernel32.VirtualAlloc(null, (ulong)(s_CodeCaveHeader.Length + CodeCave.Length + s_CodeCaveFooter.Length), 12288u, 64u); fixed (byte* source = s_CodeCaveHeader) { MSVCRT.memcpy(ptr2, source, s_CodeCaveHeader.Length); } fixed (byte* source2 = CodeCave) { MSVCRT.memcpy((void*)((ulong)ptr2 + (ulong)s_CodeCaveHeader.Length), source2, CodeCave.Length); } void* ptr3 = (void*)((long)ptr2 + (long)s_CodeCaveHeader.Length + CodeCave.Length); fixed (byte* source3 = s_CodeCaveFooter) { MSVCRT.memcpy(ptr3, source3, s_CodeCaveFooter.Length); } *(long*)((ulong)ptr3 + 2uL) = Marshal.GetFunctionPointerForDelegate(To).ToInt64(); APILogger.Verbose("NativePatch", $"Method: 0x{MethodPtr:X2}, Trampoline: 0x{ptr:X2}, Code Cave: 0x{ptr2:X2}"); MemoryUtils.CreateTrampolineBetween(ptr, end, ptr2); } } } namespace GTFO.API.JSON { public static class JsonSerializer { private static JsonSerializerOptions s_DefaultSerializerSettings; private static JsonSerializerOptions s_LocalizedTextSerializerSettings; public static JsonSerializerOptions DefaultSerializerSettings { get { if (s_DefaultSerializerSettings == null) { s_DefaultSerializerSettings = new JsonSerializerOptions { ReadCommentHandling = JsonCommentHandling.Skip, IncludeFields = false, PropertyNameCaseInsensitive = true, WriteIndented = true, IgnoreReadOnlyProperties = true }; s_DefaultSerializerSettings.Converters.Add(new JsonStringEnumConverter()); s_DefaultSerializerSettings.Converters.Add(new Vector2Converter()); s_DefaultSerializerSettings.Converters.Add(new Vector3Converter()); s_DefaultSerializerSettings.Converters.Add(new ColorConverter()); } return s_DefaultSerializerSettings; } } public static JsonSerializerOptions DefaultSerializerSettingsWithLocalizedText { get { if (s_LocalizedTextSerializerSettings == null) { s_LocalizedTextSerializerSettings = new JsonSerializerOptions(DefaultSerializerSettings); s_LocalizedTextSerializerSettings.Converters.Add(new LocalizedTextConverter()); } return s_LocalizedTextSerializerSettings; } } public static string Serialize(object value, JsonSerializerOptions options = null) { if (options == null) { options = DefaultSerializerSettings; } return System.Text.Json.JsonSerializer.Serialize(value, options); } public static T Deserialize(string json, JsonSerializerOptions options = null) { if (options == null) { options = DefaultSerializerSettings; } return System.Text.Json.JsonSerializer.Deserialize(json, options); } } } namespace GTFO.API.JSON.Converters { public sealed class ColorConverter : JsonConverter { public override bool HandleNull => false; public override bool CanConvert(Type objectType) { return objectType == typeof(Color); } public override Color Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) Color color = default(Color); float result = 1f; switch (reader.TokenType) { case JsonTokenType.StartObject: { int currentDepth = reader.CurrentDepth; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject && reader.CurrentDepth == currentDepth) { return color * result; } if (reader.TokenType != JsonTokenType.PropertyName) { throw new JsonException("Expected PropertyName token"); } string? @string = reader.GetString(); reader.Read(); switch (@string.ToLowerInvariant()) { case "r": color.r = reader.GetSingle(); break; case "g": color.g = reader.GetSingle(); break; case "b": color.b = reader.GetSingle(); break; case "a": color.a = reader.GetSingle(); break; case "multiplier": result = reader.GetSingle(); break; } } throw new JsonException("Expected EndObject token"); } case JsonTokenType.String: { string text = reader.GetString().Trim(); string[] array = text.Split("*"); string text2; switch (array.Length) { case 1: result = 1f; text2 = array[0].Trim(); break; case 2: if (!float.TryParse(array[1].Trim(), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out result)) { throw new JsonException("Color multiplier is not valid number! (*): " + text); } text2 = array[0].Trim(); break; default: throw new JsonException("Color format has more than two Mutiplier (*): " + text); } if (ColorUtility.TryParseHtmlString(text2, ref color)) { return color * result; } if (TryParseColor(text, out color)) { return color * result; } throw new JsonException("Color format is not right: " + text); } default: throw new JsonException($"ColorJson type: {reader.TokenType} is not implemented!"); } } private static bool TryParseColor(string input, out Color color) { //IL_000b: 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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (!RegexUtils.TryParseVectorString(input, out var vectorArray)) { color = Color.white; return false; } if (vectorArray.Length < 3) { color = Color.white; return false; } float num = 1f; if (vectorArray.Length > 3) { num = vectorArray[3]; } color = new Color(vectorArray[0], vectorArray[1], vectorArray[2], num); return true; } public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) writer.WriteStringValue("#" + ColorUtility.ToHtmlStringRGBA(value)); } } public sealed class LocalizedTextConverter : JsonConverter { public override bool HandleNull => false; public override LocalizedText Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown switch (reader.TokenType) { case JsonTokenType.String: { string @string = reader.GetString(); return new LocalizedText { Id = 0u, UntranslatedText = @string }; } case JsonTokenType.Number: return new LocalizedText { Id = reader.GetUInt32(), UntranslatedText = null }; default: throw new JsonException($"LocalizedTextJson type: {reader.TokenType} is not implemented!"); } } public override void Write(Utf8JsonWriter writer, LocalizedText value, JsonSerializerOptions options) { if (value.Id != 0) { writer.WriteNumberValue(value.Id); } else if (value.HasTranslation) { writer.WriteStringValue(value.UntranslatedText); } else { writer.WriteStringValue(""); } } } public sealed class Vector2Converter : JsonConverter { public override Vector2 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) Vector2 vector = default(Vector2); switch (reader.TokenType) { case JsonTokenType.StartObject: { int currentDepth = reader.CurrentDepth; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject && reader.CurrentDepth == currentDepth) { return vector; } if (reader.TokenType != JsonTokenType.PropertyName) { throw new JsonException("Expected PropertyName token"); } string? @string = reader.GetString(); reader.Read(); string text2 = @string.ToLowerInvariant(); if (!(text2 == "x")) { if (text2 == "y") { vector.y = reader.GetSingle(); } } else { vector.x = reader.GetSingle(); } } throw new JsonException("Expected EndObject token"); } case JsonTokenType.String: { string text = reader.GetString().Trim(); if (TryParseVector2(text, out vector)) { return vector; } throw new JsonException("Vector2 format is not right: " + text); } default: throw new JsonException($"Vector2Json type: {reader.TokenType} is not implemented!"); } } private static bool TryParseVector2(string input, out Vector2 vector) { //IL_000b: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!RegexUtils.TryParseVectorString(input, out var vectorArray)) { vector = Vector2.zero; return false; } if (vectorArray.Length < 2) { vector = Vector2.zero; return false; } vector = new Vector2(vectorArray[0], vectorArray[1]); return true; } public override void Write(Utf8JsonWriter writer, Vector2 value, JsonSerializerOptions options) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) writer.WriteStringValue($"({value.x} {value.y})"); } } public sealed class Vector3Converter : JsonConverter { public override bool HandleNull => false; public override Vector3 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) Vector3 vector = default(Vector3); switch (reader.TokenType) { case JsonTokenType.StartObject: { int currentDepth = reader.CurrentDepth; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject && reader.CurrentDepth == currentDepth) { return vector; } if (reader.TokenType != JsonTokenType.PropertyName) { throw new JsonException("Expected PropertyName token"); } string? @string = reader.GetString(); reader.Read(); switch (@string.ToLowerInvariant()) { case "x": vector.x = reader.GetSingle(); break; case "y": vector.y = reader.GetSingle(); break; case "z": vector.z = reader.GetSingle(); break; } } throw new JsonException("Expected EndObject token"); } case JsonTokenType.String: { string text = reader.GetString().Trim(); if (TryParseVector3(text, out vector)) { return vector; } throw new JsonException("Vector3 format is not right: " + text); } default: throw new JsonException($"Vector3Json type: {reader.TokenType} is not implemented!"); } } private static bool TryParseVector3(string input, out Vector3 vector) { //IL_000b: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!RegexUtils.TryParseVectorString(input, out var vectorArray)) { vector = Vector3.zero; return false; } if (vectorArray.Length < 3) { vector = Vector3.zero; return false; } vector = new Vector3(vectorArray[0], vectorArray[1], vectorArray[2]); return true; } public override void Write(Utf8JsonWriter writer, Vector3 value, JsonSerializerOptions options) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) writer.WriteStringValue($"({value.x} {value.y} {value.z})"); } } } namespace GTFO.API.Extensions { public static class ListExtensions { public static List ToIl2Cpp(this List list) { List val = new List(list.Count); for (int i = 0; i < list.Count; i++) { val.Add(list[i]); } return val; } public static List ToManaged(this List list) { List list2 = new List(list.Count); for (int i = 0; i < list.Count; i++) { list2.Add(list[i]); } return list2; } } } namespace GTFO.API.Components { public class ConsumableInstance : ItemWrapped { public ConsumableInstance(IntPtr hdl) : base(hdl) { } } } namespace GTFO.API.Attributes { [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] internal class APIAttribute : Attribute { public string Name; public APIAttribute(string name) { Name = name; } } [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = true)] internal class Il2CppInterfaceAttribute : Attribute { public Type Type; public Il2CppInterfaceAttribute(Type type) { Type = type; } } } namespace GTFO.API.Impl { internal class AssetAPI_Impl : MonoBehaviour { private static AssetAPI_Impl s_Instance; public static AssetAPI_Impl Instance { get { if ((Object)(object)s_Instance == (Object)null) { AssetAPI_Impl assetAPI_Impl = Object.FindObjectOfType(); if ((Object)(object)assetAPI_Impl != (Object)null) { s_Instance = assetAPI_Impl; } } return s_Instance; } } public AssetAPI_Impl(IntPtr intPtr) : base(intPtr) { } private void Awake() { s_Instance = this; APIStatus.Asset.Ready = true; foreach (KeyValuePair item in AssetAPI.s_RegistryCache) { RegisterAsset(item.Key, item.Value); } AssetAPI.s_RegistryCache.Clear(); AssetAPI.InvokeImplReady(); } public void RegisterAsset(string name, Object gameObject) { string text = name.ToUpper(); if (AssetShardManager.s_loadedAssetsLookup.ContainsKey(text)) { throw new ArgumentException("The asset with " + name + " has already been registered.", "name"); } APILogger.Verbose("AssetAPI_Impl", "Registering asset: " + name); AssetShardManager.s_loadedAssetsLookup.Add(text, gameObject); } } internal sealed class FreeSizedNetworkingEventInfo : INetworkingEventInfo { public string Name { get; set; } public Action OnReceive { get; set; } public Type EventType => null; public int EventTypeSize => -1; public byte[] Header { get; set; } public void InvokeOnReceive(ulong sender, object payload) { if (payload is byte[] arg) { OnReceive?.Invoke(sender, arg); } } } internal interface INetworkingEventInfo { const int FreeByteSize = -1; string Name { get; } Type EventType { get; } int EventTypeSize { get; } byte[] Header { get; } int HeaderSize => Header.Length; void InvokeOnReceive(ulong sender, object payload); bool IsFreeSized() { return EventTypeSize == -1; } } internal sealed class NetworkingEventInfo : INetworkingEventInfo where T : struct { public string Name { get; set; } public Action OnReceive { get; set; } public Type EventType { get; set; } public int EventTypeSize { get; set; } public byte[] Header { get; set; } public void InvokeOnReceive(ulong sender, object payload) { if (payload is T) { T arg = (T)payload; OnReceive?.Invoke(sender, arg); } } } internal sealed class NetworkAPI_Impl : MonoBehaviour { public ulong m_Signature = 18374688234229425498uL; public ushort m_ReplicatorKey = 65533; private readonly Dictionary m_Events = new Dictionary(); private static readonly byte[] s_MagicBytes = Encoding.ASCII.GetBytes("GAPI_KSQK"); private static NetworkAPI_Impl s_Instance; public static NetworkAPI_Impl Instance { get { if ((Object)(object)s_Instance == (Object)null) { NetworkAPI_Impl networkAPI_Impl = Object.FindObjectOfType(); if ((Object)(object)networkAPI_Impl != (Object)null) { s_Instance = networkAPI_Impl; } } return s_Instance; } } public NetworkAPI_Impl(IntPtr intPtr) : base(intPtr) { } private void Awake() { s_Instance = this; APIStatus.Network.Ready = true; foreach (KeyValuePair item in NetworkAPI.s_EventCache) { if (item.Value.IsFreeSize) { typeof(NetworkAPI_Impl).GetMethod("RegisterFreeSizedEvent").Invoke(this, new object[2] { item.Key, item.Value.OnReceive }); } else { typeof(NetworkAPI_Impl).GetMethod("RegisterEvent").MakeGenericMethod(item.Value.PayloadType).Invoke(this, new object[2] { item.Key, item.Value.OnReceive }); } } NetworkAPI.s_EventCache.Clear(); } internal unsafe static void XORPacket(ref byte[] packetBytes, ulong versionSig, int offset) { fixed (byte* ptr = packetBytes) { XORPacketImpl(ptr + offset, (uint)(packetBytes.Length - offset), (byte*)(&versionSig)); } } internal unsafe static void XORPacketImpl(byte* pPacket, uint packetLength, byte* pVersion) { for (int i = 0; i < packetLength; i++) { pPacket[i] ^= pVersion[i % 8]; } } [HideFromIl2Cpp] public void HandlePacket(string eventName, ulong senderId, byte[] packetData, int startIndex = 0) { INetworkingEventInfo networkingEventInfo = m_Events[eventName]; if (networkingEventInfo.IsFreeSized()) { int num = packetData.Length - networkingEventInfo.HeaderSize; XORPacket(ref packetData, m_Signature, startIndex); byte[] array = new byte[num]; Array.Copy(packetData, startIndex, array, 0, num); networkingEventInfo.InvokeOnReceive(senderId, array); } else { Type eventType = networkingEventInfo.EventType; XORPacket(ref packetData, m_Signature, startIndex); int num2 = Marshal.SizeOf(eventType); IntPtr intPtr = Marshal.AllocHGlobal(num2); Marshal.Copy(packetData, startIndex, intPtr, num2); object payload = Marshal.PtrToStructure(intPtr, eventType); Marshal.FreeHGlobal(intPtr); networkingEventInfo.InvokeOnReceive(senderId, payload); } } [HideFromIl2Cpp] private byte[] MakeHeaderBytes(string eventName) { byte[] bytes = Encoding.UTF8.GetBytes(eventName); int num = bytes.Length; int num2 = 21 + num; IntPtr intPtr; IntPtr intPtr2 = (intPtr = Marshal.AllocHGlobal(num2)); Marshal.WriteInt16(intPtr, (short)m_ReplicatorKey); intPtr += 2; Marshal.Copy(s_MagicBytes, 0, intPtr, 9); intPtr += 9; Marshal.WriteInt64(intPtr, (long)m_Signature); intPtr += 8; Marshal.WriteInt16(intPtr, (short)num); intPtr += 2; Marshal.Copy(bytes, 0, intPtr, num); byte[] array = new byte[num2]; Marshal.Copy(intPtr2, array, 0, num2); Marshal.FreeHGlobal(intPtr2); return array; } [HideFromIl2Cpp] public bool EventExists(string eventName) { return m_Events.ContainsKey(eventName); } [HideFromIl2Cpp] public void RegisterEvent(string eventName, Action onReceive) where T : struct { if (EventExists(eventName)) { throw new ArgumentException($"Type {typeof(T)} is a generic and cannot be registered.", "eventName"); } if (typeof(T).IsGenericType) { throw new ArgumentException("Generic type is not allowed to register", "T"); } NetworkingEventInfo value = new NetworkingEventInfo { Name = eventName, OnReceive = onReceive, EventType = typeof(T), EventTypeSize = Marshal.SizeOf(), Header = MakeHeaderBytes(eventName) }; m_Events.Add(eventName, value); } [HideFromIl2Cpp] public byte[] MakePacketBytes(string eventName, T payload) where T : struct { if (!m_Events.TryGetValue(eventName, out var value)) { throw new ArgumentException("An event with the name " + eventName + " was not registered.", "eventName"); } if (value.IsFreeSized()) { throw new InvalidOperationException("Event '" + eventName + "' is NOT registered as FixedSize Event!"); } if (value.EventType != typeof(T)) { throw new ArgumentException("Payload type was incorrect! expecting: " + typeof(T).FullName, "eventName"); } int eventTypeSize = value.EventTypeSize; int headerSize = value.HeaderSize; int num = headerSize + eventTypeSize; IntPtr intPtr; IntPtr intPtr2 = (intPtr = Marshal.AllocHGlobal(num)); Marshal.Copy(value.Header, 0, intPtr, headerSize); intPtr += headerSize; Marshal.StructureToPtr(payload, intPtr, fDeleteOld: true); byte[] packetBytes = new byte[num]; Marshal.Copy(intPtr2, packetBytes, 0, num); Marshal.FreeHGlobal(intPtr2); XORPacket(ref packetBytes, m_Signature, headerSize); return packetBytes; } [HideFromIl2Cpp] public void RegisterFreeSizedEvent(string eventName, Action onReceive) { if (EventExists(eventName)) { throw new ArgumentException("EventName '" + eventName + "' is already registered!", "eventName"); } FreeSizedNetworkingEventInfo value = new FreeSizedNetworkingEventInfo { Name = eventName, OnReceive = onReceive, Header = MakeHeaderBytes(eventName) }; m_Events.Add(eventName, value); } [HideFromIl2Cpp] public byte[] MakeFreeSizedPacketBytes(string eventName, byte[] payload) { if (!m_Events.TryGetValue(eventName, out var value)) { throw new ArgumentException("An event with the name " + eventName + " was not registered.", "eventName"); } if (!value.IsFreeSized()) { throw new InvalidOperationException("Event '" + eventName + "' is NOT registered as FreeSized Event!"); } if (payload == null) { throw new ArgumentNullException("payload", "Payload was null!"); } if (payload.Length == 0) { throw new ArgumentOutOfRangeException("payload", "Payload was Empty!"); } int num = payload.Length; int headerSize = value.HeaderSize; int num2 = headerSize + num; IntPtr destination; IntPtr intPtr = (destination = Marshal.AllocHGlobal(num2)); Marshal.Copy(value.Header, 0, destination, headerSize); destination += value.HeaderSize; Marshal.Copy(payload, 0, destination, num); byte[] packetBytes = new byte[num2]; Marshal.Copy(intPtr, packetBytes, 0, num2); Marshal.FreeHGlobal(intPtr); XORPacket(ref packetBytes, m_Signature, headerSize); return packetBytes; } } }