using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using Fusion;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Voice;
using Photon.Voice.Fusion;
using Photon.Voice.Unity;
using UnityEngine;
[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("DarkwaterRejoinFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+859e4696212cace146228777f6b82e506522ba9a")]
[assembly: AssemblyProduct("DarkwaterRejoinFix")]
[assembly: AssemblyTitle("DarkwaterRejoinFix")]
[assembly: AssemblyVersion("1.0.1.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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace DarkwaterRejoinFix
{
[BepInPlugin("DarkwaterRejoinFix", "DarkwaterRejoinFix", "1.0.1")]
public class Plugin : BaseUnityPlugin
{
[CompilerGenerated]
private sealed class <RecoverVoice>d__17 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public int session;
private FusionVoiceClient <voiceClient>5__2;
private int <attempt>5__3;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <RecoverVoice>d__17(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<voiceClient>5__2 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Expected O, but got Unknown
//IL_014a: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<voiceClient>5__2 = Object.FindFirstObjectByType<FusionVoiceClient>();
if (!Object.op_Implicit((Object)(object)<voiceClient>5__2))
{
Logger.LogWarning((object)$"[HotJoinRecovery {session}] FusionVoiceClient not found.");
return false;
}
if (CountRemotePlayers() == 0)
{
Logger.LogInfo((object)$"[HotJoinRecovery {session}] No remote players present, skipping voice recovery.");
return false;
}
LogVoiceState(session, <voiceClient>5__2, "before voice recovery");
if (CountLinkedRemoteSpeakers() > 0)
{
Logger.LogInfo((object)$"[HotJoinRecovery {session}] Voice already linked, skipping reconnect.");
return false;
}
<attempt>5__3 = 1;
goto IL_024c;
case 1:
<>1__state = -1;
goto IL_0144;
case 2:
{
<>1__state = -1;
bool flag = ((VoiceFollowClient)<voiceClient>5__2).ConnectAndJoinRoom();
Logger.LogInfo((object)$"[HotJoinRecovery {session}] Voice attempt {<attempt>5__3}: ConnectAndJoinRoom returned {flag}. state={((VoiceConnection)<voiceClient>5__2).ClientState}.");
<>2__current = (object)new WaitForSeconds(4f);
<>1__state = 3;
return true;
}
case 3:
{
<>1__state = -1;
LogVoiceState(session, <voiceClient>5__2, $"after voice attempt {<attempt>5__3}");
if (CountLinkedRemoteSpeakers() > 0)
{
Logger.LogInfo((object)$"[HotJoinRecovery {session}] Voice linked successfully on attempt {<attempt>5__3}.");
return false;
}
<attempt>5__3++;
goto IL_024c;
}
IL_0144:
<>2__current = (object)new WaitForSeconds(0.5f);
<>1__state = 2;
return true;
IL_024c:
if (<attempt>5__3 <= 2)
{
if (GetClientBool(((VoiceConnection)<voiceClient>5__2).Client, "IsConnected"))
{
Logger.LogInfo((object)$"[HotJoinRecovery {session}] Voice attempt {<attempt>5__3}: disconnecting busy voice client.");
((VoiceFollowClient)<voiceClient>5__2).Disconnect();
<>2__current = WaitForVoiceDisconnect(<voiceClient>5__2, 4f);
<>1__state = 1;
return true;
}
goto IL_0144;
}
Logger.LogWarning((object)$"[HotJoinRecovery {session}] Voice recovery finished without any linked remote speakers.");
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();
}
}
[CompilerGenerated]
private sealed class <RunClientRecovery>d__11 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
private int <session>5__2;
private int <observedRequestVersion>5__3;
private int <attempt>5__4;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <RunClientRecovery>d__11(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Expected O, but got Unknown
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Expected O, but got Unknown
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Expected O, but got Unknown
//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0205: Expected O, but got Unknown
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01bc: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
_clientRecoveryRunning = true;
<session>5__2 = ++_clientRecoverySession;
<observedRequestVersion>5__3 = _clientRecoveryRequestVersion;
Logger.LogInfo((object)$"[HotJoinRecovery {<session>5__2}] Started from {_clientRecoveryLastReason}.");
goto IL_009c;
case 1:
<>1__state = -1;
goto IL_009c;
case 2:
<>1__state = -1;
if (<observedRequestVersion>5__3 != _clientRecoveryRequestVersion)
{
<observedRequestVersion>5__3 = _clientRecoveryRequestVersion;
Logger.LogInfo((object)$"[HotJoinRecovery {<session>5__2}] Waiting for latest targeted sync ({_clientRecoveryLastReason}).");
goto IL_00d6;
}
<>2__current = (object)new WaitForSeconds(2.5f);
<>1__state = 3;
return true;
case 3:
<>1__state = -1;
LogClientState(<session>5__2, "before gameplay recovery");
<attempt>5__4 = 1;
goto IL_01dc;
case 4:
<>1__state = -1;
<attempt>5__4++;
goto IL_01dc;
case 5:
<>1__state = -1;
<>2__current = RecoverVoice(<session>5__2);
<>1__state = 6;
return true;
case 6:
{
<>1__state = -1;
LogClientState(<session>5__2, "after voice recovery");
CMD.Instance.hotJoined = false;
_clientRecoveryRunning = false;
Logger.LogInfo((object)$"[HotJoinRecovery {<session>5__2}] Finished.");
return false;
}
IL_01dc:
if (<attempt>5__4 <= 8)
{
if (!StabilizeLocalHotJoinState(<session>5__2, <attempt>5__4))
{
<>2__current = (object)new WaitForSeconds(0.5f);
<>1__state = 4;
return true;
}
Logger.LogInfo((object)$"[HotJoinRecovery {<session>5__2}] Local gameplay state stabilized on attempt {<attempt>5__4}.");
}
LogClientState(<session>5__2, "after gameplay recovery");
<>2__current = (object)new WaitForSeconds(1.5f);
<>1__state = 5;
return true;
IL_009c:
if (!Object.op_Implicit((Object)(object)CMD_PlayerManager.Instance) || !Object.op_Implicit((Object)(object)CMD_PlayerManager.Instance.localPlayer) || !Object.op_Implicit((Object)(object)CMD_ShipManager.Instance) || !Object.op_Implicit((Object)(object)CMD_ShipManager.Instance.playerShip))
{
<>2__current = (object)new WaitForSeconds(0.25f);
<>1__state = 1;
return true;
}
goto IL_00d6;
IL_00d6:
<>2__current = (object)new WaitForSeconds(1.5f);
<>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();
}
}
[CompilerGenerated]
private sealed class <WaitForVoiceDisconnect>d__18 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public float timeoutSeconds;
public FusionVoiceClient voiceClient;
private float <endTime>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <WaitForVoiceDisconnect>d__18(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<endTime>5__2 = Time.time + timeoutSeconds;
break;
case 1:
<>1__state = -1;
break;
}
if (Time.time < <endTime>5__2 && GetClientBool(((VoiceConnection)voiceClient).Client, "IsConnected"))
{
<>2__current = (object)new WaitForSeconds(0.1f);
<>1__state = 1;
return true;
}
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
internal const string StoreReplaySeed = "__dw_store__";
internal static ManualLogSource Logger;
private Harmony _harmony;
private static bool _clientRecoveryRunning;
private static int _clientRecoverySession;
private static int _clientRecoveryRequestVersion;
private static string _clientRecoveryLastReason = "unknown";
private static int _suppressDockOutpost;
private void Awake()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
_harmony = new Harmony("DarkwaterRejoinFix");
_harmony.PatchAll();
Logger.LogInfo((object)"Plugin DarkwaterRejoinFix is loaded!");
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
internal static void StartClientRecovery(MonoBehaviour host, string reason)
{
_clientRecoveryLastReason = reason;
_clientRecoveryRequestVersion++;
if (_clientRecoveryRunning)
{
Logger.LogInfo((object)("[HotJoinRecovery] Client recovery refreshed by " + reason + "."));
}
else
{
host.StartCoroutine(RunClientRecovery());
}
}
[IteratorStateMachine(typeof(<RunClientRecovery>d__11))]
private static IEnumerator RunClientRecovery()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <RunClientRecovery>d__11(0);
}
private static bool StabilizeLocalHotJoinState(int session, int attempt)
{
//IL_000c: 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_0017: 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_004b: 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_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Invalid comparison between Unknown and I4
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_0177: 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_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
C_Controller_Player localPlayer = CMD_PlayerManager.Instance.localPlayer;
ShipNetworkID val = DetermineDesiredLocalSubmarine(localPlayer);
E_Submarine submarine = CMD_ShipManager.Instance.GetSubmarine(val);
Transform val2 = (Object.op_Implicit((Object)(object)submarine) ? submarine.spawnLocation : null);
float num = (Object.op_Implicit((Object)(object)val2) ? Vector3.Distance(((Component)localPlayer).transform.position, val2.position) : (-1f));
((C_Controller)localPlayer).newClient = false;
ApplyDesiredLocalScene(localPlayer, val);
if (((C_Controller)localPlayer).MouseModeEnabled() || localPlayer.requiresRevive)
{
((C_Controller)localPlayer).RPC_MouseMode(false, default(RpcInfo));
localPlayer.requiresRevive = false;
}
if (Object.op_Implicit((Object)(object)CMD_Effects.Instance) && CMD_Effects.Instance.localPlayerUnderwater)
{
CMD_Effects.Instance.LocalPlayerSurface();
}
CMD_PlayerManager.Instance.UpdateAllPlayersMics();
bool flag = !((C_Controller)localPlayer).MouseModeEnabled() && !localPlayer.requiresRevive && ((C_Controller)localPlayer).inOutpost == ((int)val == 2) && ((C_Controller)localPlayer).submarineLocation == val && CMD_ShipManager.Instance.currentSubmarineID == val;
if (flag)
{
bool flag2 = ((num < 0f || num < 4f) ? true : false);
flag = flag2;
}
bool flag3 = flag;
if (attempt == 1 || flag3 || attempt == 8)
{
Logger.LogInfo((object)($"[HotJoinRecovery {session}] Gameplay attempt={attempt} stable={flag3} pos={FormatVector(((Component)localPlayer).transform.position)} " + $"desiredSub={val} sub={((C_Controller)localPlayer).submarineLocation} currentSub={CMD_ShipManager.Instance.currentSubmarineID} inOutpost={((C_Controller)localPlayer).inOutpost} " + string.Format("mouse={0} requiresRevive={1} distToSpawn={2}", ((C_Controller)localPlayer).MouseModeEnabled(), localPlayer.requiresRevive, (num < 0f) ? "n/a" : num.ToString("F2"))));
}
return flag3;
}
private static ShipNetworkID DetermineDesiredLocalSubmarine(C_Controller_Player localPlayer)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Invalid comparison between Unknown and I4
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Invalid comparison between Unknown and I4
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)CMD_ShipManager.Instance) && Object.op_Implicit((Object)(object)CMD_ShipManager.Instance.outpost))
{
if (!((C_Controller)localPlayer).inOutpost && (int)((C_Controller)localPlayer).submarineLocation != 2 && (int)CMD_ShipManager.Instance.currentSubmarineID != 2 && !(((Component)localPlayer).transform.position.y < -2.2f))
{
return (ShipNetworkID)0;
}
return (ShipNetworkID)2;
}
return (ShipNetworkID)0;
}
private static void ApplyDesiredLocalScene(C_Controller_Player localPlayer, ShipNetworkID desiredSubmarine)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Invalid comparison between Unknown and I4
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
if ((int)desiredSubmarine == 2 && Object.op_Implicit((Object)(object)CMD_ShipManager.Instance.outpost))
{
((C_Controller)localPlayer).inOutpost = true;
CMD_ShipManager.Instance.SetCurrentSubmarine((ShipNetworkID)2);
if (Object.op_Implicit((Object)(object)CMD_OutpostManager.Instance))
{
CMD_OutpostManager.Instance.EnterOutpost(CMD_ShipManager.Instance.outpost.shipTheme);
}
}
else
{
if (Object.op_Implicit((Object)(object)CMD_OutpostManager.Instance))
{
CMD_OutpostManager.Instance.ExitOutpost();
}
((C_Controller)localPlayer).inOutpost = false;
CMD_ShipManager.Instance.SetCurrentSubmarine((ShipNetworkID)0);
}
}
internal static bool IsStoreReplay(string seed)
{
return string.Equals(seed, "__dw_store__", StringComparison.Ordinal);
}
internal static void ReplayStoreDock()
{
if (Object.op_Implicit((Object)(object)CMD_OutpostManager.Instance) && Object.op_Implicit((Object)(object)CMD_Store.Instance) && !CMD_OutpostManager.Instance.DockedAtStore())
{
Logger.LogInfo((object)"Replaying local store dock for hot-join client.");
CMD_OutpostManager.Instance.DockWithStore();
CMD_Store.Instance.ModifySubmarine(false);
}
}
[IteratorStateMachine(typeof(<RecoverVoice>d__17))]
private static IEnumerator RecoverVoice(int session)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <RecoverVoice>d__17(0)
{
session = session
};
}
[IteratorStateMachine(typeof(<WaitForVoiceDisconnect>d__18))]
private static IEnumerator WaitForVoiceDisconnect(FusionVoiceClient voiceClient, float timeoutSeconds)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <WaitForVoiceDisconnect>d__18(0)
{
voiceClient = voiceClient,
timeoutSeconds = timeoutSeconds
};
}
private static void LogClientState(int session, string label)
{
//IL_009d: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)CMD_PlayerManager.Instance) || !Object.op_Implicit((Object)(object)CMD_PlayerManager.Instance.localPlayer))
{
Logger.LogInfo((object)$"[HotJoinRecovery {session}] {label}: local player missing.");
return;
}
C_Controller_Player localPlayer = CMD_PlayerManager.Instance.localPlayer;
Transform val = (Object.op_Implicit((Object)(object)CMD_AudioManager.Instance) ? CMD_AudioManager.Instance.localListener : null);
E_Submarine val2 = (Object.op_Implicit((Object)(object)CMD_ShipManager.Instance) ? CMD_ShipManager.Instance.currentSubmarine : null);
Logger.LogInfo((object)($"[HotJoinRecovery {session}] {label}: pos={FormatVector(((Component)localPlayer).transform.position)} head={FormatVector(Object.op_Implicit((Object)(object)((C_Controller)localPlayer).headPosition) ? ((C_Controller)localPlayer).headPosition.position : Vector3.zero)} " + string.Format("listener={0} sub={1} currentSub={2} ", FormatVector(Object.op_Implicit((Object)(object)val) ? val.position : Vector3.zero), ((C_Controller)localPlayer).submarineLocation, Object.op_Implicit((Object)(object)val2) ? ((object)(ShipNetworkID)(ref val2.networkShipType)).ToString() : "null") + $"inOutpost={((C_Controller)localPlayer).inOutpost} mouse={((C_Controller)localPlayer).MouseModeEnabled()} requiresRevive={localPlayer.requiresRevive} linkedSpeakers={CountLinkedRemoteSpeakers()}/{CountRemotePlayers()}."));
}
private static void LogVoiceState(int session, FusionVoiceClient voiceClient, string label)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
object client = ((VoiceConnection)voiceClient).Client;
string currentRoomName = GetCurrentRoomName(client);
Logger.LogInfo((object)(string.Format("[HotJoinRecovery {0}] {1}: voiceState={2} connected={3} ", session, label, ((VoiceConnection)voiceClient).ClientState, GetClientBool(client, "IsConnected")) + string.Format("inRoom={0} room={1} linkedSpeakers={2}/{3}.", GetClientBool(client, "InRoom"), currentRoomName, CountLinkedRemoteSpeakers(), CountRemotePlayers())));
foreach (C_Controller_Player player in CMD_PlayerManager.Instance.players)
{
if (Object.op_Implicit((Object)(object)player) && !((Object)(object)player == (Object)(object)CMD_PlayerManager.Instance.localPlayer))
{
Speaker val = (Object.op_Implicit((Object)(object)player.source_VoiceSpeaker) ? player.source_VoiceSpeaker.SpeakerInUse : null);
AudioSource val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<AudioSource>() : null);
Logger.LogInfo((object)($"[HotJoinRecovery {session}] remote={player.playerName} linked={Object.op_Implicit((Object)(object)val) && val.IsLinked} playing={Object.op_Implicit((Object)(object)val) && val.IsPlaying} " + string.Format("audioEnabled={0} volume={1} room={2}.", Object.op_Implicit((Object)(object)val2) && ((Behaviour)val2).enabled, Object.op_Implicit((Object)(object)val2) ? val2.volume.ToString("F2") : "n/a", currentRoomName)));
}
}
}
private static int CountRemotePlayers()
{
if (!Object.op_Implicit((Object)(object)CMD_PlayerManager.Instance) || CMD_PlayerManager.Instance.players == null)
{
return 0;
}
int num = 0;
C_Controller_Player localPlayer = CMD_PlayerManager.Instance.localPlayer;
foreach (C_Controller_Player player in CMD_PlayerManager.Instance.players)
{
if (Object.op_Implicit((Object)(object)player) && (Object)(object)player != (Object)(object)localPlayer)
{
num++;
}
}
return num;
}
private static int CountLinkedRemoteSpeakers()
{
if (!Object.op_Implicit((Object)(object)CMD_PlayerManager.Instance) || CMD_PlayerManager.Instance.players == null)
{
return 0;
}
int num = 0;
C_Controller_Player localPlayer = CMD_PlayerManager.Instance.localPlayer;
foreach (C_Controller_Player player in CMD_PlayerManager.Instance.players)
{
if (Object.op_Implicit((Object)(object)player) && !((Object)(object)player == (Object)(object)localPlayer) && Object.op_Implicit((Object)(object)player.source_VoiceSpeaker))
{
Speaker speakerInUse = player.source_VoiceSpeaker.SpeakerInUse;
if (Object.op_Implicit((Object)(object)speakerInUse) && speakerInUse.IsLinked)
{
num++;
}
}
}
return num;
}
private static bool GetClientBool(object client, string propertyName)
{
object obj = client.GetType().GetProperty(propertyName)?.GetValue(client);
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
private static string GetCurrentRoomName(object client)
{
object obj = client.GetType().GetProperty("CurrentRoom")?.GetValue(client);
return obj?.GetType().GetProperty("Name")?.GetValue(obj)?.ToString() ?? "null";
}
private static string FormatVector(Vector3 vector)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
return $"({vector.x:F2}, {vector.y:F2}, {vector.z:F2})";
}
internal static bool IsDockOutpostSuppressed()
{
return _suppressDockOutpost > 0;
}
internal static void PushDockOutpostSuppress()
{
_suppressDockOutpost++;
}
internal static void PopDockOutpostSuppress()
{
if (_suppressDockOutpost > 0)
{
_suppressDockOutpost--;
}
}
}
[HarmonyPatch(typeof(CMD_NetworkEssentials), "OnPlayerJoined")]
public static class LateJoinHostPatch
{
[CompilerGenerated]
private sealed class <PlaceLateJoinPlayer>d__1 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public PlayerRef player;
private int <attempt>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <PlaceLateJoinPlayer>d__1(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Expected O, but got Unknown
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Unknown result type (might be due to invalid IL or missing references)
//IL_01a8: Expected O, but got Unknown
//IL_00d7: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: 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_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
//IL_0159: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0177: 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)
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = (object)new WaitForSeconds(2.5f);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
if (Object.op_Implicit((Object)(object)CMD_NetworkEssentials.Instance) && CMD_NetworkEssentials.Instance.PlayerExists(player))
{
<>2__current = ReplayDockedScene(player);
<>1__state = 2;
return true;
}
goto IL_0085;
case 2:
<>1__state = -1;
goto IL_0085;
case 3:
{
<>1__state = -1;
<attempt>5__2++;
break;
}
IL_0085:
<attempt>5__2 = 1;
break;
}
if (<attempt>5__2 <= 4)
{
Transform val = CMD_ShipManager.Instance.GetSubmarine((ShipNetworkID)0)?.spawnLocation;
if (!Object.op_Implicit((Object)(object)val))
{
Plugin.Logger.LogWarning((object)"Late-join placement could not find the player submarine spawn.");
return false;
}
if (Object.op_Implicit((Object)(object)CMD_NetworkEssentials.Instance) && CMD_NetworkEssentials.Instance.PlayerExists(player))
{
C_Controller_Player val2 = CMD_NetworkEssentials.Instance.GetPlayer(player);
Vector3 position = ((Component)val2).transform.position;
if (Object.op_Implicit((Object)(object)val2))
{
val2.RPC_SetCurrentSubmarine((ShipNetworkID)0);
if (((C_Controller)val2).MouseModeEnabled())
{
((C_Controller)val2).RPC_MouseMode(false, default(RpcInfo));
val2.requiresRevive = false;
}
((C_Controller)val2).RPC_SetPosition(val.position, val.eulerAngles, default(RpcInfo));
if (!((C_Controller)val2).MouseModeEnabled() && Vector3.Distance(position, val.position) < 3f)
{
Plugin.Logger.LogInfo((object)$"Placed late-join player {player} at submarine spawn {val.position}.");
return false;
}
}
}
<>2__current = (object)new WaitForSeconds(0.75f);
<>1__state = 3;
return true;
}
Plugin.Logger.LogWarning((object)$"Late-join placement timed out for {player} after {4} attempts.");
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();
}
}
[CompilerGenerated]
private sealed class <ReplayDockedScene>d__2 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public PlayerRef player;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ReplayDockedScene>d__2(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: 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_00ce: Expected O, but got Unknown
//IL_010f: 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_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
{
<>1__state = -1;
if (!Object.op_Implicit((Object)(object)CMD_ShipManager.Instance) || !Object.op_Implicit((Object)(object)CMD_ShipManager.Instance.outpost))
{
return false;
}
if (Object.op_Implicit((Object)(object)CMD_OutpostManager.Instance) && CMD_OutpostManager.Instance.DockedAtStore())
{
Plugin.Logger.LogInfo((object)$"Replaying docked store for late-join player {player}.");
CMD_Network.Instance.RPC_GenerateShip_LoadByChunk_TargetedClient(player, (ShipNetworkID)2, "__dw_store__", string.Empty, ((Component)CMD_OutpostManager.Instance.store).transform.position, true, 1f, 0, CMD_Map.Instance.GetCurrentNodeID());
<>2__current = (object)new WaitForSeconds(0.75f);
<>1__state = 1;
return true;
}
E_Submarine outpost = CMD_ShipManager.Instance.outpost;
float num = ((CMD_DistrictManager.currentDistrict != null) ? CMD_DistrictManager.currentDistrict.GetLightingChance() : 1f);
Plugin.Logger.LogInfo((object)$"Replaying docked outpost for late-join player {player}.");
CMD_Network.Instance.RPC_GenerateShip_LoadByChunk_TargetedClient(player, (ShipNetworkID)2, outpost.seed, outpost.shipInstructions, ((Component)outpost).transform.position, true, num, 0, CMD_Map.Instance.GetCurrentNodeID());
<>2__current = (object)new WaitForSeconds(1.25f);
<>1__state = 2;
return true;
}
case 1:
<>1__state = -1;
return false;
case 2:
<>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();
}
}
private static void Postfix(CMD_NetworkEssentials __instance, NetworkRunner runner, PlayerRef player)
{
//IL_001f: 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)
if (runner.IsServer && CMD_Network.Instance.gameStarted)
{
Plugin.Logger.LogInfo((object)$"Scheduling late-join placement for {player}.");
((MonoBehaviour)__instance).StartCoroutine(PlaceLateJoinPlayer(player));
}
}
[IteratorStateMachine(typeof(<PlaceLateJoinPlayer>d__1))]
private static IEnumerator PlaceLateJoinPlayer(PlayerRef player)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <PlaceLateJoinPlayer>d__1(0)
{
player = player
};
}
[IteratorStateMachine(typeof(<ReplayDockedScene>d__2))]
private static IEnumerator ReplayDockedScene(PlayerRef player)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ReplayDockedScene>d__2(0)
{
player = player
};
}
}
[HarmonyPatch(typeof(CMD_Network), "RPC_LoadByChunk_GenerateSubmarineComplete_Targeted")]
public static class ClientHotJoinRecoveryPatch
{
private static void Postfix(CMD_Network __instance)
{
if (!CMD_Network.Instance.IsHost())
{
Plugin.StartClientRecovery((MonoBehaviour)(object)__instance, "targeted RPC");
}
}
}
[HarmonyPatch(typeof(CMD_Network), "RPC_LoadByChunk_GenerateOutpostComplete_Targeted")]
public static class ClientOutpostRecoveryPatch
{
private static bool Prefix(CMD_Network __instance, string P_seed, ref bool __state)
{
if (CMD_Network.Instance.IsHost())
{
return true;
}
if (Plugin.IsStoreReplay(P_seed))
{
__state = false;
Plugin.ReplayStoreDock();
return false;
}
__state = true;
Plugin.PushDockOutpostSuppress();
return true;
}
private static void Postfix(CMD_Network __instance, string P_seed, bool __state)
{
if (!CMD_Network.Instance.IsHost())
{
if (__state)
{
Plugin.PopDockOutpostSuppress();
}
Plugin.StartClientRecovery((MonoBehaviour)(object)__instance, Plugin.IsStoreReplay(P_seed) ? "targeted store RPC" : "targeted outpost RPC");
}
}
private static void Finalizer(CMD_Network __instance, bool __state)
{
if (!CMD_Network.Instance.IsHost() && __state)
{
Plugin.PopDockOutpostSuppress();
}
}
}
[HarmonyPatch(typeof(CMD_Network), "DockWithOutpost")]
public static class DockWithOutpostGuardPatch
{
private static bool Prefix()
{
if (!Plugin.IsDockOutpostSuppressed())
{
return true;
}
Plugin.Logger.LogInfo((object)"Suppressing DockWithOutpost during targeted outpost hot-join replay.");
return false;
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "DarkwaterRejoinFix";
public const string PLUGIN_NAME = "DarkwaterRejoinFix";
public const string PLUGIN_VERSION = "1.0.1";
}
}