using System; using System.Buffers.Binary; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using AK; using Agents; using AssetShards; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Unity.IL2CPP; using BepInEx.Unity.IL2CPP.Hook; using BepInEx.Unity.IL2CPP.Utils.Collections; using CellMenu; using CharacterDestruction; using Clonesoft.Json; using Clonesoft.Json.Converters; using Clonesoft.Json.Serialization; using Enemies; using FX_EffectSystem; using GTFO.API; using GameData; using GameEvent; using Gear; using Hikaria.Core.Components; using Hikaria.Core.Features.Dev; using Hikaria.Core.Interfaces; using Hikaria.Core.Managers; using Hikaria.Core.SNetworkExt; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Attributes; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppInterop.Runtime.Runtime; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using LevelGeneration; using Localization; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using Player; using SNetwork; using SemanticVersioning; using Steamworks; using TheArchive.Core; using TheArchive.Core.Attributes; using TheArchive.Core.Attributes.Feature; using TheArchive.Core.Attributes.Feature.Members; using TheArchive.Core.Attributes.Feature.Patches; using TheArchive.Core.Attributes.Feature.Settings; using TheArchive.Core.Bootstrap; using TheArchive.Core.FeaturesAPI; using TheArchive.Core.FeaturesAPI.Groups; using TheArchive.Core.FeaturesAPI.Settings; using TheArchive.Core.Localization; using TheArchive.Features.Security; using TheArchive.Interfaces; using TheArchive.Loader; using TheArchive.Utilities; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 NativeIntegerAttribute : Attribute { public readonly bool[] TransformFlags; public NativeIntegerAttribute() { TransformFlags = new bool[1] { true }; } public NativeIntegerAttribute(bool[] P_0) { TransformFlags = P_0; } } } namespace Hikaria.Core { public static class CoreAPI { public delegate void PlayerModsSynced(SNet_Player player, IEnumerable mods); public static event PlayerModsSynced OnPlayerModsSynced { add { CoreAPI_Impl.OnPlayerModsSynced += value; } remove { CoreAPI_Impl.OnPlayerModsSynced -= value; } } public static bool IsInstalledMod(string guid, VersionRange range = default(VersionRange)) { if (CoreAPI_Impl.InstalledMods.TryGetValue(guid, out var value)) { return range.Contains(value.Version); } return false; } public static bool IsPlayerInstalledCore(SNet_Player player, VersionRange range = default(VersionRange)) { return IsPlayerInstalledMod(player, "Hikaria.Core", range); } public static bool IsPlayerInstalledMod(SNet_Player player, string guid, VersionRange range = default(VersionRange)) { if ((Object)(object)player == (Object)null || player.IsBot) { return false; } if (player.IsLocal) { if (CoreAPI_Impl.InstalledMods.TryGetValue(guid, out var value)) { return range.Contains(value.Version); } return false; } if (CoreAPI_Impl.OthersMods.TryGetValue(player.Lookup, out var value2) && value2.TryGetValue(guid, out var value3)) { return range.Contains(value3.Version); } return false; } } public static class EnemyAPI { public delegate void EnemyReceivedDamage(EnemyAgent enemy, pFullEnemyReceivedDamageData data); public static event Action OnEnemyLimbDestroyed { add { EnemyAPI_Impl.OnEnemyLimbDestroyed += value; } remove { EnemyAPI_Impl.OnEnemyLimbDestroyed -= value; } } public static event Action OnEnemyDead { add { EnemyAPI_Impl.OnEnemyDead += value; } remove { EnemyAPI_Impl.OnEnemyDead -= value; } } public static event Action OnPostEnemyDead { add { EnemyAPI_Impl.OnPostEnemyDead += value; } remove { EnemyAPI_Impl.OnPostEnemyDead -= value; } } public static event EnemyReceivedDamage OnEnemyReceivedDamage { add { EnemyAPI_Impl.OnEnemyReceivedDamage += value; } remove { EnemyAPI_Impl.OnEnemyReceivedDamage -= value; } } public static event Action OnEnemySpawned { add { EnemyAPI_Impl.OnEnemySpawned += value; } remove { EnemyAPI_Impl.OnEnemySpawned -= value; } } public static event Action OnEnemyDespawn { add { EnemyAPI_Impl.OnEnemyDespawn += value; } remove { EnemyAPI_Impl.OnEnemyDespawn -= value; } } public static event Action OnEnemyDespawnd { add { EnemyAPI_Impl.OnEnemyDespawnd += value; } remove { EnemyAPI_Impl.OnEnemyDespawnd -= value; } } } public static class GameEventAPI { public static bool IsGamePaused { get { return PauseManager.IsPaused; } set { PauseManager.IsPaused = value; } } public static event Action OnGameDataInitialized { add { GameEventAPI_Impl.OnGameDataInitialized += value; } remove { GameEventAPI_Impl.OnGameDataInitialized -= value; } } public static event Action OnGameStateChanged { add { GameEventAPI_Impl.OnGameStateChanged += value; } remove { GameEventAPI_Impl.OnGameStateChanged -= value; } } public static event Action OnReceiveChatMessage { add { GameEventAPI_Impl.OnReceiveChatMessage += value; } remove { GameEventAPI_Impl.OnReceiveChatMessage -= value; } } public static event Action OnAfterLevelCleanup { add { GameEventAPI_Impl.OnAfterLevelCleanup += value; } remove { GameEventAPI_Impl.OnAfterLevelCleanup -= value; } } public static event Action OnGamePaused { add { PauseManager.OnPaused += value; } remove { PauseManager.OnPaused -= value; } } public static event Action OnGameUnpaused { add { PauseManager.OnUnpaused += value; } remove { PauseManager.OnUnpaused -= value; } } } public static class SNetEventAPI { public static event Action OnBufferCapture { add { SNetEventAPI_Impl.OnBufferCapture += value; } remove { SNetEventAPI_Impl.OnBufferCapture -= value; } } public static event Action OnBufferRecalled { add { SNetEventAPI_Impl.OnBufferRecalled += value; } remove { SNetEventAPI_Impl.OnBufferRecalled -= value; } } public static event Action OnRecallDone { add { SNetEventAPI_Impl.OnRecallDone += value; } remove { SNetEventAPI_Impl.OnRecallDone -= value; } } public static event Action OnRecallComplete { add { SNetEventAPI_Impl.OnRecallComplete += value; } remove { SNetEventAPI_Impl.OnRecallComplete -= value; } } public static event Action OnPrepareForRecall { add { SNetEventAPI_Impl.OnPrepareForRecall += value; } remove { SNetEventAPI_Impl.OnPrepareForRecall -= value; } } public static event Action OnBufferCommand { add { SNetEventAPI_Impl.OnBufferCommand += value; } remove { SNetEventAPI_Impl.OnBufferCommand -= value; } } public static event Action OnResetSession { add { SNetEventAPI_Impl.OnResetSession += value; } remove { SNetEventAPI_Impl.OnResetSession -= value; } } public static event Action OnPlayerEvent { add { SNetEventAPI_Impl.OnPlayerEvent += value; } remove { SNetEventAPI_Impl.OnPlayerEvent -= value; } } public static event Action OnSessionMemberChanged { add { SNetEventAPI_Impl.OnSessionMemberChanged += value; } remove { SNetEventAPI_Impl.OnSessionMemberChanged -= value; } } public static event Action OnMasterChanged { add { SNetEventAPI_Impl.OnMasterChanged += value; } remove { SNetEventAPI_Impl.OnMasterChanged -= value; } } public static event Action OnMasterCommand { add { SNetEventAPI_Impl.OnMasterCommand += value; } remove { SNetEventAPI_Impl.OnMasterCommand -= value; } } } public static class SNetExtAPI { public static bool TryGetVanillaWrapper(IReplicator vanilla, out SNetExt_Replicator_VanillaWrapper wrapper) { return SNetExt_Replication.TryGetVanillaWrapper(vanilla, out wrapper); } } public static class WeaponAPI { public delegate void PreBulletWeaponFire(BulletWeapon bulletWeapon, bool resetRecoilSimilarity); public delegate void PostBulletWeaponFire(BulletWeapon bulletWeapon, bool resetRecoilSimilarity); public delegate void PreShotgunFire(Shotgun shotgun, bool resetRecoilSimilarity); public delegate void PostShotgunFire(Shotgun shotgun, bool resetRecoilSimilarity); public static event PreBulletWeaponFire OnPreBulletWeaponFire { add { WeaponAPI_Impl.OnPreBulletWeaponFire += value; } remove { WeaponAPI_Impl.OnPreBulletWeaponFire -= value; } } public static event PostBulletWeaponFire OnPostBulletWeaponFire { add { WeaponAPI_Impl.OnPostBulletWeaponFire += value; } remove { WeaponAPI_Impl.OnPostBulletWeaponFire -= value; } } public static event PreShotgunFire OnPreShotgunFire { add { WeaponAPI_Impl.OnPreShotgunFire += value; } remove { WeaponAPI_Impl.OnPreShotgunFire -= value; } } public static event PostShotgunFire OnPostShotgunFire { add { WeaponAPI_Impl.OnPostShotgunFire += value; } remove { WeaponAPI_Impl.OnPostShotgunFire -= value; } } } public static class CoreGlobal { public const string GUID = "Hikaria.Core"; public const string NAME = "HikariaCore"; public const string VERSION = "1.0.0"; internal static ILocalizationService Localization { get; private set; } internal static JsonSerializerSettings JsonSerializerSettings { get; private set; } internal static void Setup(IArchiveModule module) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_002d: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown Localization = module.LocalizationService; Logs.Setup(module.Logger); JsonSerializerSettings = new JsonSerializerSettings { Formatting = (Formatting)1, ContractResolver = (IContractResolver)new DefaultContractResolver(), DateFormatHandling = (DateFormatHandling)1, DateFormatString = "yyyy-MM-dd HH:mm:ss", NullValueHandling = (NullValueHandling)0 }; JsonSerializerSettings.Converters.Add((JsonConverter)new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" }); JsonSerializerSettings.Converters.Add((JsonConverter)new StringEnumConverter()); } } [ArchiveDependency(/*Could not decode attribute arguments.*/)] [ArchiveModule("Hikaria.Core", "HikariaCore", "1.0.0")] public class EntryPoint : IArchiveModule { public ILocalizationService LocalizationService { get; set; } public IArchiveLogger Logger { get; set; } public void Init() { CoreGlobal.Setup((IArchiveModule)(object)this); } } internal static class Logs { private static IArchiveLogger _logger; public static void Setup(IArchiveLogger logger) { _logger = logger; } public static void LogDebug(object data) { _logger.Debug(data.ToString()); } public static void LogError(object data) { _logger.Error(data.ToString()); } public static void LogInfo(object data) { _logger.Info(data.ToString()); } public static void LogMessage(object data) { _logger.Msg(ConsoleColor.White, data.ToString()); } public static void LogWarning(object data) { _logger.Warning(data.ToString()); } public static void LogNotice(object data) { _logger.Notice(data.ToString()); } public static void LogSuccess(object data) { _logger.Success(data.ToString()); } public static void LogException(Exception ex) { _logger.Exception(ex); } } public enum SessionMemberEvent { JoinSessionHub, LeftSessionHub } public enum DamageTraceFlags : uint { None = 0u, Bullet = 1u, Melee = 2u, Explosion = 4u, Fire = 8u, Freeze = 0x10u, Push = 0x20u, SentryGun = 0x40u, Player = 0x80u, Enemy = 0x100u, Decoy = 0x200u, Unknown = 0x400u } public static class SharedExtensions { public static string[] SplitInChunks(this string str, int length) { return (from i in Enumerable.Range(0, (int)Math.Ceiling((double)str.Length / (double)length)) select str.Substring(i * length, Math.Min(length, str.Length - i * length))).ToArray(); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct pPopupMessage { public bool BlinkInContent; public float BlinkTimeInterval; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Header; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string UpperText; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string LowerText; public PopupType PopupType; public PopupMessage UnpackPopupMessage() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_005e: Expected O, but got Unknown return new PopupMessage { BlinkInContent = BlinkInContent, BlinkTimeInterval = BlinkTimeInterval, Header = Header, UpperText = UpperText, LowerText = LowerText, PopupType = PopupType, OnCloseCallback = Action.op_Implicit(PopupMessageManager.EmptyAction) }; } public pPopupMessage(string header, string upperText, string lowerText, bool blinkInContent = true, float blinkTimeInterval = 0.2f, PopupType type = 3) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) BlinkInContent = true; BlinkTimeInterval = 0.2f; PopupType = (PopupType)3; Header = header; UpperText = upperText; LowerText = lowerText; BlinkInContent = blinkInContent; BlinkTimeInterval = blinkTimeInterval; PopupType = type; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct pModList : ISNetExt_ReplicatedPlayerData { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public pModInfo[] Mods; public int ModCount; public const int MOD_SYNC_COUNT = 256; public pPlayer PlayerData { get; set; } public pModList(SNet_Player player, IEnumerable modList) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) Mods = new pModInfo[256]; ModCount = 0; Array.Fill(Mods, default(pModInfo)); pPlayer playerData = default(pPlayer); ((pPlayer)(ref playerData)).SetPlayer(player); PlayerData = playerData; ModCount = Math.Clamp(modList.Count(), 0, 256); for (int i = 0; i < ModCount; i++) { Mods[i] = modList.ElementAt(i); } } public pModList() { //IL_002e: 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) Mods = new pModInfo[256]; ModCount = 0; Array.Fill(Mods, default(pModInfo)); PlayerData = default(pPlayer); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct pModInfo { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string Name; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string GUID; public Version Version; public pModInfo(string name, string guid, Version version) { Name = string.Empty; GUID = string.Empty; Version = default(Version); Name = name; GUID = guid; Version = version; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct pFullEnemyReceivedDamageData { public pEnemyAgent enemy; public float damage; public pAgent damageSource; public Vector3 position; public Vector3 direction; public ES_HitreactType hitreact; public bool tryForceHitreact; public int limbID; public float staggerDamageMulti; public DamageNoiseLevel damageNoiseLevel; public uint gearCategoryId; public bool isKill; public uint gearChecksum; public DamageTraceFlags damageTraceFlags; public pFullEnemyReceivedDamageData(EnemyAgent enemy, bool isKill, float damage, Agent damageSource, Vector3 position, Vector3 direction, ES_HitreactType hitreact, bool tryForceHitreact = false, int limbID = -1, float staggerDamageMulti = 1f, DamageNoiseLevel damageNoiseLevel = 0, uint gearCategoryId = 0u, uint gearChecksum = 0u, DamageTraceFlags damageTraceFlags = DamageTraceFlags.None) { //IL_0006: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) this.enemy = default(pEnemyAgent); this.damage = 0f; this.damageSource = default(pAgent); this.position = Vector3.zero; this.direction = Vector3.zero; this.hitreact = (ES_HitreactType)0; this.tryForceHitreact = false; this.limbID = -1; this.staggerDamageMulti = 1f; this.damageNoiseLevel = (DamageNoiseLevel)0; this.gearCategoryId = 0u; this.isKill = false; this.gearChecksum = 0u; this.damageTraceFlags = DamageTraceFlags.None; this.enemy = default(pEnemyAgent); ((pEnemyAgent)(ref this.enemy)).Set(enemy); this.isKill = isKill; this.damage = damage; this.damageSource = default(pAgent); ((pAgent)(ref this.damageSource)).Set(damageSource); this.position = position; this.direction = direction; this.hitreact = hitreact; this.tryForceHitreact = tryForceHitreact; this.limbID = limbID; this.staggerDamageMulti = staggerDamageMulti; this.damageNoiseLevel = damageNoiseLevel; this.gearCategoryId = gearCategoryId; this.gearChecksum = gearChecksum; this.damageTraceFlags = damageTraceFlags; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public readonly struct Version : IComparable, IComparable, IEquatable { [CompilerGenerated] private sealed class d__18 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private int <>2__current; private int <>l__initialThreadId; public Version <>4__this; public Version <>3__<>4__this; private Version other; public Version <>3__other; int IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__18(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = <>4__this.Major.CompareTo(other.Major); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = <>4__this.Minor.CompareTo(other.Minor); <>1__state = 2; return true; case 2: <>1__state = -1; <>2__current = <>4__this.Patch.CompareTo(other.Patch); <>1__state = 3; return true; case 3: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__18 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__18(0); } d__.<>4__this = <>3__<>4__this; d__.other = <>3__other; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public static readonly Version ZeroVersion = new Version(0, 0, 0); private static readonly Regex strictRegex = new Regex("^\r\n \\s*\r\n ([0-9]+) # major version\r\n \\.\r\n ([0-9]+) # minor version\r\n \\.\r\n ([0-9]+) # patch version\r\n \\s*\r\n $", RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace); private readonly int _major; private readonly int _minor; private readonly int _patch; public int Major => _major; public int Minor => _minor; public int Patch => _patch; public Version(string input) { _major = 0; _minor = 0; _patch = 0; Match match = strictRegex.Match(input); if (!match.Success) { throw new ArgumentException("Invalid version string: " + input + ". Version must be in format 'X.Y.Z' where X, Y, Z are non-negative integers."); } _major = int.Parse(match.Groups[1].Value); _minor = int.Parse(match.Groups[2].Value); _patch = int.Parse(match.Groups[3].Value); } public Version(int major, int minor, int patch) { _major = 0; _minor = 0; _patch = 0; _major = major; _minor = minor; _patch = patch; } public override string ToString() { return $"{Major}.{Minor}.{Patch}"; } public override int GetHashCode() { return ((17 * 23 + Major.GetHashCode()) * 23 + Minor.GetHashCode()) * 23 + Patch.GetHashCode(); } public bool Equals(Version other) { return CompareTo(other) == 0; } public int CompareTo(object obj) { if (obj == null) { return 1; } if (obj is Version other) { return CompareTo(other); } throw new ArgumentException("Object is not a Version"); } public int CompareTo(Version other) { foreach (int item in PartComparisons(other)) { if (item != 0) { return item; } } return 0; } [IteratorStateMachine(typeof(d__18))] private IEnumerable PartComparisons(Version other) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__18(-2) { <>3__<>4__this = this, <>3__other = other }; } public override bool Equals(object other) { if (other == null) { return false; } if (other is Version other2) { return Equals(other2); } return false; } public static Version Parse(string input) { return new Version(input); } public static bool TryParse(string input, out Version result) { try { result = Parse(input); return true; } catch { result = default(Version); return false; } } public static bool operator ==(Version a, Version b) { return a.Equals(b); } public static bool operator !=(Version a, Version b) { return !(a == b); } public static bool operator >(Version a, Version b) { return a.CompareTo(b) > 0; } public static bool operator >=(Version a, Version b) { return a.CompareTo(b) >= 0; } public static bool operator <(Version a, Version b) { return a.CompareTo(b) < 0; } public static bool operator <=(Version a, Version b) { return a.CompareTo(b) <= 0; } public static implicit operator Version(string versionString) { return Parse(versionString); } public VersionRange To(Version maxVersion, bool includeMin = true, bool includeMax = true) { return new VersionRange(this, maxVersion, includeMin, includeMax); } public VersionRange AndAbove(bool includeThis = true) { return VersionRange.GreaterThan(this, includeThis); } public VersionRange AndBelow(bool includeThis = true) { return VersionRange.LessThan(this, includeThis); } } public struct VersionRange { private static readonly Regex RangeRegex = new Regex("^\\s*(?:(?:([\\[\\(])\\s*([0-9]+\\.[0-9]+\\.[0-9]+)\\s*,\\s*([0-9]+\\.[0-9]+\\.[0-9]+)\\s*([\\]\\)]))|(?:([<>]=?)\\s*([0-9]+\\.[0-9]+\\.[0-9]+))|(?:([0-9]+)(?:\\.([0-9]+|x))?(?:\\.([0-9]+|x))?))$", RegexOptions.Compiled); public Version Min { get; } public Version Max { get; } public bool IncludeMin { get; } public bool IncludeMax { get; } public VersionRange(Version min, Version max, bool includeMin = true, bool includeMax = true) { if (min.Equals(Version.ZeroVersion) && max.Equals(Version.ZeroVersion)) { throw new ArgumentException("MinVersion 和 MaxVersion 不能同时为 \"0.0.0\""); } Min = min; Max = max; IncludeMin = includeMin; IncludeMax = includeMax; } public bool Contains(Version version) { if (version.Equals(Version.ZeroVersion)) { return false; } if (!Min.Equals(Version.ZeroVersion)) { int num = version.CompareTo(Min); if (num < 0 || (num == 0 && !IncludeMin)) { return false; } } if (!Max.Equals(Version.ZeroVersion)) { int num2 = version.CompareTo(Max); if (num2 > 0 || (num2 == 0 && !IncludeMax)) { return false; } } return true; } public override string ToString() { string value = (IncludeMin ? "[" : "("); string value2 = (IncludeMax ? "]" : ")"); string value3 = (Min.Equals(Version.ZeroVersion) ? "0.0.0" : Min.ToString()); string value4 = (Max.Equals(Version.ZeroVersion) ? "∞" : Max.ToString()); return $"{value}{value3}, {value4}{value2}"; } public static VersionRange Parse(string input) { if (string.IsNullOrWhiteSpace(input)) { throw new ArgumentException("输入字符串不能为空", "input"); } Match match = RangeRegex.Match(input); if (!match.Success) { throw new ArgumentException("无效的版本范围格式: " + input, "input"); } if (match.Groups[1].Success) { string value = match.Groups[1].Value; string value2 = match.Groups[4].Value; bool includeMin = value == "["; bool includeMax = value2 == "]"; string value3 = match.Groups[2].Value; string value4 = match.Groups[3].Value; Version min = Version.Parse(value3); Version max = Version.Parse(value4); return new VersionRange(min, max, includeMin, includeMax); } if (match.Groups[5].Success) { string value5 = match.Groups[5].Value; Version version = Version.Parse(match.Groups[6].Value); return value5 switch { ">" => GreaterThan(version, includeMin: false), ">=" => GreaterThan(version), "<" => LessThan(version, includeMax: false), "<=" => LessThan(version), _ => throw new ArgumentException("不支持的操作符: " + value5, "input"), }; } int num = int.Parse(match.Groups[7].Value); bool flag = match.Groups[8].Success && match.Groups[8].Value != "x"; int num2 = (flag ? int.Parse(match.Groups[8].Value) : 0); bool flag2 = match.Groups[9].Success && match.Groups[9].Value != "x"; int num3 = (flag2 ? int.Parse(match.Groups[9].Value) : 0); Version version2 = new Version(num, flag ? num2 : 0, flag2 ? num3 : 0); Version max2 = ((!flag) ? new Version(num + 1, 0, 0) : (flag2 ? version2 : new Version(num, num2 + 1, 0))); return new VersionRange(version2, max2, includeMin: true, !max2.Equals(version2)); } public static bool TryParse(string input, out VersionRange range) { try { range = Parse(input); return true; } catch { range = default(VersionRange); return false; } } public static VersionRange GreaterThan(Version minVersion, bool includeMin = true) { return new VersionRange(minVersion, new Version(0, 0, 0), includeMin, includeMax: false); } public static VersionRange LessThan(Version maxVersion, bool includeMax = true) { return new VersionRange(new Version(0, 0, 0), maxVersion, includeMin: false, includeMax); } public static implicit operator VersionRange(string rangeString) { return Parse(rangeString); } } } namespace Hikaria.Core.Utility { public static class HttpHelper { private static readonly HttpClient _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(10.0) }; private static IArchiveLogger _logger = LoaderWrapper.CreateArSubLoggerInstance("HttpHelper", ConsoleColor.White); public static async Task GetAsync(string url) where T : new() { _ = 1; try { HttpResponseMessage obj = await _httpClient.GetAsync(url); obj.EnsureSuccessStatusCode(); return JsonConvert.DeserializeObject(await obj.Content.ReadAsStringAsync(), CoreGlobal.JsonSerializerSettings); } catch (Exception) { _logger.Error("Error occurred while sending GET request. [" + url + "]"); return new T(); } } public static async Task PostAsync(string url, object content) where T : new() { _ = 1; try { StringContent content2 = new StringContent(JsonConvert.SerializeObject(content, CoreGlobal.JsonSerializerSettings), Encoding.UTF8, "application/json"); HttpResponseMessage obj = await _httpClient.PostAsync(url, content2); obj.EnsureSuccessStatusCode(); return JsonConvert.DeserializeObject(await obj.Content.ReadAsStringAsync(), CoreGlobal.JsonSerializerSettings); } catch (Exception) { _logger.Error("Error occurred while sending POST request. [" + url + "]"); return new T(); } } public static async Task PutAsync(string url, object content) where T : new() { _ = 1; try { StringContent content2 = new StringContent(JsonConvert.SerializeObject(content, CoreGlobal.JsonSerializerSettings), Encoding.UTF8, "application/json"); HttpResponseMessage obj = await _httpClient.PutAsync(url, content2); obj.EnsureSuccessStatusCode(); return JsonConvert.DeserializeObject(await obj.Content.ReadAsStringAsync(), CoreGlobal.JsonSerializerSettings); } catch (Exception) { _logger.Error("Error occurred while sending PUT request. [" + url + "]"); return new T(); } } public static async Task PatchAsync(string url, object content) where T : new() { _ = 1; try { StringContent content2 = new StringContent(JsonConvert.SerializeObject(content, CoreGlobal.JsonSerializerSettings), Encoding.UTF8, "application/json"); HttpResponseMessage obj = await _httpClient.PatchAsync(url, content2); obj.EnsureSuccessStatusCode(); return JsonConvert.DeserializeObject(await obj.Content.ReadAsStringAsync(), CoreGlobal.JsonSerializerSettings); } catch (Exception) { _logger.Error("Error occurred while sending PATCH request. [" + url + "]"); return new T(); } } } public static class Utils { public static bool TryGetPlayerByCharacterSlot(int slot, out SNet_Player player) { player = null; int num = slot - 1; if (num < 0 || num > 4) { return false; } player = ((Il2CppArrayBase)(object)SNet.Slots.CharacterSlots)[num].player; return (Object)(object)player != (Object)null; } public static bool TryGetPlayerByPlayerSlot(int slot, out SNet_Player player) { player = null; int num = slot - 1; if (num < 0 || num > 4) { return false; } player = ((Il2CppArrayBase)(object)SNet.Slots.PlayerSlots)[num].player; return (Object)(object)player != (Object)null; } } } namespace Hikaria.Core.SNetworkExt { public enum SNetExt_BufferOperationType : byte { StartReceive, StoreGameState, RecallGameState } public enum SNetExt_BufferType : byte { JoinedHub, DropIn, RestartLevel, Checkpoint, Migration_A, Migration_B } public enum SNetExt_CapturePass : byte { SessionPass, FirstPass, SecondPass, ThirdPass, FourthPass, Skip } public enum SNetExt_ReplicatorLifeTime { NeverDestroyed, DestroyedOnLevelReset, DynamicallyDestroyed } public enum SNetExt_ReplicatorType { Unspecified, Manager, SelfManaged, Dynamic, VanillaWrapper } public interface ICaptureCallbackObject { bool PersistAcrossSession { get; } void OnStateCapture(); } public interface ISNetExt_DynamicReplication { pReplicationData ReplicationData { get; set; } Vector3 Position { get; set; } Quaternion Rotation { get; set; } } public interface ISNetExt_DynamicReplicatorSupplier : ISNetExt_ReplicatorSupplier where T : struct, ISNetExt_DynamicReplication { void OnDespawn(); void OnSpawn(T spawnData); bool TryCollectCaptureData(ref T spawnData, out SNetExt_CapturePass captureType); } public interface ISNetExt_Manager { void Setup(); void SetupReplication(); void OnResetSession(); void OnValidateMasterData(); } internal interface ISNetExt_MutableReplicator : ISNetExt_Replicator { void AssignKey(string key); void AssignKeyHash(in SNetExt_KeyHash16 keyHash); void ReceiveBytes(in SNetExt_KeyHash16 packetKeyHash, byte packetIndex, byte[] bytes); } internal interface ISNetExt_OwnedReplicator : ISNetExt_MutableReplicator, ISNetExt_Replicator { new SNet_Player OwningPlayer { get; set; } new bool OwnedByMaster { get; set; } } public interface ISNetExt_ReplicatedPlayerData { pPlayer PlayerData { get; set; } } public interface ISNetExt_Replicator { string Key { get; } string KeyHash { get; } ReadOnlySpan KeyHashBytes { get; } SNetExt_ReplicatorType Type { get; } bool LocallyOwned { get; } bool IsAnonymous { get; } bool HasValidKeyHash { get; } SNet_Player OwningPlayer { get; } bool OwnedByMaster { get; } ISNetExt_ReplicatorSupplier ReplicatorSupplier { get; set; } SNetExt_ReplicatedPacket CreatePacket(string packetKey, Action receiveAction, Action validateAction = null) where T : struct; SNetExt_ReplicatedPacketBytes CreatePacketBytes(string key, SNetExt_ReplicatedPacketBytes.SpanReceiveDelegate receiveAction); SNetExt_ReplicatedPacketBufferBytes CreatePacketBufferBytes(string key, SNetExt_ReplicatedPacketBufferBytes.SpanBufferReceiveDelegate receiveAction); void Despawn(); Type GetPacketType(string key, int packetIndex); } public interface ISNetExt_ReplicatorSupplier { string Key { get; } ISNetExt_Replicator Replicator { get; set; } GameObject gameObject { get; } } public interface ISNetExt_StateReplicator { ISNetExt_Replicator Replicator { get; set; } } public interface ISNetExt_StateReplicatorProvider { GameObject gameObject { get; } ISNetExt_StateReplicator GetStateReplicator(); } public interface ISNetExt_StateReplicatorProvider : ISNetExt_StateReplicatorProvider where S : struct { void OnStateChange(S oldState, S newState, bool isRecall); } public interface ISNetExt_StateReplicatorProvider : ISNetExt_StateReplicatorProvider where S : struct where I : struct { void OnStateChange(S oldState, S newState, bool isRecall); void AttemptInteract(I interaction); } internal static class SNetExt_HashUtil { [ThreadStatic] private static MD5 t_md5; private static readonly Dictionary s_keyHexCache = new Dictionary(65535); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static MD5 GetMD5() { return t_md5 ?? (t_md5 = MD5.Create()); } public static string KeyToHashHex(string key) { if (string.IsNullOrWhiteSpace(key)) { return string.Empty; } lock (s_keyHexCache) { if (s_keyHexCache.TryGetValue(key, out var value)) { return value; } } MD5 mD = GetMD5(); int byteCount = Encoding.UTF8.GetByteCount(key); string text; if (byteCount <= 256) { int bytesWritten = byteCount; Span span = stackalloc byte[bytesWritten]; Encoding.UTF8.GetBytes(key, span); Span span2 = stackalloc byte[16]; mD.TryComputeHash(span, span2, out bytesWritten); text = Convert.ToHexString(span2); } else { text = Convert.ToHexString(mD.ComputeHash(Encoding.UTF8.GetBytes(key))); } lock (s_keyHexCache) { s_keyHexCache[key] = text; return text; } } public static void KeyToHashBytes(string key, Span destination16) { if (destination16.Length < 16) { throw new ArgumentException("destination must be at least 16 bytes", "destination16"); } if (string.IsNullOrWhiteSpace(key)) { destination16.Slice(0, 16).Clear(); return; } MD5 mD = GetMD5(); int byteCount = Encoding.UTF8.GetByteCount(key); if (byteCount <= 256) { int bytesWritten = byteCount; Span span = stackalloc byte[bytesWritten]; Encoding.UTF8.GetBytes(key, span); mD.TryComputeHash(span, destination16, out bytesWritten); } else { mD.ComputeHash(Encoding.UTF8.GetBytes(key)).AsSpan(0, 16).CopyTo(destination16); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] HashHexToBytes(string keyHash) { return Convert.FromHexString(keyHash); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string HashBytesToHex(ReadOnlySpan hash16) { return Convert.ToHexString(hash16); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] public readonly struct SNetExt_KeyHash16 : IEquatable { public readonly ulong Lower; public readonly ulong Upper; public bool IsEmpty { get { if (Lower == 0L) { return Upper == 0; } return false; } } public SNetExt_KeyHash16(ulong lower, ulong upper) { Lower = lower; Upper = upper; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static SNetExt_KeyHash16 FromSpan(ReadOnlySpan bytes16) { if (bytes16.Length < 16) { throw new ArgumentException("need 16 bytes", "bytes16"); } return new SNetExt_KeyHash16(BinaryPrimitives.ReadUInt64LittleEndian(bytes16), BinaryPrimitives.ReadUInt64LittleEndian(bytes16.Slice(8))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static SNetExt_KeyHash16 FromHex(string hex32) { if (string.IsNullOrWhiteSpace(hex32) || hex32.Length != 32) { return default(SNetExt_KeyHash16); } Span span = stackalloc byte[16]; if (!TryParseHex(hex32.AsSpan(), span)) { return default(SNetExt_KeyHash16); } return FromSpan(span); } private static bool TryParseHex(ReadOnlySpan hex, Span output) { for (int i = 0; i < 16; i++) { int num = ParseNibble(hex[i * 2]); int num2 = ParseNibble(hex[i * 2 + 1]); if (num < 0 || num2 < 0) { return false; } output[i] = (byte)((num << 4) | num2); } return true; } private static int ParseNibble(char c) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return c - 48; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return c - 97 + 10; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': return c - 65 + 10; default: return -1; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteTo(Span destination16) { BinaryPrimitives.WriteUInt64LittleEndian(destination16, Lower); BinaryPrimitives.WriteUInt64LittleEndian(destination16.Slice(8), Upper); } public string ToHex() { Span span = stackalloc byte[16]; WriteTo(span); return Convert.ToHexString(span); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(SNetExt_KeyHash16 other) { if (Lower == other.Lower) { return Upper == other.Upper; } return false; } public override bool Equals(object obj) { if (obj is SNetExt_KeyHash16 other) { return Equals(other); } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { long num = (long)Lower ^ ((long)Upper * -7046029254386353131L); long num2 = (num ^ (num >>> 30)) * -4658895280553007687L; long num3 = (num2 ^ (num2 >>> 27)) * -7723592293110705685L; long num4 = num3 ^ (num3 >>> 31); return (int)(num4 ^ (num4 >>> 32)); } public static bool operator ==(SNetExt_KeyHash16 a, SNetExt_KeyHash16 b) { return a.Equals(b); } public static bool operator !=(SNetExt_KeyHash16 a, SNetExt_KeyHash16 b) { return !a.Equals(b); } public override string ToString() { return ToHex(); } } internal sealed class SNetExt_ReplicatorRegistry { public enum RegisterStatus { Success, Conflict, InvalidKeyHash } private readonly Dictionary _byKeyHash = new Dictionary(64); private readonly Dictionary _keyToKeyHash = new Dictionary(64); private readonly Dictionary _byVanillaPtr = new Dictionary(64); private readonly List _assigned = new List(); public IReadOnlyList Assigned => _assigned; public RegisterStatus Register(ISNetExt_MutableReplicator r) { if (!r.HasValidKeyHash) { return RegisterStatus.InvalidKeyHash; } SNetExt_KeyHash16 sNetExt_KeyHash = SNetExt_KeyHash16.FromHex(r.KeyHash); if (sNetExt_KeyHash.IsEmpty) { return RegisterStatus.InvalidKeyHash; } if (_byKeyHash.TryGetValue(sNetExt_KeyHash, out var value) && value != null) { return RegisterStatus.Conflict; } _byKeyHash[sNetExt_KeyHash] = r; if (!r.IsAnonymous) { _keyToKeyHash[r.Key] = sNetExt_KeyHash; } if (!_assigned.Contains(r)) { _assigned.Add(r); } return RegisterStatus.Success; } public bool Unregister(ISNetExt_Replicator r) { if (r == null) { return false; } SNetExt_KeyHash16 key = SNetExt_KeyHash16.FromHex(r.KeyHash); if (key.IsEmpty || !_byKeyHash.TryGetValue(key, out var value) || value != r) { _assigned.Remove(r); return false; } _byKeyHash.Remove(key); if (!r.IsAnonymous) { _keyToKeyHash.Remove(r.Key); } _assigned.Remove(r); return true; } public RegisterStatus Reassign(ISNetExt_MutableReplicator r, in SNetExt_KeyHash16 newHash) { if (newHash.IsEmpty) { return RegisterStatus.InvalidKeyHash; } if (_byKeyHash.TryGetValue(newHash, out var value) && value != null && value != r) { return RegisterStatus.Conflict; } Unregister(r); r.AssignKey(string.Empty); r.AssignKeyHash(in newHash); return Register(r); } public bool TryGet(in SNetExt_KeyHash16 keyHash, out ISNetExt_Replicator r) { if (_byKeyHash.TryGetValue(keyHash, out r)) { return r != null; } return false; } public bool TryGetByKey(string key, out ISNetExt_Replicator r) { r = null; if (!string.IsNullOrWhiteSpace(key) && _keyToKeyHash.TryGetValue(key, out var value) && _byKeyHash.TryGetValue(value, out r)) { return r != null; } return false; } public bool TryGetByVanilla(IntPtr ptr, out SNetExt_Replicator_VanillaWrapper w) { if (_byVanillaPtr.TryGetValue(ptr, out w)) { return w != null; } return false; } public RegisterStatus RegisterVanilla(SNetExt_Replicator_VanillaWrapper w) { RegisterStatus num = Register(w); if (num == RegisterStatus.Success) { _byVanillaPtr[((Il2CppObjectBase)w.Vanilla).Pointer] = w; } return num; } public bool UnregisterVanilla(SNetExt_Replicator_VanillaWrapper w) { if (!Unregister(w)) { return false; } _byVanillaPtr.Remove(((Il2CppObjectBase)w.Vanilla).Pointer); return true; } public void Clear() { _byKeyHash.Clear(); _keyToKeyHash.Clear(); _byVanillaPtr.Clear(); _assigned.Clear(); } } internal class SNetExt_ReplicatorSupplierWrapper : Component { [HideFromIl2Cpp] public ISNetExt_ReplicatorSupplier ReplicatorSupplier { get; private set; } [HideFromIl2Cpp] public void Setup(ISNetExt_ReplicatorSupplier supplier) { ReplicatorSupplier = supplier; } } internal class SNetExt_StateReplicatorProviderWrapper : Component { [HideFromIl2Cpp] public ISNetExt_StateReplicatorProvider Provider { get; private set; } [HideFromIl2Cpp] public void Setup(ISNetExt_StateReplicatorProvider provider) { Provider = provider; } } public static class SNetExt { internal static readonly IArchiveLogger Logger = LoaderWrapper.CreateArSubLoggerInstance("SNetExt", ConsoleColor.White); private static readonly Dictionary<(ulong PlayerLookup, Type DataType), DataWrapper> s_dataWrappersLookup = new Dictionary<(ulong, Type), DataWrapper>(16); private static readonly List s_subManagers = new List(); public static SNetExt_Replication Replication { get; private set; } public static SNetExt_Replicator SubManagerReplicator { get; private set; } public static SNetExt_Capture Capture { get; private set; } public static SNetExt_PrefabReplicationManager PrefabReplication { get; private set; } internal static GameObject RootObject { get; private set; } internal static void Setup() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown if (!((Object)(object)RootObject != (Object)null)) { ClassInjector.RegisterTypeInIl2Cpp(false); ClassInjector.RegisterTypeInIl2Cpp(false); RootObject = new GameObject("SNetExt"); Object.DontDestroyOnLoad((Object)(object)RootObject); Capture = CreateSubManager(createSubGo: true, "Capture"); Replication = CreateSubManager(createSubGo: true, "Replication"); PrefabReplication = CreateSubManager(createSubGo: false, "PrefabReplication"); SubManagerReplicator = SNetExt_Replication.AddManagerReplicator("SNetExt_SubManager") as SNetExt_Replicator; SetupReplication(); } } public static T CreateSubManager(bool createSubGo = false, string name = "") where T : MonoBehaviour, ISNetExt_Manager { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown GameObject val; if (createSubGo) { val = new GameObject(name); val.transform.SetParent(RootObject.transform, false); } else { val = RootObject; } ClassInjector.RegisterTypeInIl2Cpp(false); T val2 = val.AddComponent(); val2.Setup(); s_subManagers.Add(val2); return val2; } public static void SendAllCustomData(SNet_Player sourcePlayer, SNet_Player toPlayer = null) { foreach (KeyValuePair<(ulong, Type), DataWrapper> item in s_dataWrappersLookup) { if (item.Key.Item1 == sourcePlayer.Lookup) { item.Value.Send(sourcePlayer, toPlayer); } } } public static void SetupCustomData(string eventName, Action callback) where A : struct, ISNetExt_ReplicatedPlayerData { SNetExt_ReplicatedPlayerData.Setup(eventName, callback); } public static void SetLocalCustomData(A data) where A : struct { if ((Object)(object)SNet.LocalPlayer != (Object)null) { SNet.LocalPlayer.StoreCustomData(data); } } public static void SendCustomData(SNet_Player toPlayer = null) where A : struct { if (((Object)(object)toPlayer != (Object)null && toPlayer.IsBot) || (Object)(object)SNet.LocalPlayer == (Object)null) { return; } SNetExt_ReplicatedPlayerData.SendData(SNet.LocalPlayer, GetLocalCustomData(), toPlayer); if (!SNet.IsMaster) { return; } List allBots = SNet.Core.GetAllBots(true); for (int i = 0; i < allBots.Count; i++) { SNet_Player val = allBots[i]; if (!((Object)(object)val == (Object)null) && val.IsBot) { SNetExt_ReplicatedPlayerData.SendData(val, val.LoadCustomData(), toPlayer); } } } public static A GetLocalCustomData() where A : struct { if ((Object)(object)SNet.LocalPlayer != (Object)null) { return SNet.LocalPlayer.LoadCustomData(); } return new A(); } public static A LoadCustomData(this SNet_Player player) where A : struct { (ulong, Type) key = (player.Lookup, typeof(A)); if (!s_dataWrappersLookup.TryGetValue(key, out var value)) { DataWrapper dataWrapper = new DataWrapper(); s_dataWrappersLookup.Add(key, dataWrapper); return dataWrapper.Load(); } return ((DataWrapper)value).Load(); } public static void StoreCustomData(this SNet_Player player, A data) where A : struct { (ulong, Type) key = (player.Lookup, typeof(A)); DataWrapper dataWrapper; if (!s_dataWrappersLookup.TryGetValue(key, out var value)) { dataWrapper = new DataWrapper(); s_dataWrappersLookup.Add(key, dataWrapper); } else { dataWrapper = (DataWrapper)value; } dataWrapper.Store(player, data); } public static void StoreCustomDataLocal(this SNet_Player player, A data) where A : struct { (ulong, Type) key = (player.Lookup, typeof(A)); DataWrapper dataWrapper; if (!s_dataWrappersLookup.TryGetValue(key, out var value)) { dataWrapper = new DataWrapper(); s_dataWrappersLookup.Add(key, dataWrapper); } else { dataWrapper = (DataWrapper)value; } dataWrapper.StoreLocal(data); } private static void SetupReplication() { for (int i = 0; i < s_subManagers.Count; i++) { s_subManagers[i].SetupReplication(); } } internal static void ResetSession() { for (int i = 0; i < s_subManagers.Count; i++) { s_subManagers[i].OnResetSession(); } } internal static void ValidateMasterData() { for (int i = 0; i < s_subManagers.Count; i++) { s_subManagers[i].OnValidateMasterData(); } } internal static void DestroySelfManagedReplicatedObject(GameObject go) { Il2CppArrayBase componentsInChildren = go.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { ISNetExt_StateReplicator stateReplicator = componentsInChildren[i].Provider.GetStateReplicator(); if (stateReplicator != null) { ISNetExt_Replicator replicator = stateReplicator.Replicator; if (stateReplicator is ICaptureCallbackObject syncInterface) { SNetExt_Capture.UnRegisterForDropInCallback(syncInterface); } SNetExt_Replication.DeallocateReplicator(replicator); } } } } public class SNetExt_AuthorativeAction : SNetExt_SyncedAction where T : struct { private Action m_incomingActionValidation; protected SNetExt_AuthorativeAction() { } public static SNetExt_AuthorativeAction Create(string eventName, Action incomingAction, Action incomingActionValidation, Func listenerFilter = null, SNet_ChannelType channelType = 2) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) SNetExt_AuthorativeAction sNetExt_AuthorativeAction = new SNetExt_AuthorativeAction(); sNetExt_AuthorativeAction.Setup(eventName, incomingAction, incomingActionValidation, listenerFilter, channelType); sNetExt_AuthorativeAction.m_incomingActionValidation = incomingActionValidation; return sNetExt_AuthorativeAction; } public void Ask(T data) { if (SNet.IsMaster) { m_incomingActionValidation(data); } else if (SNet.HasMaster) { m_packet.Send(data, SNet.Master); } } public void Do(T data) { if (SNet.IsMaster) { m_packet.Send(data, m_listeners); } else if (SNet.HasMaster) { m_packet.Send(data, SNet.Master); } } } public class SNetExt_BroadcastAction : SNetExt_SyncedAction where T : struct { public static SNetExt_BroadcastAction Create(string eventName, Action incomingAction, Func listenerFilter = null, SNet_ChannelType channelType = 2) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) SNetExt_BroadcastAction sNetExt_BroadcastAction = new SNetExt_BroadcastAction(); sNetExt_BroadcastAction.Setup(eventName, incomingAction, null, listenerFilter, channelType); return sNetExt_BroadcastAction; } public void Do(T data) { m_packet.Send(data, m_listeners); } } public class SNetExt_BufferSender { public enum State { Open, Send, Close, Done } private State m_state; private readonly float m_sendInterval; private readonly int m_packetsPerFrame; private int m_passIndex; private int m_packetIndex; private SNetExt_CaptureBuffer m_buffer; private readonly List m_sendToPlayers = new List(); private readonly SNetExt_BufferType m_bufferType; private readonly SNet_ChannelType m_channelType; private float m_sendTimer; private byte[] m_bufferBytes = new byte[3]; public SNetExt_BufferSender(int packetsPerFrame, float sendInterval, SNetExt_CaptureBuffer buffer, List players, SNet_ChannelType channelType) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) m_packetsPerFrame = packetsPerFrame; m_sendInterval = sendInterval; m_buffer = buffer; m_bufferType = buffer.type; m_channelType = channelType; for (int i = 0; i < players.Count; i++) { SNet_Player val = players[i]; if ((Object)(object)val != (Object)null && val.IsInSessionHub && !val.IsBot) { m_sendToPlayers.Add(val); } } } private void UpdateBufferBytes() { SNetExt_ReplicatedPacketBufferBytes.WriteBufferDataBytes(new SNetExt_ReplicatedPacketBufferBytes.BufferData(m_buffer.data.bufferID, (byte)m_passIndex), m_bufferBytes.AsSpan()); } private bool UpdatePlayerList() { for (int num = m_sendToPlayers.Count - 1; num >= 0; num--) { SNet_Player val = m_sendToPlayers[num]; if ((Object)(object)val == (Object)null || !val.IsInSessionHub || val.IsBot) { m_sendToPlayers.RemoveAt(num); } } return m_sendToPlayers.Count > 0; } public bool Update() { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) if (!SNet.IsMaster) { return true; } if (m_state == State.Send) { m_sendTimer += Clock.Delta; if (m_sendTimer < m_sendInterval) { return false; } m_sendTimer = 0f; } else { if (m_state == State.Done) { return true; } m_sendTimer = m_sendInterval + 1f; } if (!UpdatePlayerList()) { m_state = State.Done; return true; } switch (m_state) { case State.Open: SNetExt.Capture.m_bufferCommandPacket.Send(new pBufferCommand { type = m_bufferType, operation = SNetExt_BufferOperationType.StartReceive, bufferID = m_buffer.data.bufferID }, m_channelType, m_sendToPlayers); UpdateBufferBytes(); m_state = State.Send; break; case State.Send: { List list = m_buffer.m_passes[m_passIndex]; int num = m_packetIndex; if (num >= list.Count) { list = null; m_passIndex++; while (m_passIndex < m_buffer.m_passes.Length) { List list2 = m_buffer.m_passes[m_passIndex]; if (list2.Count > 0) { list = list2; m_packetIndex = 0; num = Mathf.Min(m_packetIndex + m_packetsPerFrame, list2.Count); UpdateBufferBytes(); break; } m_passIndex++; } if (list == null) { m_state = State.Close; break; } } else { num = Mathf.Min(m_packetIndex + m_packetsPerFrame, list.Count); } for (int i = m_packetIndex; i < num; i++) { SNetExt.Capture.m_bufferBytesPacket.Send(list[i], m_bufferBytes, m_sendToPlayers); m_packetIndex++; } break; } case State.Close: SNetExt.Capture.m_bufferCompletionPacket.Send(new pBufferCompletion { type = m_bufferType, data = m_buffer.data }, m_channelType, m_sendToPlayers); m_state = State.Done; break; case State.Done: return true; } return false; } } public class SNetExt_Capture : MonoBehaviour, ISNetExt_Manager { public enum SNetExt_CaptureState { Idle, Capturing, Recalling } internal SNetExt_ReplicatedPacket m_bufferCommandPacket; internal SNetExt_ReplicatedPacket m_bufferCompletionPacket; internal SNetExt_ReplicatedPacketBufferBytes m_bufferBytesPacket; private SNetExt_CaptureState _state; private SNetExt_CaptureBuffer _activeBuffer; private SNetExt_BufferType _activeBufferType; private SNetExt_CaptureBuffer[] m_buffers; private SNetExt_BufferSender m_passiveMigrationBufferSend; private float m_migrationTimer; private const float MIGRATION_CAPTURE_INTERVAL = 60f; private const float MIGRATION_CAPTURE_INTERVAL_MIN_DELAY = 20f; private ushort m_highestBufferID = 1; private float m_minTimeToSendNextBuffer; private readonly List m_migrationPlayerScratch = new List(8); private readonly List _summariesScratch = new List(8); private static readonly List s_captureCallbackObjects = new List(); private readonly IArchiveLogger _logger = LoaderWrapper.CreateArSubLoggerInstance("SNetExt_Capture", ConsoleColor.White); [HideFromIl2Cpp] public SNetExt_CaptureState State => _state; [HideFromIl2Cpp] public bool IsCapturing => _state == SNetExt_CaptureState.Capturing; [HideFromIl2Cpp] public bool IsRecalling => _state == SNetExt_CaptureState.Recalling; [HideFromIl2Cpp] public SNetExt_CaptureBuffer PrimedBuffer { get { if (!IsCapturing) { return null; } return _activeBuffer; } } [HideFromIl2Cpp] public SNetExt_BufferType PrimedBufferType => _activeBufferType; [HideFromIl2Cpp] public void Setup() { } [HideFromIl2Cpp] public void SetupReplication() { m_bufferCommandPacket = SNetExt.SubManagerReplicator.CreatePacket(typeof(pBufferCommand).FullName, OnReceiveBufferCommand); m_bufferCompletionPacket = SNetExt.SubManagerReplicator.CreatePacket(typeof(pBufferCompletion).FullName, OnReceiveBufferCompletion); m_bufferBytesPacket = SNetExt.SubManagerReplicator.CreatePacketBufferBytes(typeof(SNetExt_Capture).FullName + ".BufferBytes", OnReceiveBufferBytes); int length = Enum.GetValues(typeof(SNetExt_BufferType)).Length; m_buffers = new SNetExt_CaptureBuffer[length]; for (int i = 0; i < length; i++) { m_buffers[i] = new SNetExt_CaptureBuffer((SNetExt_BufferType)i); } } [HideFromIl2Cpp] public void OnResetSession() { for (int i = 0; i < m_buffers.Length; i++) { m_buffers[i].Clear(); } m_highestBufferID = 1; m_passiveMigrationBufferSend = null; _activeBuffer = null; _state = SNetExt_CaptureState.Idle; } [HideFromIl2Cpp] public void OnValidateMasterData() { } [HideFromIl2Cpp] internal static void RegisterCaptureCallback(ICaptureCallbackObject syncInterface) { s_captureCallbackObjects.Add(syncInterface); } [HideFromIl2Cpp] internal static void UnRegisterForDropInCallback(ICaptureCallbackObject syncInterface) { s_captureCallbackObjects.Remove(syncInterface); } [HideFromIl2Cpp] internal static void UnregisterCaptureCallback(ICaptureCallbackObject syncInterface) { UnRegisterForDropInCallback(syncInterface); } [HideFromIl2Cpp] internal static void CleanUpAllButManagersCaptureCallbacks() { int count = s_captureCallbackObjects.Count; while (count-- > 0) { ICaptureCallbackObject captureCallbackObject = s_captureCallbackObjects[count]; if (captureCallbackObject == null || !captureCallbackObject.PersistAcrossSession) { s_captureCallbackObjects.RemoveAt(count); } } } [HideFromIl2Cpp] internal void InitCheckpointRecall() { IncreaseRecallCount(SNetExt_BufferType.Checkpoint); } [HideFromIl2Cpp] internal void IncreaseRecallCount(SNetExt_BufferType bufferType) { SNetExt_CaptureBuffer sNetExt_CaptureBuffer = m_buffers[(uint)bufferType]; if (!sNetExt_CaptureBuffer.isValid) { _logger.Warning($"IncreaseRecallCount on invalid buffer {bufferType}"); } else { sNetExt_CaptureBuffer.data.recallCount++; } } [HideFromIl2Cpp] public List GetBufferSummaries() { _summariesScratch.Clear(); for (int i = 0; i < m_buffers.Length; i++) { SNetExt_CaptureBuffer sNetExt_CaptureBuffer = m_buffers[i]; if (sNetExt_CaptureBuffer.type != 0 && sNetExt_CaptureBuffer.isValid) { _summariesScratch.Add(new pBuffersSummary(sNetExt_CaptureBuffer)); } } return _summariesScratch; } [HideFromIl2Cpp] public bool HasCorrectMigrationBuffer(ref pBuffersSummary bufferSummary) { for (int i = 4; i <= 5; i++) { if (new pBuffersSummary(m_buffers[i]).IsSame(ref bufferSummary)) { return true; } } return false; } [HideFromIl2Cpp] public bool TrySendMigrationBuffer(pBuffersSummary bufferSummary, SNet_Player toPlayer) { SNetExt_CaptureBuffer sNetExt_CaptureBuffer = m_buffers[(uint)bufferSummary.bufferType]; if (!new pBuffersSummary(sNetExt_CaptureBuffer).IsSame(ref bufferSummary)) { return false; } SendBuffer(sNetExt_CaptureBuffer.type, toPlayer, sendAsMigrationBuffer: true); return true; } [HideFromIl2Cpp] public bool TrySendLatestMigrationBuffer(SNet_Player toPlayer, bool forceCapture = false) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected I4, but got Unknown //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_0057: Expected I4, but got Unknown if (SNet.Sync.IsBitSet(SNet.Sync.MASK_IN_SESSION_HUB, (int)SNet.LocalPlayer.Session.mode)) { return false; } if (!TryGetNewestMigrationBuffer(out var type)) { if (!forceCapture || !SNet.Sync.IsBitSet(SNet.Sync.MASK_MASTER_CAN_RECALL_GAMESTATE, (int)SNet.LocalPlayer.Session.mode)) { return false; } SNetExt.Capture.CaptureGameState(GetOldestMigrationBuffer()); if (!TryGetNewestMigrationBuffer(out type)) { _logger.Error("TrySendLatestMigrationBuffer: forceCapture failed to produce usable buffer"); return false; } } SendBuffer(type, toPlayer); return true; } [HideFromIl2Cpp] public bool GotBuffer(SNetExt_BufferType type) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) SNetExt_CaptureBuffer sNetExt_CaptureBuffer = m_buffers[(uint)type]; if (sNetExt_CaptureBuffer.isValid) { return SNet.LocalPlayer.Session.levelChecksum == sNetExt_CaptureBuffer.data.levelChecksum; } return false; } [HideFromIl2Cpp] private SNetExt_BufferType GetOldestMigrationBuffer() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) SNetExt_CaptureBuffer sNetExt_CaptureBuffer = null; for (int i = 4; i <= 5; i++) { SNetExt_CaptureBuffer sNetExt_CaptureBuffer2 = m_buffers[i]; if (!sNetExt_CaptureBuffer2.isValid || SNet.LocalPlayer.Session.levelChecksum != sNetExt_CaptureBuffer2.data.levelChecksum) { sNetExt_CaptureBuffer = sNetExt_CaptureBuffer2; } else if (sNetExt_CaptureBuffer == null || sNetExt_CaptureBuffer2.data.progressionTime < sNetExt_CaptureBuffer.data.progressionTime) { sNetExt_CaptureBuffer = sNetExt_CaptureBuffer2; } } return sNetExt_CaptureBuffer.type; } [HideFromIl2Cpp] public bool TryGetNewestMigrationBuffer(out SNetExt_BufferType type) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) SNetExt_CaptureBuffer sNetExt_CaptureBuffer = null; for (int i = 4; i <= 5; i++) { SNetExt_CaptureBuffer sNetExt_CaptureBuffer2 = m_buffers[i]; if (sNetExt_CaptureBuffer2.isValid && SNet.LocalPlayer.Session.levelChecksum == sNetExt_CaptureBuffer2.data.levelChecksum && (sNetExt_CaptureBuffer == null || sNetExt_CaptureBuffer2.data.progressionTime > sNetExt_CaptureBuffer.data.progressionTime)) { sNetExt_CaptureBuffer = sNetExt_CaptureBuffer2; } } if (sNetExt_CaptureBuffer != null) { type = sNetExt_CaptureBuffer.type; return true; } type = SNetExt_BufferType.JoinedHub; return false; } private void Update() { if (SNet.IsMaster) { UpdateMigrationSend(); } } [HideFromIl2Cpp] private void UpdateMigrationSend() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected I4, but got Unknown if (SNet.MasterManagement.IsMigrating || !SNet.Sync.IsBitSet(SNet.Sync.MASK_PLAYER_READY_TO_START_PLAYING, (int)SNet.LocalPlayer.Session.mode)) { m_passiveMigrationBufferSend = null; } else if (m_passiveMigrationBufferSend != null) { if (m_passiveMigrationBufferSend.Update()) { m_passiveMigrationBufferSend = null; m_minTimeToSendNextBuffer = Clock.Time + 20f; } } else { if (m_minTimeToSendNextBuffer > Clock.Time || m_migrationTimer >= Clock.Time) { return; } SNetExt_BufferType oldestMigrationBuffer = GetOldestMigrationBuffer(); CaptureGameState(oldestMigrationBuffer); m_migrationPlayerScratch.Clear(); List playersInSession = SNet.SessionHub.PlayersInSession; for (int i = 0; i < playersInSession.Count; i++) { SNet_Player val = playersInSession[i]; if (!val.IsLocal && !val.IsBot) { m_migrationPlayerScratch.Add(val); } } if (m_migrationPlayerScratch.Count == 0) { m_minTimeToSendNextBuffer = Clock.Time + 20f; return; } m_passiveMigrationBufferSend = new SNetExt_BufferSender(5, 0.5f, m_buffers[(uint)oldestMigrationBuffer], m_migrationPlayerScratch, (SNet_ChannelType)1); m_migrationTimer = Clock.Time + 60f; } } [HideFromIl2Cpp] internal void CaptureGameState(SNetExt_BufferType buffer) { pBufferCommand pBufferCommand2 = default(pBufferCommand); pBufferCommand2.type = buffer; pBufferCommand2.operation = SNetExt_BufferOperationType.StoreGameState; pBufferCommand command = pBufferCommand2; OnBufferCommand(command); } [HideFromIl2Cpp] internal void RecallGameState(SNetExt_BufferType buffer) { pBufferCommand pBufferCommand2 = default(pBufferCommand); pBufferCommand2.type = buffer; pBufferCommand2.operation = SNetExt_BufferOperationType.RecallGameState; pBufferCommand command = pBufferCommand2; OnBufferCommand(command); } [HideFromIl2Cpp] internal void SendBufferCommand(SNetExt_BufferType buffer, SNetExt_BufferOperationType operation, SNet_Player toPlayer = null, ushort bufferID = 0) { if ((Object)(object)toPlayer != (Object)null) { m_bufferCommandPacket.Send(new pBufferCommand { type = buffer, operation = operation, bufferID = bufferID }, (SNet_ChannelType)0, toPlayer); } else { m_bufferCommandPacket.Send(new pBufferCommand { type = buffer, operation = operation, bufferID = bufferID }, (SNet_ChannelType)0); } } [HideFromIl2Cpp] private void OnReceiveBufferCommand(pBufferCommand command) { if (SNet.MasterManagement.IsMigrating) { OnBufferCommand(command); } else if (SNetExt.Replication.IsLastSenderMaster) { OnBufferCommand(command); } } [HideFromIl2Cpp] private void OnBufferCommand(pBufferCommand command) { switch (command.operation) { case SNetExt_BufferOperationType.StartReceive: OpenBuffer(command.type, command.bufferID); if (_activeBuffer != null) { _activeBuffer.data.sendingPlayerLookup = SNetExt.Replication.LastSenderID; } break; case SNetExt_BufferOperationType.StoreGameState: OpenBuffer(command.type, 0); TriggerCapture(); CloseBuffer(command.type); break; case SNetExt_BufferOperationType.RecallGameState: RecallBuffer(command.type); break; } } [HideFromIl2Cpp] private void OpenBuffer(SNetExt_BufferType type, ushort bufferID = 0) { switch (bufferID) { case 0: m_highestBufferID++; if (m_highestBufferID == ushort.MaxValue) { m_highestBufferID = 1; } bufferID = m_highestBufferID; break; case 1: m_highestBufferID = 1; break; default: if (m_highestBufferID < bufferID) { m_highestBufferID = bufferID; } break; } _activeBufferType = type; _activeBuffer = m_buffers[(uint)type]; _activeBuffer.Clear(); _activeBuffer.data.bufferID = bufferID; _state = SNetExt_CaptureState.Capturing; } [HideFromIl2Cpp] private void TriggerCapture() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < SNetExt.Replication.ReplicationManagers.Count; i++) { SNetExt.Replication.ReplicationManagers[i].OnStateCapture(); } for (int j = 0; j < s_captureCallbackObjects.Count; j++) { s_captureCallbackObjects[j].OnStateCapture(); } if (_activeBuffer != null) { _activeBuffer.data.levelChecksum = SNet.LocalPlayer.Session.levelChecksum; _activeBuffer.data.progressionTime = Clock.ExpeditionProgressionTime; } } [HideFromIl2Cpp] internal void CaptureToBuffer(byte[] data, SNetExt_CapturePass captureDataType) { if (captureDataType != SNetExt_CapturePass.Skip && _activeBuffer != null) { byte[] array = new byte[data.Length]; Buffer.BlockCopy(data, 0, array, 0, data.Length); _activeBuffer.GetPass(captureDataType).Add(array); } } [HideFromIl2Cpp] private bool IsValidBufferData(SNet_Player sender) { if (!SNet.MasterManagement.IsMigrating) { return SNetExt.Replication.IsLastSenderMaster; } return true; } [HideFromIl2Cpp] private void OnReceiveBufferCompletion(pBufferCompletion completion) { if (SNetExt.Replication.TryGetLastSender(out var sender) && sender.IsInSessionHub && _state == SNetExt_CaptureState.Capturing && _activeBuffer != null && SNetExt.Replication.LastSenderID == _activeBuffer.data.sendingPlayerLookup && _activeBufferType == completion.type && _activeBuffer.data.bufferID == completion.data.bufferID) { _activeBuffer.isValid = true; _activeBuffer.data = completion.data; _activeBuffer = null; _state = SNetExt_CaptureState.Idle; } } [HideFromIl2Cpp] private void CloseBuffer(SNetExt_BufferType type) { if (_state == SNetExt_CaptureState.Capturing && _activeBufferType == type) { if (_activeBuffer != null) { _activeBuffer.isValid = true; } _activeBuffer = null; _state = SNetExt_CaptureState.Idle; } } [HideFromIl2Cpp] public void SendBuffer(SNetExt_BufferType bufferType, SNet_Player player = null, bool sendAsMigrationBuffer = false) { m_minTimeToSendNextBuffer = Clock.Time + 20f; SNetExt_BufferType sNetExt_BufferType = (sendAsMigrationBuffer ? GetOldestMigrationBuffer() : bufferType); SNetExt_CaptureBuffer sNetExt_CaptureBuffer = m_buffers[(uint)sNetExt_BufferType]; pBufferCommand pBufferCommand2 = default(pBufferCommand); pBufferCommand2.type = sNetExt_BufferType; pBufferCommand2.operation = SNetExt_BufferOperationType.StartReceive; pBufferCommand2.bufferID = sNetExt_CaptureBuffer.data.bufferID; pBufferCommand data = pBufferCommand2; if ((Object)(object)player != (Object)null) { m_bufferCommandPacket.Send(data, (SNet_ChannelType)0, player); } else { m_bufferCommandPacket.Send(data, (SNet_ChannelType)0); } pBufferCompletion pBufferCompletion2 = default(pBufferCompletion); pBufferCompletion2.type = sNetExt_BufferType; pBufferCompletion2.data = sNetExt_CaptureBuffer.data; pBufferCompletion data2 = pBufferCompletion2; byte[] array = new byte[3]; if ((Object)(object)player != (Object)null) { for (int i = 0; i < SNetExt_CaptureBuffer.PassCount; i++) { List list = sNetExt_CaptureBuffer.m_passes[i]; SNetExt_ReplicatedPacketBufferBytes.WriteBufferDataBytes(new SNetExt_ReplicatedPacketBufferBytes.BufferData(sNetExt_CaptureBuffer.data.bufferID, (byte)i), array.AsSpan()); int count = list.Count; for (int j = 0; j < count; j++) { m_bufferBytesPacket.Send(list[j], array, player); } } m_bufferCompletionPacket.Send(data2, (SNet_ChannelType)0, player); return; } for (int k = 0; k < SNetExt_CaptureBuffer.PassCount; k++) { List list2 = sNetExt_CaptureBuffer.m_passes[k]; SNetExt_ReplicatedPacketBufferBytes.WriteBufferDataBytes(new SNetExt_ReplicatedPacketBufferBytes.BufferData(sNetExt_CaptureBuffer.data.bufferID, (byte)k), array.AsSpan()); int count2 = list2.Count; for (int l = 0; l < count2; l++) { m_bufferBytesPacket.Send(list2[l], array); } } m_bufferCompletionPacket.Send(data2, (SNet_ChannelType)0); } [HideFromIl2Cpp] public void OnReceiveBufferBytes(ReadOnlySpan bytes, SNetExt_ReplicatedPacketBufferBytes.BufferData bufferData) { if (_state == SNetExt_CaptureState.Capturing) { SNetExt_CaptureBuffer activeBuffer = _activeBuffer; if (activeBuffer != null && activeBuffer.data.bufferID == bufferData.bufferID && activeBuffer.data.sendingPlayerLookup == SNetExt.Replication.LastSenderID && (SNet.MasterManagement.IsMigrating || SNetExt.Replication.IsLastSenderMaster) && bufferData.pass < SNetExt_CaptureBuffer.PassCount) { activeBuffer.m_passes[bufferData.pass].Add(bytes.ToArray()); } } } [HideFromIl2Cpp] public ulong GetRecallCount(SNetExt_BufferType type) { SNetExt_CaptureBuffer sNetExt_CaptureBuffer = m_buffers[(uint)type]; if (!sNetExt_CaptureBuffer.isValid) { return 0uL; } return sNetExt_CaptureBuffer.data.recallCount; } [HideFromIl2Cpp] private void RecallBuffer(SNetExt_BufferType bufferType) { SNetExt_CaptureBuffer sNetExt_CaptureBuffer = m_buffers[(uint)bufferType]; _state = SNetExt_CaptureState.Recalling; _activeBufferType = bufferType; try { if (!sNetExt_CaptureBuffer.isValid) { return; } List replicationManagers = SNetExt.Replication.ReplicationManagers; for (int i = 0; i < replicationManagers.Count; i++) { replicationManagers[i].ClearAllLocal(); } SNetExt.Replication.OnRecall(); for (int j = 0; j < SNetExt_CaptureBuffer.PassCount; j++) { List list = sNetExt_CaptureBuffer.m_passes[j]; int count = list.Count; for (int k = 0; k < count; k++) { byte[] bytes = list[k]; SNetExt.Replication.RecallBytes(bytes); } } SNetExt.Replication.OnPostRecall(); } finally { _state = SNetExt_CaptureState.Idle; } } [HideFromIl2Cpp] public static bool TryGetInterface(A obj, out B intObj) where A : class where B : Object { intObj = (B)(object)((obj is B) ? obj : null); return (Object)(object)intObj != (Object)null; } } public class SNetExt_CaptureBuffer { public static readonly int PassCount = Enum.GetValues(typeof(SNetExt_BufferType)).Length - 1; public bool isValid; public SNetExt_BufferType type; public pBufferData data; public List[] m_passes; public SNetExt_CaptureBuffer(SNetExt_BufferType type) { this.type = type; m_passes = new List[PassCount]; for (int i = 0; i < PassCount; i++) { m_passes[i] = new List(); } } public List GetPass(SNetExt_CapturePass pass) { if ((int)pass < 0 || (int)pass >= PassCount) { throw new ArgumentOutOfRangeException("pass", $"pass={pass} must be < PassCount ({PassCount})"); } return m_passes[(uint)pass]; } public void Clear() { isValid = false; for (int i = 0; i < PassCount; i++) { m_passes[i].Clear(); } } } public abstract class DataWrapper { public abstract void Send(SNet_Player fromPlayer, SNet_Player toPlayer = null); } public class DataWrapper : DataWrapper where A : struct { private A m_data; public A Load() { return m_data; } public void Store(SNet_Player player, A data) { m_data = data; SNetExt_ReplicatedPlayerData.SendData(player, m_data); } public void StoreLocal(A data) { m_data = data; } public override void Send(SNet_Player fromPlayer, SNet_Player toPlayer = null) { SNetExt_ReplicatedPlayerData.SendData(fromPlayer, m_data, toPlayer); } } public class SNetExt_DynamicReplicator : SNetExt_Replicator, ISNetExt_OwnedReplicator, ISNetExt_MutableReplicator, ISNetExt_Replicator where T : struct, ISNetExt_DynamicReplication { private bool m_isRegistered; private SNetExt_ReplicationManager m_manager; private T m_spawnData; public override SNetExt_ReplicatorType Type => SNetExt_ReplicatorType.Dynamic; public override bool LocallyOwned { get { if (!OwnedByMaster) { if ((Object)(object)OwningPlayer != (Object)null) { return OwningPlayer.IsLocal; } return false; } return SNet.IsMaster; } } SNet_Player ISNetExt_OwnedReplicator.OwningPlayer { get { return OwningPlayer; } set { SetOwningPlayerInternal(value); } } bool ISNetExt_OwnedReplicator.OwnedByMaster { get { return OwnedByMaster; } set { SetOwnedByMasterInternal(value); } } public bool HasManager => m_manager != null; public void SetManager(SNetExt_ReplicationManager manager) { m_manager = manager; m_isRegistered = manager != null; } internal void SetSpawnData(T spawnData) { m_spawnData = spawnData; } public T GetSpawnData() { return m_spawnData; } public bool TryInternalCollectCapture(out T spawnData, out SNetExt_CapturePass captureType) { if (base.ReplicatorSupplier is ISNetExt_DynamicReplicatorSupplier iSNetExt_DynamicReplicatorSupplier && iSNetExt_DynamicReplicatorSupplier.TryCollectCaptureData(ref m_spawnData, out captureType)) { pReplicationData replicationData = m_spawnData.ReplicationData; replicationData.isRecall = true; m_spawnData.ReplicationData = replicationData; spawnData = m_spawnData; return true; } captureType = SNetExt_CapturePass.Skip; spawnData = new T(); return false; } public override void Despawn() { if (m_isRegistered && SNet.IsMaster) { m_manager.DeSpawn(this); return; } ISNetExt_ReplicatorSupplier replicatorSupplier = base.ReplicatorSupplier; base.ReplicatorSupplier = null; if ((Object)(object)replicatorSupplier?.gameObject != (Object)null) { Object.Destroy((Object)(object)replicatorSupplier.gameObject); } } } public static class SNetExt_Marshal { public static SNetExt_Marshaller GetMarshaler() where T : struct { SNetExt_Marshaller sNetExt_Marshaller = new SNetExt_Marshaller(); sNetExt_Marshaller.Setup(Marshal.SizeOf()); return sNetExt_Marshaller; } } public abstract class SNetExt_Marshaller { protected Type m_marshallingType; public abstract void Setup(int size); public Type MarshalsType() { return m_marshallingType; } } public class SNetExt_Marshaller : SNetExt_Marshaller where T : struct { public int SizeWithIDs; public int Size; public bool IsBlittable { get; private set; } public override void Setup(int size) { Size = size; SizeWithIDs = Size + 33; m_marshallingType = typeof(T); IsBlittable = DetectBlittable(typeof(T)); } private static bool DetectBlittable(Type type) { if (type.IsPrimitive) { return true; } if (type.IsEnum) { return true; } if (type == typeof(string)) { return false; } if (!type.IsValueType) { return false; } if (type == typeof(IntPtr) || type == typeof(UIntPtr)) { return true; } if (type == typeof(decimal)) { return false; } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.GetCustomAttribute() != null) { return false; } if (!fieldInfo.FieldType.IsValueType) { return false; } if (!fieldInfo.FieldType.IsPrimitive && !fieldInfo.FieldType.IsEnum && !DetectBlittable(fieldInfo.FieldType)) { return false; } } return true; } public virtual void MarshalToBytes(T data, byte[] bytes) { if (IsBlittable) { MemoryMarshal.Write(bytes.AsSpan(33, Size), ref data); return; } IntPtr intPtr = Marshal.AllocHGlobal(Size); try { Marshal.StructureToPtr(data, intPtr, fDeleteOld: false); Marshal.Copy(intPtr, bytes, 33, Size); } finally { Marshal.DestroyStructure(intPtr); Marshal.FreeHGlobal(intPtr); } } public void MarshalToData(byte[] bytes, ref T data) { if (IsBlittable) { data = MemoryMarshal.Read(bytes.AsSpan(33, Size)); return; } IntPtr intPtr = Marshal.AllocHGlobal(Size); try { Marshal.Copy(bytes, 33, intPtr, Size); data = (T)Marshal.PtrToStructure(intPtr, m_marshallingType); } finally { Marshal.FreeHGlobal(intPtr); } } } public class SNetExt_Packet where T : struct { [ThreadStatic] private List t_remotePlayerScratch; private T m_data = new T(); private bool m_hasValidateAction; public string EventName { get; private set; } public SNet_ChannelType ChannelType { get; private set; } private Action ValidateAction { get; set; } private Action ReceiveAction { get; set; } public static SNetExt_Packet Create(string eventName, Action receiveAction, Action validateAction = null, SNet_ChannelType channelType = 2) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) SNetExt_Packet sNetExt_Packet = new SNetExt_Packet { EventName = eventName, ChannelType = channelType, ReceiveAction = receiveAction, ValidateAction = validateAction, m_hasValidateAction = (validateAction != null) }; NetworkAPI.RegisterEvent(eventName, (Action)sNetExt_Packet.OnReceiveData); return sNetExt_Packet; } public void Ask(T data) { if (SNet.IsMaster) { ValidateAction(data); } else if (SNet.HasMaster) { Send(data, SNet.Master); } } public void Send(T data) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) NetworkAPI.InvokeEvent(EventName, data, ChannelType); } public void Send(T data, SNet_Player player) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (player.IsLocal) { OnReceiveData(player, data); } else { NetworkAPI.InvokeEvent(EventName, data, player, ChannelType); } } public void Send(T data, List players) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if (players == null || players.Count == 0) { return; } bool flag = false; int num = 0; for (int i = 0; i < players.Count; i++) { if (players[i].IsLocal) { flag = true; } else { num++; } } if (num > 0) { if (!flag) { NetworkAPI.InvokeEvent(EventName, data, players, ChannelType); } else { List remotePlayerScratchList = GetRemotePlayerScratchList(); remotePlayerScratchList.Clear(); if (remotePlayerScratchList.Capacity < num) { remotePlayerScratchList.Capacity = num; } for (int j = 0; j < players.Count; j++) { if (!players[j].IsLocal) { remotePlayerScratchList.Add(players[j]); } } NetworkAPI.InvokeEvent(EventName, data, remotePlayerScratchList, ChannelType); } } if (flag) { OnReceiveData(SNet.LocalPlayer, data); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private List GetRemotePlayerScratchList() { return t_remotePlayerScratch ?? (t_remotePlayerScratch = new List(8)); } private void OnReceiveData(ulong senderId, T data) { SNet_Player sender = default(SNet_Player); if (SNet.TryGetPlayer(senderId, ref sender)) { OnReceiveData(sender, data); } } private void OnReceiveData(SNet_Player sender, T data) { m_data = data; if (m_hasValidateAction && SNet.IsMaster) { ValidateAction(m_data); } else { ReceiveAction(sender, m_data); } } protected SNetExt_Packet() { } } public class SNetExt_PrefabReplicationManager : MonoBehaviour, ISNetExt_Manager { private readonly Dictionary m_repManagers = new Dictionary(16); [HideFromIl2Cpp] public void OnValidateMasterData() { } [HideFromIl2Cpp] public void SetupReplicationFor(Action callback = null) where TData : struct, ISNetExt_DynamicReplication { GetRepManager(out SNetExt_ReplicationManager> repManager); repManager.SpawnDespawnCallback = callback; } [HideFromIl2Cpp] public void ClearPrefabs() where TData : struct, ISNetExt_DynamicReplication { GetRepManager(out SNetExt_ReplicationManager> repManager); repManager.ClearPrefabs(); } [HideFromIl2Cpp] public void AddPrefab(string prefabKey, GameObject prefab) where TData : struct, ISNetExt_DynamicReplication { GetRepManager(out SNetExt_ReplicationManager> repManager); repManager.AddPrefab(prefabKey, prefab); } [HideFromIl2Cpp] public bool RemovePrefab(string prefabKey) where TData : struct, ISNetExt_DynamicReplication { GetRepManager(out SNetExt_ReplicationManager> repManager); return repManager.RemovePrefab(prefabKey); } [HideFromIl2Cpp] public bool RemovePrefab(GameObject prefab) where TData : struct, ISNetExt_DynamicReplication { GetRepManager(out SNetExt_ReplicationManager> repManager); return repManager.RemovePrefab(prefab); } [HideFromIl2Cpp] private void GetRepManager(out SNetExt_ReplicationManager repManager) where TReplicator : SNetExt_DynamicReplicator, new() where TData : struct, ISNetExt_DynamicReplication { Type typeFromHandle = typeof(TData); if (m_repManagers.TryGetValue(typeFromHandle, out var value)) { repManager = value as SNetExt_ReplicationManager; if (repManager == null) { throw new InvalidOperationException($"Manager for {typeFromHandle.Name} was registered with a different TReplicator (existing: {value.GetType().Name})"); } } else { repManager = new SNetExt_ReplicationManager((SNet_ChannelType)2); m_repManagers.Add(typeFromHandle, repManager); } } [HideFromIl2Cpp] public void Spawn(GameObject prefab, TData spawnData) where TData : struct, ISNetExt_DynamicReplication { GetRepManager(out SNetExt_ReplicationManager> repManager); repManager.Spawn(prefab, spawnData); } [HideFromIl2Cpp] public List> GetReplicatorList() where TData : struct, ISNetExt_DynamicReplication { GetRepManager(out SNetExt_ReplicationManager> repManager); return repManager.m_replicators; } [HideFromIl2Cpp] public void Setup() { } [HideFromIl2Cpp] public void SetupReplication() { } [HideFromIl2Cpp] public void OnResetSession() { } [HideFromIl2Cpp] public void OnClearAllSpawnedLocal() { foreach (KeyValuePair repManager in m_repManagers) { repManager.Value.ClearAllLocal(); } } } public abstract class SNetExt_ReplicatedPacket { private string m_key; private string m_keyHash; private byte[] m_keyHashBytes; private static readonly byte[] s_emptyHashBytes = new byte[16]; public ISNetExt_Replicator Replicator { get; private set; } public byte Index { get; private set; } public string Key { get { return m_key; } set { m_key = value ?? string.Empty; if (string.IsNullOrWhiteSpace(m_key)) { m_keyHash = string.Empty; m_keyHashBytes = s_emptyHashBytes; return; } Span span = stackalloc byte[16]; SNetExt_HashUtil.KeyToHashBytes(m_key, span); m_keyHash = SNetExt_HashUtil.HashBytesToHex(span); m_keyHashBytes = span.ToArray(); } } public string KeyHash { get { return m_keyHash; } set { m_keyHash = value ?? string.Empty; if (string.IsNullOrWhiteSpace(m_keyHash) || m_keyHash.Length != 32) { m_keyHashBytes = s_emptyHashBytes; } else { m_keyHashBytes = SNetExt_HashUtil.HashHexToBytes(m_keyHash); } } } public byte[] KeyHashBytes { get { return m_keyHashBytes; } private set { m_keyHashBytes = value; } } public bool IsAnonymous => string.IsNullOrWhiteSpace(Key); public bool HasValidKeyHash { get { if (!string.IsNullOrWhiteSpace(KeyHash)) { return KeyHash.Length == 32; } return false; } } public virtual void Setup(ISNetExt_Replicator replicator, byte index) { if (string.IsNullOrWhiteSpace(Key)) { Key = GetType().FullName; } Replicator = replicator; Index = index; } public virtual void ReceiveBytes(byte[] bytes) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] protected void InjectIDPacketIndex(byte[] bytes) { Replicator.KeyHashBytes.CopyTo(bytes.AsSpan(0, 16)); Buffer.BlockCopy(KeyHashBytes, 0, bytes, 16, 16); bytes[32] = Index; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InjectIDPacketIndex(SNetExt_ReplicatedPacket packet, byte[] bytes, ReadOnlySpan replicatorKeyHashBytes, byte[] packetKeyHashBytes) { replicatorKeyHashBytes.CopyTo(bytes.AsSpan(0, 16)); Buffer.BlockCopy(packetKeyHashBytes, 0, bytes, 16, 16); bytes[32] = packet.Index; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] PacketKeyHashToBytes(string keyHash) { return SNetExt_HashUtil.HashHexToBytes(keyHash); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string PacketKeyToHash(string key) { return SNetExt_HashUtil.KeyToHashHex(key); } } public class SNetExt_ReplicatedPacket : SNetExt_ReplicatedPacket where T : struct { private T m_data = new T(); private byte[] m_internalBytes; private bool m_hasValidateAction; private static bool s_hasMarshaller; private static SNetExt_Marshaller s_marshaller; private Action ValidateAction { get; set; } private Action ReceiveAction { get; set; } public override void Setup(ISNetExt_Replicator replicator, byte index) { if (string.IsNullOrWhiteSpace(base.Key)) { base.Key = typeof(T).FullName; } base.Setup(replicator, index); SetInternalSize(); } public static SNetExt_ReplicatedPacket Create(string key, Action receiveAction, Action validateAction = null) { if (!s_hasMarshaller) { s_marshaller = SNetExt_Marshal.GetMarshaler(); s_hasMarshaller = s_marshaller != null; if (!s_hasMarshaller) { return null; } } return new SNetExt_ReplicatedPacket { Key = (string.IsNullOrWhiteSpace(key) ? typeof(T).FullName : key), ReceiveAction = receiveAction, ValidateAction = validateAction, m_hasValidateAction = (validateAction != null) }; } public void Ask(T data, SNet_ChannelType channelType = 0) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (SNet.IsMaster) { ValidateAction(data); } else if (SNet.HasMaster) { Send(data, channelType, SNet.Master); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(T data, SNet_ChannelType type) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) WritePayload(data); NetworkAPI.InvokeFreeSizedEvent("SNetExt_Replication", m_internalBytes, type); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(T data, SNet_ChannelType type, SNet_Player player) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) WritePayload(data); NetworkAPI.InvokeFreeSizedEvent("SNetExt_Replication", m_internalBytes, player, type); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(T data, SNet_ChannelType type, List players) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) WritePayload(data); NetworkAPI.InvokeFreeSizedEvent("SNetExt_Replication", m_internalBytes, (IEnumerable)players, type); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WritePayload(T data) { if (s_marshaller.IsBlittable) { MemoryMarshal.Write(m_internalBytes.AsSpan(33, s_marshaller.Size), ref data); return; } IntPtr intPtr = Marshal.AllocHGlobal(s_marshaller.Size); try { Marshal.StructureToPtr(data, intPtr, fDeleteOld: false); Marshal.Copy(intPtr, m_internalBytes, 33, s_marshaller.Size); } finally { Marshal.DestroyStructure(intPtr); Marshal.FreeHGlobal(intPtr); } } internal void CaptureToBuffer(T data, SNetExt_CapturePass captureDataType) { s_marshaller.MarshalToBytes(data, m_internalBytes); SNetExt.Capture.CaptureToBuffer(m_internalBytes, captureDataType); } public override void ReceiveBytes(byte[] bytes) { if (bytes.Length != s_marshaller.SizeWithIDs) { SNetExt.Logger.Warning($"ReceiveBytes<{typeof(T).Name}>: size mismatch (expected {s_marshaller.SizeWithIDs}, got {bytes.Length})"); } else { s_marshaller.MarshalToData(bytes, ref m_data); if (m_hasValidateAction && SNet.IsMaster) { ValidateAction(m_data); } else { ReceiveAction(m_data); } } } private void SetInternalSize() { m_internalBytes = new byte[s_marshaller.SizeWithIDs]; InjectIDPacketIndex(m_internalBytes); } } public class SNetExt_ReplicatedPacketBufferBytes : SNetExt_ReplicatedPacket { public delegate void SpanBufferReceiveDelegate(ReadOnlySpan payload, BufferData bufferData); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct BufferData { public ushort bufferID; public byte pass; public BufferData(ushort bufferID, byte pass) { this.bufferID = bufferID; this.pass = pass; } } public static readonly int BUFFER_DATA_BYTE_SIZE = Marshal.SizeOf(); private SNet_ChannelType m_channelType; public SNet_ChannelType ChannelType { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return m_channelType; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) m_channelType = value; } } private SpanBufferReceiveDelegate ReceiveAction { get; set; } public static SNetExt_ReplicatedPacketBufferBytes Create(string key, SpanBufferReceiveDelegate receiveAction) { if (receiveAction == null) { throw new ArgumentNullException("receiveAction"); } return new SNetExt_ReplicatedPacketBufferBytes { Key = key, ReceiveAction = receiveAction }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteBufferDataBytes(BufferData bufferData, Span destination3) { if (destination3.Length < 3) { throw new ArgumentException("need 3 bytes", "destination3"); } destination3[0] = (byte)(bufferData.bufferID & 0xFFu); destination3[1] = (byte)((uint)(bufferData.bufferID >> 8) & 0xFFu); destination3[2] = bufferData.pass; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static BufferData GetBufferData(byte[] bytes) { ushort bufferID = BinaryPrimitives.ReadUInt16LittleEndian(bytes.AsSpan(33, 2)); byte pass = bytes[35]; return new BufferData(bufferID, pass); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(byte[] data, byte[] bufferDataBytes) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[data.Length + 33 + BUFFER_DATA_BYTE_SIZE]; Buffer.BlockCopy(bufferDataBytes, 0, array, 33, BUFFER_DATA_BYTE_SIZE); Buffer.BlockCopy(data, 0, array, 33 + BUFFER_DATA_BYTE_SIZE, data.Length); SNetExt_ReplicatedPacket.InjectIDPacketIndex(this, array, base.Replicator.KeyHashBytes, base.KeyHashBytes); NetworkAPI.InvokeFreeSizedEvent("SNetExt_Replication", array, m_channelType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(byte[] data, byte[] bufferDataBytes, SNet_Player toPlayer) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[data.Length + 33 + BUFFER_DATA_BYTE_SIZE]; Buffer.BlockCopy(bufferDataBytes, 0, array, 33, BUFFER_DATA_BYTE_SIZE); Buffer.BlockCopy(data, 0, array, 33 + BUFFER_DATA_BYTE_SIZE, data.Length); SNetExt_ReplicatedPacket.InjectIDPacketIndex(this, array, base.Replicator.KeyHashBytes, base.KeyHashBytes); NetworkAPI.InvokeFreeSizedEvent("SNetExt_Replication", array, toPlayer, m_channelType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(byte[] data, byte[] bufferDataBytes, List toPlayers) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[data.Length + 33 + BUFFER_DATA_BYTE_SIZE]; Buffer.BlockCopy(bufferDataBytes, 0, array, 33, BUFFER_DATA_BYTE_SIZE); Buffer.BlockCopy(data, 0, array, 33 + BUFFER_DATA_BYTE_SIZE, data.Length); SNetExt_ReplicatedPacket.InjectIDPacketIndex(this, array, base.Replicator.KeyHashBytes, base.KeyHashBytes); NetworkAPI.InvokeFreeSizedEvent("SNetExt_Replication", array, (IEnumerable)toPlayers, m_channelType); } public override void ReceiveBytes(byte[] bytes) { int num = 33 + BUFFER_DATA_BYTE_SIZE; int num2 = bytes.Length - num; if (num2 >= 0) { BufferData bufferData = GetBufferData(bytes); ReceiveAction(bytes.AsSpan(num, num2), bufferData); } } } public class SNetExt_ReplicatedPacketBytes : SNetExt_ReplicatedPacket { public delegate void SpanReceiveDelegate(ReadOnlySpan payload); private SNet_ChannelType m_channelType; public SNet_ChannelType ChannelType { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return m_channelType; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) m_channelType = value; } } private SpanReceiveDelegate ReceiveAction { get; set; } public static SNetExt_ReplicatedPacketBytes Create(string key, SpanReceiveDelegate receiveAction) { return new SNetExt_ReplicatedPacketBytes { Key = key, ReceiveAction = receiveAction }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(byte[] data) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[data.Length + 33]; Buffer.BlockCopy(data, 0, array, 33, data.Length); SNetExt_ReplicatedPacket.InjectIDPacketIndex(this, array, base.Replicator.KeyHashBytes, base.KeyHashBytes); NetworkAPI.InvokeFreeSizedEvent("SNetExt_Replication", array, m_channelType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(byte[] data, SNet_Player toPlayer) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[data.Length + 33]; Buffer.BlockCopy(data, 0, array, 33, data.Length); SNetExt_ReplicatedPacket.InjectIDPacketIndex(this, array, base.Replicator.KeyHashBytes, base.KeyHashBytes); NetworkAPI.InvokeFreeSizedEvent("SNetExt_Replication", array, toPlayer, m_channelType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Send(byte[] data, List toPlayers) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[data.Length + 33]; Buffer.BlockCopy(data, 0, array, 33, data.Length); SNetExt_ReplicatedPacket.InjectIDPacketIndex(this, array, base.Replicator.KeyHashBytes, base.KeyHashBytes); NetworkAPI.InvokeFreeSizedEvent("SNetExt_Replication", array, (IEnumerable)toPlayers, m_channelType); } public override void ReceiveBytes(byte[] bytes) { int num = bytes.Length - 33; if (num >= 0) { ReceiveAction?.Invoke(bytes.AsSpan(33, num)); } } } public class SNetExt_ReplicatedPlayerData where A : struct { public delegate bool delegateComparisonAction(A playerData, SNet_Player player, A comparisonData); private static SNetExt_ReplicatedPlayerData s_singleton; private SNetExt_Packet m_syncPacket; private Action m_onChangeCallback; public static void Setup(string eventName, Action callback) { if (s_singleton == null) { s_singleton = new SNetExt_ReplicatedPlayerData { m_syncPacket = SNetExt_Packet.Create(eventName, OnReceiveData, null, (SNet_ChannelType)0) }; } s_singleton.m_onChangeCallback = callback; } private static void OnReceiveData(SNet_Player sender, A wrappedData) { //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) pPlayer playerData = (wrappedData as ISNetExt_ReplicatedPlayerData).PlayerData; SNet_Player val = default(SNet_Player); if (((pPlayer)(ref playerData)).TryGetPlayer(ref val) && !val.IsLocal) { val.StoreCustomDataLocal(wrappedData); Utils.SafeInvoke>(s_singleton.m_onChangeCallback, new object[2] { val, wrappedData }); } } public static void SendData(SNet_Player player, A data, SNet_Player toPlayer = null) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((!((Object)(object)toPlayer != (Object)null) || !toPlayer.IsBot) && (player.IsLocal || SNet.IsMaster)) { pPlayer playerData = default(pPlayer); ((pPlayer)(ref playerData)).SetPlayer(player); ISNetExt_ReplicatedPlayerData obj = data as ISNetExt_ReplicatedPlayerData; obj.PlayerData = playerData; data = (A)obj; if ((Object)(object)toPlayer != (Object)null) { s_singleton.m_syncPacket.Send(data, toPlayer); } else { s_singleton.m_syncPacket.Send(data); } } } public static bool Compare(delegateComparisonAction comparisonAction, A comparisonValue, eComparisonGroup group, bool includeBots = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 List val; if ((int)group != 0) { if ((int)group != 1) { return false; } val = SNet.Slots.PlayersSynchedWithGame; } else { val = SNet.Slots.SlottedPlayers; } int count = val.Count; for (int i = 0; i < count; i++) { SNet_Player val2 = val[i]; if (includeBots || !val2.IsBot) { A playerData = val2.LoadCustomData(); if (!comparisonAction(playerData, val2, comparisonValue)) { return false; } } } return true; } } public class SNetExt_Replication : MonoBehaviour, ISNetExt_Manager { public const string NETWORK_EVENT_NAME = "SNetExt_Replication"; private static readonly IArchiveLogger _logger = LoaderWrapper.CreateArSubLoggerInstance("SNetExt_Replication", ConsoleColor.White); private static readonly SNetExt_ReplicatorRegistry s_registry = new SNetExt_ReplicatorRegistry(); private readonly List m_replicationManagers = new List(); internal static SNetExt_ReplicatorRegistry Registry => s_registry; [HideFromIl2Cpp] public List ReplicationManagers => m_replicationManagers; [HideFromIl2Cpp] public bool IsLastSenderMaster { get { SNet_Player val = ResolveLastSender(); if ((Object)(object)val != (Object)null) { return val.IsMaster; } return false; } } [HideFromIl2Cpp] public bool IsLastSenderInSessionHub { get { SNet_Player val = ResolveLastSender(); if ((Object)(object)val != (Object)null) { return val.IsInSessionHub; } return false; } } [HideFromIl2Cpp] public bool IsLastSenderInSlot { get { SNet_Player val = ResolveLastSender(); if ((Object)(object)val != (Object)null && val.IsInSessionHub) { return val.IsInSlot; } return false; } } [HideFromIl2Cpp] public ulong LastSenderID { get; private set; } public static event Action RecallStarted; public static event Action RecallFinished; [HideFromIl2Cpp] public void Setup() { NetworkAPI.RegisterFreeSizedEvent("SNetExt_Replication", (Action)ReceiveBytes); } [HideFromIl2Cpp] public void SetupReplication() { } [HideFromIl2Cpp] internal void OnRecall() { SNetExt_Replication.RecallStarted?.Invoke(); } [HideFromIl2Cpp] internal void OnPostRecall() { SNetExt_Replication.RecallFinished?.Invoke(); } [HideFromIl2Cpp] public void OnResetSession() { CleanupReplicators(); } [HideFromIl2Cpp] public void OnValidateMasterData() { if (m_replicationManagers != null) { for (int i = 0; i < m_replicationManagers.Count; i++) { m_replicationManagers[i].OnValidateMasterData(); } } } [HideFromIl2Cpp] internal void CleanupReplicators() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Invalid comparison between Unknown and I4 SNetExt.PrefabReplication.OnClearAllSpawnedLocal(); IReadOnlyList assigned = s_registry.Assigned; for (int num = assigned.Count - 1; num >= 0; num--) { ISNetExt_Replicator iSNetExt_Replicator = assigned[num]; if (iSNetExt_Replicator != null) { switch (iSNetExt_Replicator.Type) { case SNetExt_ReplicatorType.Dynamic: iSNetExt_Replicator.Despawn(); break; case SNetExt_ReplicatorType.SelfManaged: if (iSNetExt_Replicator is ISNetExt_MutableReplicator iSNetExt_MutableReplicator) { iSNetExt_MutableReplicator.AssignKey(string.Empty); } s_registry.Unregister(iSNetExt_Replicator); break; case SNetExt_ReplicatorType.VanillaWrapper: { SNetExt_Replicator_VanillaWrapper sNetExt_Replicator_VanillaWrapper = iSNetExt_Replicator as SNetExt_Replicator_VanillaWrapper; if ((int)sNetExt_Replicator_VanillaWrapper.VanillaType == 3) { sNetExt_Replicator_VanillaWrapper.Despawn(); } else if ((int)sNetExt_Replicator_VanillaWrapper.VanillaType == 2) { DeallocateVanillaWrapper(sNetExt_Replicator_VanillaWrapper); } break; } } } } } [HideFromIl2Cpp] public void RegisterReplicationManager(SNetExt_ReplicationManager manager) { m_replicationManagers.Add(manager); } [HideFromIl2Cpp] public void UnregisterReplicationManager(SNetExt_ReplicationManager manager) { m_replicationManagers.Remove(manager); } [HideFromIl2Cpp] public bool TryGetLastSender(out SNet_Player sender, bool allowCreate = false) { return SNet.Core.TryGetPlayer(LastSenderID, ref sender, allowCreate); } [HideFromIl2Cpp] internal SNet_Player ResolveLastSender() { SNet_Player result = default(SNet_Player); if (!SNet.Core.TryGetPlayer(LastSenderID, ref result, false)) { return null; } return result; } [HideFromIl2Cpp] internal void RecallBytes(byte[] bytes) { LastSenderID = 0uL; if (TryGetReplicator(bytes, out var replicator, out var packetKeyHash, out var packetIndex)) { ((ISNetExt_MutableReplicator)replicator).ReceiveBytes(in packetKeyHash, packetIndex, bytes); } } [HideFromIl2Cpp] private void ReceiveBytes(ulong senderId, byte[] bytes) { LastSenderID = senderId; if (bytes.Length >= 33 && TryGetReplicator(bytes, out var replicator, out var packetKeyHash, out var packetIndex)) { ((ISNetExt_MutableReplicator)replicator).ReceiveBytes(in packetKeyHash, packetIndex, bytes); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] [HideFromIl2Cpp] public static bool TryGetReplicatorByKeyHash(string keyHash, out ISNetExt_Replicator replicator) { SNetExt_KeyHash16 keyHash2 = SNetExt_KeyHash16.FromHex(keyHash); if (keyHash2.IsEmpty) { replicator = null; return false; } return s_registry.TryGet(in keyHash2, out replicator); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [HideFromIl2Cpp] internal static bool TryGetReplicatorByKeyHash16(in SNetExt_KeyHash16 keyHash, out ISNetExt_Replicator replicator) { return s_registry.TryGet(in keyHash, out replicator); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [HideFromIl2Cpp] public static bool TryGetReplicationSupplierByKeyHash(string keyHash, out A supplier) where A : class { if (TryGetReplicatorByKeyHash(keyHash, out var replicator) && replicator.ReplicatorSupplier != null) { supplier = replicator.ReplicatorSupplier as A; if (supplier != null) { return true; } } supplier = null; return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [HideFromIl2Cpp] public static bool TryGetReplicator(pReplicationData data, out ISNetExt_Replicator replicator) { return s_registry.TryGet(in data.ReplicatorKeyHash, out replicator); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [HideFromIl2Cpp] private static bool TryGetReplicator(byte[] bytes, out ISNetExt_Replicator replicator, out SNetExt_KeyHash16 packetKeyHash, out byte packetIndex) { SNetExt_KeyHash16 keyHash = SNetExt_KeyHash16.FromSpan(bytes.AsSpan(0, 16)); if (!s_registry.TryGet(in keyHash, out replicator)) { packetKeyHash = default(SNetExt_KeyHash16); packetIndex = byte.MaxValue; return false; } packetKeyHash = SNetExt_KeyHash16.FromSpan(bytes.AsSpan(16, 16)); packetIndex = bytes[32]; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [HideFromIl2Cpp] public static byte[] ReplicatorKeyHashToBytes(string keyHash) { return SNetExt_HashUtil.HashHexToBytes(keyHash); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [HideFromIl2Cpp] public static string ReplicatorKeyToHash(string key) { return SNetExt_HashUtil.KeyToHashHex(key); } [HideFromIl2Cpp] internal static void AllocateReplicator(ISNetExt_MutableReplicator replicator) { switch (s_registry.Register(replicator)) { case SNetExt_ReplicatorRegistry.RegisterStatus.InvalidKeyHash: _logger.Error("AllocateReplicator, Invalid KeyHash. Hash: '" + replicator.KeyHash + "'"); throw new InvalidOperationException("Replicator has invalid KeyHash '" + replicator.KeyHash + "'"); case SNetExt_ReplicatorRegistry.RegisterStatus.Conflict: { SNetExt_ReplicatorRegistry sNetExt_ReplicatorRegistry = s_registry; SNetExt_KeyHash16 keyHash = SNetExt_KeyHash16.FromHex(replicator.KeyHash); sNetExt_ReplicatorRegistry.TryGet(in keyHash, out var r); _logger.Error($"AllocateReplicator, KeyHash conflict. Existing Key: '{r?.Key}', New Key: '{replicator.Key}', KeyHash: '{replicator.KeyHash}'"); throw new InvalidOperationException("Replicator with KeyHash '" + replicator.KeyHash + "' already exists"); } } } [HideFromIl2Cpp] internal static void AssignReplicatorKey(ISNetExt_MutableReplicator replicator, string keyHash, bool isRecall = false) { SNetExt_KeyHash16 newHash = SNetExt_KeyHash16.FromHex(keyHash); if (newHash.IsEmpty) { _logger.Error("AssignReplicatorKey, Invalid KeyHash. Hash: '" + keyHash + "'"); } else if (s_registry.Reassign(replicator, in newHash) == SNetExt_ReplicatorRegistry.RegisterStatus.Conflict) { _logger.Error("AssignReplicatorKey, KeyHash conflict on '" + keyHash + "'"); throw new InvalidOperationException("Cannot reassign to KeyHash '" + keyHash + "': occupied"); } } [HideFromIl2Cpp] internal static void DeallocateReplicator(ISNetExt_Replicator replicator) { s_registry.Unregister(replicator); if (replicator is ISNetExt_MutableReplicator iSNetExt_MutableReplicator) { iSNetExt_MutableReplicator.AssignKey(string.Empty); } } [HideFromIl2Cpp] public static ISNetExt_Replicator AddManagerReplicator(string key) { SNetExt_Replicator_Manager sNetExt_Replicator_Manager = new SNetExt_Replicator_Manager(); ((ISNetExt_MutableReplicator)sNetExt_Replicator_Manager).AssignKey(key); AllocateReplicator(sNetExt_Replicator_Manager); return sNetExt_Replicator_Manager; } [HideFromIl2Cpp] public static ISNetExt_Replicator AddManagerReplicator(ISNetExt_ReplicatorSupplier supplier) { SNetExt_Replicator_Manager obj = new SNetExt_Replicator_Manager { ReplicatorSupplier = supplier }; AllocateReplicator(obj); return obj; } [HideFromIl2Cpp] public static ISNetExt_Replicator AddSelfManagedReplicator(string key) { SNetExt_Replicator_SelfManaged sNetExt_Replicator_SelfManaged = new SNetExt_Replicator_SelfManaged(); ((ISNetExt_MutableReplicator)sNetExt_Replicator_SelfManaged).AssignKey(key); AllocateReplicator(sNetExt_Replicator_SelfManaged); return sNetExt_Replicator_SelfManaged; } [HideFromIl2Cpp] public static ISNetExt_Replicator AddSelfManagedReplicator(ISNetExt_ReplicatorSupplier supplier) { SNetExt_Replicator_SelfManaged obj = new SNetExt_Replicator_SelfManaged { ReplicatorSupplier = supplier }; AllocateReplicator(obj); return obj; } [HideFromIl2Cpp] internal static bool TryBindVanillaWrapper(IReplicator vanilla) { if (vanilla == null || vanilla.Key == 0) { return false; } if (s_registry.TryGetByVanilla(((Il2CppObjectBase)vanilla).Pointer, out var w) && w != null && w.IsAlive) { return true; } return BindVanillaInternal(vanilla) != null; } [HideFromIl2Cpp] private static SNetExt_Replicator_VanillaWrapper BindVanillaInternal(IReplicator vanilla) { SNetExt_Replicator_VanillaWrapper sNetExt_Replicator_VanillaWrapper = new SNetExt_Replicator_VanillaWrapper(vanilla); if (!sNetExt_Replicator_VanillaWrapper.HasValidKeyHash) { _logger.Error($"BindVanillaInternal: invalid keyhash for vanilla.Key={vanilla.Key}"); return null; } SNetExt_ReplicatorRegistry.RegisterStatus registerStatus = s_registry.RegisterVanilla(sNetExt_Replicator_VanillaWrapper); if (registerStatus != 0) { _logger.Error($"BindVanillaInternal: failed to register wrapper, status={registerStatus}"); return null; } return sNetExt_Replicator_VanillaWrapper; } [HideFromIl2Cpp] internal static bool TryGetVanillaWrapper(IReplicator vanilla, out SNetExt_Replicator_VanillaWrapper wrapper) { return s_registry.TryGetByVanilla(((Il2CppObjectBase)vanilla).Pointer, out wrapper); } [HideFromIl2Cpp] internal static void DeallocateVanillaWrapper(SNetExt_Replicator_VanillaWrapper wrapper) { if (!s_registry.UnregisterVanilla(wrapper)) { _logger.Error($"DeallocateVanillaWrapper: Wrapper doesn't exist for Vanilla.Pointer={((Il2CppObjectBase)wrapper.Vanilla).Pointer}"); } } } public abstract class SNetExt_ReplicationManager : ISNetExt_ReplicatorSupplier { public ISNetExt_Replicator Replicator { get; set; } public GameObject gameObject { get; set; } public virtual string Key => GetType().FullName; public abstract void OnStateCapture(); public abstract void ClearAllLocal(); public abstract void OnValidateMasterData(); } public abstract class SNetExt_ReplicationManager : SNetExt_ReplicationManager where T : struct, ISNetExt_DynamicReplication { public override string Key => "SNetExt_ReplicationManager<" + typeof(T).FullName + ">"; public virtual void DeSpawn(SNetExt_DynamicReplicator replicator) { } } public class SNetExt_ReplicationManager : SNetExt_ReplicationManager where T : struct, ISNetExt_DynamicReplication where R : SNetExt_DynamicReplicator, new() { protected IArchiveLogger _logger; public List m_replicators = new List(); private SNet_ChannelType m_channelType; protected R m_preSpawnedReplicator; protected R m_internalSpawnCallbackReturnReplicator; protected SNetExt_ReplicatedPacket m_spawnPacket; protected SNetExt_ReplicatedPacket m_spawnRequestPacket; protected SNetExt_ReplicatedPacket m_despawnPacket; protected Dictionary m_prefabs = new Dictionary(16); protected Dictionary m_prefabKeyToKeyHash = new Dictionary(16); protected Dictionary m_prefabKeyHashToKey = new Dictionary(16); protected Dictionary m_prefabLookup = new Dictionary(16); protected bool m_hasSpawnDespawnCallback; protected Action m_spawnDespawnCallback; protected Vector3 m_tempPosition; protected Quaternion m_tempQuaternion; public override string Key => $"SNetExt_ReplicationManager<{typeof(T).FullName}, {typeof(R).FullName}>"; public Action SpawnDespawnCallback { set { m_spawnDespawnCallback = value; m_hasSpawnDespawnCallback = value != null; } } public SNetExt_ReplicationManager(SNet_ChannelType channelType = 2) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) _logger = LoaderWrapper.CreateArSubLoggerInstance(GetType().Name, ConsoleColor.White); m_channelType = channelType; m_spawnPacket = SNetExt.SubManagerReplicator.CreatePacket(typeof(T).FullName, InternalSpawnCallback); m_spawnRequestPacket = SNetExt.SubManagerReplicator.CreatePacket(typeof(T).FullName, InternalSpawnRequestFromSlaveCallback); m_despawnPacket = SNetExt.SubManagerReplicator.CreatePacket(typeof(T).FullName + "_despawn", InternalDeSpawnCallback_Slave); SNetExt.Replication.RegisterReplicationManager(this); } public void AddPrefab(string key, GameObject prefab, GameObject prefabSyncVersion = null) { SNetExt_KeyHash16 sNetExt_KeyHash = PrefabKeyToHash(key); if (m_prefabs.ContainsKey(sNetExt_KeyHash)) { _logger.Error($"AddPrefab, Hash Conflict. Key: '{key}', KeyHash: '{sNetExt_KeyHash}'"); } else { m_prefabLookup.Add(((Il2CppObjectBase)prefab).Pointer, sNetExt_KeyHash); m_prefabs.Add(sNetExt_KeyHash, (prefab, prefabSyncVersion)); m_prefabKeyToKeyHash.Add(key, sNetExt_KeyHash); m_prefabKeyHashToKey.Add(sNetExt_KeyHash, key); } } public void ClearPrefabs() { m_prefabLookup.Clear(); m_prefabs.Clear(); m_prefabKeyToKeyHash.Clear(); m_prefabKeyHashToKey.Clear(); } public bool RemovePrefab(string key) { SNetExt_KeyHash16 key2 = PrefabKeyToHash(key); if (!m_prefabs.TryGetValue(key2, out (GameObject, GameObject) value)) { return false; } if ((Object)(object)value.Item1 != (Object)null) { m_prefabLookup.Remove(((Il2CppObjectBase)value.Item1).Pointer); } m_prefabs.Remove(key2); m_prefabKeyToKeyHash.Remove(key); m_prefabKeyHashToKey.Remove(key2); return true; } public bool RemovePrefab(GameObject prefab) { if (!TryGetPrefabKey(prefab, out var key, out var _)) { return false; } return RemovePrefab(key); } public bool TryGetPrefabKey(GameObject prefab, out string key, out SNetExt_KeyHash16 keyHash) { if (!m_prefabLookup.TryGetValue(((Il2CppObjectBase)prefab).Pointer, out keyHash) || !m_prefabKeyHashToKey.TryGetValue(keyHash, out key)) { key = string.Empty; keyHash = default(SNetExt_KeyHash16); return false; } return true; } public bool HasPrefab(GameObject prefab) { return m_prefabLookup.ContainsKey(((Il2CppObjectBase)prefab).Pointer); } public void Spawn(GameObject prefab, T spawnData) { if (!TryGetPrefabKey(prefab, out var _, out var keyHash)) { _logger.Error("Spawn, prefabKey for '" + ((Object)prefab).name + "' add prefab before attempting spawn"); } else { Spawn(keyHash, spawnData); } } public void Spawn(SNetExt_KeyHash16 prefabKeyHash, T spawnData) { pReplicationData replicationData = spawnData.ReplicationData; replicationData.PrefabKeyHash = prefabKeyHash; spawnData.ReplicationData = replicationData; Spawn(spawnData); } public void InjectOfflinePrespawn(T spawnData, R preSpawnReplicator) { m_preSpawnedReplicator = preSpawnReplicator; InternalSpawnCallback(spawnData); m_preSpawnedReplicator = null; } public void Spawn(T spawnData) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (SNet.IsMaster) { InternalSpawnCallback(spawnData); } else if (SNet.HasMaster) { m_spawnRequestPacket.Send(spawnData, m_channelType, SNet.Master); } } private void InternalSpawnRequestFromSlaveCallback(T spawnData) { if (SNet.IsMaster) { if (OnSpawnRequest(spawnData)) { InternalSpawnCallback(spawnData); } else { OnSpawnRequestRejected(spawnData); } } } protected virtual bool OnSpawnRequest(T spawnData) { return true; } protected virtual void OnSpawnRequestRejected(T spawnData) { } protected virtual void InternalSpawnCallback(T spawnData) { //IL_016f: Unknown result type (might be due to invalid IL or missing references) if (!SNet.IsMaster && m_preSpawnedReplicator == null && !SNetExt.Replication.IsLastSenderMaster && !SNet.MasterManagement.IsMigrating) { _logger.Warning($"Rejected spawn packet from non-master sender (id={SNetExt.Replication.LastSenderID})"); m_internalSpawnCallbackReturnReplicator = null; return; } pReplicationData replicationData = spawnData.ReplicationData; R replicator = null; GameObject go = null; bool num = m_preSpawnedReplicator != null; if (num) { replicator = m_preSpawnedReplicator; go = replicator.ReplicatorSupplier.gameObject; } if (num || TryGetGameObjectReplicator(spawnData, out replicator, out go)) { if (SNet.IsMaster && !spawnData.ReplicationData.isRecall) { ISNetExt_DynamicReplicatorSupplier iSNetExt_DynamicReplicatorSupplier = LinkSupplier(replicator, go); if (iSNetExt_DynamicReplicatorSupplier == null) { if ((Object)(object)go != (Object)null) { Object.Destroy((Object)(object)go); } m_internalSpawnCallbackReturnReplicator = null; return; } SNetExt_Replication.AllocateReplicator(replicator); replicationData.ReplicatorKeyHash = SNetExt_KeyHash16.FromHex(replicator.KeyHash); spawnData.ReplicationData = replicationData; replicator.SetSpawnData(spawnData); RegisterDynamicReplicator(replicator); iSNetExt_DynamicReplicatorSupplier.OnSpawn(spawnData); m_spawnPacket.Send(spawnData, m_channelType); } else { ISNetExt_DynamicReplicatorSupplier iSNetExt_DynamicReplicatorSupplier2 = LinkSupplier(replicator, go); if (iSNetExt_DynamicReplicatorSupplier2 == null) { if ((Object)(object)go != (Object)null) { Object.Destroy((Object)(object)go); } m_internalSpawnCallbackReturnReplicator = null; return; } SNetExt_Replication.AssignReplicatorKey(replicator, replicationData.ReplicatorKeyHash.ToHex(), spawnData.ReplicationData.isRecall); replicator.SetSpawnData(spawnData); RegisterDynamicReplicator(replicator); iSNetExt_DynamicReplicatorSupplier2.OnSpawn(spawnData); } OnSpawn(spawnData, replicator); m_internalSpawnCallbackReturnReplicator = replicator; } else { _logger.Error($"InternalSpawnCallback, Prefab not found {replicationData.PrefabKeyHash}"); m_internalSpawnCallbackReturnReplicator = null; } } private ISNetExt_DynamicReplicatorSupplier LinkSupplier(R replicator, GameObject go) { SNetExt_ReplicatorSupplierWrapper component = go.GetComponent(); if ((Object)(object)component == (Object)null || !(component.ReplicatorSupplier is ISNetExt_DynamicReplicatorSupplier iSNetExt_DynamicReplicatorSupplier)) { _logger.Error($"LinkSupplier failed on '{((Object)go).name}': wrapper={(Object)(object)component != (Object)null}, supplier type={component?.ReplicatorSupplier?.GetType().Name ?? ""}"); return null; } replicator.ReplicatorSupplier = iSNetExt_DynamicReplicatorSupplier; iSNetExt_DynamicReplicatorSupplier.Replicator = replicator; return iSNetExt_DynamicReplicatorSupplier; } public override void DeSpawn(SNetExt_DynamicReplicator incomingReplicator) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (incomingReplicator != null) { R val = (R)incomingReplicator; if (SNet.IsMaster) { T spawnData = val.GetSpawnData(); m_despawnPacket.Send(spawnData.ReplicationData, m_channelType); } OnDeSpawn(val); UnregisterDynamicReplicator(val); } } public override void ClearAllLocal() { for (int num = m_replicators.Count - 1; num > -1; num--) { R val = m_replicators[num]; if (val != null) { OnDeSpawn(val); UnregisterDynamicReplicator(val); } } m_replicators.Clear(); } private void InternalDeSpawnCallback_Slave(pReplicationData despawnData) { ISNetExt_Replicator replicator; if (!SNetExt.Replication.IsLastSenderMaster && !SNet.MasterManagement.IsMigrating) { _logger.Warning($"Rejected despawn packet from non-master sender (id={SNetExt.Replication.LastSenderID})"); } else if (SNetExt_Replication.TryGetReplicator(despawnData, out replicator)) { OnDeSpawn(replicator as R); UnregisterDynamicReplicator(replicator as R); } } public virtual bool UseSyncPrefab(T spawnData) { return false; } protected virtual R CreateReplicator(T spawnData, GameObject go) { return new R(); } public virtual void SetOwnership(T spawnData, R replicator) { ((ISNetExt_OwnedReplicator)replicator).OwnedByMaster = true; } protected bool TryGetGameObjectReplicator(T spawnData, out R replicator, out GameObject go) { if (!TryGetInstanceReplicator(spawnData, out replicator, out go)) { return false; } SetOwnership(spawnData, replicator); return true; } protected virtual bool TryGetInstanceReplicator(T spawnData, out R replicator, out GameObject go) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) pReplicationData replicationData = spawnData.ReplicationData; if (!m_prefabs.ContainsKey(replicationData.PrefabKeyHash)) { replicator = null; go = null; return false; } GameObject val = ((!UseSyncPrefab(spawnData)) ? m_prefabs[replicationData.PrefabKeyHash].local : m_prefabs[replicationData.PrefabKeyHash].sync); go = Object.Instantiate(val, spawnData.Position, spawnData.Rotation); replicator = CreateReplicator(spawnData, go); return true; } private void RegisterDynamicReplicator(R replicator) { replicator.SetManager(this); m_replicators.Add(replicator); } private void UnregisterDynamicReplicator(R replicator) { replicator.SetManager(null); m_replicators.Remove(replicator); SNetExt_Replication.DeallocateReplicator(replicator); } protected virtual void OnSpawn(T spawnData, R replicator) { if (m_hasSpawnDespawnCallback) { m_spawnDespawnCallback(replicator, arg2: true); } } protected virtual void OnDeSpawn(R replicator) { if (m_hasSpawnDespawnCallback) { m_spawnDespawnCallback(replicator, arg2: false); } if (replicator.ReplicatorSupplier != null) { (replicator.ReplicatorSupplier as ISNetExt_DynamicReplicatorSupplier)?.OnDespawn(); replicator.ReplicatorSupplier = null; } } public override void OnStateCapture() { for (int i = 0; i < m_replicators.Count; i++) { if (m_replicators[i].TryInternalCollectCapture(out var spawnData, out var captureType)) { m_spawnPacket.CaptureToBuffer(spawnData, captureType); } } } public override void OnValidateMasterData() { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] PrefabKeyHashToBytes(string keyHash) { return SNetExt_HashUtil.HashHexToBytes(keyHash); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static SNetExt_KeyHash16 PrefabKeyToHash(string key) { return SNetExt_KeyHash16.FromHex(SNetExt_HashUtil.KeyToHashHex(key)); } } public abstract class SNetExt_Replicator : ISNetExt_MutableReplicator, ISNetExt_Replicator { private string m_key = string.Empty; private string m_keyHash = string.Empty; private readonly byte[] m_keyHashBytes = new byte[16]; private ISNetExt_ReplicatorSupplier m_supplier; private SNet_Player m_owningPlayer; private bool m_ownedByMaster; protected readonly Dictionary> m_packetsByKeyHash = new Dictionary>(); private static readonly IArchiveLogger _logger = LoaderWrapper.CreateArSubLoggerInstance("SNetExt_Replicator", ConsoleColor.White); public ISNetExt_ReplicatorSupplier ReplicatorSupplier { get { return m_supplier; } set { m_supplier = value; if (m_supplier != null) { AssignKeyCore(m_supplier.Key); } } } public string Key => m_key; public string KeyHash => m_keyHash; public ReadOnlySpan KeyHashBytes => m_keyHashBytes; public bool IsAnonymous => string.IsNullOrWhiteSpace(m_key); public bool HasValidKeyHash { get { if (!string.IsNullOrWhiteSpace(m_keyHash)) { return m_keyHash.Length == 32; } return false; } } public virtual SNetExt_ReplicatorType Type => SNetExt_ReplicatorType.Unspecified; public virtual SNet_Player OwningPlayer => m_owningPlayer; public virtual bool OwnedByMaster => m_ownedByMaster; public abstract bool LocallyOwned { get; } void ISNetExt_MutableReplicator.AssignKey(string key) { AssignKeyCore(key); } void ISNetExt_MutableReplicator.AssignKeyHash(in SNetExt_KeyHash16 keyHash) { AssignKeyHashCore(in keyHash); } void ISNetExt_MutableReplicator.ReceiveBytes(in SNetExt_KeyHash16 packetKeyHash, byte packetIndex, byte[] bytes) { if (m_packetsByKeyHash.TryGetValue(packetKeyHash, out var value) && packetIndex < value.Count) { value[packetIndex].ReceiveBytes(bytes); } } protected void AssignKeyCore(string key) { m_key = key ?? string.Empty; SNetExt_KeyHash16 keyHash; if (string.IsNullOrWhiteSpace(m_key)) { keyHash = default(SNetExt_KeyHash16); AssignKeyHashCore(in keyHash); return; } Span span = stackalloc byte[16]; SNetExt_HashUtil.KeyToHashBytes(m_key, span); keyHash = SNetExt_KeyHash16.FromSpan(span); AssignKeyHashCore(in keyHash); } protected void AssignKeyHashCore(in SNetExt_KeyHash16 keyHash) { if (keyHash.IsEmpty) { m_keyHash = string.Empty; Array.Clear(m_keyHashBytes, 0, 16); } else { m_keyHash = keyHash.ToHex(); keyHash.WriteTo(m_keyHashBytes); } } protected void SetOwningPlayerInternal(SNet_Player player) { m_owningPlayer = player; } protected void SetOwnedByMasterInternal(bool value) { m_ownedByMaster = value; } public void AddPacket(SNetExt_ReplicatedPacket packet) { if (!packet.HasValidKeyHash) { _logger.Error("AddPacket, Invalid KeyHash."); return; } SNetExt_KeyHash16 key = SNetExt_KeyHash16.FromHex(packet.KeyHash); if (!m_packetsByKeyHash.TryGetValue(key, out var value)) { value = new List(); m_packetsByKeyHash.Add(key, value); } if (value.Count > 255) { _logger.Error("AddPacket, more than 256 packets share the same KeyHash '" + packet.KeyHash + "'; rejecting."); return; } packet.Setup(this, (byte)value.Count); value.Add(packet); } public SNetExt_ReplicatedPacket CreatePacket(string key, Action receiveAction, Action validateAction = null) where T : struct { SNetExt_ReplicatedPacket sNetExt_ReplicatedPacket = SNetExt_ReplicatedPacket.Create(key, receiveAction, validateAction); AddPacket(sNetExt_ReplicatedPacket); return sNetExt_ReplicatedPacket; } public SNetExt_ReplicatedPacketBufferBytes CreatePacketBufferBytes(string key, SNetExt_ReplicatedPacketBufferBytes.SpanBufferReceiveDelegate receiveAction) { SNetExt_ReplicatedPacketBufferBytes sNetExt_ReplicatedPacketBufferBytes = SNetExt_ReplicatedPacketBufferBytes.Create(key, receiveAction); AddPacket(sNetExt_ReplicatedPacketBufferBytes); return sNetExt_ReplicatedPacketBufferBytes; } public SNetExt_ReplicatedPacketBytes CreatePacketBytes(string key, SNetExt_ReplicatedPacketBytes.SpanReceiveDelegate receiveAction) { SNetExt_ReplicatedPacketBytes sNetExt_ReplicatedPacketBytes = SNetExt_ReplicatedPacketBytes.Create(key, receiveAction); AddPacket(sNetExt_ReplicatedPacketBytes); return sNetExt_ReplicatedPacketBytes; } public abstract void Despawn(); public Type GetPacketType(string key, int packetIndex) { SNetExt_KeyHash16 key2 = SNetExt_KeyHash16.FromHex(key); if (m_packetsByKeyHash.TryGetValue(key2, out var value) && packetIndex >= 0 && packetIndex < value.Count) { return value[packetIndex].GetType(); } return null; } } public class SNetExt_Replicator_Manager : SNetExt_Replicator { public override SNetExt_ReplicatorType Type => SNetExt_ReplicatorType.Manager; public override bool LocallyOwned => true; public override void Despawn() { SNetExt.Logger.Warning($"Despawn called on Manager replicator '{base.Key}' (KeyHash={base.KeyHash}); ignored."); } } public class SNetExt_Replicator_SelfManaged : SNetExt_Replicator, ISNetExt_OwnedReplicator, ISNetExt_MutableReplicator, ISNetExt_Replicator { public override SNetExt_ReplicatorType Type => SNetExt_ReplicatorType.SelfManaged; public override bool LocallyOwned => true; SNet_Player ISNetExt_OwnedReplicator.OwningPlayer { get { return OwningPlayer; } set { SetOwningPlayerInternal(value); } } bool ISNetExt_OwnedReplicator.OwnedByMaster { get { return OwnedByMaster; } set { SetOwnedByMasterInternal(value); } } public override void Despawn() { SNetExt_Replication.DeallocateReplicator(this); base.ReplicatorSupplier = null; } } public sealed class SNetExt_Replicator_VanillaWrapper : SNetExt_Replicator { private static readonly IArchiveLogger _logger = LoaderWrapper.CreateArSubLoggerInstance("SNetExt_Replicator_VanillaWrapper", ConsoleColor.White); private IReplicator m_vanillaInterface; private SNet_Replicator m_vanilla; public IReplicator Vanilla => m_vanillaInterface; public bool IsAlive => m_vanillaInterface != null; public SNet_ReplicatorType VanillaType => m_vanillaInterface.Type; public override SNetExt_ReplicatorType Type => SNetExt_ReplicatorType.VanillaWrapper; public override SNet_Player OwningPlayer { get { IReplicator vanillaInterface = m_vanillaInterface; if (vanillaInterface == null) { return null; } return vanillaInterface.OwningPlayer; } } public override bool OwnedByMaster { get { if (m_vanilla != null) { return m_vanilla.OwnedByMaster; } return false; } } public override bool LocallyOwned { get { if (m_vanillaInterface != null) { return m_vanillaInterface.LocallyOwned; } return false; } } internal SNetExt_Replicator_VanillaWrapper(IReplicator vanilla) { m_vanillaInterface = vanilla ?? throw new ArgumentNullException("vanilla"); m_vanilla = ((Il2CppObjectBase)vanilla).Cast(); ((ISNetExt_MutableReplicator)this).AssignKey($"VanillaWrapper_{m_vanilla.Key}"); } public override void Despawn() { SNetExt_Replication.DeallocateVanillaWrapper(this); } } public class SNetExt_StateReplicator : ISNetExt_StateReplicator, ICaptureCallbackObject, ISNetExt_ReplicatorSupplier where S : struct { internal ISNetExt_StateReplicatorProvider m_provider; private SNet_ChannelType m_channelType; private SNetExt_ReplicatedPacket m_statePacket; private SNetExt_ReplicatedPacket m_statePacket_Dropin; private S m_currentState; public string Key => "SNetExt_StateReplicator<" + typeof(S).FullName + ">"; public GameObject gameObject => m_provider.gameObject; public ISNetExt_Replicator Replicator { get; set; } public bool PersistAcrossSession { get { ISNetExt_Replicator replicator = Replicator; if (replicator == null) { return false; } return replicator.Type == SNetExt_ReplicatorType.Manager; } } public S State { get { return m_currentState; } set { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (SNet.IsMaster) { m_statePacket.Send(value, m_channelType); OnStateChange(value, isRecall: false); } } } public static SNetExt_StateReplicator Create(ISNetExt_StateReplicatorProvider provider, SNetExt_ReplicatorLifeTime replictorLifeTime, S startingState = default(S), SNet_ChannelType channelType = 2) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) SNetExt_StateReplicator sNetExt_StateReplicator = new SNetExt_StateReplicator { m_provider = provider }; switch (replictorLifeTime) { case SNetExt_ReplicatorLifeTime.NeverDestroyed: sNetExt_StateReplicator.Replicator = SNetExt_Replication.AddManagerReplicator(sNetExt_StateReplicator); break; case SNetExt_ReplicatorLifeTime.DestroyedOnLevelReset: sNetExt_StateReplicator.Replicator = SNetExt_Replication.AddSelfManagedReplicator(sNetExt_StateReplicator); break; default: SNetExt.Logger.Error($"SNetExt_StateReplicator does not support {replictorLifeTime}"); return null; } sNetExt_StateReplicator.m_channelType = channelType; sNetExt_StateReplicator.m_statePacket = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(S).FullName, sNetExt_StateReplicator.OnStateChangeReceive); sNetExt_StateReplicator.m_statePacket_Dropin = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(S).FullName, sNetExt_StateReplicator.OnStateChangeReceive_Dropin); sNetExt_StateReplicator.m_currentState = startingState; SNetExt_Capture.RegisterCaptureCallback(sNetExt_StateReplicator); return sNetExt_StateReplicator; } public static SNetExt_StateReplicator Create(GameObject holder, Action, S, S, bool> onStateChange, S startingState = default(S), SNet_ChannelType channelType = 2) { //IL_002f: 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) ClassInjector.RegisterTypeInIl2Cpp>(false); SNetExt_StateReplicatorProviderWrapper sNetExt_StateReplicatorProviderWrapper = holder.AddComponent>(); SNetExt_StateReplicator sNetExt_StateReplicator = new SNetExt_StateReplicator { m_provider = sNetExt_StateReplicatorProviderWrapper }; sNetExt_StateReplicatorProviderWrapper.Setup(sNetExt_StateReplicator, onStateChange); sNetExt_StateReplicator.Replicator = SNetExt_Replication.AddSelfManagedReplicator(sNetExt_StateReplicator); sNetExt_StateReplicator.m_channelType = channelType; sNetExt_StateReplicator.m_statePacket = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(S).FullName, sNetExt_StateReplicator.OnStateChangeReceive); sNetExt_StateReplicator.m_statePacket_Dropin = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(S).FullName, sNetExt_StateReplicator.OnStateChangeReceive_Dropin); sNetExt_StateReplicator.m_currentState = startingState; SNetExt_Capture.RegisterCaptureCallback(sNetExt_StateReplicator); return sNetExt_StateReplicator; } public pStateReplicatorProvider GetProviderSyncStruct() { pStateReplicatorProvider result = default(pStateReplicatorProvider); result.Set(this); return result; } public void SetStateUnsynced(S state) { m_currentState = state; } private void OnStateChangeReceive(S state) { if (SNetExt.Replication.IsLastSenderMaster) { OnStateChange(state, isRecall: false); } } private void OnStateChangeReceive_Dropin(S state) { if (!SNetExt.Replication.IsLastSenderMaster && !SNet.MasterManagement.IsMigrating) { SNetExt.Logger.Warning("Rejected dropin state packet from non-master sender"); } else { OnStateChange(state, isRecall: true); } } private void OnStateChange(S newState, bool isRecall) { m_provider.OnStateChange(m_currentState, newState, isRecall); m_currentState = newState; } public void OnStateChange_Master(S newState) { if (SNet.IsMaster) { OnStateChange(newState, isRecall: false); } } public void OnStateCapture() { m_statePacket_Dropin.CaptureToBuffer(m_currentState, SNetExt_CapturePass.FirstPass); } } public class SNetExt_StateReplicator : ISNetExt_StateReplicator, ICaptureCallbackObject, ISNetExt_ReplicatorSupplier where S : struct where I : struct { internal ISNetExt_StateReplicatorProvider m_provider; private SNet_ChannelType m_channelType; private SNetExt_ReplicatedPacket m_statePacket; private SNetExt_ReplicatedPacket m_statePacket_Recall; private SNetExt_ReplicatedPacket m_interactionPacket; private S m_currentState; public SNetExt_CapturePass CapturePass = SNetExt_CapturePass.FirstPass; public GameObject gameObject => m_provider.gameObject; public string Key => $"SNetExt_StateReplicator<{typeof(S).FullName}, {typeof(I).FullName}>"; public ISNetExt_Replicator Replicator { get; set; } public bool PersistAcrossSession { get { ISNetExt_Replicator replicator = Replicator; if (replicator == null) { return false; } return replicator.Type == SNetExt_ReplicatorType.Manager; } } public S State { get { return m_currentState; } private set { OnStateChange(isRecall: false, value); } } public static SNetExt_StateReplicator Create(ISNetExt_StateReplicatorProvider provider, SNetExt_ReplicatorLifeTime replictorLifeTime, S startingState = default(S), SNet_ChannelType channelType = 2) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) SNetExt_StateReplicator sNetExt_StateReplicator = new SNetExt_StateReplicator { m_provider = provider }; switch (replictorLifeTime) { case SNetExt_ReplicatorLifeTime.NeverDestroyed: sNetExt_StateReplicator.Replicator = SNetExt_Replication.AddManagerReplicator(sNetExt_StateReplicator); break; case SNetExt_ReplicatorLifeTime.DestroyedOnLevelReset: sNetExt_StateReplicator.Replicator = SNetExt_Replication.AddSelfManagedReplicator(sNetExt_StateReplicator); break; default: SNetExt.Logger.Error($"SNetExt_StateReplicator does not support {replictorLifeTime}"); return null; } sNetExt_StateReplicator.m_channelType = channelType; sNetExt_StateReplicator.m_statePacket = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(S).FullName, sNetExt_StateReplicator.OnStateChangeReceive); sNetExt_StateReplicator.m_statePacket_Recall = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(S).FullName, sNetExt_StateReplicator.OnStateChangeReceive_Recall); sNetExt_StateReplicator.m_interactionPacket = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(I).FullName, sNetExt_StateReplicator.AttemptInteract); sNetExt_StateReplicator.m_currentState = startingState; SNetExt_Capture.RegisterCaptureCallback(sNetExt_StateReplicator); return sNetExt_StateReplicator; } public static SNetExt_StateReplicator Create(GameObject holder, Action, S, S, bool> onStateChange, Action, I> attemptInteract, S startingState = default(S), SNet_ChannelType channelType = 2) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) ClassInjector.RegisterTypeInIl2Cpp>(false); SNetExt_StateReplicatorProviderWrapper sNetExt_StateReplicatorProviderWrapper = holder.AddComponent>(); SNetExt_StateReplicator sNetExt_StateReplicator = new SNetExt_StateReplicator { m_provider = sNetExt_StateReplicatorProviderWrapper }; sNetExt_StateReplicatorProviderWrapper.Setup(sNetExt_StateReplicator, onStateChange, attemptInteract); sNetExt_StateReplicator.Replicator = SNetExt_Replication.AddSelfManagedReplicator(sNetExt_StateReplicator); sNetExt_StateReplicator.m_channelType = channelType; sNetExt_StateReplicator.m_statePacket = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(S).FullName, sNetExt_StateReplicator.OnStateChangeReceive); sNetExt_StateReplicator.m_statePacket_Recall = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(S).FullName, sNetExt_StateReplicator.OnStateChangeReceive_Recall); sNetExt_StateReplicator.m_interactionPacket = sNetExt_StateReplicator.Replicator.CreatePacket(typeof(I).FullName, sNetExt_StateReplicator.AttemptInteract); sNetExt_StateReplicator.m_currentState = startingState; SNetExt_Capture.RegisterCaptureCallback(sNetExt_StateReplicator); return sNetExt_StateReplicator; } public pStateReplicatorProvider GetProviderSyncStruct() { pStateReplicatorProvider result = default(pStateReplicatorProvider); result.Set(this); return result; } private void AttemptInteract(I interaction) { if (SNetExt.Replication.IsLastSenderInSessionHub) { m_provider.AttemptInteract(interaction); } } public void InteractWithState(I interaction) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (SNet.IsMaster) { m_provider.AttemptInteract(interaction); } else if (SNet.HasMaster) { m_interactionPacket.Send(interaction, m_channelType, SNet.Master); } } public void SetStateUnsynced(S state) { m_currentState = state; } private void OnStateChangeReceive(S state) { if (SNetExt.Replication.IsLastSenderMaster) { OnStateChange(isRecall: false, state); } } private void OnStateChangeReceive_Recall(S state) { OnStateChange(isRecall: true, state); } public void OnStateChange(bool isRecall, S newState) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!isRecall && SNet.IsMaster) { m_statePacket.Send(newState, m_channelType); } S currentState = m_currentState; m_currentState = newState; m_provider.OnStateChange(currentState, newState, isRecall); } public void OnStateChange_Master(S newState) { if (SNet.IsMaster) { OnStateChange(isRecall: false, newState); } } public void OnStateCapture() { m_statePacket_Recall.CaptureToBuffer(m_currentState, CapturePass); } } internal class SNetExt_StateReplicatorProviderWrapper : MonoBehaviour, ISNetExt_StateReplicatorProvider, ISNetExt_StateReplicatorProvider where S : struct { private Action, S, S, bool> m_onStateChange; private SNetExt_StateReplicator m_stateReplicator; [HideFromIl2Cpp] public ISNetExt_StateReplicator GetStateReplicator() { return m_stateReplicator; } [HideFromIl2Cpp] public void OnStateChange(S oldState, S newState, bool isRecall) { m_onStateChange(m_stateReplicator, oldState, newState, isRecall); } [HideFromIl2Cpp] public void Setup(SNetExt_StateReplicator stateReplicator, Action, S, S, bool> onStateChange) { m_stateReplicator = stateReplicator; m_onStateChange = onStateChange; ((Component)this).gameObject.AddComponent().Setup(this); } private void OnDestroy() { if (m_stateReplicator != null) { SNetExt_Capture.UnRegisterForDropInCallback(m_stateReplicator); if (m_stateReplicator.Replicator != null) { SNetExt_Replication.DeallocateReplicator(m_stateReplicator.Replicator); } } } GameObject ISNetExt_StateReplicatorProvider.get_gameObject() { return ((Component)this).gameObject; } } internal class SNetExt_StateReplicatorProviderWrapper : MonoBehaviour, ISNetExt_StateReplicatorProvider, ISNetExt_StateReplicatorProvider where S : struct where I : struct { private Action, S, S, bool> m_onStateChange; private Action, I> m_attemptInteract; private SNetExt_StateReplicator m_stateReplicator; [HideFromIl2Cpp] public ISNetExt_StateReplicator GetStateReplicator() { return m_stateReplicator; } [HideFromIl2Cpp] public void OnStateChange(S oldState, S newState, bool isRecall) { m_onStateChange(m_stateReplicator, oldState, newState, isRecall); } [HideFromIl2Cpp] public void AttemptInteract(I interaction) { m_attemptInteract(m_stateReplicator, interaction); } [HideFromIl2Cpp] public void Setup(SNetExt_StateReplicator stateReplicator, Action, S, S, bool> onStateChange, Action, I> attemptInteract) { m_stateReplicator = stateReplicator; m_onStateChange = onStateChange; m_attemptInteract = attemptInteract; ((Component)this).gameObject.AddComponent().Setup(this); } private void OnDestroy() { if (m_stateReplicator != null) { SNetExt_Capture.UnRegisterForDropInCallback(m_stateReplicator); if (m_stateReplicator.Replicator != null) { SNetExt_Replication.DeallocateReplicator(m_stateReplicator.Replicator); } } } GameObject ISNetExt_StateReplicatorProvider.get_gameObject() { return ((Component)this).gameObject; } } public abstract class SNetExt_SyncedAction : IDisposable where T : struct { private bool _disposed; private Action _sessionMemberHandler; private CoreAPI.PlayerModsSynced _modsSyncedHandler; protected SNetExt_Packet m_packet; protected Func m_listenerFilter; protected bool m_hasListenerFilter; protected List m_listeners = new List(); protected Dictionary m_listenersLookup = new Dictionary(); public IEnumerable Listeners => m_listeners; public IReadOnlyDictionary ListenersLookup => m_listenersLookup; public event Action OnPlayerAddedToListeners; public event Action OnPlayerRemovedFromListeners; public void Dispose() { if (!_disposed) { _disposed = true; if (_sessionMemberHandler != null) { SNetEventAPI.OnSessionMemberChanged -= _sessionMemberHandler; } if (_modsSyncedHandler != null) { CoreAPI.OnPlayerModsSynced -= _modsSyncedHandler; } m_listeners.Clear(); m_listenersLookup.Clear(); GC.SuppressFinalize(this); } } ~SNetExt_SyncedAction() { Dispose(); } protected void Setup(string eventName, Action incomingAction, Action incomingActionValidation = null, Func listenerFilter = null, SNet_ChannelType channelType = 2) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) m_packet = SNetExt_Packet.Create(eventName, incomingAction, incomingActionValidation, channelType); m_listenerFilter = listenerFilter; m_hasListenerFilter = listenerFilter != null; _sessionMemberHandler = OnSessionMemberChanged; _modsSyncedHandler = OnPlayerModsSynced; SNetEventAPI.OnSessionMemberChanged += _sessionMemberHandler; CoreAPI.OnPlayerModsSynced += _modsSyncedHandler; } public void SyncToPlayer(SNet_Player player, T data) { m_packet.Send(data, player); } public void SyncToPlayer(SNet_Player player, params T[] datas) { foreach (T data in datas) { SyncToPlayer(player, data); } } public void SyncToPlayer(SNet_Player player, IEnumerable datas) { foreach (T data in datas) { SyncToPlayer(player, data); } } private void OnPlayerModsSynced(SNet_Player player, IEnumerable mods) { if (m_hasListenerFilter && m_listenerFilter(player) && player.IsInSessionHub) { Internal_AddPlayerToListeners(player); } } private void OnSessionMemberChanged(SNet_Player player, SessionMemberEvent playerEvent) { switch (playerEvent) { case SessionMemberEvent.JoinSessionHub: if (!m_hasListenerFilter || m_listenerFilter(player)) { Internal_AddPlayerToListeners(player); } break; case SessionMemberEvent.LeftSessionHub: Internal_RemovePlayerFromListeners(player); break; } } private void Internal_AddPlayerToListeners(SNet_Player player) { if (m_listenersLookup.ContainsKey(player.Lookup)) { for (int i = 0; i < m_listeners.Count; i++) { if (m_listeners[i].Lookup == player.Lookup) { m_listeners[i] = player; break; } } m_listenersLookup[player.Lookup] = player; } else { m_listeners.Add(player); m_listenersLookup[player.Lookup] = player; Utils.SafeInvoke>(this.OnPlayerAddedToListeners, new object[1] { player }); } } private void Internal_RemovePlayerFromListeners(SNet_Player player) { if (player.IsLocal) { List listeners = m_listeners; m_listeners = new List(); m_listenersLookup.Clear(); for (int i = 0; i < listeners.Count; i++) { Utils.SafeInvoke>(this.OnPlayerRemovedFromListeners, new object[1] { listeners[i] }); } } else { int num = m_listeners.RemoveAll((SNet_Player p) => p.Lookup == player.Lookup); m_listenersLookup.Remove(player.Lookup); if (num > 0) { Utils.SafeInvoke>(this.OnPlayerRemovedFromListeners, new object[1] { player }); } } } public void AddPlayerToListeners(SNet_Player player) { if (!m_hasListenerFilter || m_listenerFilter(player)) { Internal_AddPlayerToListeners(player); } } public void RemovePlayerFromListeners(SNet_Player player) { Internal_RemovePlayerFromListeners(player); } public bool IsListener(SNet_Player player) { if ((Object)(object)player == (Object)null) { return false; } return IsListener(player.Lookup); } public bool IsListener(ulong lookup) { return m_listenersLookup.ContainsKey(lookup); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct pBufferCommand { public SNetExt_BufferType type; public SNetExt_BufferOperationType operation; public ushort bufferID; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct pBufferCompletion { public SNetExt_BufferType type; public pBufferData data; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct pBufferData { public ulong sendingPlayerLookup; public ulong levelChecksum; public ushort bufferID; public float progressionTime; public ulong recallCount; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct pBuffersSummary { private static readonly IArchiveLogger _logger = LoaderWrapper.CreateArSubLoggerInstance("pBuffersSummary", ConsoleColor.White); public SNetExt_BufferType bufferType; public ulong levelChecksum; public ushort bufferID; public float progressionTime; public pBuffersSummary(SNetExt_CaptureBuffer buffer) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) bufferType = buffer.type; if (buffer.isValid && SNet.LocalPlayer.Session.levelChecksum == buffer.data.levelChecksum) { bufferID = buffer.data.bufferID; progressionTime = buffer.data.progressionTime; levelChecksum = buffer.data.levelChecksum; } else { bufferID = 0; progressionTime = 0f; levelChecksum = 0uL; } } public readonly bool IsValid() { return bufferID > 0; } public readonly bool IsSame(ref pBuffersSummary sum) { if (sum.levelChecksum != levelChecksum) { _logger.Error(sum.levelChecksum + " != " + levelChecksum); return false; } if (sum.bufferID != bufferID) { _logger.Error(sum.bufferID + " != " + bufferID); return false; } if (Mathf.Abs(sum.progressionTime - progressionTime) > 1f) { _logger.Error(sum.progressionTime + " != " + progressionTime); return false; } return true; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct pReplicationData { public SNetExt_KeyHash16 PrefabKeyHash; public SNetExt_KeyHash16 ReplicatorKeyHash; [MarshalAs(UnmanagedType.U1)] public bool isRecall; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct pReplicator { public SNetExt_KeyHash16 KeyHash; public readonly bool TryGetReplicator(out ISNetExt_Replicator rep) { return SNetExt_Replication.TryGetReplicatorByKeyHash16(in KeyHash, out rep); } public void SetReplicator(ISNetExt_Replicator rep) { if (rep != null) { KeyHash = SNetExt_KeyHash16.FromHex(rep.KeyHash); } else { KeyHash = default(SNetExt_KeyHash16); } } public readonly bool IsValid() { return !KeyHash.IsEmpty; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] public struct pStateReplicatorProvider { private pReplicator pRep; public readonly bool TryGet(out ISNetExt_StateReplicatorProvider provider) where S : struct { if (pRep.TryGetReplicator(out var rep) && rep != null && rep.ReplicatorSupplier != null && rep.ReplicatorSupplier is SNetExt_StateReplicator sNetExt_StateReplicator) { provider = sNetExt_StateReplicator.m_provider; return true; } provider = null; return false; } public readonly bool TryGet(out ISNetExt_StateReplicatorProvider provider) where S : struct where I : struct { if (pRep.TryGetReplicator(out var rep) && rep != null && rep.ReplicatorSupplier != null && rep.ReplicatorSupplier is SNetExt_StateReplicator sNetExt_StateReplicator) { provider = sNetExt_StateReplicator.m_provider; return true; } provider = null; return false; } internal void Set(SNetExt_StateReplicator stateReplicator) where S : struct { if (stateReplicator != null) { pRep.SetReplicator(stateReplicator.Replicator); } else { pRep.SetReplicator(null); } } internal void Set(SNetExt_StateReplicator stateReplicator) where S : struct where I : struct { if (stateReplicator != null) { pRep.SetReplicator(stateReplicator.Replicator); } else { pRep.SetReplicator(null); } } } } namespace Hikaria.Core.Managers { public class GameEventLogManager : MonoBehaviour, IPauseable { private static Queue queue = new Queue(); private float timer; private const float _updateInterval = 1f / 3f; public static GameEventLogManager Instance { get; private set; } private static PUI_GameEventLog PageLoadoutLog => MainMenuGuiLayer.Current.PageLoadout.m_gameEventLog; private static PUI_GameEventLog PlayerLayerLog => GuiManager.PlayerLayer.m_gameEventLog; private void Awake() { Instance = this; PauseManager.RegisterPauseable(this); } private void OnDestroy() { PauseManager.DeregisterPauseable(this); } private void FixedUpdate() { timer += Time.fixedDeltaTime; if (!(timer < 1f / 3f)) { timer = 0f; if (queue.TryDequeue(out var result)) { PageLoadoutLog.AddLogItem(result, (eGameEventChatLogType)2); PlayerLayerLog.AddLogItem(result, (eGameEventChatLogType)2); } } } public static void AddLog(string log) { queue.Enqueue(log); } public static void AddLogInSeparate(string log, int chunkSize = 50) { string[] array = log.SplitInChunks(chunkSize); foreach (string item in array) { queue.Enqueue(item); } } public void PausedUpdate() { timer += PauseManager.PauseUpdateInterval; if (!(timer < 1f / 3f)) { timer = 0f; if (queue.TryDequeue(out var result)) { PageLoadoutLog.AddLogItem(result, (eGameEventChatLogType)2); PlayerLayerLog.AddLogItem(result, (eGameEventChatLogType)2); } } } public void OnPaused() { } public void OnUnpaused() { } } internal class PauseManager : MonoBehaviour { [CompilerGenerated] private sealed class d__3 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private WaitForSecondsRealtime 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; } else { <>1__state = -1; 5__2 = new WaitForSecondsRealtime(PauseUpdateInterval); } foreach (IPauseable s_pausableUpdater in s_pausableUpdaters) { try { s_pausableUpdater.PausedUpdate(); } catch { } } <>2__current = 5__2; <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private Coroutine _pauseUpdateCoroutine; private static readonly HashSet s_pausableUpdaters = new HashSet(); private static bool s_isPaused; private static IArchiveLogger _logger; public static bool IsPaused { get { return s_isPaused; } set { if (s_isPaused != value) { s_isPaused = value; if (value) { Current.SetPaused(); } else { Current.SetUnpaused(); } } } } public static float PauseUpdateInterval => Time.fixedUnscaledDeltaTime; public static PauseManager Current { get; private set; } private static IArchiveLogger Logger => _logger ?? (_logger = LoaderWrapper.CreateLoggerInstance("PauseManager", ConsoleColor.White)); public static event Action OnPaused; public static event Action OnUnpaused; private void Awake() { Current = this; } private void SetPaused() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if (SNet.IsMaster && (int)GameStateManager.CurrentStateName == 10) { SNet.Capture.CaptureGameState((eBufferType)4); } if (_pauseUpdateCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_pauseUpdateCoroutine); } _pauseUpdateCoroutine = ((MonoBehaviour)this).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(UpdateRegistered())); foreach (IPauseable s_pausableUpdater in s_pausableUpdaters) { try { s_pausableUpdater.OnPaused(); } catch { } } Utils.SafeInvoke(PauseManager.OnPaused, Array.Empty()); Logger.Notice("Game Paused"); } private void SetUnpaused() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Invalid comparison between Unknown and I4 if (_pauseUpdateCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_pauseUpdateCoroutine); _pauseUpdateCoroutine = null; } foreach (IPauseable s_pausableUpdater in s_pausableUpdaters) { try { s_pausableUpdater.OnUnpaused(); } catch { } } Utils.SafeInvoke(PauseManager.OnUnpaused, Array.Empty()); if (SNet.IsMaster && (int)GameStateManager.CurrentStateName == 10) { SNet.Sync.StartRecallWithAllSyncedPlayers((eBufferType)4, false); } Logger.Notice("Game Unpaused"); } [IteratorStateMachine(typeof(d__3))] private IEnumerator UpdateRegistered() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(0); } public static void RegisterPauseable(IPauseable pu) { s_pausableUpdaters.Add(pu); } public static void DeregisterPauseable(IPauseable pu) { s_pausableUpdaters.Remove(pu); } } public static class PopupMessageManager { [CompilerGenerated] private sealed class d__17 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private WaitForSeconds 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (_runningShowAllPopups) { return false; } _runningShowAllPopups = true; 5__2 = new WaitForSeconds(0.1f); <>2__current = 5__2; <>1__state = 1; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; } try { if (AllowToShowPopup && _popupQueue.TryDequeue(out var result)) { GlobalPopupMessageManager.ShowPopup(result); } } catch (Exception ex) { Logger.Error("Failed to show popup."); Logger.Exception(ex); } <>2__current = 5__2; <>1__state = 2; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static IArchiveLogger _logger; private static IArchiveLogger Logger; private static SNetExt_Packet s_PopupMessagePacket; private static readonly Queue _popupQueue; private static bool _runningShowAllPopups; public static Action EmptyAction { get; private set; } public static bool AllowToShowPopup { get { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Invalid comparison between Unknown and I4 if (((CM_PageBase)MainMenuGuiLayer.Current.PageRundownNew).m_isActive || ((CM_PageBase)MainMenuGuiLayer.Current.PageLoadout).m_isActive) { return (int)GameStateManager.CurrentStateName <= 5; } return false; } } static PopupMessageManager() { Logger = _logger ?? (_logger = LoaderWrapper.CreateLoggerInstance("PopupMessageManager", ConsoleColor.White)); EmptyAction = Empty; _popupQueue = new Queue(); _runningShowAllPopups = false; s_PopupMessagePacket = SNetExt_Packet.Create(typeof(pPopupMessage).FullName, OnReceivePopupMessage, null, (SNet_ChannelType)0); } internal static void Setup() { CoroutineManager.StartPersistantCoroutine(CollectionExtensions.WrapToIl2Cpp(ShowAllPopups())); } private static void OnReceivePopupMessage(SNet_Player sender, pPopupMessage data) { Logger.Notice($"Receive pPopupMessage from '{sender.NickName}' [{sender.Lookup}]"); ShowPopup(data.UnpackPopupMessage()); } public static void SendPopupMessage(pPopupMessage data, List players) { s_PopupMessagePacket.Send(data, players); } private static void Empty() { } public static void ShowPopup(PopupMessage popupMessage) { _popupQueue.Enqueue(popupMessage); } [IteratorStateMachine(typeof(d__17))] private static IEnumerator ShowAllPopups() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__17(0); } } } namespace Hikaria.Core.Interfaces { public interface IInteractable { Transform Root { get; } bool PlayerCanInteract(PlayerAgent source); bool PlayerDoInteract(PlayerAgent source); void PlayerSetSelected(bool sel, PlayerAgent agent); bool PlayerCheckInput(PlayerAgent agent); } public interface IPauseable { void PausedUpdate(); void OnPaused(); void OnUnpaused(); } } namespace Hikaria.Core.Features.Security { [DisallowInGameToggle] [EnableFeatureByDefault] [DoNotSaveToConfig] internal class LobbySettingsOverride : Feature { public class LobbySettingOverrideSettings { [JsonIgnore] [FSDisplayName("Privacy")] public LobbyPrivacy Privacy { get { return LobbySettingsManager.CurrentSettings.Privacy; } set { LobbySettingsManager.CurrentSettings.Privacy = value; LobbySettingsManager.OnLobbySettingsChanged(); } } [JsonIgnore] [FSMaxLength(25)] [FSDisplayName("Password")] public string Password { get { return LobbySettingsManager.CurrentSettings.Password; } set { LobbySettingsManager.CurrentSettings.Password = value; LobbySettingsManager.OnLobbySettingsChanged(); } } [JsonIgnore] [FSHeader("Join Other Lobby", true)] [FSMaxLength(25)] [FSDisplayName("Password For Join Other Lobby")] public string PasswordForJoinOthers { get { return LobbySettingsManager.PasswordForJoinOtherLobby; } set { LobbySettingsManager.PasswordForJoinOtherLobby = value; } } } public enum LobbyPrivacy { Public, FriendsOnly, Private, Invisible } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_SessionHub__SlaveSendSessionQuestion__Patch { private static void Prefix(SlaveSessionQuestion question) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) LobbySettingsManager.SlaveSendSessionRequest(question); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_SessionHub__OnSlaveQuestion__Patch { private static bool Prefix(pSlaveQuestion data) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return LobbySettingsManager.OnSlaveQuestionOverride(data); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_LobbyManager__CreateLobby__Patch { private static void Prefix(ref SNet_LobbySettings settings) { if (settings != null) { LobbySettingsManager.ApplyLobbySettings(ref settings); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SteamMatchmaking__InviteUserToLobby__Patch { private static void Postfix(CSteamID steamIDInvitee) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) LobbySettingsManager.WhitelistPlayer(steamIDInvitee.m_SteamID); } } public static class LobbySettingsManager { public enum SlaveRequest : byte { WantsToJoin, Leaving } public enum MasterAnswer : byte { LeaveLobby, AllowToJoin } [Flags] public enum MasterAnswerReason { None = 0, Public = 1, Banned = 2, PasswordMismatch = 4, IsNotFriend = 8, InvisibleLobby = 0x10, PasswordMatch = 0x20, IsFriend = 0x40, Whitelist = 0x80 } public struct pSlaveRequest { public SlaveRequest Request; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)] public string Password; public pSlaveRequest(SlaveRequest question, string password = "") { Request = question; if (password == null) { password = string.Empty; } Password = password.Substring(0, Math.Min(password.Length, 25)); } } public struct pLobbyMasterAnswer { public LobbyPrivacy LobbyPrivacy; public MasterAnswer Answer; public MasterAnswerReason Reason; public pLobbyMasterAnswer(LobbyPrivacy privacy, MasterAnswer answer, MasterAnswerReason reason) { LobbyPrivacy = privacy; Answer = answer; Reason = reason; } } public class LobbySettings { public LobbyPrivacy Privacy; public const int PASSWORD_MAX_LENGTH = 25; private string _password = string.Empty; public string LobbyName { get; set; } public string Password { get { return _password; } set { if (value == null) { value = string.Empty; } value = value.Substring(0, Math.Min(value.Length, 25)); _password = value; HasPassword = !string.IsNullOrWhiteSpace(_password); } } public bool HasPassword { get; private set; } public LobbyType Type => ToSNetLobbyType(Privacy); } private static IArchiveLogger _logger; private static SNetExt_Packet s_slaveSessionRequestPacket; private static SNetExt_Packet s_lobbySettingsAnswerPacket; private static Dictionary s_receivedSlaveRequestsLookup = new Dictionary(); private static HashSet s_tempWhitelist = new HashSet(); private static string _passwordForJoinOthers = string.Empty; private static IArchiveLogger Logger => _logger ?? (_logger = LoaderWrapper.CreateLoggerInstance("LobbySettingsManager", ConsoleColor.White)); public static LobbySettings CurrentSettings { get; private set; } = new LobbySettings(); public static SNet_Lobby_STEAM SteamLobby { get { SNet_Lobby lobby = SNet.Lobby; if (lobby == null) { return null; } return ((Il2CppObjectBase)lobby).TryCast(); } } public static SNet_Core_STEAM Core => ((Il2CppObjectBase)SNet.Core).TryCast(); public static string PasswordForJoinOtherLobby { get { return _passwordForJoinOthers; } set { if (value == null) { value = string.Empty; } value = value.Substring(0, Math.Min(value.Length, 25)); _passwordForJoinOthers = value; } } private static PopupMessage Popup_Banned => new PopupMessage { BlinkInContent = true, BlinkTimeInterval = 0.5f, Header = Localization.GetById(1u, (string)null), UpperText = "无法加入大厅\n\n原因:被封禁的玩家", LowerText = string.Empty, PopupType = (PopupType)3, OnCloseCallback = Action.op_Implicit((Action)delegate { if (SNet.LocalPlayer.IsOutOfSync) { SNet.SessionHub.LeaveHub(false); } }) }; private static PopupMessage Popup_InvisibleLobby => new PopupMessage { BlinkInContent = true, BlinkTimeInterval = 0.5f, Header = Localization.GetById(1u, (string)null), UpperText = "无法加入大厅\n\n原因:大厅已锁定", LowerText = string.Empty, PopupType = (PopupType)3, OnCloseCallback = Action.op_Implicit((Action)delegate { if (SNet.LocalPlayer.IsOutOfSync) { SNet.SessionHub.LeaveHub(false); } }) }; private static PopupMessage Popup_PasswordMismatch => new PopupMessage { BlinkInContent = true, BlinkTimeInterval = 0.5f, Header = Localization.GetById(1u, (string)null), UpperText = "无法加入大厅\n\n原因:密码错误", LowerText = string.Empty, PopupType = (PopupType)3, OnCloseCallback = Action.op_Implicit((Action)delegate { if (SNet.LocalPlayer.IsOutOfSync) { SNet.SessionHub.LeaveHub(false); } }) }; private static PopupMessage Popup_IsNotFriend => new PopupMessage { BlinkInContent = true, BlinkTimeInterval = 0.5f, Header = Localization.GetById(1u, (string)null), UpperText = "无法加入大厅\n\n原因:您不是房主好友", LowerText = string.Empty, PopupType = (PopupType)3, OnCloseCallback = Action.op_Implicit((Action)delegate { if (SNet.LocalPlayer.IsOutOfSync) { SNet.SessionHub.LeaveHub(false); } }) }; public static void Setup() { s_slaveSessionRequestPacket = SNetExt_Packet.Create(typeof(pSlaveRequest).FullName, OnReceiveSlaveRequest, null, (SNet_ChannelType)0); s_lobbySettingsAnswerPacket = SNetExt_Packet.Create(typeof(pLobbyMasterAnswer).FullName, OnReceiveLobbySettingsAnswer, null, (SNet_ChannelType)0); } public static void ApplyLobbySettings(ref SNet_LobbySettings settings) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) settings.Password = CurrentSettings.Password; settings.LobbyType = ToSNetLobbyType(CurrentSettings.Privacy); settings.LobbyName = CurrentSettings.LobbyName; } public static void OnLobbySettingsChanged() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (SNet.IsInLobby && SNet.IsMaster && !((Object)(object)SteamLobby == (Object)null)) { SNet_LobbySettings lastLobbySettings = Core.m_lastLobbySettings; lastLobbySettings.Password = CurrentSettings.Password; lastLobbySettings.LobbyType = ToSNetLobbyType(CurrentSettings.Privacy); lastLobbySettings.LobbyName = CurrentSettings.LobbyName; ((SNet_Lobby)SteamLobby).Password = CurrentSettings.Password; SteamLobby.Name = CurrentSettings.LobbyName; ((SNet_Lobby)SteamLobby).Identifier.Name = CurrentSettings.LobbyName; } } private static void OnReceiveSlaveRequest(SNet_Player sender, pSlaveRequest data) { if (SNet.IsMaster) { s_receivedSlaveRequestsLookup[sender.Lookup] = data; } } private static void OnReceiveLobbySettingsAnswer(SNet_Player sender, pLobbyMasterAnswer data) { if (!sender.IsMaster || data.Answer != 0) { return; } if (data.Reason == MasterAnswerReason.Banned) { PopupMessageManager.ShowPopup(Popup_Banned); return; } switch (data.LobbyPrivacy) { case LobbyPrivacy.Invisible: PopupMessageManager.ShowPopup(Popup_InvisibleLobby); break; case LobbyPrivacy.Private: if (data.Reason == MasterAnswerReason.PasswordMismatch) { PopupMessageManager.ShowPopup(Popup_PasswordMismatch); } break; case LobbyPrivacy.FriendsOnly: if (data.Reason == MasterAnswerReason.IsNotFriend) { PopupMessageManager.ShowPopup(Popup_IsNotFriend); } break; } } public static void SlaveSendSessionRequest(SlaveSessionQuestion question) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (SNet.HasMaster && (int)question == 0) { s_slaveSessionRequestPacket.Send(new pSlaveRequest(SlaveRequest.WantsToJoin, PasswordForJoinOtherLobby), SNet.Master); } } public static bool OnSlaveQuestionOverride(pSlaveQuestion data) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!SNet.IsMaster || !SNet.LocalPlayer.IsInSessionHub || (int)data.question != 0) { return true; } SNet_Player val = default(SNet_Player); if (!SNet.Core.TryGetPlayer(SNet.Replication.LastSenderID, ref val, true)) { return false; } if (val.IsLocal) { return true; } if (!IsPlayerAllowedToJoinLobby(val, out var reason)) { s_lobbySettingsAnswerPacket.Send(new pLobbyMasterAnswer(CurrentSettings.Privacy, MasterAnswer.LeaveLobby, reason), val); SNet.SessionHub.RemovePlayerFromSession(val, true); return false; } s_lobbySettingsAnswerPacket.Send(new pLobbyMasterAnswer(CurrentSettings.Privacy, MasterAnswer.AllowToJoin, reason), val); return true; } public static void DoPlayerLeftCleanup(SNet_Player player) { if (player.IsLocal) { s_tempWhitelist.Clear(); s_receivedSlaveRequestsLookup.Clear(); } else { s_tempWhitelist.Remove(player.Lookup); } } public static void WhitelistPlayer(ulong steamid) { s_tempWhitelist.Add(steamid); } public static bool IsPlayerAllowedToJoinLobby(SNet_Player player, out MasterAnswerReason reason) { string name = player.GetName(); if (PlayerLobbyManagement.IsPlayerBanned(player.Lookup)) { reason = MasterAnswerReason.Banned; Logger.Notice($"Player {name} failed to join. Reason: {reason}."); return false; } if (s_tempWhitelist.Contains(player.Lookup)) { reason = MasterAnswerReason.Whitelist; return true; } switch (CurrentSettings.Privacy) { case LobbyPrivacy.Invisible: reason = MasterAnswerReason.InvisibleLobby; Logger.Notice($"Player {name} failed to join. Reason: {reason}."); return false; case LobbyPrivacy.FriendsOnly: if (!SharedUtils.IsFriend(player)) { reason = MasterAnswerReason.IsNotFriend; Logger.Notice($"Player {name} failed to join. Reason: {reason}."); return false; } reason = MasterAnswerReason.IsFriend; return true; case LobbyPrivacy.Private: { if (!CurrentSettings.HasPassword) { reason = MasterAnswerReason.Public; return true; } if (s_receivedSlaveRequestsLookup.TryGetValue(player.Lookup, out var value) && value.Password == CurrentSettings.Password) { reason = MasterAnswerReason.PasswordMatch; return true; } reason = MasterAnswerReason.PasswordMismatch; Logger.Notice($"Player {name} failed to join. Reason: {reason}. Lobby: {CurrentSettings.Password}, Slave: {value.Password}"); return false; } case LobbyPrivacy.Public: reason = MasterAnswerReason.Public; return true; default: reason = MasterAnswerReason.None; return true; } } public static LobbyType ToSNetLobbyType(LobbyPrivacy privacy) { //IL_0019: 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) //IL_001d: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) return (LobbyType)(privacy switch { LobbyPrivacy.Public => 2, LobbyPrivacy.Private => 0, LobbyPrivacy.FriendsOnly => 1, LobbyPrivacy.Invisible => 3, _ => 3, }); } } public override string Name => "大厅设置覆盖"; public override string Description => "提供大厅权限和密码的设置。"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Security", false); public static ILocalizationService Localization { get; set; } public override Type[] ExternalLocalizedTypes => new Type[1] { typeof(LobbyPrivacy) }; [FeatureConfig] public static LobbySettingOverrideSettings Settings { get; set; } public override void OnFeatureSettingChanged(FeatureSetting setting) { } public override void Init() { LobbySettingsManager.Setup(); } public override void OnEnable() { SNetEventAPI.OnSessionMemberChanged += OnSessionMemberChanged; } public override void OnDisable() { SNetEventAPI.OnSessionMemberChanged -= OnSessionMemberChanged; } public void OnSessionMemberChanged(SNet_Player player, SessionMemberEvent playerEvent) { if (playerEvent == SessionMemberEvent.LeftSessionHub) { LobbySettingsManager.DoPlayerLeftCleanup(player); } } } } namespace Hikaria.Core.Features.Misc { [ForceDisable("WIP")] [EnableFeatureByDefault] internal class EnemyRagdollTweaker : Feature { public class RagdollMultiplierSettings { [FSDisplayName("增幅倍率")] public float ImpactForceMultiplie { get; set; } = 10f; [FSDisplayName("垂直增幅倍率")] public float UpwardMultiplier { get; set; } = 10f; } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class EnemyRagdollBodyController__SetRagdollEnabled__Patch { [CompilerGenerated] private sealed class d__1 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public EnemyRagdollBodyController __instance; private float 5__2; private Dictionary 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForFixedUpdate(); <>1__state = 1; return true; case 1: <>1__state = -1; 5__2 = Time.time + 0.3f; 5__3 = new Dictionary(); break; case 2: <>1__state = -1; break; } if (s_masterHasCore && Time.time < 5__2) { if (!s_killedEnemies.Contains(((Agent)__instance.m_owner).GlobalID)) { <>2__current = null; <>1__state = 2; return true; } foreach (var (num, pFullEnemyReceivedDamageData) in s_enemyReceivedDamages[((Agent)__instance.m_owner).GlobalID]) { if (Time.time - num <= 0.5f) { if (5__3.ContainsKey(pFullEnemyReceivedDamageData.limbID)) { Dictionary dictionary = 5__3; int limbID = pFullEnemyReceivedDamageData.limbID; dictionary[limbID] += pFullEnemyReceivedDamageData.direction * pFullEnemyReceivedDamageData.damage; } else { 5__3.Add(pFullEnemyReceivedDamageData.limbID, pFullEnemyReceivedDamageData.direction * pFullEnemyReceivedDamageData.damage); } } } } EnemyRagdollRef component = __instance.m_owner.RagdollInstance.GetComponent(); ((Component)__instance).transform.SetParent(__instance.m_owner.RagdollInstance.transform, true); CustomExtensions.ChangeLayerRecursive(__instance.m_owner.RagdollInstance, LayerManager.LAYER_ENEMY_DEAD, (Il2CppStructArray)null); __instance.m_owner.RagdollInstance.SetActive(true); Enumerator enumerator2 = ((Dictionary)(object)component.m_rigidBodyLookup).GetEnumerator(); while (enumerator2.MoveNext()) { KeyValuePair current = enumerator2.Current; if (!__instance.m_bodyDatas.ContainsKey(current.Key)) { continue; } Transform transform = ((Component)current.Value).transform; Transform transform2 = ((Component)__instance.m_bodyDatas[current.Key]).transform; transform.localPosition = transform2.localPosition; transform.localRotation = transform2.localRotation; transform.localScale = transform2.localScale; transform2.SetParent(transform, false); transform2.localPosition = Vector3.zero; transform2.localRotation = Quaternion.identity; transform2.localScale = Vector3.one; if ((Object)(object)__instance.m_bodyDatas[current.Key].m_colliderInstance != (Object)null) { __instance.m_bodyDatas[current.Key].m_colliderInstance.enabled = false; } current.Value.isKinematic = false; current.Value.useGravity = true; current.Value.collisionDetectionMode = (CollisionDetectionMode)1; current.Value.interpolation = (RigidbodyInterpolation)1; current.Value.velocity = __instance.m_bodyDatas[current.Key].m_velocity; if (s_masterHasCore) { if (5__3.TryGetValue(__instance.m_bodyDatas.FindEntry(current.Key), out var value)) { Vector3 val = value * Settings.ImpactForceMultiplie; val.y = Mathf.Max(0f, val.y); val += Vector3.up * Settings.UpwardMultiplier; current.Value.AddForce(val, (ForceMode)1); Vector3 val2 = Vector3.Cross(value, Vector3.up) * Settings.ImpactForceMultiplie; current.Value.AddTorque(val2, (ForceMode)1); } } else { current.Value.AddForce(Vector3.up * Settings.UpwardMultiplier, (ForceMode)1); } } if (s_masterHasCore) { s_killedEnemies.Remove(((Agent)__instance.m_owner).GlobalID); s_enemyReceivedDamages.Remove(((Agent)__instance.m_owner).GlobalID); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static bool Prefix(EnemyRagdollBodyController __instance, bool enabled) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (enabled && __instance.UseRagdollOptimization) { __instance.m_owner.RagdollInstance = Object.Instantiate(__instance.ragdollRefToInstantiate, ((Component)__instance).transform.position, ((Component)__instance).transform.rotation); __instance.m_owner.RagdollInstance.SetActive(false); __instance.m_owner.RagdollInstance.transform.localScale = ((Component)__instance.m_owner).transform.localScale; ((MonoBehaviour)__instance).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(LinkToSpawnedRagdoll(__instance))); return false; } return true; } [IteratorStateMachine(typeof(d__1))] private static IEnumerator LinkToSpawnedRagdoll(EnemyRagdollBodyController __instance) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(0) { __instance = __instance }; } } private static bool s_masterHasCore; private static readonly HashSet s_killedEnemies = new HashSet(); private static readonly Dictionary> s_enemyReceivedDamages = new Dictionary>(); public override string Name => "布娃娃调节器"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Misc", false); [FeatureConfig] public static RagdollMultiplierSettings Settings { get; set; } public override void OnEnable() { EnemyAPI.OnEnemyReceivedDamage += OnEnemyReceivedDamage; CoreAPI.OnPlayerModsSynced += OnPlayerModsSynced; SNetEventAPI.OnMasterChanged += OnMasterChanged; } public override void OnDisable() { EnemyAPI.OnEnemyReceivedDamage -= OnEnemyReceivedDamage; CoreAPI.OnPlayerModsSynced -= OnPlayerModsSynced; SNetEventAPI.OnMasterChanged -= OnMasterChanged; s_killedEnemies.Clear(); s_enemyReceivedDamages.Clear(); } private static void OnPlayerModsSynced(SNet_Player player, IEnumerable mods) { if (player.IsMaster) { s_masterHasCore = CoreAPI.IsPlayerInstalledCore(player); } } private static void OnMasterChanged() { s_masterHasCore = CoreAPI.IsPlayerInstalledCore(SNet.Master); } private static void OnEnemyReceivedDamage(EnemyAgent enemy, pFullEnemyReceivedDamageData data) { if (!s_enemyReceivedDamages.TryGetValue(((Agent)enemy).GlobalID, out List<(float, pFullEnemyReceivedDamageData)> value)) { value = new List<(float, pFullEnemyReceivedDamageData)>(); s_enemyReceivedDamages.Add(((Agent)enemy).GlobalID, value); } value.Add((Time.time, data)); if (data.isKill) { s_killedEnemies.Add(((Agent)enemy).GlobalID); } } } } namespace Hikaria.Core.Features.Fixes { [EnableFeatureByDefault] internal class BackBonusFix : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageLimb__ApplyDamageFromBehindBonus__Patch { private static readonly Quaternion rotation = Quaternion.Euler(0f, -90f, 0f); private static bool Prefix(Dam_EnemyDamageLimb __instance, float dam, Vector3 dir, float backstabberMulti, ref float __result) { //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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) EnemyAgent owner = __instance.m_base.Owner; if ((Object)(object)owner == (Object)null) { return true; } if (owner.EnemyBalancingData.AllowDamgeBonusFromBehind) { ((Vector3)(ref dir)).Normalize(); Vector3 forward = ((Component)owner).transform.forward; float num = Vector3.Dot(forward, dir); float num2 = Vector3.Dot(dir, forward); Transform boneTransform = owner.Anim.GetBoneTransform((HumanBodyBones)7); if ((Object)(object)boneTransform != (Object)null) { num = Vector3.Dot(rotation * boneTransform.forward, dir); num2 = Vector3.Dot(dir, boneTransform.up * -1f); } if (num > 0f) { dam *= Mathf.Clamp01(num + 0.25f) + 1f; } if (backstabberMulti > 1f && (num > 0.55f || num2 > 0.55f)) { dam *= backstabberMulti; } } __result = dam; return false; } } public override string Name => "背伤加成修复"; public override string Description => "使得背伤加成通过敌人的背部实际朝向计算"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Fixes", false); } [EnableFeatureByDefault] internal class BulletPierceFix : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private static class Weapon__CastWeaponRay__Patch { public static Type[] ParameterTypes() { return new Type[4] { typeof(Transform), typeof(WeaponHitData).MakeByRefType(), typeof(Vector3), typeof(int) }; } private static void Postfix(ref WeaponHitData weaponRayData) { weaponRayData.randomSpread = 0f; weaponRayData.angOffsetX = 0f; weaponRayData.angOffsetY = 0f; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private static class BulletWeapon__Fire__Patch { private static int Priority() { return PatchPriority; } private static bool Prefix(BulletWeapon __instance, bool resetRecoilSimilarity = true) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_007c: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_037e: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) float num = ((!((ItemEquippable)__instance).FPItemHolder.ItemAimTrigger) ? ((ItemEquippable)__instance).ArchetypeData.HipFireSpread : ((ItemEquippable)__instance).ArchetypeData.AimSpread); if (Clock.Time - __instance.m_lastFireTime > __instance.m_fireRecoilCooldown) { num *= 0.2f; } __instance.m_lastFireTime = Clock.Time; if (((Agent)((Item)__instance).Owner).IsLocallyOwned) { PlayerAgent.LastLocalShotFiredTime = __instance.m_lastFireTime; } Vector3 val = ((Item)__instance).Owner.FPSCamera.Position; WeaponHitData val2 = new WeaponHitData { randomSpread = num, maxRayDist = ((Weapon)__instance).MaxRayDist }; Vector3 val3 = ((Item)__instance).Owner.FPSCamera.CameraRayPos - val; val2.fireDir = ((Vector3)(ref val3)).normalized; val2.owner = ((Item)__instance).Owner; val2.damage = ((ItemEquippable)__instance).ArchetypeData.GetDamageWithBoosterEffect(((Item)__instance).Owner, ((Item)__instance).ItemDataBlock.inventorySlot); val2.staggerMulti = ((ItemEquippable)__instance).ArchetypeData.StaggerDamageMulti; val2.precisionMulti = ((ItemEquippable)__instance).ArchetypeData.PrecisionDamageMulti; val2.damageFalloff = ((ItemEquippable)__instance).ArchetypeData.DamageFalloff; Weapon.s_weaponRayData = val2; WeaponHitData s_weaponRayData = Weapon.s_weaponRayData; RaycastHit rayHit; if (((ItemEquippable)__instance).ArchetypeData.PiercingBullets) { if (__instance.m_damageSearchID >= uint.MaxValue) { __instance.m_damageSearchID = 0u; } __instance.m_damageSearchID += 1; bool flag = false; float num2 = 0f; int num3 = -1; while (!flag && Weapon.s_weaponRayData.maxRayDist > 0f && num3 < ((ItemEquippable)__instance).ArchetypeData.PiercingDamageCountLimit) { if (Weapon.CastWeaponRay(((Component)((Item)__instance).Owner.FPSCamera).transform, ref s_weaponRayData, val, -1)) { if (BulletWeapon.BulletHit(Weapon.s_weaponRayData, true, num2, __instance.m_damageSearchID, true)) { num3++; } rayHit = Weapon.s_weaponRayData.rayHit; FX_Manager.EffectTargetPosition = ((RaycastHit)(ref rayHit)).point; rayHit = Weapon.s_weaponRayData.rayHit; flag = !CustomExtensions.IsInLayerMask(((Component)((RaycastHit)(ref rayHit)).collider).gameObject, LayerMask.op_Implicit(LayerManager.MASK_BULLETWEAPON_PIERCING_PASS)); rayHit = Weapon.s_weaponRayData.rayHit; val = ((RaycastHit)(ref rayHit)).point + Weapon.s_weaponRayData.fireDir * 0.1f; float num4 = num2; rayHit = Weapon.s_weaponRayData.rayHit; num2 = num4 + ((RaycastHit)(ref rayHit)).distance; WeaponHitData s_weaponRayData2 = Weapon.s_weaponRayData; float maxRayDist = s_weaponRayData2.maxRayDist; rayHit = Weapon.s_weaponRayData.rayHit; s_weaponRayData2.maxRayDist = maxRayDist - ((RaycastHit)(ref rayHit)).distance; } else { flag = true; FX_Manager.EffectTargetPosition = ((Item)__instance).Owner.FPSCamera.CameraRayPos; } } } else if (Weapon.CastWeaponRay(((Component)((Item)__instance).Owner.FPSCamera).transform, ref s_weaponRayData, val, -1)) { BulletWeapon.BulletHit(Weapon.s_weaponRayData, true, 0f, 0u, true); rayHit = Weapon.s_weaponRayData.rayHit; FX_Manager.EffectTargetPosition = ((RaycastHit)(ref rayHit)).point; } else { FX_Manager.EffectTargetPosition = ((Item)__instance).Owner.FPSCamera.CameraRayPos; } FX_Manager.PlayLocalVersion = false; ((FX_EffectBase)BulletWeapon.s_tracerPool.AquireEffect()).Play((FX_Trigger)null, ((ItemEquippable)__instance).MuzzleAlign.position, Quaternion.LookRotation(Weapon.s_weaponRayData.fireDir)); EX_SpriteMuzzleFlash muzzleFlash = ((Weapon)__instance).m_muzzleFlash; if ((Object)(object)muzzleFlash != (Object)null) { muzzleFlash.Play(); } if ((Object)(object)((ItemEquippable)__instance).m_rotatingCylinder != (Object)null) { if ((Object)(object)__instance.m_cylinderRotationCoroutineScript == (Object)null) { __instance.m_cylinderRotationCoroutineScript = ((ItemEquippable)__instance).m_rotatingCylinder.GetComponent(); } float num5 = 360f / (float)((ItemEquippable)__instance).ClipSize; __instance.m_cylinderRotationCoroutineScript.RotationAngle = Quaternion.Euler(0f, num5, 0f); } if (((ItemEquippable)__instance).ShellCasingData != null && (int)((ItemEquippable)__instance).ShellCasingData.ShellCasingType != 0) { if (((Agent)((Item)__instance).Owner).IsLocallyOwned) { WeaponShellManager.RegisterFPSShellEject(((ItemEquippable)__instance).ShellCasingData.ShellCasingType, 1f, 1f, ((ItemEquippable)__instance).ShellEjectAlign); } else { WeaponShellManager.EjectShell(((ItemEquippable)__instance).ShellCasingData.ShellCasingType, 1f, 1f, ((ItemEquippable)__instance).ShellEjectAlign, Vector3.one, false); } } if (((ItemEquippable)__instance).RecoilAnimation != null) { ((Weapon)__instance).ApplyRecoil(true); } else { ((Weapon)__instance).ApplyRecoil(resetRecoilSimilarity); } ((ItemEquippable)__instance).TriggerFireAnimationSequence(); ((Agent)((Item)__instance).Owner).Noise = (NoiseType)8; ((Item)__instance).Owner.Sync.RegisterFiredBullets(1); ((ItemEquippable)__instance).FPItemHolder.DontRelax(); for (int i = 0; i < ((ItemEquippable)__instance).m_itemPartAnimators.Count; i++) { ((ItemEquippable)__instance).m_itemPartAnimators[i].CrossFadeInFixedTime("Fire", 0f, 0); } int clip = __instance.m_clip; __instance.m_clip = clip - 1; __instance.UpdateAmmoStatus(); return false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private static class Shotgun__Fire__Patch { public static int Priority() { return PatchPriority; } private static bool Prefix(Shotgun __instance, bool resetRecoilSimilarity = true) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0104: 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_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < ((ItemEquippable)__instance).ArchetypeData.ShotgunBulletCount; i++) { Vector3 val = ((Item)__instance).Owner.FPSCamera.Position; float num = __instance.m_segmentSize * (float)i; float num2 = 0f; float num3 = 0f; if (i > 0) { num2 += (float)((ItemEquippable)__instance).ArchetypeData.ShotgunConeSize * Mathf.Cos(num); num3 += (float)((ItemEquippable)__instance).ArchetypeData.ShotgunConeSize * Mathf.Sin(num); } WeaponHitData val2 = new WeaponHitData { owner = ((Item)__instance).Owner, damage = ((ItemEquippable)__instance).ArchetypeData.GetDamageWithBoosterEffect(((Item)__instance).Owner, ((Item)__instance).ItemDataBlock.inventorySlot), staggerMulti = ((ItemEquippable)__instance).ArchetypeData.StaggerDamageMulti, precisionMulti = ((ItemEquippable)__instance).ArchetypeData.PrecisionDamageMulti, damageFalloff = ((ItemEquippable)__instance).ArchetypeData.DamageFalloff, maxRayDist = ((Weapon)__instance).MaxRayDist, angOffsetX = num2, angOffsetY = num3, randomSpread = ((ItemEquippable)__instance).ArchetypeData.ShotgunBulletSpread }; Vector3 val3 = ((Item)__instance).Owner.FPSCamera.CameraRayPos - val; val2.fireDir = ((Vector3)(ref val3)).normalized; Weapon.s_weaponRayData = val2; WeaponHitData s_weaponRayData = Weapon.s_weaponRayData; RaycastHit rayHit; if (((ItemEquippable)__instance).ArchetypeData.PiercingBullets) { if (((BulletWeapon)__instance).m_damageSearchID >= uint.MaxValue) { ((BulletWeapon)__instance).m_damageSearchID = 0u; } ((BulletWeapon)__instance).m_damageSearchID = ((BulletWeapon)__instance).m_damageSearchID + 1; bool flag = false; float num4 = 0f; int num5 = -1; while (!flag && Weapon.s_weaponRayData.maxRayDist > 0f && num5 < ((ItemEquippable)__instance).ArchetypeData.PiercingDamageCountLimit) { if (Weapon.CastWeaponRay(((Component)((Item)__instance).Owner.FPSCamera).transform, ref s_weaponRayData, val, -1)) { if (BulletWeapon.BulletHit(Weapon.s_weaponRayData, true, num4, ((BulletWeapon)__instance).m_damageSearchID, true)) { num5++; } rayHit = Weapon.s_weaponRayData.rayHit; FX_Manager.EffectTargetPosition = ((RaycastHit)(ref rayHit)).point; rayHit = Weapon.s_weaponRayData.rayHit; flag = !CustomExtensions.IsInLayerMask(((Component)((RaycastHit)(ref rayHit)).collider).gameObject, LayerMask.op_Implicit(LayerManager.MASK_BULLETWEAPON_PIERCING_PASS)); rayHit = Weapon.s_weaponRayData.rayHit; val = ((RaycastHit)(ref rayHit)).point + Weapon.s_weaponRayData.fireDir * 0.1f; float num6 = num4; rayHit = Weapon.s_weaponRayData.rayHit; num4 = num6 + ((RaycastHit)(ref rayHit)).distance; WeaponHitData s_weaponRayData2 = Weapon.s_weaponRayData; float maxRayDist = s_weaponRayData2.maxRayDist; rayHit = Weapon.s_weaponRayData.rayHit; s_weaponRayData2.maxRayDist = maxRayDist - ((RaycastHit)(ref rayHit)).distance; } else { flag = true; FX_Manager.EffectTargetPosition = ((Item)__instance).Owner.FPSCamera.CameraRayPos; } } } else if (Weapon.CastWeaponRay(((ItemEquippable)__instance).MuzzleAlign, ref s_weaponRayData, val, -1)) { BulletWeapon.BulletHit(Weapon.s_weaponRayData, true, 0f, 0u, true); rayHit = Weapon.s_weaponRayData.rayHit; FX_Manager.EffectTargetPosition = ((RaycastHit)(ref rayHit)).point; } else { FX_Manager.EffectTargetPosition = ((Item)__instance).Owner.FPSCamera.CameraRayPos; } FX_Manager.PlayLocalVersion = false; ((FX_EffectBase)BulletWeapon.s_tracerPool.AquireEffect()).Play((FX_Trigger)null, ((ItemEquippable)__instance).MuzzleAlign.position, Quaternion.LookRotation(Weapon.s_weaponRayData.fireDir)); } ((ItemEquippable)__instance).TriggerFireAnimationSequence(); ((Agent)((Item)__instance).Owner).Noise = (NoiseType)8; ((Weapon)__instance).ApplyRecoil(true); EX_SpriteMuzzleFlash muzzleFlash = ((Weapon)__instance).m_muzzleFlash; if ((Object)(object)muzzleFlash != (Object)null) { muzzleFlash.Play(); } if (((ItemEquippable)__instance).ShellCasingData != null) { WeaponShellManager.EjectShell(((ItemEquippable)__instance).ShellCasingData.ShellCasingType, 1f, 1f, ((ItemEquippable)__instance).ShellEjectAlign, Vector3.one, false); } ((ItemEquippable)__instance).FPItemHolder.DontRelax(); ((Item)__instance).Owner.Sync.RegisterFiredBullets(1); for (int j = 0; j < ((ItemEquippable)__instance).m_itemPartAnimators.Count; j++) { ((ItemEquippable)__instance).m_itemPartAnimators[j].CrossFadeInFixedTime("Fire", 0f, 0); } ((BulletWeapon)__instance).m_lastFireTime = Clock.Time; if (((Agent)((Item)__instance).Owner).IsLocallyOwned) { PlayerAgent.LastLocalShotFiredTime = ((BulletWeapon)__instance).m_lastFireTime; } int clip = ((BulletWeapon)__instance).m_clip; ((BulletWeapon)__instance).m_clip = clip - 1; ((BulletWeapon)__instance).UpdateAmmoStatus(); return false; } } public static readonly int PatchPriority = int.MinValue; public override string Name => "子弹穿透修复"; public override string Description => "修正了下列问题\n\n1. 穿透存在上限 --> 解除穿透次数限制\n2. 穿透后扩散增加 --> 穿透后将扩散设为0\n3. 穿透次数代表最多可命中敌人数 --> 穿透次数代表可穿透敌人数"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Fixes", false); public static IArchiveLogger FeatureLogger { get; set; } } [EnableFeatureByDefault] public class DeadBodyFix : Feature { public class DeadBodyFixSettings { [FSDisplayName("预测过期时间")] [FSDescription("本地预测敌人死亡状态保持时间")] [FSTooltip(/*Could not decode attribute arguments.*/)] public float ExpirationTime { get { return s_expirationTime * 1000f; } set { s_expirationTime = value / 1000f; } } [FSHide] [FSDisplayName("阻止特殊部位伤害溢出")] [FSDescription("启用该选项以消除客户端在使用霰弹类与高射速枪械攻击特殊部位的优势\n该选项只影响未启用此功能的玩家\n注意这将会导致溢出的伤害被直接丢弃!!!")] public bool BlockCustomLimbDamageOverflow { get { return s_blockCustomLimbDamageOverflow; } set { s_blockCustomLimbDamageOverflow = value; } } } internal sealed class EnemyDamagePredictionStore { private sealed class EnemyPredictionState { public EnemyAgent Enemy { get; } public Dam_EnemyDamageBase Damage { get; } public LimbPredictionState[] Limbs { get; } public float AuthoritativeHealth { get; private set; } public bool IsAuthorityDead { get; private set; } public bool HasPrediction { get; private set; } public bool IsPredictedDead { get; private set; } public float PredictionExpiresAt { get; private set; } public EnemyPredictionState(EnemyAgent enemy) { Enemy = enemy; Damage = enemy.Damage; Limbs = ((IEnumerable)Damage.DamageLimbs).Select((Dam_EnemyDamageLimb limb) => new LimbPredictionState(limb)).ToArray(); CaptureAuthoritativeFromGame(); } public void CaptureAuthoritativeFromGame() { AuthoritativeHealth = ((Dam_SyncedDamageBase)Damage).Health; for (int i = 0; i < Limbs.Length; i++) { Limbs[i].CaptureAuthoritativeFromGame(); } } public void CaptureAuthoritativeFromGame(int limbID) { AuthoritativeHealth = ((Dam_SyncedDamageBase)Damage).Health; if (TryGetLimb(limbID, out var limbState)) { limbState.CaptureAuthoritativeFromGame(); } } public void MarkPrediction(float expiresAt) { HasPrediction = true; PredictionExpiresAt = expiresAt; } public void MarkPredictedDead() { HasPrediction = true; IsPredictedDead = true; } public void MarkAuthorityDead() { IsAuthorityDead = true; AuthoritativeHealth = 0f; ((Dam_SyncedDamageBase)Damage).Health = 0f; ClearPredictionFlags(); } public void ClearPredictionFlags() { HasPrediction = false; IsPredictedDead = false; PredictionExpiresAt = 0f; for (int i = 0; i < Limbs.Length; i++) { Limbs[i].ClearPredictionFlags(); } } public void RestoreAuthoritative(bool restoreAllLimbs) { ((Dam_SyncedDamageBase)Damage).Health = AuthoritativeHealth; for (int i = 0; i < Limbs.Length; i++) { if (restoreAllLimbs || Limbs[i].HasPrediction) { Limbs[i].RestoreAuthoritative(); } } } public bool TryGetLimb(int limbID, out LimbPredictionState limbState) { limbState = null; if (limbID < 0 || limbID >= Limbs.Length) { return false; } limbState = Limbs[limbID]; return (Object)(object)limbState.Limb != (Object)null; } } private sealed class LimbPredictionState { public Dam_EnemyDamageLimb Limb { get; } public float AuthoritativeHealth { get; private set; } public bool HasPrediction { get; private set; } public bool HasPredictedCustomDestroyed { get; private set; } public LimbPredictionState(Dam_EnemyDamageLimb limb) { Limb = limb; CaptureAuthoritativeFromGame(); } public void CaptureAuthoritativeFromGame() { AuthoritativeHealth = Limb.m_health; } public void MarkPredicted() { HasPrediction = true; } public void MarkPredictedCustomDestroyed() { HasPrediction = true; HasPredictedCustomDestroyed = true; } public void ClearPredictionFlags() { HasPrediction = false; HasPredictedCustomDestroyed = false; } public void RestoreAuthoritative() { Limb.m_health = AuthoritativeHealth; } } private readonly Dictionary _states = new Dictionary(); private readonly CorpsePierceLayerPolicy _layerPolicy; private readonly Func _expirationTimeProvider; public bool MasterHasFullDamageSync { get; set; } public EnemyDamagePredictionStore(CorpsePierceLayerPolicy layerPolicy, Func expirationTimeProvider) { _layerPolicy = layerPolicy; _expirationTimeProvider = expirationTimeProvider; } public void Register(EnemyAgent enemy) { if (CanTrack(enemy)) { _states[((Agent)enemy).GlobalID] = new EnemyPredictionState(enemy); } } public void Forget(EnemyAgent enemy) { if (!((Object)(object)enemy == (Object)null)) { _states.Remove(((Agent)enemy).GlobalID); } } public void ApplyLocalDamagePrediction(EnemyAgent enemy, int limbID, float damageAmount) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Invalid comparison between Unknown and I4 if (damageAmount <= 0f || !TryGetOrRegister(enemy, out var state) || state.IsAuthorityDead) { return; } if (!state.HasPrediction) { state.CaptureAuthoritativeFromGame(); } if (state.TryGetLimb(limbID, out var limbState)) { Dam_EnemyDamageLimb limb = limbState.Limb; bool num = (int)limb.DestructionType == 1 && limb.IsDestroyed; bool flag = limb.DoDamage(damageAmount); limbState.MarkPredicted(); bool flag2 = (int)limb.DestructionType == 1 && (limb.IsDestroyed || limb.m_health < 0f || flag); if (!num && flag2) { limbState.MarkPredictedCustomDestroyed(); _layerPolicy.MarkPredictedCustomLimbDestroyed(limb); } } ((Dam_SyncedDamageBase)state.Damage).RegisterDamage(damageAmount); state.MarkPrediction(Time.unscaledTime + _expirationTimeProvider()); if (((Dam_SyncedDamageBase)state.Damage).Health <= 0f) { state.MarkPredictedDead(); _layerPolicy.MarkEnemyPredictedDead(enemy); } } public void ApplyAuthoritativeDamage(EnemyAgent enemy, pFullEnemyReceivedDamageData data) { if (!TryGetOrRegister(enemy, out var state)) { return; } if (data.isKill) { ApplyAuthoritativeDeath(enemy); return; } state.CaptureAuthoritativeFromGame(data.limbID); if (MasterHasFullDamageSync) { state.RestoreAuthoritative(restoreAllLimbs: false); } _layerPolicy.ClearEnemyPredictedDead(enemy); _layerPolicy.ClearPredictedCustomLimbDestroyed(enemy); state.ClearPredictionFlags(); } public void ApplyAuthoritativeDeath(EnemyAgent enemy) { if (TryGetOrRegister(enemy, out var state)) { state.MarkAuthorityDead(); _layerPolicy.ClearEnemyPredictedDead(enemy); _layerPolicy.MarkEnemyConfirmedDead(enemy); } } public void ApplyAuthoritativeLimbDestroyed(Dam_EnemyDamageLimb limb) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 if ((Object)(object)limb == (Object)null || (Object)(object)limb.m_base == (Object)null || (Object)(object)limb.m_base.Owner == (Object)null) { return; } EnemyAgent owner = limb.m_base.Owner; if (TryGetOrRegister(owner, out var state) && state.TryGetLimb(limb.m_limbID, out var limbState)) { limbState.CaptureAuthoritativeFromGame(); limbState.ClearPredictionFlags(); if ((int)limb.DestructionType == 1) { _layerPolicy.ConfirmCustomLimbDestroyed(limb); } } } public void CheckExpiration(EnemyAgent enemy) { if (!((Object)(object)enemy == (Object)null) && _states.TryGetValue(((Agent)enemy).GlobalID, out var value) && value.HasPrediction && !value.IsAuthorityDead && !(Time.unscaledTime <= value.PredictionExpiresAt)) { if (MasterHasFullDamageSync || value.IsPredictedDead) { value.RestoreAuthoritative(MasterHasFullDamageSync); _layerPolicy.ClearEnemyPredictedDead(enemy); } _layerPolicy.ClearPredictedCustomLimbDestroyed(enemy); value.ClearPredictionFlags(); } } public void RestoreAll() { foreach (EnemyPredictionState value in _states.Values) { if (value.HasPrediction && !value.IsAuthorityDead) { value.RestoreAuthoritative(restoreAllLimbs: true); } } _states.Clear(); } private bool TryGetOrRegister(EnemyAgent enemy, out EnemyPredictionState state) { state = null; if (!CanTrack(enemy)) { return false; } if (!_states.TryGetValue(((Agent)enemy).GlobalID, out state)) { state = new EnemyPredictionState(enemy); _states.Add(((Agent)enemy).GlobalID, state); } return true; } private static bool CanTrack(EnemyAgent enemy) { if ((Object)(object)enemy != (Object)null && (Object)(object)enemy.Damage != (Object)null) { return enemy.Damage.DamageLimbs != null; } return false; } } internal static class EnemyDamageEstimator { public static float EstimateBulletDamage(Dam_EnemyDamageBase damageBase, float rawDamage) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)damageBase == (Object)null || (Object)(object)damageBase.Owner == (Object)null) { return 0f; } pFullDamageData val = default(pFullDamageData); ((UFloat16)(ref val.damage)).Set(rawDamage, ((Dam_SyncedDamageBase)damageBase).HealthMax); return AgentModifierManager.ApplyModifier((Agent)(object)damageBase.Owner, (AgentModifier)7, ((UFloat16)(ref val.damage)).Get(((Dam_SyncedDamageBase)damageBase).HealthMax)); } public static float EstimateMeleeDamage(Dam_EnemyDamageBase damageBase, float rawDamage) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)damageBase == (Object)null || (Object)(object)damageBase.Owner == (Object)null) { return 0f; } pFullDamageData val = default(pFullDamageData); ((UFloat16)(ref val.damage)).Set(rawDamage, ((Dam_SyncedDamageBase)damageBase).DamageMax); float num = Dam_EnemyDamageBase.RoundDamage(((UFloat16)(ref val.damage)).Get(((Dam_SyncedDamageBase)damageBase).DamageMax)); return AgentModifierManager.ApplyModifier((Agent)(object)damageBase.Owner, (AgentModifier)6, num); } } internal sealed class CorpsePierceLayerPolicy { [Flags] private enum LimbLayerOverrideReason { None = 0, PredictedDead = 1, ConfirmedDead = 2, PredictedCustomLimbDestroyed = 4, CustomLimbDestroyed = 8 } private sealed class LimbLayerOverride { public Dam_EnemyDamageLimb Limb { get; } public int LimbID { get; } public int OriginalLayer { get; } public LimbLayerOverrideReason Reasons { get; private set; } public LimbLayerOverride(Dam_EnemyDamageLimb limb, int limbID) { Limb = limb; LimbID = limbID; OriginalLayer = ((Component)limb).gameObject.layer; Reasons = LimbLayerOverrideReason.None; } public void AddReason(LimbLayerOverrideReason reason) { Reasons |= reason; } public void RemoveReason(LimbLayerOverrideReason reason) { Reasons &= ~reason; } public void SetReasons(LimbLayerOverrideReason reasons) { Reasons = reasons; } } private readonly Dictionary> _enemyOverrides = new Dictionary>(); private int _originalPiercingMask; private bool _hasOriginalPiercingMask; public void ApplyPiercingMask(LayerManager layerManager) { if (!((Object)(object)layerManager == (Object)null)) { if (!_hasOriginalPiercingMask) { _originalPiercingMask = LayerManager.MASK_BULLETWEAPON_PIERCING_PASS; _hasOriginalPiercingMask = true; } LayerManager.MASK_BULLETWEAPON_PIERCING_PASS = _originalPiercingMask | (1 << LayerManager.LAYER_ENEMY_DEAD); } } public void MarkEnemyPredictedDead(EnemyAgent enemy) { AddEnemyReason(enemy, LimbLayerOverrideReason.PredictedDead); } public void ClearEnemyPredictedDead(EnemyAgent enemy) { RemoveEnemyReason(enemy, LimbLayerOverrideReason.PredictedDead); } public void MarkEnemyConfirmedDead(EnemyAgent enemy) { AddEnemyReason(enemy, LimbLayerOverrideReason.ConfirmedDead); } public void MarkPredictedCustomLimbDestroyed(Dam_EnemyDamageLimb limb) { AddLimbReason(limb, LimbLayerOverrideReason.PredictedCustomLimbDestroyed); } public void ConfirmCustomLimbDestroyed(Dam_EnemyDamageLimb limb) { RemoveLimbReason(limb, LimbLayerOverrideReason.PredictedCustomLimbDestroyed); AddLimbReason(limb, LimbLayerOverrideReason.CustomLimbDestroyed); } public void ClearPredictedCustomLimbDestroyed(EnemyAgent enemy) { RemoveEnemyReason(enemy, LimbLayerOverrideReason.PredictedCustomLimbDestroyed); } public void Forget(EnemyAgent enemy) { if (!((Object)(object)enemy == (Object)null)) { _enemyOverrides.Remove(((Agent)enemy).GlobalID); } } public void RestoreEnemy(EnemyAgent enemy) { if ((Object)(object)enemy == (Object)null || !_enemyOverrides.TryGetValue(((Agent)enemy).GlobalID, out var value)) { return; } foreach (LimbLayerOverride item in value) { RestoreLayer(item); } _enemyOverrides.Remove(((Agent)enemy).GlobalID); } public void RestoreAll() { foreach (List value in _enemyOverrides.Values) { foreach (LimbLayerOverride item in value) { RestoreLayer(item); } } _enemyOverrides.Clear(); if (_hasOriginalPiercingMask) { LayerManager.MASK_BULLETWEAPON_PIERCING_PASS = _originalPiercingMask; _hasOriginalPiercingMask = false; } } private void AddEnemyReason(EnemyAgent enemy, LimbLayerOverrideReason reason) { if (!TryGetDamage(enemy, out var damage)) { return; } foreach (Dam_EnemyDamageLimb item in (Il2CppArrayBase)(object)damage.DamageLimbs) { AddLimbReason(item, reason); } } private void RemoveEnemyReason(EnemyAgent enemy, LimbLayerOverrideReason reason) { if ((Object)(object)enemy == (Object)null || !_enemyOverrides.TryGetValue(((Agent)enemy).GlobalID, out var value)) { return; } for (int num = value.Count - 1; num >= 0; num--) { LimbLayerOverride limbLayerOverride = value[num]; limbLayerOverride.RemoveReason(reason); ApplyOverrideState(limbLayerOverride); if (limbLayerOverride.Reasons == LimbLayerOverrideReason.None) { value.RemoveAt(num); } } if (value.Count == 0) { _enemyOverrides.Remove(((Agent)enemy).GlobalID); } } private void AddLimbReason(Dam_EnemyDamageLimb limb, LimbLayerOverrideReason reason) { if (TryGetLimbIdentity(limb, out var enemyGlobalID, out var limbID)) { LimbLayerOverride orCreateOverride = GetOrCreateOverride(limb, enemyGlobalID, limbID); orCreateOverride.AddReason(reason); ApplyOverrideState(orCreateOverride); } } private void RemoveLimbReason(Dam_EnemyDamageLimb limb, LimbLayerOverrideReason reason) { if (!TryGetLimbIdentity(limb, out var enemyGlobalID, out var limbID) || !_enemyOverrides.TryGetValue(enemyGlobalID, out var value)) { return; } for (int num = value.Count - 1; num >= 0; num--) { LimbLayerOverride limbLayerOverride = value[num]; if (limbLayerOverride.LimbID == limbID) { limbLayerOverride.RemoveReason(reason); ApplyOverrideState(limbLayerOverride); if (limbLayerOverride.Reasons == LimbLayerOverrideReason.None) { value.RemoveAt(num); } break; } } if (value.Count == 0) { _enemyOverrides.Remove(enemyGlobalID); } } private LimbLayerOverride GetOrCreateOverride(Dam_EnemyDamageLimb limb, int enemyGlobalID, int limbID) { if (!_enemyOverrides.TryGetValue(enemyGlobalID, out var value)) { value = new List(); _enemyOverrides.Add(enemyGlobalID, value); } for (int i = 0; i < value.Count; i++) { LimbLayerOverride limbLayerOverride = value[i]; if (limbLayerOverride.LimbID == limbID) { if ((Object)(object)limbLayerOverride.Limb == (Object)(object)limb) { return limbLayerOverride; } LimbLayerOverride limbLayerOverride2 = new LimbLayerOverride(limb, limbID); limbLayerOverride2.SetReasons(limbLayerOverride.Reasons); RestoreLayer(limbLayerOverride); value[i] = limbLayerOverride2; return limbLayerOverride2; } } LimbLayerOverride limbLayerOverride3 = new LimbLayerOverride(limb, limbID); value.Add(limbLayerOverride3); return limbLayerOverride3; } private static void ApplyOverrideState(LimbLayerOverride layerOverride) { if (!((Object)(object)layerOverride.Limb == (Object)null) && !((Object)(object)((Component)layerOverride.Limb).gameObject == (Object)null)) { ((Component)layerOverride.Limb).gameObject.layer = ((layerOverride.Reasons == LimbLayerOverrideReason.None) ? layerOverride.OriginalLayer : LayerManager.LAYER_ENEMY_DEAD); } } private static void RestoreLayer(LimbLayerOverride layerOverride) { if (!((Object)(object)layerOverride.Limb == (Object)null) && !((Object)(object)((Component)layerOverride.Limb).gameObject == (Object)null)) { ((Component)layerOverride.Limb).gameObject.layer = layerOverride.OriginalLayer; } } private static bool TryGetDamage(EnemyAgent enemy, out Dam_EnemyDamageBase damage) { damage = null; if ((Object)(object)enemy == (Object)null || (Object)(object)enemy.Damage == (Object)null) { return false; } damage = enemy.Damage; return true; } private static bool TryGetLimbIdentity(Dam_EnemyDamageLimb limb, out int enemyGlobalID, out int limbID) { enemyGlobalID = 0; limbID = -1; if ((Object)(object)limb == (Object)null || (Object)(object)limb.m_base == (Object)null || (Object)(object)limb.m_base.Owner == (Object)null) { return false; } enemyGlobalID = ((Agent)limb.m_base.Owner).GlobalID; limbID = limb.m_limbID; return true; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class LayerManager__Setup__Patch { private static void Postfix(LayerManager __instance) { s_layerPolicy.ApplyPiercingMask(__instance); LayerManager.MASK_MELEE_ATTACK_TARGETS_WITH_STATIC = __instance.GetMask(new string[5] { "EnemyDamagable", "Dynamic", "Default", "Default_NoGraph", "Default_BlockGraph" }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class EnemyAgent__UpdateEmemyAgent__Patch { private static void Postfix(EnemyAgent __instance) { s_predictionStore.CheckExpiration(__instance); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__BulletDamage__Patch { private static Type[] ParameterTypes() { return new Type[10] { typeof(float), typeof(Agent), typeof(Vector3), typeof(Vector3), typeof(Vector3), typeof(bool), typeof(int), typeof(float), typeof(float), typeof(uint) }; } private static void Postfix(Dam_EnemyDamageBase __instance, float dam, int limbID) { if (!SNet.IsMaster && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.Owner == (Object)null)) { float damageAmount = EnemyDamageEstimator.EstimateBulletDamage(__instance, dam); s_predictionStore.ApplyLocalDamagePrediction(__instance.Owner, limbID, damageAmount); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__MeleeDamage__Patch { private static Type[] ParameterTypes() { return new Type[12] { typeof(float), typeof(Agent), typeof(Vector3), typeof(Vector3), typeof(int), typeof(float), typeof(float), typeof(float), typeof(float), typeof(bool), typeof(DamageNoiseLevel), typeof(uint) }; } private static void Postfix(Dam_EnemyDamageBase __instance, float dam, int limbID) { if (!SNet.IsMaster && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.Owner == (Object)null)) { float damageAmount = EnemyDamageEstimator.EstimateMeleeDamage(__instance, dam); s_predictionStore.ApplyLocalDamagePrediction(__instance.Owner, limbID, damageAmount); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ReceiveBulletDamage__Patch { private static void Prefix(Dam_EnemyDamageBase __instance, ref pBulletDamageData data) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 if (SNet.IsMaster && s_blockCustomLimbDamageOverflow) { Dam_EnemyDamageLimb val = ((Il2CppArrayBase)(object)__instance.DamageLimbs)[(int)data.limbID]; if ((int)val.DestructionType == 1 && val.IsDestroyed) { ((UFloat16)(ref data.damage)).Set(0f, ((Dam_SyncedDamageBase)__instance).HealthMax); } } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ReceiveMeleeDamage__Patch { private static void Prefix(Dam_EnemyDamageBase __instance, ref pFullDamageData data) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 if (SNet.IsMaster && s_blockCustomLimbDamageOverflow) { Dam_EnemyDamageLimb val = ((Il2CppArrayBase)(object)__instance.DamageLimbs)[(int)data.limbID]; if ((int)val.DestructionType == 1 && val.IsDestroyed) { ((UFloat16)(ref data.damage)).Set(0f, ((Dam_SyncedDamageBase)__instance).DamageMax); } } } } private static float s_expirationTime = 0.2f; private static bool s_blockCustomLimbDamageOverflow = true; private static readonly CorpsePierceLayerPolicy s_layerPolicy = new CorpsePierceLayerPolicy(); private static readonly EnemyDamagePredictionStore s_predictionStore = new EnemyDamagePredictionStore(s_layerPolicy, () => s_expirationTime); public override string Name => "敌人尸体穿透修复"; public override string Description => "使攻击可以穿透敌人的尸体"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Fixes", false); public static IArchiveLogger FeatureLogger { get; set; } [FeatureConfig] public static DeadBodyFixSettings Settings { get; set; } public override void OnEnable() { EnemyAPI.OnEnemyReceivedDamage += OnEnemyReceivedDamage; EnemyAPI.OnEnemyLimbDestroyed += OnEnemyLimbDestroyed; EnemyAPI.OnEnemyDead += OnEnemyDead; EnemyAPI.OnEnemySpawned += OnEnemySpawned; SNetEventAPI.OnMasterChanged += OnMasterChanged; CoreAPI.OnPlayerModsSynced += OnPlayerModsSynced; UpdateMasterDamageSyncState(); if (Feature.CurrentGameState != 10) { return; } foreach (EnemyAgent item in Object.FindObjectsOfType()) { s_predictionStore.Register(item); } } public override void OnDisable() { EnemyAPI.OnEnemyReceivedDamage -= OnEnemyReceivedDamage; EnemyAPI.OnEnemyLimbDestroyed -= OnEnemyLimbDestroyed; EnemyAPI.OnEnemyDead -= OnEnemyDead; EnemyAPI.OnEnemySpawned -= OnEnemySpawned; SNetEventAPI.OnMasterChanged -= OnMasterChanged; CoreAPI.OnPlayerModsSynced -= OnPlayerModsSynced; s_predictionStore.RestoreAll(); s_layerPolicy.RestoreAll(); } private void OnMasterChanged() { UpdateMasterDamageSyncState(); } private void OnPlayerModsSynced(SNet_Player player, IEnumerable mods) { UpdateMasterDamageSyncState(); } private static void UpdateMasterDamageSyncState() { s_predictionStore.MasterHasFullDamageSync = CoreAPI.IsPlayerInstalledCore(SNet.Master); } private void OnEnemyReceivedDamage(EnemyAgent enemy, pFullEnemyReceivedDamageData data) { s_predictionStore.ApplyAuthoritativeDamage(enemy, data); } private void OnEnemySpawned(EnemyAgent enemy) { s_predictionStore.Register(enemy); } private void OnEnemyLimbDestroyed(Dam_EnemyDamageLimb limb) { s_predictionStore.ApplyAuthoritativeLimbDestroyed(limb); } private void OnEnemyDead(EnemyAgent enemy) { s_predictionStore.ApplyAuthoritativeDeath(enemy); s_predictionStore.Forget(enemy); s_layerPolicy.Forget(enemy); } } [HideInModSettings] [EnableFeatureByDefault] [DoNotSaveToConfig] [DisallowInGameToggle] internal class EnemyDamageDoDamageFix : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ReceiveBulletDamage__Patch { private static bool Prefix(Dam_EnemyDamageBase __instance, pBulletDamageData data) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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) //IL_0085: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance.Owner == (Object)null || !((Agent)__instance.Owner).Alive || __instance.IsImortal) { return false; } float num = AgentModifierManager.ApplyModifier((Agent)(object)__instance.Owner, (AgentModifier)7, ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax)); ES_HitreactType val = (ES_HitreactType)3; bool flag = false; bool num2 = ((Dam_SyncedDamageBase)__instance).WillDamageKill(num); CD_DestructionSeverity val2; if (num2) { flag = true; val = (ES_HitreactType)4; val2 = (CD_DestructionSeverity)3; } else { val2 = (CD_DestructionSeverity)2; } Vector3 value = ((LowResVector3_Normalized)(ref data.direction)).Value; Vector3 val3 = ((LowResVector3)(ref data.localPosition)).Get(10f); Vector3 val4 = val3 + __instance.Owner.Position; Dam_EnemyDamageLimb val5 = ((Il2CppArrayBase)(object)__instance.DamageLimbs)[(int)data.limbID]; bool flag2 = val5.DoDamage(num); if (num2 || flag2) { __instance.CheckDestruction(val5, ref val3, ref value, (int)data.limbID, ref val2, ref flag, ref val); } Agent val6 = default(Agent); ((pAgent)(ref data.source)).TryGet(ref val6); __instance.ProcessReceivedDamage(num, val6, val4, value, val, flag, (int)data.limbID, ((UFloat16)(ref data.staggerMulti)).Get(10f), (DamageNoiseLevel)0, data.gearCategoryId); return false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ReceiveMeleeDamage__Patch { private static bool Prefix(Dam_EnemyDamageBase __instance, pFullDamageData data) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance.Owner == (Object)null || !((Agent)__instance.Owner).Alive || __instance.IsImortal) { return false; } float num = AgentModifierManager.ApplyModifier((Agent)(object)__instance.Owner, (AgentModifier)6, Dam_EnemyDamageBase.RoundDamage(((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).DamageMax))); bool num2 = ((Dam_SyncedDamageBase)__instance).WillDamageKill(num); ES_HitreactType val = (ES_HitreactType)(data.skipLimbDestruction ? 1 : 0); bool flag = false; CD_DestructionSeverity val2; if (num2) { flag = true; val = (ES_HitreactType)4; val2 = (CD_DestructionSeverity)3; } else { val2 = (CD_DestructionSeverity)2; } Vector3 value = ((LowResVector3_Normalized)(ref data.direction)).Value; Vector3 val3 = ((LowResVector3)(ref data.localPosition)).Get(10f); Vector3 val4 = val3 + __instance.Owner.Position; Dam_EnemyDamageLimb val5 = ((Il2CppArrayBase)(object)__instance.DamageLimbs)[(int)data.limbID]; bool flag2 = val5.DoDamage(num); if ((num2 || flag2) && !data.skipLimbDestruction) { __instance.CheckDestruction(val5, ref val3, ref value, (int)data.limbID, ref val2, ref flag, ref val); } Agent val6 = default(Agent); ((pAgent)(ref data.source)).TryGet(ref val6); if (__instance.ProcessReceivedDamage(num, val6, val4, value, val, flag, (int)data.limbID, ((UFloat16)(ref data.staggerMulti)).Get(10f), (DamageNoiseLevel)data.damageNoiseLevel, data.gearCategoryId)) { GameEventManager.PostEvent((eGameEvent)(__instance.Owner.IsScout ? 25 : 26), (PlayerAgent)null, 0f, string.Empty, (Dictionary)null); } return false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ReceiveExplosionDamage__Patch { private static bool Prefix(Dam_EnemyDamageBase __instance, pExplosionDamageData data) { //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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance.Owner == (Object)null || !((Agent)__instance.Owner).Alive || __instance.IsImortal) { return false; } Vector3 val = ((LowResVector3)(ref data.force)).Get(10f); Vector3 normalized = ((Vector3)(ref val)).normalized; ES_HitreactType val2 = (ES_HitreactType)3; bool flag = false; float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).HealthMax); num = AgentModifierManager.ApplyModifier((Agent)(object)__instance.Owner, (AgentModifier)12, num); bool flag2 = ((Dam_SyncedDamageBase)__instance).WillDamageKill(num); CD_DestructionSeverity val3; if (flag2) { flag = true; val2 = (ES_HitreactType)4; val3 = (CD_DestructionSeverity)3; } else { val3 = (CD_DestructionSeverity)2; } Vector3 val4 = ((LowResVector3)(ref data.localPosition)).Get(10f); int num2 = 0; if (__instance.DamageLimbsWithDestruction != null && __instance.DamageLimbsWithDestruction.Count > 0) { num2 = Random.Range(0, __instance.DamageLimbsWithDestruction.Count); Dam_EnemyDamageLimb val5 = __instance.DamageLimbsWithDestruction[num2]; bool flag3 = val5.DoDamage(num); if (flag2 || flag3) { __instance.CheckDestruction(val5, ref val4, ref normalized, num2, ref val3, ref flag, ref val2); } } else { ((Il2CppArrayBase)(object)__instance.DamageLimbs)[num2].DoDamage(num); } Vector3 val6 = val4 + __instance.Owner.Position; __instance.ProcessReceivedDamage(num, (Agent)(object)PlayerManager.Current.m_localPlayerAgentInLevel, val6, val, val2, flag, num2, 0f, (DamageNoiseLevel)0, data.gearCategoryId); return false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ReceivePushDamage__Patch { private static void Postfix(Dam_EnemyDamageBase __instance, pFullDamageData data) { if (!((Object)(object)__instance.Owner == (Object)null) && ((Agent)__instance.Owner).Alive && (__instance.IsImortal || !__instance.Owner.EnemyBalancingData.CanBePushed)) { Agent val = default(Agent); ((pAgent)(ref data.source)).TryGet(ref val); ((Agent)__instance.Owner).RegisterDamageInflictor(val); } } } public override string Name => "敌人受到伤害修复"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Fixes", false); } [EnableFeatureByDefault] internal class KillIndicatorFix : Feature { public override string Name => "击杀标记修复"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Fixes", false); public override void OnEnable() { EnemyAPI.OnEnemyReceivedDamage += OnEnemyReceivedDamage; } public override void OnDisable() { EnemyAPI.OnEnemyReceivedDamage -= OnEnemyReceivedDamage; } private static void OnEnemyReceivedDamage(EnemyAgent enemy, pFullEnemyReceivedDamageData data) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Agent val = default(Agent); if (!SNet.IsMaster && ((pAgent)(ref data.damageSource)).TryGet(ref val) && val.IsLocallyOwned) { if (data.isKill && !enemy.Damage.DeathIndicatorShown) { GuiManager.CrosshairLayer.ShowDeathIndicator(data.position); enemy.Damage.DeathIndicatorShown = true; } else if (data.damageTraceFlags.HasFlag(DamageTraceFlags.SentryGun)) { Dam_EnemyDamageLimb val2 = ((Il2CppArrayBase)(object)enemy.Damage.DamageLimbs)[data.limbID]; val2.ShowHitIndicator((int)val2.m_type == 1, data.isKill, data.position, val2.m_armorDamageMulti < 1f); } } } } [EnableFeatureByDefault] internal class LobbyGhostPlayerFix : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_PlayerSlotManager__SetSlotPermission__Patch { private static void Postfix(SNet_PlayerSlotManager __instance, int playerIndex, SlotPermission permission) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if (SNet.IsMaster && (int)permission == 1) { CleanupForPlayer(((Il2CppArrayBase)(object)__instance.PlayerSlots)[playerIndex].player); } } } public override string Name => "卡房修复"; public override string Description => "在玩家离开大厅时自动检查是否有位置被卡\n可通过锁定位置的方法手动修复特定位置被卡的问题"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Fixes", false); public override void OnEnable() { SNetEventAPI.OnSessionMemberChanged += OnSessionMemberChanged; } public override void OnDisable() { SNetEventAPI.OnSessionMemberChanged -= OnSessionMemberChanged; } public void OnSessionMemberChanged(SNet_Player player, SessionMemberEvent playerEvent) { if (SNet.IsMaster && !player.IsLocal && playerEvent == SessionMemberEvent.LeftSessionHub && CheckNeedCleanup(player)) { CleanupForPlayer(player); } } private static bool CheckNeedCleanup(SNet_Player player) { if ((Object)(object)player == (Object)null) { return false; } SNet_PlayerSlotManager slots = SNet.Slots; for (int i = 0; i < ((Il2CppArrayBase)(object)slots.CharacterSlots).Count; i++) { SNet_Slot val = ((Il2CppArrayBase)(object)slots.CharacterSlots)[i]; if ((Object)(object)val.player != (Object)null && val.player.Lookup == player.Lookup) { return true; } } for (int j = 0; j < ((Il2CppArrayBase)(object)slots.PlayerSlots).Count; j++) { SNet_Slot val2 = ((Il2CppArrayBase)(object)slots.PlayerSlots)[j]; if ((Object)(object)val2.player != (Object)null && val2.player.Lookup == player.Lookup) { return true; } } for (int k = 0; k < SNet.Lobby.Players.Count; k++) { if (SNet.Lobby.Players[k].Lookup == player.Lookup) { return true; } } return false; } private static void CleanupForPlayer(SNet_Player player) { if ((Object)(object)player == (Object)null) { return; } SNet_PlayerSlotManager slots = SNet.Slots; SNet.Sync.KickPlayer(player, (SNet_PlayerEventReason)1); for (int i = 0; i < ((Il2CppArrayBase)(object)slots.CharacterSlots).Count; i++) { SNet_Slot val = ((Il2CppArrayBase)(object)slots.CharacterSlots)[i]; if ((Object)(object)val.player != (Object)null && val.player.Lookup == player.Lookup) { slots.Internal_ManageSlot(player, ref val, slots.CharacterSlots, (SNet_SlotType)1, (SNet_SlotHandleType)2, -1); } } for (int j = 0; j < ((Il2CppArrayBase)(object)slots.PlayerSlots).Count; j++) { SNet_Slot val2 = ((Il2CppArrayBase)(object)slots.PlayerSlots)[j]; if ((Object)(object)val2.player != (Object)null && val2.player.Lookup == player.Lookup) { slots.Internal_ManageSlot(player, ref val2, slots.PlayerSlots, (SNet_SlotType)0, (SNet_SlotHandleType)2, -1); } } SNet.Lobby.Players.RemoveAll(Predicate.op_Implicit((Func)((SNet_Player p) => p.Lookup == player.Lookup))); } } } namespace Hikaria.Core.Features.Dev { [EnableFeatureByDefault] [DisallowInGameToggle] [HideInModSettings] [DoNotSaveToConfig] internal class CoreAPI_Impl : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Player__SendAllCustomData__Patch { private static void Postfix(SNet_Player __instance, SNet_Player toPlayer) { SNetExt.SendAllCustomData(__instance, toPlayer); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Core_STEAM__CreateLocalPlayer__Patch { private static void Postfix() { SNetExt.SetLocalCustomData(new pModList(SNet.LocalPlayer, InstalledMods.Values)); } } public static Dictionary InstalledMods = new Dictionary(); public static Dictionary> OthersMods = new Dictionary>(); public override string Name => "CoreAPI Impl"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Developer", true); public static event CoreAPI.PlayerModsSynced OnPlayerModsSynced; public override void Init() { SNetExt.SetupCustomData(typeof(pModList).FullName, ReceiveModListData); ArchiveModuleChainloader.Instance.Finished += OnChainloaderFinished; SNetEventAPI.OnSessionMemberChanged += OnSessionMemberChanged; } private void ReceiveModListData(SNet_Player player, pModList data) { if (player.IsLocal || player.IsBot) { return; } if (!OthersMods.ContainsKey(player.Lookup)) { OthersMods[player.Lookup] = new Dictionary(); } else { OthersMods[player.Lookup].Clear(); } for (int i = 0; i < data.ModCount; i++) { pModInfo value = data.Mods[i]; if (!string.IsNullOrWhiteSpace(value.GUID)) { OthersMods[player.Lookup][value.GUID] = value; } } Utils.SafeInvoke(CoreAPI_Impl.OnPlayerModsSynced, new object[2] { player, data.Mods.Take(data.ModCount) }); } private void OnPluginLoaded(PluginInfo pluginInfo) { BepInPlugin metadata = pluginInfo.Metadata; Version version = pluginInfo.Metadata.Version; Version version2 = new Version(version.Major, version.Minor, version.Patch); InstalledMods[metadata.GUID] = new pModInfo(metadata.Name, metadata.GUID, version2); } private void OnModuleLoaded(ModuleInfo moduleInfo) { ArchiveModule metadata = moduleInfo.Metadata; Version version = moduleInfo.Metadata.Version; Version version2 = new Version(version.Major, version.Minor, version.Patch); InstalledMods[metadata.GUID] = new pModInfo(metadata.Name, metadata.GUID, version2); } private void OnChainloaderFinished() { InstalledMods.Clear(); foreach (KeyValuePair plugin in ((BaseChainloader)(object)IL2CPPChainloader.Instance).Plugins) { BepInPlugin metadata = plugin.Value.Metadata; Version version = metadata.Version; Version version2 = new Version(version.Major, version.Minor, version.Patch); InstalledMods[metadata.GUID] = new pModInfo(metadata.Name, metadata.GUID, version2); } foreach (KeyValuePair module in ArchiveModuleChainloader.Instance.Modules) { ArchiveModule metadata2 = module.Value.Metadata; Version version3 = metadata2.Version; Version version4 = new Version(version3.Major, version3.Minor, version3.Patch); InstalledMods[metadata2.GUID] = new pModInfo(metadata2.Name, metadata2.GUID, version4); } ((BaseChainloader)(object)IL2CPPChainloader.Instance).PluginLoaded += OnPluginLoaded; ArchiveModuleChainloader.Instance.ModuleLoaded += OnModuleLoaded; } public void OnSessionMemberChanged(SNet_Player player, SessionMemberEvent playerEvent) { if (!player.IsBot && playerEvent == SessionMemberEvent.LeftSessionHub) { if (player.IsLocal) { OthersMods.Clear(); } else { OthersMods.Remove(player.Lookup); } } } } [EnableFeatureByDefault] [DisallowInGameToggle] [HideInModSettings] [DoNotSaveToConfig] internal class CoreBootstrap : Feature { private const string CompsObjName = "Hikaria.Core.Comps"; private static GameObject _compsObj; public override string Name => "核心引导"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Developer", true); public override void Init() { ClassInjector.RegisterTypeInIl2CppWithInterfaces(false, new Type[1] { typeof(IInteractable) }); ClassInjector.RegisterTypeInIl2Cpp(false); ClassInjector.RegisterTypeInIl2Cpp(false); ClassInjector.RegisterTypeInIl2Cpp(false); ClassInjector.RegisterTypeInIl2Cpp(false); } public override void OnGameDataInitialized() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)_compsObj == (Object)null) { _compsObj = new GameObject("Hikaria.Core.Comps"); Object.DontDestroyOnLoad((Object)(object)_compsObj); } if ((Object)(object)_compsObj.GetComponent() == (Object)null) { _compsObj.AddComponent(); } if ((Object)(object)_compsObj.GetComponent() == (Object)null) { _compsObj.AddComponent(); } PopupMessageManager.Setup(); } } [EnableFeatureByDefault] [DisallowInGameToggle] [DoNotSaveToConfig] [HideInModSettings] internal class EnemyAPI_Impl : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageLimb__DestroyLimb__Patch { private static void Postfix(Dam_EnemyDamageLimb __instance) { Utils.SafeInvoke>(EnemyAPI_Impl.OnEnemyLimbDestroyed, new object[1] { __instance }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageLimb_Custom__DestroyLimb__Patch { private static void Postfix(Dam_EnemyDamageLimb_Custom __instance) { Utils.SafeInvoke>(EnemyAPI_Impl.OnEnemyLimbDestroyed, new object[1] { __instance }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class EnemyAgent__OnDead__Patch { private static void Prefix(EnemyAgent __instance) { Utils.SafeInvoke>(EnemyAPI_Impl.OnEnemyDead, new object[1] { __instance }); } private static void Postfix(EnemyAgent __instance) { Utils.SafeInvoke>(EnemyAPI_Impl.OnPostEnemyDead, new object[1] { __instance }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class EnemySync__OnSpawn__Patch { private static void Postfix(EnemySync __instance) { Utils.SafeInvoke>(EnemyAPI_Impl.OnEnemySpawned, new object[1] { __instance.m_agent }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class EnemySync__OnDespawn__Patch { private static void Prefix(EnemySync __instance) { Utils.SafeInvoke>(EnemyAPI_Impl.OnEnemyDespawn, new object[1] { __instance.m_agent }); } private static void Postfix(EnemySync __instance) { Utils.SafeInvoke>(EnemyAPI_Impl.OnEnemyDespawnd, new object[1] { __instance.m_agent }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class ES_HitreactBase__set_CurrentReactionType__Patch { private static void Postfix(ES_HitreactBase __instance, ES_HitreactType value) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if (Feature.CurrentGameState == 10 && (int)value == 5) { Utils.SafeInvoke>(EnemyAPI_Impl.OnEnemyDead, new object[1] { ((ES_Base)__instance).m_enemyAgent }); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SentryGunInstance_Firing_Bullets__FireBullet__Patch { private static void Prefix(SentryGunInstance_Firing_Bullets __instance) { iSentrygunInstanceCore core = __instance.m_core; s_tempGearIDRange = ((core != null) ? core.GearIDRange : null); s_damageSourceFlags |= DamageTraceFlags.SentryGun; } private static void Postfix() { s_damageSourceFlags &= (DamageTraceFlags)4294967231u; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ReceiveBulletDamage__Patch { private static void Prefix(Dam_EnemyDamageBase __instance) { s_damageSourceFlags |= DamageTraceFlags.Bullet; } private static void Postfix() { s_damageSourceFlags &= (DamageTraceFlags)4294967294u; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ReceiveMeleeDamage__Patch { private static void Prefix() { s_damageSourceFlags |= DamageTraceFlags.Melee; } private static void Postfix() { s_damageSourceFlags &= (DamageTraceFlags)4294967293u; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ReceiveExplosionDamage__Patch { private static void Prefix() { s_damageSourceFlags |= DamageTraceFlags.Explosion; } private static void Postfix() { s_damageSourceFlags &= (DamageTraceFlags)4294967291u; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageBase__ProcessReceivedDamage__Patch { private static void Postfix(Dam_EnemyDamageBase __instance, bool __result, float damage, Agent damageSource, Vector3 position, Vector3 direction, ES_HitreactType hitreact, bool tryForceHitreact = false, int limbID = -1, float staggerDamageMulti = 1f, DamageNoiseLevel damageNoiseLevel = 0, uint gearCategoryId = 0u) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected I4, but got Unknown //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Invalid comparison between Unknown and I4 //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Invalid comparison between Unknown and I4 //IL_0143: Unknown result type (might be due to invalid IL or missing references) if (!SNet.IsMaster) { return; } if (!__result) { if (limbID >= 0) { Dam_EnemyDamageLimb limb = ((Il2CppArrayBase)(object)__instance.DamageLimbs)[limbID]; SendEnemyHealth(__instance.Owner, limb); } SendEnemyHealth(__instance.Owner); } if ((Object)(object)damageSource != (Object)null) { DamageTraceFlags s_damageSourceFlags = EnemyAPI_Impl.s_damageSourceFlags; AgentType type = damageSource.Type; EnemyAPI_Impl.s_damageSourceFlags = s_damageSourceFlags | ((int)type switch { 0 => DamageTraceFlags.Player, 3 => DamageTraceFlags.SentryGun, 2 => DamageTraceFlags.Decoy, 1 => DamageTraceFlags.Enemy, _ => DamageTraceFlags.Unknown, }); } if (EnemyAPI_Impl.s_tempGearIDRange == null && EnemyAPI_Impl.s_damageSourceFlags.HasFlag(DamageTraceFlags.Player) && !EnemyAPI_Impl.s_damageSourceFlags.HasFlag(DamageTraceFlags.SentryGun)) { PlayerAgent val = ((Il2CppObjectBase)damageSource).Cast(); if (EnemyAPI_Impl.s_damageSourceFlags.HasFlag(DamageTraceFlags.Melee)) { BackpackItem val2 = default(BackpackItem); if (PlayerBackpackManager.TryGetItem(val.Owner, (InventorySlot)10, ref val2)) { EnemyAPI_Impl.s_tempGearIDRange = val2.GearIDRange; } } else if (EnemyAPI_Impl.s_damageSourceFlags.HasFlag(DamageTraceFlags.Bullet)) { InventorySlot val3 = val.Inventory.WieldedSlot; if ((int)val3 != 1 && (int)val3 != 2) { val3 = (InventorySlot)1; } BackpackItem val4 = default(BackpackItem); if (PlayerBackpackManager.TryGetItem(val.Owner, val3, ref val4)) { EnemyAPI_Impl.s_tempGearIDRange = val4.GearIDRange; } } } GearIDRange s_tempGearIDRange = EnemyAPI_Impl.s_tempGearIDRange; uint gearChecksum = ((s_tempGearIDRange != null) ? s_tempGearIDRange.GetChecksum() : 0u); SendEnemyReceivedDamageData(__instance.Owner, __result, damage, damageSource, position, direction, hitreact, tryForceHitreact, limbID, staggerDamageMulti, damageNoiseLevel, gearCategoryId, gearChecksum, EnemyAPI_Impl.s_damageSourceFlags); } private static void Finalizer() { s_damageSourceFlags = DamageTraceFlags.None; s_tempGearIDRange = null; } } private struct pEnemySetHealthData { public pEnemyAgent enemy; public float health; public int limbID; public pEnemySetHealthData(EnemyAgent enemy, float health, int limbID) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) this.enemy = default(pEnemyAgent); this.health = 0f; this.limbID = -1; ((pEnemyAgent)(ref this.enemy)).Set(enemy); this.health = health; this.limbID = limbID; } } private static DamageTraceFlags s_damageSourceFlags; private static GearIDRange s_tempGearIDRange; private static pEnemySetHealthData s_enemySetHealthData; private static SNetExt_BroadcastAction s_enemySetHealthAction; private static pFullEnemyReceivedDamageData s_fullEnemyReceivedDamageData; private static SNetExt_BroadcastAction s_enemyReceivedDamageAction; public override string Name => "EnemyAPI Impl"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Developer", true); public static IArchiveLogger FeatureLogger { get; set; } public static event Action OnEnemyLimbDestroyed; public static event Action OnEnemyDead; public static event Action OnPostEnemyDead; public static event EnemyAPI.EnemyReceivedDamage OnEnemyReceivedDamage; public static event Action OnEnemySpawned; public static event Action OnEnemyDespawn; public static event Action OnEnemyDespawnd; public override void Init() { s_enemyReceivedDamageAction = SNetExt_BroadcastAction.Create(typeof(pFullEnemyReceivedDamageData).FullName, OnReceivedFullEnemyReceivedDamage, (SNet_Player p) => CoreAPI.IsPlayerInstalledCore(p), (SNet_ChannelType)3); s_enemySetHealthAction = SNetExt_BroadcastAction.Create(typeof(pEnemySetHealthData).FullName, OnReceiveEnemySetHealthData, (SNet_Player p) => CoreAPI.IsPlayerInstalledCore(p), (SNet_ChannelType)3); } private static void OnReceivedFullEnemyReceivedDamage(SNet_Player sender, pFullEnemyReceivedDamageData data) { EnemyAgent val = default(EnemyAgent); if (sender.IsMaster && ((pEnemyAgent)(ref data.enemy)).TryGet(ref val)) { Utils.SafeInvoke(EnemyAPI_Impl.OnEnemyReceivedDamage, new object[2] { val, data }); } } private static void OnReceiveEnemySetHealthData(SNet_Player sender, pEnemySetHealthData data) { EnemyAgent val = default(EnemyAgent); if (!SNet.IsMaster && sender.IsMaster && ((pEnemyAgent)(ref data.enemy)).TryGet(ref val)) { if (data.limbID == -1) { ((Dam_SyncedDamageBase)val.Damage).Health = data.health; } else { ((Il2CppArrayBase)(object)val.Damage.DamageLimbs)[data.limbID].m_health = data.health; } } } private static void SendEnemyReceivedDamageData(EnemyAgent enemy, bool isKill, float damage, Agent damageSource, Vector3 position, Vector3 direction, ES_HitreactType hitreact, bool tryForceHitreact = false, int limbID = -1, float staggerDamageMulti = 1f, DamageNoiseLevel damageNoiseLevel = 0, uint gearCategoryId = 0u, uint gearChecksum = 0u, DamageTraceFlags damageTraceFlags = DamageTraceFlags.Unknown) { //IL_003b: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) ((pEnemyAgent)(ref s_fullEnemyReceivedDamageData.enemy)).Set(enemy); s_fullEnemyReceivedDamageData.damage = damage; s_fullEnemyReceivedDamageData.isKill = isKill; ((pAgent)(ref s_fullEnemyReceivedDamageData.damageSource)).Set(damageSource); s_fullEnemyReceivedDamageData.position = position; s_fullEnemyReceivedDamageData.direction = direction; s_fullEnemyReceivedDamageData.hitreact = hitreact; s_fullEnemyReceivedDamageData.limbID = limbID; s_fullEnemyReceivedDamageData.staggerDamageMulti = staggerDamageMulti; s_fullEnemyReceivedDamageData.damageNoiseLevel = damageNoiseLevel; s_fullEnemyReceivedDamageData.gearCategoryId = gearCategoryId; s_fullEnemyReceivedDamageData.gearChecksum = gearChecksum; s_fullEnemyReceivedDamageData.damageTraceFlags = damageTraceFlags; s_enemyReceivedDamageAction.Do(s_fullEnemyReceivedDamageData); } private static void SendEnemyHealth(EnemyAgent enemy, Dam_EnemyDamageLimb limb = null) { ((pEnemyAgent)(ref s_enemySetHealthData.enemy)).Set(enemy); if ((Object)(object)limb == (Object)null) { s_enemySetHealthData.health = ((Dam_SyncedDamageBase)enemy.Damage).Health; s_enemySetHealthData.limbID = -1; } else { s_enemySetHealthData.health = limb.m_health; s_enemySetHealthData.limbID = limb.m_limbID; } s_enemySetHealthAction.Do(s_enemySetHealthData); } } [EnableFeatureByDefault] [DisallowInGameToggle] [HideInModSettings] [DoNotSaveToConfig] internal class GameEventAPI_Impl : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class GameDataInit__Initialize__Patch { private static void Postfix() { Utils.SafeInvoke(GameEventAPI_Impl.OnGameDataInitialized, Array.Empty()); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class GS_AfterLevel__CleanupAfterExpedition__Patch { private static void Postfix() { Utils.SafeInvoke(GameEventAPI_Impl.OnAfterLevelCleanup, Array.Empty()); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class GameStateManager__DoChangeState__Patch { private static eGameStateName preState; private static void Prefix(GameStateManager __instance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) preState = __instance.m_currentStateName; } private static void Postfix(eGameStateName nextState) { //IL_000d: 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) Utils.SafeInvoke>(GameEventAPI_Impl.OnGameStateChanged, new object[2] { preState, nextState }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class PlayerCharManager__DoSendChatMessage__Patch { private static void Postfix(pChatMessage data) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) pPlayer fromPlayer = data.fromPlayer; SNet_Player val = default(SNet_Player); if (((pPlayer)(ref fromPlayer)).TryGetPlayer(ref val)) { Utils.SafeInvoke>(GameEventAPI_Impl.OnReceiveChatMessage, new object[2] { val, data.message.data }); } } } public override string Name => "游戏事件监听"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Developer", true); public static IArchiveLogger FeatureLogger { get; set; } public static event Action OnGameDataInitialized; public static event Action OnGameStateChanged; public static event Action OnReceiveChatMessage; public static event Action OnAfterLevelCleanup; } [EnableFeatureByDefault] [DisallowInGameToggle] [HideInModSettings] [DoNotSaveToConfig] internal class SNetEventAPI_Impl : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_GlobalManager__Setup__Patch { private static void Postfix() { SNet_Events.OnMasterCommand += Action.op_Implicit((Action)delegate(pMasterCommand command) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) Utils.SafeInvoke>(SNetEventAPI_Impl.OnMasterCommand, new object[1] { command }); }); SNet_Events.OnPlayerEvent += Action.op_Implicit((Action)delegate(SNet_Player player, SNet_PlayerEvent playerEvent, SNet_PlayerEventReason reason) { //IL_0011: 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_0026: Unknown result type (might be due to invalid IL or missing references) Utils.SafeInvoke>(SNetEventAPI_Impl.OnPlayerEvent, new object[3] { player, playerEvent, reason }); if ((int)playerEvent == 0) { FeatureLogger.Notice($"{player.NickName} [{player.Lookup}] {"LeftSessionHub"}"); Utils.SafeInvoke>(SNetEventAPI_Impl.OnSessionMemberChanged, new object[2] { player, SessionMemberEvent.LeftSessionHub }); } }); SNet_Events.OnRecallComplete += Action.op_Implicit((Action)delegate(eBufferType buffer) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) Utils.SafeInvoke>(SNetEventAPI_Impl.OnRecallComplete, new object[1] { buffer }); }); SNet_Events.OnMasterChanged += Action.op_Implicit((Action)delegate { Utils.SafeInvoke(SNetEventAPI_Impl.OnMasterChanged, Array.Empty()); }); SNet_Events.OnPrepareForRecall += Action.op_Implicit((Action)delegate(eBufferType buffer) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) Utils.SafeInvoke>(SNetEventAPI_Impl.OnPrepareForRecall, new object[1] { buffer }); }); SNet_Events.OnResetSessionEvent += Action.op_Implicit((Action)delegate { Utils.SafeInvoke(SNetEventAPI_Impl.OnResetSession, Array.Empty()); }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Capture__TriggerCapture__Patch { private static void Prefix(SNet_Capture __instance) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) Utils.SafeInvoke>(SNetEventAPI_Impl.OnBufferCapture, new object[1] { __instance.PrimedBufferType }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Capture__RecallBuffer__Patch { private static void Postfix(SNet_Capture __instance, eBufferType bufferType) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!__instance.IsRecalling) { Utils.SafeInvoke>(SNetEventAPI_Impl.OnBufferRecalled, new object[1] { bufferType }); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Capture__OnBufferCommand__Patch { private static void Postfix(pBufferCommand command) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) Utils.SafeInvoke>(SNetEventAPI_Impl.OnBufferCommand, new object[1] { command }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_SyncManager__OnRecallDone__Patch { private static void Postfix(eBufferType bufferType) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) Utils.SafeInvoke>(SNetEventAPI_Impl.OnRecallDone, new object[1] { bufferType }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_SessionHub__AddPlayerToSession__Patch { private static void Postfix(SNet_Player player) { FeatureLogger.Notice($"{player.NickName} [{player.Lookup}] {"JoinSessionHub"}"); Utils.SafeInvoke>(SNetEventAPI_Impl.OnSessionMemberChanged, new object[2] { player, SessionMemberEvent.JoinSessionHub }); } } public override string Name => "SNetworkAPI Impl"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Developer", true); public static IArchiveLogger FeatureLogger { get; set; } public static event Action OnBufferCommand; public static event Action OnBufferCapture; public static event Action OnPrepareForRecall; public static event Action OnBufferRecalled; public static event Action OnRecallDone; public static event Action OnRecallComplete; public static event Action OnPlayerEvent; public static event Action OnSessionMemberChanged; public static event Action OnMasterChanged; public static event Action OnMasterCommand; public static event Action OnResetSession; } [DoNotSaveToConfig] [HideInModSettings] [DisallowInGameToggle] [EnableFeatureByDefault] internal class SNetExtAPI_Impl : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Replication__AssignReplicatorKey__Patch { private static void Postfix(IReplicator replicator, ushort key) { if (replicator != null && replicator.Key == key) { SNetExt_Replication.TryBindVanillaWrapper(replicator); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Replication__ClearReplicatorKey__Patch { private static void Prefix(IReplicator newReplicator) { if (newReplicator != null && SNetExt_Replication.TryGetVanillaWrapper(newReplicator, out var wrapper)) { wrapper.Despawn(); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Replication__DeallocateReplicator__Patch { private static void Prefix(IReplicator replicator) { if (replicator != null && SNetExt_Replication.TryGetVanillaWrapper(replicator, out var wrapper)) { SNetExt_Replication.DeallocateVanillaWrapper(wrapper); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class GS_AfterLevel__CleanupAfterExpedition__Patch { private static void Postfix() { SNetExt.Replication.CleanupReplicators(); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet__ValidateMasterData__Patch { private static void Postfix() { SNetExt.ValidateMasterData(); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet__Setup__Patch { private static void Prefix() { SNetExt.Setup(); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet__ResetSession__Patch { private static void Postfix() { SNetExt.ResetSession(); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet__DestroySelfManagedReplicatedObject__Patch { private static void Prefix(GameObject go) { SNetExt.DestroySelfManagedReplicatedObject(go); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Capture__SendBufferCommand__Patch { private static void Postfix(eBufferType buffer, eBufferOperationType operation, SNet_Player toPlayer = null, ushort bufferID = 0) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected I4, but got Unknown //IL_000e: Expected I4, but got Unknown SNetExt.Capture.SendBufferCommand((SNetExt_BufferType)(int)buffer, (SNetExt_BufferOperationType)(int)operation, toPlayer, bufferID); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Capture__CaptureGameState__Patch { private static void Postfix(eBufferType buffer) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected I4, but got Unknown SNetExt.Capture.CaptureGameState((SNetExt_BufferType)(int)buffer); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Capture__RecallGameState__Patch { private static void Postfix(eBufferType buffer) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected I4, but got Unknown SNetExt.Capture.RecallGameState((SNetExt_BufferType)(int)buffer); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Capture__SendBuffer__Patch { private static void Postfix(eBufferType bufferType, SNet_Player player = null, bool sendAsMigrationBuffer = false) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected I4, but got Unknown SNetExt.Capture.SendBuffer((SNetExt_BufferType)(int)bufferType, player, sendAsMigrationBuffer); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Capture__InitCheckpointRecall__Patch { private static void Postfix() { SNetExt.Capture.InitCheckpointRecall(); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_SyncManager__CleanUpAllButManagersCaptureCallbacks__Patch { private static void Postfix() { SNetExt_Capture.CleanUpAllButManagersCaptureCallbacks(); } } public override string Name => "SNetExtAPI Impl"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Developer", true); public static IArchiveLogger FeatureLogger { get; set; } } [EnableFeatureByDefault] [DisallowInGameToggle] [DoNotSaveToConfig] [HideInModSettings] internal class WeaponAPI_Impl : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class BulletWeapon__Fire__Patch { private static void Prefix(BulletWeapon __instance, bool resetRecoilSimilarity) { Utils.SafeInvoke(WeaponAPI_Impl.OnPreBulletWeaponFire, new object[2] { __instance, resetRecoilSimilarity }); } private static void Postfix(BulletWeapon __instance, bool resetRecoilSimilarity) { Utils.SafeInvoke(WeaponAPI_Impl.OnPostBulletWeaponFire, new object[2] { __instance, resetRecoilSimilarity }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Shotgun__Fire__Patch { private static void Prefix(Shotgun __instance, bool resetRecoilSimilarity) { Utils.SafeInvoke(WeaponAPI_Impl.OnPreShotgunFire, new object[2] { __instance, resetRecoilSimilarity }); } private static void Postfix(Shotgun __instance, bool resetRecoilSimilarity) { Utils.SafeInvoke(WeaponAPI_Impl.OnPostShotgunFire, new object[2] { __instance, resetRecoilSimilarity }); } } public override string Name => "WeaponAPI Impl"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Developer", true); public static IArchiveLogger FeatureLogger { get; set; } public static event WeaponAPI.PreBulletWeaponFire OnPreBulletWeaponFire; public static event WeaponAPI.PostBulletWeaponFire OnPostBulletWeaponFire; public static event WeaponAPI.PreShotgunFire OnPreShotgunFire; public static event WeaponAPI.PostShotgunFire OnPostShotgunFire; } } namespace Hikaria.Core.Features.Core { [EnableFeatureByDefault] [DisallowInGameToggle] [DoNotSaveToConfig] internal class ModList : Feature { public class ModListSetting { [FSDisplayName("我的插件")] public List InstalledMods { get; set; } = new List(); [FSInline] [FSDisplayName("其他人的插件")] public List OthersMods { get; set; } = new List(); } public class PlayerModListEntry { [FSIgnore] public ulong Lookup { get; private set; } [FSSeparator] [FSReadOnly(true)] [FSDisplayName("昵称")] public string Nickname { get; set; } = string.Empty; [FSReadOnly(true)] [FSInline] [FSDisplayName("插件列表")] public List ModList { get; set; } = new List(); public PlayerModListEntry(SNet_Player player) { Lookup = player.Lookup; Nickname = player.NickName; ModList = new List(); } } public class ModInfoEntry { [FSSeparator] [FSReadOnly(true)] [FSDisplayName("名称")] public string Name { get; set; } [FSReadOnly(true)] [FSDisplayName("唯一识别符")] public string GUID { get; set; } [FSReadOnly(true)] [FSDisplayName("版本")] public string Version { get; set; } public ModInfoEntry(pModInfo modInfo) { Name = modInfo.Name; GUID = modInfo.GUID; Version = modInfo.Version.ToString(); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SNet_Core_STEAM__CreateLocalPlayer__Patch { private static void Postfix() { Settings.InstalledMods = new List(CoreAPI_Impl.InstalledMods.Values.Select((pModInfo modInfo) => new ModInfoEntry(modInfo))); } } public override string Name => "插件列表"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Core", false); [FeatureConfig] public static ModListSetting Settings { get; set; } public override void OnEnable() { SNetEventAPI.OnSessionMemberChanged += OnSessionMemberChanged; CoreAPI.OnPlayerModsSynced += OnPlayerModSynced; } public override void OnDisable() { SNetEventAPI.OnSessionMemberChanged -= OnSessionMemberChanged; CoreAPI.OnPlayerModsSynced -= OnPlayerModSynced; } private void OnSessionMemberChanged(SNet_Player player, SessionMemberEvent playerEvent) { if (player.IsBot || playerEvent != SessionMemberEvent.LeftSessionHub) { return; } if (player.IsLocal) { Settings.OthersMods.Clear(); return; } Settings.OthersMods.RemoveAll((PlayerModListEntry p) => p.Lookup == player.Lookup); } private void OnPlayerModSynced(SNet_Player player, IEnumerable mods) { if (player.IsLocal) { return; } PlayerModListEntry playerModListEntry = Settings.OthersMods.Find((PlayerModListEntry p) => p.Lookup == player.Lookup); if (playerModListEntry == null) { playerModListEntry = new PlayerModListEntry(player) { ModList = new List(mods.Select((pModInfo modInfo) => new ModInfoEntry(modInfo))) }; Settings.OthersMods.Add(playerModListEntry); } else { playerModListEntry.ModList = new List(mods.Select((pModInfo modInfo) => new ModInfoEntry(modInfo))); } } } [DisallowInGameToggle] [EnableFeatureByDefault] [DoNotSaveToConfig] internal class PauseGame : Feature { public class PauseGameSettings { [FSDisplayName("当前状态")] public PauseGameStatus CurrentStatus { get { if (!GameEventAPI.IsGamePaused) { return PauseGameStatus.Unpaused; } return PauseGameStatus.Paused; } set { if (SNet.IsMaster && Feature.CurrentGameState == 10) { GameEventAPI.IsGamePaused = value == PauseGameStatus.Paused; } } } } [Localized] public enum PauseGameStatus { Unpaused, Paused } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class GS_InLevel__Update__Postfix { private static void Postfix() { if (GameEventAPI.IsGamePaused) { Clock.ExpeditionProgressionTime = ExpeditionProgressionTime; } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Global__OnPaused__Patch { private static void Postfix() { PauseManager.IsPaused = true; DoPauseGame(pause: true); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Global__SetUnpaused__Patch { private static void Postfix() { PauseManager.IsPaused = false; DoPauseGame(pause: false); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class PlayerSync__IncomongLocomotion__Patch { private static void Postfix(PlayerSync __instance, pPlayerLocomotion data) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (!SNet.IsMaster || !GameEventAPI.IsGamePaused || ((Agent)__instance.m_agent).IsLocallyOwned) { return; } PlayerAgent agent = __instance.m_agent; bool? obj; if (agent == null) { obj = null; } else { SNet_Player owner = agent.Owner; obj = ((owner != null) ? new bool?(owner.Load().isReady) : null); } bool? flag = obj; if (flag.GetValueOrDefault() && !__instance.m_agent.Owner.IsOutOfSync) { if (Vector3.Distance(data.Pos, ((Agent)__instance.m_agent).Position) >= 2f) { __instance.m_agent.RequestToggleControlsEnabled(false); } if ((int)__instance.m_agent.Inventory.WieldedSlot != 0) { __instance.m_agent.RequestToggleControlsEnabled(false); __instance.WantsToWieldSlot((InventorySlot)0, false); } } } } private static float ExpeditionProgressionTime; public override string Name => "暂停游戏"; public override string Description => "为暂停游戏提供图形化交互。"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Core", false); [FeatureConfig] public static PauseGameSettings Settings { get; set; } public override void OnGameStateChanged(int _) { GameEventAPI.IsGamePaused = false; } private static void DoPauseGame(bool pause) { if (pause) { ExpeditionProgressionTime = Clock.ExpeditionProgressionTime; } else { Clock.ExpeditionProgressionTime = ExpeditionProgressionTime; } SetPauseForWardenObjectiveItems(pause); SetPauseForAllPlayers(pause); } private static void SetPauseForAllPlayers(bool paused) { Enumerator enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator(); while (enumerator.MoveNext()) { PlayerAgent current = enumerator.Current; if (paused) { current.Sync.WantsToWieldSlot((InventorySlot)0, false); } current.RequestToggleControlsEnabled(!paused); } } private static void SetPauseForWardenObjectiveItems(bool paused) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 foreach (LG_WardenObjective_Reactor item in Object.FindObjectsOfType()) { if (item.m_isWardenObjective && !item.ObjectiveItemSolved) { eReactorStatus status = item.m_currentState.status; if (status - 2 <= 2 || (int)status == 6) { item.m_progressUpdateEnabled = !paused; } } } } } } namespace Hikaria.Core.Features.Accessibility { [EnableFeatureByDefault] internal class PlayerPingHelper : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class LayerManager__PostSetup__Patch { private static void Postfix(LayerManager __instance) { LayerManager.MASK_PING_TARGET = __instance.GetMask(new string[6] { "Default", "Default_NoGraph", "Default_BlockGraph", "Interaction", "Dynamic", "EnemyDamagable" }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class EnemyPrefabManager__GenerateEnemy__Patch { private static void Postfix(EnemyPrefabManager __instance, EnemyDataBlock data) { foreach (Collider componentsInChild in EnemyPrefabManager.Current.m_enemyPrefabs[((GameDataBlockBase)(object)data).persistentID].GetComponentsInChildren(true)) { if (!((Object)(object)((Component)componentsInChild).GetComponent() != (Object)null)) { ((Component)componentsInChild).gameObject.AddComponent().m_pingTargetStyle = (eNavMarkerStyle)2; } } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class LocalPlayerAgent__Setup__Patch { private static void Postfix(LocalPlayerAgent __instance) { s_LocalPlayerAgent = __instance; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class GuiManager__PlayerMarkerIsVisibleAndInFocus__Patch { private static void Postfix(bool __result) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) RaycastHit val = default(RaycastHit); if (!__result && Physics.Raycast(s_LocalPlayerAgent.CamPos, ((PlayerAgent)s_LocalPlayerAgent).FPSCamera.Forward, ref val, 40f, LayerManager.MASK_PING_TARGET, (QueryTriggerInteraction)1)) { s_tempPlayerPingTarget = ((Component)((RaycastHit)(ref val)).collider).GetComponentInChildren(true); if ((Object)(object)s_tempPlayerPingTarget == (Object)null) { s_tempPlayerPingTarget = ((Component)((RaycastHit)(ref val)).collider).gameObject.AddComponent(); s_tempPlayerPingTarget.m_pingTargetStyle = (eNavMarkerStyle)0; } else if (!((Behaviour)s_tempPlayerPingTarget).enabled) { ((Behaviour)s_tempPlayerPingTarget).enabled = true; } } } } private static LocalPlayerAgent s_LocalPlayerAgent; private static PlayerPingTarget s_tempPlayerPingTarget; public override string Name => "标点助手"; public override string Description => "允许玩家随意进行标点"; public override bool RequiresRestart => true; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Accessibility", false); } [EnableFeatureByDefault] internal class ReceiveAmmoGiveFix : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] public class PlayerBackpackManager__ReceiveAmmoGive__Patch { private static Dictionary AmmoMaxCapLookup = new Dictionary { { (InventorySlot)1, 0f }, { (InventorySlot)2, 0f } }; private static InventorySlotAmmo StandardAmmo; private static InventorySlotAmmo SpeacialAmmo; private static float AmmoStandardResourcePackMaxCap => GameDataBlockBase.GetBlock(1u).AmmoStandardResourcePackMaxCap; private static float AmmoSpecialResourcePackMaxCap => GameDataBlockBase.GetBlock(1u).AmmoSpecialResourcePackMaxCap; private static void Prefix(ref pAmmoGive data) { bool flag = false; bool flag2 = false; float num = 0f; float num2 = 0f; SNet_Player val = default(SNet_Player); if (((pPlayer)(ref data.targetPlayer)).TryGetPlayer(ref val) && val.IsLocal) { BackpackItem val2 = default(BackpackItem); if (PlayerBackpackManager.LocalBackpack.TryGetBackpackItem((InventorySlot)1, ref val2)) { BulletWeapon val3 = ((Il2CppObjectBase)val2.Instance).TryCast(); float num3 = (float)(((ItemEquippable)val3).ClipSize - val3.m_clip) * ((ItemEquippable)val3).ArchetypeData.CostOfBullet; StandardAmmo = PlayerBackpackManager.LocalBackpack.AmmoStorage.StandardAmmo; AmmoMaxCapLookup[(InventorySlot)1] = StandardAmmo.AmmoMaxCap; InventorySlotAmmo standardAmmo = StandardAmmo; standardAmmo.AmmoMaxCap += num3; num = data.ammoStandardRel * AmmoStandardResourcePackMaxCap + StandardAmmo.AmmoInPack - StandardAmmo.AmmoMaxCap; flag = num > 0f; } if (PlayerBackpackManager.LocalBackpack.TryGetBackpackItem((InventorySlot)2, ref val2)) { BulletWeapon val4 = ((Il2CppObjectBase)val2.Instance).TryCast(); float num4 = (float)(((ItemEquippable)val4).ClipSize - val4.m_clip) * ((ItemEquippable)val4).ArchetypeData.CostOfBullet; SpeacialAmmo = PlayerBackpackManager.LocalBackpack.AmmoStorage.SpecialAmmo; AmmoMaxCapLookup[(InventorySlot)2] = SpeacialAmmo.AmmoMaxCap; InventorySlotAmmo speacialAmmo = SpeacialAmmo; speacialAmmo.AmmoMaxCap += num4; num2 = data.ammoSpecialRel * AmmoSpecialResourcePackMaxCap + SpeacialAmmo.AmmoInPack - SpeacialAmmo.AmmoMaxCap; flag2 = num2 > 0f; } if (flag && !flag2) { data.ammoSpecialRel += num / AmmoStandardResourcePackMaxCap; } else if (!flag && flag2) { data.ammoStandardRel += num2 / AmmoSpecialResourcePackMaxCap; } } } private static void Postfix(pAmmoGive data) { SNet_Player val = default(SNet_Player); if (((pPlayer)(ref data.targetPlayer)).TryGetPlayer(ref val) && val.IsLocal) { BackpackItem val2 = default(BackpackItem); if (PlayerBackpackManager.LocalBackpack.TryGetBackpackItem((InventorySlot)1, ref val2)) { StandardAmmo.AmmoMaxCap = AmmoMaxCapLookup[(InventorySlot)1]; PlayerBackpackManager.LocalBackpack.AmmoStorage.UpdateSlotAmmoUI((InventorySlot)1); } if (PlayerBackpackManager.LocalBackpack.TryGetBackpackItem((InventorySlot)2, ref val2)) { SpeacialAmmo.AmmoMaxCap = AmmoMaxCapLookup[(InventorySlot)2]; PlayerBackpackManager.LocalBackpack.AmmoStorage.UpdateSlotAmmoUI((InventorySlot)2); } } } } public override string Name => "弹药补给修复"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Accessibility", false); } [EnableFeatureByDefault] internal class ResourceStack : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private class LG_PickupItem_Sync__AttemptInteract__Patch { private static void Prefix(LG_PickupItem_Sync __instance, pPickupItemInteraction interaction) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) SNet_Player player = default(SNet_Player); if (SNet.IsMaster && (int)interaction.type == 0 && ((pPlayer)(ref interaction.pPlayer)).TryGetPlayer(ref player)) { TryStackItem(__instance.item, player); } } } public override string Name => "资源堆叠"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Accessibility", false); private static void TryStackItem(Item item, SNet_Player player) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Invalid comparison between Unknown and I4 //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) InventorySlot slot = item.pItemData.slot; PlayerBackpack val = default(PlayerBackpack); BackpackItem val2 = default(BackpackItem); if (((int)slot != 4 && (int)slot != 5) || !PlayerBackpackManager.TryGetBackpack(player, ref val) || !val.TryGetBackpackItem(slot, ref val2) || val2.Instance.pItemData.itemID_gearCRC != item.pItemData.itemID_gearCRC) { return; } float num = item.ItemDataBlock.ConsumableAmmoMax; if ((int)slot == 4) { num = 100f; } AmmoType val3 = (AmmoType)(((int)slot == 4) ? 3 : 5); float ammoInPack = val.AmmoStorage.GetAmmoInPack(val3); if (!(ammoInPack >= num)) { float num2 = item.pItemData.custom.ammo + ammoInPack; pItemData_Custom customData = item.GetCustomData(); if (num2 > num) { customData.ammo = num; ((Il2CppObjectBase)item).TryCast().GetSyncComponent().SetCustomData(customData, true); val.AmmoStorage.SetAmmo(val3, num2 - num); } else { PlayerBackpackManager.MasterRemoveItem(val2.Instance, player); customData.ammo = num2; ((Il2CppObjectBase)item).TryCast().GetSyncComponent().SetCustomData(customData, true); } } } } [EnableFeatureByDefault] public class ToolPlacementIndicator : Feature { [ArchivePatch(/*Could not decode attribute arguments.*/)] private static class MineDeployerFirstPerson__Update__Patch { private static void Postfix(MineDeployerFirstPerson __instance) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)CurrentLineRenderer == (Object)null) { return; } if (__instance.m_hasRayHit && __instance.m_lastCanPlace && ((ItemEquippable)__instance).CanWield) { if (!((Component)CurrentLineRenderer).gameObject.active) { ((Component)CurrentLineRenderer).gameObject.SetActive(true); } LineRenderer currentLineRenderer = CurrentLineRenderer; RaycastHit lastRayHit = __instance.m_lastRayHit; currentLineRenderer.SetPosition(0, ((RaycastHit)(ref lastRayHit)).point); lastRayHit = __instance.m_lastRayHit; Vector3 point = ((RaycastHit)(ref lastRayHit)).point; lastRayHit = __instance.m_lastRayHit; RaycastHit val = default(RaycastHit); if (Physics.Raycast(point, ((RaycastHit)(ref lastRayHit)).normal, ref val, 20f, LayerManager.MASK_STICKY_MINE_TARGETS)) { CurrentLineRenderer.SetPosition(1, ((RaycastHit)(ref val)).point); return; } LineRenderer currentLineRenderer2 = CurrentLineRenderer; lastRayHit = __instance.m_lastRayHit; Vector3 point2 = ((RaycastHit)(ref lastRayHit)).point; lastRayHit = __instance.m_lastRayHit; currentLineRenderer2.SetPosition(1, point2 + ((RaycastHit)(ref lastRayHit)).normal * 20f); } else if (((Component)CurrentLineRenderer).gameObject.active) { ((Component)CurrentLineRenderer).gameObject.SetActive(false); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private static class MineDeployerFirstPerson__OnWield__Patch { private static void Postfix(MineDeployerFirstPerson __instance) { if ((Object)(object)CurrentLineRenderer == (Object)null) { CurrentLineRenderer = GetLineRenderer(__instance); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private static class MineDeployerFirstPerson__OnUnWield__Patch { private static void Prefix() { if (!((Object)(object)CurrentLineRenderer == (Object)null)) { Object.Destroy((Object)(object)CurrentLineRenderer); CurrentLineRenderer = null; } } } private const string EXPLOSIVE_MINE_PREFAB = "ASSETS/ASSETPREFABS/ITEMS/CONSUMABLES/TRIPMINE/CONSUMABLE_TRIPMINE_EXPLOSIVE_INSTANCE.PREFAB"; private const string GLUE_MINE_PREFAB = "ASSETS/ASSETPREFABS/ITEMS/CONSUMABLES/TRIPMINE/CONSUMABLE_TRIPMINE_GLUE_INSTANCE.PREFAB"; private static LineRenderer explosiveLineRenderPrefab; private static LineRenderer glueLineRenderPrefab; private static LineRenderer CurrentLineRenderer; public override string Name => "工具摆放指示器"; public override GroupBase Group => ((GroupBase)((Feature)this).ModuleGroup).GetOrCreateSubGroup("Accessibility", false); public static ToolPlacementIndicator Instance { get; set; } public override void Init() { AssetShardManager.OnSharedAsssetLoaded += Action.op_Implicit((Action)LoadAssets); } private static void LoadAssets() { Object loadedAsset = AssetShardManager.GetLoadedAsset("ASSETS/ASSETPREFABS/ITEMS/CONSUMABLES/TRIPMINE/CONSUMABLE_TRIPMINE_EXPLOSIVE_INSTANCE.PREFAB", false); Object loadedAsset2 = AssetShardManager.GetLoadedAsset("ASSETS/ASSETPREFABS/ITEMS/CONSUMABLES/TRIPMINE/CONSUMABLE_TRIPMINE_GLUE_INSTANCE.PREFAB", false); if (loadedAsset == (Object)null || loadedAsset2 == (Object)null) { ((Feature)Instance).RequestDisable("Missing Prefab"); return; } explosiveLineRenderPrefab = ((Il2CppObjectBase)loadedAsset).Cast().GetComponent().m_lineRenderer; glueLineRenderPrefab = ((Il2CppObjectBase)loadedAsset2).Cast().GetComponent().m_lineRenderer; } private static LineRenderer GetLineRenderer(MineDeployerFirstPerson deployer) { LineRenderer obj = Object.Instantiate((deployer.m_mineIdToSpawn == 126 || deployer.m_mineIdToSpawn == 144) ? glueLineRenderPrefab : explosiveLineRenderPrefab); Object.DontDestroyOnLoad((Object)(object)obj); return obj; } } } namespace Hikaria.Core.Extensions { public static class SNet_PlayerExtensions { public static string GetColoredNameWithoutRichTextTags(this SNet_Player player) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) return $"{player.NickName.RemoveRichTextTags()}"; } } public static class RichTextTagsExtensions { private sealed class OpenTagInfo { public string Name { get; set; } public string OpenText { get; set; } } private static readonly HashSet SupportedTags = new HashSet(StringComparer.OrdinalIgnoreCase) { "b", "i", "u", "s", "mark", "color", "size", "material", "align", "alpha", "cspace", "font", "indent", "line-height", "line-indent", "link", "lowercase", "uppercase", "smallcaps", "margin", "noparse", "nobr", "pos", "style", "voffset", "width", "gradient" }; private static readonly HashSet SelfClosingTags = new HashSet(StringComparer.OrdinalIgnoreCase) { "br", "page", "sprite", "quad", "space" }; private static readonly Regex TagRegex = new Regex("<\\s*(?/?)\\s*(?[a-zA-Z][a-zA-Z0-9-]*)(?:\\s*=\\s*[^<>]*)?\\s*/?\\s*>", RegexOptions.IgnoreCase); private static readonly Regex ShortColorRegex = new Regex("<\\s*#(?[0-9A-Fa-f]{3,8})\\s*>", RegexOptions.IgnoreCase); public static string FixRichTextTags(this string input) { if (string.IsNullOrEmpty(input)) { return input; } input = input.NormalizeShortColorTags(); StringBuilder stringBuilder = new StringBuilder(input.Length); Stack stack = new Stack(); int num = 0; foreach (Match item in TagRegex.Matches(input)) { string text = item.Groups["name"].Value.ToLowerInvariant(); bool flag = item.Groups["slash"].Value == "/"; if (!SupportedTags.Contains(text) && !SelfClosingTags.Contains(text)) { continue; } stringBuilder.Append(input, num, item.Index - num); num = item.Index + item.Length; if (SelfClosingTags.Contains(text)) { stringBuilder.Append(item.Value); } else if (!flag) { stringBuilder.Append(item.Value); stack.Push(new OpenTagInfo { Name = text, OpenText = item.Value }); } else { if (stack.Count == 0) { continue; } if (stack.Peek().Name == text) { stack.Pop(); stringBuilder.Append(item.Value); continue; } List list = new List(); bool flag2 = false; while (stack.Count > 0) { OpenTagInfo openTagInfo = stack.Pop(); if (openTagInfo.Name == text) { flag2 = true; break; } list.Add(openTagInfo); } if (!flag2) { for (int num2 = list.Count - 1; num2 >= 0; num2--) { stack.Push(list[num2]); } continue; } for (int i = 0; i < list.Count; i++) { stringBuilder.Append(""); } stringBuilder.Append(item.Value); for (int num3 = list.Count - 1; num3 >= 0; num3--) { stringBuilder.Append(list[num3].OpenText); stack.Push(list[num3]); } } } stringBuilder.Append(input, num, input.Length - num); while (stack.Count > 0) { OpenTagInfo openTagInfo2 = stack.Pop(); stringBuilder.Append(""); } return stringBuilder.ToString(); } public static string RemoveRichTextTags(this string input) { if (string.IsNullOrEmpty(input)) { return input; } input = ShortColorRegex.Replace(input, string.Empty); return TagRegex.Replace(input, delegate(Match match) { string value = match.Groups["name"].Value; return (SupportedTags.Contains(value) || SelfClosingTags.Contains(value)) ? string.Empty : match.Value; }); } public static string NormalizeShortColorTags(this string input) { if (string.IsNullOrEmpty(input)) { return input; } return ShortColorRegex.Replace(input, ""); } } } namespace Hikaria.Core.Detour { public sealed class DetourDescriptor { private nint _cachedPtr; private bool _resolved; private readonly object _resolveLock = new object(); public Type Type { get; init; } public string MethodName { get; init; } public Type[] ArgTypes { get; init; } public Type ReturnType { get; init; } public bool IsGeneric { get; init; } public Type[] GenericTypeArguments { get; init; } public unsafe nint GetMethodPointer() { if (Volatile.Read(ref _resolved)) { return _cachedPtr; } lock (_resolveLock) { if (_resolved) { return _cachedPtr; } ValidateDescriptor(); IntPtr nativeClassPointer = Il2CppClassPointerStore.GetNativeClassPointer(Type); string fullName = GetFullName(ReturnType); Type[] argTypes = ArgTypes; string[] array = ((argTypes != null && argTypes.Length > 0) ? ArgTypes.Select(GetFullName).ToArray() : Array.Empty()); void** ptr = (void**)IL2CPP.GetIl2CppMethod(nativeClassPointer, IsGeneric, MethodName, fullName, array).ToPointer(); _cachedPtr = (nint)((ptr != null) ? (*ptr) : null); Volatile.Write(ref _resolved, value: true); return _cachedPtr; } } private void ValidateDescriptor() { if (Type == null) { throw new ArgumentNullException("Type", "目标类型不可为空"); } if (ReturnType == null) { throw new ArgumentNullException("ReturnType", "返回类型不可为空"); } if (string.IsNullOrWhiteSpace(MethodName)) { throw new ArgumentException("目标方法名称不可为空", "MethodName"); } } private static string GetFullName(Type type) { if (type == null) { throw new ArgumentNullException("type"); } int num = 0; while (type.IsPointer) { type = type.GetElementType() ?? throw new InvalidOperationException("无效的指针类型: GetElementType 返回 null"); num++; } string text = type.FullName ?? type.Name; if (num == 0) { return text; } return text + new string('*', num); } public override string ToString() { Type[] source = ArgTypes ?? Array.Empty(); string text; if (IsGeneric) { Type[] genericTypeArguments = GenericTypeArguments; if (genericTypeArguments != null && genericTypeArguments.Length > 0) { text = "<" + string.Join(", ", genericTypeArguments.Select((Type a) => a?.FullName)) + ">"; goto IL_006d; } } text = string.Empty; goto IL_006d; IL_006d: string value = text; return $"{Type?.FullName}.{MethodName}{value}({string.Join(", ", source.Select((Type a) => a?.FullName))})"; } } public interface INativeDetourHandle : IDisposable { DetourDescriptor Descriptor { get; } INativeDetour NativeDetour { get; } bool IsApplied { get; } bool Apply(); void Unpatch(); } public sealed class NativeDetourHandle : INativeDetourHandle, IDisposable where TDelegate : Delegate { private readonly object _sync = new object(); private TDelegate _original; private INativeDetour _detour; private bool _applied; private int _disposed; public DetourDescriptor Descriptor { get; } public TDelegate Hook { get; } public TDelegate Original { get { ThrowIfDisposed(); return Volatile.Read(ref _original) ?? throw new InvalidOperationException($"NativeDetourHandle 尚未 Apply,Original 不可用: {Descriptor}"); } } public INativeDetour NativeDetour => _detour; public bool IsApplied => Volatile.Read(ref _applied); internal NativeDetourHandle(DetourDescriptor descriptor, TDelegate hook) { Descriptor = descriptor ?? throw new ArgumentNullException("descriptor"); Hook = hook ?? throw new ArgumentNullException("hook"); } public bool Apply() { ThrowIfDisposed(); lock (_sync) { if (_applied) { return true; } if (_detour != null) { try { ((IDetour)_detour).Apply(); Volatile.Write(ref _applied, value: true); return true; } catch (Exception ex) { Hikaria.Core.Detour.NativeDetour.LogException("NativeDetour 重新启用错误", Descriptor, ex); return false; } } if (Hikaria.Core.Detour.NativeDetour.CreateAndApplyCore(Descriptor, Hook, out _original, out _detour)) { Volatile.Write(ref _applied, value: true); return true; } return false; } } public void Unpatch() { ThrowIfDisposed(); lock (_sync) { if (_applied && _detour != null) { try { ((IDetour)_detour).Undo(); } catch (Exception ex) { Hikaria.Core.Detour.NativeDetour.LogException("NativeDetour 撤销错误", Descriptor, ex); } Volatile.Write(ref _applied, value: false); } } } public void Dispose() { if (Interlocked.Exchange(ref _disposed, 1) == 0) { DisposeCore(); } } private void DisposeCore() { lock (_sync) { INativeDetour detour = _detour; _detour = null; _original = null; Volatile.Write(ref _applied, value: false); if (detour == null) { return; } Hikaria.Core.Detour.NativeDetour.Unregister(detour); try { ((IDetour)detour).Undo(); } catch { } try { ((IDetour)detour).Free(); } catch { } try { ((IDisposable)detour).Dispose(); } catch { } } } private void ThrowIfDisposed() { if (Volatile.Read(ref _disposed) != 0) { throw new ObjectDisposedException(GetType().FullName); } } } public static class NativeDetour { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public unsafe delegate void StaticVoidDelegate(Il2CppMethodInfo* methodInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public unsafe delegate void InstanceVoidDelegate(IntPtr self, Il2CppMethodInfo* methodInfo); private static IArchiveLogger _logger; private static IArchiveLogger Logger => LazyInitializer.EnsureInitialized(ref _logger, () => LoaderWrapper.CreateArSubLoggerInstance("NativeDetour", ConsoleColor.White)); public static NativeDetourHandle Create(DetourDescriptor descriptor, T hook) where T : Delegate { return new NativeDetourHandle(descriptor, hook); } public static NativeDetourHandle CreateAndApply(DetourDescriptor descriptor, T hook) where T : Delegate { NativeDetourHandle nativeDetourHandle = new NativeDetourHandle(descriptor, hook); nativeDetourHandle.Apply(); return nativeDetourHandle; } internal static void DisposeAll() { NativeDetourRegistry.DisposeAll(); } internal static void Unregister(INativeDetour d) { NativeDetourRegistry.Unregister(d); } internal static void LogFail(string what, DetourDescriptor descriptor) { Logger.Fail($"NativeDetour 应用失败 ({what}): {descriptor}"); } internal static void LogException(string what, DetourDescriptor descriptor, Exception ex) { Logger.Error($"{what}: {descriptor}"); Logger.Exception(ex); } internal static bool CreateAndApplyCore(DetourDescriptor descriptor, T hook, out T original, out INativeDetour detour) where T : Delegate { original = null; detour = null; if (descriptor == null) { Logger.Fail("NativeDetour 应用失败 (descriptor 为 null)"); return false; } if ((Delegate?)hook == (Delegate?)null) { LogFail("hook 委托为 null", descriptor); return false; } try { nint methodPointer = descriptor.GetMethodPointer(); if (methodPointer == 0) { LogFail("找不到 IL2CPP 方法", descriptor); return false; } if (NativeDetourRegistry.IsRegistered(methodPointer)) { throw new NativeDetourConflictException(methodPointer, descriptor); } detour = INativeDetour.CreateAndApply((IntPtr)methodPointer, hook, ref original); if (detour == null) { LogFail("INativeDetour.CreateAndApply 返回 null", descriptor); return false; } try { NativeDetourRegistry.Register(methodPointer, detour); } catch (NativeDetourConflictException) { SafeReleaseDetour(detour); detour = null; original = null; throw new NativeDetourConflictException(methodPointer, descriptor); } Logger.Success($"NativeDetour 已应用: {descriptor}"); return true; } catch (NativeDetourConflictException) { throw; } catch (Exception ex3) { LogException("NativeDetour 应用错误", descriptor, ex3); if (detour != null) { SafeReleaseDetour(detour); detour = null; } original = null; return false; } } private static void SafeReleaseDetour(INativeDetour d) { try { ((IDetour)d).Undo(); } catch { } try { ((IDetour)d).Free(); } catch { } try { ((IDisposable)d).Dispose(); } catch { } } } [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public sealed class NativeDetourAttribute : Attribute { public Type DeclaringType { get; } public string MethodName { get; } public bool Static { get; init; } public NativeDetourMember Member { get; init; } public Type[] TypeArguments { get; init; } public NativeDetourAttribute(Type declaringType, string methodName) { DeclaringType = declaringType; MethodName = methodName; } public NativeDetourAttribute(Type declaringType) { DeclaringType = declaringType; MethodName = null; Member = NativeDetourMember.Constructor; } } public enum NativeDetourMember { Method, Constructor, Getter, Setter } public sealed class NativeDetourConflictException : InvalidOperationException { public nint MethodPointer { get; } public DetourDescriptor Descriptor { get; } internal NativeDetourConflictException(nint methodPointer, DetourDescriptor descriptor = null) : base(BuildMessage(methodPointer, descriptor)) { MethodPointer = methodPointer; Descriptor = descriptor; } private static string BuildMessage(nint ptr, DetourDescriptor d) { if (d != null) { return $"方法 '{d}' (指针 0x{ptr:X}) 已被另一个 NativeDetour 占用,不允许重复 detour"; } return $"方法指针 0x{ptr:X} 已被另一个 NativeDetour 占用,不允许重复 detour"; } } public static class NativeDetourRegistry { private static readonly ConcurrentDictionary s_byPointer = new ConcurrentDictionary(); private static readonly ConcurrentDictionary s_byDetour = new ConcurrentDictionary(); public static bool IsRegistered(nint methodPointer) { if (methodPointer != 0) { return s_byPointer.ContainsKey(methodPointer); } return false; } internal static void Register(nint methodPointer, INativeDetour detour) { if (methodPointer == 0) { throw new ArgumentException("方法指针不可为 0", "methodPointer"); } if (detour == null) { throw new ArgumentNullException("detour"); } if (!s_byPointer.TryAdd(methodPointer, detour)) { throw new NativeDetourConflictException(methodPointer); } s_byDetour.TryAdd(detour, methodPointer); } internal static void Unregister(INativeDetour detour) { if (detour != null && s_byDetour.TryRemove(detour, out IntPtr value)) { s_byPointer.TryRemove(value, out var _); } } internal static void DisposeAll() { KeyValuePair[] array = s_byPointer.ToArray(); foreach (KeyValuePair keyValuePair in array) { INativeDetour value = keyValuePair.Value; try { ((IDetour)value).Undo(); } catch { } try { ((IDetour)value).Free(); } catch { } try { ((IDisposable)value).Dispose(); } catch { } } s_byPointer.Clear(); s_byDetour.Clear(); } } } namespace Hikaria.Core.Components { public class Interact_Base : MonoBehaviourExtended, IInteractable { public Collider m_colliderToOwn; public Action OnPickedUp; private bool m_isBlocked; private bool m_isActive = true; public virtual KeyCode InputKey => (KeyCode)0; public virtual bool ManualTriggeringOnly => false; public virtual bool AllowTriggerWithCarryItem { get; set; } public virtual bool OnlyActiveWhenLookingStraightAt { get; set; } public bool IsActive => m_isActive; public bool IsBlocked => m_isBlocked; public bool RequireCollisionCheck { get; set; } = true; public bool IsSelected { get; private set; } public Transform Root => ((Component)this).transform; public virtual void SetupFromItem(Item item) { } public virtual void SetActive(bool active) { m_isActive = active; ((Behaviour)this).enabled = active; if ((Object)(object)m_colliderToOwn != (Object)null) { m_colliderToOwn.enabled = active; } } public void SetBlocked(bool state) { m_isBlocked = state; } public virtual bool PlayerCanInteract(PlayerAgent source) { return m_isActive; } public virtual bool PlayerDoInteract(PlayerAgent source) { return false; } public virtual void PlayerSetSelected(bool selected, PlayerAgent agent) { bool flag = selected && !GuiManager.InteractionLayer.InteractPromptVisible; if (IsSelected != selected || flag) { OnSelectedChange(selected, agent, flag); } IsSelected = selected; } protected virtual void OnSelectedChange(bool selected, PlayerAgent agent, bool forceUpdate = false) { } public virtual bool PlayerCheckInput(PlayerAgent agent) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Input.GetKey(InputKey); } public virtual void OnProximityEnter(PlayerAgent agent) { } public virtual void OnProximityExit(PlayerAgent agent) { } public virtual void LocalPickup(PlayerAgent agent) { } public virtual void SyncedPickup(PlayerAgent agent) { } protected virtual void Update() { } } public class Interact_ManualTimedWithCallback : Interact_Timed { private KeyCode m_inputKey; public override bool ManualTriggeringOnly => true; public override KeyCode InputKey => m_inputKey; public Action OnTrigger { get; set; } public override uint SFXInteractStart { get; set; } = EVENTS.INTERACT_TOOL_START; public override uint SFXInteractCancel { get; set; } = EVENTS.INTERACT_TOOL_CANCEL; public override uint SFXInteractEnd { get; set; } = EVENTS.INTERACT_TOOL_FINISHED; public void SetAction(string desc, KeyCode inputKey) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) InteractionMessage = desc; m_inputKey = inputKey; } public void ManualUpdateWithCondition(bool condition, PlayerAgent source, bool selectedOnIdle = false) { if (condition) { if (PlayerCheckInput(source)) { PlayerDoInteract(source); PlayerSetSelected(selected: false, source); } else if (base.InteractionTimerRel > 0f && !base.IsSelected) { PlayerSetSelected(selected: true, source); } else if (base.InteractionTimerRel <= 0f && base.IsSelected != selectedOnIdle) { PlayerSetSelected(selectedOnIdle, source); } } else if (base.IsSelected) { PlayerSetSelected(selected: false, source); } } protected override void TriggerInteractionAction(PlayerAgent source) { base.TriggerInteractionAction(source); OnTrigger?.Invoke(); } } public class Interact_Timed : Interact_Base { protected class InteractorInfo { public PlayerAgent Agent; } private float m_interactDuration = 0.6f; protected PlayerAgent m_interactTargetAgent; protected bool m_timerIsActive; private bool m_UIState; protected InteractorInfo m_localPlayerInteractInfo; private CellSoundPlayer m_sound; protected List m_interactors = new List(); protected bool m_hasShownInteractionPrompt; private Vector3 m_triggerStartAgentWorldPos; private Vector3 m_triggerStartAgentLookDir; private float m_minCamDotAllowed = 0.5f; private float m_maxMoveDisAllowed = 2f; private float m_timerProgressRel; public virtual float InteractDuration { get { return m_interactDuration; } set { m_interactDuration = value; } } public virtual uint SFXInteractStart { get; set; } = EVENTS.REVIVELOOP; public virtual uint SFXInteractCancel { get; set; } = EVENTS.REVIVECANCEL; public virtual uint SFXInteractEnd { get; set; } = EVENTS.REVIVEEND; public virtual uint SFXInteractTrigger { get; set; } public float InteractionTimerRel => m_timerProgressRel; protected virtual bool InternalAllowInput => true; public bool TimerIsActive => m_timerIsActive; public virtual string InteractionMessage { get; set; } = "Surprise"; public bool AbortOnDotOrDistanceDiff { get; set; } = true; public event Action OnInteractionEvaluationAbort; public event Action OnInteractionTriggered; public event Action OnInteractionSelected; public event Func ExternalPlayerCanInteract; public event Func OnAdditionalInteractionText; protected virtual void Start() { } protected override void Update() { base.Update(); float num = 0f; for (int i = 0; i < m_interactors.Count; i++) { num = ApplySpeedModifier(m_interactors[i].Agent, 1f); } if (num > 0f && m_timerProgressRel != 1f) { m_timerProgressRel += Time.deltaTime * num / InteractDuration; m_timerProgressRel = Mathf.Min(1f, m_timerProgressRel); OnTimerUpdate(m_timerProgressRel); } } public virtual void Setup(PlayerAgent owner) { m_interactTargetAgent = owner; } protected virtual float ApplySpeedModifier(PlayerAgent sourceAgent, float dt) { return dt; } public virtual string GetAdditionalInteractionInfo() { if (this.OnAdditionalInteractionText != null) { return this.OnAdditionalInteractionText(); } return string.Empty; } public override bool PlayerCanInteract(PlayerAgent source) { if (base.PlayerCanInteract(source)) { return this.ExternalPlayerCanInteract?.Invoke(source) ?? true; } return false; } public void ForceUpdatePrompt() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (base.IsSelected) { GuiManager.InteractionLayer.SetInteractPrompt(InteractionMessage + GetAdditionalInteractionInfo(), string.Format(Text.Get(827u), InputKey), (ePUIMessageStyle)0); } } protected override void OnSelectedChange(bool selected, PlayerAgent agent, bool forceUpdate = false) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) if ((selected && !m_hasShownInteractionPrompt) || (!selected && m_hasShownInteractionPrompt) || forceUpdate) { GuiManager.InteractionLayer.InteractPromptVisible = selected; } if (selected) { GuiManager.InteractionLayer.SetInteractPrompt(InteractionMessage + GetAdditionalInteractionInfo(), string.Format(Text.Get(827u), InputKey), (ePUIMessageStyle)0); } m_hasShownInteractionPrompt = selected; TriggerOnInteractionSelectedCallback(agent, selected); if (!selected) { OnInteractorStateChanged(agent, state: false); } } public void TriggerOnInteractionSelectedCallback(PlayerAgent agent, bool selected) { this.OnInteractionSelected?.Invoke(agent, selected); } public override void SetActive(bool active) { if (m_timerIsActive) { SetTimerActive(active: false); SetUIState(state: false, fadeOut: false); } base.SetActive(active); } public override bool PlayerCheckInput(PlayerAgent agent) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!InternalAllowInput) { OnInteractorStateChanged(agent, state: false); return false; } if (m_localPlayerInteractInfo == null) { if (Input.GetKey(InputKey)) { OnInteractorStateChanged(agent, state: true); } } else if (Input.GetKey(InputKey) && EvaluateTimedInteraction()) { if (InteractionTimerRel == 1f) { OnInteractorCompleted(agent); return true; } } else { OnInteractorStateChanged(agent, state: false); } return false; } public override bool PlayerDoInteract(PlayerAgent source) { TriggerInteractionAction(source); return true; } protected virtual bool EvaluateTimedInteraction() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_003b: Unknown result type (might be due to invalid IL or missing references) if (AbortOnDotOrDistanceDiff) { PlayerAgent agent = m_localPlayerInteractInfo.Agent; float num = Vector3.Dot(agent.FPSCamera.Forward, m_triggerStartAgentLookDir); Vector3 val = m_triggerStartAgentWorldPos - ((Agent)agent).Position; float magnitude = ((Vector3)(ref val)).magnitude; if (num < m_minCamDotAllowed || magnitude > m_maxMoveDisAllowed) { return false; } } return true; } protected virtual void OnTimerUpdate(float timeRel) { GuiManager.InteractionLayer.SetTimer(timeRel); } protected virtual void TriggerInteractionAction(PlayerAgent source) { CheckSoundPlayer(); m_sound.Post(SFXInteractEnd, true); if (SFXInteractTrigger != 0) { m_sound.Post(SFXInteractTrigger, true); } if (source == null) { source = PlayerManager.GetLocalPlayerAgent(); } this.OnInteractionTriggered?.Invoke(source); } private void CheckSoundPlayer() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (m_sound == null) { m_sound = new CellSoundPlayer(((Component)this).transform.position); } } protected virtual void SetTimerActive(bool active) { CheckSoundPlayer(); if (active) { if (!m_timerIsActive) { m_sound.Post(SFXInteractStart, true); m_timerProgressRel = 0f; } } else if (m_timerIsActive) { m_sound.Post(SFXInteractCancel, true); m_timerProgressRel = 0f; } m_timerIsActive = active; } protected virtual void SetUIState(bool state, bool fadeOut) { if (state) { if (NeedsUI()) { m_UIState = true; GuiManager.InteractionLayer.SetTimer(m_timerProgressRel); GuiManager.InteractionLayer.TimerVisible = true; GuiManager.InteractionLayer.SetTimerAlphaMul(1f); } } else if (m_UIState && NeedsUI()) { m_UIState = false; if (fadeOut) { float num = 0.1f; GuiManager.InteractionLayer.TimerFlash(num); ((MonoBehaviourExtended)this).Callback(Action.op_Implicit((Action)HideTimer), num * 2f); } else { HideTimer(); } } } protected bool NeedsUI() { if (!((Object)(object)m_interactTargetAgent != (Object)null) || !((Agent)m_interactTargetAgent).IsLocallyOwned) { return m_localPlayerInteractInfo != null; } return true; } private void HideTimer() { GuiManager.InteractionLayer.TimerVisible = false; } public void OnInteractorCompleted(PlayerAgent sourceAgent) { OnTimerUpdate(1f); SetTimerActive(active: false); SetUIState(state: false, fadeOut: true); OnInteractorStateChanged(sourceAgent, state: false); } public virtual void OnInteractorStateChanged(PlayerAgent sourceAgent, bool state) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (state) { for (int i = 0; i < m_interactors.Count; i++) { if ((Object)(object)m_interactors[i].Agent == (Object)(object)sourceAgent) { return; } } InteractorInfo interactorInfo = new InteractorInfo { Agent = sourceAgent }; m_interactors.Add(interactorInfo); if (((Agent)sourceAgent).IsLocallyOwned) { m_localPlayerInteractInfo = interactorInfo; m_triggerStartAgentWorldPos = ((Agent)sourceAgent).Position; m_triggerStartAgentLookDir = sourceAgent.FPSCamera.Forward; } SetTimerActive(active: true); SetUIState(state: true, fadeOut: false); return; } for (int j = 0; j < m_interactors.Count; j++) { if ((Object)(object)m_interactors[j].Agent == (Object)(object)sourceAgent) { if (m_interactors.Count == 1) { SetTimerActive(active: false); } if (m_interactors.Count == 1 || ((Agent)sourceAgent).IsLocallyOwned) { SetUIState(state: false, fadeOut: false); } m_interactors.RemoveAt(j); if (((Agent)sourceAgent).IsLocallyOwned) { m_localPlayerInteractInfo = null; } break; } } } } }