Decompiled source of Socialize v1.0.16

Landoria.Socialize.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Landoria.SharedLib;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Landoria.Socialize")]
[assembly: AssemblyDescription("Adds session-based groups and expanded chat channels to Valheim.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Landoria")]
[assembly: AssemblyProduct("Landoria.Socialize")]
[assembly: AssemblyCopyright("Copyright © 2026 End3rbyte")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("DA5DE9DF-7727-4D5F-8274-896B8EB80ED3")]
[assembly: AssemblyFileVersion("1.0.16")]
[assembly: AssemblyInformationalVersion("1.0.16")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]
[assembly: AssemblyVersion("1.0.16.13989")]
namespace Landoria.Socialize
{
	internal static class ChatChannelState
	{
		private static PersistentChatChannel current;

		private static string whisperTarget = "";

		private static bool redirecting;

		internal static void SetNormal()
		{
			current = PersistentChatChannel.Normal;
			whisperTarget = "";
		}

		internal static void SetShout()
		{
			current = PersistentChatChannel.Shout;
			whisperTarget = "";
		}

		internal static void SetWhisper(string target)
		{
			current = PersistentChatChannel.Whisper;
			whisperTarget = target ?? "";
		}

		internal static void SetGroup()
		{
			current = PersistentChatChannel.Group;
			whisperTarget = "";
		}

		internal static string GetPrompt()
		{
			return ChatBehaviorPolicy.GetPrompt(current, whisperTarget);
		}

		internal static bool TryRedirect(string text)
		{
			if (!ChatBehaviorPolicy.ShouldRedirect(current, redirecting, text))
			{
				return false;
			}
			redirecting = true;
			try
			{
				return Send(text);
			}
			finally
			{
				redirecting = false;
			}
		}

