Decompiled source of TextYourFriends Il2Cpp v1.0.1

Mods/TextYourFriends_Il2cpp.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using Il2Cpp;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppNewtonsoft.Json;
using Il2CppNewtonsoft.Json.Linq;
using Il2CppScheduleOne;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Messaging;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.Networking;
using Il2CppScheduleOne.Persistence.Datas;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Phone;
using Il2CppScheduleOne.UI.Phone.Messages;
using Il2CppSteamworks;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using S1API.Internal.Abstraction;
using S1API.Saveables;
using SteamNetworkLib;
using SteamNetworkLib.Core;
using SteamNetworkLib.Events;
using SteamNetworkLib.Models;
using SteamNetworkLib.Utilities;
using TextYourFriends;
using TextYourFriends.Events;
using TextYourFriends.GameIntegration;
using TextYourFriends.Models;
using TextYourFriends.Models.Persistence;
using TextYourFriends.Models.Sync;
using TextYourFriends.Persistence;
using TextYourFriends.Services;
using TextYourFriends.UI;
using TextYourFriends.Utils;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "TextYourFriends", "1.0.0", "Bars", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TextYourFriends_Il2cpp")]
[assembly: AssemblyConfiguration("Il2cpp")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TextYourFriends_Il2cpp")]
[assembly: AssemblyTitle("TextYourFriends_Il2cpp")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TextYourFriends
{
	public class Core : MelonMod
	{
		private ISteamLobbyService? _steamLobbyService;

		private IPlayerMessagePersistenceService? _persistenceService;

		private IPlayerMessagingService? _messagingService;

		private PlayerConversationManager? _conversationManager;

		private bool _isInitialized = false;

		private MessagesApp? _messagesAppInstance;

		public static Core? Instance { get; private set; }

		public override void OnInitializeMelon()
		{
			Instance = this;
			ModConfig.Initialize();
			ModLogger.LogInitialization();
			try
			{
				HarmonyPatches.SetModInstance(this);
				ModLogger.Info("TextYourFriends mod initialized successfully");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to initialize TextYourFriends mod", exception);
			}
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			try
			{
				ModLogger.Debug($"Scene initialized: {sceneName} (index: {buildIndex})");
				if (sceneName.Contains("Main"))
				{
					ModLogger.Debug("Main game scene detected, initializing TextYourFriends services...");
					InitializeServices();
				}
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error during scene initialization", exception);
			}
		}

		public override void OnUpdate()
		{
			try
			{
				if (_isInitialized && _messagingService != null)
				{
					_messagingService.Update();
				}
				_steamLobbyService?.Update();
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error during update", exception);
			}
		}

		public override void OnApplicationQuit()
		{
			try
			{
				ModLogger.LogShutdown();
				Cleanup();
				Instance = null;
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error during shutdown", exception);
			}
		}

		private void InitializeServices()
		{
			if (_isInitialized)
			{
				return;
			}
			try
			{
				ModLogger.Debug("Initializing TextYourFriends services...");
				_steamLobbyService = new SteamLobbyService();
				if (!_steamLobbyService.Initialize())
				{
					ModLogger.Error("Failed to initialize Steam lobby service");
					return;
				}
				_persistenceService = new PlayerMessagePersistenceService();
				if (!_persistenceService.Initialize())
				{
					ModLogger.Error("Failed to initialize persistence service");
					return;
				}
				_messagingService = new PlayerMessagingService(_steamLobbyService, _persistenceService);
				if (!_messagingService.Initialize())
				{
					ModLogger.Error("Failed to initialize messaging service");
					return;
				}
				SubscribeToMessagingEvents();
				_isInitialized = true;
				ModLogger.Debug("TextYourFriends services initialized successfully");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to initialize services", exception);
			}
		}

		private void SubscribeToMessagingEvents()
		{
			if (_messagingService != null)
			{
				_messagingService.OnMessageReceived += OnMessageReceived;
				_messagingService.OnMessageSent += OnMessageSent;
				_messagingService.OnConversationUpdated += OnConversationUpdated;
			}
		}

		private void OnMessageReceived(object? sender, PlayerMessageEventArgs e)
		{
			try
			{
				ModLogger.Debug("Core.OnMessageReceived: Message received from " + e.Message.SenderName + ": " + e.Message.Content);
				if ((Object)(object)_conversationManager != (Object)null)
				{
					_conversationManager.AddReceivedMessage(e.Conversation, e.Message);
				}
				else
				{
					ModLogger.Warning("_conversationManager is null, cannot add received message to UI");
				}
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error handling received message", exception);
			}
		}

		private void OnMessageSent(object? sender, PlayerMessageEventArgs e)
		{
			//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)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_conversationManager != (Object)null)
				{
					CSteamID steamId = e.Conversation.OtherPlayer.SteamId;
					PlayerMSGConversation playerMSGConversation = _conversationManager.GetPlayerMSGConversation(steamId);
					if (playerMSGConversation != null)
					{
						playerMSGConversation.PlayerConversation = e.Conversation;
						playerMSGConversation.AddSentMessage(e.Message);
					}
					else
					{
						ModLogger.Warning("No MSGConversation found for " + e.Conversation.OtherPlayer.DisplayName + ", creating new one");
						_conversationManager.AddPlayerConversation(e.Conversation);
					}
				}
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error handling sent message", exception);
			}
		}

		private void OnConversationUpdated(object? sender, PlayerConversation e)
		{
			try
			{
				if ((Object)(object)_conversationManager != (Object)null)
				{
					_conversationManager.AddPlayerConversation(e);
				}
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error handling conversation update", exception);
			}
		}

		internal void OnMessagesAppUpdate(MessagesApp messagesApp)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_messagingService != null && (Object)(object)_conversationManager != (Object)null)
				{
					_conversationManager.UpdateConversationList(_messagingService.Conversations);
				}
				if (_messagingService == null || !_messagingService.IsMessagingAvailable || _messagingService.Conversations.Count != 0)
				{
					return;
				}
				ISteamLobbyService steamLobbyService = _steamLobbyService;
				if (steamLobbyService == null || !steamLobbyService.IsInLobby || steamLobbyService.PlayerCount <= 1)
				{
					return;
				}
				List<PlayerInfo> lobbyPlayers = steamLobbyService.GetLobbyPlayers();
				foreach (PlayerInfo item in lobbyPlayers)
				{
					if (!item.IsLocalPlayer)
					{
						_messagingService.GetOrCreateConversation(item.SteamId);
					}
				}
				if (_messagingService.Conversations.Count > 0)
				{
					UpdatePlayerConversationsUI();
				}
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error handling MessagesApp update", exception);
			}
		}

		internal void OnMessagesAppReturnButtonClicked(MessagesApp messagesApp)
		{
			try
			{
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error handling return button click", exception);
			}
		}

		internal void OnLobbyChatMessageReceived(string message, CSteamID sender)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ModLogger.Debug($"Core.OnLobbyChatMessageReceived: Entry - sender={sender.m_SteamID}, messageLength={message?.Length ?? 0}");
				if (_steamLobbyService is SteamLobbyService steamLobbyService)
				{
					ModLogger.Debug("Core.OnLobbyChatMessageReceived: Triggering SteamLobbyService.TriggerLobbyChatMessage");
					steamLobbyService.TriggerLobbyChatMessage(message);
					return;
				}
				ModLogger.Warning("Could not trigger lobby chat message - service is not SteamLobbyService type");
				ModLogger.Debug("Core.OnLobbyChatMessageReceived: Falling back to ProcessInterceptedMessage");
				if (_messagingService != null)
				{
					ProcessInterceptedMessage(message, sender);
				}
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error handling lobby chat message", exception);
			}
		}

		private void ProcessInterceptedMessage(string lobbyMessage, CSteamID sender)
		{
			//IL_0007: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ModLogger.Debug($"Core.ProcessInterceptedMessage: Entry - sender={sender.m_SteamID}, rawLength={lobbyMessage?.Length ?? 0}");
				PlayerMessage playerMessage = MessageJsonSerializer.TryParseFromLobbyMessage(lobbyMessage);
				if (playerMessage == null)
				{
					ModLogger.Warning("Could not parse intercepted message");
					ModLogger.Debug("Core.ProcessInterceptedMessage: Parse failed, raw preview: " + lobbyMessage?.Substring(0, Math.Min(100, lobbyMessage?.Length ?? 0)) + "...");
					return;
				}
				ModLogger.Debug($"Core.ProcessInterceptedMessage: Parsed - senderId={playerMessage.SenderId.m_SteamID}, recipientId={playerMessage.RecipientId.m_SteamID}, type={playerMessage.MessageType}");
				if (_steamLobbyService != null && playerMessage.SenderId == _steamLobbyService.LocalPlayerId)
				{
					ModLogger.Debug("Core.ProcessInterceptedMessage: Skipping message from self");
					return;
				}
				if (_steamLobbyService != null && playerMessage.RecipientId != _steamLobbyService.LocalPlayerId && playerMessage.RecipientId != CSteamID.Nil)
				{
					ModLogger.Debug($"Core.ProcessInterceptedMessage: Message not for us (recipient={playerMessage.RecipientId.m_SteamID}), skipping");
					return;
				}
				ModLogger.Debug("Processing intercepted message from " + playerMessage.SenderName + ": " + playerMessage.Content);
				PlayerConversation orCreateConversation = _messagingService.GetOrCreateConversation(playerMessage.SenderId);
				if (playerMessage.IsTextMessage)
				{
					orCreateConversation.AddMessage(playerMessage);
					if ((Object)(object)_conversationManager != (Object)null)
					{
						_conversationManager.AddReceivedMessage(orCreateConversation, playerMessage);
					}
					ModLogger.Debug("Core.ProcessInterceptedMessage: Successfully processed text message from " + playerMessage.SenderName);
				}
				else
				{
					ModLogger.Debug($"Core.ProcessInterceptedMessage: Message was not a text message (isText={playerMessage.IsTextMessage}), skipping UI update");
				}
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error processing intercepted message", exception);
			}
		}

		internal void OnConversationOpened(MSGConversation conversation)
		{
			try
			{
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error handling conversation opened", exception);
			}
		}

		internal void OnConversationClosed(MSGConversation conversation)
		{
			try
			{
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error handling conversation closed", exception);
			}
		}

		public IPlayerMessagingService? GetMessagingService()
		{
			return _messagingService;
		}

		public IPlayerMessagePersistenceService? GetPersistenceService()
		{
			return _persistenceService;
		}

		public bool ForceSave()
		{
			try
			{
				ModLogger.Debug("=== Force Save Triggered ===");
				bool flag = false;
				if (_messagingService is PlayerMessagingService playerMessagingService)
				{
					flag = playerMessagingService.ForceSave();
					ModLogger.Debug($"Messaging service force save result: {flag}");
				}
				if (_persistenceService != null && _persistenceService is PlayerMessagePersistenceService playerMessagePersistenceService)
				{
					playerMessagePersistenceService.SaveToDisk();
				}
				else
				{
					Saveable.RequestGameSave(false);
				}
				return flag;
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error in ForceSave", exception);
				return false;
			}
		}

		public Dictionary<string, object> GetFullStatistics()
		{
			Dictionary<string, object> dictionary = _messagingService?.GetStatistics() ?? new Dictionary<string, object>();
			if (_persistenceService != null)
			{
				Dictionary<string, object> saveStatistics = _persistenceService.GetSaveStatistics();
				foreach (KeyValuePair<string, object> item in saveStatistics)
				{
					dictionary["Persistence_" + item.Key] = item.Value;
				}
			}
			TextYourFriendsSave instance = TextYourFriendsSave.Instance;
			dictionary["SaveSystem_S1API"] = instance != null;
			dictionary["SaveSystem_HasChanges"] = _persistenceService?.HasUnsavedChanges ?? false;
			return dictionary;
		}

		private void Cleanup()
		{
			try
			{
				_conversationManager?.Cleanup();
				_messagingService?.Dispose();
				_persistenceService?.Dispose();
				_steamLobbyService?.Dispose();
				_conversationManager = null;
				_messagingService = null;
				_persistenceService = null;
				_steamLobbyService = null;
				_messagesAppInstance = null;
				_isInitialized = false;
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error during cleanup", exception);
			}
		}

		public void OnMessagesAppStarted(MessagesApp messagesApp)
		{
			try
			{
				if ((Object)(object)messagesApp == (Object)null)
				{
					ModLogger.Warning("MessagesApp is null in OnMessagesAppStarted");
					return;
				}
				_messagesAppInstance = messagesApp;
				InitializeUIService(messagesApp);
				IPlayerMessagingService? messagingService = _messagingService;
				if (messagingService != null && messagingService.Conversations?.Count > 0)
				{
					UpdatePlayerConversationsUI();
				}
				ModLogger.Debug("MessagesApp integration initialized successfully");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error in OnMessagesAppStarted", exception);
			}
		}

		private void InitializeUIService(MessagesApp messagesApp)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			try
			{
				GameObject val = new GameObject("PlayerConversationManager");
				_conversationManager = val.AddComponent<PlayerConversationManager>();
				_conversationManager.Initialize(messagesApp);
				ModLogger.Debug("Player Conversation Manager initialized successfully");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error initializing player conversation manager", exception);
			}
		}

		private void UpdatePlayerConversationsUI()
		{
			if (_messagingService == null)
			{
				ModLogger.Warning("Messaging service is null, cannot update player conversations UI");
				return;
			}
			try
			{
				PlayerConversationManager instance = PlayerConversationManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					ModLogger.Warning("PlayerConversationManager instance is null, UI not yet initialized");
					return;
				}
				IReadOnlyList<PlayerConversation> conversations = _messagingService.Conversations;
				ModLogger.Debug($"Updating UI with {conversations.Count} player conversations");
				foreach (PlayerConversation item in conversations)
				{
					ModLogger.Debug($"Adding conversation to UI: {item.OtherPlayer.DisplayName} ({item.Messages.Count} messages)");
					instance.AddPlayerConversation(item);
				}
				ModLogger.Debug($"Successfully updated UI with {conversations.Count} player conversations");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error updating player conversations UI", exception);
			}
		}

		public void CheckSaveSystemStatus()
		{
			try
			{
				ModLogger.Debug("=== TextYourFriends Save System Status (S1API) ===");
				TextYourFriendsSave instance = TextYourFriendsSave.Instance;
				ModLogger.Debug($"S1API Saveable Instance: {instance != null}");
				if (instance != null)
				{
					ModLogger.Debug($"Saved Conversations: {(instance.GetData()?.Conversations?.Count).GetValueOrDefault()}");
				}
				ModLogger.Debug($"Persistence Service Available: {_persistenceService != null}");
				ModLogger.Debug($"Messaging Service Available: {_messagingService != null}");
				if (_messagingService != null)
				{
					List<PlayerConversation> allConversations = _messagingService.GetAllConversations();
					ModLogger.Debug($"Current Conversations: {allConversations.Count}");
					foreach (PlayerConversation item in allConversations)
					{
						ModLogger.Debug($"  - {item.OtherPlayer.DisplayName}: {item.Messages.Count} messages");
					}
				}
				Dictionary<string, object> fullStatistics = GetFullStatistics();
				ModLogger.Debug("=== Full Statistics ===");
				foreach (KeyValuePair<string, object> item2 in fullStatistics)
				{
					ModLogger.Debug($"{item2.Key}: {item2.Value}");
				}
				ModLogger.Debug("=== End Save System Status ===");
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error checking save system status: " + ex.Message, ex);
			}
		}

		public static T? GetService<T>() where T : class
		{
			if (Instance == null)
			{
				return null;
			}
			if (typeof(T) == typeof(IPlayerMessagingService))
			{
				return Instance._messagingService as T;
			}
			if (typeof(T) == typeof(IPlayerMessagePersistenceService))
			{
				return Instance._persistenceService as T;
			}
			if (typeof(T) == typeof(ISteamLobbyService))
			{
				return Instance._steamLobbyService as T;
			}
			return null;
		}
	}
}
namespace TextYourFriends.Utils
{
	public static class Constants
	{
		public const string MOD_NAME = "TextYourFriends";

