Decompiled source of Socialize v1.0.2

IronLabs.Socialize.dll

Decompiled 2 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 BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using IronLabs.SharedLib;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("IronLabs.Socialize")]
[assembly: AssemblyDescription("Adds persistent groups and expanded chat channels to Valheim.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("IronLabs")]
[assembly: AssemblyProduct("IronLabs.Socialize")]
[assembly: AssemblyCopyright("Copyright © 2026 End3rbyte")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("DA5DE9DF-7727-4D5F-8274-896B8EB80ED3")]
[assembly: AssemblyFileVersion("1.0.2")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.2.17987")]
namespace IronLabs.Socialize
{
	internal static class ChatChannelState
	{
		private enum Channel
		{
			Normal,
			Shout,
			Whisper,
			Group
		}

		private static Channel current;

		private static string whisperTarget = "";

		private static bool redirecting;

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

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

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

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

		internal static string GetPrompt()
		{
			return current switch
			{
				Channel.Shout => "Shouting...", 
				Channel.Whisper => "Talking to " + whisperTarget + "...", 
				Channel.Group => "Speaking to the group...", 
				_ => "Speaking...", 
			};
		}

		internal static bool TryRedirect(string text)
		{
			if (redirecting || current == Channel.Normal || string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			redirecting = true;
			try
			{
				return Send(text);
			}
			finally
			{
				redirecting = false;
			}
		}

		private static bool Send(string text)
		{
			switch (current)
			{
			case Channel.Shout:
				SocialChatSender.SendShout(text);
				return true;
			case Channel.Whisper:
				return PrivateChat.Send(whisperTarget, text, (Terminal)(object)Chat.instance);
			case Channel.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 ApplyShoutRange(Talker talker)
		{
			talker.m_shoutDistance = talker.m_normalDistance * 2f;
		}
	}
	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_0011: Unknown result type (might be due to invalid IL or missing references)
			new ConsoleCommand(name, GetDescription(name), handler, 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 (!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 (!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;
		}

		private static bool TryParseTarget(string fullLine, out string target, out string message)
		{
			target = "";
			message = "";
			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 class PrivateChat
	{
		internal static bool Send(string targetName, string message, Terminal context)
		{
			//IL_0025: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			if (!TryFindPlayer(targetName, out var player))
			{
				if (context != null)
				{
					context.AddString("No connected player named \"" + targetName + "\" was found.");
				}
				return false;
			}
			if (IsLocalPlayer(player))
			{
				if (context != null)
				{
					context.AddString("You cannot whisper yourself.");
				}
				return false;
			}
			SendToTarget(player, message);
			string name = Game.instance.GetPlayerProfile().GetName();
			ChatFormatting.AddPrivate(context, name, "to " + player.m_name + ": " + message, timestamp: false);
			return true;
		}

		private static void SendToTarget(PlayerInfo target, string message)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			UserInfo val = default(UserInfo);
			string text = default(string);
			Chat.GetChatMessageData(message, true, ref val, ref text);
			ZRoutedRpc.instance.InvokeRoutedRPC(((ZDOID)(ref target.m_characterID)).UserID, "ChatMessage", new object[4]
			{
				((Character)Player.m_localPlayer).GetHeadPoint(),
				0,
				val,
				text
			});
		}

		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;
		}
	}
	internal static class ChatFormatting
	{
		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 void AddPrivate(Terminal terminal, string user, string text, bool timestamp)
		{
			terminal.AddString(GetTimestamp(timestamp) + "<color=#2FAE5F>" + user + FormatPrivateText(text) + "</color>");
		}

		internal static void AddShout(Terminal terminal, string user, string text, bool timestamp)
		{
			terminal.AddString(GetTimestamp(timestamp) + "<color=orange>" + user + "</color>: <color=#FFFF00>" + text + "</color>");
		}

		internal static void AddPing(Terminal terminal, string user, string target, string message)
		{
			string text = (string.IsNullOrEmpty(target) ? ": " : (" to " + target + ": "));
			terminal.AddString("<color=#2FAE5F>" + user + text + "</color><color=#FFFF00>((Ping))</color><color=#2FAE5F> " + message + "</color>");
		}

		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 FormatPrivateText(string text)
		{
			if (!(text ?? "").StartsWith("to ", StringComparison.OrdinalIgnoreCase))
			{
				return ": " + text;
			}
			return " " + text;
		}

		private static string GetTimestamp(bool enabled)
		{
			if (!enabled)
			{
				return "";
			}
			return "[" + DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss") + "] ";
		}
	}
	[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(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()
		{
			if (GroupService.IsLocalPlayerInGroup())
			{
				return true;
			}
			SocializePlugin.Log.LogDebug("Map ping ignored because the local player is not in a group.");
			return false;
		}
	}
	[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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			if ((int)type == 2)
			{
				SocialChatSender.SendShout(text);
				return false;
			}
			if ((int)type == 1)
			{
				return !ChatChannelState.TryRedirect(text);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Talker), "Awake")]
	internal static class SocialShoutRangePatch
	{
		private static void Postfix(Talker __instance)
		{
			SocialChatSender.ApplyShoutRange(__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
			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;
			}
			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_0024: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_0044: 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, (ConsoleOptionsFetcher)null, false, false, false);
			new ConsoleCommand("g", "[message] sends a message to your group.", new ConsoleEvent(HandleGroupChat), 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 (!IsValid(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 bool IsValid(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;
			}
		}

		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 SocialGroup
	{
		internal int Id;

		internal long Leader;

		internal readonly Dictionary<long, string> Members = new Dictionary<long, string>();
	}
	internal static class GroupState
	{
		internal const int MaximumSize = 5;

		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 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_0035: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<long, PlayerInfo> player in Players)
			{
				if (!IsLocalPlayer(player.Key) && !Contains(players, player.Key))
				{
					players.Add(player.Value);
				}
			}
		}

		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 bool Contains(List<PlayerInfo> players, long playerId)
		{
			//IL_000b: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			foreach (PlayerInfo player in players)
			{
				ZDOID characterID = player.m_characterID;
				if (((ZDOID)(ref characterID)).UserID == playerId)
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsLocalPlayer(long playerId)
		{
			if ((Object)(object)Game.instance != (Object)null)
			{
				return Game.instance.GetPlayerProfile().GetPlayerID() == playerId;
			}
			return false;
		}
	}
	internal static class GroupRpc
	{
		internal static void RPC_Request(long sender, ZPackage package)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && GroupStorage.TryLoad())
			{
				string action = package.ReadString();
				long playerId = package.ReadLong();
				string playerName = package.ReadString();
				string argument = package.ReadString().Trim();
				GroupService.Dispatch(sender, playerId, playerName, action, argument);
			}
		}

		internal static void RPC_Response(long sender, ZPackage package)
		{
			GroupService.ReadResponse(package);
		}
	}
	internal static class GroupService
	{
		internal const string RequestRpc = "IronLabs_Social_GroupRequest";

		internal const string ResponseRpc = "IronLabs_Social_GroupResponse";

		private static ZRoutedRpc registeredRpc;

		private static float nextStateRequest;

		internal static void Update()
		{
			EnsureRpcs();
			if (!((Object)(object)ZNet.instance == (Object)null) && ZRoutedRpc.instance != null)
			{
				if (ZNet.instance.IsServer())
				{
					GroupStorage.TryLoad();
				}
				if ((Object)(object)Player.m_localPlayer != (Object)null && Time.unscaledTime >= nextStateRequest)
				{
					nextStateRequest = Time.unscaledTime + 1f;
					SendRequest("state", "");
				}
			}
		}

		internal static void Reset()
		{
			registeredRpc = null;
			nextStateRequest = 0f;
			GroupStorage.Reset();
			GroupState.ClearAll();
		}

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

		internal static void SendChat(string message)
		{
			if (!IsLocalPlayerInGroup())
			{
				Chat instance = Chat.instance;
				if (instance != null)
				{
					((Terminal)instance).AddString("You are not in a group.");
				}
			}
			else
			{
				SendRequest("chat", message);
			}
		}

		internal static void SendRequest(string action, string argument)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			EnsureRpcs();
			if (ZRoutedRpc.instance != null && !((Object)(object)Game.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				ZPackage val = new ZPackage();
				val.Write(action);
				val.Write(Game.instance.GetPlayerProfile().GetPlayerID());
				val.Write(Game.instance.GetPlayerProfile().GetName());
				val.Write(argument ?? "");
				ZRoutedRpc.instance.InvokeRoutedRPC("IronLabs_Social_GroupRequest", new object[1] { val });
			}
		}

		internal static void Dispatch(long sender, long playerId, string playerName, string action, string argument)
		{
			GroupState.PeerPlayers[sender] = playerId;
			if (action == null)
			{
				return;
			}
			switch (action.Length)
			{
			case 5:
				switch (action[0])
				{
				case 's':
					if (action == "state")
					{
						SendSnapshot(sender, playerId);
					}
					break;
				case 'l':
					if (action == "leave")
					{
						Leave(sender, playerId);
					}
					break;
				}
				break;
			case 6:
				switch (action[2])
				{
				case 'v':
					if (action == "invite")
					{
						Invite(sender, playerId, playerName, argument);
					}
					break;
				case 'c':
					if (action == "accept")
					{
						Accept(sender, playerId, playerName, argument);
					}
					break;
				case 'j':
					if (action == "reject")
					{
						Reject(sender, playerId, argument);
					}
					break;
				case 'm':
					if (action == "remove")
					{
						Remove(sender, playerId, argument);
					}
					break;
				}
				break;
			case 4:
				switch (action[0])
				{
				case 'i':
					if (action == "info")
					{
						SendInfo(sender, playerId);
					}
					break;
				case 'c':
					if (action == "chat")
					{
						SendGroupChat(sender, playerId, argument);
					}
					break;
				}
				break;
			case 7:
				if (action == "promote")
				{
					Promote(sender, playerId, argument);
				}
				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 "snapshot":
				ReadSnapshot(package);
				break;
			case "invite":
				ShowInvite(package.ReadString(), package.ReadString());
				break;
			}
		}

		private static void EnsureRpcs()
		{
			if (RpcRegistry.RegisterIfChanged(ref registeredRpc, RegisterRpcs))
			{
				GroupStorage.Reset();
				GroupState.ClearAll();
			}
		}

		private static void RegisterRpcs(ZRoutedRpc rpc)
		{
			rpc.Register<ZPackage>("IronLabs_Social_GroupRequest", (Action<long, ZPackage>)GroupRpc.RPC_Request);
			rpc.Register<ZPackage>("IronLabs_Social_GroupResponse", (Action<long, ZPackage>)GroupRpc.RPC_Response);
			GameModeGroupIntegration.Register(rpc);
		}

		private static void Invite(long sender, long inviter, string inviterName, string targetName)
		{
			long num = FindPeerByName(targetName);
			if (!TryGetPlayerForPeer(num, out var playerId))
			{
				SendMessage(sender, "Player not found or not ready.");
			}
			else if (CanInvite(sender, inviter, playerId))
			{
				GroupState.Invitations[playerId] = inviter;
				ZPackage val = NewResponse("invite");
				val.Write(inviter.ToString());
				val.Write(inviterName);
				ZRoutedRpc.instance.InvokeRoutedRPC(num, "IronLabs_Social_GroupResponse", new object[1] { val });
				SendMessage(sender, "Group invitation sent.");
			}
		}

		private static bool CanInvite(long sender, long inviter, long target)
		{
			SocialGroup socialGroup = GroupState.GetGroup(inviter);
			if (GroupState.PlayerGroups.ContainsKey(target))
			{
				SendMessage(sender, "That player is already in a group.");
				return false;
			}
			if (socialGroup != null && socialGroup.Leader != inviter)
			{
				SendMessage(sender, "Only the group leader can invite players.");
				return false;
			}
			if (socialGroup != null && socialGroup.Members.Count >= 5)
			{
				SendMessage(sender, "Your group is full.");
				return false;
			}
			return inviter != target;
		}

		private static void Accept(long sender, long playerId, string playerName, string inviterText)
		{
			if (!long.TryParse(inviterText, out var result) || !GroupState.Invitations.TryGetValue(playerId, out var value) || value != result)
			{
				SendMessage(sender, "That group invitation is no longer valid.");
				return;
			}
			SocialGroup orCreateGroup = GetOrCreateGroup(result);
			if (orCreateGroup == null || orCreateGroup.Members.Count >= 5)
			{
				SendMessage(sender, "That group is no longer available.");
				return;
			}
			orCreateGroup.Members[playerId] = playerName;
			GroupState.PlayerGroups[playerId] = orCreateGroup.Id;
			GroupState.Invitations.Remove(playerId);
			SaveAndBroadcast(orCreateGroup, 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.Members[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)
		{
			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];
			socialGroup.Members.Remove(playerId);
			GroupState.PlayerGroups.Remove(playerId);
			NormalizeAfterRemoval(socialGroup);
			GroupStorage.Save();
			SendMessage(sender, "You left the group.");
			Broadcast(socialGroup, text + " 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];
				socialGroup.Members.Remove(num);
				GroupState.PlayerGroups.Remove(num);
				NormalizeAfterRemoval(socialGroup);
				GroupStorage.Save();
				SendMessage(FindPeer(num), "You were removed from the group.");
				Broadcast(socialGroup, text + " was 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);
			if (ValidateLeaderAction(sender, actor, targetName, socialGroup, num) && ValidatePromoteTarget(sender, actor, num))
			{
				socialGroup.Leader = num;
				GroupStorage.Save();
				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)
		{
			if (group == null)
			{
				SendMessage(sender, "You are not in a group.");
				return false;
			}
			if (group.Leader != actor)
			{
				SendMessage(sender, "Only the group leader can do that.");
				return false;
			}
			if (target == 0L)
			{
				SendMessage(sender, "Player not found in your group: " + targetName);
				return false;
			}
			return true;
		}

		private static bool ValidateRemoveTarget(long sender, long actor, long target)
		{
			if (target != actor)
			{
				return true;
			}
			SendMessage(sender, "You cannot remove yourself.");
			return false;
		}

		private static bool ValidatePromoteTarget(long sender, long actor, long target)
		{
			if (target != actor)
			{
				return true;
			}
			SendMessage(sender, "You are already group leader.");
			return false;
		}

		private static void NormalizeAfterRemoval(SocialGroup group)
		{
			if (group.Members.Count <= 1)
			{
				foreach (long key in group.Members.Keys)
				{
					GroupState.PlayerGroups.Remove(key);
					SendMessage(FindPeer(key), "The group was disbanded.");
					SendSnapshot(FindPeer(key), key);
				}
				GroupState.Groups.Remove(group.Id);
				group.Members.Clear();
			}
			else
			{
				if (group.Members.ContainsKey(group.Leader))
				{
					return;
				}
				using Dictionary<long, string>.KeyCollection.Enumerator enumerator = group.Members.Keys.GetEnumerator();
				if (enumerator.MoveNext())
				{
					long current2 = enumerator.Current;
					group.Leader = current2;
				}
			}
		}

		private static void SendGroupChat(long sender, long actor, string message)
		{
			SocialGroup socialGroup = GroupState.GetGroup(actor);
			if (socialGroup == null)
			{
				SendMessage(sender, "You are not in a group.");
			}
			else if (!HasOtherOnlineMember(socialGroup, actor))
			{
				SendMessage(sender, "No other group member is connected.");
			}
			else
			{
				Broadcast(socialGroup, ChatFormatting.FormatGroup(socialGroup.Members[actor], message));
			}
		}

		private static bool HasOtherOnlineMember(SocialGroup group, long actor)
		{
			foreach (long key in group.Members.Keys)
			{
				if (key != actor && FindPeer(key) != 0L)
				{
					return true;
				}
			}
			return false;
		}

		private static void SendInfo(long sender, long playerId)
		{
			SocialGroup socialGroup = GroupState.GetGroup(playerId);
			if (socialGroup == null)
			{
				SendMessage(sender, "You are not in a group.");
				return;
			}
			List<string> list = new List<string> { "Group members:" };
			foreach (KeyValuePair<long, string> member in socialGroup.Members)
			{
				string text = ((FindPeer(member.Key) != 0L) ? "Connected" : "Disconnected");
				string text2 = ((member.Key == socialGroup.Leader) ? " - Group Leader" : "");
				list.Add(member.Value + " - " + text + text2);
			}
			SendMessage(sender, string.Join("\n", list));
		}

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

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

		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);
				}
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(peer, "IronLabs_Social_GroupResponse", new object[1] { val });
		}

		private static void ReadSnapshot(ZPackage package)
		{
			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);
			}
		}

		private static void ShowInvite(string inviterId, string inviterName)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_003b: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			UnifiedPopup.Push((PopupBase)new YesNoPopup("Group invitation", inviterName + " invited you to a group.", (PopupButtonCallback)delegate
			{
				RespondToInvite("accept", inviterId);
			}, (PopupButtonCallback)delegate
			{
				RespondToInvite("reject", inviterId);
			}, false));
		}

		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 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, "IronLabs_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)
				{
					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 static class GroupStorage
	{
		private const string PrefabName = "IronLabsSocialGroupStorage";

		private const string DataKey = "IronLabs.Social.Groups";

		private static ZDO storage;

		internal static bool TryLoad()
		{
			if (storage != null)
			{
				return true;
			}
			storage = FindOrCreate();
			if (storage == null)
			{
				return false;
			}
			Load(storage.GetString("IronLabs.Social.Groups", ""));
			return true;
		}

		internal static void Save()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			if (storage == null)
			{
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(GroupState.Groups.Count);
			foreach (SocialGroup value in GroupState.Groups.Values)
			{
				WriteGroup(val, value);
			}
			storage.Set("IronLabs.Social.Groups", Convert.ToBase64String(val.GetArray()));
			GameModeGroupIntegration.Broadcast();
		}

		internal static void Reset()
		{
			storage = null;
		}

		private static ZDO FindOrCreate()
		{
			if (ZDOMan.instance == null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return null;
			}
			List<ZDO> list = new List<ZDO>();
			int num = 0;
			while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative("IronLabsSocialGroupStorage", list, ref num))
			{
			}
			if (list.Count <= 0)
			{
				return Create();
			}
			return list[0];
		}

		private static ZDO Create()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			int stableHashCode = StringExtensionMethods.GetStableHashCode("IronLabsSocialGroupStorage");
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(1000000f, -10000f, 1000000f);
			ZDO obj = ZDOMan.instance.CreateNewZDO(val, stableHashCode);
			obj.Persistent = true;
			obj.Distant = true;
			obj.SetPrefab(stableHashCode);
			SocializePlugin.Log.LogInfo("Created persistent social group storage for the world.");
			return obj;
		}

		private static void Load(string encoded)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			GroupState.ClearServer();
			if (string.IsNullOrEmpty(encoded))
			{
				return;
			}
			try
			{
				ReadGroups(new ZPackage(Convert.FromBase64String(encoded)));
				SocializePlugin.Log.LogInfo($"Loaded {GroupState.Groups.Count} social group(s).");
			}
			catch (Exception ex)
			{
				SocializePlugin.Log.LogError("Could not load social groups: " + ex);
			}
		}

		private static void ReadGroups(ZPackage package)
		{
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				SocialGroup socialGroup = ReadGroup(package);
				GroupState.Groups[socialGroup.Id] = socialGroup;
			}
		}

		private static SocialGroup ReadGroup(ZPackage package)
		{
			SocialGroup socialGroup = new SocialGroup
			{
				Id = package.ReadInt(),
				Leader = package.ReadLong()
			};
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				long key = package.ReadLong();
				socialGroup.Members[key] = package.ReadString();
				GroupState.PlayerGroups[key] = socialGroup.Id;
			}
			return socialGroup;
		}

		private static void WriteGroup(ZPackage package, SocialGroup group)
		{
			package.Write(group.Id);
			package.Write(group.Leader);
			package.Write(group.Members.Count);
			foreach (KeyValuePair<long, string> member in group.Members)
			{
				package.Write(member.Key);
				package.Write(member.Value);
			}
		}
	}
	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.UpdatePingVisibility(__instance);
		}
	}
	[HarmonyPatch(typeof(ZNet), "SetPublicReferencePosition")]
	internal static class DisablePublicPositionPatch
	{
		private static void Prefix(ref bool pub)
		{
			pub = false;
		}
	}
	[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)
		{
			Toggle publicPosition = __instance.m_publicPosition;
			if ((Object)(object)publicPosition != (Object)null)
			{
				publicPosition.isOn = false;
				((Component)publicPosition).gameObject.SetActive(false);
				HideDedicatedContainer(__instance, publicPosition);
			}
			UpdatePingVisibility(__instance);
		}

		internal static void UpdatePingVisibility(Minimap minimap)
		{
			if (!((Object)(object)minimap.m_pingImageObject == (Object)null))
			{
				GetPingButton(minimap).SetActive(GroupService.IsLocalPlayerInGroup());
			}
		}

		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 HideDedicatedContainer(Minimap minimap, Toggle toggle)
		{
			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(false);
				}
			}
		}

		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;
		}
	}
	[BepInPlugin("IronLabs.Socialize", "IronLabs.Socialize", "1.0.2")]
	public sealed class SocializePlugin : IronLabsPlugin
	{
		private const string PluginGuid = "IronLabs.Socialize";

		private const string PluginName = "IronLabs.Socialize";

		private const string PluginVersion = "1.0.2";

		internal static ModLog Log { get; private set; }

		private void Awake()
		{
			Log = InitializePlugin("IronLabs.Socialize");
			Log.LogInfo("IronLabs.Socialize 1.0.2 is loaded.");
		}

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

		private void OnDestroy()
		{
			GroupService.Reset();
			TargetPingService.Reset();
			ShutdownPlugin();
			Log = null;
		}
	}
	internal static class GameModeGroupIntegration
	{
		private const string WardenRequestRpc = "IronLabs_WardenGameMode_RequestGroups";

		private const string WardenSyncRpc = "IronLabs_WardenGameMode_SyncGroups";

		private const string VanillaRequestRpc = "IronLabs_VanillaGameMode_RequestGroups";

		private const string VanillaSyncRpc = "IronLabs_VanillaGameMode_SyncGroups";

		private static bool wardenRequested;

		private static bool vanillaRequested;

		internal static void Register(ZRoutedRpc rpc)
		{
			wardenRequested = false;
			vanillaRequested = false;
			rpc.Register("IronLabs_WardenGameMode_RequestGroups", (Action<long>)RPC_RequestWardenGroups);
			rpc.Register("IronLabs_VanillaGameMode_RequestGroups", (Action<long>)RPC_RequestVanillaGroups);
		}

		internal static void Broadcast()
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZRoutedRpc.instance != null)
			{
				if (wardenRequested)
				{
					Send(ZRoutedRpc.Everybody, "IronLabs_WardenGameMode_SyncGroups");
				}
				if (vanillaRequested)
				{
					Send(ZRoutedRpc.Everybody, "IronLabs_VanillaGameMode_SyncGroups");
				}
			}
		}

		private static void RPC_RequestWardenGroups(long sender)
		{
			wardenRequested = true;
			SendRequestedSnapshot(sender, "IronLabs_WardenGameMode_SyncGroups");
		}

		private static void RPC_RequestVanillaGroups(long sender)
		{
			vanillaRequested = true;
			SendRequestedSnapshot(sender, "IronLabs_VanillaGameMode_SyncGroups");
		}

		private static void SendRequestedSnapshot(long sender, string syncRpc)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				GroupStorage.TryLoad();
				Send(sender, syncRpc);
			}
		}

		private static void Send(long target, string syncRpc)
		{
			//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(GroupState.PlayerGroups.Count);
			foreach (KeyValuePair<long, int> playerGroup in GroupState.PlayerGroups)
			{
				val.Write(playerGroup.Key);
				val.Write(playerGroup.Value);
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(target, syncRpc, new object[1] { val });
		}
	}
	internal static class TargetPingService
	{
		private const string RequestRpc = "IronLabs_Social_TargetPing";

		private const string MessageRpc = "IronLabs_Social_TargetPingMessage";

		private static ZRoutedRpc registeredRpc;

		internal static void Update()
		{
			RpcRegistry.RegisterIfChanged(ref registeredRpc, RegisterRpcs);
		}

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

		internal static bool Send(string targetName, string message, Terminal context)
		{
			//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_0065: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!TryFindTarget(targetName, out var target) || (Object)(object)Player.m_localPlayer == (Object)null || ZRoutedRpc.instance == null)
			{
				if (context != null)
				{
					context.AddString("No connected player named \"" + targetName + "\" was found.");
				}
				return false;
			}
			EnsureRpcs();
			Vector3 headPoint = ((Character)Player.m_localPlayer).GetHeadPoint();
			UserInfo user = default(UserInfo);
			string message2 = default(string);
			Chat.GetChatMessageData(message, true, ref user, ref message2);
			long userID = ((ZDOID)(ref target.m_characterID)).UserID;
			ZDOID localPlayerCharacterID = ZNet.instance.LocalPlayerCharacterID;
			if (userID != ((ZDOID)(ref localPlayerCharacterID)).UserID)
			{
				SendRequest(headPoint, user, ((ZDOID)(ref target.m_characterID)).UserID, message2);
			}
			ShowLocalPing(headPoint, user, target.m_name, message2, context);
			return true;
		}

		internal static void RPC_TargetPing(long sender, Vector3 position, UserInfo user, long targetPlayerId, string message)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(targetPlayerId, "ChatMessage", new object[4] { position, 3, user, message });
				ZRoutedRpc.instance.InvokeRoutedRPC(targetPlayerId, "IronLabs_Social_TargetPingMessage", new object[2] { user, message });
			}
		}

		internal static void RPC_TargetPingMessage(long sender, UserInfo user, string message)
		{
			ChatFormatting.AddPing((Terminal)(object)Chat.instance, user.GetDisplayName(), "", message);
		}

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

		private static void RegisterRpcs(ZRoutedRpc rpc)
		{
			rpc.Register<Vector3, UserInfo, long, string>("IronLabs_Social_TargetPing", (Method<Vector3, UserInfo, long, string>)RPC_TargetPing);
			rpc.Register<UserInfo, string>("IronLabs_Social_TargetPingMessage", (Action<long, UserInfo, string>)RPC_TargetPingMessage);
		}

		private static void SendRequest(Vector3 position, UserInfo user, long target, string message)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			ZRoutedRpc.instance.InvokeRoutedRPC("IronLabs_Social_TargetPing", new object[4] { position, user, target, message });
		}

		private static void ShowLocalPing(Vector3 position, UserInfo user, string targetName, string message, Terminal context)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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)
			ZDOID localPlayerCharacterID = ZNet.instance.LocalPlayerCharacterID;
			long userID = ((ZDOID)(ref localPlayerCharacterID)).UserID;
			ZRoutedRpc.instance.InvokeRoutedRPC(userID, "ChatMessage", new object[4] { position, 3, user, message });
			ChatFormatting.AddPing(context, user.GetDisplayName(), targetName, message);
		}

		private static bool TryFindTarget(string targetName, out PlayerInfo target)
		{
			//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 player in ZNet.instance.GetPlayerList())
			{
				if (string.Equals(player.m_name, targetName, StringComparison.OrdinalIgnoreCase))
				{
					target = player;
					return true;
				}
			}
			target = default(PlayerInfo);
			return false;
		}
	}
}
namespace IronLabs.SharedLib
{
	public abstract class IronLabsPlugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		private bool _patchesApplied;