		private static bool Send(string text)
		{
			switch (current)
			{
			case PersistentChatChannel.Shout:
				SocialChatSender.SendShout(text);
				return true;
			case PersistentChatChannel.Whisper:
				return PrivateChat.Send(whisperTarget, text, (Terminal)(object)Chat.instance);
			case PersistentChatChannel.Group:
				GroupService.SendChat(text);
				return true;
			default:
				return false;
			}
		}
	}
	internal static class SocialChatSender
	{
		internal static void SendShout(string text)
		{
			Talker val = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).GetComponent<Talker>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				val.Say((Type)2, text);
			}
		}

		internal static void ApplyRanges(Talker talker)
		{
			talker.m_normalDistance = SocializePlugin.Settings.SayDistance;
			talker.m_shoutDistance = SocializePlugin.Settings.ShoutDistance;
		}

		internal static void ApplyRangesToLoadedTalkers()
		{
			if (SocializePlugin.Settings != null)
			{
				Talker[] array = Object.FindObjectsByType<Talker>((FindObjectsSortMode)0);
				for (int i = 0; i < array.Length; i++)
				{
					ApplyRanges(array[i]);
				}
			}
		}
	}
	internal enum PersistentChatChannel
	{
		Normal,
		Shout,
		Whisper,
		Group
	}
	internal static class ChatBehaviorPolicy
	{
		internal static string GetPrompt(PersistentChatChannel channel, string whisperTarget)
		{
			return channel switch
			{
				PersistentChatChannel.Shout => "Shouting...", 
				PersistentChatChannel.Whisper => "Talking to " + whisperTarget + "...", 
				PersistentChatChannel.Group => "Speaking to the group...", 
				_ => "Speaking...", 
			};
		}

		internal static bool ShouldRedirect(PersistentChatChannel channel, bool redirecting, string text)
		{
			if (!redirecting && channel != PersistentChatChannel.Normal)
			{
				return !string.IsNullOrWhiteSpace(text);
			}
			return false;
		}
	}
	internal static class PrivateChatPolicy
	{
		internal static GroupDecision CanSend(bool targetFound, bool isLocalPlayer, string targetName)
		{
			if (!targetFound)
			{
				return GroupDecision.Deny("No connected player named \"" + targetName + "\" was found.");
			}
			if (!isLocalPlayer)
			{
				return GroupDecision.Allow();
			}
			return GroupDecision.Deny("You cannot whisper yourself.");
		}
	}
	internal static class TargetPingPolicy
	{
		internal static GroupDecision CanSend(bool targetFound, bool clientReady, string targetName)
		{
			if (!(targetFound && clientReady))
			{
				return GroupDecision.Deny("No connected player named \"" + targetName + "\" was found.");
			}
			return GroupDecision.Allow();
		}
	}
	internal static class ChatCommandParser
	{
		internal static bool TryParseTarget(string fullLine, out string target, out string message)
		{
			target = "";
			message = "";
			if (string.IsNullOrEmpty(fullLine))
			{
				return false;
			}
			int num = fullLine.IndexOf(' ');
			if (num < 0)
			{
				return false;
			}
			int num2 = fullLine.IndexOf(' ', num + 1);
			string text = ((num2 >= 0) ? fullLine.Substring(num + 1, num2 - num - 1) : fullLine.Substring(num + 1));
			target = text.Trim();
			if (target.StartsWith("@", StringComparison.Ordinal))
			{
				target = target.Substring(1);
			}
			message = ((num2 >= 0) ? fullLine.Substring(num2 + 1) : "");
			if (!string.IsNullOrWhiteSpace(target))
			{
				return !string.IsNullOrWhiteSpace(message);
			}
			return false;
		}

		internal static bool IsValidGroupAction(string action, string argument)
		{
			switch (action)
			{
			case "leave":
			case "info":
				return string.IsNullOrEmpty(argument);
			case "invite":
			case "remove":
			case "promote":
				return !string.IsNullOrEmpty(argument);
			default:
				return false;
			}
		}
	}
	internal static class ChatCommands
	{
		internal static void Register()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			Register("sh", new ConsoleEventFailable(SendShout));
			Register("shout", new ConsoleEventFailable(SendShout));
			Register("s", new ConsoleEventFailable(SendSay));
			Register("say", new ConsoleEventFailable(SendSay));
			Register("w", new ConsoleEventFailable(SendWhisper));
			Register("wping", new ConsoleEventFailable(SendTargetPing));
		}

		private static void Register(string name, ConsoleEventFailable handler)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			new ConsoleCommand(name, GetDescription(name), handler, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static string GetDescription(string name)
		{
			if (name == "w")
			{
				return "[player] [message] sends a private message";
			}
			if (name == "wping")
			{
				return "[player] [message] sends a private message with a ping";
			}
			return "[message] " + ((name == "s" || name == "say") ? "says something to nearby players" : "shouts so everyone around you can hear you");
		}

		private static object SendShout(ConsoleEventArgs args)
		{
			if (!TryGetMessage(args, out var message))
			{
				args.Context.AddString("Usage: /sh message");
				return true;
			}
			ChatChannelState.SetShout();
			SocialChatSender.SendShout(message);
			return true;
		}

		private static object SendSay(ConsoleEventArgs args)
		{
			if (!TryGetMessage(args, out var message))
			{
				args.Context.AddString("Usage: /s message");
				return true;
			}
			ChatChannelState.SetNormal();
			Chat.instance.SendText((Type)1, message);
			return true;
		}

		private static object SendWhisper(ConsoleEventArgs args)
		{
			if (!ChatCommandParser.TryParseTarget(args.FullLine, out var target, out var message))
			{
				args.Context.AddString("Usage: /w PlayerName message");
				return true;
			}
			if (!PrivateChat.Send(target, message, args.Context))
			{
				return true;
			}
			ChatChannelState.SetWhisper(target);
			return true;
		}

		private static object SendTargetPing(ConsoleEventArgs args)
		{
			if (!ChatCommandParser.TryParseTarget(args.FullLine, out var target, out var message))
			{
				args.Context.AddString("Usage: /wping PlayerName message");
				return true;
			}
			TargetPingService.Send(target, message, args.Context);
			return true;
		}

		private static bool TryGetMessage(ConsoleEventArgs args, out string message)
		{
			message = (args.ArgsAll ?? "").Trim();
			if ((Object)(object)Chat.instance != (Object)null)
			{
				return !string.IsNullOrEmpty(message);
			}
			return false;
		}
	}
	internal static class PrivateChat
	{
		private sealed class PendingMessage
		{
			internal long TargetPeer;

			internal string TargetName;

			internal string Message;

			internal Terminal Context;

			internal float SentAt;
		}

		private const string MessageRpc = "Landoria_Social_PrivateMessage";

		private const string ReceiptRpc = "Landoria_Social_PrivateReceipt";

		private const float ReceiptTimeoutSeconds = 15f;

		private static readonly Dictionary<string, PendingMessage> Pending = new Dictionary<string, PendingMessage>();

		private static ZRoutedRpc registeredRpc;

		internal static void Update()
		{
			EnsureRpcs();
			if (Pending.Count == 0)
			{
				return;
			}
			List<string> list = null;
			foreach (KeyValuePair<string, PendingMessage> item in Pending)
			{
				if (!(Time.realtimeSinceStartup - item.Value.SentAt < 15f))
				{
					(list ?? (list = new List<string>())).Add(item.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (string item2 in list)
			{
				PendingMessage pendingMessage = Pending[item2];
				Pending.Remove(item2);
				SocializePlugin.Log.LogWarning("Private message [" + item2 + "] to '" + pendingMessage.TargetName + "' timed out waiting for a delivery receipt.");
				Terminal context = pendingMessage.Context;
				if (context != null)
				{
					context.AddString("Private message to " + pendingMessage.TargetName + " was not confirmed.");
				}
			}
		}

		internal static void Reset()
		{
			Pending.Clear();
			registeredRpc = null;
		}

		internal static bool Send(string targetName, string message, Terminal context)
		{
			//IL_0024: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			PlayerInfo target;
			bool num = TryFindPlayer(targetName, out target);
			GroupDecision groupDecision = PrivateChatPolicy.CanSend(num, num && IsLocalPlayer(target), targetName);
			if (!groupDecision.Allowed)
			{
				Terminal obj = context;
				if (obj != null)
				{
					obj.AddString(groupDecision.Message);
				}
				return false;
			}
			if (!PrivilegeResultExtentions.IsGranted(PlatformManager.DistributionPlatform.PrivilegeProvider.CheckPrivilege((Privilege)3)))
			{
				SocializePlugin.Log.LogWarning("Private message to '" + target.m_name + "' blocked by the sender's text privilege.");
				Terminal obj2 = context;
				if (obj2 != null)
				{
					obj2.AddString("Text communication is not permitted for this account.");
				}
				return false;
			}
			EnsureRpcs();
			SocializePlugin.Log.LogInfo($"Checking sender permission for private message to '{target.m_name}' (peer={((ZDOID)(ref target.m_characterID)).UserID}).");
			TextPermissionService.Check(target.m_userInfo.m_id, isSender: true, delegate(RelationsManagerPermissionResult result)
			{
				//IL_0001: 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)
				CompleteSendPermission(target, message, context, result);
			});
			return true;
		}

		private static void CompleteSendPermission(PlayerInfo target, string message, Terminal context, RelationsManagerPermissionResult result)
		{
			//IL_000a: 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_0020: 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_004a: Invalid comparison between Unknown and I4
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			SocializePlugin.Log.LogInfo($"Sender permission result for private message to '{target.m_name}': {result}.");
			if (!RelationsManagerPermissionResultExtentions.IsGranted(result))
			{
				if (context != null)
				{
					context.AddString("Private message to " + target.m_name + " is not permitted.");
				}
				return;
			}
			UserInfo val = default(UserInfo);
			string text = default(string);
			Chat.GetChatMessageData(message, (int)result == 1, ref val, ref text);
			string text2 = Guid.NewGuid().ToString("N").Substring(0, 12);
			long userID = ((ZDOID)(ref target.m_characterID)).UserID;
			Pending[text2] = new PendingMessage
			{
				TargetPeer = userID,
				TargetName = target.m_name,
				Message = text,
				Context = context,
				SentAt = Time.realtimeSinceStartup
			};
			SocializePlugin.Log.LogInfo($"Sending private message [{text2}] to '{target.m_name}' (peer={userID}, length={text.Length}).");
			ZRoutedRpc.instance.InvokeRoutedRPC(userID, "Landoria_Social_PrivateMessage", new object[3] { text2, val, text });
		}

		private static void EnsureRpcs()
		{
			RpcRegistry.RegisterIfChanged(ref registeredRpc, RegisterRpcs);
		}

		private static void RegisterRpcs(ZRoutedRpc rpc)
		{
			rpc.Register<string, UserInfo, string>("Landoria_Social_PrivateMessage", (Action<long, string, UserInfo, string>)RPC_PrivateMessage);
			rpc.Register<string, int>("Landoria_Social_PrivateReceipt", (Action<long, string, int>)RPC_PrivateReceipt);
			SocializePlugin.Log.LogDebug("Private message RPCs registered.");
		}

		private static void RPC_PrivateMessage(long sender, string requestId, UserInfo user, string message)
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (!IsExpectedUser(sender, user))
			{
				SocializePlugin.Log.LogWarning($"Private message [{requestId}] rejected because peer={sender} supplied an invalid identity.");
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance != null)
				{
					instance.InvokeRoutedRPC(sender, "Landoria_Social_PrivateReceipt", new object[2] { requestId, 3 });
				}
			}
			else
			{
				SocializePlugin.Log.LogInfo($"Private message [{requestId}] received from peer={sender} (user='{user.GetDisplayName()}', length={message.Length}); checking text permission.");
				TextPermissionService.Check(user.UserId, isSender: false, delegate(RelationsManagerPermissionResult result)
				{
					//IL_0018: Unknown result type (might be due to invalid IL or missing references)
					CompleteReceive(sender, requestId, user, message, result);
				});
			}
		}

		private static void CompleteReceive(long sender, string requestId, UserInfo user, string message, RelationsManagerPermissionResult result)
		{
			//IL_0011: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Invalid comparison between Unknown and I4
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected I4, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected I4, but got Unknown
			SocializePlugin.Log.LogInfo($"Private message [{requestId}] permission result for peer={sender}: {result}.");
			if (!RelationsManagerPermissionResultExtentions.IsGranted(result))
			{
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance != null)
				{
					instance.InvokeRoutedRPC(sender, "Landoria_Social_PrivateReceipt", new object[2]
					{
						requestId,
						(int)result
					});
				}
				return;
			}
			if ((Object)(object)Chat.instance == (Object)null)
			{
				SocializePlugin.Log.LogWarning("Private message [" + requestId + "] cannot be displayed because Chat is unavailable.");
				ZRoutedRpc instance2 = ZRoutedRpc.instance;
				if (instance2 != null)
				{
					instance2.InvokeRoutedRPC(sender, "Landoria_Social_PrivateReceipt", new object[2] { requestId, 3 });
				}
				return;
			}
			string text = message.Replace('<', ' ').Replace('>', ' ');
			if ((int)result == 1)
			{
				CensorShittyWords.Filter(text, ref text);
			}
			ChatFormatting.AddPrivate((Terminal)(object)Chat.instance, user.GetDisplayName(), text, timestamp: false);
			SocializePlugin.Log.LogInfo($"Private message [{requestId}] displayed; sending delivery receipt to peer={sender}.");
			ZRoutedRpc instance3 = ZRoutedRpc.instance;
			if (instance3 != null)
			{
				instance3.InvokeRoutedRPC(sender, "Landoria_Social_PrivateReceipt", new object[2]
				{
					requestId,
					(int)result
				});
			}
		}

		private static void RPC_PrivateReceipt(long sender, string requestId, int resultValue)
		{
			//IL_0001: 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_006f: 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)
			RelationsManagerPermissionResult val = (RelationsManagerPermissionResult)resultValue;
			if (!Pending.TryGetValue(requestId, out var value))
			{
				SocializePlugin.Log.LogWarning($"Ignoring unknown private message receipt [{requestId}] from peer={sender}, result={val}.");
				return;
			}
			if (value.TargetPeer != sender)
			{
				SocializePlugin.Log.LogWarning($"Ignoring private message receipt [{requestId}] from unexpected peer={sender}; expected={value.TargetPeer}.");
				return;
			}
			Pending.Remove(requestId);
			if (!RelationsManagerPermissionResultExtentions.IsGranted(val))
			{
				SocializePlugin.Log.LogWarning($"Private message [{requestId}] to '{value.TargetName}' was rejected: {val}.");
				Terminal context = value.Context;
				if (context != null)
				{
					context.AddString("Private message to " + value.TargetName + " was not delivered.");
				}
			}
			else
			{
				string name = Game.instance.GetPlayerProfile().GetName();
				ChatFormatting.AddPrivate(value.Context, name, "to " + value.TargetName + ": " + value.Message, timestamp: false);
				SocializePlugin.Log.LogInfo("Private message [" + requestId + "] to '" + value.TargetName + "' confirmed and shown to the sender.");
			}
		}

		private static bool TryFindPlayer(string name, out PlayerInfo player)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			foreach (PlayerInfo player2 in ZNet.instance.GetPlayerList())
			{
				if (string.Equals(player2.m_name, name, StringComparison.OrdinalIgnoreCase))
				{
					player = player2;
					return true;
				}
			}
			player = default(PlayerInfo);
			return false;
		}

		private static bool IsLocalPlayer(PlayerInfo player)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				long userID = ((ZDOID)(ref player.m_characterID)).UserID;
				ZDOID localPlayerCharacterID = ZNet.instance.LocalPlayerCharacterID;
				return userID == ((ZDOID)(ref localPlayerCharacterID)).UserID;
			}
			return false;
		}

		private unsafe static bool IsExpectedUser(long sender, UserInfo user)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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)
			if (user == null || (Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
			{
				ZDOID characterID = player.m_characterID;
				if (((ZDOID)(ref characterID)).UserID == sender)
				{
					int result;
					if (player.m_name == user.Name)
					{
						PlatformUserID id = player.m_userInfo.m_id;
						result = ((((object)(*(PlatformUserID*)(&id))/*cast due to .constrained prefix*/).ToString() == ((object)Unsafe.As<PlatformUserID, PlatformUserID>(ref user.UserId)/*cast due to .constrained prefix*/).ToString()) ? 1 : 0);
					}
					else
					{
						result = 0;
					}
					return (byte)result != 0;
				}
			}
			return false;
		}
	}
	internal static class ChatFormatting
	{
		internal static string FormatGroup(string sender, string message)
		{
			return ChatFormattingPolicy.FormatGroup(sender, message);
		}

		internal static void AddPrivate(Terminal terminal, string user, string text, bool timestamp)
		{
			terminal.AddString(GetTimestamp(timestamp) + ChatFormattingPolicy.FormatPrivate(user, text));
		}

		internal static void AddShout(Terminal terminal, string user, string text, bool timestamp)
		{
			terminal.AddString(GetTimestamp(timestamp) + ChatFormattingPolicy.FormatShout(user, text));
		}

		internal static void AddPing(Terminal terminal, string user, string target, string message)
		{
			terminal.AddString(ChatFormattingPolicy.FormatPing(user, target, message));
		}

		internal unsafe static string GetPlayerName(PlatformUserID user)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			PlayerInfo val = default(PlayerInfo);
			if (!ZNet.TryGetPlayerByPlatformUserID(user, ref val))
			{
				return ((object)(*(PlatformUserID*)(&user))/*cast due to .constrained prefix*/).ToString();
			}
			return val.m_name;
		}

		private static string GetTimestamp(bool enabled)
		{
			if (!enabled)
			{
				return "";
			}
			return "[" + DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss") + "] ";
		}
	}
	internal static class ChatFormattingPolicy
	{
		private const string GroupColor = "#4A90E2";

		private const string PrivateColor = "#2FAE5F";

		private const string ShoutColor = "#FFFF00";

		internal static string FormatGroup(string sender, string message)
		{
			return "<color=#4A90E2>" + sender + ": " + message + "</color>";
		}

		internal static string FormatPrivate(string user, string text)
		{
			string text2 = ((text ?? "").StartsWith("to ", StringComparison.OrdinalIgnoreCase) ? " " : ": ");
			return "<color=#2FAE5F>" + user + text2 + text + "</color>";
		}

		internal static string FormatShout(string user, string text)
		{
			return "<color=orange>" + user + "</color>: <color=#FFFF00>" + text + "</color>";
		}

		internal static string FormatArrival(string playerName, string message)
		{
			return "<color=orange>" + SecurityElement.Escape(playerName) + "</color><color=white>: </color><color=#FFFF00>" + SecurityElement.Escape(message) + "</color>";
		}

		internal static string FormatPing(string user, string target, string message)
		{
			string text = (string.IsNullOrEmpty(target) ? ": " : (" to " + target + ": "));
			return "<color=#2FAE5F>" + user + text + "</color><color=#FFFF00>((Ping))</color><color=#2FAE5F> " + message + "</color>";
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class RegisterSocialCommandsPatch
	{
		private static bool registered;

		private static void Postfix()
		{
			if (!registered)
			{
				registered = true;
				ChatCommands.Register();
				GroupCommands.Register();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class RequestSocialStateOnSpawnPatch
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				GroupService.RequestInitialState();
			}
		}
	}
	[HarmonyPatch(typeof(Chat), "AddInworldText")]
	internal static class DisablePrivateWorldTextPatch
	{
		private static bool Prefix(Type type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			return (int)type > 0;
		}
	}
	[HarmonyPatch(typeof(Chat), "SendPing")]
	internal static class LimitMapPingToGroupPatch
	{
		private static bool Prefix(Vector3 position)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (!SocializePlugin.Settings.RestrictPublicPings)
			{
				return true;
			}
			if (!MapSharingPolicy.CanSendPublicPing(restricted: true, GroupService.IsLocalPlayerInGroup()))
			{
				SocializePlugin.Log.LogDebug("Map ping ignored because the local player is not in a group.");
				return false;
			}
			GroupPingSender.Send(position);
			return false;
		}
	}
	internal static class GroupPingSender
	{
		internal static void Send(Vector3 position)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)ZNet.instance == (Object)null) && ZRoutedRpc.instance != null)
			{
				position.y = ((Component)Player.m_localPlayer).transform.position.y;
				ZRoutedRpc.instance.InvokeRoutedRPC("Landoria_Social_GroupPingRequest", new object[2]
				{
					position,
					UserInfo.GetLocalUser()
				});
			}
		}
	}
	[HarmonyPatch(typeof(Chat), "SendInput")]
	internal static class PersistentChatInputPatch
	{
		private static bool Prefix(Chat __instance)
		{
			if ((Object)(object)((Terminal)__instance).m_input == (Object)null || string.IsNullOrWhiteSpace(((TMP_InputField)((Terminal)__instance).m_input).text) || ((TMP_InputField)((Terminal)__instance).m_input).text.StartsWith("/") || !ChatChannelState.TryRedirect(((TMP_InputField)((Terminal)__instance).m_input).text))
			{
				return true;
			}
			((TMP_InputField)((Terminal)__instance).m_input).text = "";
			__instance.Hide();
			return false;
		}
	}
	[HarmonyPatch(typeof(Chat), "SendText")]
	internal static class PersistentChatChannelPatch
	{
		private static bool Prefix(Type type, string text)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			if ((int)type == 2)
			{
				if (text == Localization.instance.Localize("$text_player_arrived"))
				{
					return false;
				}
				SocialChatSender.SendShout(text);
				return false;
			}
			if ((int)type == 1)
			{
				return !ChatChannelState.TryRedirect(text);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Talker), "Awake")]
	internal static class SocialChatRangePatch
	{
		private static void Postfix(Talker __instance)
		{
			SocialChatSender.ApplyRanges(__instance);
		}
	}
	[HarmonyPatch(typeof(Chat), "Update")]
	internal static class ChatPresentationPatch
	{
		private static Chat owner;

		private static TMP_Text placeholder;

		private static float showUntil;

		private static void Postfix(Chat __instance)
		{
			if ((Object)(object)owner != (Object)(object)__instance)
			{
				owner = __instance;
				placeholder = null;
			}
			EnsurePlaceholder(__instance);
			if ((Object)(object)placeholder != (Object)null)
			{
				placeholder.text = ChatChannelState.GetPrompt();
			}
			if ((Object)(object)((Terminal)__instance).m_chatWindow != (Object)null && Time.time < showUntil)
			{
				((Component)((Terminal)__instance).m_chatWindow).gameObject.SetActive(true);
			}
		}

		internal static void Show(Terminal terminal)
		{
			Chat val = (Chat)(object)((terminal is Chat) ? terminal : null);
			if (!((Object)(object)val == (Object)null) && !val.HasFocus() && !((Object)(object)((Terminal)val).m_chatWindow == (Object)null))
			{
				((Component)((Terminal)val).m_chatWindow).gameObject.SetActive(true);
				showUntil = Time.time + val.m_hideDelay;
			}
		}

		private static void EnsurePlaceholder(Chat chat)
		{
			if (!((Object)(object)placeholder != (Object)null) && !((Object)(object)((Terminal)chat).m_input == (Object)null))
			{
				TMP_InputField val = ((Component)((Terminal)chat).m_input).GetComponent<TMP_InputField>() ?? ((Component)((Terminal)chat).m_input).GetComponentInChildren<TMP_InputField>(true);
				placeholder = (TMP_Text)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "AddString", new Type[] { typeof(string) })]
	internal static class AutoDisplaySimpleChatPatch
	{
		private static void Postfix(Terminal __instance)
		{
			ChatPresentationPatch.Show(__instance);
		}
	}
	[HarmonyPatch(typeof(Terminal), "AddString", new Type[]
	{
		typeof(string),
		typeof(string),
		typeof(Type),
		typeof(bool)
	})]
	internal static class FormatTitleChatPatch
	{
		private static bool Prefix(Terminal __instance, string title, string text, Type type, bool timestamp)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			if ((int)type == 0)
			{
				ChatFormatting.AddPrivate(__instance, title, text, timestamp);
				return false;
			}
			if ((int)type == 2)
			{
				ChatFormatting.AddShout(__instance, title, text, timestamp);
				return false;
			}
			return true;
		}

		private static void Postfix(Terminal __instance)
		{
			ChatPresentationPatch.Show(__instance);
		}
	}
	[HarmonyPatch(typeof(Terminal), "AddString", new Type[]
	{
		typeof(PlatformUserID),
		typeof(string),
		typeof(Type),
		typeof(bool)
	})]
	internal static class FormatUserChatPatch
	{
		private static bool Prefix(Terminal __instance, PlatformUserID user, string text, Type type, bool timestamp)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			string playerName = ChatFormatting.GetPlayerName(user);
			if ((int)type == 0)
			{
				ChatFormatting.AddPrivate(__instance, playerName, text, timestamp);
				return false;
			}
			if ((int)type == 2)
			{
				ChatFormatting.AddShout(__instance, playerName, text, timestamp);
				return false;
			}
			if ((int)type == 1)
			{
				__instance.AddString(playerName, text, type, timestamp);
				return false;
			}
			return true;
		}

		private static void Postfix(Terminal __instance)
		{
			ChatPresentationPatch.Show(__instance);
		}
	}
	internal static class GroupCommands
	{
		internal static void Register()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			new ConsoleCommand("group", "[help|invite|leave|remove|promote|info] manages your group", new ConsoleEvent(HandleGroup), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			new ConsoleCommand("g", "[message] sends a message to your group.", new ConsoleEvent(HandleGroupChat), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static void HandleGroup(ConsoleEventArgs args)
		{
			string text = (args.ArgsAll ?? "").Trim();
			int num = text.IndexOf(' ');
			string text2 = ((num < 0) ? text.ToLowerInvariant() : text.Substring(0, num).ToLowerInvariant());
			string argument = ((num < 0) ? "" : text.Substring(num + 1).Trim());
			if (text2 == "help" || string.IsNullOrEmpty(text2))
			{
				ShowHelp(args.Context);
			}
			else if (!ChatCommandParser.IsValidGroupAction(text2, argument))
			{
				ShowHelp(args.Context);
			}
			else
			{
				GroupService.SendRequest(text2, argument);
			}
		}

		private static void HandleGroupChat(ConsoleEventArgs args)
		{
			string text = (args.ArgsAll ?? "").Trim();
			if (string.IsNullOrEmpty(text))
			{
				args.Context.AddString("Usage: /g message");
				return;
			}
			ChatChannelState.SetGroup();
			GroupService.SendChat(text);
		}

		private static void ShowHelp(Terminal context)
		{
			context.AddString("/group invite <PlayerName> - Invites a connected player.");
			context.AddString("/group leave - Leaves your group.");
			context.AddString("/group remove <PlayerName> - Removes a member.");
			context.AddString("/group promote <PlayerName> - Promotes a member.");
			context.AddString("/group info - Lists group members.");
			context.AddString("/g <message> - Sends a group message.");
		}
	}
	internal sealed class GroupChatResult
	{
		internal bool Broadcast { get; }

		internal string Message { get; }

		internal GroupChatResult(bool broadcast, string message)
		{
			Broadcast = broadcast;
			Message = message;
		}
	}
	internal static class GroupChatPolicy
	{
		internal static GroupChatResult Prepare(SocialGroup group, long actor, string message, Func<long, bool> isOnline, Func<string, string, string> format)
		{
			if (group == null)
			{
				return Reject("You are not in a group.");
			}
			foreach (long key in group.Members.Keys)
			{
				if (key != actor && isOnline(key))
				{
					return new GroupChatResult(broadcast: true, format(group.Members[actor], message));
				}
			}
			return Reject("No other group member is connected.");
		}

		private static GroupChatResult Reject(string message)
		{
			return new GroupChatResult(broadcast: false, message);
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	internal static class GroupNewConnectionPatch
	{
		private static void Prefix(ZNetPeer peer)
		{
			if (peer != null)
			{
				GroupService.BeginPeerSession(peer.m_uid);
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Disconnect")]
	internal static class GroupDisconnectPatch
	{
		private static void Prefix(ZNetPeer peer)
		{
			if (peer != null)
			{
				GroupService.DisconnectPeer(peer.m_uid);
			}
		}
	}
	internal sealed class GroupAcceptanceResult
	{
		internal bool Accepted { get; }

		internal SocialGroup Group { get; }

		internal string Message { get; }

		internal GroupAcceptanceResult(bool accepted, SocialGroup group, string message)
		{
			Accepted = accepted;
			Group = group;
			Message = message;
		}
	}
	internal static class GroupAcceptancePolicy
	{
		internal static GroupAcceptanceResult Accept(long playerId, string playerName, string inviterText, IDictionary<long, long> invitations, Func<long, SocialGroup> getOrCreateGroup, IDictionary<long, int> playerGroups)
		{
			if (!long.TryParse(inviterText, out var result) || !invitations.TryGetValue(playerId, out var value) || value != result)
			{
				return Reject("That group invitation is no longer valid.");
			}
			SocialGroup socialGroup = getOrCreateGroup(result);
			if (socialGroup == null || socialGroup.Members.Count >= 5)
			{
				return Reject("That group is no longer available.");
			}
			socialGroup.AddMember(playerId, playerName);
			playerGroups[playerId] = socialGroup.Id;
			invitations.Remove(playerId);
			return new GroupAcceptanceResult(accepted: true, socialGroup, null);
		}

		private static GroupAcceptanceResult Reject(string message)
		{
			return new GroupAcceptanceResult(accepted: false, null, message);
		}
	}
	internal static class GroupInfoPolicy
	{
		internal static string Build(SocialGroup group, Func<long, bool> isOnline)
		{
			if (group == null)
			{
				return "You are not in a group.";
			}
			List<string> list = new List<string> { "Group members:" };
			foreach (KeyValuePair<long, string> member in group.Members)
			{
				string text = (isOnline(member.Key) ? "Connected" : "Disconnected");
				string text2 = ((member.Key == group.Leader) ? " - Group Leader" : "");
				list.Add(member.Value + " - " + text + text2);
			}
			return string.Join("\n", list);
		}
	}
	internal static class GroupInvitationPolicy
	{
		internal static GroupDecision TryInvite(SocialGroup group, long inviter, long target, bool targetAlreadyGrouped, IDictionary<long, long> invitations)
		{
			GroupDecision groupDecision = GroupPolicy.CanInvite(group, inviter, target, targetAlreadyGrouped);
			if (groupDecision.Allowed)
			{
				invitations[target] = inviter;
			}
			return groupDecision;
		}
	}
	internal sealed class GroupRemovalResult
	{
		internal bool Disbanded;

		internal long NewLeader;

		internal readonly List<long> RemainingMembers = new List<long>();
	}
	internal static class GroupLifecyclePolicy
	{
		internal static GroupRemovalResult Remove(SocialGroup group, long playerId)
		{
			group.RemoveMember(playerId);
			GroupRemovalResult groupRemovalResult = new GroupRemovalResult();
			if (group.Members.Count <= 1)
			{
				groupRemovalResult.Disbanded = true;
				groupRemovalResult.RemainingMembers.AddRange(group.Members.Keys);
				group.Members.Clear();
				return groupRemovalResult;
			}
			if (!group.Members.ContainsKey(group.Leader))
			{
				group.Leader = group.GetOldestMember();
			}
			groupRemovalResult.NewLeader = group.Leader;
			groupRemovalResult.RemainingMembers.AddRange(group.Members.Keys);
			return groupRemovalResult;
		}
	}
	internal static class GroupPromotionPolicy
	{
		internal static GroupDecision TryPromote(SocialGroup group, long actor, long target, string targetName)
		{
			GroupDecision groupDecision = GroupPolicy.CanTargetMember(group, actor, target, targetName);
			if (!groupDecision.Allowed)
			{
				return groupDecision;
			}
			groupDecision = GroupPolicy.CanPromote(actor, target);
			if (groupDecision.Allowed)
			{
				group.Leader = target;
			}
			return groupDecision;
		}
	}
	internal static class GroupState
	{
		internal static readonly Dictionary<int, SocialGroup> Groups = new Dictionary<int, SocialGroup>();

		internal static readonly Dictionary<long, int> PlayerGroups = new Dictionary<long, int>();

		internal static readonly Dictionary<long, long> PeerPlayers = new Dictionary<long, long>();

		internal static readonly Dictionary<long, long> Invitations = new Dictionary<long, long>();

		internal static readonly HashSet<long> LocalMembers = new HashSet<long>();

		internal static SocialGroup GetGroup(long playerId)
		{
			if (!PlayerGroups.TryGetValue(playerId, out var value) || !Groups.TryGetValue(value, out var value2))
			{
				return null;
			}
			return value2;
		}

		internal static int GetNextGroupId()
		{
			int num = 0;
			foreach (int key in Groups.Keys)
			{
				num = ((key > num) ? key : num);
			}
			return num + 1;
		}

		internal static void ClearServer()
		{
			Groups.Clear();
			PlayerGroups.Clear();
			PeerPlayers.Clear();
			Invitations.Clear();
		}

		internal static void ClearAll()
		{
			ClearServer();
			LocalMembers.Clear();
			GroupMapSharing.Clear();
		}
	}
	internal sealed class GroupDecision
	{
		internal bool Allowed { get; }

		internal string Message { get; }

		private GroupDecision(bool allowed, string message)
		{
			Allowed = allowed;
			Message = message;
		}

		internal static GroupDecision Allow()
		{
			return new GroupDecision(allowed: true, null);
		}

		internal static GroupDecision Deny(string message = null)
		{
			return new GroupDecision(allowed: false, message);
		}
	}
	internal static class GroupPolicy
	{
		internal static GroupDecision CanInviteTarget(bool targetReady)
		{
			if (!targetReady)
			{
				return GroupDecision.Deny("Player not found or not ready.");
			}
			return GroupDecision.Allow();
		}

		internal static GroupDecision CanInvite(SocialGroup group, long inviter, long target, bool targetAlreadyGrouped)
		{
			if (targetAlreadyGrouped)
			{
				return GroupDecision.Deny("That player is already in a group.");
			}
			if (group != null && group.Leader != inviter)
			{
				return GroupDecision.Deny("Only the group leader can invite players.");
			}
			if (group != null && group.Members.Count >= 5)
			{
				return GroupDecision.Deny("Your group is full.");
			}
			if (inviter == target)
			{
				return GroupDecision.Deny();
			}
			return GroupDecision.Allow();
		}

		internal static GroupDecision CanTargetMember(SocialGroup group, long actor, long target, string targetName)
		{
			if (group == null)
			{
				return GroupDecision.Deny("You are not in a group.");
			}
			if (group.Leader != actor)
			{
				return GroupDecision.Deny("Only the group leader can do that.");
			}
			if (target == 0L)
			{
				return GroupDecision.Deny("Player not found in your group: " + targetName);
			}
			return GroupDecision.Allow();
		}

		internal static GroupDecision CanRemove(long actor, long target)
		{
			if (target == actor)
			{
				return GroupDecision.Deny("You cannot remove yourself.");
			}
			return GroupDecision.Allow();
		}

		internal static GroupDecision CanPromote(long actor, long target)
		{
			if (target == actor)
			{
				return GroupDecision.Deny("You are already group leader.");
			}
			return GroupDecision.Allow();
		}
	}
	internal static class GroupMapSharing
	{
		private static readonly Dictionary<long, PlayerInfo> Players = new Dictionary<long, PlayerInfo>();

		internal static void Clear()
		{
			Players.Clear();
		}

		internal static void WritePosition(ZPackage package, long playerId)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetPosition(playerId, out var characterId, out var position))
			{
				package.Write(false);
				return;
			}
			package.Write(true);
			package.Write(characterId);
			package.Write(position);
		}

		internal static void ReadPosition(ZPackage package, long playerId, string name)
		{
			//IL_001d: 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_0033: 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_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)
			if (!package.ReadBool())
			{
				Players.Remove(playerId);
				return;
			}
			Players[playerId] = new PlayerInfo
			{
				m_name = name,
				m_characterID = package.ReadZDOID(),
				m_publicPosition = true,
				m_position = package.ReadVector3()
			};
		}

		internal static void AddGroupMembers(List<PlayerInfo> players)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			HashSet<long> hashSet = new HashSet<long>();
			foreach (PlayerInfo player in players)
			{
				ZDOID characterID = player.m_characterID;
				hashSet.Add(((ZDOID)(ref characterID)).UserID);
			}
			long localPlayerId = GetLocalPlayerId();
			foreach (KeyValuePair<long, PlayerInfo> player2 in Players)
			{
				if (MapSharingPolicy.ShouldAddGroupMember(player2.Key, localPlayerId, hashSet))
				{
					players.Add(player2.Value);
					hashSet.Add(player2.Key);
				}
			}
		}

		private static bool TryGetPosition(long playerId, out ZDOID characterId, out Vector3 position)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			Player player = Player.GetPlayer(playerId);
			if ((Object)(object)player != (Object)null)
			{
				characterId = ((Character)player).GetZDOID();
				position = ((Component)player).transform.position;
				return true;
			}
			return TryGetPeerPosition(playerId, out characterId, out position);
		}

		private static bool TryGetPeerPosition(long playerId, out ZDOID characterId, out Vector3 position)
		{
			//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_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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (GroupState.PeerPlayers.TryGetValue(peer.m_uid, out var value) && value == playerId && peer.IsReady() && !((ZDOID)(ref peer.m_characterID)).IsNone())
				{
					characterId = peer.m_characterID;
					position = peer.m_refPos;
					return true;
				}
			}
			characterId = ZDOID.None;
			position = Vector3.zero;
			return false;
		}

		private static long GetLocalPlayerId()
		{
			if (!((Object)(object)Game.instance != (Object)null))
			{
				return 0L;
			}
			return Game.instance.GetPlayerProfile().GetPlayerID();
		}
	}
	internal static class GroupRpc
	{
		internal static void RPC_Request(long sender, ZPackage package)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				SocializePlugin.Settings.InitializeServer(SocializePlugin.Log);
				string action = package.ReadString();
				long playerId = package.ReadLong();
				string playerName = package.ReadString();
				string argument = package.ReadString().Trim();
				UserInfo val = new UserInfo();
				val.Deserialize(ref package);
				GroupService.Dispatch(sender, playerId, playerName, action, argument, val);
			}
		}

		internal static void RPC_Response(long sender, ZPackage package)
		{
			if (!GroupService.IsExpectedServer(sender))
			{
				SocializePlugin.Log.LogWarning($"Ignored group response from unexpected peer={sender}.");
			}
			else
			{
				GroupService.ReadResponse(package);
			}
		}

		internal static void RPC_PingRequest(long sender, Vector3 position, UserInfo user)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				GroupService.RelayPing(sender, position, user);
			}
		}

		internal static void RPC_ChatReceipt(long sender, string requestId, int result)
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				GroupService.ReceiveChatReceipt(sender, requestId, (RelationsManagerPermissionResult)result);
			}
		}
	}
	internal static class GroupService
	{
		private sealed class PendingGroupChat
		{
			internal long Sender;

			internal UserInfo User;

			internal string Message;

			internal readonly HashSet<long> Waiting = new HashSet<long>();

			internal int Rejected;

			internal float SentAt;
		}

		private sealed class PendingInvite
		{
			internal long InviterPeer;

			internal string TargetName;

			internal float SentAt;
		}

		internal const string RequestRpc = "Landoria_Social_GroupRequest";

		internal const string ResponseRpc = "Landoria_Social_GroupResponse";

		internal const string PingRequestRpc = "Landoria_Social_GroupPingRequest";

		internal const string ChatReceiptRpc = "Landoria_Social_GroupChatReceipt";

		private const float PositionUpdateInterval = 2f;

		private const float ChatReceiptTimeout = 15f;

		private static ZRoutedRpc registeredRpc;

		private static float nextPositionUpdate;

		private static bool awaitingInitialState;

		private static float nextInitialStateRequest;

		private static readonly Dictionary<string, PendingGroupChat> PendingChats = new Dictionary<string, PendingGroupChat>();

		private static readonly Dictionary<long, PendingInvite> PendingInvites = new Dictionary<long, PendingInvite>();

		internal static void Update()
		{
			EnsureRpcs();
			if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null)
			{
				return;
			}
			if (ZNet.instance.IsServer())
			{
				SocializePlugin.Settings.InitializeServer(SocializePlugin.Log);
				if (Time.unscaledTime >= nextPositionUpdate)
				{
					nextPositionUpdate = Time.unscaledTime + 2f;
					BroadcastPositionUpdates();
				}
				ExpireGroupChats();
				ExpireInvites();
			}
			else if (awaitingInitialState && (Object)(object)Player.m_localPlayer != (Object)null && Time.unscaledTime >= nextInitialStateRequest)
			{
				SendInitialStateRequest();
			}
		}

		internal static void Reset()
		{
			registeredRpc = null;
			nextPositionUpdate = 0f;
			awaitingInitialState = false;
			nextInitialStateRequest = 0f;
			PendingChats.Clear();
			PendingInvites.Clear();
			GroupState.ClearAll();
			SocializePlugin.Settings?.ResetState();
			SocialChatSender.ApplyRangesToLoadedTalkers();
		}

		internal static bool IsLocalPlayerInGroup()
		{
			if ((Object)(object)Game.instance != (Object)null)
			{
				return GroupState.LocalMembers.Contains(Game.instance.GetPlayerProfile().GetPlayerID());
			}
			return false;
		}

		internal static bool IsExpectedServer(long sender)
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			if (ZNet.instance.IsServer())
			{
				return true;
			}
			ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
			if (serverPeer != null)
			{
				return serverPeer.m_uid == sender;
			}
			return false;
		}

		internal static void SendChat(string message)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (!IsLocalPlayerInGroup())
			{
				Chat instance = Chat.instance;
				if (instance != null)
				{
					((Terminal)instance).AddString("You are not in a group.");
				}
			}
			else if (!PrivilegeResultExtentions.IsGranted(PlatformManager.DistributionPlatform.PrivilegeProvider.CheckPrivilege((Privilege)3)))
			{
				SocializePlugin.Log.LogWarning("Group chat blocked by the sender's text privilege.");
				Chat instance2 = Chat.instance;
				if (instance2 != null)
				{
					((Terminal)instance2).AddString("Text communication is not permitted for this account.");
				}
			}
			else
			{
				BeginGroupChatPermissionCheck(message);
			}
		}

		private static void BeginGroupChatPermissionCheck(string message)
		{
			//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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0060: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			List<PlayerInfo> list = new List<PlayerInfo>();
			ZDOID val = ZNet.instance.LocalPlayerCharacterID;
			long userID = ((ZDOID)(ref val)).UserID;
			foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
			{
				val = player.m_characterID;
				if (((ZDOID)(ref val)).UserID != userID)
				{
					HashSet<long> localMembers = GroupState.LocalMembers;
					val = player.m_characterID;
					if (localMembers.Contains(((ZDOID)(ref val)).UserID))
					{
						list.Add(player);
					}
				}
			}
			if (list.Count == 0)
			{
				SendChatRequest(message);
				return;
			}
			int remaining = list.Count;
			bool denied = false;
			SocializePlugin.Log.LogInfo($"Checking sender permission for group chat against {list.Count} recipient(s).");
			foreach (PlayerInfo item in list)
			{
				PlayerInfo captured = item;
				TextPermissionService.Check(captured.m_userInfo.m_id, isSender: true, delegate(RelationsManagerPermissionResult result)
				{
					//IL_0015: 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)
					SocializePlugin.Log.LogInfo($"Sender permission result for group member '{captured.m_name}': {result}.");
					if (!RelationsManagerPermissionResultExtentions.IsGranted(result))
					{
						denied = true;
					}
					int num = remaining;
					remaining = num - 1;
					if (remaining == 0)
					{
						if (denied)
						{
							Chat instance = Chat.instance;
							if (instance != null)
							{
								((Terminal)instance).AddString("Group message is not permitted for every connected member.");
							}
							SocializePlugin.Log.LogWarning("Group chat cancelled because at least one sender permission check failed.");
						}
						else
						{
							SendChatRequest(message);
						}
					}
				});
			}
		}

		private static void SendChatRequest(string message)
		{
			EnsureRpcs();
			if (ZRoutedRpc.instance != null && !((Object)(object)Game.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				UserInfo val = default(UserInfo);
				string text = default(string);
				Chat.GetChatMessageData(message, true, ref val, ref text);
				ZPackage val2 = NewRequest("chat", text);
				SocializePlugin.Log.LogInfo($"Sending group chat request (length={text.Length}).");
				ZRoutedRpc.instance.InvokeRoutedRPC("Landoria_Social_GroupRequest", new object[1] { val2 });
			}
		}

		internal static void SendRequest(string action, string argument)
		{
			EnsureRpcs();
			if (ZRoutedRpc.instance != null && !((Object)(object)Game.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				ZPackage val = NewRequest(action, argument);
				ZRoutedRpc.instance.InvokeRoutedRPC("Landoria_Social_GroupRequest", new object[1] { val });
			}
		}

		private static ZPackage NewRequest(string action, string argument)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(action);
			val.Write(Game.instance.GetPlayerProfile().GetPlayerID());
			val.Write(Game.instance.GetPlayerProfile().GetName());
			val.Write(argument ?? "");
			UserInfo.GetLocalUser().Serialize(ref val);
			return val;
		}

		internal static void RequestInitialState()
		{
			awaitingInitialState = true;
			SendInitialStateRequest();
		}

		private static void SendInitialStateRequest()
		{
			nextInitialStateRequest = Time.unscaledTime + 2f;
			SocializePlugin.Log.LogDebug("Requesting initial group state from the server.");
			SendRequest("state", "");
		}

		internal static void Dispatch(long sender, long playerId, string playerName, string action, string argument, UserInfo user)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!TryValidateIdentity(sender, playerId, playerName, user, out var connected, out var reason))
			{
				SocializePlugin.Log.LogWarning($"Rejected group action '{action}' from peer={sender}: {reason}");
				if (action != "state")
				{
					SendMessage(sender, "Group action rejected because the player identity could not be verified.");
				}
				return;
			}
			SocializePlugin.Log.LogInfo($"Processing group action '{action}' from '{connected.m_name}' (peer={sender}).");
			if (RegisterSession(sender, playerId))
			{
				BroadcastArrival(playerName);
			}
			switch (action)
			{
			case "state":
				SendSnapshot(sender, playerId);
				break;
			case "invite":
				Invite(sender, playerId, playerName, argument);
				break;
			case "invite-received":
				ConfirmInviteReceipt(sender, playerId, argument);
				break;
			case "accept":
				Accept(sender, playerId, playerName, argument);
				break;
			case "reject":
				Reject(sender, playerId, argument);
				break;
			case "leave":
				Leave(sender, playerId);
				break;
			case "remove":
				Remove(sender, playerId, argument);
				break;
			case "promote":
				Promote(sender, playerId, argument);
				break;
			case "info":
				SendInfo(sender, playerId);
				break;
			case "chat":
				SendGroupChat(sender, playerId, argument, user);
				break;
			default:
				SocializePlugin.Log.LogWarning($"Ignored unknown group action '{action}' from peer={sender}.");
				break;
			}
		}

		internal static void ReadResponse(ZPackage package)
		{
			switch (package.ReadString())
			{
			case "message":
			{
				Chat instance = Chat.instance;
				if (instance != null)
				{
					((Terminal)instance).AddString(package.ReadString());
				}
				break;
			}
			case "arrival":
				ShowArrival(package.ReadString());
				break;
			case "snapshot":
				ReadSnapshot(package);
				break;
			case "positions":
				ReadPositionUpdate(package);
				break;
			case "invite":
				ShowInvite(package.ReadString(), package.ReadString());
				break;
			case "groupChat":
				ReadGroupChat(package);
				break;
			case "groupChatResult":
				ReadGroupChatResult(package);
				break;
			}
		}

		private static void EnsureRpcs()
		{
			if (RpcRegistry.RegisterIfChanged(ref registeredRpc, RegisterRpcs))
			{
				GroupState.ClearAll();
				SocializePlugin.Settings?.ResetState();
				SocialChatSender.ApplyRangesToLoadedTalkers();
			}
		}

		private static void RegisterRpcs(ZRoutedRpc rpc)
		{
			rpc.Register<ZPackage>("Landoria_Social_GroupRequest", (Action<long, ZPackage>)GroupRpc.RPC_Request);
			rpc.Register<ZPackage>("Landoria_Social_GroupResponse", (Action<long, ZPackage>)GroupRpc.RPC_Response);
			rpc.Register<Vector3, UserInfo>("Landoria_Social_GroupPingRequest", (Action<long, Vector3, UserInfo>)GroupRpc.RPC_PingRequest);
			rpc.Register<string, int>("Landoria_Social_GroupChatReceipt", (Action<long, string, int>)GroupRpc.RPC_ChatReceipt);
		}

		internal static void RelayPing(long sender, Vector3 position, UserInfo user)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			if (!GroupState.PeerPlayers.TryGetValue(sender, out var value))
			{
				SocializePlugin.Log.LogDebug("Group ping ignored because the sender is not registered.");
				return;
			}
			SocialGroup socialGroup = GroupState.GetGroup(value);
			if (socialGroup == null)
			{
				SocializePlugin.Log.LogDebug("Group ping ignored because the sender is not in a group.");
				return;
			}
			if (!TryGetAuthoritativeUser(sender, user, out var user2))
			{
				SocializePlugin.Log.LogWarning($"Group ping ignored because peer={sender} supplied an invalid identity.");
				return;
			}
			int num = 0;
			foreach (long key in socialGroup.Members.Keys)
			{
				long num2 = FindPeer(key);
				if (num2 != 0L)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(num2, "ChatMessage", new object[4] { position, 3, user2, "" });
					num++;
				}
			}
			SocializePlugin.Log.LogDebug($"Relayed group ping from {GetPlayerName(value)} to {num} member(s).");
		}

		private static void Invite(long sender, long inviter, string inviterName, string targetName)
		{
			long num = FindPeerByName(targetName);
			long playerId;
			GroupDecision groupDecision = GroupPolicy.CanInviteTarget(TryGetPlayerForPeer(num, out playerId));
			if (!groupDecision.Allowed)
			{
				SendMessage(sender, groupDecision.Message);
				return;
			}
			GroupDecision groupDecision2 = GroupInvitationPolicy.TryInvite(GroupState.GetGroup(inviter), inviter, playerId, GroupState.PlayerGroups.ContainsKey(playerId), GroupState.Invitations);
			if (!groupDecision2.Allowed)
			{
				if (groupDecision2.Message != null)
				{
					SendMessage(sender, groupDecision2.Message);
				}
				return;
			}
			ZPackage val = NewResponse("invite");
			val.Write(inviter.ToString());
			val.Write(inviterName);
			PendingInvites[playerId] = new PendingInvite
			{
				InviterPeer = sender,
				TargetName = targetName,
				SentAt = Time.realtimeSinceStartup
			};
			ZRoutedRpc.instance.InvokeRoutedRPC(num, "Landoria_Social_GroupResponse", new object[1] { val });
			SocializePlugin.Log.LogInfo($"Group invitation queued from peer={sender} for peer={num}; awaiting display receipt.");
		}

		private static void ConfirmInviteReceipt(long sender, long playerId, string inviterText)
		{
			if (!long.TryParse(inviterText, out var result) || !GroupState.Invitations.TryGetValue(playerId, out var value) || result != value)
			{
				SocializePlugin.Log.LogWarning($"Invalid group invitation receipt from peer={sender} for inviter={inviterText}.");
				return;
			}
			long peer = FindPeer(result);
			PendingInvites.Remove(playerId);
			SendMessage(peer, "Group invitation delivered.");
			SocializePlugin.Log.LogInfo($"Group invitation from player={result} displayed for player={playerId}.");
		}

		private static void Accept(long sender, long playerId, string playerName, string inviterText)
		{
			PendingInvites.Remove(playerId);
			GroupAcceptanceResult groupAcceptanceResult = GroupAcceptancePolicy.Accept(playerId, playerName, inviterText, GroupState.Invitations, GetOrCreateGroup, GroupState.PlayerGroups);
			if (!groupAcceptanceResult.Accepted)
			{
				SendMessage(sender, groupAcceptanceResult.Message);
			}
			else
			{
				BroadcastChange(groupAcceptanceResult.Group, playerName + " joined the group.");
			}
		}

		private static SocialGroup GetOrCreateGroup(long inviter)
		{
			SocialGroup socialGroup = GroupState.GetGroup(inviter);
			if (socialGroup != null)
			{
				if (socialGroup.Leader != inviter)
				{
					return null;
				}
				return socialGroup;
			}
			socialGroup = new SocialGroup
			{
				Id = GroupState.GetNextGroupId(),
				Leader = inviter
			};
			socialGroup.AddMember(inviter, GetPlayerName(inviter));
			GroupState.Groups[socialGroup.Id] = socialGroup;
			GroupState.PlayerGroups[inviter] = socialGroup.Id;
			return socialGroup;
		}

		private static void Reject(long sender, long playerId, string inviterText)
		{
			PendingInvites.Remove(playerId);
			GroupState.Invitations.Remove(playerId);
			SendMessage(sender, "Group invitation rejected.");
			if (long.TryParse(inviterText, out var result))
			{
				SendMessage(FindPeer(result), GetPlayerName(playerId) + " rejected the group invitation.");
			}
		}

		private static void Leave(long sender, long playerId)
		{
			SocialGroup socialGroup = GroupState.GetGroup(playerId);
			if (socialGroup == null)
			{
				SendMessage(sender, "You are not in a group.");
				return;
			}
			string text = socialGroup.Members[playerId];
			GroupState.PlayerGroups.Remove(playerId);
			GroupRemovalResult groupRemovalResult = GroupLifecyclePolicy.Remove(socialGroup, playerId);
			BroadcastMembers(groupRemovalResult.RemainingMembers, text + " left the group.");
			ApplyRemoval(socialGroup, groupRemovalResult);
			SendSnapshot(sender, playerId);
			SendMessage(sender, "You left the group.");
			BroadcastSnapshots(socialGroup);
		}

		private static void Remove(long sender, long actor, string targetName)
		{
			SocialGroup socialGroup = GroupState.GetGroup(actor);
			long num = FindMember(socialGroup, targetName);
			if (ValidateLeaderAction(sender, actor, targetName, socialGroup, num) && ValidateRemoveTarget(sender, actor, num))
			{
				string text = socialGroup.Members[num];
				long peer = FindPeer(num);
				GroupState.PlayerGroups.Remove(num);
				GroupRemovalResult groupRemovalResult = GroupLifecyclePolicy.Remove(socialGroup, num);
				BroadcastMembers(groupRemovalResult.RemainingMembers, text + " was removed from the group.");
				ApplyRemoval(socialGroup, groupRemovalResult);
				SendSnapshot(peer, num);
				SendMessage(peer, "You were removed from the group.");
				BroadcastSnapshots(socialGroup);
			}
		}

		private static void Promote(long sender, long actor, string targetName)
		{
			SocialGroup socialGroup = GroupState.GetGroup(actor);
			long num = FindMember(socialGroup, targetName);
			GroupDecision groupDecision = GroupPromotionPolicy.TryPromote(socialGroup, actor, num, targetName);
			if (!groupDecision.Allowed)
			{
				SendMessage(sender, groupDecision.Message);
				return;
			}
			Broadcast(socialGroup, socialGroup.Members[num] + " is now the group leader.");
			BroadcastSnapshots(socialGroup);
		}

		private static bool ValidateLeaderAction(long sender, long actor, string targetName, SocialGroup group, long target)
		{
			GroupDecision groupDecision = GroupPolicy.CanTargetMember(group, actor, target, targetName);
			if (!groupDecision.Allowed)
			{
				SendMessage(sender, groupDecision.Message);
			}
			return groupDecision.Allowed;
		}

		private static bool ValidateRemoveTarget(long sender, long actor, long target)
		{
			return ValidateTargetDecision(sender, GroupPolicy.CanRemove(actor, target));
		}

		private static bool ValidateTargetDecision(long sender, GroupDecision decision)
		{
			if (!decision.Allowed)
			{
				SendMessage(sender, decision.Message);
			}
			return decision.Allowed;
		}

		private static void ApplyRemoval(SocialGroup group, GroupRemovalResult result)
		{
			if (!result.Disbanded)
			{
				return;
			}
			foreach (long remainingMember in result.RemainingMembers)
			{
				GroupState.PlayerGroups.Remove(remainingMember);
				SendMessage(FindPeer(remainingMember), "The group was disbanded.");
				SendSnapshot(FindPeer(remainingMember), remainingMember);
			}
			GroupState.Groups.Remove(group.Id);
		}

		private static void SendGroupChat(long sender, long actor, string message, UserInfo user)
		{
			SocialGroup socialGroup = GroupState.GetGroup(actor);
			GroupChatResult groupChatResult = GroupChatPolicy.Prepare(socialGroup, actor, message, (long member) => FindPeer(member) != 0, (string name, string result) => result);
			if (!groupChatResult.Broadcast)
			{
				SendMessage(sender, groupChatResult.Message);
				return;
			}
			if (!TryGetAuthoritativeUser(sender, user, out var user2))
			{
				SocializePlugin.Log.LogWarning($"Rejected group chat from peer={sender}: identity mismatch.");
				SendMessage(sender, "Group message rejected because the sender identity could not be verified.");
				return;
			}
			string text = Guid.NewGuid().ToString("N").Substring(0, 12);
			PendingGroupChat pendingGroupChat = new PendingGroupChat
			{
				Sender = sender,
				User = user2,
				Message = groupChatResult.Message,
				SentAt = Time.realtimeSinceStartup
			};
			foreach (long key in socialGroup.Members.Keys)
			{
				long num = FindPeer(key);
				if (num != 0L && num != sender)
				{
					pendingGroupChat.Waiting.Add(num);
				}
			}
			PendingChats[text] = pendingGroupChat;
			foreach (long item in pendingGroupChat.Waiting)
			{
				SendGroupChatDelivery(item, text, user2, groupChatResult.Message);
			}
			SocializePlugin.Log.LogInfo($"Group chat [{text}] accepted from peer={sender}; waiting for {pendingGroupChat.Waiting.Count} receipt(s).");
			if (pendingGroupChat.Waiting.Count == 0)
			{
				CompleteGroupChat(text, pendingGroupChat);
			}
		}

		private static void SendGroupChatDelivery(long peer, string requestId, UserInfo user, string message)
		{
			ZPackage val = NewResponse("groupChat");
			val.Write(requestId);
			user.Serialize(ref val);
			val.Write(message);
			ZRoutedRpc.instance.InvokeRoutedRPC(peer, "Landoria_Social_GroupResponse", new object[1] { val });
		}

		private static void ReadGroupChat(ZPackage package)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			string requestId = package.ReadString();
			UserInfo user = new UserInfo();
			user.Deserialize(ref package);
			string message = package.ReadString();
			SocializePlugin.Log.LogInfo($"Group chat [{requestId}] received from '{user.GetDisplayName()}' (length={message.Length}); checking permission.");
			TextPermissionService.Check(user.UserId, isSender: false, delegate(RelationsManagerPermissionResult result)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				CompleteGroupChatReceive(requestId, user, message, result);
			});
		}

		private static void CompleteGroupChatReceive(string requestId, UserInfo user, string message, RelationsManagerPermissionResult result)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected I4, but got Unknown
			SocializePlugin.Log.LogInfo($"Group chat [{requestId}] permission result: {result}.");
			if (RelationsManagerPermissionResultExtentions.IsGranted(result) && (Object)(object)Chat.instance != (Object)null)
			{
				string text = message.Replace('<', ' ').Replace('>', ' ');
				if ((int)result == 1)
				{
					CensorShittyWords.Filter(text, ref text);
				}
				((Terminal)Chat.instance).AddString(ChatFormatting.FormatGroup(user.GetDisplayName(), text));
				SocializePlugin.Log.LogInfo("Group chat [" + requestId + "] displayed; sending receipt.");
			}
			else if (RelationsManagerPermissionResultExtentions.IsGranted(result))
			{
				result = (RelationsManagerPermissionResult)3;
			}
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.InvokeRoutedRPC("Landoria_Social_GroupChatReceipt", new object[2]
				{
					requestId,
					(int)result
				});
			}
		}

		internal static void ReceiveChatReceipt(long sender, string requestId, RelationsManagerPermissionResult result)
		{
			//IL_0039: 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)
			if (!PendingChats.TryGetValue(requestId, out var value) || !value.Waiting.Remove(sender))
			{
				SocializePlugin.Log.LogWarning($"Ignoring unknown group chat receipt [{requestId}] from peer={sender}.");
				return;
			}
			if (!RelationsManagerPermissionResultExtentions.IsGranted(result))
			{
				value.Rejected++;
			}
			SocializePlugin.Log.LogInfo($"Group chat [{requestId}] receipt from peer={sender}: {result}; remaining={value.Waiting.Count}.");
			if (value.Waiting.Count == 0)
			{
				CompleteGroupChat(requestId, value);
			}
		}

		private static void CompleteGroupChat(string requestId, PendingGroupChat pending)
		{
			PendingChats.Remove(requestId);
			ZPackage val = NewResponse("groupChatResult");
			val.Write(requestId);
			val.Write(pending.Rejected == 0);
			pending.User.Serialize(ref val);
			val.Write(pending.Message);
			val.Write(pending.Rejected);
			ZRoutedRpc.instance.InvokeRoutedRPC(pending.Sender, "Landoria_Social_GroupResponse", new object[1] { val });
		}

		private static void ReadGroupChatResult(ZPackage package)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			string text = package.ReadString();
			bool num = package.ReadBool();
			UserInfo val = new UserInfo();
			val.Deserialize(ref package);
			string text2 = package.ReadString();
			int num2 = package.ReadInt();
			if (num)
			{
				string message = text2.Replace('<', ' ').Replace('>', ' ');
				Chat instance = Chat.instance;
				if (instance != null)
				{
					((Terminal)instance).AddString(ChatFormatting.FormatGroup(val.GetDisplayName(), message));
				}
				SocializePlugin.Log.LogInfo("Group chat [" + text + "] confirmed and shown to the sender.");
			}
			else
			{
				Chat instance2 = Chat.instance;
				if (instance2 != null)
				{
					((Terminal)instance2).AddString("Group message was not delivered to every member.");
				}
				SocializePlugin.Log.LogWarning($"Group chat [{text}] completed with {num2} rejected delivery attempt(s).");
			}
		}

		private static void ExpireGroupChats()
		{
			List<string> list = null;
			foreach (KeyValuePair<string, PendingGroupChat> pendingChat in PendingChats)
			{
				if (Time.realtimeSinceStartup - pendingChat.Value.SentAt >= 15f)
				{
					(list ?? (list = new List<string>())).Add(pendingChat.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (string item in list)
			{
				PendingGroupChat pendingGroupChat = PendingChats[item];
				PendingChats.Remove(item);
				SendMessage(pendingGroupChat.Sender, "Group message was not confirmed by every member.");
				SocializePlugin.Log.LogWarning($"Group chat [{item}] timed out with {pendingGroupChat.Waiting.Count} missing receipt(s).");
			}
		}

		private static void ExpireInvites()
		{
			List<long> list = null;
			foreach (KeyValuePair<long, PendingInvite> pendingInvite2 in PendingInvites)
			{
				if (Time.realtimeSinceStartup - pendingInvite2.Value.SentAt >= 15f)
				{
					(list ?? (list = new List<long>())).Add(pendingInvite2.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (long item in list)
			{
				PendingInvite pendingInvite = PendingInvites[item];
				PendingInvites.Remove(item);
				GroupState.Invitations.Remove(item);
				SendMessage(pendingInvite.InviterPeer, "Group invitation to " + pendingInvite.TargetName + " was not confirmed.");
				SocializePlugin.Log.LogWarning($"Group invitation to player={item} timed out waiting for display confirmation.");
			}
		}

		private unsafe static bool TryGetAuthoritativeUser(long sender, UserInfo claimed, out UserInfo user)
		{
			//IL_0012: 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)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			user = null;
			if (claimed == null || !TryGetPlayerInfo(sender, out var player))
			{
				return false;
			}
			if (player.m_name != claimed.Name || ((object)(*(PlatformUserID*)(&player.m_userInfo.m_id))/*cast due to .constrained prefix*/).ToString() != ((object)Unsafe.As<PlatformUserID, PlatformUserID>(ref claimed.UserId)/*cast due to .constrained prefix*/).ToString())
			{
				return false;
			}
			user = new UserInfo
			{
				Name = player.m_name,
				UserId = player.m_userInfo.m_id
			};
			return true;
		}

		private static bool TryGetPlayerInfo(long peer, out PlayerInfo player)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				foreach (PlayerInfo player2 in ZNet.instance.GetPlayerList())
				{
					ZDOID characterID = player2.m_characterID;
					if (((ZDOID)(ref characterID)).UserID == peer)
					{
						player = player2;
						return true;
					}
				}
			}
			player = default(PlayerInfo);
			return false;
		}

		private static bool IsPlayerIdClaimedByOtherPeer(long peer, long playerId)
		{
			foreach (KeyValuePair<long, long> peerPlayer in GroupState.PeerPlayers)
			{
				if (peerPlayer.Key != peer && peerPlayer.Value == playerId)
				{
					return true;
				}
			}
			return false;
		}

		private static bool TryValidateIdentity(long peer, long playerId, string playerName, UserInfo claimed, out PlayerInfo connected, out string reason)
		{
			if (!TryGetPlayerInfo(peer, out connected))
			{
				reason = "the peer is not present in the server player list yet";
				return false;
			}
			if (claimed == null)
			{
				reason = "the request did not contain a platform identity";
				return false;
			}
			if (connected.m_name != playerName || connected.m_name != claimed.Name)
			{
				reason = "name mismatch (connected='" + connected.m_name + "', player='" + playerName + "', platform='" + claimed.Name + "')";
				return false;
			}
			string text = ((object)Unsafe.As<PlatformUserID, PlatformUserID>(ref connected.m_userInfo.m_id)/*cast due to .constrained prefix*/).ToString();
			string text2 = ((object)Unsafe.As<PlatformUserID, PlatformUserID>(ref claimed.UserId)/*cast due to .constrained prefix*/).ToString();
			if (text != text2)
			{
				reason = "platform user mismatch (connected='" + text + "', claimed='" + text2 + "')";
				return false;
			}
			if (IsPlayerIdClaimedByOtherPeer(peer, playerId))
			{
				reason = $"player id '{playerId}' is already associated with another peer";
				return false;
			}
			reason = null;
			return true;
		}

		private static void SendInfo(long sender, long playerId)
		{
			SocialGroup socialGroup = GroupState.GetGroup(playerId);
			SendMessage(sender, GroupInfoPolicy.Build(socialGroup, (long member) => FindPeer(member) != 0));
		}

		private static void BroadcastChange(SocialGroup group, string message)
		{
			Broadcast(group, message);
			BroadcastSnapshots(group);
			SocializePlugin.Log.LogInfo(message);
		}

		internal static void BeginPeerSession(long peer)
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && GroupState.PeerPlayers.ContainsKey(peer))
			{
				DisconnectPeer(peer);
			}
		}

		internal static void DisconnectPeer(long peer)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && GroupState.PeerPlayers.TryGetValue(peer, out var value))
			{
				GroupState.PeerPlayers.Remove(peer);
				RemovePlayerSession(value);
			}
		}

		private static bool RegisterSession(long peer, long playerId)
		{
			int num;
			if (GroupState.PeerPlayers.TryGetValue(peer, out var value))
			{
				num = ((value == playerId) ? 1 : 0);
				if (num != 0)
				{
					goto IL_0028;
				}
			}
			else
			{
				num = 0;
			}
			if (value != 0L)
			{
				RemovePlayerSession(value);
			}
			RemovePlayerSession(playerId);
			goto IL_0028;
			IL_0028:
			GroupState.PeerPlayers[peer] = playerId;
			return num == 0;
		}

		private static void RemovePlayerSession(long playerId)
		{
			RemovePeerMappings(playerId);
			RemoveInvitations(playerId);
			SocialGroup socialGroup = GroupState.GetGroup(playerId);
			if (socialGroup != null)
			{
				string text = socialGroup.Members[playerId];
				GroupState.PlayerGroups.Remove(playerId);
				GroupRemovalResult groupRemovalResult = GroupLifecyclePolicy.Remove(socialGroup, playerId);
				BroadcastMembers(groupRemovalResult.RemainingMembers, text + " left the group.");
				ApplyRemoval(socialGroup, groupRemovalResult);
				BroadcastSnapshots(socialGroup);
			}
		}

		private static void RemovePeerMappings(long playerId)
		{
			foreach (long item in new List<long>(GroupState.PeerPlayers.Keys))
			{
				if (GroupState.PeerPlayers[item] == playerId)
				{
					GroupState.PeerPlayers.Remove(item);
				}
			}
		}

		private static void RemoveInvitations(long playerId)
		{
			GroupState.Invitations.Remove(playerId);
			PendingInvites.Remove(playerId);
			foreach (long item in new List<long>(GroupState.Invitations.Keys))
			{
				if (GroupState.Invitations[item] == playerId)
				{
					GroupState.Invitations.Remove(item);
					PendingInvites.Remove(item);
				}
			}
		}

		private static void BroadcastSnapshots(SocialGroup group)
		{
			if (group == null)
			{
				return;
			}
			foreach (long key in group.Members.Keys)
			{
				SendSnapshot(FindPeer(key), key);
			}
		}

		private static void BroadcastPositionUpdates()
		{
			foreach (SocialGroup value in GroupState.Groups.Values)
			{
				foreach (long key in value.Members.Keys)
				{
					SendPositionUpdate(FindPeer(key), value);
				}
			}
		}

		private static void SendPositionUpdate(long peer, SocialGroup group)
		{
			if (peer == 0L || group == null)
			{
				return;
			}
			ZPackage val = NewResponse("positions");
			val.Write(group.Members.Count);
			foreach (KeyValuePair<long, string> member in group.Members)
			{
				val.Write(member.Key);
				val.Write(member.Value);
				GroupMapSharing.WritePosition(val, member.Key);
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(peer, "Landoria_Social_GroupResponse", new object[1] { val });
		}

		private static void SendSnapshot(long peer, long playerId)
		{
			if (peer == 0L)
			{
				return;
			}
			SocialGroup socialGroup = GroupState.GetGroup(playerId);
			ZPackage val = NewResponse("snapshot");
			val.Write(socialGroup?.Leader ?? 0);
			val.Write(socialGroup?.Members.Count ?? 0);
			if (socialGroup != null)
			{
				foreach (KeyValuePair<long, string> member in socialGroup.Members)
				{
					val.Write(member.Key);
					val.Write(member.Value);
					GroupMapSharing.WritePosition(val, member.Key);
				}
			}
			SocializePlugin.Settings.WriteState(val);
			ZRoutedRpc.instance.InvokeRoutedRPC(peer, "Landoria_Social_GroupResponse", new object[1] { val });
		}

		private static void ReadSnapshot(ZPackage package)
		{
			awaitingInitialState = false;
			package.ReadLong();
			GroupState.LocalMembers.Clear();
			GroupMapSharing.Clear();
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				long num2 = package.ReadLong();
				string name = package.ReadString();
				GroupState.LocalMembers.Add(num2);
				GroupMapSharing.ReadPosition(package, num2, name);
			}
			SocializePlugin.Settings.ReadState(package);
			SocialChatSender.ApplyRangesToLoadedTalkers();
		}

		private static void ReadPositionUpdate(ZPackage package)
		{
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				long playerId = package.ReadLong();
				string name = package.ReadString();
				GroupMapSharing.ReadPosition(package, playerId, name);
			}
		}

		private static void ShowInvite(string inviterId, string inviterName)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_004e: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			InvitationPresentation presentation = InvitationPresentationPolicy.Build(inviterName);
			UnifiedPopup.Push((PopupBase)new YesNoPopup(presentation.Title, presentation.Message, (PopupButtonCallback)delegate
			{
				RespondToInvite(presentation.AcceptAction, inviterId);
			}, (PopupButtonCallback)delegate
			{
				RespondToInvite(presentation.RejectAction, inviterId);
			}, false, false));
			SendRequest("invite-received", inviterId);
		}

		private static void RespondToInvite(string action, string inviterId)
		{
			UnifiedPopup.Pop();
			SendRequest(action, inviterId);
		}

		private static void Broadcast(SocialGroup group, string message)
		{
			if (group == null)
			{
				return;
			}
			foreach (long key in group.Members.Keys)
			{
				SendMessage(FindPeer(key), message);
			}
		}

		private static void BroadcastMembers(IEnumerable<long> members, string message)
		{
			foreach (long member in members)
			{
				SendMessage(FindPeer(member), message);
			}
		}

		private static void BroadcastArrival(string playerName)
		{
			foreach (long item in new List<long>(GroupState.PeerPlayers.Keys))
			{
				ZNetPeer peer = ZNet.instance.GetPeer(item);
				if (peer != null && peer.IsReady())
				{
					SendArrival(item, playerName);
				}
			}
			SocializePlugin.Log.LogInfo(playerName + " arrived on the server.");
		}

		private static void SendArrival(long peer, string playerName)
		{
			if (peer == 0L)
			{
				ShowArrival(playerName);
				return;
			}
			ZPackage val = NewResponse("arrival");
			val.Write(playerName ?? "");
			ZRoutedRpc.instance.InvokeRoutedRPC(peer, "Landoria_Social_GroupResponse", new object[1] { val });
		}

		private static void ShowArrival(string playerName)
		{
			string message = Localization.instance.Localize("$text_player_arrived");
			Chat instance = Chat.instance;
			if (instance != null)
			{
				((Terminal)instance).AddString(ChatFormattingPolicy.FormatArrival(playerName, message));
			}
		}

		private static void SendMessage(long peer, string message)
		{
			if (peer == 0L)
			{
				Chat instance = Chat.instance;
				if (instance != null)
				{
					((Terminal)instance).AddString(message);
				}
			}
			else
			{
				ZPackage val = NewResponse("message");
				val.Write(message ?? "");
				ZRoutedRpc.instance.InvokeRoutedRPC(peer, "Landoria_Social_GroupResponse", new object[1] { val });
			}
		}

		private static ZPackage NewResponse(string type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(type);
			return val;
		}

		private static long FindMember(SocialGroup group, string name)
		{
			if (group == null)
			{
				return 0L;
			}
			foreach (KeyValuePair<long, string> member in group.Members)
			{
				if (string.Equals(member.Value, name, StringComparison.OrdinalIgnoreCase))
				{
					return member.Key;
				}
			}
			return 0L;
		}

		private static long FindPeerByName(string name)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return 0L;
			}
			foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
			{
				if (string.Equals(player.m_name, name, StringComparison.OrdinalIgnoreCase))
				{
					ZDOID characterID = player.m_characterID;
					return ((ZDOID)(ref characterID)).UserID;
				}
			}
			return 0L;
		}

		private static bool TryGetPlayerForPeer(long peer, out long playerId)
		{
			playerId = 0L;
			if (peer != 0L)
			{
				return GroupState.PeerPlayers.TryGetValue(peer, out playerId);
			}
			return false;
		}

		private static long FindPeer(long playerId)
		{
			foreach (KeyValuePair<long, long> peerPlayer in GroupState.PeerPlayers)
			{
				if (peerPlayer.Value == playerId && (Object)(object)ZNet.instance != (Object)null)
				{
					ZNetPeer peer = ZNet.instance.GetPeer(peerPlayer.Key);
					if (peer != null && peer.IsReady())
					{
						return peerPlayer.Key;
					}
				}
			}
			return 0L;
		}

		private static string GetPlayerName(long playerId)
		{
			SocialGroup socialGroup = GroupState.GetGroup(playerId);
			if (socialGroup != null && socialGroup.Members.TryGetValue(playerId, out var value))
			{
				return value;
			}
			foreach (KeyValuePair<long, long> peerPlayer in GroupState.PeerPlayers)
			{
				if (peerPlayer.Value == playerId)
				{
					ZNetPeer peer = ZNet.instance.GetPeer(peerPlayer.Key);
					if (peer != null)
					{
						return peer.m_playerName;
					}
				}
			}
			return playerId.ToString();
		}
	}
	internal sealed class InvitationPresentation
	{
		internal string Title;

		internal string Message;

		internal string AcceptAction;

		internal string RejectAction;
	}
	internal static class InvitationPresentationPolicy
	{
		internal static InvitationPresentation Build(string inviterName)
		{
			return new InvitationPresentation
			{
				Title = "Group invitation",
				Message = inviterName + " invited you to a group.",
				AcceptAction = "accept",
				RejectAction = "reject"
			};
		}
	}
	internal static class RpcRegistry
	{
		internal static bool RegisterIfChanged(ref ZRoutedRpc registered, Action<ZRoutedRpc> register)
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null || instance == registered)
			{
				return false;
			}
			registered = instance;
			register(instance);
			return true;
		}
	}
	[HarmonyPatch(typeof(Minimap), "Update")]
	internal static class UpdateMapPingVisibilityPatch
	{
		private static void Postfix(Minimap __instance)
		{
			HidePublicPositionTogglePatch.UpdateVisibility(__instance);
		}
	}
	[HarmonyPatch(typeof(ZNet), "SetPublicReferencePosition")]
	internal static class DisablePublicPositionPatch
	{
		private static void Prefix(ref bool pub)
		{
			pub = MapSharingPolicy.GetPublicPosition(SocializePlugin.Settings.RestrictPublicPositions, pub);
		}
	}
	[HarmonyPatch(typeof(ZNet), "GetOtherPublicPlayers")]
	internal static class ShowGroupMembersOnMapPatch
	{
		private static void Postfix(List<PlayerInfo> playerList)
		{
			GroupMapSharing.AddGroupMembers(playerList);
		}
	}
	[HarmonyPatch(typeof(Minimap), "Start")]
	internal static class HidePublicPositionTogglePatch
	{
		private static void Postfix(Minimap __instance)
		{
			UpdateVisibility(__instance);
		}

		internal static void UpdateVisibility(Minimap minimap)
		{
			UpdatePositionVisibility(minimap);
			if (!((Object)(object)minimap.m_pingImageObject == (Object)null))
			{
				GetPingButton(minimap).SetActive(MapSharingPolicy.CanSendPublicPing(SocializePlugin.Settings.RestrictPublicPings, GroupService.IsLocalPlayerInGroup()));
			}
		}

		private static void UpdatePositionVisibility(Minimap minimap)
		{
			Toggle publicPosition = minimap.m_publicPosition;
			if (!((Object)(object)publicPosition == (Object)null))
			{
				bool flag = !SocializePlugin.Settings.RestrictPublicPositions;
				if (!flag)
				{
					publicPosition.isOn = false;
				}
				((Component)publicPosition).gameObject.SetActive(flag);
				SetDedicatedContainerVisibility(minimap, publicPosition, flag);
			}
		}

		private static GameObject GetPingButton(Minimap minimap)
		{
			Button componentInParent = ((Component)minimap.m_pingImageObject).GetComponentInParent<Button>(true);
			if ((Object)(object)componentInParent != (Object)null && !IsMapRoot(minimap, ((Component)componentInParent).gameObject))
			{
				return ((Component)componentInParent).gameObject;
			}
			Transform parent = ((Component)minimap.m_pingImageObject).transform.parent;
			if ((Object)(object)parent != (Object)null && !IsMapRoot(minimap, ((Component)parent).gameObject) && ((Component)parent).GetComponentsInChildren<RawImage>(true).Length == 0)
			{
				return ((Component)parent).gameObject;
			}
			return ((Component)minimap.m_pingImageObject).gameObject;
		}

		private static void SetDedicatedContainerVisibility(Minimap minimap, Toggle toggle, bool visible)
		{
			Transform parent = ((Component)toggle).transform.parent;
			if (!((Object)(object)parent == (Object)null) && !IsMapRoot(minimap, ((Component)parent).gameObject))
			{
				bool num = ((Component)parent).GetComponentsInChildren<Toggle>(true).Length == 1;
				bool flag = ((Component)parent).GetComponentsInChildren<RawImage>(true).Length != 0;
				if (num && !flag)
				{
					((Component)parent).gameObject.SetActive(visible);
				}
			}
		}

		private static bool IsMapRoot(Minimap minimap, GameObject target)
		{
			if (!((Object)(object)target == (Object)(object)minimap.m_largeRoot) && !((Object)(object)target == (Object)(object)minimap.m_smallRoot) && !((Object)(object)target == (Object)(object)minimap.m_mapLarge))
			{
				return (Object)(object)target == (Object)(object)minimap.m_mapSmall;
			}
			return true;
		}
	}
	internal static class MapSharingPolicy
	{
		internal static bool CanSendPublicPing(bool restricted, bool isInGroup)
		{
			return !restricted || isInGroup;
		}

		internal static bool GetPublicPosition(bool restricted, bool requested)
		{
			if (!restricted)
			{
				return requested;
			}
			return false;
		}

		internal static bool ShouldAddGroupMember(long playerId, long localPlayerId, ISet<long> visiblePlayerIds)
		{
			if (playerId != localPlayerId)
			{
				return !visiblePlayerIds.Contains(playerId);
			}
			return false;
		}
	}
	[BepInPlugin("Landoria.Socialize", "Landoria.Socialize", "1.0.16")]
	public sealed class SocializePlugin : LandoriaPlugin
	{
		private const string PluginGuid = "Landoria.Socialize";

		private const string PluginName = "Landoria.Socialize";

		private const string PluginVersion = "1.0.16";

		internal static ModLog Log { get; private set; }

		internal static SocializeSettings Settings { get; private set; }

		private void Awake()
		{
			Log = InitializePlugin("Landoria.Socialize");
			Settings = new SocializeSettings();
			Log.LogInfo("Landoria.Socialize 1.0.16 is loaded.");
		}

		private void Update()
		{
			TextPermissionService.Update();
			GroupService.Update();
			TargetPingService.Update();
			PrivateChat.Update();
		}

		private void OnDestroy()
		{
			GroupService.Reset();
			TargetPingService.Reset();
			PrivateChat.Reset();
			TextPermissionService.Reset();
			Log?.LogInfo("Landoria.Socialize 1.0.16 is unloaded.");
			ShutdownPlugin();
			Settings = null;
			Log = null;
		}
	}
	internal sealed class SocializeSettings
	{
		private const float FixedShoutDistance = 70f;

		private const float FixedSayDistance = 15f;

		private bool serverInitialized;

		internal bool RestrictPublicPositions { get; private set; }

		internal bool RestrictPublicPings { get; private set; }

		internal float ShoutDistance { get; private set; }

		internal float SayDistance { get; private set; }

		internal SocializeSettings()
		{
			ResetState();
		}

		internal void InitializeServer(ModLog logger)
		{
			if (!serverInitialized && ServerRole.IsDedicatedServer)
			{
				serverInitialized = true;
				LogSettings(logger);
			}
		}

		private void LogSettings(ModLog logger)
		{
			logger.LogInfo("Effective map settings: restrictPublicPositions=" + $"{RestrictPublicPositions}, restrictPublicPings={RestrictPublicPings}.");
			logger.LogInfo($"Effective chat settings: shoutDistance={ShoutDistance}, " + $"sayDistance={SayDistance}.");
		}

		internal void WriteState(ZPackage package)
		{
			package.Write(RestrictPublicPositions);
			package.Write(RestrictPublicPings);
			package.Write(ShoutDistance);
			package.Write(SayDistance);
		}

		internal void ReadState(ZPackage package)
		{
			RestrictPublicPositions = package.ReadBool();
			RestrictPublicPings = package.ReadBool();
			ShoutDistance = package.ReadSingle();
			SayDistance = package.ReadSingle();
		}

		internal void ResetState()
		{
			if (!serverInitialized)
			{
				RestrictPublicPositions = true;
				RestrictPublicPings = true;
				ShoutDistance = 70f;
				SayDistance = 15f;
			}
		}
	}
	internal sealed class SocialGroup
	{
		internal const int MaximumSize = 5;

		internal int Id;

		internal long Leader;

		internal readonly Dictionary<long, string> Members = new Dictionary<long, string>();

		private readonly List<long> memberOrder = new List<long>();

		internal void AddMember(long playerId, string playerName)
		{
			if (!Members.ContainsKey(playerId))
			{
				memberOrder.Add(playerId);
			}
			Members[playerId] = playerName;
		}

		internal void RemoveMember(long playerId)
		{
			Members.Remove(playerId);
			memberOrder.Remove(playerId);
		}

		internal long GetOldestMember()
		{
			foreach (long item in memberOrder)
			{
				if (Members.ContainsKey(item))
				{
					return item;
				}
			}
			return 0L;
		}
	}
	internal static class TargetPingService
	{
		private sealed class PendingPing
		{
			internal long TargetPeer;

			internal string TargetName;

			internal string Message;

			internal Terminal Context;

			internal float SentAt;
		}

		private const string MessageRpc = "Landoria_Social_TargetPingMessage";

		private const string ReceiptRpc = "Landoria_Social_TargetPingReceipt";

		private const float ReceiptTimeoutSeconds = 15f;

		private static readonly MethodInfo AddInworldText = AccessTools.Method(typeof(Chat), "AddInworldText", (Type[])null, (Type[])null);

		private static readonly Dictionary<string, PendingPing> Pending = new Dictionary<string, PendingPing>();

		private static ZRoutedRpc registeredRpc;

		internal static void Update()
		{
			EnsureRpcs();
			List<string> list = null;
			foreach (KeyValuePair<string, PendingPing> item in Pending)
			{
				if (Time.realtimeSinceStartup - item.Value.SentAt >= 15f)
				{
					(list ?? (list = new List<string>())).Add(item.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (string item2 in list)
			{
				PendingPing pendingPing = Pending[item2];
				Pending.Remove(item2);
				SocializePlugin.Log.LogWarning("Target ping [" + item2 + "] to '" + pendingPing.TargetName + "' timed out.");
				Terminal context = pendingPing.Context;
				if (context != null)
				{
					context.AddString("Ping to " + pendingPing.TargetName + " was not confirmed.");
				}
			}
		}

		internal static void Reset()
		{
			Pending.Clear();
			registeredRpc = null;
		}

		internal static bool Send(string targetName, string message, Terminal context)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			PlayerInfo target;
			bool num = Tr