		public const string MOD_VERSION = "1.0.0";

		public const string MOD_AUTHOR = "Bars";

		public const string MESSAGE_PREFIX = "TYF_MSG:";

		public const string MESSAGE_TYPE_PLAYER = "player_message";

		public const string MESSAGE_TYPE_TYPING = "typing_indicator";

		public const string MESSAGE_TYPE_READ_RECEIPT = "read_receipt";

		public const string LOBBY_KEY_MOD_VERSION = "tyf_version";

		public const string MEMBER_KEY_DISPLAY_NAME = "tyf_display_name";

		public const string MEMBER_KEY_STATUS = "tyf_status";

		public const int MAX_MESSAGE_LENGTH = 500;

		public const int MAX_CONVERSATION_HISTORY = 50;

		public const int MAX_TYPING_INDICATOR_TIME_MS = 3000;

		public const string PLAYER_CONVERSATION_CATEGORY = "Players";

		public const float MESSAGE_SEND_COOLDOWN_MS = 100f;

		public const string ERROR_STEAM_NOT_INITIALIZED = "Steam is not initialized";

		public const string ERROR_NOT_IN_LOBBY = "Player is not in a lobby";

		public const string ERROR_MESSAGE_TOO_LONG = "Message exceeds maximum length";

		public const string ERROR_PLAYER_NOT_FOUND = "Target player not found in lobby";

		public const string SAVE_FILE_NAME = "TextYourFriends_SaveData.json";

		public const string SAVE_FOLDER_NAME = "TextYourFriends";

		public const int SAVE_VERSION = 1;

		public const int AUTO_SAVE_INTERVAL_SECONDS = 30;

		public const int MAX_SAVE_RETRIES = 3;

		public const bool ENABLE_AUTO_SAVE = true;

		public const bool ENABLE_BACKUP_SAVES = true;

		public const int MAX_BACKUP_COUNT = 5;

		public const string BACKUP_FILE_PREFIX = "TextYourFriends_Backup_";

		public const string TEMP_FILE_SUFFIX = ".tmp";

		public const string BACKUP_FOLDER_NAME = "Backups";
	}
	internal static class JsonUtils
	{
		public static string Serialize(object value, bool indented = false)
		{
			//IL_0008: 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)
			Formatting val = (Formatting)(indented ? 1 : 0);
			return JsonConvert.SerializeObject((Object)((value is Object) ? value : null), val);
		}
	}
	public static class MessageJsonSerializer
	{
		public static string SerializeMessage(PlayerMessage message)
		{
			//IL_004b: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			if (message == null)
			{
				throw new ArgumentNullException("message");
			}
			string text = ((message.Timestamp.Kind == DateTimeKind.Utc) ? message.Timestamp : message.Timestamp.ToUniversalTime()).ToString("O");
			JObject val = new JObject
			{
				["messageId"] = JToken.op_Implicit(message.MessageId),
				["senderId"] = JToken.op_Implicit(message.SenderId.m_SteamID.ToString()),
				["recipientId"] = JToken.op_Implicit(message.RecipientId.m_SteamID.ToString()),
				["senderName"] = JToken.op_Implicit(message.SenderName),
				["content"] = JToken.op_Implicit(message.Content),
				["timestamp"] = JToken.op_Implicit(text),
				["messageType"] = JToken.op_Implicit(message.MessageType),
				["shouldNotify"] = JToken.op_Implicit(message.ShouldNotify)
			};
			return ((Object)val).ToString();
		}

		public static PlayerMessage? DeserializeMessage(string json)
		{
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(json))
			{
				return null;
			}
			try
			{
				JObject val = JObject.Parse(json);
				if (val == null)
				{
					return null;
				}
				PlayerMessage playerMessage = new PlayerMessage();
				JToken obj = val["messageId"];
				playerMessage.MessageId = ((obj != null) ? ((Object)obj).ToString() : null) ?? Guid.NewGuid().ToString();
				JToken obj2 = val["content"];
				playerMessage.Content = ((obj2 != null) ? ((Object)obj2).ToString() : null) ?? string.Empty;
				JToken obj3 = val["senderName"];
				playerMessage.SenderName = ((obj3 != null) ? ((Object)obj3).ToString() : null) ?? "Unknown";
				JToken obj4 = val["messageType"];
				playerMessage.MessageType = ((obj4 != null) ? ((Object)obj4).ToString() : null) ?? "player_message";
				JToken obj5 = val["shouldNotify"];
				playerMessage.ShouldNotify = obj5 == null || obj5.ToObject<bool>();
				PlayerMessage playerMessage2 = playerMessage;
				JToken obj6 = val["senderId"];
				if (ulong.TryParse((obj6 != null) ? ((Object)obj6).ToString() : null, out var result))
				{
					playerMessage2.SenderId = new CSteamID(result);
				}
				JToken obj7 = val["recipientId"];
				if (ulong.TryParse((obj7 != null) ? ((Object)obj7).ToString() : null, out var result2))
				{
					playerMessage2.RecipientId = new CSteamID(result2);
				}
				JToken obj8 = val["timestamp"];
				string text = ((obj8 != null) ? ((Object)obj8).ToString() : null);
				if (DateTime.TryParse(text, null, DateTimeStyles.AdjustToUniversal, out var result3))
				{
					playerMessage2.Timestamp = result3;
				}
				else
				{
					ModLogger.Warning("Failed to parse timestamp '" + text + "' for message " + playerMessage2.MessageId + ", using current time");
					playerMessage2.Timestamp = DateTime.UtcNow;
				}
				playerMessage2.IsFromLocalPlayer = playerMessage2.SenderId == SteamUser.GetSteamID();
				ModLogger.Debug($"MessageJsonSerializer.DeserializeMessage: Success - id={playerMessage2.MessageId}, sender={playerMessage2.SenderId.m_SteamID}, recipient={playerMessage2.RecipientId.m_SteamID}, type={playerMessage2.MessageType}");
				return playerMessage2;
			}
			catch (Exception ex)
			{
				ModLogger.Error("Failed to deserialize message: " + ex.Message);
				ModLogger.Debug("MessageJsonSerializer.DeserializeMessage: Exception - " + ex.Message + ", json preview: " + json?.Substring(0, Math.Min(80, json?.Length ?? 0)) + "...");
				return null;
			}
		}

