using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Managing;
using FishNet.Managing.Client;
using FishNet.Object;
using FishNet.Transporting;
using FishNet.Transporting.Multipass;
using FishNet.Transporting.UTP;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[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("HumanGenome")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 HumanGenome")]
[assembly: AssemblyFileVersion("0.1.4.0")]
[assembly: AssemblyInformationalVersion("0.1.4+530ef4b059826b59e2f02a1c2d8fc8749661580b")]
[assembly: AssemblyProduct("Driftwood")]
[assembly: AssemblyTitle("DriftwoodConnect")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/HumanGenome/Driftwood")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("0.1.4.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[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 Driftwood.Connect
{
internal static class AddressParser
{
internal static bool TryParse(string text, out string host, out int port)
{
host = null;
port = 0;
if (string.IsNullOrEmpty(text))
{
return false;
}
text = text.Trim();
if (text.Length == 0 || text.Length > 260)
{
return false;
}
bool flag = true;
string text2 = text;
foreach (char c in text2)
{
if (char.IsWhiteSpace(c))
{
return false;
}
if (c < '0' || c > '9')
{
flag = false;
}
}
if (flag)
{
return false;
}
string text3 = null;
string text4;
if (text[0] == '[')
{
int num = text.IndexOf(']');
if (num <= 1)
{
return false;
}
text4 = text.Substring(1, num - 1);
if (text4.IndexOf(':') < 0)
{
return false;
}
string text5 = text.Substring(num + 1);
if (text5.Length > 0)
{
if (text5[0] != ':' || text5.Length < 2)
{
return false;
}
text3 = text5.Substring(1);
}
}
else
{
int num2 = text.LastIndexOf(':');
if (num2 >= 0 && text.IndexOf(':') != num2)
{
return false;
}
if (num2 >= 0)
{
text4 = text.Substring(0, num2);
text3 = text.Substring(num2 + 1);
}
else
{
text4 = text;
}
if (text4.Length == 0 || text4[0] == '.' || text4[0] == '-')
{
return false;
}
bool flag2 = false;
text2 = text4;
foreach (char c2 in text2)
{
if ((c2 < 'a' || c2 > 'z') && (c2 < 'A' || c2 > 'Z') && (c2 < '0' || c2 > '9') && c2 != '.' && c2 != '-')
{
return false;
}
switch (c2)
{
default:
if (c2 < 'A' || c2 > 'Z')
{
continue;
}
break;
case '.':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
break;
}
flag2 = true;
}
if (!flag2)
{
return false;
}
}
if (text3 != null)
{
if (!int.TryParse(text3, NumberStyles.None, CultureInfo.InvariantCulture, out var result))
{
return false;
}
if (result < 1 || result > 65535)
{
return false;
}
port = result;
}
host = text4;
return true;
}
internal static string LabelFor(string host, int port)
{
if (port <= 0)
{
return host;
}
return host + ":" + port;
}
}
internal static class ClaimRules
{
internal const string Route = "/api/v1/identity";
internal const ulong FirstRealSteamId = 76561197960265729uL;
internal const ulong LastRealSteamId = 76561202255233023uL;
internal const int MaxNameLength = 64;
internal static bool IsClaimableSteamId(ulong steamId)
{
if (steamId >= 76561197960265729L)
{
return steamId <= 76561202255233023L;
}
return false;
}
internal static int StatusPortFor(int gamePort)
{
if (gamePort <= 0 || gamePort >= 65535)
{
return 0;
}
return gamePort + 1;
}
internal static string BuildBody(int clientId, ulong steamId, string name)
{
StringBuilder stringBuilder = new StringBuilder(128);
stringBuilder.Append("{\"clientId\":\"").Append(clientId.ToString(CultureInfo.InvariantCulture)).Append('"');
stringBuilder.Append(",\"steamId\":\"").Append(steamId.ToString(CultureInfo.InvariantCulture)).Append('"');
string text = CleanName(name);
if (text != null)
{
stringBuilder.Append(",\"name\":\"").Append(EscapeJson(text)).Append('"');
}
stringBuilder.Append('}');
return stringBuilder.ToString();
}
internal static string BuildRequest(string host, int statusPort, string body)
{
int byteCount = Encoding.UTF8.GetByteCount(body);
string text = ((host.IndexOf(':') >= 0) ? ("[" + host + "]") : host);
return "POST /api/v1/identity HTTP/1.1\r\nHost: " + text + ":" + statusPort.ToString(CultureInfo.InvariantCulture) + "\r\nContent-Type: application/json\r\nContent-Length: " + byteCount.ToString(CultureInfo.InvariantCulture) + "\r\nConnection: close\r\n\r\n" + body;
}
internal static bool IsOkStatusLine(string line)
{
if (string.IsNullOrEmpty(line) || !line.StartsWith("HTTP/1.", StringComparison.Ordinal))
{
return false;
}
string[] array = line.Split(' ');
if (array.Length >= 2)
{
return array[1] == "200";
}
return false;
}
internal static string CleanName(string name)
{
if (string.IsNullOrEmpty(name))
{
return null;
}
StringBuilder stringBuilder = new StringBuilder(Math.Min(name.Length, 64));
foreach (char c in name)
{
if (!char.IsControl(c))
{
stringBuilder.Append(c);
if (stringBuilder.Length >= 64)
{
break;
}
}
}
string text = stringBuilder.ToString().Trim();
if (text.Length != 0)
{
return text;
}
return null;
}
internal static string EscapeJson(string text)
{
StringBuilder stringBuilder = new StringBuilder(text.Length + 8);
foreach (char c in text)
{
if (c != '"')
{
if (c == '\\')
{
stringBuilder.Append("\\\\");
}
else if (c < ' ' || c == '\u2028' || c == '\u2029')
{
StringBuilder stringBuilder2 = stringBuilder.Append("\\u");
int num = c;
stringBuilder2.Append(num.ToString("x4", CultureInfo.InvariantCulture));
}
else
{
stringBuilder.Append(c);
}
}
else
{
stringBuilder.Append("\\\"");
}
}
return stringBuilder.ToString();
}
}
internal static class ConnectPatch
{
private static FieldInfo _fMultipass;
private static FieldInfo _fClientConnectionExpected;
private static FieldInfo _fReturnToMenuRequested;
internal static bool Applied { get; private set; }
internal static bool Apply(Harmony harmony)
{
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(ConnectionManager), "JoinOfflineLobby", (Type[])null, (Type[])null);
if (methodInfo == null)
{
DriftwoodConnectPlugin.L.LogError((object)"ConnectionManager.JoinOfflineLobby not found. The game build has moved.");
return false;
}
_fMultipass = AccessTools.Field(typeof(ConnectionManager), "_multipass");
_fClientConnectionExpected = AccessTools.Field(typeof(ConnectionManager), "_clientConnectionExpected");
_fReturnToMenuRequested = AccessTools.Field(typeof(ConnectionManager), "_returnToMenuRequested");
if (_fMultipass == null || _fClientConnectionExpected == null || _fReturnToMenuRequested == null)
{
DriftwoodConnectPlugin.L.LogError((object)("ConnectionManager fields moved: _multipass=" + (_fMultipass != null) + " _clientConnectionExpected=" + (_fClientConnectionExpected != null) + " _returnToMenuRequested=" + (_fReturnToMenuRequested != null)));
return false;
}
harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(ConnectPatch), "JoinOfflineLobbyPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Applied = true;
return true;
}
private static bool ResolveTarget(out string host, out int port, out string label)
{
if (MenuJoin.TryTakePending(out host, out port, out label))
{
return true;
}
if (DriftwoodConnectPlugin.SessionArmed)
{
host = DriftwoodConnectPlugin.ConnectAddress.Value;
if (!string.IsNullOrEmpty(host))
{
port = DriftwoodConnectPlugin.ConnectPort.Value;
label = DriftwoodConnectPlugin.Label();
return true;
}
DriftwoodConnectPlugin.L.LogWarning((object)"No ConnectAddress configured; leaving JoinOfflineLobby alone.");
}
host = null;
port = 0;
label = null;
return false;
}
private static bool JoinOfflineLobbyPrefix(ConnectionManager __instance)
{
if (!ResolveTarget(out var host, out var port, out var label))
{
IdentityClaim.Disarm();
return true;
}
try
{
object? value = _fMultipass.GetValue(__instance);
Multipass val = (Multipass)((value is Multipass) ? value : null);
if ((Object)(object)val == (Object)null)
{
DriftwoodConnectPlugin.L.LogError((object)"Multipass was null on ConnectionManager; falling back to the stock method.");
return true;
}
ConnectionManager.IsUsingSteam = false;
val.SetClientTransport<UnityTransport>();
Transport clientTransport = val.ClientTransport;
if ((Object)(object)clientTransport == (Object)null)
{
DriftwoodConnectPlugin.L.LogError((object)"Multipass returned no client transport after selecting UnityTransport.");
JoinStatus.Fail("Could not select the network transport.");
return false;
}
if (port > 0 && port <= 65535)
{
clientTransport.SetPort((ushort)port);
}
clientTransport.SetClientAddress(host);
_fClientConnectionExpected.SetValue(__instance, true);
bool flag = clientTransport.StartConnection(false);
DriftwoodConnectPlugin.L.LogInfo((object)("Dialling " + label + " -> StartConnection returned " + flag + "."));
if (flag)
{
IdentityClaim.Arm(host, clientTransport.GetPort());
}
else
{
IdentityClaim.Disarm();
}
if (!flag)
{
_fReturnToMenuRequested.SetValue(__instance, true);
JoinStatus.Fail("Couldn't reach " + label + ".");
}
MainMenuManager.CrashAnimation();
return false;
}
catch (Exception ex)
{
DriftwoodConnectPlugin.L.LogError((object)("Joining " + label + " threw (" + ex?.ToString() + ")."));
JoinStatus.Fail("Could not start the connection.");
try
{
_fReturnToMenuRequested.SetValue(__instance, true);
}
catch
{
}
return false;
}
}
}
internal static class IdentityClaim
{
private sealed class ClaimJob
{
private readonly string _host;
private readonly int _port;
private readonly string _request;
internal volatile bool Done;
internal bool Ok;
internal string Failure;
internal ClaimJob(string host, int port, string request)
{
_host = host;
_port = port;
_request = request;
}
internal void Run()
{
try
{
IPAddress iPAddress = Resolve(_host);
if (iPAddress == null)
{
Failure = "could not resolve " + _host;
return;
}
using TcpClient tcpClient = new TcpClient(iPAddress.AddressFamily);
IAsyncResult asyncResult = tcpClient.BeginConnect(iPAddress, _port, null, null);
if (!asyncResult.AsyncWaitHandle.WaitOne(2500))
{
Failure = "the status port did not answer";
return;
}
tcpClient.EndConnect(asyncResult);
tcpClient.SendTimeout = 2500;
tcpClient.ReceiveTimeout = 2500;
NetworkStream stream = tcpClient.GetStream();
byte[] bytes = Encoding.UTF8.GetBytes(_request);
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
string text = ReadLine(stream, 256);
Ok = ClaimRules.IsOkStatusLine(text);
if (!Ok)
{
Failure = "the server answered \"" + text + "\"";
}
}
catch (Exception ex)
{
Failure = ex.GetType().Name + ": " + ex.Message;
}
finally
{
Done = true;
}
}
private static IPAddress Resolve(string host)
{
if (IPAddress.TryParse(host, out IPAddress address))
{
return address;
}
IPAddress[] hostAddresses = Dns.GetHostAddresses(host);
IPAddress[] array = hostAddresses;
foreach (IPAddress iPAddress in array)
{
if (iPAddress.AddressFamily == AddressFamily.InterNetwork)
{
return iPAddress;
}
}
if (hostAddresses.Length == 0)
{
return null;
}
return hostAddresses[0];
}
private static string ReadLine(NetworkStream stream, int max)
{
StringBuilder stringBuilder = new StringBuilder();
int num;
while (stringBuilder.Length < max && (num = stream.ReadByte()) >= 0)
{
switch (num)
{
default:
stringBuilder.Append((char)num);
continue;
case 13:
continue;
case 10:
break;
}
break;
}
return stringBuilder.ToString();
}
}
private static MethodInfo _sendSpawnPlayer;
private static MethodInfo _setLocalClient;
private static string _host;
private static int _gamePort;
private const float ClaimBudgetSeconds = 6f;
private const int AttemptTimeoutMs = 2500;
internal static bool Applied { get; private set; }
internal static bool Apply(Harmony harmony)
{
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(Client), "InitializeLocal", (Type[])null, (Type[])null);
_sendSpawnPlayer = AccessTools.Method(typeof(Client), "SendSpawnPlayer", (Type[])null, (Type[])null);
_setLocalClient = AccessTools.PropertySetter(typeof(Client), "LocalClient");
if (methodInfo == null || _sendSpawnPlayer == null || _setLocalClient == null || !typeof(IEnumerator).IsAssignableFrom(_sendSpawnPlayer.ReturnType))
{
DriftwoodConnectPlugin.L.LogWarning((object)("IdentityClaim: the game's spawn path moved (initializeLocal=" + (methodInfo != null) + " sendSpawnPlayer=" + (_sendSpawnPlayer != null) + " localClientSetter=" + (_setLocalClient != null) + "). Joins still work; the server will key characters on the join slot."));
return false;
}
harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(IdentityClaim), "InitializeLocalPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Applied = true;
return true;
}
internal static void Arm(string host, int gamePort)
{
_host = host;
_gamePort = gamePort;
}
internal static void Disarm()
{
_host = null;
_gamePort = 0;
}
private static bool InitializeLocalPrefix(Client __instance)
{
string host = _host;
int gamePort = _gamePort;
Disarm();
if (string.IsNullOrEmpty(host))
{
return true;
}
if (ConnectionManager.IsUsingSteam)
{
return true;
}
try
{
NetworkManager networkManager = InstanceFinder.NetworkManager;
if ((Object)(object)networkManager != (Object)null && networkManager.IsServerStarted)
{
return true;
}
}
catch
{
}
int num = ClaimRules.StatusPortFor(gamePort);
if (num == 0)
{
return true;
}
if (!TryReadSteam(out var steamId, out var name))
{
return true;
}
int clientId;
try
{
clientId = ((NetworkBehaviour)__instance).Owner.ClientId;
}
catch
{
return true;
}
if (clientId < 0)
{
return true;
}
IEnumerator enumerator;
try
{
_setLocalClient.Invoke(null, new object[1] { __instance });
enumerator = (IEnumerator)_sendSpawnPlayer.Invoke(__instance, null);
if (enumerator == null)
{
return true;
}
}
catch (Exception ex)
{
DriftwoodConnectPlugin.L.LogWarning((object)("IdentityClaim: could not stage the spawn (" + ex.Message + "); joining without a claim."));
return true;
}
((MonoBehaviour)__instance).StartCoroutine(ClaimThenSpawn(host, num, clientId, steamId, name, enumerator));
return false;
}
private static bool TryReadSteam(out ulong steamId, out string name)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
steamId = 0uL;
name = null;
try
{
steamId = SteamUser.GetSteamID().m_SteamID;
}
catch (Exception ex)
{
DriftwoodConnectPlugin.L.LogWarning((object)("IdentityClaim: Steam did not say who is signed in (" + ex.Message + "). Joining anyway; the server will key this character on the join slot."));
return false;
}
if (!ClaimRules.IsClaimableSteamId(steamId))
{
DriftwoodConnectPlugin.L.LogWarning((object)"IdentityClaim: Steam reported an id that is not a player account; not sending it.");
return false;
}
try
{
name = SteamFriends.GetPersonaName();
}
catch
{
}
return true;
}
private static IEnumerator ClaimThenSpawn(string host, int statusPort, int clientId, ulong steamId, string name, IEnumerator spawn)
{
string request = ClaimRules.BuildRequest(host, statusPort, ClaimRules.BuildBody(clientId, steamId, name));
float started = Time.realtimeSinceStartup;
string failure = null;
bool sent = false;
for (int attempt = 1; attempt <= 2; attempt++)
{
if (sent)
{
break;
}
ClaimJob job = new ClaimJob(host, statusPort, request);
ThreadPool.QueueUserWorkItem(delegate
{
job.Run();
});
while (!job.Done && Time.realtimeSinceStartup - started < 6f)
{
yield return null;
}
if (job.Done && job.Ok)
{
sent = true;
break;
}
failure = (job.Done ? job.Failure : ("no answer within " + 6f + " s"));
if (Time.realtimeSinceStartup - started >= 6f)
{
break;
}
yield return (object)new WaitForSecondsRealtime(0.5f);
}
float num = Time.realtimeSinceStartup - started;
if (sent)
{
DriftwoodConnectPlugin.L.LogInfo((object)("IdentityClaim: told " + host + ":" + statusPort + " this player's Steam ID for connection " + clientId + " in " + Math.Round(num * 1000f) + " ms; the saved character follows the player."));
}
else
{
DriftwoodConnectPlugin.L.LogWarning((object)("IdentityClaim: could not reach " + host + ":" + statusPort + " (" + failure + "). Joining anyway; on this join the server keys the character on the join slot."));
}
yield return spawn;
}
}
internal static class JoinStatus
{
private sealed class Driver : MonoBehaviour
{
private static Driver _self;
private float _clearAt = -1f;
internal static Driver EnsureExists()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Expected O, but got Unknown
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_self != (Object)null)
{
return _self;
}
GameObject val = new GameObject("Driftwood.JoinStatus");
Object.DontDestroyOnLoad((Object)val);
((Object)val).hideFlags = (HideFlags)61;
_self = val.AddComponent<Driver>();
return _self;
}
internal void HoldThenClear(float seconds)
{
_clearAt = Time.realtimeSinceStartup + seconds;
}
private void LateUpdate()
{
Pump();
if (_clearAt > 0f && Time.realtimeSinceStartup >= _clearAt)
{
_clearAt = -1f;
Clear();
}
else if (_message != null && _clearAt < 0f && WorldIsUp())
{
Clear();
}
}
}
private static TextMeshProUGUI _text;
private static CanvasGroup _perma;
private static bool _resolved;
private static string _origText;
private static float _origFontSize;
private static Color _origColor;
private static TextAlignmentOptions _origAlignment;
private static Vector2 _origAnchorMin;
private static Vector2 _origAnchorMax;
private static Vector2 _origPivot;
private static Vector2 _origAnchoredPos;
private static Vector2 _origSizeDelta;
private static bool _origEnabled;
private static float _origPermaAlpha;
private static TextWrappingModes _origWrapping;
private static TextOverflowModes _origOverflow;
private static bool _origAutoSize;
private static Transform _origParent;
private static int _origSiblingIndex;
private static bool _reparented;
private static GameObject[] _children;
private static bool[] _childrenActive;
private static ContentSizeFitter _fitter;
private static bool _origFitterEnabled;
private static bool _hostWarned;
private static bool _saved;
private static bool _broken;
private static string _message;
private static bool _watching;
private static readonly Vector2 BandAnchorMin = new Vector2(0.1f, 0.16f);
private static readonly Vector2 BandAnchorMax = new Vector2(0.9f, 0.16f);
private const float BandHeight = 120f;
private const float BandFontSize = 34f;
internal static void Set(string message)
{
_message = message;
Pump();
}
internal static void Fail(string message)
{
Set(message);
Driver.EnsureExists().HoldThenClear(8f);
}
internal static void Clear()
{
//IL_004e: 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_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0139: 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_014f: 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)
_message = null;
if (!_saved || (Object)(object)_text == (Object)null)
{
return;
}
try
{
((TMP_Text)_text).text = _origText;
((TMP_Text)_text).fontSize = _origFontSize;
((TMP_Text)_text).enableAutoSizing = _origAutoSize;
((Graphic)_text).color = _origColor;
((TMP_Text)_text).alignment = _origAlignment;
((TMP_Text)_text).textWrappingMode = _origWrapping;
((TMP_Text)_text).overflowMode = _origOverflow;
((Behaviour)_text).enabled = _origEnabled;
RectTransform rectTransform = ((TMP_Text)_text).rectTransform;
if (_reparented && (Object)(object)_origParent != (Object)null)
{
((Transform)rectTransform).SetParent(_origParent, false);
((Transform)rectTransform).SetSiblingIndex(_origSiblingIndex);
}
_reparented = false;
if ((Object)(object)_fitter != (Object)null)
{
((Behaviour)_fitter).enabled = _origFitterEnabled;
}
if (_children != null)
{
for (int i = 0; i < _children.Length; i++)
{
if ((Object)(object)_children[i] != (Object)null)
{
_children[i].SetActive(_childrenActive[i]);
}
}
}
_children = null;
rectTransform.anchorMin = _origAnchorMin;
rectTransform.anchorMax = _origAnchorMax;
rectTransform.pivot = _origPivot;
rectTransform.anchoredPosition = _origAnchoredPos;
rectTransform.sizeDelta = _origSizeDelta;
if ((Object)(object)_perma != (Object)null)
{
_perma.alpha = _origPermaAlpha;
}
}
catch (Exception e)
{
Break("restoring the version stamp", e);
}
_saved = false;
}
internal static void Watch()
{
if (!_watching)
{
_watching = true;
Driver.EnsureExists();
ClientManager clientManager = InstanceFinder.ClientManager;
if ((Object)(object)clientManager != (Object)null)
{
clientManager.OnClientConnectionState += OnClientConnectionState;
}
}
}
private static void OnClientConnectionState(ClientConnectionStateArgs args)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Invalid comparison between Unknown and I4
if ((int)args.ConnectionState == 8)
{
Set("Connected. Loading the island...");
}
else if ((int)args.ConnectionState == 1 && _message != null)
{
Fail("Lost the connection to " + DriftwoodConnectPlugin.Label() + ".");
}
}
private static bool WorldIsUp()
{
try
{
return (Object)(object)Island.CurIsland != (Object)null && !IslandManager.IsLoading && (Object)(object)Player.LocalPlayer != (Object)null;
}
catch
{
return false;
}
}
private static void Pump()
{
//IL_005f: 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_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_025c: Unknown result type (might be due to invalid IL or missing references)
//IL_0267: Unknown result type (might be due to invalid IL or missing references)
//IL_027c: Unknown result type (might be due to invalid IL or missing references)
//IL_0287: Unknown result type (might be due to invalid IL or missing references)
//IL_029c: Unknown result type (might be due to invalid IL or missing references)
//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
//IL_02e8: Invalid comparison between Unknown and I4
//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0320: Unknown result type (might be due to invalid IL or missing references)
if (_message == null || _broken || !Resolve())
{
return;
}
try
{
RectTransform rectTransform = ((TMP_Text)_text).rectTransform;
if (!_saved)
{
_origText = ((TMP_Text)_text).text;
_origFontSize = ((TMP_Text)_text).fontSize;
_origAutoSize = ((TMP_Text)_text).enableAutoSizing;
_origColor = ((Graphic)_text).color;
_origAlignment = ((TMP_Text)_text).alignment;
_origWrapping = ((TMP_Text)_text).textWrappingMode;
_origOverflow = ((TMP_Text)_text).overflowMode;
_origEnabled = ((Behaviour)_text).enabled;
_origParent = ((Transform)rectTransform).parent;
_origSiblingIndex = ((Transform)rectTransform).GetSiblingIndex();
_origAnchorMin = rectTransform.anchorMin;
_origAnchorMax = rectTransform.anchorMax;
_origPivot = rectTransform.pivot;
_origAnchoredPos = rectTransform.anchoredPosition;
_origSizeDelta = rectTransform.sizeDelta;
_origPermaAlpha = (((Object)(object)_perma != (Object)null) ? _perma.alpha : 1f);
_fitter = ((Component)_text).GetComponent<ContentSizeFitter>();
_origFitterEnabled = (Object)(object)_fitter != (Object)null && ((Behaviour)_fitter).enabled;
int childCount = ((Transform)rectTransform).childCount;
_children = (GameObject[])(object)new GameObject[childCount];
_childrenActive = new bool[childCount];
for (int i = 0; i < childCount; i++)
{
_children[i] = ((Component)((Transform)rectTransform).GetChild(i)).gameObject;
_childrenActive[i] = _children[i].activeSelf;
}
_reparented = false;
_saved = true;
}
if ((Object)(object)_fitter != (Object)null && ((Behaviour)_fitter).enabled)
{
((Behaviour)_fitter).enabled = false;
}
if (_children != null)
{
for (int j = 0; j < _children.Length; j++)
{
if ((Object)(object)_children[j] != (Object)null && _children[j].activeSelf)
{
_children[j].SetActive(false);
}
}
}
RectTransform val = HostRect();
if ((Object)(object)val != (Object)null)
{
if ((Object)(object)((Transform)rectTransform).parent != (Object)(object)val)
{
((Transform)rectTransform).SetParent((Transform)(object)val, false);
((Transform)rectTransform).SetAsLastSibling();
_reparented = true;
}
}
else if (!_hostWarned)
{
_hostWarned = true;
DriftwoodConnectPlugin.L.LogWarning((object)"JoinStatus: no root canvas above the version stamp; placing the status against its own parent, which may not be the screen.");
}
rectTransform.anchorMin = BandAnchorMin;
rectTransform.anchorMax = BandAnchorMax;
rectTransform.pivot = new Vector2(0.5f, 0.5f);
rectTransform.anchoredPosition = Vector2.zero;
rectTransform.sizeDelta = new Vector2(0f, 120f);
if (((TMP_Text)_text).enableAutoSizing)
{
((TMP_Text)_text).enableAutoSizing = false;
}
if (((TMP_Text)_text).fontSize < 34f)
{
((TMP_Text)_text).fontSize = 34f;
}
if ((int)((TMP_Text)_text).textWrappingMode != 1)
{
((TMP_Text)_text).textWrappingMode = (TextWrappingModes)1;
}
if ((int)((TMP_Text)_text).overflowMode != 0)
{
((TMP_Text)_text).overflowMode = (TextOverflowModes)0;
}
((TMP_Text)_text).alignment = (TextAlignmentOptions)514;
((Graphic)_text).color = Color.white;
if (!((Behaviour)_text).enabled)
{
((Behaviour)_text).enabled = true;
}
if (((TMP_Text)_text).text != _message)
{
((TMP_Text)_text).text = _message;
}
if ((Object)(object)_perma != (Object)null && _perma.alpha < 1f)
{
_perma.alpha = 1f;
}
}
catch (Exception e)
{
Break("placing the connecting message", e);
}
}
private static RectTransform HostRect()
{
Canvas val = ((Graphic)_text).canvas;
if ((Object)(object)val == (Object)null)
{
val = ((Component)_text).GetComponentInParent<Canvas>();
}
if ((Object)(object)val == (Object)null)
{
return null;
}
Transform transform = ((Component)(((Object)(object)val.rootCanvas != (Object)null) ? val.rootCanvas : val)).transform;
return (RectTransform)(object)((transform is RectTransform) ? transform : null);
}
private static void Break(string doing, Exception e)
{
_broken = true;
_message = null;
try
{
DriftwoodConnectPlugin.L.LogError((object)("JoinStatus switched itself off for this session while " + doing + ". The join is unaffected; only the on-screen message is gone. " + e));
}
catch
{
}
}
private static bool Resolve()
{
if ((Object)(object)_text != (Object)null)
{
return true;
}
_saved = false;
_reparented = false;
if (_resolved)
{
_resolved = false;
}
Type type = AccessTools.TypeByName("CanvasManager");
if (type == null)
{
return false;
}
object obj = AccessTools.Field(type, "_instance")?.GetValue(null);
if (obj == null)
{
return false;
}
object? obj2 = AccessTools.Field(type, "_versionText")?.GetValue(obj);
_text = (TextMeshProUGUI)((obj2 is TextMeshProUGUI) ? obj2 : null);
object? obj3 = AccessTools.Field(type, "_permaCanvas")?.GetValue(obj);
_perma = (CanvasGroup)((obj3 is CanvasGroup) ? obj3 : null);
if ((Object)(object)_text == (Object)null)
{
if (!_resolved)
{
_resolved = true;
DriftwoodConnectPlugin.L.LogWarning((object)"CanvasManager._versionText not found; the join will proceed but nothing will narrate it on screen.");
}
return false;
}
_resolved = true;
LogHierarchy();
return true;
}
private static void LogHierarchy()
{
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_028e: Unknown result type (might be due to invalid IL or missing references)
//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_018c: Unknown result type (might be due to invalid IL or missing references)
//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
try
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("JoinStatus host element: screen ").Append(Screen.width).Append('x')
.Append(Screen.height);
RectTransform rectTransform = ((TMP_Text)_text).rectTransform;
int num = 0;
Transform val = (Transform)(object)rectTransform;
while ((Object)(object)val != (Object)null && num < 16)
{
stringBuilder.Append("\n ").Append((num == 0) ? "stamp " : "parent ").Append(((Object)val).name);
RectTransform val2 = (RectTransform)(object)((val is RectTransform) ? val : null);
if ((Object)(object)val2 != (Object)null)
{
StringBuilder stringBuilder2 = stringBuilder.Append(" anchors(").Append(F(val2.anchorMin)).Append("..")
.Append(F(val2.anchorMax))
.Append(')')
.Append(" pos ")
.Append(F(val2.anchoredPosition))
.Append(" size ")
.Append(F(val2.sizeDelta))
.Append(" rect ");
Rect rect = val2.rect;
stringBuilder2.Append(F(((Rect)(ref rect)).size));
}
Canvas component = ((Component)val).GetComponent<Canvas>();
if ((Object)(object)component != (Object)null)
{
stringBuilder.Append(" [Canvas ").Append(component.renderMode).Append(component.isRootCanvas ? " ROOT" : "")
.Append(']');
CanvasScaler component2 = ((Component)val).GetComponent<CanvasScaler>();
if ((Object)(object)component2 != (Object)null)
{
stringBuilder.Append(" [CanvasScaler ").Append(component2.uiScaleMode).Append(' ')
.Append(F(component2.referenceResolution))
.Append(']');
}
}
if ((Object)(object)((Component)val).GetComponent<CanvasGroup>() != (Object)null)
{
stringBuilder.Append(" [CanvasGroup]");
}
if ((Object)(object)((Component)val).GetComponent<LayoutGroup>() != (Object)null)
{
stringBuilder.Append(" [LayoutGroup]");
}
if ((Object)(object)((Component)val).GetComponent<ContentSizeFitter>() != (Object)null)
{
stringBuilder.Append(" [ContentSizeFitter]");
}
val = val.parent;
num++;
}
for (int i = 0; i < ((Transform)rectTransform).childCount; i++)
{
Transform child = ((Transform)rectTransform).GetChild(i);
stringBuilder.Append("\n child ").Append(((Object)child).name).Append(((Component)child).gameObject.activeSelf ? "" : " (inactive)");
RectTransform val3 = (RectTransform)(object)((child is RectTransform) ? child : null);
if ((Object)(object)val3 != (Object)null)
{
stringBuilder.Append(" anchors(").Append(F(val3.anchorMin)).Append("..")
.Append(F(val3.anchorMax))
.Append(") size ")
.Append(F(val3.sizeDelta));
}
}
DriftwoodConnectPlugin.L.LogInfo((object)stringBuilder.ToString());
}
catch (Exception ex)
{
DriftwoodConnectPlugin.L.LogWarning((object)("JoinStatus: could not describe the version stamp's hierarchy: " + ex.Message));
}
}
private static string F(Vector2 v)
{
return "(" + v.x.ToString("0.##") + "," + v.y.ToString("0.##") + ")";
}
}
internal static class MenuJoin
{
private static FieldInfo _fField;
private static FieldInfo _fButton;
private static string _pendingHost;
private static int _pendingPort;
private static bool _changeWarned;
internal static bool Applied { get; private set; }
internal static bool Apply(Harmony harmony)
{
//IL_014f: Unknown result type (might be due to invalid IL or missing references)
//IL_015c: Expected O, but got Unknown
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Expected O, but got Unknown
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(ButtonManager), "OnLobbyIDInputFieldChange", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(ButtonManager), "JoinByIDButton", (Type[])null, (Type[])null);
MethodInfo methodInfo3 = AccessTools.Method(typeof(ButtonManager), "Start", (Type[])null, (Type[])null);
_fField = AccessTools.Field(typeof(ButtonManager), "_lobbyIdInputField");
_fButton = AccessTools.Field(typeof(ButtonManager), "_joinByIDButton");
if (methodInfo == null || methodInfo2 == null || _fField == null || _fButton == null)
{
DriftwoodConnectPlugin.L.LogWarning((object)("MenuJoin: the Join Game menu moved (change=" + (methodInfo != null) + " join=" + (methodInfo2 != null) + " field=" + (_fField != null) + " button=" + (_fButton != null) + "). Addresses cannot be typed in the menu this build; the launcher path is unaffected."));
return false;
}
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(MenuJoin), "ChangePostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(AccessTools.Method(typeof(MenuJoin), "JoinPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
if (methodInfo3 != null)
{
harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(MenuJoin), "StartPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
Applied = true;
return true;
}
internal static bool TryTakePending(out string host, out int port, out string label)
{
if (string.IsNullOrEmpty(_pendingHost))
{
host = null;
port = 0;
label = null;
return false;
}
host = _pendingHost;
port = _pendingPort;
label = LabelFor(host, port);
_pendingHost = null;
_pendingPort = 0;
return true;
}
private static void StartPostfix(ButtonManager __instance)
{
//IL_0020: 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)
try
{
object? value = _fField.GetValue(__instance);
TMP_InputField val = (TMP_InputField)((value is TMP_InputField) ? value : null);
if (!((Object)(object)val == (Object)null))
{
if ((int)val.contentType != 0)
{
val.contentType = (ContentType)0;
}
if ((int)val.characterValidation != 0)
{
val.characterValidation = (CharacterValidation)0;
}
if (val.characterLimit > 0 && val.characterLimit < 64)
{
val.characterLimit = 64;
}
Graphic placeholder = val.placeholder;
TMP_Text val2 = (TMP_Text)(object)((placeholder is TMP_Text) ? placeholder : null);
if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(val2.text) && val2.text.Length <= 24 && val2.text.IndexOf("IP", StringComparison.OrdinalIgnoreCase) < 0)
{
val2.text += " or IP:Port";
}
}
}
catch (Exception ex)
{
DriftwoodConnectPlugin.L.LogWarning((object)("MenuJoin: could not widen the lobby-ID box (" + ex.Message + "). Pasting an address may not work this session."));
}
}
private static void ChangePostfix(ButtonManager __instance)
{
try
{
object? value = _fButton.GetValue(__instance);
Button val = (Button)((value is Button) ? value : null);
if (!((Object)(object)val == (Object)null) && !((Behaviour)val).enabled)
{
object? value2 = _fField.GetValue(__instance);
TMP_InputField val2 = (TMP_InputField)((value2 is TMP_InputField) ? value2 : null);
if (!((Object)(object)val2 == (Object)null) && TryParseAddress(val2.text, out var _, out var _))
{
((Behaviour)val).enabled = true;
}
}
}
catch (Exception ex)
{
if (!_changeWarned)
{
_changeWarned = true;
DriftwoodConnectPlugin.L.LogWarning((object)("MenuJoin: the Join button cannot follow the lobby box (" + ex.Message + "). Typed addresses may leave it greyed out."));
}
}
}
private static bool JoinPrefix(ButtonManager __instance)
{
bool flag = false;
try
{
object? value = _fField.GetValue(__instance);
TMP_InputField val = (TMP_InputField)((value is TMP_InputField) ? value : null);
if ((Object)(object)val == (Object)null)
{
return true;
}
string text = (val.text ?? "").Trim();
if (text.Length == 0 || ulong.TryParse(text, out var _))
{
return true;
}
if (!TryParseAddress(text, out var host, out var port))
{
return true;
}
if (port == 0)
{
port = 22003;
}
if (!ConnectPatch.Applied)
{
DriftwoodConnectPlugin.L.LogError((object)"MenuJoin: address typed but the join patch is not in place; not dialling.");
return true;
}
ConnectionManager instance = ConnectionManager.Instance;
if ((Object)(object)instance == (Object)null)
{
DriftwoodConnectPlugin.L.LogError((object)"MenuJoin: ConnectionManager.Instance is null; cannot join from the menu.");
JoinStatus.Fail("Could not start the connection.");
return false;
}
_pendingHost = host;
_pendingPort = port;
flag = true;
DriftwoodConnectPlugin.L.LogInfo((object)("MenuJoin: joining " + LabelFor(host, port) + " typed in the Join Game menu."));
JoinStatus.Set("Connecting to " + LabelFor(host, port));
JoinStatus.Watch();
Application.runInBackground = true;
instance.JoinOfflineLobby();
return false;
}
catch (Exception ex)
{
DriftwoodConnectPlugin.L.LogError((object)("MenuJoin: join from the menu failed (" + ex?.ToString() + ")."));
_pendingHost = null;
_pendingPort = 0;
return !flag;
}
}
internal static string LabelFor(string host, int port)
{
return AddressParser.LabelFor(host, port);
}
internal static bool TryParseAddress(string text, out string host, out int port)
{
return AddressParser.TryParse(text, out host, out port);
}
}
[BepInPlugin("com.humangenome.driftwood.connect", "DriftwoodConnect", "0.1.4")]
public class DriftwoodConnectPlugin : BaseUnityPlugin
{
public const string Guid = "com.humangenome.driftwood.connect";
public const string Version = "0.1.4";
internal static ManualLogSource L;
internal static bool SessionArmed;
internal static ConfigEntry<bool> Enable;
internal static ConfigEntry<bool> AutoConnect;
internal static ConfigEntry<string> ConnectAddress;
internal static ConfigEntry<int> ConnectPort;
internal static ConfigEntry<string> ServerLabel;
internal static ConfigEntry<string> JoinPassword;
internal static ConfigEntry<float> AutoConnectDelaySeconds;
internal static ConfigEntry<string> ArmedAtUtc;
private const double ArmWindowHours = 2.0;
private const double ArmFutureSkewMinutes = 10.0;
private void Awake()
{
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Expected O, but got Unknown
L = ((BaseUnityPlugin)this).Logger;
Enable = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "Enable", false, "Master switch. Default OFF so a stale install of this mod can never hijack a normal singleplayer or Steam-lobby session. The launcher writes true on every Connect.");
AutoConnect = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "AutoConnect", true, "Join ConnectAddress as soon as the main menu is up, instead of waiting for the player to do something.");
ConnectAddress = ((BaseUnityPlugin)this).Config.Bind<string>("Client", "ConnectAddress", "", "Host to dial. The game hardcodes \"localhost\" here; this is the value that replaces it.");
ConnectPort = ((BaseUnityPlugin)this).Config.Bind<int>("Client", "ConnectPort", 0, "UDP gameplay port. 0 leaves the transport's own port untouched.");
ServerLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Client", "ServerLabel", "", "Shown in the on-screen connecting banner so the player can see which server they are joining.");
JoinPassword = ((BaseUnityPlugin)this).Config.Bind<string>("Client", "JoinPassword", "", "Reserved. Current Driftwood hosts do not check a join password - they accept any client that knows the address - so this value is not presented to anything. It exists so the key has one meaning if that changes.");
AutoConnectDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Client", "AutoConnectDelaySeconds", 3f, "Seconds to let the menu scene settle before auto-joining.");
ArmedAtUtc = ((BaseUnityPlugin)this).Config.Bind<string>("Client", "ArmedAtUtc", "", "Round-trip UTC timestamp of the Connect that armed this file. An arm older than a couple of hours is refused, so a config that outlived its session can never auto-join. Written by the launcher; cleared by this mod once used.");
Silence.InstallIfHeadless();
Harmony harmony = new Harmony("com.humangenome.driftwood.connect");
bool flag = ConnectPatch.Apply(harmony);
if (flag)
{
MenuJoin.Apply(harmony);
IdentityClaim.Apply(harmony);
}
else
{
L.LogError((object)"DriftwoodConnect could not patch ConnectionManager.JoinOfflineLobby. Neither the launcher nor a typed address can join this session.");
}
if (!Enable.Value)
{
L.LogInfo((object)"DriftwoodConnect 0.1.4 is idle (Client.Enable=false). Vanilla behaviour is untouched; a server address typed into the Join Game menu's lobby box still joins.");
return;
}
if (!ArmIsFresh(out var age))
{
L.LogWarning((object)("DriftwoodConnect found an armed config that is " + age + ". Not joining anything: launch through Driftwood to join a server, or type its address into the Join Game menu."));
Disarm();
return;
}
bool value = AutoConnect.Value;
if (!Disarm())
{
L.LogError((object)("DriftwoodConnect could not clear the arm from " + ((BaseUnityPlugin)this).Config.ConfigFilePath + ". Joining anyway; the arm expires on its own within " + 2.0 + " hours."));
}
Application.runInBackground = true;
if (flag)
{
SessionArmed = true;
L.LogInfo((object)string.Format("DriftwoodConnect {0} armed. target={1} autoConnect={2}", "0.1.4", Describe(), value));
if (value)
{
((MonoBehaviour)this).StartCoroutine(AutoConnectRoutine());
}
}
}
private bool ArmIsFresh(out string age)
{
string text = (ArmedAtUtc.Value ?? "").Trim();
if (text.Length == 0)
{
age = "not dated (no ArmedAtUtc), so its age cannot be established";
return false;
}
if (!DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var result))
{
age = "dated with something that is not a timestamp (" + text + ")";
return false;
}
TimeSpan timeSpan = DateTime.UtcNow - result.ToUniversalTime();
if (timeSpan.TotalMinutes < -10.0)
{
age = "dated " + Math.Round(0.0 - timeSpan.TotalMinutes) + " minutes in the FUTURE, so this machine's clock and the stamp disagree";
return false;
}
if (timeSpan.TotalHours > 2.0)
{
age = "from " + Math.Round(timeSpan.TotalHours, 1) + " hours ago, past the " + 2.0 + " hour limit";
return false;
}
age = "from " + Math.Round(Math.Max(0.0, timeSpan.TotalSeconds)) + " seconds ago";
return true;
}
private bool Disarm()
{
try
{
Enable.Value = false;
AutoConnect.Value = false;
ArmedAtUtc.Value = "";
((BaseUnityPlugin)this).Config.Save();
string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
if (!File.Exists(configFilePath))
{
L.LogWarning((object)("The connect config is gone from " + configFilePath + " after clearing the arm. Nothing left to auto-join from, which is the safe outcome."));
return true;
}
string[] array = File.ReadAllLines(configFilePath);
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (text.Length == 0 || text[0] == '#' || text[0] == '[')
{
continue;
}
int num = text.IndexOf('=');
if (num > 0 && text.Substring(0, num).Trim().Equals("Enable", StringComparison.OrdinalIgnoreCase))
{
string text2 = text.Substring(num + 1).Trim();
if (text2.Equals("true", StringComparison.OrdinalIgnoreCase) || text2 == "1")
{
return false;
}
return true;
}
}
return true;
}
catch (Exception ex)
{
L.LogError((object)("Clearing the arm threw (" + ex.GetType().Name + ": " + ex.Message + ")."));
return false;
}
}
internal static string Describe()
{
string value = ConnectAddress.Value;
if (string.IsNullOrEmpty(value))
{
return "(none)";
}
if (ConnectPort.Value <= 0)
{
return value;
}
return value + ":" + ConnectPort.Value;
}
internal static string Label()
{
string value = ServerLabel.Value;
if (!string.IsNullOrEmpty(value))
{
return value;
}
return Describe();
}
private IEnumerator AutoConnectRoutine()
{
if (string.IsNullOrEmpty(ConnectAddress.Value))
{
L.LogWarning((object)"AutoConnect is on but ConnectAddress is empty. Staying on the menu.");
yield break;
}
yield return (object)new WaitForSeconds(Mathf.Max(0f, AutoConnectDelaySeconds.Value));
ConnectionManager instance = ConnectionManager.Instance;
if ((Object)(object)instance == (Object)null)
{
L.LogError((object)"ConnectionManager.Instance is null after the menu settled. Cannot join.");
JoinStatus.Fail("Could not start the connection.");
}
else
{
JoinStatus.Set("Connecting to " + Label());
JoinStatus.Watch();
instance.JoinOfflineLobby();
}
}
}
internal class Silence : MonoBehaviour
{
internal static void InstallIfHeadless()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Expected O, but got Unknown
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
if (IsHeadless())
{
AudioListener.pause = true;
AudioListener.volume = 0f;
GameObject val = new GameObject("Driftwood.Silence");
Object.DontDestroyOnLoad((Object)val);
((Object)val).hideFlags = (HideFlags)61;
val.AddComponent<Silence>();
}
}
private static bool IsHeadless()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Invalid comparison between Unknown and I4
if (!Application.isBatchMode)
{
return (int)SystemInfo.graphicsDeviceType == 4;
}
return true;
}
private void Update()
{
if (AudioListener.volume != 0f)
{
AudioListener.volume = 0f;
}
if (!AudioListener.pause)
{
AudioListener.pause = true;
}
}
}
}