Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Empress LateJoin v1.1.0
EmpressLateJoin.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Empress")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("2.0.7.0")] [assembly: AssemblyInformationalVersion("2.0.7")] [assembly: AssemblyProduct("EmpressLateJoin")] [assembly: AssemblyTitle("EmpressLateJoin")] [assembly: AssemblyVersion("2.0.7.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace EmpressLateJoin { [BepInPlugin("empress.repo.empresslatejoin", "EmpressLateJoin", "2.0.7")] public sealed class EmpressLateJoinPlugin : BaseUnityPlugin { internal const string PluginGuid = "empress.repo.empresslatejoin"; internal const string PluginName = "EmpressLateJoin"; internal const string PluginVersion = "2.0.7"; private Harmony? _empressHarmony; private bool _empressApplicationQuitting; internal ConfigEntry<bool> EmpressEnabled; internal ConfigEntry<bool> EmpressKeepRoomJoinable; internal ConfigEntry<bool> EmpressLiveJoinActiveLevels; internal ConfigEntry<bool> EmpressQueueDuringActiveLevels; internal ConfigEntry<float> EmpressWaitingLeashRadius; internal ConfigEntry<float> EmpressWaitingSnapCooldown; internal ConfigEntry<float> EmpressSceneSwitchSettleDelay; internal ConfigEntry<float> EmpressSceneSwitchSettleTimeout; internal static EmpressLateJoinPlugin? Instance { get; private set; } internal static EmpressLateJoinRuntime? Runtime { get; private set; } internal ManualLogSource EmpressLog => ((BaseUnityPlugin)this).Logger; private void Awake() { //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Expected O, but got Unknown ((Component)this).gameObject.transform.parent = null; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); Instance = this; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; EmpressEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for EmpressLateJoin."); EmpressKeepRoomJoinable = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "KeepRoomJoinable", true, "Keeps the active multiplayer room joinable after the host starts the run."); EmpressLiveJoinActiveLevels = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LiveJoinActiveLevels", true, "Lets mid-level joiners load straight into the active scene and replay the missing live state from the host."); EmpressQueueDuringActiveLevels = ((BaseUnityPlugin)this).Config.Bind<bool>("WaitingRoom", "QueueDuringActiveLevels", true, "Parks mid-level late joiners in the Empress holding cell and lets them enter normal play on the next scene."); EmpressWaitingLeashRadius = ((BaseUnityPlugin)this).Config.Bind<float>("WaitingRoom", "WaitingLeashRadius", 7f, "How far a waiting player can stray from the holding cell anchor before EmpressLateJoin snaps them back."); EmpressWaitingSnapCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("WaitingRoom", "WaitingSnapCooldown", 0.75f, "Minimum delay between holding-cell snapbacks."); EmpressSceneSwitchSettleDelay = ((BaseUnityPlugin)this).Config.Bind<float>("WaitingRoom", "SceneSwitchSettleDelay", 1.25f, "Minimum amount of time EmpressLateJoin waits for a late joiner to settle before allowing the next scene switch."); EmpressSceneSwitchSettleTimeout = ((BaseUnityPlugin)this).Config.Bind<float>("WaitingRoom", "SceneSwitchSettleTimeout", 8f, "Maximum amount of time EmpressLateJoin will delay a scene switch while a late joiner settles."); Runtime = Resources.FindObjectsOfTypeAll<EmpressLateJoinRuntime>().FirstOrDefault(); if ((Object)(object)Runtime == (Object)null) { GameObject val = new GameObject("EmpressLateJoin.Runtime") { hideFlags = (HideFlags)61 }; val.transform.parent = null; Object.DontDestroyOnLoad((Object)val); Runtime = val.AddComponent<EmpressLateJoinRuntime>(); } else { ((Component)Runtime).gameObject.transform.parent = null; Object.DontDestroyOnLoad((Object)(object)((Component)Runtime).gameObject); ((Object)((Component)Runtime).gameObject).hideFlags = (HideFlags)61; } _empressHarmony = new Harmony("empress.repo.empresslatejoin"); _empressHarmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"EmpressLateJoin 2.0.7 loaded."); } private void OnApplicationQuit() { _empressApplicationQuitting = true; } private void OnDestroy() { if (_empressApplicationQuitting) { Harmony? empressHarmony = _empressHarmony; if (empressHarmony != null) { empressHarmony.UnpatchSelf(); } if (Instance == this && (Object)(object)Runtime != (Object)null) { Object.Destroy((Object)(object)((Component)Runtime).gameObject); Runtime = null; } if (Instance == this) { Instance = null; } } } } internal sealed class EmpressLateJoinRuntime : MonoBehaviour { private sealed class EmpressDelayedSceneChangeRequest { internal RunManager RunManager; internal bool CompletedLevel; internal bool LevelFailed; internal ChangeLevelType ChangeLevelType; internal float RequestedAt; internal bool TimeoutLogged; } private const float EmpressJoinabilityRefreshInterval = 1f; private const float EmpressSupportAuditInterval = 1f; private const float EmpressWaitingAnchorRadiusBase = 1.3f; private const float EmpressLateJoinReadyHoldTime = 0.2f; private const float EmpressLateJoinMinimumIdentityTime = 0.5f; private const float EmpressLiveJoinUpdateLevelDelay = 2f; private const float EmpressLiveJoinGenerateDoneDelay = 3.5f; private const float EmpressLiveJoinReplayDelay = 4.5f; private static readonly FieldInfo? EmpressGameManagerConnectRandomField = AccessTools.Field(typeof(GameManager), "connectRandom"); private static readonly FieldInfo? EmpressPlayerAvatarSpawnedField = AccessTools.Field(typeof(PlayerAvatar), "spawned"); private static readonly FieldInfo? EmpressPlayerAvatarDeathHeadField = AccessTools.Field(typeof(PlayerAvatar), "playerDeathHead"); private static readonly FieldInfo? EmpressPlayerAvatarTumbleField = AccessTools.Field(typeof(PlayerAvatar), "tumble"); private static readonly FieldInfo? EmpressPlayerDeathHeadPhysGrabObjectField = AccessTools.Field(typeof(PlayerDeathHead), "physGrabObject"); private static readonly FieldInfo? EmpressPlayerDeathHeadSetupField = AccessTools.Field(typeof(PlayerDeathHead), "setup"); private static readonly FieldInfo? EmpressPlayerTumblePhysGrabObjectField = AccessTools.Field(typeof(PlayerTumble), "physGrabObject"); private static readonly FieldInfo? EmpressPlayerTumbleSetupField = AccessTools.Field(typeof(PlayerTumble), "setup"); private static readonly FieldInfo? EmpressPlayerAvatarSteamIdField = AccessTools.Field(typeof(PlayerAvatar), "steamID"); private static readonly FieldInfo? EmpressPlayerAvatarPlayerNameField = AccessTools.Field(typeof(PlayerAvatar), "playerName"); private static readonly FieldInfo? EmpressPlayerAvatarLevelAnimationCompletedField = AccessTools.Field(typeof(PlayerAvatar), "levelAnimationCompleted"); private static readonly FieldInfo? EmpressRunManagerGameOverField = AccessTools.Field(typeof(RunManager), "gameOver"); private static readonly FieldInfo? EmpressRunManagerPunField = AccessTools.Field(typeof(RunManager), "runManagerPUN"); private static readonly FieldInfo? EmpressRunManagerPunPhotonViewField = AccessTools.Field(typeof(RunManagerPUN), "photonView"); private static readonly FieldInfo? EmpressLevelGeneratorPhotonViewField = AccessTools.Field(typeof(LevelGenerator), "PhotonView"); private static readonly FieldInfo? EmpressLevelGeneratorDeathHeadPrefabField = AccessTools.Field(typeof(LevelGenerator), "PlayerDeathHeadPrefab"); private static readonly FieldInfo? EmpressLevelGeneratorTumblePrefabField = AccessTools.Field(typeof(LevelGenerator), "PlayerTumblePrefab"); private static readonly FieldInfo? EmpressPhotonRemoveFilterField = AccessTools.Field(typeof(PhotonNetwork), "removeFilter"); private static readonly FieldInfo? EmpressPhotonKeyByteSevenField = AccessTools.Field(typeof(PhotonNetwork), "keyByteSeven"); private static readonly FieldInfo? EmpressPhotonServerCleanOptionsField = AccessTools.Field(typeof(PhotonNetwork), "ServerCleanOptions"); private static readonly MethodInfo? EmpressPhotonRaiseEventInternalMethod = AccessTools.Method(typeof(PhotonNetwork), "RaiseEventInternal", (Type[])null, (Type[])null); private readonly HashSet<int> _empressHostWaitingActors = new HashSet<int>(); private readonly HashSet<int> _empressDeferredWaitingRoomActors = new HashSet<int>(); private readonly HashSet<int> _empressEnemyRegisteredActors = new HashSet<int>(); private readonly HashSet<int> _empressLiveJoinLevelUpdateSentActors = new HashSet<int>(); private readonly HashSet<int> _empressLiveJoinBootstrapSentActors = new HashSet<int>(); private readonly HashSet<int> _empressLiveStateReplayedActors = new HashSet<int>(); private readonly Dictionary<int, float> _empressLateJoinDetectedAt = new Dictionary<int, float>(); private readonly Dictionary<int, float> _empressLateJoinReadyAt = new Dictionary<int, float>(); private readonly Dictionary<int, float> _empressNextSnapByActor = new Dictionary<int, float>(); private EmpressDelayedSceneChangeRequest? _empressDelayedSceneChange; private bool _empressRunningDelayedSceneChange; private bool _empressLiveJoinCachePrepared; private bool _empressSteamLobbyUnlockApplied; private bool _empressRunLevelCachePruned; private float _empressNextJoinabilityRefreshTime; private float _empressNextSupportAuditTime; private string _empressSteamLobbyUnlockRoomName = string.Empty; private void Awake() { ((Component)this).gameObject.transform.parent = null; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; } private void OnEnable() { SceneManager.sceneLoaded += EmpressOnSceneLoaded; } private void OnDisable() { SceneManager.sceneLoaded -= EmpressOnSceneLoaded; } private void Update() { if (!((Object)(object)EmpressLateJoinPlugin.Instance == (Object)null) && EmpressLateJoinPlugin.Instance.EmpressEnabled.Value) { if (Time.unscaledTime >= _empressNextJoinabilityRefreshTime) { EmpressRefreshJoinability(); _empressNextJoinabilityRefreshTime = Time.unscaledTime + 1f; } EmpressMaybePruneRunLevelCache(); EmpressMaintainSupportObjects(); EmpressMaintainLateJoinState(); EmpressMaintainWaitingPlayers(); EmpressProcessDelayedSceneChange(); } } internal bool EmpressTryHandleLateJoinSpawn() { if (!EmpressCanHostLateJoinLogic()) { return false; } List<PlayerAvatar> list = (from avatar in SemiFunc.PlayerGetList() where (Object)(object)avatar != (Object)null && (Object)(object)avatar.photonView != (Object)null && !EmpressGetAvatarSpawned(avatar) select avatar).ToList(); if (list.Count == 0) { return false; } foreach (PlayerAvatar item in list) { int ownerActorNr = item.photonView.OwnerActorNr; if (EmpressEnsureRunLevelWaitingRoomMode()) { EmpressBackfillLateJoinerIntoEnemySystems(item); if (_empressDeferredWaitingRoomActors.Add(ownerActorNr)) { EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"EmpressLateJoin is holding late joiner {EmpressGetAvatarDisplayName(item)} ({ownerActorNr}) outside the active level until the next scene."); } continue; } EmpressTrackLateJoin(ownerActorNr); EmpressEnsureSupportObjects(item); if (EmpressShouldQueueLateJoiner()) { EmpressQueueLateJoiner(item); } else { EmpressAdmitLateJoiner(item); } } return true; } internal void EmpressHandlePlayerLeft(Player player) { _empressHostWaitingActors.Remove(player.ActorNumber); _empressDeferredWaitingRoomActors.Remove(player.ActorNumber); _empressEnemyRegisteredActors.Remove(player.ActorNumber); _empressLiveJoinLevelUpdateSentActors.Remove(player.ActorNumber); _empressLiveJoinBootstrapSentActors.Remove(player.ActorNumber); _empressLiveStateReplayedActors.Remove(player.ActorNumber); _empressNextSnapByActor.Remove(player.ActorNumber); EmpressClearLateJoinTracking(player.ActorNumber); } internal void EmpressHandlePlayerEntered(Player player) { if (EmpressCanHostLateJoinLogic() && SemiFunc.RunIsLevel()) { if (EmpressEnsureRunLevelWaitingRoomMode()) { EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"Late join detected for {player.NickName} ({player.ActorNumber}); EmpressLateJoin is keeping them in the waiting room until the next scene."); return; } EmpressTrackLateJoin(player.ActorNumber); string arg = (EmpressShouldQueueLateJoiner() ? "park them in the Empress holding cell" : "drop them into the truck and replay the live run state"); EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"Late join detected for {player.NickName} ({player.ActorNumber}); EmpressLateJoin will {arg}."); } } internal bool EmpressTryDelaySceneChange(RunManager runManager, bool completedLevel, bool levelFailed, ChangeLevelType changeLevelType) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Invalid comparison between Unknown and I4 //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Invalid comparison between Unknown and I4 //IL_0102: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (_empressRunningDelayedSceneChange || !EmpressCanHostRoomControl() || !SemiFunc.RunIsLevel()) { return false; } if (EmpressEnsureRunLevelWaitingRoomMode()) { return false; } if (completedLevel && !levelFailed) { if (_empressLateJoinDetectedAt.Count > 0) { EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)("EmpressLateJoin is not delaying the completed-run truck departure. Any unfinished live joiners will be carried forward by the normal level switch: " + EmpressDescribeTrackedLateJoiners() + ".")); } return false; } if (_empressLateJoinDetectedAt.Count == 0) { return false; } if ((int)changeLevelType == 4 || (int)changeLevelType == 3) { return false; } if (_empressDelayedSceneChange == null) { _empressDelayedSceneChange = new EmpressDelayedSceneChangeRequest { RunManager = runManager, CompletedLevel = completedLevel, LevelFailed = levelFailed, ChangeLevelType = changeLevelType, RequestedAt = Time.unscaledTime }; EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)("EmpressLateJoin is delaying the scene switch while late joiners finish syncing: " + EmpressDescribeTrackedLateJoiners() + ".")); } else { _empressDelayedSceneChange.RunManager = runManager; _empressDelayedSceneChange.CompletedLevel = completedLevel; _empressDelayedSceneChange.LevelFailed = levelFailed; _empressDelayedSceneChange.ChangeLevelType = changeLevelType; } return true; } internal void EmpressHandleChangeLevelCompleted(RunManager runManager, ChangeLevelType changeLevelType) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) EmpressPrepareLiveJoinLevelDescriptor(runManager, changeLevelType); EmpressEnsureRunLevelWaitingRoomMode(); } private void EmpressOnSceneLoaded(Scene scene, LoadSceneMode mode) { _empressHostWaitingActors.Clear(); _empressDeferredWaitingRoomActors.Clear(); _empressEnemyRegisteredActors.Clear(); _empressLiveJoinLevelUpdateSentActors.Clear(); _empressLiveJoinBootstrapSentActors.Clear(); _empressLiveStateReplayedActors.Clear(); _empressLateJoinDetectedAt.Clear(); _empressLateJoinReadyAt.Clear(); _empressNextSnapByActor.Clear(); _empressDelayedSceneChange = null; _empressRunningDelayedSceneChange = false; _empressLiveJoinCachePrepared = false; _empressSteamLobbyUnlockApplied = false; _empressRunLevelCachePruned = false; _empressNextJoinabilityRefreshTime = 0f; _empressNextSupportAuditTime = 0f; _empressSteamLobbyUnlockRoomName = string.Empty; EmpressRefreshJoinability(); } private void EmpressRefreshJoinability() { if (!EmpressCanHostRoomControl()) { _empressSteamLobbyUnlockApplied = false; _empressSteamLobbyUnlockRoomName = string.Empty; } else { EmpressForceJoinabilityRefresh(); } } internal void EmpressForceJoinabilityRefresh(bool forceSteamLobbyUnlock = false) { if (!EmpressCanHostRoomControl() || !EmpressLateJoinPlugin.Instance.EmpressKeepRoomJoinable.Value) { _empressSteamLobbyUnlockApplied = false; _empressSteamLobbyUnlockRoomName = string.Empty; return; } Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom == null) { _empressSteamLobbyUnlockApplied = false; _empressSteamLobbyUnlockRoomName = string.Empty; return; } if (!string.Equals(_empressSteamLobbyUnlockRoomName, currentRoom.Name, StringComparison.Ordinal)) { _empressSteamLobbyUnlockRoomName = currentRoom.Name; _empressSteamLobbyUnlockApplied = false; } currentRoom.IsOpen = true; if (EmpressGetConnectRandom()) { currentRoom.IsVisible = true; _empressSteamLobbyUnlockApplied = false; } if (EmpressGetConnectRandom() || !((Object)(object)SteamManager.instance != (Object)null) || (_empressSteamLobbyUnlockApplied && !forceSteamLobbyUnlock)) { return; } try { SteamManager.instance.UnlockLobby(false); _empressSteamLobbyUnlockApplied = true; } catch (Exception ex) { _empressSteamLobbyUnlockApplied = false; EmpressLateJoinPlugin? instance = EmpressLateJoinPlugin.Instance; if (instance != null) { instance.EmpressLog.LogDebug((object)("EmpressLateJoin could not unlock the Steam lobby yet: " + ex.Message)); } } } private bool EmpressGetCurrentRunGameOver() { return EmpressGetFieldValue<bool>(EmpressRunManagerGameOverField, RunManager.instance); } private bool EmpressLiveJoinEnabled() { return EmpressLateJoinPlugin.Instance?.EmpressLiveJoinActiveLevels.Value ?? false; } private void EmpressPrepareLiveJoinLevelDescriptor(RunManager runManager, ChangeLevelType changeLevelType) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (EmpressLiveJoinEnabled() && EmpressCanHostRoomControl() && !((Object)(object)runManager == (Object)null) && !((Object)(object)runManager.levelCurrent == (Object)null) && SemiFunc.RunIsLevel()) { PhotonView val = EmpressGetRunManagerPhotonView(); if (!((Object)(object)val == (Object)null) && val.ViewID > 0) { PhotonNetwork.RemoveBufferedRPCs(val.ViewID, "UpdateLevelRPC", (int[])null); EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"EmpressLateJoin removed buffered UpdateLevelRPC for {((Object)runManager.levelCurrent).name} ({changeLevelType}) right after the host level switch so late joiners do not consume the stale room handoff on entry."); } } } private void EmpressPrepareLiveJoinRoomState() { if (!_empressLiveJoinCachePrepared && EmpressLiveJoinEnabled() && EmpressCanHostRoomControl() && SemiFunc.RunIsLevel()) { PhotonView val = EmpressGetFieldValue<PhotonView>(EmpressLevelGeneratorPhotonViewField, LevelGenerator.Instance); if (!((Object)(object)val == (Object)null) && val.ViewID > 0) { PhotonNetwork.RemoveBufferedRPCs(val.ViewID, "GenerateDone", (int[])null); _empressLiveJoinCachePrepared = true; EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)"EmpressLateJoin removed buffered GenerateDone so live joiners can be staged into Start only after the host decides they are ready."); } } } private void EmpressMaybePruneRunLevelCache() { EmpressPrepareLiveJoinRoomState(); EmpressEnsureRunLevelWaitingRoomMode(); } private void EmpressMaintainSupportObjects() { if (!EmpressLiveJoinEnabled() || !EmpressCanHostRoomControl() || (Object)(object)LevelGenerator.Instance == (Object)null || SemiFunc.MenuLevel() || Time.unscaledTime < _empressNextSupportAuditTime) { return; } _empressNextSupportAuditTime = Time.unscaledTime + 1f; foreach (PlayerAvatar item in SemiFunc.PlayerGetList()) { if (!((Object)(object)item == (Object)null)) { EmpressEnsureSupportObjects(item); } } } private void EmpressMaintainLateJoinState() { if (!EmpressCanHostRoomControl() || _empressLateJoinDetectedAt.Count == 0) { return; } float num = Mathf.Max(1f, EmpressLateJoinPlugin.Instance.EmpressSceneSwitchSettleTimeout.Value); foreach (int item in _empressLateJoinDetectedAt.Keys.ToList()) { if (!EmpressIsActorStillConnected(item)) { EmpressClearLateJoinTracking(item); continue; } float num2 = _empressLateJoinDetectedAt[item]; PlayerAvatar val = EmpressFindAvatar(item); if ((Object)(object)val == (Object)null || (Object)(object)val.photonView == (Object)null) { if (Time.unscaledTime - num2 >= num) { EmpressLateJoinPlugin.Instance.EmpressLog.LogWarning((object)$"EmpressLateJoin timed out waiting for actor {item} to finish spawning on the host."); EmpressClearLateJoinTracking(item); } continue; } EmpressEnsureSupportObjects(val); EmpressBackfillLateJoinerIntoEnemySystems(val); EmpressAdvanceLiveJoinBootstrap(val, num2); if (EmpressIsLateJoinerSettled(val, num2)) { if (!_empressLateJoinReadyAt.ContainsKey(item)) { _empressLateJoinReadyAt[item] = Time.unscaledTime; EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"Late joiner {EmpressGetAvatarDisplayName(val)} ({item}) has settled on the host."); } else if (Time.unscaledTime - _empressLateJoinReadyAt[item] >= 0.2f) { EmpressClearLateJoinTracking(item); } } else { _empressLateJoinReadyAt.Remove(item); if (Time.unscaledTime - num2 >= num) { EmpressLateJoinPlugin.Instance.EmpressLog.LogWarning((object)$"EmpressLateJoin waited {num:0.0}s for {EmpressGetAvatarDisplayName(val)} ({item}) to settle and will stop delaying scene switches for them."); EmpressClearLateJoinTracking(item); } } } } private void EmpressAdvanceLiveJoinBootstrap(PlayerAvatar avatar, float detectedAt) { if (!EmpressLiveJoinEnabled() || (Object)(object)avatar.photonView == (Object)null || !EmpressGetAvatarSpawned(avatar)) { return; } int ownerActorNr = avatar.photonView.OwnerActorNr; if (ownerActorNr <= 0 || PhotonNetwork.CurrentRoom == null || !PhotonNetwork.CurrentRoom.Players.TryGetValue(ownerActorNr, out var value)) { return; } float num = Time.unscaledTime - detectedAt; try { if (!_empressLiveJoinLevelUpdateSentActors.Contains(ownerActorNr) && num >= 2f) { if (!EmpressHasLateJoinIdentity(avatar, detectedAt)) { return; } PhotonView val = EmpressGetRunManagerPhotonView(); if ((Object)(object)val != (Object)null) { val.RPC("UpdateLevelRPC", value, new object[3] { ((Object)RunManager.instance.levelCurrent).name, RunManager.instance.levelsCompleted, EmpressGetCurrentRunGameOver() }); _empressLiveJoinLevelUpdateSentActors.Add(ownerActorNr); EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"EmpressLateJoin pushed the current level descriptor to {EmpressGetAvatarDisplayName(avatar)} ({ownerActorNr}) after a live-join delay."); } } if (_empressLiveJoinLevelUpdateSentActors.Contains(ownerActorNr) && !_empressLiveJoinBootstrapSentActors.Contains(ownerActorNr) && num >= 3.5f) { PhotonView val2 = EmpressGetFieldValue<PhotonView>(EmpressLevelGeneratorPhotonViewField, LevelGenerator.Instance); if ((Object)(object)val2 != (Object)null) { val2.RPC("GenerateDone", value, Array.Empty<object>()); _empressLiveJoinBootstrapSentActors.Add(ownerActorNr); EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"EmpressLateJoin released {EmpressGetAvatarDisplayName(avatar)} ({ownerActorNr}) into the Start state after a live-join bootstrap delay."); } } if (_empressLiveJoinBootstrapSentActors.Contains(ownerActorNr) && !_empressLiveStateReplayedActors.Contains(ownerActorNr) && num >= 4.5f) { EmpressReplayStatsToJoiner(value); EmpressReplayItemsToJoiner(value); EmpressReplayPlayerStateToJoiner(value); EmpressReplayRoundStateToJoiner(value); _empressLiveStateReplayedActors.Add(ownerActorNr); EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"EmpressLateJoin replayed live run state to {EmpressGetAvatarDisplayName(avatar)} ({ownerActorNr})."); } } catch (Exception ex) { EmpressLateJoinPlugin? instance = EmpressLateJoinPlugin.Instance; if (instance != null) { instance.EmpressLog.LogWarning((object)$"EmpressLateJoin could not advance live-join bootstrap for actor {ownerActorNr}: {ex.Message}"); } } } private bool EmpressHasLateJoinIdentity(PlayerAvatar avatar, float detectedAt) { if (!EmpressGetAvatarSpawned(avatar)) { return false; } if (string.IsNullOrWhiteSpace(EmpressGetAvatarSteamId(avatar)) || string.IsNullOrWhiteSpace(EmpressGetAvatarPlayerName(avatar))) { return false; } EmpressEnsureSupportObjects(avatar); if (!EmpressHasSupportObjectsReady(avatar)) { return false; } int num = (((Object)(object)avatar.photonView != (Object)null) ? avatar.photonView.OwnerActorNr : 0); if (num > 0 && !_empressEnemyRegisteredActors.Contains(num)) { return false; } return Time.unscaledTime - detectedAt >= 0.5f; } private void EmpressReplayStatsToJoiner(Player targetPlayer) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown if ((Object)(object)PunManager.instance == (Object)null || (Object)(object)PunManager.instance.photonView == (Object)null || (Object)(object)StatsManager.instance == (Object)null) { return; } List<KeyValuePair<string, Dictionary<string, int>>> list = StatsManager.instance.dictionaryOfDictionaries.ToList(); if (list.Count == 0) { return; } Hashtable val = new Hashtable(); int num = 0; for (int i = 0; i < list.Count; i++) { KeyValuePair<string, Dictionary<string, int>> keyValuePair = list[i]; val[(object)keyValuePair.Key] = EmpressConvertDictionaryToHashtable(keyValuePair.Value); num++; if (num >= 4 || i >= list.Count - 1) { bool flag = i >= list.Count - 1; PunManager.instance.photonView.RPC("ReceiveSyncData", targetPlayer, new object[2] { val, flag }); val = new Hashtable(); num = 0; } } } private void EmpressReplayItemsToJoiner(Player targetPlayer) { //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected I4, but got Unknown if ((Object)(object)PunManager.instance == (Object)null || (Object)(object)PunManager.instance.photonView == (Object)null) { return; } foreach (ItemAttributes item in from item in Object.FindObjectsOfType<ItemAttributes>() where (Object)(object)item != (Object)null && (Object)(object)item.photonView != (Object)null && item.photonView.ViewID > 0 orderby item.photonView.ViewID select item) { string text = ((!string.IsNullOrWhiteSpace(item.instanceName)) ? item.instanceName : item.itemAssetName); if (!string.IsNullOrWhiteSpace(text)) { PunManager.instance.photonView.RPC("SetItemNameRPC", targetPlayer, new object[2] { text, item.photonView.ViewID }); } item.photonView.RPC("GetValueRPC", targetPlayer, new object[1] { item.value }); if (item.disableUI) { item.photonView.RPC("DisableUIRPC", targetPlayer, new object[1] { true }); } ItemEquippable itemEquippable = item.itemEquippable; if ((Object)(object)itemEquippable != (Object)null && (int)itemEquippable.currentState != 0) { item.photonView.RPC("RPC_UpdateItemState", targetPlayer, new object[3] { (int)itemEquippable.currentState, itemEquippable.inventorySpotIndex, itemEquippable.ownerPlayerId }); } } } private void EmpressReplayPlayerStateToJoiner(Player targetPlayer) { foreach (PlayerAvatar item in from player in SemiFunc.PlayerGetList() where (Object)(object)player != (Object)null && (Object)(object)player.photonView != (Object)null select player) { if ((Object)(object)item.playerHealth != (Object)null) { item.photonView.RPC("UpdateHealthRPC", targetPlayer, new object[3] { item.playerHealth.health, item.playerHealth.maxHealth, false }); } if (item.deadSet || item.isDisabled || !((Component)item).gameObject.activeSelf) { item.photonView.RPC("PlayerDeathRPC", targetPlayer, new object[1] { -1 }); } if ((Object)(object)item.tumble != (Object)null && (Object)(object)item.tumble.photonView != (Object)null && item.tumble.isTumbling) { item.tumble.photonView.RPC("TumbleSetRPC", targetPlayer, new object[2] { true, false }); if (item.tumble.tumbleOverride) { item.tumble.photonView.RPC("TumbleOverrideRPC", targetPlayer, new object[1] { true }); } } } } private void EmpressReplayRoundStateToJoiner(Player targetPlayer) { if ((Object)(object)PunManager.instance?.photonView != (Object)null) { if (!string.IsNullOrWhiteSpace(SessionManager.instance?.crownedPlayerSteamID)) { PunManager.instance.photonView.RPC("CrownPlayerRPC", targetPlayer, new object[1] { SessionManager.instance.crownedPlayerSteamID }); } if ((Object)(object)RoundDirector.instance != (Object)null) { PunManager.instance.photonView.RPC("SyncHaul", targetPlayer, new object[1] { RoundDirector.instance.totalHaul }); } if (SemiFunc.RunIsShop() && (Object)(object)ShopManager.instance != (Object)null) { PunManager.instance.photonView.RPC("UpdateShoppingCostRPC", targetPlayer, new object[1] { ShopManager.instance.totalCost }); } } if (!((Object)(object)RoundDirector.instance?.photonView == (Object)null)) { if (RoundDirector.instance.extractionPointActive && (Object)(object)RoundDirector.instance.extractionPointCurrent != (Object)null && (Object)(object)RoundDirector.instance.extractionPointCurrent.photonView != (Object)null) { RoundDirector.instance.photonView.RPC("ExtractionPointActivateRPC", targetPlayer, new object[1] { RoundDirector.instance.extractionPointCurrent.photonView.ViewID }); } else { RoundDirector.instance.photonView.RPC("ExtractionPointsUnlockRPC", targetPlayer, Array.Empty<object>()); } if (RoundDirector.instance.allExtractionPointsCompleted) { RoundDirector.instance.photonView.RPC("ExtractionCompletedAllRPC", targetPlayer, Array.Empty<object>()); } } } private void EmpressMaintainWaitingPlayers() { //IL_0082: 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) //IL_0088: 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_00b0: 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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) if (!EmpressCanHostLateJoinLogic() || _empressHostWaitingActors.Count == 0) { return; } foreach (int item3 in _empressHostWaitingActors.ToList()) { PlayerAvatar val = EmpressFindAvatar(item3); if ((Object)(object)val == (Object)null || (Object)(object)val.photonView == (Object)null) { _empressHostWaitingActors.Remove(item3); _empressNextSnapByActor.Remove(item3); } else { if (!SemiFunc.RunIsLevel()) { continue; } (Vector3 position, Quaternion rotation) tuple = EmpressGetWaitingSpawn(item3); Vector3 item = tuple.position; Quaternion item2 = tuple.rotation; float num = Mathf.Max(1f, EmpressLateJoinPlugin.Instance.EmpressWaitingLeashRadius.Value); if (!(Vector3.Distance(((Component)val).transform.position, item) <= num)) { float value; float num2 = (_empressNextSnapByActor.TryGetValue(item3, out value) ? value : 0f); if (!(Time.unscaledTime < num2)) { val.Spawn(item, item2); _empressNextSnapByActor[item3] = Time.unscaledTime + Mathf.Max(0.1f, EmpressLateJoinPlugin.Instance.EmpressWaitingSnapCooldown.Value); } } } } } private void EmpressProcessDelayedSceneChange() { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) if (_empressDelayedSceneChange == null) { return; } EmpressDelayedSceneChangeRequest empressDelayedSceneChange = _empressDelayedSceneChange; if ((Object)(object)empressDelayedSceneChange.RunManager == (Object)null || ((object)empressDelayedSceneChange.RunManager).Equals((object?)null)) { _empressDelayedSceneChange = null; return; } float num = Mathf.Max(1f, EmpressLateJoinPlugin.Instance.EmpressSceneSwitchSettleTimeout.Value); bool flag = Time.unscaledTime - empressDelayedSceneChange.RequestedAt >= num; if (_empressLateJoinDetectedAt.Count > 0 && !flag) { return; } if (_empressLateJoinDetectedAt.Count > 0 && flag && !empressDelayedSceneChange.TimeoutLogged) { empressDelayedSceneChange.TimeoutLogged = true; EmpressLateJoinPlugin.Instance.EmpressLog.LogWarning((object)$"EmpressLateJoin is forcing the delayed scene switch after {num:0.0}s because these actors never finished settling: {EmpressDescribeTrackedLateJoiners()}."); } _empressDelayedSceneChange = null; EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)"EmpressLateJoin is replaying the delayed scene switch."); _empressRunningDelayedSceneChange = true; try { empressDelayedSceneChange.RunManager.ChangeLevel(empressDelayedSceneChange.CompletedLevel, empressDelayedSceneChange.LevelFailed, empressDelayedSceneChange.ChangeLevelType); } finally { _empressRunningDelayedSceneChange = false; } } private void EmpressQueueLateJoiner(PlayerAvatar avatar) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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) int ownerActorNr = avatar.photonView.OwnerActorNr; _empressHostWaitingActors.Add(ownerActorNr); var (val, val2) = EmpressGetWaitingSpawn(ownerActorNr); avatar.Spawn(val, val2); EmpressRefreshAvatarRoomState(avatar); EmpressBackfillLateJoinerIntoEnemySystems(avatar); EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"Parked late joiner {EmpressGetAvatarDisplayName(avatar)} ({ownerActorNr}) in the Empress holding cell."); } private void EmpressAdmitLateJoiner(PlayerAvatar avatar) { //IL_003e: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) int ownerActorNr = avatar.photonView.OwnerActorNr; _empressHostWaitingActors.Remove(ownerActorNr); _empressNextSnapByActor.Remove(ownerActorNr); Vector3 val; Quaternion val2; if (EmpressLiveJoinEnabled() && SemiFunc.RunIsLevel()) { (val, val2) = EmpressGetWaitingSpawn(ownerActorNr); } else { (val, val2) = EmpressGetAdmissionSpawn(avatar); } avatar.Spawn(val, val2); EmpressRefreshAvatarRoomState(avatar); EmpressBackfillLateJoinerIntoEnemySystems(avatar); EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"Admitted late joiner {EmpressGetAvatarDisplayName(avatar)} ({ownerActorNr}) directly into the current scene at the truck spawn."); } private void EmpressEnsureSupportObjects(PlayerAvatar avatar) { //IL_0091: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)avatar == (Object)null || (Object)(object)LevelGenerator.Instance == (Object)null || SemiFunc.MenuLevel() || !EmpressHasAvatarSteamIdentity(avatar)) { return; } bool flag = false; GameObject val = EmpressGetLevelDeathHeadPrefab(); PlayerDeathHead val2 = EmpressGetAvatarDeathHead(avatar); if ((Object)(object)val2 != (Object)null) { flag |= EmpressRepairDeathHeadSupport(avatar, val2); } else if ((Object)(object)val != (Object)null) { val2 = (GameManager.Multiplayer() ? PhotonNetwork.Instantiate(((Object)val).name, new Vector3(0f, 3000f, 0f), Quaternion.identity, (byte)0, (object[])null) : Object.Instantiate<GameObject>(val, new Vector3(0f, 3000f, 0f), Quaternion.identity)).GetComponent<PlayerDeathHead>(); if ((Object)(object)val2 != (Object)null) { val2.playerAvatar = avatar; EmpressSetAvatarDeathHead(avatar, val2); flag = true; } } GameObject val3 = EmpressGetLevelTumblePrefab(); PlayerTumble val4 = EmpressGetAvatarTumble(avatar); if ((Object)(object)val4 != (Object)null) { flag |= EmpressRepairTumbleSupport(avatar, val4); } else if ((Object)(object)val3 != (Object)null) { val4 = (GameManager.Multiplayer() ? PhotonNetwork.Instantiate(((Object)val3).name, new Vector3(0f, 3000f, 0f), Quaternion.identity, (byte)0, (object[])null) : Object.Instantiate<GameObject>(val3, new Vector3(0f, 3000f, 0f), Quaternion.identity)).GetComponent<PlayerTumble>(); if ((Object)(object)val4 != (Object)null) { val4.playerAvatar = avatar; EmpressSetAvatarTumble(avatar, val4); flag = true; } } if (flag) { EmpressLateJoinPlugin? instance = EmpressLateJoinPlugin.Instance; if (instance != null) { instance.EmpressLog.LogDebug((object)("EmpressLateJoin prepared support objects for " + EmpressGetAvatarDisplayName(avatar) + ".")); } } } private bool EmpressRepairDeathHeadSupport(PlayerAvatar avatar, PlayerDeathHead deathHead) { bool result = false; if ((Object)(object)deathHead.playerAvatar != (Object)(object)avatar) { deathHead.playerAvatar = avatar; EmpressSetAvatarDeathHead(avatar, deathHead); result = true; } if (!EmpressGetDeathHeadSetup(deathHead) && (Object)(object)EmpressGetDeathHeadPhysGrabObject(deathHead) != (Object)null) { try { deathHead.SetupDone(); EmpressSetDeathHeadSetup(deathHead, setup: true); result = true; } catch (Exception ex) { EmpressLateJoinPlugin? instance = EmpressLateJoinPlugin.Instance; if (instance != null) { instance.EmpressLog.LogDebug((object)("EmpressLateJoin could not finish death head setup for " + EmpressGetAvatarDisplayName(avatar) + ": " + ex.Message)); } } } return result; } private bool EmpressRepairTumbleSupport(PlayerAvatar avatar, PlayerTumble tumble) { bool result = false; if ((Object)(object)tumble.playerAvatar != (Object)(object)avatar) { tumble.playerAvatar = avatar; EmpressSetAvatarTumble(avatar, tumble); result = true; } if (!EmpressGetTumbleSetup(tumble) && (Object)(object)EmpressGetTumblePhysGrabObject(tumble) != (Object)null) { try { tumble.SetupDone(); result = true; } catch (Exception ex) { EmpressLateJoinPlugin? instance = EmpressLateJoinPlugin.Instance; if (instance != null) { instance.EmpressLog.LogDebug((object)("EmpressLateJoin could not finish tumble setup for " + EmpressGetAvatarDisplayName(avatar) + ": " + ex.Message)); } } } return result; } private (Vector3 position, Quaternion rotation) EmpressGetAdmissionSpawn(PlayerAvatar lateJoiner) { //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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) List<SpawnPoint> list = EmpressFindSceneObjects<SpawnPoint>(); if (list.Count == 0) { return EmpressGetFallbackSpawn(); } SpawnPoint val = list[0]; float num = float.NegativeInfinity; foreach (SpawnPoint item in list) { if ((Object)(object)item == (Object)null) { continue; } float num2 = float.PositiveInfinity; foreach (PlayerAvatar item2 in SemiFunc.PlayerGetList()) { if (!((Object)(object)item2 == (Object)null) && !((Object)(object)item2 == (Object)(object)lateJoiner) && EmpressGetAvatarSpawned(item2) && !((Object)(object)item2.photonView == (Object)null) && !_empressHostWaitingActors.Contains(item2.photonView.OwnerActorNr)) { num2 = Mathf.Min(num2, Vector3.Distance(((Component)item).transform.position, ((Component)item2).transform.position)); } } float num3 = (float.IsPositiveInfinity(num2) ? 9999f : num2); if (num3 > num) { num = num3; val = item; } } return (((Component)val).transform.position, ((Component)val).transform.rotation); } private (Vector3 position, Quaternion rotation) EmpressGetWaitingSpawn(int actorNumber) { //IL_0007: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //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_005c: Unknown result type (might be due to invalid IL or missing references) (Vector3 position, Quaternion rotation) tuple = EmpressGetWaitingAnchor(); Vector3 item = tuple.position; Quaternion item2 = tuple.rotation; float num = (float)actorNumber * 47f; float num2 = 1.3f + (float)(actorNumber % 3) * 0.45f; Vector3 val = Quaternion.Euler(0f, num, 0f) * new Vector3(0f, 0f, num2); return (item + val, item2); } private (Vector3 position, Quaternion rotation) EmpressGetWaitingAnchor() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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) TruckSafetySpawnPoint val = EmpressFindSceneObjects<TruckSafetySpawnPoint>().FirstOrDefault(); if ((Object)(object)val != (Object)null) { return (((Component)val).transform.position, ((Component)val).transform.rotation); } List<SpawnPoint> list = EmpressFindSceneObjects<SpawnPoint>(); if (list.Count > 0 && (Object)(object)list[0] != (Object)null) { return (((Component)list[0]).transform.position, ((Component)list[0]).transform.rotation); } return EmpressGetFallbackSpawn(); } private static (Vector3 position, Quaternion rotation) EmpressGetFallbackSpawn() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_0048: 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) if ((Object)(object)PlayerController.instance != (Object)null) { return (((Component)PlayerController.instance).transform.position, ((Component)PlayerController.instance).transform.rotation); } if ((Object)(object)Camera.main != (Object)null) { return (((Component)Camera.main).transform.position, ((Component)Camera.main).transform.rotation); } return (Vector3.zero, Quaternion.identity); } private static PlayerAvatar? EmpressFindAvatar(int actorNumber) { return ((IEnumerable<PlayerAvatar>)SemiFunc.PlayerGetList()).FirstOrDefault((Func<PlayerAvatar, bool>)((PlayerAvatar player) => (Object)(object)player != (Object)null && (Object)(object)player.photonView != (Object)null && player.photonView.OwnerActorNr == actorNumber)); } private bool EmpressShouldQueueLateJoiner() { if (!SemiFunc.RunIsLevel()) { return false; } if (EmpressLiveJoinEnabled()) { return false; } return EmpressLateJoinPlugin.Instance.EmpressQueueDuringActiveLevels.Value; } private void EmpressTrackLateJoin(int actorNumber) { if (!_empressLateJoinDetectedAt.ContainsKey(actorNumber)) { _empressLateJoinDetectedAt[actorNumber] = Time.unscaledTime; } _empressDeferredWaitingRoomActors.Remove(actorNumber); _empressEnemyRegisteredActors.Remove(actorNumber); _empressLiveJoinLevelUpdateSentActors.Remove(actorNumber); _empressLiveJoinBootstrapSentActors.Remove(actorNumber); _empressLiveStateReplayedActors.Remove(actorNumber); _empressLateJoinReadyAt.Remove(actorNumber); } private void EmpressClearLateJoinTracking(int actorNumber) { _empressLateJoinDetectedAt.Remove(actorNumber); _empressLateJoinReadyAt.Remove(actorNumber); } private bool EmpressEnsureRunLevelWaitingRoomMode() { if (EmpressLiveJoinEnabled()) { return false; } if (_empressRunLevelCachePruned) { return true; } if (!EmpressCanHostRoomControl() || !SemiFunc.RunIsLevel()) { return false; } if ((Object)(object)EmpressGetRunManagerPhotonView() == (Object)null) { return false; } int num = EmpressPruneBufferedRunLevelState(); if (num <= 0) { return false; } _empressRunLevelCachePruned = true; _empressHostWaitingActors.Clear(); _empressLateJoinDetectedAt.Clear(); _empressLateJoinReadyAt.Clear(); _empressDelayedSceneChange = null; EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"EmpressLateJoin pruned buffered active-level state for {num} Photon views. New joiners will wait for the next scene instead of loading into the live run."); return true; } private bool EmpressIsLateJoinerSettled(PlayerAvatar avatar, float detectedAt) { if (!EmpressGetAvatarSpawned(avatar)) { return false; } if (string.IsNullOrWhiteSpace(EmpressGetAvatarSteamId(avatar)) || string.IsNullOrWhiteSpace(EmpressGetAvatarPlayerName(avatar))) { return false; } if (!EmpressHasSupportObjectsReady(avatar)) { return false; } int num = (((Object)(object)avatar.photonView != (Object)null) ? avatar.photonView.OwnerActorNr : 0); if (num > 0 && !_empressEnemyRegisteredActors.Contains(num)) { return false; } float num2 = Time.unscaledTime - detectedAt; if (num2 < 0.5f) { return false; } if (EmpressGetAvatarLevelAnimationCompleted(avatar)) { return true; } return num2 >= Mathf.Max(0.75f, EmpressLateJoinPlugin.Instance.EmpressSceneSwitchSettleDelay.Value); } private void EmpressBackfillLateJoinerIntoEnemySystems(PlayerAvatar avatar) { if ((Object)(object)avatar.photonView == (Object)null) { return; } int ownerActorNr = avatar.photonView.OwnerActorNr; int viewID = avatar.photonView.ViewID; if (ownerActorNr <= 0 || viewID <= 0 || _empressEnemyRegisteredActors.Contains(ownerActorNr)) { return; } HashSet<Enemy> hashSet = new HashSet<Enemy>(from enemy in EmpressFindSceneObjects<Enemy>() where (Object)(object)enemy != (Object)null select enemy); if (hashSet.Count == 0) { return; } int num = 0; foreach (Enemy item in hashSet) { try { item.PlayerAdded(viewID); num++; } catch (Exception ex) { EmpressLateJoinPlugin? instance = EmpressLateJoinPlugin.Instance; if (instance != null) { instance.EmpressLog.LogDebug((object)$"EmpressLateJoin could not backfill {EmpressGetAvatarDisplayName(avatar)} ({ownerActorNr}) into enemy {((Object)item).name}: {ex.Message}"); } } } _empressEnemyRegisteredActors.Add(ownerActorNr); EmpressLateJoinPlugin.Instance.EmpressLog.LogInfo((object)$"EmpressLateJoin backfilled {EmpressGetAvatarDisplayName(avatar)} ({ownerActorNr}) into {num} enemy trackers."); } private static void EmpressRefreshAvatarRoomState(PlayerAvatar avatar) { try { RoomVolumeCheck roomVolumeCheck = avatar.RoomVolumeCheck; if (roomVolumeCheck != null) { roomVolumeCheck.CheckSet(); } } catch { } } private int EmpressPruneBufferedRunLevelState() { int num = 0; PhotonView val = EmpressGetRunManagerPhotonView(); if ((Object)(object)val != (Object)null) { PhotonNetwork.RemoveBufferedRPCs(val.ViewID, "UpdateLevelRPC", (int[])null); num++; } PhotonView val2 = EmpressGetFieldValue<PhotonView>(EmpressLevelGeneratorPhotonViewField, LevelGenerator.Instance); if ((Object)(object)val2 != (Object)null) { PhotonNetwork.RemoveBufferedRPCs(val2.ViewID, (string)null, (int[])null); num++; } return num; } private void EmpressRemoveInstantiationCache(PhotonView photonView) { //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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_003f: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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) if (photonView.InstantiationId == 0 || EmpressPhotonRaiseEventInternalMethod == null) { return; } object obj = EmpressPhotonKeyByteSevenField?.GetValue(null); if (obj == null) { return; } Hashtable val = EmpressGetFieldValue<Hashtable>(EmpressPhotonRemoveFilterField, null); Hashtable val2 = new Hashtable(); if (val != null) { DictionaryEntryEnumerator enumerator = val.GetEnumerator(); try { while (((DictionaryEntryEnumerator)(ref enumerator)).MoveNext()) { DictionaryEntry current = ((DictionaryEntryEnumerator)(ref enumerator)).Current; val2[current.Key] = current.Value; } } finally { ((IDisposable)(DictionaryEntryEnumerator)(ref enumerator)).Dispose(); } } val2[obj] = photonView.InstantiationId; RaiseEventOptions val3 = EmpressGetFieldValue<RaiseEventOptions>(EmpressPhotonServerCleanOptionsField, null); EventCaching cachingOption = (EventCaching)((val3 != null) ? ((int)val3.CachingOption) : 0); RaiseEventOptions val4 = (RaiseEventOptions)(((object)val3) ?? ((object)new RaiseEventOptions())); val4.CachingOption = (EventCaching)6; try { EmpressPhotonRaiseEventInternalMethod.Invoke(null, new object[4] { (byte)202, val2, val4, SendOptions.SendReliable }); } catch (Exception ex) { EmpressLateJoinPlugin? instance = EmpressLateJoinPlugin.Instance; if (instance != null) { instance.EmpressLog.LogDebug((object)("EmpressLateJoin could not clear instantiation cache for " + ((Object)photonView).name + ": " + ex.Message)); } } finally { if (val3 != null) { val3.CachingOption = cachingOption; } } } private static PhotonView? EmpressGetRunManagerPhotonView() { RunManagerPUN val = EmpressGetFieldValue<RunManagerPUN>(EmpressRunManagerPunField, RunManager.instance); if ((Object)(object)val == (Object)null) { return null; } return EmpressGetFieldValue<PhotonView>(EmpressRunManagerPunPhotonViewField, val); } private static bool EmpressIsActorStillConnected(int actorNumber) { if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null) { return false; } return PhotonNetwork.CurrentRoom.Players.ContainsKey(actorNumber); } private string EmpressDescribeTrackedLateJoiners() { List<string> list = new List<string>(); foreach (int item in _empressLateJoinDetectedAt.Keys.OrderBy((int value) => value)) { PlayerAvatar val = EmpressFindAvatar(item); Player value2; if ((Object)(object)val != (Object)null) { list.Add($"{EmpressGetAvatarDisplayName(val)} ({item})"); } else if (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.Players.TryGetValue(item, out value2)) { list.Add($"{value2.NickName} ({item})"); } else { list.Add(item.ToString()); } } if (list.Count != 0) { return string.Join(", ", list); } return "unknown players"; } private static bool EmpressCanHostRoomControl() { if ((Object)(object)EmpressLateJoinPlugin.Instance == (Object)null || !EmpressLateJoinPlugin.Instance.EmpressEnabled.Value) { return false; } if ((Object)(object)GameManager.instance == (Object)null || !PhotonNetwork.InRoom || !GameManager.Multiplayer() || !PhotonNetwork.IsMasterClient) { return false; } return true; } private static bool EmpressCanHostLateJoinLogic() { if (!EmpressCanHostRoomControl()) { return false; } if ((Object)(object)GameDirector.instance == (Object)null || (Object)(object)LevelGenerator.Instance == (Object)null) { return false; } return SemiFunc.LevelGenDone(); } private static bool EmpressGetConnectRandom() { return EmpressGetFieldValue<bool>(EmpressGameManagerConnectRandomField, GameManager.instance); } private static bool EmpressGetAvatarSpawned(PlayerAvatar avatar) { return EmpressGetFieldValue<bool>(EmpressPlayerAvatarSpawnedField, avatar); } private static string EmpressGetAvatarSteamId(PlayerAvatar avatar) { return EmpressGetFieldValue<string>(EmpressPlayerAvatarSteamIdField, avatar) ?? string.Empty; } private static bool EmpressHasAvatarSteamIdentity(PlayerAvatar avatar) { if ((Object)(object)avatar != (Object)null) { return !string.IsNullOrWhiteSpace(EmpressGetAvatarSteamId(avatar)); } return false; } private static string EmpressGetAvatarPlayerName(PlayerAvatar avatar) { return EmpressGetFieldValue<string>(EmpressPlayerAvatarPlayerNameField, avatar) ?? string.Empty; } private static bool EmpressGetAvatarLevelAnimationCompleted(PlayerAvatar avatar) { return EmpressGetFieldValue<bool>(EmpressPlayerAvatarLevelAnimationCompletedField, avatar); } private static bool EmpressHasSupportObjectsReady(PlayerAvatar avatar) { PlayerDeathHead val = EmpressGetAvatarDeathHead(avatar); if ((Object)(object)val == (Object)null || (Object)(object)val.playerAvatar != (Object)(object)avatar || !EmpressGetDeathHeadSetup(val)) { return false; } PlayerTumble val2 = EmpressGetAvatarTumble(avatar); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.playerAvatar == (Object)(object)avatar) { return EmpressGetTumbleSetup(val2); } return false; } private static PlayerDeathHead? EmpressGetAvatarDeathHead(PlayerAvatar avatar) { return EmpressGetFieldValue<PlayerDeathHead>(EmpressPlayerAvatarDeathHeadField, avatar); } private static void EmpressSetAvatarDeathHead(PlayerAvatar avatar, PlayerDeathHead deathHead) { EmpressSetFieldValue(EmpressPlayerAvatarDeathHeadField, avatar, deathHead); } private static PlayerTumble? EmpressGetAvatarTumble(PlayerAvatar avatar) { return EmpressGetFieldValue<PlayerTumble>(EmpressPlayerAvatarTumbleField, avatar); } private static void EmpressSetAvatarTumble(PlayerAvatar avatar, PlayerTumble tumble) { EmpressSetFieldValue(EmpressPlayerAvatarTumbleField, avatar, tumble); } private static bool EmpressGetDeathHeadSetup(PlayerDeathHead deathHead) { return EmpressGetFieldValue<bool>(EmpressPlayerDeathHeadSetupField, deathHead); } private static PhysGrabObject? EmpressGetDeathHeadPhysGrabObject(PlayerDeathHead deathHead) { return EmpressGetFieldValue<PhysGrabObject>(EmpressPlayerDeathHeadPhysGrabObjectField, deathHead); } private static void EmpressSetDeathHeadSetup(PlayerDeathHead deathHead, bool setup) { EmpressSetFieldValue(EmpressPlayerDeathHeadSetupField, deathHead, setup); } private static PhysGrabObject? EmpressGetTumblePhysGrabObject(PlayerTumble tumble) { return EmpressGetFieldValue<PhysGrabObject>(EmpressPlayerTumblePhysGrabObjectField, tumble); } private static bool EmpressGetTumbleSetup(PlayerTumble tumble) { return EmpressGetFieldValue<bool>(EmpressPlayerTumbleSetupField, tumble); } private static GameObject? EmpressGetLevelDeathHeadPrefab() { return EmpressGetFieldValue<GameObject>(EmpressLevelGeneratorDeathHeadPrefabField, LevelGenerator.Instance); } private static GameObject? EmpressGetLevelTumblePrefab() { return EmpressGetFieldValue<GameObject>(EmpressLevelGeneratorTumblePrefabField, LevelGenerator.Instance); } private static List<T> EmpressFindSceneObjects<T>() where T : Object { //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_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_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_00ad: 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) List<T> list = new List<T>(); T[] array = Resources.FindObjectsOfTypeAll<T>(); foreach (T val in array) { if ((Object)(object)val == (Object)null) { continue; } T val2 = val; object obj = val2; Component val3 = (Component)((obj is Component) ? obj : null); Scene scene; if (val3 == null) { object obj2 = val2; GameObject val4 = (GameObject)((obj2 is GameObject) ? obj2 : null); if (val4 == null) { continue; } GameObject val5 = val4; scene = val5.scene; if (((Scene)(ref scene)).IsValid()) { scene = val5.scene; if (!string.IsNullOrWhiteSpace(((Scene)(ref scene)).name)) { list.Add(val); } } continue; } Component val6 = val3; scene = val6.gameObject.scene; if (((Scene)(ref scene)).IsValid()) { scene = val6.gameObject.scene; if (!string.IsNullOrWhiteSpace(((Scene)(ref scene)).name)) { list.Add(val); } } } return list; } private static string EmpressGetAvatarDisplayName(PlayerAvatar avatar) { PhotonView photonView = avatar.photonView; if (((photonView != null) ? photonView.Owner : null) != null && !string.IsNullOrWhiteSpace(avatar.photonView.Owner.NickName)) { return avatar.photonView.Owner.NickName; } string text = EmpressGetAvatarPlayerName(avatar); if (!string.IsNullOrWhiteSpace(text)) { return text; } return ((Object)avatar).name; } private static Hashtable EmpressConvertDictionaryToHashtable(Dictionary<string, int> dictionary) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown Hashtable val = new Hashtable(); foreach (KeyValuePair<string, int> item in dictionary) { val[(object)item.Key] = item.Value; } return val; } private static T EmpressGetFieldValue<T>(FieldInfo? fieldInfo, object? instance) { if (fieldInfo == null || (!fieldInfo.IsStatic && instance == null)) { return default(T); } try { object value = fieldInfo.GetValue(fieldInfo.IsStatic ? null : instance); if (value is T) { return (T)value; } } catch { } return default(T); } private static void EmpressSetFieldValue(FieldInfo? fieldInfo, object? instance, object? value) { if (fieldInfo == null || (!fieldInfo.IsStatic && instance == null)) { return; } try { fieldInfo.SetValue(fieldInfo.IsStatic ? null : instance, value); } catch { } } } [HarmonyPatch(typeof(LevelGenerator), "PlayerSpawn")] internal static class EmpressLateJoinLevelGeneratorPatch { private static bool Prefix() { return !(EmpressLateJoinPlugin.Runtime?.EmpressTryHandleLateJoinSpawn() ?? false); } } [HarmonyPatch(typeof(NetworkManager), "OnPlayerEnteredRoom")] internal static class EmpressLateJoinPlayerEnteredPatch { private static void Postfix(Player newPlayer) { EmpressLateJoinPlugin.Runtime?.EmpressHandlePlayerEntered(newPlayer); } } [HarmonyPatch(typeof(NetworkManager), "OnPlayerLeftRoom")] internal static class EmpressLateJoinPlayerLeftPatch { private static void Postfix(Player otherPlayer) { EmpressLateJoinPlugin.Runtime?.EmpressHandlePlayerLeft(otherPlayer); } } [HarmonyPatch(typeof(MenuPageLobby), "ButtonStart")] internal static class EmpressLateJoinLobbyStartPatch { private static void Postfix() { EmpressLateJoinPlugin.Runtime?.EmpressForceJoinabilityRefresh(forceSteamLobbyUnlock: true); EmpressLateJoinPlugin? instance = EmpressLateJoinPlugin.Instance; if (instance != null) { instance.EmpressLog.LogInfo((object)"EmpressLateJoin reopened the room immediately after the host pressed Start."); } } } [HarmonyPatch(typeof(RunManager), "ChangeLevel")] internal static class EmpressLateJoinChangeLevelPatch { private static bool Prefix(RunManager __instance, bool _completedLevel, bool _levelFailed, ChangeLevelType _changeLevelType) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) return !(EmpressLateJoinPlugin.Runtime?.EmpressTryDelaySceneChange(__instance, _completedLevel, _levelFailed, _changeLevelType) ?? false); } private static void Postfix(RunManager __instance, ChangeLevelType _changeLevelType) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) EmpressLateJoinPlugin.Runtime?.EmpressHandleChangeLevelCompleted(__instance, _changeLevelType); } } internal static class EmpressLateJoinGrabGuard { internal static bool TryResolveGrabber(int playerPhotonId, string rpcName) { if (playerPhotonId <= 0) { EmpressLateJoinPlugin? instance = EmpressLateJoinPlugin.Instance; if (instance != null) { instance.EmpressLog.LogDebug((object)("EmpressLateJoin ignored " + rpcName + " because it referenced an invalid player grabber view id.")); } return false; } PhotonView val = PhotonView.Find(playerPhotonId); if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponent<PhysGrabber>() != (Object)null) { return true; } EmpressLateJoinPlugin? instance2 = EmpressLateJoinPlugin.Instance; if (instance2 != null) { instance2.EmpressLog.LogDebug((object)$"EmpressLateJoin ignored {rpcName} because player grabber view {playerPhotonId} is not available on the host yet."); } return false; } } [HarmonyPatch(typeof(PhysGrabObject), "GrabLinkRPC", new Type[] { typeof(int), typeof(int), typeof(Vector3), typeof(Vector3), typeof(Vector3) })] internal static class EmpressLateJoinPhysGrabObjectGrabLinkPatch { private static bool Prefix(PhysGrabObject __instance, int playerPhotonID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(playerPhotonID, "PhysGrabObject.GrabLinkRPC on " + ((Object)__instance).name); } } [HarmonyPatch(typeof(PhysGrabObject), "GrabPointSyncRPC", new Type[] { typeof(int), typeof(Vector3) })] internal static class EmpressLateJoinPhysGrabObjectGrabPointSyncPatch { private static bool Prefix(PhysGrabObject __instance, int playerPhotonID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(playerPhotonID, "PhysGrabObject.GrabPointSyncRPC on " + ((Object)__instance).name); } } [HarmonyPatch(typeof(PhysGrabObject), "GrabStartedRPC", new Type[] { typeof(int), typeof(PhotonMessageInfo) })] internal static class EmpressLateJoinPhysGrabObjectGrabStartedPatch { private static bool Prefix(PhysGrabObject __instance, int playerPhotonID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(playerPhotonID, "PhysGrabObject.GrabStartedRPC on " + ((Object)__instance).name); } } [HarmonyPatch(typeof(PhysGrabObject), "GrabPlayerAddRPC", new Type[] { typeof(int) })] internal static class EmpressLateJoinPhysGrabObjectGrabPlayerAddPatch { private static bool Prefix(PhysGrabObject __instance, int photonViewID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(photonViewID, "PhysGrabObject.GrabPlayerAddRPC on " + ((Object)__instance).name); } } [HarmonyPatch(typeof(PhysGrabObject), "GrabPlayerRemoveRPC", new Type[] { typeof(int) })] internal static class EmpressLateJoinPhysGrabObjectGrabPlayerRemovePatch { private static bool Prefix(PhysGrabObject __instance, int photonViewID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(photonViewID, "PhysGrabObject.GrabPlayerRemoveRPC on " + ((Object)__instance).name); } } [HarmonyPatch(typeof(PhysGrabObject), "GrabEndedRPC", new Type[] { typeof(int), typeof(PhotonMessageInfo) })] internal static class EmpressLateJoinPhysGrabObjectGrabEndedPatch { private static bool Prefix(PhysGrabObject __instance, int playerPhotonID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(playerPhotonID, "PhysGrabObject.GrabEndedRPC on " + ((Object)__instance).name); } } [HarmonyPatch(typeof(StaticGrabObject), "GrabLinkRPC", new Type[] { typeof(int), typeof(Vector3) })] internal static class EmpressLateJoinStaticGrabObjectGrabLinkPatch { private static bool Prefix(StaticGrabObject __instance, int playerPhotonID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(playerPhotonID, "StaticGrabObject.GrabLinkRPC on " + ((Object)__instance).name); } } [HarmonyPatch(typeof(StaticGrabObject), "GrabPointSyncRPC", new Type[] { typeof(int), typeof(Vector3) })] internal static class EmpressLateJoinStaticGrabObjectGrabPointSyncPatch { private static bool Prefix(StaticGrabObject __instance, int playerPhotonID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(playerPhotonID, "StaticGrabObject.GrabPointSyncRPC on " + ((Object)__instance).name); } } [HarmonyPatch(typeof(StaticGrabObject), "GrabStartedRPC", new Type[] { typeof(int) })] internal static class EmpressLateJoinStaticGrabObjectGrabStartedPatch { private static bool Prefix(StaticGrabObject __instance, int playerPhotonID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(playerPhotonID, "StaticGrabObject.GrabStartedRPC on " + ((Object)__instance).name); } } [HarmonyPatch(typeof(StaticGrabObject), "GrabEndedRPC", new Type[] { typeof(int) })] internal static class EmpressLateJoinStaticGrabObjectGrabEndedPatch { private static bool Prefix(StaticGrabObject __instance, int playerPhotonID) { return EmpressLateJoinGrabGuard.TryResolveGrabber(playerPhotonID, "StaticGrabObject.GrabEndedRPC on " + ((Object)__instance).name); } } }