		public static string CreateLobbyMessage(PlayerMessage message)
		{
			string text = SerializeMessage(message);
			string text2 = "TYF_MSG:" + text;
			ModLogger.Debug($"MessageJsonSerializer.CreateLobbyMessage: Created lobby message, jsonLength={text?.Length ?? 0}, totalLength={text2?.Length ?? 0}, messageId={message?.MessageId}");
			return text2;
		}

		public static PlayerMessage? TryParseFromLobbyMessage(string lobbyMessage)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			ModLogger.Debug(string.Format("MessageJsonSerializer.TryParseFromLobbyMessage: Entry - length={0}, hasPrefix={1}", lobbyMessage?.Length ?? 0, lobbyMessage?.StartsWith("TYF_MSG:") ?? false));
			if (string.IsNullOrEmpty(lobbyMessage) || !lobbyMessage.StartsWith("TYF_MSG:"))
			{
				ModLogger.Debug("MessageJsonSerializer.TryParseFromLobbyMessage: Early exit - null, empty, or missing prefix");
				return null;
			}
			string json = lobbyMessage.Substring("TYF_MSG:".Length);
			PlayerMessage playerMessage = DeserializeMessage(json);
			ModLogger.Debug("MessageJsonSerializer.TryParseFromLobbyMessage: Deserialize result=" + ((playerMessage != null) ? $"id={playerMessage.MessageId}, sender={playerMessage.SenderId.m_SteamID}" : "null"));
			return playerMessage;
		}

		public static bool IsTextYourFriendsMessage(string lobbyMessage)
		{
			return !string.IsNullOrEmpty(lobbyMessage) && lobbyMessage.StartsWith("TYF_MSG:");
		}

		public static string SerializeMessages(IEnumerable<PlayerMessage> messages)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			if (messages == null)
			{
				throw new ArgumentNullException("messages");
			}
			JArray val = new JArray();
			foreach (PlayerMessage message in messages)
			{
				DateTime dateTime = ((message.Timestamp.Kind == DateTimeKind.Utc) ? message.Timestamp : message.Timestamp.ToUniversalTime());
				JObject val2 = new JObject
				{
					["messageId"] = JToken.op_Implicit(message.MessageId),
					["senderId"] = JToken.op_Implicit(message.SenderId.m_SteamID.ToString()),
					["recipientId"] = JToken.op_Implicit(message.RecipientId.m_SteamID.ToString()),
					["senderName"] = JToken.op_Implicit(message.SenderName),
					["content"] = JToken.op_Implicit(message.Content),
					["timestamp"] = JToken.op_Implicit(dateTime.ToString("O")),
					["messageType"] = JToken.op_Implicit(message.MessageType),
					["shouldNotify"] = JToken.op_Implicit(message.ShouldNotify)
				};
				val.Add((JToken)(object)val2);
			}
			return ((Object)val).ToString();
		}

		public static List<PlayerMessage> DeserializeMessages(string json)
		{
			List<PlayerMessage> list = new List<PlayerMessage>();
			if (string.IsNullOrEmpty(json))
			{
				return list;
			}
			try
			{
				JArray val = JArray.Parse(json);
				if (val == null)
				{
					return list;
				}
				for (int i = 0; i < ((JContainer)val).Count; i++)
				{
					JToken obj = val[i];
					PlayerMessage playerMessage = DeserializeMessage(((obj != null) ? ((Object)obj).ToString() : null) ?? string.Empty);
					if (playerMessage != null)
					{
						list.Add(playerMessage);
					}
				}
			}
			catch (Exception ex)
			{
				ModLogger.Error("Failed to deserialize messages: " + ex.Message);
			}
			return list;
		}
	}
	public static class ModConfig
	{
		private const string CategoryName = "TextYourFriends";

		private static MelonPreferences_Category? _category;

		private static MelonPreferences_Entry<bool>? _debugLoggingEnabled;

		public static bool DebugLoggingEnabled => _debugLoggingEnabled?.Value ?? false;

		public static void Initialize()
		{
			_category = MelonPreferences.CreateCategory("TextYourFriends");
			_debugLoggingEnabled = _category.CreateEntry<bool>("DebugLogging", false, "Debug Logging", "Enable verbose debug logging for troubleshooting", false, false, (ValueValidator)null, (string)null);
			_category.SaveToFile(false);
			ModLogger.Info($"Configuration initialized. Debug logging: {DebugLoggingEnabled}");
		}

		public static void Reload()
		{
			MelonPreferences_Category? category = _category;
			if (category != null)
			{
				category.LoadFromFile(true);
			}
		}

		public static void SetDebugLogging(bool enabled)
		{
			if (_debugLoggingEnabled != null)
			{
				_debugLoggingEnabled.Value = enabled;
				MelonPreferences_Category? category = _category;
				if (category != null)
				{
					category.SaveToFile(false);
				}
			}
		}
	}
	public static class ModLogger
	{
		public static void Info(string message)
		{
			MelonLogger.Msg(message);
		}

		public static void Warning(string message)
		{
			MelonLogger.Warning(message);
		}

		public static void Error(string message)
		{
			MelonLogger.Error(message);
		}

		public static void Error(string message, Exception exception)
		{
			MelonLogger.Error(message + ": " + exception.Message);
			MelonLogger.Error("Stack trace: " + exception.StackTrace);
		}

		public static void Debug(string message)
		{
			if (ModConfig.DebugLoggingEnabled)
			{
				MelonLogger.Msg("[DEBUG] " + message);
			}
		}

		public static void LogInitialization()
		{
			Info("Initializing TextYourFriends v1.0.0 by Bars");
		}

		public static void LogShutdown()
		{
			Info("TextYourFriends shutting down");
		}
	}
	public static class SteamAvatarLoader
	{
		public static Sprite? LoadSteamAvatar(CSteamID steamId)
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!SteamManager.Initialized)
				{
					ModLogger.Warning("Steamworks not initialized");
					return null;
				}
				int mediumFriendAvatar = SteamFriends.GetMediumFriendAvatar(steamId);
				if (mediumFriendAvatar == 0)
				{
					return null;
				}
				uint num = default(uint);
				uint num2 = default(uint);
				if (!SteamUtils.GetImageSize(mediumFriendAvatar, ref num, ref num2) || num == 0 || num2 == 0)
				{
					ModLogger.Warning($"Couldn't get avatar size for {steamId}");
					return null;
				}
				byte[] array = new byte[num * num2 * 4];
				if (!SteamUtils.GetImageRGBA(mediumFriendAvatar, Il2CppStructArray<byte>.op_Implicit(array), (int)(num * num2 * 4)))
				{
					ModLogger.Warning($"Couldn't get avatar data for {steamId}");
					return null;
				}
				Texture2D val = new Texture2D((int)num, (int)num2, (TextureFormat)4, false, false);
				val.LoadRawTextureData(Il2CppStructArray<byte>.op_Implicit(array));
				val.Apply();
				return Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f));
			}
			catch (Exception ex)
			{
				ModLogger.Error($"Error loading Steam avatar for {steamId}: {ex.Message}", ex);
				return null;
			}
		}

		public static Sprite? LoadLocalPlayerAvatar()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (!SteamManager.Initialized)
			{
				ModLogger.Warning("Steamworks not initialized");
				return null;
			}
			CSteamID steamID = SteamUser.GetSteamID();
			return LoadSteamAvatar(steamID);
		}

		public static bool HasAvatar(CSteamID steamId)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!SteamManager.Initialized)
				{
					return false;
				}
				int mediumFriendAvatar = SteamFriends.GetMediumFriendAvatar(steamId);
				return mediumFriendAvatar != 0;
			}
			catch
			{
				return false;
			}
		}

		public static void TestSteamAvatarLoading()
		{
			//IL_002c: 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)
			//IL_003e: 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)
			//IL_0070: 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)
			//IL_0084: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ModLogger.Debug("=== Steam Avatar Loading Test ===");
				if (!SteamManager.Initialized)
				{
					ModLogger.Warning("Steam is not initialized - cannot test avatar loading");
					return;
				}
				CSteamID steamID = SteamUser.GetSteamID();
				string personaName = SteamFriends.GetPersonaName();
				ModLogger.Debug($"Local Player: {personaName} ({steamID})");
				Sprite val = LoadSteamAvatar(steamID);
				Rect rect;
				if ((Object)(object)val != (Object)null)
				{
					string name = ((Object)val).name;
					rect = val.rect;
					object arg = ((Rect)(ref rect)).width;
					rect = val.rect;
					ModLogger.Debug($"✓ Successfully loaded local player avatar: {name} ({arg}x{((Rect)(ref rect)).height})");
				}
				else
				{
					ModLogger.Warning("✗ Failed to load local player avatar");
				}
				bool flag = HasAvatar(steamID);
				ModLogger.Debug($"Local player has avatar: {flag}");
				CSteamID steamId = default(CSteamID);
				((CSteamID)(ref steamId))..ctor(76561197960287930uL);
				Sprite val2 = LoadSteamAvatar(steamId);
				if ((Object)(object)val2 != (Object)null)
				{
					string name2 = ((Object)val2).name;
					rect = val2.rect;
					object arg2 = ((Rect)(ref rect)).width;
					rect = val2.rect;
					ModLogger.Debug($"✓ Successfully loaded Steam official avatar: {name2} ({arg2}x{((Rect)(ref rect)).height})");
				}
				else
				{
					ModLogger.Warning("✗ Failed to load Steam official avatar");
				}
				ModLogger.Debug("=== Steam Avatar Loading Test Complete ===");
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error during Steam avatar loading test: " + ex.Message, ex);
			}
		}
	}
}
namespace TextYourFriends.UI
{
	[RegisterTypeInIl2Cpp]
	public class PlayerConversationManager : MonoBehaviour
	{
		private MessagesApp _messagesApp;

		private readonly Dictionary<CSteamID, PlayerMSGConversation> _playerConversations = new Dictionary<CSteamID, PlayerMSGConversation>();

