Decompiled source of Socialize v1.0.17

Landoria.Socialize.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 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.17")]
[assembly: AssemblyInformationalVersion("1.0.17")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.17.32521")]
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((object)("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((object)("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((object)$"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((object)$"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((object)$"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((object)"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((object)$"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((object)$"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((object)$"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((object)("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((object)$"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((object)$"Ignoring unknown private message receipt [{requestId}] from peer={sender}, result={val}.");
			return;
		}
		if (value.TargetPeer != sender)
		{
			SocializePlugin.Log.LogWarning((object)$"Ignoring private message receipt [{requestId}] from unexpected peer={sender}; expected={value.TargetPeer}.");
			return;
		}
		Pending.Remove(requestId);
		if (!RelationsManagerPermissionResultExtentions.IsGranted(val))
		{
			SocializePlugin.Log.LogWarning((object)$"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((object)("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((object)"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((object)$"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((object)"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((object)$"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((object)$"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((object)"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((object)$"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((object)"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((object)$"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((object)$"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((object)$"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((object)"Group ping ignored because the sender is not registered.");
			return;
		}
		SocialGroup socialGroup = GroupState.GetGroup(value);
		if (socialGroup == null)
		{
			SocializePlugin.Log.LogDebug((object)"Group ping ignored because the sender is not in a group.");
			return;
		}
		if (!TryGetAuthoritativeUser(sender, user, out var user2))
		{
			SocializePlugin.Log.LogWarning((object)$"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((object)$"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((object)$"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((object)$"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((object)$"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((object)$"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((object)$"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((object)$"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((object)$"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((object)("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((object)$"Ignoring unknown group chat receipt [{requestId}] from peer={sender}.");
			return;
		}
		if (!RelationsManagerPermissionResultExtentions.IsGranted(result))
		{
			value.Rejected++;
		}
		SocializePlugin.Log.LogInfo((object)$"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((object)("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((object)$"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((object)$"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((object)$"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((object)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((object)(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.17")]
public sealed class SocializePlugin : BaseUnityPlugin
{
	private const string PluginGuid = "Landoria.Socialize";

	private const string PluginName = "Landoria.Socialize";

	private const string PluginVersion = "1.0.17";

	private Harmony _harmony;

	internal static ManualLogSource Log { get; private set; }

	internal static SocializeSettings Settings { get; private set; }

	private void Awake()
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"AssemblyVersion: {((object)this).GetType().Assembly.GetName().Version}.");
		_harmony = new Harmony("Landoria.Socialize");
		_harmony.PatchAll();
		Settings = new SocializeSettings();
		Log.LogInfo((object)"Landoria.Socialize 1.0.17 is loaded.");
	}

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

	private void OnDestroy()
	{
		GroupService.Reset();
		TargetPingService.Reset();
		PrivateChat.Reset();
		TextPermissionService.Reset();
		ManualLogSource log = Log;
		if (log != null)
		{
			log.LogInfo((object)"Landoria.Socialize 1.0.17 is unloaded.");
		}
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		_harmony = null;
		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(ManualLogSource logger)
	{
		if (!serverInitialized && ServerRole.IsDedicatedServer)
		{
			serverInitialized = true;
			LogSettings(logger);
		}
	}

	private void LogSettings(ManualLogSource logger)
	{
		logger.LogInfo((object)("Effective map settings: restrictPublicPositions=" + $"{RestrictPublicPositions}, restrictPublicPings={RestrictPublicPings}."));
		logger.LogInfo((object)($"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 static class ServerRole
{
	public static bool IsDedicatedServer
	{
		get
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				return ZNet.instance.IsDedicated();
			}
			return false;
		}
	}
}
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((object)("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 = TryFindTarget(targetName, out target);
		bool flag = (Object)(object)Player.m_localPlayer != (Object)null && ZRoutedRpc.instance != null;
		int num2;
		if (num && (Object)(object)ZNet.instance != (Object)null)
		{
			long userID = ((ZDOID)(ref target.m_characterID)).UserID;
			ZDOID localPlayerCharacterID = ZNet.instance.LocalPlayerCharacterID;
			num2 = ((userID == ((ZDOID)(ref localPlayerCharacterID)).UserID) ? 1 : 0);
		}
		else
		{
			num2 = 0;
		}
		bool isLocalPlayer = (byte)num2 != 0;
		GroupDecision groupDecision = PrivateChatPolicy.CanSend(num && flag, isLocalPlayer, targetName);
		if (!groupDecision.Allowed)
		{
			SocializePlugin.Log.LogWarning((object)("Target ping to '" + targetName + "' rejected locally: " + groupDecision.Message));
			Terminal obj = context;
			if (obj != null)
			{
				obj.AddString(groupDecision.Message);
			}
			return false;
		}
		if (!PrivilegeResultExtentions.IsGranted(PlatformManager.DistributionPlatform.PrivilegeProvider.CheckPrivilege((Privilege)3)))
		{
			SocializePlugin.Log.LogWarning((object)("Target ping 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((object)$"Checking sender permission for target ping 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 miss