		protected ModLog InitializePlugin(string pluginGuid)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			ModLog modLog = new ModLog(((BaseUnityPlugin)this).Logger);
			Version version = ((object)this).GetType().Assembly.GetName().Version;
			modLog.LogInfo($"AssemblyVersion: {version}.");
			_harmony = new Harmony(pluginGuid);
			PatchOwnNamespace(modLog);
			return modLog;
		}

		protected void PatchOwnNamespace(ModLog log)
		{
			if (_patchesApplied)
			{
				log.LogDebug("Harmony patches are already active; skipping registration.");
				return;
			}
			string text = ((object)this).GetType().Namespace;
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in types)
			{
				if (type.Namespace == text)
				{
					_harmony.CreateClassProcessor(type).Patch();
				}
			}
			_patchesApplied = true;
			log.LogDebug("Harmony patches were applied for the plugin namespace.");
		}

		protected void ShutdownPlugin()
		{
			if (_patchesApplied)
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
				_patchesApplied = false;
			}
		}
	}
	public sealed class ModLog
	{
		private readonly ManualLogSource _logger;

		public ModLog(ManualLogSource logger)
		{
			_logger = logger;
		}

		public void LogFatal(object message)
		{
			Write((LogLevel)1, message);
		}

		public void LogError(object message)
		{
			Write((LogLevel)2, message);
		}

		public void LogWarning(object message)
		{
			Write((LogLevel)4, message);
		}

		public void LogMessage(object message)
		{
			Write((LogLevel)8, message);
		}

		public void LogInfo(object message)
		{
			Write((LogLevel)16, message);
		}

		public void LogDebug(object message)
		{
			Write((LogLevel)32, message);
		}

		public void Log(LogLevel level, object message)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Write(level, message);
		}

		private void Write(LogLevel level, object message)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			string arg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
			_logger.Log(level, (object)$"[{arg}] {message}");
		}
	}
}