		private readonly Dictionary<CSteamID, PlayerConversation> _activeConversations = new Dictionary<CSteamID, PlayerConversation>();

		public static PlayerConversationManager? Instance { get; private set; }

		public PlayerConversationManager(IntPtr ptr)
			: base(ptr)
		{
		}

		public void Initialize(MessagesApp messagesApp)
		{
			if ((Object)(object)messagesApp == (Object)null)
			{
				ModLogger.Error("MessagesApp is null, cannot initialize PlayerConversationManager");
				return;
			}
			try
			{
				_messagesApp = messagesApp;
				Instance = this;
				ModLogger.Debug("Player Conversation Manager initialized successfully");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to initialize PlayerConversationManager", exception);
			}
		}

		[HideFromIl2Cpp]
		public void AddPlayerConversation(PlayerConversation conversation)
		{
			//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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (conversation?.OtherPlayer == null)
			{
				ModLogger.Warning("Invalid conversation or player data");
				return;
			}
			try
			{
				CSteamID steamId = conversation.OtherPlayer.SteamId;
				_activeConversations[steamId] = conversation;
				if (_playerConversations.TryGetValue(steamId, out var value))
				{
					UpdateExistingConversation(value, conversation);
					return;
				}
				PlayerMSGConversation playerMSGConversation = new PlayerMSGConversation(conversation.OtherPlayer);
				playerMSGConversation.PlayerConversation = conversation;
				_playerConversations[steamId] = playerMSGConversation;
				playerMSGConversation.EnsureUIWithPlayerInput();
				if (conversation.Messages.Count > 0)
				{
					ModLogger.Debug($"Loading {conversation.Messages.Count} existing messages for {conversation.OtherPlayer.DisplayName}");
					playerMSGConversation.LoadExistingMessages();
				}
				playerMSGConversation.OnMessageSent += OnPlayerMessageSent;
				ModLogger.Debug("Created new PlayerMSGConversation for " + conversation.OtherPlayer.DisplayName);
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error adding player conversation: " + ex.Message, ex);
			}
		}

		public void RemovePlayerConversation(CSteamID playerId)
		{
			//IL_0008: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_playerConversations.TryGetValue(playerId, out var value))
				{
					value.OnMessageSent -= OnPlayerMessageSent;
					value.Cleanup();
					if (MessagesApp.ActiveConversations.Contains((MSGConversation)(object)value))
					{
						MessagesApp.ActiveConversations.Remove((MSGConversation)(object)value);
					}
					_playerConversations.Remove(playerId);
				}
				_activeConversations.Remove(playerId);
				ModLogger.Debug($"Removed player conversation for {playerId}");
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error removing player conversation: " + ex.Message, ex);
			}
		}

		[HideFromIl2Cpp]
		private void UpdateExistingConversation(PlayerMSGConversation msgConversation, PlayerConversation conversation)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int valueOrDefault = (msgConversation.PlayerConversation?.Messages?.Count).GetValueOrDefault();
				PlayerConversation playerConversation = msgConversation.PlayerConversation;
				_activeConversations[conversation.OtherPlayer.SteamId] = conversation;
				msgConversation.PlayerConversation = conversation;
				int num = conversation.Messages?.Count ?? 0;
				if (num <= valueOrDefault)
				{
					return;
				}
				ModLogger.Debug($"Conversation for {conversation.OtherPlayer.DisplayName} has new messages ({valueOrDefault} -> {num}), adding new messages");
				HashSet<string> hashSet = new HashSet<string>();
				if (playerConversation?.Messages != null)
				{
					foreach (PlayerMessage message in playerConversation.Messages)
					{
						hashSet.Add(message.MessageId);
					}
				}
				ModLogger.Debug("Reloading all messages for " + conversation.OtherPlayer.DisplayName + " to maintain chronological order");
				msgConversation.LoadExistingMessages(clearExisting: true);
				ModLogger.Debug("Reloaded all messages in chronological order");
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error updating existing conversation: " + ex.Message, ex);
				try
				{
					ModLogger.Debug("Falling back to full message reload due to error");
					msgConversation.LoadExistingMessages();
				}
				catch (Exception ex2)
				{
					ModLogger.Error("Fallback reload also failed: " + ex2.Message, ex2);
				}
			}
		}

		[HideFromIl2Cpp]
		public void AddReceivedMessage(PlayerConversation conversation, PlayerMessage message)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if (conversation?.OtherPlayer == null || message == null)
			{
				ModLogger.Warning("AddReceivedMessage called with null conversation or message");
				return;
			}
			try
			{
				CSteamID steamId = conversation.OtherPlayer.SteamId;
				ModLogger.Debug($"PlayerConversationManager.AddReceivedMessage: Adding message from {conversation.OtherPlayer.DisplayName} (ID: {steamId})");
				if (!_playerConversations.ContainsKey(steamId))
				{
					ModLogger.Debug($"Player conversation doesn't exist for {steamId}, creating it");
					AddPlayerConversation(conversation);
				}
				if (_playerConversations.TryGetValue(steamId, out var value))
				{
					ModLogger.Debug($"Found MSGConversation for {steamId}, calling AddReceivedMessage");
					value.AddReceivedMessage(message);
					ModLogger.Debug("Successfully added received message from " + conversation.OtherPlayer.DisplayName + ": " + message.Content);
				}
				else
				{
					ModLogger.Error($"Could not find MSGConversation for player {steamId} after creation attempt");
				}
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error adding received message: " + ex.Message, ex);
			}
		}

		[HideFromIl2Cpp]
		public void UpdateConversationList(IEnumerable<PlayerConversation> conversations)
		{
			try
			{
				foreach (PlayerConversation conversation in conversations)
				{
					AddPlayerConversation(conversation);
				}
				if ((Object)(object)_messagesApp != (Object)null)
				{
					_messagesApp.RepositionEntries();
				}
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error updating conversation list: " + ex.Message, ex);
			}
		}

		[HideFromIl2Cpp]
		private void OnPlayerMessageSent(object? sender, string messageContent)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!(sender is PlayerMSGConversation playerMSGConversation) || playerMSGConversation.PlayerConversation?.OtherPlayer == null)
				{
					return;
				}
				CSteamID steamId = playerMSGConversation.PlayerConversation.OtherPlayer.SteamId;
				Core instance = Core.Instance;
				if (instance != null)
				{
					object obj = ((object)instance).GetType().GetField("_messagingService", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance);
					if (obj != null)
					{
						MethodInfo method = obj.GetType().GetMethod("SendMessage", new Type[2]
						{
							typeof(CSteamID),
							typeof(string)
						});
						if (method != null)
						{
							method.Invoke(obj, new object[2] { steamId, messageContent });
							ModLogger.Debug("Successfully sent message via messaging service");
						}
						else
						{
							ModLogger.Warning("SendMessage method not found on messaging service");
						}
					}
				}
				ModLogger.Debug("Player sent message to " + playerMSGConversation.PlayerConversation.OtherPlayer.DisplayName + ": " + messageContent);
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error handling sent message: " + ex.Message, ex);
			}
		}

		public PlayerMSGConversation? GetPlayerMSGConversation(CSteamID playerId)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			_playerConversations.TryGetValue(playerId, out var value);
			return value;
		}

		public void RefreshAllConversations()
		{
			//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_0058: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ModLogger.Debug($"Refreshing all conversations - {_activeConversations.Count} active conversations");
				foreach (KeyValuePair<CSteamID, PlayerConversation> item in _activeConversations.ToList())
				{
					CSteamID key = item.Key;
					PlayerConversation value = item.Value;
					if (_playerConversations.TryGetValue(key, out var value2))
					{
						ModLogger.Debug($"Refreshing conversation with {value.OtherPlayer.DisplayName} ({value.Messages.Count} messages)");
						value2.PlayerConversation = value;
						if (value.Messages.Count > 0)
						{
							value2.LoadExistingMessages();
						}
					}
					else
					{
						ModLogger.Warning("No MSGConversation found for " + value.OtherPlayer.DisplayName + ", recreating");
						AddPlayerConversation(value);
					}
				}
				ModLogger.Debug("Conversation refresh completed");
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error refreshing conversations: " + ex.Message, ex);
			}
		}

		public void Cleanup()
		{
			try
			{
				foreach (KeyValuePair<CSteamID, PlayerMSGConversation> playerConversation in _playerConversations)
				{
					PlayerMSGConversation value = playerConversation.Value;
					value.OnMessageSent -= OnPlayerMessageSent;
					value.Cleanup();
					if (MessagesApp.ActiveConversations.Contains((MSGConversation)(object)value))
					{
						MessagesApp.ActiveConversations.Remove((MSGConversation)(object)value);
					}
				}
				_playerConversations.Clear();
				_activeConversations.Clear();
				Instance = null;
				ModLogger.Debug("PlayerConversationManager cleaned up successfully");
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error during cleanup: " + ex.Message, ex);
			}
		}

		private void OnDestroy()
		{
			Cleanup();
		}
	}
}
namespace TextYourFriends.Services
{
	public interface IPlayerMessagePersistenceService : IDisposable
	{
		bool IsInitialized { get; }

		bool HasUnsavedChanges { get; }

		event EventHandler<TextYourFriendsSaveData>? OnDataLoaded;

		event EventHandler<bool>? OnDataSaved;

		event EventHandler? OnDataChanged;

		bool Initialize();

		void SaveConversation(PlayerConversation conversation);

		void SaveConversations(IEnumerable<PlayerConversation> conversations);

		List<PlayerConversation> LoadConversations(IPlayerMessagingService messagingService);

		bool SaveToDisk();

		bool LoadData();

		void ClearAllData();

		void CleanupInvalidConversations();

		Dictionary<string, object> GetSaveStatistics();

		TextYourFriendsSaveData GetCurrentSaveData();

		void LoadFromExternalData(TextYourFriendsSaveData externalData);

		void LoadSaveData(TextYourFriendsSaveData saveData);

		void MarkAsSaved();
	}
	public interface IPlayerMessagingService : IDisposable
	{
		bool IsInitialized { get; }

		bool IsMessagingAvailable { get; }

		IReadOnlyList<PlayerConversation> Conversations { get; }

		int UnreadConversationCount { get; }

		int TotalUnreadMessageCount { get; }

		event EventHandler<PlayerMessageEventArgs>? OnMessageReceived;

		event EventHandler<PlayerMessageEventArgs>? OnMessageSent;

		event EventHandler<MessageReadEventArgs>? OnMessageRead;

		event EventHandler<PlayerConversation>? OnConversationUpdated;

		bool Initialize();

		bool SendMessage(CSteamID recipientId, string content);

		void MarkMessageAsRead(string messageId, CSteamID senderId);

		PlayerConversation? GetConversation(CSteamID playerId);

		PlayerConversation GetOrCreateConversation(CSteamID playerId);

		void MarkConversationAsRead(CSteamID playerId);

		List<PlayerConversation> GetConversationsWithUnreadMessages();

		(bool IsValid, string ErrorMessage) ValidateMessage(string content, CSteamID recipientId);

		void Update();

		void ClearAllConversations();

		Dictionary<string, object> GetStatistics();

		List<PlayerConversation> GetAllConversations();

		void AddLoadedConversation(PlayerConversation conversation);
	}
	public interface ISteamLobbyService : IDisposable
	{
		SteamNetworkClient NetworkClient { get; }

		bool IsInitialized { get; }

		bool IsInLobby { get; }

		bool IsHost { get; }

		CSteamID LocalPlayerId { get; }

		int PlayerCount { get; }

		event EventHandler<PlayerJoinedEventArgs>? OnPlayerJoined;

		event EventHandler<PlayerLeftEventArgs>? OnPlayerLeft;

		event EventHandler<LobbyStateChangedEventArgs>? OnLobbyStateChanged;

		event EventHandler<string>? OnLobbyChatMessage;

		bool Initialize();

		List<PlayerInfo> GetLobbyPlayers();

		PlayerInfo? GetPlayer(CSteamID steamId);

		bool SendLobbyMessage(string message);

		void SetModLobbyData(string key, string value);

		string? GetModLobbyData(string key);

		void Update();

		bool IsSteamInitialized();

		void TriggerLobbyChatMessage(string message);
	}
	internal sealed class PlayerConversationAvatarService
	{
		private readonly PlayerInfo _playerInfo;

		public PlayerConversationAvatarService(PlayerInfo playerInfo)
		{
			_playerInfo = playerInfo;
		}

		public Sprite ResolvePlayerMugshot()
		{
			//IL_0017: 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_0027: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CSteamID? val = _playerInfo?.SteamId;
				CSteamID nil = CSteamID.Nil;
				if (!val.HasValue || val.GetValueOrDefault() != nil)
				{
					Sprite val2 = SteamAvatarLoader.LoadSteamAvatar(_playerInfo.SteamId);
					if ((Object)(object)val2 != (Object)null)
					{
						return val2;
					}
				}
				return ResolveFallbackSprite();
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error loading player mugshot: " + ex.Message, ex);
				return ResolveFallbackSprite();
			}
		}

		public Sprite ResolveForSenderFallback()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			Sprite val = ResolvePlayerMugshot();
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			Texture2D val2 = new Texture2D(64, 64);
			Color32[] array = (Color32[])(object)new Color32[4096];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new Color32((byte)128, (byte)128, (byte)128, byte.MaxValue);
			}
			val2.SetPixels32(Il2CppStructArray<Color32>.op_Implicit(array));
			val2.Apply();
			return Sprite.Create(val2, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
		}

		private static Sprite ResolveFallbackSprite()
		{
			MessagesApp instance = PlayerSingleton<MessagesApp>.Instance;
			Sprite val = ((instance != null) ? instance.BlankAvatarSprite : null);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			return Resources.Load<Sprite>("UI/BlankAvatar");
		}
	}
	internal sealed class PlayerConversationMessageService
	{
		private readonly int _maxMessageHistory;

		public PlayerConversationMessageService(int maxMessageHistory)
		{
			_maxMessageHistory = maxMessageHistory;
		}

		public bool CanSend(string value, int maxMessageLength)
		{
			return !string.IsNullOrWhiteSpace(value) && value.Length <= maxMessageLength;
		}

		public string? NormalizeOutgoingText(string rawText)
		{
			if (string.IsNullOrWhiteSpace(rawText))
			{
				return null;
			}
			return rawText.Trim();
		}

		public bool ContainsMessage(List<Message> messageHistory, string content, ESenderType senderType)
		{
			//IL_000e: 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)
			return messageHistory.Any((Message m) => m.text == content && m.sender == senderType);
		}

		public bool ContainsMessage(List<Message> messageHistory, string content, ESenderType senderType)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < messageHistory.Count; i++)
			{
				Message val = messageHistory[i];
				if (val.text == content && val.sender == senderType)
				{
					return true;
				}
			}
			return false;
		}

		public void TrimHistory(List<Message> messageHistory)
		{
			while (messageHistory.Count > _maxMessageHistory)
			{
				messageHistory.RemoveAt(0);
			}
		}

		public void TrimHistory(List<Message> messageHistory)
		{
			while (messageHistory.Count > _maxMessageHistory)
			{
				messageHistory.RemoveAt(0);
			}
		}

		public HashSet<string> BuildRenderedSet(List<Message> messageHistory)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> hashSet = new HashSet<string>();
			foreach (Message item in messageHistory)
			{
				hashSet.Add(BuildUniqueKey(item.text, item.sender));
			}
			return hashSet;
		}

		public HashSet<string> BuildRenderedSet(List<Message> messageHistory)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> hashSet = new HashSet<string>();
			Enumerator<Message> enumerator = messageHistory.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Message current = enumerator.Current;
				hashSet.Add(BuildUniqueKey(current.text, current.sender));
			}
			return hashSet;
		}

		public string BuildUniqueKey(string content, ESenderType senderType)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return $"{content}_{senderType}";
		}
	}
	public class PlayerMessagePersistenceService : IPlayerMessagePersistenceService, IDisposable
	{
		private TextYourFriendsSaveData _currentSaveData;

		private bool _hasUnsavedChanges;

		private bool _isInitialized;

		private bool _isDisposed;

		public bool IsInitialized => _isInitialized && !_isDisposed;

		public bool HasUnsavedChanges => _hasUnsavedChanges;

		public event EventHandler<TextYourFriendsSaveData>? OnDataLoaded;

		public event EventHandler<bool>? OnDataSaved;

		public event EventHandler? OnDataChanged;

		public PlayerMessagePersistenceService()
		{
			TextYourFriendsSaveData textYourFriendsSaveData = TextYourFriendsSave.Instance?.GetData();
			_currentSaveData = ((textYourFriendsSaveData != null && textYourFriendsSaveData.IsValid()) ? textYourFriendsSaveData : TextYourFriendsSaveData.CreateDefault());
		}

		public bool Initialize()
		{
			if (_isInitialized || _isDisposed)
			{
				return _isInitialized;
			}
			try
			{
				ModLogger.Debug("Initializing PlayerMessagePersistenceService (game save integration mode)...");
				CleanupInvalidConversations();
				_isInitialized = true;
				ModLogger.Debug("PlayerMessagePersistenceService initialized successfully");
				return true;
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to initialize PlayerMessagePersistenceService", exception);
				return false;
			}
		}

		public void SaveConversation(PlayerConversation conversation)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!IsInitialized || conversation?.OtherPlayer == null)
			{
				return;
			}
			try
			{
				string playerId = conversation.OtherPlayer.SteamId.m_SteamID.ToString();
				int num = _currentSaveData.Conversations.FindIndex((PlayerConversationData c) => c.OtherPlayerId == playerId);
				PlayerConversationData playerConversationData = PlayerConversationData.FromPlayerConversation(conversation);
				if (num >= 0)
				{
					_currentSaveData.Conversations[num] = playerConversationData;
				}
				else
				{
					_currentSaveData.Conversations.Add(playerConversationData);
				}
				_hasUnsavedChanges = true;
				SyncToSaveable();
				this.OnDataChanged?.Invoke(this, EventArgs.Empty);
				ModLogger.Debug("Marked conversation with " + conversation.OtherPlayer.DisplayName + " for saving");
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error saving conversation: " + ex.Message, ex);
			}
		}

		public void SaveConversations(IEnumerable<PlayerConversation> conversations)
		{
			if (!IsInitialized || conversations == null)
			{
				return;
			}
			foreach (PlayerConversation conversation in conversations)
			{
				SaveConversation(conversation);
			}
		}

		public List<PlayerConversation> LoadConversations(IPlayerMessagingService messagingService)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			if (!IsInitialized || messagingService == null)
			{
				return new List<PlayerConversation>();
			}
			List<PlayerConversation> list = new List<PlayerConversation>();
			try
			{
				CSteamID val = default(CSteamID);
				foreach (PlayerConversationData conversation in _currentSaveData.Conversations)
				{
					if (!conversation.IsValid())
					{
						ModLogger.Warning("Invalid conversation data for player " + conversation.OtherPlayerId);
						continue;
					}
					if (!ulong.TryParse(conversation.OtherPlayerId, out var result))
					{
						ModLogger.Warning("Invalid player ID: " + conversation.OtherPlayerId);
						continue;
					}
					((CSteamID)(ref val))..ctor(result);
					if (val == SteamUser.GetSteamID())
					{
						ModLogger.Warning("Skipping invalid conversation with local player: " + conversation.OtherPlayerName);
						continue;
					}
					PlayerInfo otherPlayer = new PlayerInfo(val, conversation.OtherPlayerName);
					PlayerConversation playerConversation = conversation.ToPlayerConversation(otherPlayer);
					list.Add(playerConversation);
					ModLogger.Debug($"Loaded conversation with {playerConversation.OtherPlayer.DisplayName} ({playerConversation.Messages.Count} messages)");
				}
				ModLogger.Debug($"Loaded {list.Count} conversations from save data");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error loading conversations", exception);
			}
			return list;
		}

		public bool SaveToDisk()
		{
			//IL_0050: 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)
			if (!IsInitialized)
			{
				return false;
			}
			try
			{
				ModLogger.Debug("Marking TextYourFriends data for save (handled by game save system)...");
				_currentSaveData.LastSaved = DateTime.UtcNow.ToString("O");
				if (SteamAPI.IsSteamRunning())
				{
					_currentSaveData.LocalPlayerId = SteamUser.GetSteamID().m_SteamID.ToString();
				}
				TextYourFriendsSave.Instance?.SetData(_currentSaveData);
				Saveable.RequestGameSave(false);
				_hasUnsavedChanges = false;
				this.OnDataSaved?.Invoke(this, e: true);
				return true;
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to mark TextYourFriends data for save", exception);
				this.OnDataSaved?.Invoke(this, e: false);
				return false;
			}
		}

		public bool LoadData()
		{
			try
			{
				ModLogger.Debug("LoadData called - using default data (loading handled by game save system)");
				if (_currentSaveData == null || !_currentSaveData.IsValid())
				{
					_currentSaveData = TextYourFriendsSaveData.CreateDefault();
				}
				_hasUnsavedChanges = false;
				this.OnDataLoaded?.Invoke(this, _currentSaveData);
				return true;
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to initialize default data", exception);
				_currentSaveData = TextYourFriendsSaveData.CreateDefault();
				this.OnDataLoaded?.Invoke(this, _currentSaveData);
				return false;
			}
		}

		public void ClearAllData()
		{
			if (!IsInitialized)
			{
				return;
			}
			try
			{
				_currentSaveData.Conversations.Clear();
				_hasUnsavedChanges = true;
				this.OnDataChanged?.Invoke(this, EventArgs.Empty);
				ModLogger.Debug("Cleared all conversation data");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error clearing conversation data", exception);
			}
		}

		public void CleanupInvalidConversations()
		{
			//IL_001c: 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)
			if (!IsInitialized)
			{
				return;
			}
			try
			{
				string localPlayerId = SteamUser.GetSteamID().m_SteamID.ToString();
				int count = _currentSaveData.Conversations.Count;
				_currentSaveData.Conversations.RemoveAll((PlayerConversationData c) => c.OtherPlayerId == localPlayerId || !c.IsValid() || string.IsNullOrEmpty(c.OtherPlayerId) || c.OtherPlayerId == "0");
				int num = count - _currentSaveData.Conversations.Count;
				if (num > 0)
				{
					_hasUnsavedChanges = true;
					ModLogger.Debug($"Cleaned up {num} invalid conversations");
				}
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error cleaning up invalid conversations", exception);
			}
		}

		private void SyncToSaveable()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				_currentSaveData.LastSaved = DateTime.UtcNow.ToString("O");
				if (SteamAPI.IsSteamRunning())
				{
					_currentSaveData.LocalPlayerId = SteamUser.GetSteamID().m_SteamID.ToString();
				}
				TextYourFriendsSave.Instance?.SetData(_currentSaveData);
			}
			catch (Exception ex)
			{
				ModLogger.Error("Failed to sync to Saveable: " + ex.Message, ex);
			}
		}

		public void MarkAsSaved()
		{
			_hasUnsavedChanges = false;
			ModLogger.Debug("Marked TextYourFriends data as saved");
		}

		public TextYourFriendsSaveData GetCurrentSaveData()
		{
			return _currentSaveData ?? TextYourFriendsSaveData.CreateDefault();
		}

		public Dictionary<string, object> GetSaveStatistics()
		{
			if (!IsInitialized)
			{
				return new Dictionary<string, object>();
			}
			return new Dictionary<string, object>
			{
				["SavedConversations"] = _currentSaveData.Conversations.Count,
				["TotalMessages"] = _currentSaveData.Conversations.Sum((PlayerConversationData c) => c.Messages.Count),
				["LastSaved"] = _currentSaveData.LastSaved,
				["HasUnsavedChanges"] = _hasUnsavedChanges,
				["SaveMode"] = "GameSaveIntegration",
				["SchemaVersion"] = _currentSaveData.SchemaVersion
			};
		}

		public void LoadFromExternalData(TextYourFriendsSaveData saveData)
		{
			try
			{
				if (saveData?.Conversations == null)
				{
					ModLogger.Warning("Cannot load from null or invalid save data");
					return;
				}
				ModLogger.Debug($"Loading {saveData.Conversations.Count} conversations from external save data");
				_currentSaveData = saveData;
				CleanupInvalidConversations();
				_hasUnsavedChanges = false;
				ModLogger.Debug($"Successfully loaded {_currentSaveData.Conversations.Count} conversations from external data");
				this.OnDataLoaded?.Invoke(this, saveData);
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to load from external save data", exception);
			}
		}

		public void LoadSaveData(TextYourFriendsSaveData saveData)
		{
			LoadFromExternalData(saveData);
		}

		public void Dispose()
		{
			if (_isDisposed)
			{
				return;
			}
			try
			{
				ModLogger.Debug("Disposing PlayerMessagePersistenceService...");
				if (_hasUnsavedChanges)
				{
					ModLogger.Debug("Marking unsaved changes for game save system before disposal...");
					this.OnDataChanged?.Invoke(this, EventArgs.Empty);
				}
				_isInitialized = false;
				_isDisposed = true;
				ModLogger.Debug("PlayerMessagePersistenceService disposed");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error disposing persistence service", exception);
			}
		}
	}
	public class PlayerMessagingService : IPlayerMessagingService, IDisposable
	{
		private readonly ISteamLobbyService _lobbyService;

		private readonly IPlayerMessagePersistenceService _persistenceService;

		private bool _isInitialized = false;

		private bool _isDisposed = false;

		private readonly Dictionary<CSteamID, PlayerConversation> _conversations = new Dictionary<CSteamID, PlayerConversation>();

		private DateTime _lastMessageSent = DateTime.MinValue;

		private int _totalMessagesSent = 0;

		private int _totalMessagesReceived = 0;

		public bool IsInitialized => _isInitialized && !_isDisposed;

		public bool IsMessagingAvailable => IsInitialized && _lobbyService.IsInLobby && _lobbyService.PlayerCount > 1;

		public IReadOnlyList<PlayerConversation> Conversations => _conversations.Values.ToList();

		public int UnreadConversationCount => _conversations.Values.Count((PlayerConversation c) => c.HasUnreadMessages);

		public int TotalUnreadMessageCount => _conversations.Values.Sum((PlayerConversation c) => c.UnreadCount);

		public event EventHandler<PlayerMessageEventArgs>? OnMessageReceived;

		public event EventHandler<PlayerMessageEventArgs>? OnMessageSent;

		public event EventHandler<MessageReadEventArgs>? OnMessageRead;

		public event EventHandler<PlayerConversation>? OnConversationUpdated;

		public PlayerMessagingService(ISteamLobbyService lobbyService, IPlayerMessagePersistenceService persistenceService)
		{
			_lobbyService = lobbyService ?? throw new ArgumentNullException("lobbyService");
			_persistenceService = persistenceService ?? throw new ArgumentNullException("persistenceService");
		}

		public bool Initialize()
		{
			if (_isInitialized || _isDisposed)
			{
				return _isInitialized;
			}
			try
			{
				if (!_lobbyService.IsInitialized && !_lobbyService.Initialize())
				{
					ModLogger.Error("Failed to initialize Steam lobby service");
					return false;
				}
				if (!_persistenceService.Initialize())
				{
					ModLogger.Error("Failed to initialize persistence service");
					return false;
				}
				_lobbyService.OnPlayerJoined += OnPlayerJoined;
				_lobbyService.OnPlayerLeft += OnPlayerLeft;
				_lobbyService.OnLobbyStateChanged += OnLobbyStateChanged;
				_lobbyService.OnLobbyChatMessage += OnLobbyChatMessage;
				_persistenceService.OnDataLoaded += OnPersistenceDataLoaded;
				_persistenceService.OnDataSaved += OnPersistenceDataSaved;
				_isInitialized = true;
				ModLogger.Debug("Player messaging service initialized successfully");
				LoadSavedConversations();
				CreateConversationsForExistingPlayers();
				return true;
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to initialize player messaging service", exception);
				return false;
			}
		}

		public bool SendMessage(CSteamID recipientId, string content)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			ModLogger.Debug($"PlayerMessagingService.SendMessage: Entry - recipientId={recipientId.m_SteamID}, contentLength={content?.Length ?? 0}");
			(bool, string) tuple = ValidateMessage(content, recipientId);
			if (!tuple.Item1)
			{
				ModLogger.Warning("Message validation failed: " + tuple.Item2);
				ModLogger.Debug("PlayerMessagingService.SendMessage: Validation failed - " + tuple.Item2);
				return false;
			}
			DateTime utcNow = DateTime.UtcNow;
			if ((utcNow - _lastMessageSent).TotalMilliseconds < 100.0)
			{
				ModLogger.Warning("Message send cooldown active");
				ModLogger.Debug($"PlayerMessagingService.SendMessage: Cooldown active, {(utcNow - _lastMessageSent).TotalMilliseconds}ms since last send");
				return false;
			}
			try
			{
				string personaName = SteamFriends.GetPersonaName();
				PlayerMessage playerMessage = new PlayerMessage(_lobbyService.LocalPlayerId, recipientId, personaName, content)
				{
					IsFromLocalPlayer = true
				};
				ModLogger.Debug($"PlayerMessagingService.SendMessage: Created PlayerMessage id={playerMessage.MessageId}, sender={personaName}, recipient={recipientId.m_SteamID}");
				string text = MessageJsonSerializer.CreateLobbyMessage(playerMessage);
				ModLogger.Debug($"PlayerMessagingService.SendMessage: Lobby message created, length={text?.Length ?? 0}, calling SendLobbyMessage");
				if (!_lobbyService.SendLobbyMessage(text))
				{
					ModLogger.Error("Failed to send lobby message - running diagnostics...");
					return false;
				}
				PlayerConversation orCreateConversation = GetOrCreateConversation(recipientId);
				orCreateConversation.AddMessage(playerMessage);
				_persistenceService.SaveConversation(orCreateConversation);
				_lastMessageSent = utcNow;
				_totalMessagesSent++;
				ModLogger.Debug($"PlayerMessagingService.SendMessage: Success - message sent, totalSent={_totalMessagesSent}");
				this.OnMessageSent?.Invoke(this, new PlayerMessageEventArgs(playerMessage, orCreateConversation, isOutgoing: true));
				this.OnConversationUpdated?.Invoke(this, orCreateConversation);
				return true;
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to send message", exception);
				return false;
			}
		}

		public void MarkMessageAsRead(string messageId, CSteamID senderId)
		{
			//IL_0030: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if (!IsMessagingAvailable || string.IsNullOrEmpty(messageId))
			{
				return;
			}
			try
			{
				PlayerConversation conversation = GetConversation(senderId);
				if (conversation == null)
				{
					return;
				}
				PlayerMessage playerMessage = conversation.Messages.FirstOrDefault((PlayerMessage m) => m.MessageId == messageId);
				if (playerMessage != null && !playerMessage.IsRead)
				{
					playerMessage.MarkAsRead();
					PlayerMessage message = PlayerMessage.CreateReadReceipt(_lobbyService.LocalPlayerId, senderId, messageId);
					string message2 = MessageJsonSerializer.CreateLobbyMessage(message);
					ModLogger.Debug($"PlayerMessagingService.MarkMessageAsRead: Sending read receipt for messageId={messageId} to sender={senderId.m_SteamID}");
					_lobbyService.SendLobbyMessage(message2);
					PlayerInfo player = _lobbyService.GetPlayer(_lobbyService.LocalPlayerId);
					if (player != null)
					{
						this.OnMessageRead?.Invoke(this, new MessageReadEventArgs(messageId, player, conversation));
					}
					this.OnConversationUpdated?.Invoke(this, conversation);
				}
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to mark message as read", exception);
			}
		}

		public PlayerConversation? GetConversation(CSteamID playerId)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			PlayerConversation value;
			return _conversations.TryGetValue(playerId, out value) ? value : null;
		}

		public PlayerConversation GetOrCreateConversation(CSteamID playerId)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0089: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			if (playerId == _lobbyService.LocalPlayerId)
			{
				ModLogger.Error($"Attempted to create conversation with local player {playerId}. This should not happen!");
				throw new InvalidOperationException("Cannot create conversation with local player");
			}
			if (_conversations.TryGetValue(playerId, out var value))
			{
				return value;
			}
			PlayerInfo playerInfo = _lobbyService.GetPlayer(playerId);
			if (playerInfo == null)
			{
				string friendPersonaName = SteamFriends.GetFriendPersonaName(playerId);
				playerInfo = new PlayerInfo(playerId, friendPersonaName);
			}
			PlayerConversation playerConversation = new PlayerConversation(playerInfo);
			_conversations[playerId] = playerConversation;
			_persistenceService.SaveConversation(playerConversation);
			this.OnConversationUpdated?.Invoke(this, playerConversation);
			return playerConversation;
		}

		public void MarkConversationAsRead(CSteamID playerId)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			PlayerConversation conversation = GetConversation(playerId);
			if (conversation == null)
			{
				return;
			}
			List<PlayerMessage> list = conversation.Messages.Where((PlayerMessage m) => !m.IsRead && !m.IsFromLocalPlayer).ToList();
			foreach (PlayerMessage item in list)
			{
				MarkMessageAsRead(item.MessageId, playerId);
			}
		}

		public List<PlayerConversation> GetConversationsWithUnreadMessages()
		{
			return _conversations.Values.Where((PlayerConversation c) => c.HasUnreadMessages).ToList();
		}

		public (bool IsValid, string ErrorMessage) ValidateMessage(string content, CSteamID recipientId)
		{
			//IL_005b: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			if (!IsMessagingAvailable)
			{
				return (false, "Player is not in a lobby");
			}
			if (string.IsNullOrWhiteSpace(content))
			{
				return (false, "Message cannot be empty");
			}
			if (content.Length > 500)
			{
				return (false, "Message exceeds maximum length");
			}
			if (recipientId == CSteamID.Nil)
			{
				return (false, "Invalid recipient");
			}
			if (recipientId == _lobbyService.LocalPlayerId)
			{
				return (false, "Cannot send message to yourself");
			}
			PlayerInfo player = _lobbyService.GetPlayer(recipientId);
			if (player == null)
			{
				return (false, "Target player not found in lobby");
			}
			return (true, string.Empty);
		}

		public void Update()
		{
			if (!IsInitialized)
			{
				return;
			}
			try
			{
				_lobbyService.Update();
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error updating messaging service", exception);
			}
		}

		public void ClearAllConversations()
		{
			_conversations.Clear();
			ModLogger.Debug("All conversations cleared");
		}

		public Dictionary<string, object> GetStatistics()
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>
			{
				["TotalMessagesSent"] = _totalMessagesSent,
				["TotalMessagesReceived"] = _totalMessagesReceived,
				["ActiveConversations"] = _conversations.Count,
				["UnreadConversations"] = UnreadConversationCount,
				["TotalUnreadMessages"] = TotalUnreadMessageCount,
				["IsInLobby"] = _lobbyService.IsInLobby,
				["PlayerCount"] = _lobbyService.PlayerCount
			};
			if (_persistenceService != null)
			{
				Dictionary<string, object> saveStatistics = _persistenceService.GetSaveStatistics();
				foreach (KeyValuePair<string, object> item in saveStatistics)
				{
					dictionary["Persistence_" + item.Key] = item.Value;
				}
			}
			return dictionary;
		}

		public List<PlayerConversation> GetAllConversations()
		{
			return _conversations.Values.ToList();
		}

		public bool ForceSave()
		{
			if (!IsInitialized || _persistenceService == null)
			{
				return false;
			}
			try
			{
				_persistenceService.SaveConversations(_conversations.Values);
				return _persistenceService.SaveToDisk();
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error forcing save", exception);
				return false;
			}
		}

		public IPlayerMessagePersistenceService? GetPersistenceService()
		{
			return _persistenceService;
		}

		private void OnPlayerJoined(object? sender, PlayerJoinedEventArgs e)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			ModLogger.Debug("Player joined lobby: " + e.Player.DisplayName);
			if (!e.Player.IsLocalPlayer)
			{
				GetOrCreateConversation(e.Player.SteamId);
			}
		}

		private void OnPlayerLeft(object? sender, PlayerLeftEventArgs e)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			ModLogger.Debug("Player left lobby: " + e.Player.DisplayName);
			PlayerConversation conversation = GetConversation(e.Player.SteamId);
			if (conversation != null)
			{
				conversation.UpdatePlayerStatus(isOnline: false);
				this.OnConversationUpdated?.Invoke(this, conversation);
			}
		}

		private void OnLobbyStateChanged(object? sender, LobbyStateChangedEventArgs e)
		{
			if (!e.IsInLobby)
			{
				ClearAllConversations();
			}
			else
			{
				CreateConversationsForExistingPlayers();
			}
		}

		private void OnLobbyChatMessage(object? sender, string lobbyMessage)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ModLogger.Debug($"PlayerMessagingService.OnLobbyChatMessage: Received lobby message, length={lobbyMessage?.Length ?? 0}, isTYF={MessageJsonSerializer.IsTextYourFriendsMessage(lobbyMessage)}");
				if (!MessageJsonSerializer.IsTextYourFriendsMessage(lobbyMessage))
				{
					ModLogger.Debug("PlayerMessagingService.OnLobbyChatMessage: Not a TextYourFriends message, ignoring");
					return;
				}
				PlayerMessage playerMessage = MessageJsonSerializer.TryParseFromLobbyMessage(lobbyMessage);
				if (playerMessage == null)
				{
					ModLogger.Warning("Failed to parse TextYourFriends message");
					ModLogger.Debug("PlayerMessagingService.OnLobbyChatMessage: Parse failed for: " + lobbyMessage?.Substring(0, Math.Min(150, lobbyMessage?.Length ?? 0)) + "...");
					return;
				}
				ModLogger.Debug($"PlayerMessagingService.OnLobbyChatMessage: Parsed message - sender={playerMessage.SenderId.m_SteamID}, recipient={playerMessage.RecipientId.m_SteamID}, type={playerMessage.MessageType}, isText={playerMessage.IsTextMessage}, isReadReceipt={playerMessage.IsReadReceipt}");
				if (playerMessage.SenderId == _lobbyService.LocalPlayerId)
				{
					ModLogger.Debug("PlayerMessagingService.OnLobbyChatMessage: Ignoring message from self");
					return;
				}
				if (playerMessage.RecipientId != _lobbyService.LocalPlayerId && playerMessage.RecipientId != CSteamID.Nil)
				{
					ModLogger.Debug($"PlayerMessagingService.OnLobbyChatMessage: Message not for us (recipient={playerMessage.RecipientId.m_SteamID}, local={_lobbyService.LocalPlayerId.m_SteamID}), ignoring");
					return;
				}
				ModLogger.Debug("Processing received message from " + playerMessage.SenderName + ": " + playerMessage.Content);
				HandleReceivedMessage(playerMessage);
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error processing lobby chat message", exception);
			}
		}

		private void CreateConversationsForExistingPlayers()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (!_lobbyService.IsInLobby)
			{
				return;
			}
			List<PlayerInfo> lobbyPlayers = _lobbyService.GetLobbyPlayers();
			ModLogger.Debug($"Creating conversations for {lobbyPlayers.Count} existing lobby players");
			foreach (PlayerInfo item in lobbyPlayers)
			{
				if (!item.IsLocalPlayer)
				{
					GetOrCreateConversation(item.SteamId);
				}
			}
			ModLogger.Debug($"Created {_conversations.Count} conversations for existing players");
		}

		private void HandleReceivedMessage(PlayerMessage message)
		{
			//IL_0007: 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)
			ModLogger.Debug($"PlayerMessagingService.HandleReceivedMessage: Entry - sender={message.SenderId.m_SteamID}, isText={message.IsTextMessage}, isReadReceipt={message.IsReadReceipt}");
			PlayerConversation orCreateConversation = GetOrCreateConversation(message.SenderId);
			if (message.IsTextMessage)
			{
				orCreateConversation.AddMessage(message);
				_totalMessagesReceived++;
				ModLogger.Debug($"PlayerMessagingService.HandleReceivedMessage: Added text message, totalReceived={_totalMessagesReceived}, conversationMessages={orCreateConversation.Messages.Count}");
				_persistenceService.SaveConversation(orCreateConversation);
				this.OnMessageReceived?.Invoke(this, new PlayerMessageEventArgs(message, orCreateConversation, isOutgoing: false));
				this.OnConversationUpdated?.Invoke(this, orCreateConversation);
			}
			else if (message.IsReadReceipt)
			{
				string messageId = message.Content;
				ModLogger.Debug("PlayerMessagingService.HandleReceivedMessage: Processing read receipt for messageId=" + messageId);
				PlayerMessage playerMessage = orCreateConversation.Messages.FirstOrDefault((PlayerMessage m) => m.MessageId == messageId);
				if (playerMessage != null && !playerMessage.IsRead)
				{
					playerMessage.MarkAsRead();
					ModLogger.Debug("PlayerMessagingService.HandleReceivedMessage: Marked message " + messageId + " as read");
					this.OnMessageRead?.Invoke(this, new MessageReadEventArgs(messageId, orCreateConversation.OtherPlayer, orCreateConversation));
				}
				else
				{
					ModLogger.Debug("PlayerMessagingService.HandleReceivedMessage: Read receipt - message not found or already read (messageId=" + messageId + ")");
				}
			}
		}

		private void LoadSavedConversations()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<PlayerConversation> list = _persistenceService.LoadConversations(this);
				foreach (PlayerConversation item in list)
				{
					if (item?.OtherPlayer != null)
					{
						_conversations[item.OtherPlayer.SteamId] = item;
					}
				}
				ModLogger.Debug($"Loaded {list.Count} saved conversations");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error loading saved conversations", exception);
			}
		}

		private void OnPersistenceDataLoaded(object? sender, TextYourFriendsSaveData saveData)
		{
			ModLogger.Debug($"Persistence data loaded - {saveData.Conversations.Count} conversations");
		}

		private void OnPersistenceDataSaved(object? sender, bool success)
		{
			if (!success)
			{
				ModLogger.Warning("Failed to save persistence data");
			}
		}

		public void AddLoadedConversation(PlayerConversation conversation)
		{
			//IL_002c: 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)
			//IL_0032: 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_0091: 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)
			try
			{
				if (conversation?.OtherPlayer == null)
				{
					ModLogger.Warning("Cannot add null or invalid conversation");
					return;
				}
				CSteamID steamId = conversation.OtherPlayer.SteamId;
				if (steamId == _lobbyService.LocalPlayerId)
				{
					ModLogger.Warning($"Skipping conversation with local player {steamId}");
					return;
				}
				ModLogger.Debug($"Adding loaded conversation with {conversation.OtherPlayer.DisplayName} ({conversation.Messages.Count} messages)");
				_conversations[steamId] = conversation;
				this.OnConversationUpdated?.Invoke(this, conversation);
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error adding loaded conversation", exception);
			}
		}

		public void Dispose()
		{
			if (_isDisposed)
			{
				return;
			}
			try
			{
				if (_lobbyService != null)
				{
					_lobbyService.OnPlayerJoined -= OnPlayerJoined;
					_lobbyService.OnPlayerLeft -= OnPlayerLeft;
					_lobbyService.OnLobbyStateChanged -= OnLobbyStateChanged;
					_lobbyService.OnLobbyChatMessage -= OnLobbyChatMessage;
				}
				if (_persistenceService != null)
				{
					_persistenceService.OnDataLoaded -= OnPersistenceDataLoaded;
					_persistenceService.OnDataSaved -= OnPersistenceDataSaved;
					_persistenceService.SaveConversations(_conversations.Values);
					_persistenceService.Dispose();
				}
				_conversations.Clear();
				_isInitialized = false;
				_isDisposed = true;
				ModLogger.Debug("Player messaging service disposed");
			}
			catch (Exception exception)
			{
				ModLogger.Error("Error disposing messaging service", exception);
			}
		}
	}
	public class SaveSynchronizationService : IDisposable
	{
		private class SaveRequestInfo
		{
			public string RequestId { get; set; } = string.Empty;


			public DateTime RequestTime { get; set; }

			public List<CSteamID> TargetPlayers { get; set; } = new List<CSteamID>();


			public List<CSteamID> ResponsesReceived { get; set; } = new List<CSteamID>();


			public int TimeoutSeconds { get; set; } = 30;


			public Action<Dictionary<string, TextYourFriendsSaveData>>? OnCompleted { get; set; }
		}

		private readonly ISteamLobbyService _lobbyService;

		private readonly IPlayerMessagingService _messagingService;

		private readonly IPlayerMessagePersistenceService _persistenceService;

		private SteamNetworkClient _networkClient;

		private bool _isInitialized = false;

		private bool _isDisposed = false;

		private TextYourFriendsGameData? _multiplayerSaveData;

		private readonly Dictionary<string, SaveRequestInfo> _pendingSaveRequests = new Dictionary<string, SaveRequestInfo>();

		private readonly Dictionary<string, Dictionary<string, TextYourFriendsSaveData>> _collectedSaveData = new Dictionary<string, Dictionary<string, TextYourFriendsSaveData>>();

		public bool IsInitialized => _isInitialized && !_isDisposed;

		public bool IsHost => _lobbyService?.IsHost ?? false;

		public event EventHandler<SaveSyncCompletedEventArgs>? OnSaveSyncCompleted;

		public event EventHandler<LoadSyncCompletedEventArgs>? OnLoadSyncCompleted;

		public SaveSynchronizationService(ISteamLobbyService lobbyService, IPlayerMessagingService messagingService, IPlayerMessagePersistenceService persistenceService)
		{
			_lobbyService = lobbyService ?? throw new ArgumentNullException("lobbyService");
			_messagingService = messagingService ?? throw new ArgumentNullException("messagingService");
			_persistenceService = persistenceService ?? throw new ArgumentNullException("persistenceService");
			_networkClient = lobbyService.NetworkClient;
		}

		public bool Initialize()
		{
			if (_isInitialized || _isDisposed)
			{
				return _isInitialized;
			}
			try
			{
				ModLogger.Debug("Initializing SaveSynchronizationService...");
				RegisterMessageHandlers();
				_isInitialized = true;
				ModLogger.Debug("SaveSynchronizationService initialized successfully");
				return true;
			}
			catch (Exception exception)
			{
				ModLogger.Error("Failed to initialize SaveSynchronizationService", exception);
				return false;
			}
		}

		private void RegisterMessageHandlers()
		{
			_networkClient.RegisterMessageHandler<SaveSyncRequestMessage>((Action<SaveSyncRequestMessage, CSteamID>)OnSaveRequestMessageReceived);
			_networkClient.RegisterMessageHandler<SaveSyncResponseMessage>((Action<SaveSyncResponseMessage, CSteamID>)OnSaveResponseMessageReceived);
			_networkClient.RegisterMessageHandler<SaveSyncDataMessage>((Action<SaveSyncDataMessage, CSteamID>)OnSaveDataMessageReceived);
			_networkClient.RegisterMessageHandler<SaveSyncLoadDataRequestMessage>((Action<SaveSyncLoadDataRequestMessage, CSteamID>)OnLoadDataRequestMessageReceived);
			_networkClient.RegisterMessageHandler<SaveSyncLoadDataResponseMessage>((Action<SaveSyncLoadDataResponseMessage, CSteamID>)OnLoadDataResponseMessageReceived);
			ModLogger.Debug("Registered SaveSync message handlers with SteamNetworkClient");
		}

		public void ProcessMessages()
		{
		}

		public async Task<Dictionary<string, TextYourFriendsSaveData>> RequestSaveDataFromClients(int timeoutSeconds = 30)
		{
			if (!IsHost)
			{
				ModLogger.Warning("RequestSaveDataFromClients can only be called by the host");
				return new Dictionary<string, TextYourFriendsSaveData>();
			}
			if (!IsInitialized)
			{
				ModLogger.Error("SaveSynchronizationService not initialized");
				return new Dictionary<string, TextYourFriendsSaveData>();
			}
			try
			{
				ModLogger.Debug("Requesting save data from all connected clients...");
				List<PlayerInfo> lobbyPlayers = _lobbyService.GetLobbyPlayers();
				List<PlayerInfo> clientPlayers = lobbyPlayers.Where((PlayerInfo p) => p.SteamId != _lobbyService.LocalPlayerId).ToList();
				if (clientPlayers.Count == 0)
				{
					ModLogger.Debug("No clients connected, skipping save data request");
					return new Dictionary<string, TextYourFriendsSaveData>();
				}
				string requestId = Guid.NewGuid().ToString();
				SaveRequestInfo requestInfo = new SaveRequestInfo
				{
					RequestId = requestId,
					RequestTime = DateTime.UtcNow,
					TargetPlayers = clientPlayers.Select((PlayerInfo p) => p.SteamId).ToList(),
					TimeoutSeconds = timeoutSeconds
				};
				_pendingSaveRequests[requestId] = requestInfo;
				_collectedSaveData[requestId] = new Dictionary<string, TextYourFriendsSaveData>();
				SaveSyncRequestMessage requestMessage = new SaveSyncRequestMessage
				{
					RequestId = requestId,
					Operation = "SAVE",
					TimeoutSeconds = timeoutSeconds
				};
				foreach (PlayerInfo client in clientPlayers)
				{
					ModLogger.Debug($"Sending save request to {client.DisplayName} ({client.SteamId})");
					if (!(await _networkClient.SendMessageToPlayerAsync(client.SteamId, (P2PMessage)(object)requestMessage)))
					{
						ModLogger.Warning("Failed to send save request to " + client.DisplayName);
					}
				}
				DateTime startTime = DateTime.UtcNow;
				while ((DateTime.UtcNow - startTime).TotalSeconds < (double)timeoutSeconds)
				{
					SaveRequestInfo request = _pendingSaveRequests.GetValueOrDefault(requestId);
					if (request != null && request.ResponsesReceived.Count >= request.TargetPlayers.Count)
					{
						break;
					}
					await Task.Delay(100);
				}
				Dictionary<string, TextYourFriendsSaveData> results = _collectedSaveData.GetValueOrDefault(requestId) ?? new Dictionary<string, TextYourFriendsSaveData>();
				_pendingSaveRequests.Remove(requestId);
				_collectedSaveData.Remove(requestId);
				ModLogger.Debug($"Save data collection completed. Received data from {results.Count}/{clientPlayers.Count} clients");
				return results;
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error requesting save data from clients", ex);
				return new Dictionary<string, TextYourFriendsSaveData>();
			}
		}

		public void SetMultiplayerSaveData(TextYourFriendsGameData gameData)
		{
			if (!IsHost)
			{
				ModLogger.Warning("SetMultiplayerSaveData can only be called by the host");
				return;
			}
			_multiplayerSaveData = gameData;
			ModLogger.Debug($"Stored multiplayer save data for {(gameData?.AllPlayersData?.Count).GetValueOrDefault()} players");
		}

		public async Task<bool> RequestSavedDataFromHost(int timeoutSeconds = 10)
		{
			if (IsHost)
			{
				ModLogger.Warning("RequestSavedDataFromHost should only be called by clients");
				return false;
			}
			if (!IsInitialized)
			{
				ModLogger.Error("SaveSynchronizationService not initialized");
				return false;
			}
			try
			{
				string localPlayerId = _lobbyService.LocalPlayerId.m_SteamID.ToString();
				ModLogger.Debug("Client " + localPlayerId + " requesting saved data from host...");
				SaveSyncLoadDataRequestMessage requestMessage = new SaveSyncLoadDataRequestMessage
				{
					RequestingPlayerId = localPlayerId
				};
				if (_lobbyService.IsHost)
				{
					ModLogger.Error("Client tried to request data from host, but we are the host!");
					return false;
				}
				List<PlayerInfo> lobbyPlayers = _lobbyService.GetLobbyPlayers();
				List<PlayerInfo> otherPlayers = lobbyPlayers.Where((PlayerInfo p) => p.SteamId != _lobbyService.LocalPlayerId).ToList();
				if (otherPlayers.Count == 0)
				{
					ModLogger.Error("Cannot find any other players to request data from");
					return false;
				}
				CSteamID hostSteamId = otherPlayers[0].SteamId;
				ModLogger.Debug($"Sending load data request to assumed host ({hostSteamId})");
				if (!(await _networkClient.SendMessageToPlayerAsync(hostSteamId, (P2PMessage)(object)requestMessage)))
				{
					ModLogger.Error("Failed to send load data request to host");
					return false;
				}
				await Task.Delay(timeoutSeconds * 1000);
				ModLogger.Debug("Load data request sent successfully");
				return true;
			}
			catch (Exception ex)
			{
				ModLogger.Error("Error requesting saved data from host", ex);
				return false;
			}
		}

		public async Task<bool> SendConversationDataToClients(Dictionary<string, TextYourFriendsSaveData> playerData)
		{
			if (!IsHost)
			{
				ModLogger.Warning("SendConversationDataToClients can only be called by the host");
				return false;
			}
			if (!IsInitialized)
			{
				ModLogger.Error("SaveSynchronizationService not initialized");
				return false;
			}
			try
			{
				ModLogger.Debug($"Sending conversation data to {playerData.Count} clients...");
				foreach (KeyV