Decompiled source of Chat Configs v0.0.1

OutwardChatConfigs.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using OutwardChatConfigs.Events;
using OutwardChatConfigs.Handlers;
using OutwardChatConfigs.Interfaces;
using OutwardChatConfigs.Managers;
using OutwardChatConfigs.Models;
using OutwardChatConfigs.Triggers;
using OutwardChatConfigs.Utility.Enums;
using OutwardChatConfigs.Utility.Helpers;
using OutwardModsCommunicator.EventBus;
using OutwardModsCommunicator.Managers;
using SideLoader;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("OutwardChatConfigs")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OutwardChatConfigs")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("c5450fe0-edcf-483f-b9ea-4b1ef9d36da7")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace OutwardChatConfigs
{
	[BepInPlugin("gymmed.chat_configs", "Chat Configs", "0.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class OCC : BaseUnityPlugin
	{
		public const string GUID = "gymmed.chat_configs";

		public const string NAME = "Chat Configs";

		public const string VERSION = "0.0.1";

		public const string EVENTS_LISTENER_GUID = "gymmed.chat_configs_*";

		public static string prefix = "[Chat-Configs]";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		internal void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			LogMessage("Hello world from Chat Configs 0.0.1!");
			_harmony = new Harmony("gymmed.chat_configs");
			_harmony.PatchAll();
			EventBusRegister.RegisterEvents();
			EventBusSubscriber.AddSubscribers();
			RegisterInternalEvents();
			EventBusPublisher.SendCommands();
			LogMessage("OutwardChatConfigs loaded!");
		}

		public static void LogMessage(string message)
		{
			Log.LogMessage((object)(prefix + " " + message));
		}

		public static void LogStatusMessage(string message, ChatLogStatus status = ChatLogStatus.Info)
		{
			LogMessage($"[{status}] {message}");
		}

		public static void LogSL(string message)
		{
			SL.Log(prefix + " " + message);
		}

		public static string GetProjectLocation()
		{
			return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		}

		private void RegisterInternalEvents()
		{
			ScheduledEventsManager.Instance.RegisterInternalEvent("SL", "BeforePacksLoaded", delegate
			{
			}, "Before Packs Loaded");
			ScheduledEventsManager.Instance.RegisterInternalEvent("SL", "OnPacksLoaded", delegate
			{
			}, "Packs Loaded");
			ScheduledEventsManager.Instance.RegisterInternalEvent("SL", "OnSceneLoaded", delegate
			{
			}, "Scene Loaded");
			ScheduledEventsManager.Instance.RegisterInternalEvent("SL", "OnGameplayResumedAfterLoading", delegate
			{
			}, "Gameplay Resumed");
			ScheduledEventsManager.Instance.RegisterInternalEvent("SL", "OnBeforeHotReload", delegate
			{
			}, "Before Hot Reload");
			ScheduledEventsManager.Instance.RegisterInternalEvent("gymmed", "OnFirstGameReady", delegate
			{
			}, "First Game Ready");
		}
	}
}
namespace OutwardChatConfigs.Utility.Helpers
{
	public static class CharacterHelpers
	{
		public static Character TryToFindOtherCharacterInLobby(Character mainCharacter, string otherCharName)
		{
			//IL_002b: 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)
			Character val = null;
			foreach (PlayerSystem item in Global.Lobby.PlayersInLobby)
			{
				val = item.ControlledCharacter;
				if ((Object)(object)val != (Object)null && val.UID != mainCharacter.UID && string.Equals(otherCharName, val.Name))
				{
					return val;
				}
			}
			return null;
		}

		public static Character TryToFindOtherCharacterInLobby(Character mainCharacter)
		{
			//IL_002b: 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)
			Character val = null;
			foreach (PlayerSystem item in Global.Lobby.PlayersInLobby)
			{
				val = item.ControlledCharacter;
				if ((Object)(object)val != (Object)null && val.UID != mainCharacter.UID)
				{
					return val;
				}
			}
			return val;
		}

		public static bool IsCharacterInDistance(Character firstCharacter, Character secondCharacter, float minimumDistance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)firstCharacter).transform.position - ((Component)secondCharacter).transform.position;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			float num = minimumDistance * minimumDistance;
			if (sqrMagnitude > num)
			{
				return false;
			}
			return true;
		}

		public static bool HasManualMovement(Character character)
		{
			CharacterControl characterControl = character.CharacterControl;
			LocalCharacterControl val = (LocalCharacterControl)(object)((characterControl is LocalCharacterControl) ? characterControl : null);
			if (val == null)
			{
				return false;
			}
			if (((Vector2)(ref ((CharacterControl)val).m_moveInput)).sqrMagnitude > 0.01f)
			{
				return true;
			}
			return false;
		}
	}
	public static class ChatHelpers
	{
		public static void SendChatLog(ChatPanel panel, string message, ChatLogStatus status = ChatLogStatus.Info)
		{
			panel.ChatMessageReceived("System", ChatLogStatusHelper.GetChatLogText(message, status));
		}

		public static void SendChatLog(Character character, string message, ChatLogStatus status = ChatLogStatus.Info)
		{
			CharacterUI characterUI = character.CharacterUI;
			if ((Object)(object)((characterUI != null) ? characterUI.ChatPanel : null) == (Object)null)
			{
				OCC.LogMessage("ChatHelpers@SendChatLog provided character with missing chatPanel!");
			}
			else
			{
				SendChatLog(character.CharacterUI.ChatPanel, message, status);
			}
		}

		public static void SendChatOrLog(Character character, string message, ChatLogStatus status = ChatLogStatus.Info)
		{
			CharacterUI characterUI = character.CharacterUI;
			if ((Object)(object)((characterUI != null) ? characterUI.ChatPanel : null) == (Object)null)
			{
				OCC.LogStatusMessage(message, status);
			}
			else
			{
				SendChatLog(character.CharacterUI.ChatPanel, message, status);
			}
		}
	}
}
namespace OutwardChatConfigs.Utility.Enums
{
	public enum ChatCommandsManagerParams
	{
		CommandName,
		CommandParameters,
		CommandAction,
		IsCheatCommand,
		CommandDescription,
		CommandRequiresDebugMode
	}
	public static class ChatCommandsManagerParamsHelper
	{
		private static readonly Dictionary<ChatCommandsManagerParams, (string key, Type type)> _registry = new Dictionary<ChatCommandsManagerParams, (string, Type)>
		{
			[ChatCommandsManagerParams.CommandName] = ("command", typeof(string)),
			[ChatCommandsManagerParams.CommandParameters] = ("parameters", typeof(Dictionary<string, (string, string)>)),
			[ChatCommandsManagerParams.CommandAction] = ("function", typeof(Action<Character, Dictionary<string, string>>)),
			[ChatCommandsManagerParams.IsCheatCommand] = ("isCheatCommand", typeof(bool)),
			[ChatCommandsManagerParams.CommandDescription] = ("description", typeof(string)),
			[ChatCommandsManagerParams.CommandRequiresDebugMode] = ("debugMode", typeof(bool))
		};

		public static (string key, Type type) Get(ChatCommandsManagerParams param)
		{
			return _registry[param];
		}
	}
	public enum ChatLogStatus
	{
		Info,
		Success,
		Warning,
		Error
	}
	public static class ChatLogStatusHelper
	{
		public static string GetChatLogText(string message, ChatLogStatus status = ChatLogStatus.Info)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			return status switch
			{
				ChatLogStatus.Success => Global.SetTextColor(message, Global.LIGHT_GREEN), 
				ChatLogStatus.Warning => Global.SetTextColor(message, Global.LIGHT_ORANGE), 
				ChatLogStatus.Error => "<color=#" + UnityEngineExtensions.ToHex(Global.LIGHT_RED) + ">" + message + "</color>", 
				_ => message, 
			};
		}
	}
}
namespace OutwardChatConfigs.Triggers
{
	public class ExternalEventTrigger : IScheduledTrigger
	{
		private readonly string _eventKey;

		private Action _callback;

		public string EventKey => _eventKey;

		public ExternalEventTrigger(string eventKey)
		{
			_eventKey = eventKey;
		}

		public void Subscribe(Action callback)
		{
			_callback = (Action)Delegate.Combine(_callback, callback);
		}

		public void Unsubscribe(Action callback)
		{
			_callback = (Action)Delegate.Remove(_callback, callback);
		}

		public void Initialize()
		{
		}

		public void Trigger()
		{
			_callback?.Invoke();
		}
	}
	public class SLEventTrigger : IScheduledTrigger
	{
		private readonly string _eventKey;

		private readonly SLEventType _eventType;

		private Action _callback;

		public string EventKey => _eventKey;

		public SLEventTrigger(string eventKey, SLEventType eventType)
		{
			_eventKey = eventKey;
			_eventType = eventType;
		}

		public void Subscribe(Action callback)
		{
			_callback = (Action)Delegate.Combine(_callback, callback);
		}

		public void Unsubscribe(Action callback)
		{
			_callback = (Action)Delegate.Remove(_callback, callback);
		}

		public void Initialize()
		{
			switch (_eventType)
			{
			case SLEventType.BeforePacksLoaded:
				SL.BeforePacksLoaded += OnSLEvent;
				break;
			case SLEventType.OnPacksLoaded:
				SL.OnPacksLoaded += OnSLEvent;
				break;
			case SLEventType.OnSceneLoaded:
				SL.OnSceneLoaded += OnSLEvent;
				break;
			case SLEventType.OnGameplayResumedAfterLoading:
				SL.OnGameplayResumedAfterLoading += OnSLEvent;
				break;
			case SLEventType.OnBeforeHotReload:
				SL.OnBeforeHotReload += OnSLEvent;
				break;
			}
		}

		private void OnSLEvent()
		{
			_callback?.Invoke();
		}
	}
	public enum SLEventType
	{
		BeforePacksLoaded,
		OnPacksLoaded,
		OnSceneLoaded,
		OnGameplayResumedAfterLoading,
		OnBeforeHotReload
	}
	public static class TriggerFactory
	{
		private static readonly Dictionary<string, SLEventType> InternalEventMappings = new Dictionary<string, SLEventType>
		{
			{
				"BeforePacksLoaded",
				SLEventType.BeforePacksLoaded
			},
			{
				"OnPacksLoaded",
				SLEventType.OnPacksLoaded
			},
			{
				"OnSceneLoaded",
				SLEventType.OnSceneLoaded
			},
			{
				"OnGameplayResumedAfterLoading",
				SLEventType.OnGameplayResumedAfterLoading
			},
			{
				"OnBeforeHotReload",
				SLEventType.OnBeforeHotReload
			}
		};

		public static IScheduledTrigger CreateInternalTrigger(string eventName)
		{
			if (InternalEventMappings.TryGetValue(eventName, out var value))
			{
				return new SLEventTrigger("SL." + eventName, value);
			}
			throw new ArgumentException("Unknown internal event: " + eventName);
		}

		public static IScheduledTrigger CreateExternalTrigger(string eventKey)
		{
			return new ExternalEventTrigger(eventKey);
		}

		public static bool IsInternalEvent(string eventKey)
		{
			return eventKey.StartsWith("SL.");
		}

		public static bool TryGetInternalEventName(string eventKey, out string eventName)
		{
			if (eventKey.StartsWith("SL."))
			{
				eventName = eventKey.Substring(3);
				return InternalEventMappings.ContainsKey(eventName);
			}
			eventName = null;
			return false;
		}
	}
}
namespace OutwardChatConfigs.Patches
{
	[HarmonyPatch(typeof(ResourcesPrefabManager), "Load")]
	public static class Patch_ResourcesPrefabManager_Load
	{
		public static void Postfix()
		{
			OCC.LogMessage("ResourcesPrefabManager.Load completed - pre-loading scheduled events data");
			ScheduledEventsSerializer.Instance.PreLoadAllData();
		}
	}
}
namespace OutwardChatConfigs.Models
{
	public class RegisteredEvent
	{
		public string Namespace { get; set; }

		public string EventName { get; set; }

		public string EventKey { get; set; }

		public Action Callback { get; set; }

		public string DisplayName { get; set; }

		public bool IsInternal { get; set; }

		public RegisteredEvent(string @namespace, string eventName, Action callback, string displayName = null, bool isInternal = false)
		{
			Namespace = @namespace;
			EventName = eventName;
			EventKey = @namespace + "." + eventName;
			Callback = callback;
			DisplayName = displayName ?? eventName;
			IsInternal = isInternal;
		}
	}
	[XmlRoot("Binding")]
	public class ScheduledEventBinding
	{
		[XmlAttribute("key")]
		public string EventKey { get; set; }

		[XmlArray("Messages")]
		[XmlArrayItem("Message")]
		public List<ScheduledMessage> Messages { get; set; }

		public ScheduledEventBinding()
		{
			Messages = new List<ScheduledMessage>();
		}

		public ScheduledEventBinding(string eventKey)
			: this()
		{
			EventKey = eventKey;
		}
	}
	[XmlRoot("ScheduledMessages")]
	public class ScheduledEventsDataFile
	{
		[XmlArray("Bindings")]
		[XmlArrayItem("Binding")]
		public List<ScheduledEventBinding> Bindings { get; set; }

		public ScheduledEventsDataFile()
		{
			Bindings = new List<ScheduledEventBinding>();
		}
	}
	[XmlRoot("ScheduledMessage")]
	public class ScheduledMessage
	{
		[XmlElement("Index")]
		public int Index { get; set; }

		[XmlElement("Text")]
		public string Text { get; set; }

		[XmlElement("CreatedAt")]
		public DateTime CreatedAt { get; set; }

		public ScheduledMessage()
		{
		}

		public ScheduledMessage(int index, string text)
		{
			Index = index;
			Text = text;
			CreatedAt = DateTime.Now;
		}
	}
}
namespace OutwardChatConfigs.Managers
{
	public static class ExecutionTracker
	{
		private static readonly HashSet<string> _executedMessages = new HashSet<string>();

		public static void MarkAsExecuted(string eventKey, string messageText)
		{
			_executedMessages.Add(GetHash(eventKey, messageText));
		}

		public static bool IsExecuted(string eventKey, string messageText)
		{
			return _executedMessages.Contains(GetHash(eventKey, messageText));
		}

		public static void Reset()
		{
			_executedMessages.Clear();
		}

		private static string GetHash(string eventKey, string messageText)
		{
			string s = eventKey + "|" + messageText;
			using SHA256 sHA = SHA256.Create();
			return Convert.ToBase64String(sHA.ComputeHash(Encoding.UTF8.GetBytes(s)));
		}
	}
	public class PathsManager
	{
		private static PathsManager _instance;

		public static PathsManager Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new PathsManager();
				}
				return _instance;
			}
		}

		public string configPath { get; private set; }

		public string xmlFilePath { get; private set; }

		public string ProfilesPath { get; private set; }

		private PathsManager()
		{
			configPath = Path.Combine(PathsManager.ConfigPath, "Chat_Configs");
			xmlFilePath = Path.Combine(configPath, "MyDocument.xml");
			ProfilesPath = Path.Combine(configPath, "Profiles");
		}

		public void EnsureDirectoriesExist()
		{
			if (!Directory.Exists(configPath))
			{
				Directory.CreateDirectory(configPath);
			}
			if (!Directory.Exists(ProfilesPath))
			{
				Directory.CreateDirectory(ProfilesPath);
			}
		}
	}
	public class ProfileManager
	{
		private static ProfileManager _instance;

		public static ProfileManager Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new ProfileManager();
				}
				return _instance;
			}
		}

		private ProfileManager()
		{
		}

		public bool ProfileExists(string name)
		{
			return File.Exists(GetProfilePath(name));
		}

		public string GetProfilePath(string name)
		{
			string text = SanitizeFileName(name);
			return Path.Combine(PathsManager.Instance.ProfilesPath, text + ".xml");
		}

		public List<string> ListProfiles()
		{
			PathsManager.Instance.EnsureDirectoriesExist();
			List<string> list = new List<string>();
			string profilesPath = PathsManager.Instance.ProfilesPath;
			if (!Directory.Exists(profilesPath))
			{
				return list;
			}
			string[] files = Directory.GetFiles(profilesPath, "*.xml");
			for (int i = 0; i < files.Length; i++)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(files[i]);
				list.Add(fileNameWithoutExtension);
			}
			return list.OrderBy((string p) => p).ToList();
		}

		public void CreateProfile(string name, Character character)
		{
			PathsManager.Instance.EnsureDirectoriesExist();
			string profilePath = GetProfilePath(name);
			ScheduledEventsDataFile data = ScheduledEventsSerializer.Instance.Load(character);
			SaveToPath(profilePath, data);
		}

		public void StoreProfile(string name, Character character)
		{
			PathsManager.Instance.EnsureDirectoriesExist();
			string profilePath = GetProfilePath(name);
			ScheduledEventsDataFile data = ScheduledEventsSerializer.Instance.Load(character);
			SaveToPath(profilePath, data);
		}

		public ScheduledEventsDataFile LoadProfile(string name, Character character)
		{
			PathsManager.Instance.EnsureDirectoriesExist();
			string profilePath = GetProfilePath(name);
			ScheduledEventsDataFile scheduledEventsDataFile = LoadFromPath(profilePath);
			if (scheduledEventsDataFile != null)
			{
				ScheduledEventsSerializer.Instance.Save(character, scheduledEventsDataFile);
				ScheduledEventsSerializer.Instance.InvalidateCache();
			}
			return scheduledEventsDataFile;
		}

		public bool DeleteProfile(string name)
		{
			string profilePath = GetProfilePath(name);
			if (File.Exists(profilePath))
			{
				try
				{
					File.Delete(profilePath);
					return true;
				}
				catch (Exception ex)
				{
					OCC.LogMessage("ProfileManager: Failed to delete profile '" + name + "': " + ex.Message);
					return false;
				}
			}
			return false;
		}

		private void SaveToPath(string path, ScheduledEventsDataFile data)
		{
			try
			{
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(ScheduledEventsDataFile));
				XmlWriterSettings settings = new XmlWriterSettings
				{
					Indent = true,
					NewLineOnAttributes = false
				};
				using XmlWriter xmlWriter = XmlWriter.Create(path, settings);
				xmlSerializer.Serialize(xmlWriter, data);
			}
			catch (Exception ex)
			{
				OCC.LogMessage("ProfileManager@SaveToPath failed: " + ex.Message);
			}
		}

		private ScheduledEventsDataFile LoadFromPath(string path)
		{
			try
			{
				if (!File.Exists(path))
				{
					OCC.LogMessage("ProfileManager: Profile file not found at: " + path);
					return null;
				}
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(ScheduledEventsDataFile));
				using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
				return xmlSerializer.Deserialize(stream) as ScheduledEventsDataFile;
			}
			catch (Exception ex)
			{
				OCC.LogMessage("ProfileManager@LoadFromPath failed: " + ex.Message);
				return null;
			}
		}

		private string SanitizeFileName(string name)
		{
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				name = name.Replace(oldChar, '_');
			}
			return name;
		}
	}
	public class ScheduledEventsManager
	{
		private static ScheduledEventsManager _instance;

		private readonly Dictionary<string, RegisteredEvent> _registeredEvents;

		private readonly Dictionary<string, IScheduledTrigger> _triggers;

		public static ScheduledEventsManager Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new ScheduledEventsManager();
				}
				return _instance;
			}
		}

		private ScheduledEventsManager()
		{
			_registeredEvents = new Dictionary<string, RegisteredEvent>();
			_triggers = new Dictionary<string, IScheduledTrigger>();
		}

		public void RegisterEvent(string @namespace, string eventName, Action callback, string displayName = null)
		{
			string eventKey = @namespace + "." + eventName;
			if (_registeredEvents.ContainsKey(eventKey))
			{
				OCC.LogMessage("ScheduledEventsManager: Event " + eventKey + " already registered. Overwriting.");
			}
			RegisteredEvent value = new RegisteredEvent(@namespace, eventName, callback, displayName);
			_registeredEvents[eventKey] = value;
			IScheduledTrigger scheduledTrigger = TriggerFactory.CreateExternalTrigger(eventKey);
			scheduledTrigger.Subscribe(delegate
			{
				EventDispatcher.DispatchEvent(eventKey);
			});
			_triggers[eventKey] = scheduledTrigger;
			OCC.LogMessage("ScheduledEventsManager: Registered event " + eventKey);
		}

		public void RegisterInternalEvent(string @namespace, string eventName, Action callback, string displayName = null)
		{
			string eventKey = @namespace + "." + eventName;
			if (_registeredEvents.ContainsKey(eventKey))
			{
				OCC.LogMessage("ScheduledEventsManager: Internal event " + eventKey + " already registered. Overwriting.");
			}
			RegisteredEvent value = new RegisteredEvent(@namespace, eventName, callback, displayName, isInternal: true);
			_registeredEvents[eventKey] = value;
			if (@namespace == "SL")
			{
				try
				{
					IScheduledTrigger scheduledTrigger = TriggerFactory.CreateInternalTrigger(eventName);
					scheduledTrigger.Initialize();
					scheduledTrigger.Subscribe(delegate
					{
						EventDispatcher.DispatchEvent(eventKey);
					});
					_triggers[eventKey] = scheduledTrigger;
				}
				catch (Exception ex)
				{
					OCC.LogMessage("ScheduledEventsManager: Failed to register internal SL event " + eventKey + ": " + ex.Message);
				}
			}
			if (@namespace == "gymmed" && eventName == "OnFirstGameReady")
			{
				try
				{
					IScheduledTrigger scheduledTrigger2 = TriggerFactory.CreateInternalTrigger("OnSceneLoaded");
					scheduledTrigger2.Initialize();
					scheduledTrigger2.Subscribe(delegate
					{
						EventDispatcher.DispatchEvent(eventKey);
					});
				}
				catch (Exception ex2)
				{
					OCC.LogMessage("ScheduledEventsManager: Failed to register gymmed.OnFirstGameReady to SL.OnSceneLoaded: " + ex2.Message);
				}
			}
			OCC.LogMessage("ScheduledEventsManager: Registered internal event " + eventKey);
		}

		public bool IsEventRegistered(string eventKey)
		{
			return _registeredEvents.ContainsKey(eventKey);
		}

		public RegisteredEvent GetRegisteredEvent(string eventKey)
		{
			_registeredEvents.TryGetValue(eventKey, out var value);
			return value;
		}

		public IEnumerable<RegisteredEvent> GetAllRegisteredEvents()
		{
			return _registeredEvents.Values;
		}

		public IEnumerable<RegisteredEvent> GetRegisteredEventsByNamespace(string @namespace)
		{
			foreach (RegisteredEvent value in _registeredEvents.Values)
			{
				if (value.Namespace == @namespace)
				{
					yield return value;
				}
			}
		}
	}
	public class ScheduledEventsSerializer : IMessageSerializer
	{
		private static ScheduledEventsSerializer _instance;

		private string _configPath;

		private Dictionary<string, ScheduledEventsDataFile> _cachedBindings;

		private bool _isCacheLoaded;

		public static ScheduledEventsSerializer Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new ScheduledEventsSerializer();
				}
				return _instance;
			}
		}

		private ScheduledEventsSerializer()
		{
			_configPath = PathsManager.Instance.configPath;
			_cachedBindings = new Dictionary<string, ScheduledEventsDataFile>();
		}

		public void PreLoadAllData()
		{
			if (_isCacheLoaded)
			{
				OCC.LogMessage("ScheduledEventsSerializer: Cache already loaded, skipping pre-load");
				return;
			}
			OCC.LogMessage("ScheduledEventsSerializer: Pre-loading all character event data");
			_cachedBindings = LoadAllCharacters();
			_isCacheLoaded = true;
			OCC.LogMessage($"ScheduledEventsSerializer: Loaded {_cachedBindings.Count} character bindings into cache");
		}

		public void InvalidateCache()
		{
			_isCacheLoaded = false;
			_cachedBindings.Clear();
		}

		public Dictionary<string, ScheduledEventsDataFile> GetCachedBindings()
		{
			if (!_isCacheLoaded)
			{
				PreLoadAllData();
			}
			return _cachedBindings;
		}

		public string GetFilePath(Character character)
		{
			//IL_0007: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			if (character != null)
			{
				_ = character.UID;
				if (0 == 0)
				{
					string configPath = _configPath;
					UID uID = character.UID;
					return Path.Combine(configPath, ((UID)(ref uID)).Value, "ScheduledChatEvents.xml");
				}
			}
			OCC.LogMessage("ScheduledEventsSerializer@GetCharacterXmlFilePath: Provided null character!");
			return Path.Combine(_configPath, "ScheduledChatEvents.xml");
		}

		public ScheduledEventsDataFile Load(Character character)
		{
			string filePath = GetFilePath(character);
			return Load(filePath);
		}

		public ScheduledEventsDataFile Load(string path)
		{
			try
			{
				if (!File.Exists(path))
				{
					OCC.LogMessage("ScheduledEventsSerializer: File not found at: " + path);
					return new ScheduledEventsDataFile();
				}
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(ScheduledEventsDataFile));
				using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
				return (xmlSerializer.Deserialize(stream) as ScheduledEventsDataFile) ?? new ScheduledEventsDataFile();
			}
			catch (Exception ex)
			{
				OCC.LogMessage("ScheduledEventsSerializer@Load failed: " + ex.Message);
				return new ScheduledEventsDataFile();
			}
		}

		public void Save(Character character, ScheduledEventsDataFile data)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			string filePath = GetFilePath(character);
			Save(filePath, data);
			if (character != null)
			{
				_ = character.UID;
				Dictionary<string, ScheduledEventsDataFile> cachedBindings = _cachedBindings;
				UID uID = character.UID;
				cachedBindings[((UID)(ref uID)).Value] = data;
			}
		}

		public void Save(string path, ScheduledEventsDataFile data)
		{
			try
			{
				string directoryName = Path.GetDirectoryName(path);
				if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(ScheduledEventsDataFile));
				XmlWriterSettings settings = new XmlWriterSettings
				{
					Indent = true,
					NewLineOnAttributes = false
				};
				using XmlWriter xmlWriter = XmlWriter.Create(path, settings);
				xmlSerializer.Serialize(xmlWriter, data);
			}
			catch (Exception ex)
			{
				OCC.LogMessage("ScheduledEventsSerializer@Save failed: " + ex.Message);
			}
		}

		public Dictionary<string, ScheduledEventsDataFile> LoadAllCharacters()
		{
			Dictionary<string, ScheduledEventsDataFile> dictionary = new Dictionary<string, ScheduledEventsDataFile>();
			if (!Directory.Exists(_configPath))
			{
				return dictionary;
			}
			string[] directories = Directory.GetDirectories(_configPath);
			foreach (string obj in directories)
			{
				string fileName = Path.GetFileName(obj);
				string path = Path.Combine(obj, "ScheduledChatEvents.xml");
				if (File.Exists(path))
				{
					ScheduledEventsDataFile scheduledEventsDataFile = Load(path);
					if (scheduledEventsDataFile.Bindings.Count > 0)
					{
						dictionary[fileName] = scheduledEventsDataFile;
					}
				}
			}
			return dictionary;
		}
	}
}
namespace OutwardChatConfigs.Interfaces
{
	public interface IMessageSerializer
	{
		void Save(Character character, ScheduledEventsDataFile data);

		ScheduledEventsDataFile Load(Character character);

		string GetFilePath(Character character);
	}
	public interface IScheduledTrigger
	{
		string EventKey { get; }

		void Subscribe(Action callback);

		void Unsubscribe(Action callback);

		void Initialize();
	}
}
namespace OutwardChatConfigs.Handlers
{
	public static class ChatInputHandler
	{
		public static void HandleProfileCreate(Character character, Dictionary<string, string> arguments)
		{
			if (!arguments.TryGetValue("name", out var value) || string.IsNullOrWhiteSpace(value))
			{
				SendError(character, "Missing required parameter: --name");
			}
			else if (ProfileManager.Instance.ProfileExists(value))
			{
				SendWarning(character, "Profile '" + value + "' already exists. Use '/chatProfileStore --name=" + value + "' instead.");
			}
			else
			{
				ProfileManager.Instance.CreateProfile(value, character);
				SendSuccess(character, "Created profile '" + value + "' with current scheduled messages.");
			}
		}

		public static void HandleProfileStore(Character character, Dictionary<string, string> arguments)
		{
			if (!arguments.TryGetValue("name", out var value) || string.IsNullOrWhiteSpace(value))
			{
				SendError(character, "Missing required parameter: --name");
			}
			else if (!ProfileManager.Instance.ProfileExists(value))
			{
				SendError(character, "Profile '" + value + "' does not exist. Use '/chatProfileCreate --name=" + value + "' instead.");
			}
			else
			{
				ProfileManager.Instance.StoreProfile(value, character);
				SendSuccess(character, "Stored current scheduled messages to profile '" + value + "'.");
			}
		}

		public static void HandleProfileList(Character character, Dictionary<string, string> arguments)
		{
			List<string> list = ProfileManager.Instance.ListProfiles();
			if (list.Count == 0)
			{
				SendInfo(character, "No profiles found.");
				return;
			}
			SendInfo(character, $"Available profiles ({list.Count}):");
			foreach (string item in list)
			{
				SendInfo(character, "  - " + item);
			}
		}

		public static void HandleProfileRemove(Character character, Dictionary<string, string> arguments)
		{
			if (!arguments.TryGetValue("name", out var value) || string.IsNullOrWhiteSpace(value))
			{
				SendError(character, "Missing required parameter: --name");
				return;
			}
			if (!ProfileManager.Instance.ProfileExists(value))
			{
				SendError(character, "Profile '" + value + "' does not exist.");
				return;
			}
			ProfileManager.Instance.DeleteProfile(value);
			SendSuccess(character, "Deleted profile '" + value + "'.");
		}

		public static void HandleProfileUse(Character character, Dictionary<string, string> arguments)
		{
			if (!arguments.TryGetValue("name", out var value) || string.IsNullOrWhiteSpace(value))
			{
				SendError(character, "Missing required parameter: --name");
				return;
			}
			if (!ProfileManager.Instance.ProfileExists(value))
			{
				SendError(character, "Profile '" + value + "' does not exist.");
				return;
			}
			ScheduledEventsDataFile scheduledEventsDataFile = ProfileManager.Instance.LoadProfile(value, character);
			if (scheduledEventsDataFile != null)
			{
				int num = scheduledEventsDataFile.Bindings.Sum((ScheduledEventBinding b) => b.Messages.Count);
				SendSuccess(character, $"Loaded profile '{value}' with {num} message(s).");
			}
			else
			{
				SendError(character, "Failed to load profile '" + value + "'.");
			}
		}

		public static void HandleBind(Character character, Dictionary<string, string> arguments)
		{
			if (!arguments.TryGetValue("mod", out var value) || string.IsNullOrWhiteSpace(value))
			{
				SendError(character, "Missing required parameter: --mod");
				return;
			}
			if (!arguments.TryGetValue("event", out var value2) || string.IsNullOrWhiteSpace(value2))
			{
				SendError(character, "Missing required parameter: --event");
				return;
			}
			if (!arguments.TryGetValue("message", out var value3) || string.IsNullOrWhiteSpace(value3))
			{
				SendError(character, "Missing required parameter: --message");
				return;
			}
			string eventKey = value + "." + value2;
			if (!ScheduledEventsManager.Instance.IsEventRegistered(eventKey))
			{
				SendError(character, "Event '" + eventKey + "' is not registered. Use /listbinds to see available events.");
				return;
			}
			ScheduledEventsDataFile scheduledEventsDataFile = ScheduledEventsSerializer.Instance.Load(character);
			ScheduledEventBinding scheduledEventBinding = scheduledEventsDataFile.Bindings.FirstOrDefault((ScheduledEventBinding b) => b.EventKey == eventKey);
			if (scheduledEventBinding == null)
			{
				scheduledEventBinding = new ScheduledEventBinding(eventKey);
				scheduledEventsDataFile.Bindings.Add(scheduledEventBinding);
			}
			int count = scheduledEventBinding.Messages.Count;
			scheduledEventBinding.Messages.Add(new ScheduledMessage(count, value3));
			ScheduledEventsSerializer.Instance.Save(character, scheduledEventsDataFile);
			SendSuccess(character, $"Bound message to event '{eventKey}' with index {count}: {value3}");
		}

		public static void HandleUnbind(Character character, Dictionary<string, string> arguments)
		{
			if (!arguments.TryGetValue("mod", out var value) || string.IsNullOrWhiteSpace(value))
			{
				SendError(character, "Missing required parameter: --mod");
				return;
			}
			if (!arguments.TryGetValue("event", out var value2) || string.IsNullOrWhiteSpace(value2))
			{
				SendError(character, "Missing required parameter: --event");
				return;
			}
			if (!arguments.TryGetValue("index", out var value3) || !int.TryParse(value3, out var result))
			{
				SendError(character, "Missing required parameter: --index (must be a number)");
				return;
			}
			string eventKey = value + "." + value2;
			ScheduledEventsDataFile scheduledEventsDataFile = ScheduledEventsSerializer.Instance.Load(character);
			ScheduledEventBinding scheduledEventBinding = scheduledEventsDataFile.Bindings.FirstOrDefault((ScheduledEventBinding b) => b.EventKey == eventKey);
			if (scheduledEventBinding == null)
			{
				SendError(character, "No bindings found for event '" + eventKey + "'.");
				return;
			}
			if (result < 0 || result >= scheduledEventBinding.Messages.Count)
			{
				SendError(character, $"Invalid index {result}. Valid range: 0-{scheduledEventBinding.Messages.Count - 1}");
				return;
			}
			ScheduledMessage scheduledMessage = scheduledEventBinding.Messages[result];
			scheduledEventBinding.Messages.RemoveAt(result);
			for (int i = result; i < scheduledEventBinding.Messages.Count; i++)
			{
				scheduledEventBinding.Messages[i].Index = i;
			}
			ScheduledEventsSerializer.Instance.Save(character, scheduledEventsDataFile);
			SendSuccess(character, $"Removed binding at index {result}: {scheduledMessage.Text}");
		}

		public static void HandleListBinds(Character character, Dictionary<string, string> arguments)
		{
			arguments.TryGetValue("mod", out var modFilter);
			IEnumerable<ScheduledEventBinding> source = ScheduledEventsSerializer.Instance.Load(character).Bindings.AsEnumerable();
			if (!string.IsNullOrWhiteSpace(modFilter))
			{
				source = source.Where((ScheduledEventBinding b) => b.EventKey.StartsWith(modFilter + "."));
			}
			List<ScheduledEventBinding> list = source.ToList();
			if (list.Count == 0)
			{
				SendInfo(character, string.IsNullOrWhiteSpace(modFilter) ? "No event bindings found." : ("No event bindings found for mod '" + modFilter + "'."));
				return;
			}
			SendInfo(character, "Event bindings" + (string.IsNullOrWhiteSpace(modFilter) ? "" : (" for mod '" + modFilter + "'")) + ":");
			foreach (ScheduledEventBinding item in list)
			{
				SendInfo(character, "  " + item.EventKey + ":");
				if (item.Messages.Count == 0)
				{
					SendInfo(character, "    (no messages bound)");
					continue;
				}
				foreach (ScheduledMessage message in item.Messages)
				{
					SendInfo(character, $"    [{message.Index}]: {message.Text}");
				}
			}
		}

		public static void HandleConfigEvents(Character character, Dictionary<string, string> arguments)
		{
			SendInfo(character, "=== Available Events ===");
			SendInfo(character, "");
			SendInfo(character, "Internal Events:");
			SendInfo(character, "  gymmed.OnFirstGameReady - First time game is ready for chat");
			SendInfo(character, "");
			SendInfo(character, "SL Events (SideLoader):");
			SendInfo(character, "  SL.BeforePacksLoaded - Before packs are loaded");
			SendInfo(character, "  SL.OnPacksLoaded - When packs are loaded");
			SendInfo(character, "  SL.OnSceneLoaded - When a scene is loaded");
			SendInfo(character, "  SL.OnGameplayResumedAfterLoading - When gameplay resumes after loading");
			SendInfo(character, "  SL.OnBeforeHotReload - Before hot reload");
			SendInfo(character, "");
			SendInfo(character, "External Events:");
			SendInfo(character, "  Any custom event key (format: ModNamespace.EventName)");
			SendInfo(character, "  Example: MyMod.OnPlayerLogin, MyMod.OnQuestComplete");
			SendInfo(character, "");
			SendInfo(character, "How to bind a message:");
			SendInfo(character, "  /bind --mod=\"gymmed\" --event=\"OnFirstGameReady\" --message=\"/say Hello!\"");
			SendInfo(character, "");
			SendInfo(character, "To listen for external events, use Mods Communicator:");
			SendInfo(character, "  Subscribe to 'namespace' with event name 'EventName'");
			SendInfo(character, "  Then publish events to trigger bound chat messages");
		}

		private static void SendSuccess(Character character, string message)
		{
			character.CharacterUI.ChatPanel.ChatMessageReceived("System", ChatLogStatusHelper.GetChatLogText(message, ChatLogStatus.Success));
		}

		private static void SendError(Character character, string message)
		{
			character.CharacterUI.ChatPanel.ChatMessageReceived("System", ChatLogStatusHelper.GetChatLogText(message, ChatLogStatus.Error));
		}

		private static void SendWarning(Character character, string message)
		{
			character.CharacterUI.ChatPanel.ChatMessageReceived("System", ChatLogStatusHelper.GetChatLogText(message, ChatLogStatus.Warning));
		}

		private static void SendInfo(Character character, string message)
		{
			character.CharacterUI.ChatPanel.ChatMessageReceived("System", ChatLogStatusHelper.GetChatLogText(message));
		}
	}
	public static class EventDispatcher
	{
		private static readonly FieldInfo ChatEntryField;

		static EventDispatcher()
		{
			ChatEntryField = typeof(ChatPanel).GetField("m_chatEntry", BindingFlags.Instance | BindingFlags.NonPublic);
		}

		public static void DispatchEvent(string eventKey)
		{
			RegisteredEvent registeredEvent = ScheduledEventsManager.Instance.GetRegisteredEvent(eventKey);
			if (registeredEvent != null && registeredEvent.Callback != null)
			{
				try
				{
					registeredEvent.Callback();
				}
				catch (Exception ex)
				{
					OCC.LogMessage("EventDispatcher: Error executing callback for " + eventKey + ": " + ex.Message);
				}
			}
			foreach (KeyValuePair<string, ScheduledEventsDataFile> cachedBinding in ScheduledEventsSerializer.Instance.GetCachedBindings())
			{
				Character character = CharacterManager.Instance.GetCharacter(cachedBinding.Key);
				if ((Object)(object)character == (Object)null)
				{
					continue;
				}
				ScheduledEventBinding scheduledEventBinding = cachedBinding.Value.Bindings.FirstOrDefault((ScheduledEventBinding b) => b.EventKey == eventKey);
				if (scheduledEventBinding == null || scheduledEventBinding.Messages.Count == 0)
				{
					continue;
				}
				CharacterUI characterUI = character.CharacterUI;
				ChatPanel val = ((characterUI != null) ? characterUI.ChatPanel : null);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				foreach (ScheduledMessage message in scheduledEventBinding.Messages)
				{
					bool flag = eventKey.StartsWith("gymmed.");
					if (flag && ExecutionTracker.IsExecuted(eventKey, message.Text))
					{
						continue;
					}
					try
					{
						SendChatMessageViaReflection(val, message.Text);
						if (flag)
						{
							ExecutionTracker.MarkAsExecuted(eventKey, message.Text);
						}
					}
					catch (Exception ex2)
					{
						OCC.LogMessage("EventDispatcher: Error executing message '" + message.Text + "': " + ex2.Message);
					}
				}
			}
		}

		private static void SendChatMessageViaReflection(ChatPanel panel, string messageText)
		{
			InputField chatEntry = panel.m_chatEntry;
			if ((Object)(object)chatEntry == (Object)null)
			{
				OCC.LogMessage("EventDispatcher: Failed to get m_chatEntry field from ChatPanel");
				return;
			}
			chatEntry.text = messageText;
			panel.SendChatMessage();
		}
	}
}
namespace OutwardChatConfigs.Events
{
	public static class ChatCommandsRegistrar
	{
		public static void RegisterCommand(string commandName, Dictionary<string, (string, string)> parameters, string description, bool requiresDebubMode, bool isCheatCommand, Action<Character, Dictionary<string, string>> function)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_0090: Expected O, but got Unknown
			EventPayload val = new EventPayload { };
			string item;
			((Dictionary<string, object>)val)[item] = commandName;
			string item2 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandParameters).key;
			((Dictionary<string, object>)val)[item2] = parameters;
			string item3 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandAction).key;
			((Dictionary<string, object>)val)[item3] = function;
			string item4 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandDescription).key;
			((Dictionary<string, object>)val)[item4] = description;
			string item5 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandRequiresDebugMode).key;
			((Dictionary<string, object>)val)[item5] = requiresDebubMode;
			string item6 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.IsCheatCommand).key;
			((Dictionary<string, object>)val)[item6] = isCheatCommand;
			EventPayload val2 = val;
			EventBus.Publish("gymmed.chat_commands_manager_*", "ChatCommandsManager@AddChatCommand", val2);
		}
	}
	public static class EventBusPublisher
	{
		public const string Event_AddCommand = "ChatCommandsManager@AddChatCommand";

		public const string Event_RemoveCommand = "ChatCommandsManager@RemoveChatCommand";

		public const string ChatCommands_Listener = "gymmed.chat_commands_manager_*";

		public static void SendCommands()
		{
			RegisterChatCommands();
		}

		public static void RegisterChatCommands()
		{
			ChatCommandsRegistrar.RegisterCommand("bind", new Dictionary<string, (string, string)>
			{
				{
					"mod",
					("Required. Mod namespace.", "")
				},
				{
					"event",
					("Required. Event name.", "")
				},
				{
					"message",
					("Required. Text to execute when event fires.", "")
				}
			}, "Binds a message to an event. Example: /bind --mod=\"MyMod\" --event=\"OnPlayerLogin\" --message=\"/say Hello!\"", requiresDebubMode: false, isCheatCommand: false, ChatInputHandler.HandleBind);
			ChatCommandsRegistrar.RegisterCommand("unbind", new Dictionary<string, (string, string)>
			{
				{
					"mod",
					("Required. Mod namespace.", "")
				},
				{
					"event",
					("Required. Event name.", "")
				},
				{
					"index",
					("Required. Message index to remove.", "0")
				}
			}, "Removes a bound message from an event. Example: /unbind --mod=\"MyMod\" --event=\"OnPlayerLogin\" --index=0", requiresDebubMode: false, isCheatCommand: false, ChatInputHandler.HandleUnbind);
			ChatCommandsRegistrar.RegisterCommand("listbinds", new Dictionary<string, (string, string)> { 
			{
				"mod",
				("Optional. Filter by mod namespace. Leave empty for all.", "")
			} }, "Shows all bound messages. Example: /listbinds or /listbinds --mod=\"MyMod\"", requiresDebubMode: false, isCheatCommand: false, ChatInputHandler.HandleListBinds);
			ChatCommandsRegistrar.RegisterCommand("configEvents", new Dictionary<string, (string, string)>(), "Shows all available events for binding. Example: /configEvents", requiresDebubMode: false, isCheatCommand: false, ChatInputHandler.HandleConfigEvents);
			ChatCommandsRegistrar.RegisterCommand("chatProfileCreate", new Dictionary<string, (string, string)> { 
			{
				"name",
				("Required. Profile name.", "")
			} }, "Creates a new profile with current scheduled messages. Example: /chatProfileCreate --name=myProfile", requiresDebubMode: false, isCheatCommand: false, ChatInputHandler.HandleProfileCreate);
			ChatCommandsRegistrar.RegisterCommand("chatProfileStore", new Dictionary<string, (string, string)> { 
			{
				"name",
				("Required. Profile name.", "")
			} }, "Stores current scheduled messages to existing profile. Example: /chatProfileStore --name=myProfile", requiresDebubMode: false, isCheatCommand: false, ChatInputHandler.HandleProfileStore);
			ChatCommandsRegistrar.RegisterCommand("chatProfilesList", new Dictionary<string, (string, string)>(), "Lists all available profiles. Example: /chatProfilesList", requiresDebubMode: false, isCheatCommand: false, ChatInputHandler.HandleProfileList);
			ChatCommandsRegistrar.RegisterCommand("chatProfilesRemove", new Dictionary<string, (string, string)> { 
			{
				"name",
				("Required. Profile name to remove.", "")
			} }, "Removes a profile. Example: /chatProfilesRemove --name=myProfile", requiresDebubMode: false, isCheatCommand: false, ChatInputHandler.HandleProfileRemove);
			ChatCommandsRegistrar.RegisterCommand("chatProfilesUse", new Dictionary<string, (string, string)> { 
			{
				"name",
				("Required. Profile name to load.", "")
			} }, "Loads a profile, replacing current scheduled messages. Example: /chatProfilesUse --name=myProfile", requiresDebubMode: false, isCheatCommand: false, ChatInputHandler.HandleProfileUse);
		}
	}
	public static class EventBusRegister
	{
		private static readonly (string key, Type type, string description)[] RegisterEventData = new(string, Type, string)[4]
		{
			("namespace", typeof(string), "Required. The namespace to prevent collision (e.g., 'MyMod')."),
			("eventName", typeof(string), "Required. The event name (e.g., 'OnPlayerLogin')."),
			("action", typeof(Action), "Required. The callback to execute when the event fires."),
			("displayName", typeof(string), "Optional. User-facing name for the event.")
		};

		private static readonly (string key, Type type, string description)[] TriggerEventData = new(string, Type, string)[2]
		{
			("namespace", typeof(string), "Required. The namespace of the event (e.g., 'MyMod')."),
			("eventName", typeof(string), "Required. The event name to trigger (e.g., 'OnPlayerLogin').")
		};

		public static void RegisterEvents()
		{
			EventBus.RegisterEvent("gymmed.chat_configs_*", "ScheduledEvents@RegisterEvent", "Registers a new event that users can bind messages to.", RegisterEventData);
			EventBus.RegisterEvent("gymmed.chat_configs_*", "ScheduledEvents@TriggerEvent", "Triggers an event, executing any bound chat messages.", TriggerEventData);
		}
	}
	public static class EventBusSubscriber
	{
		public const string Event_AddedChatCommand = "ChatCommandsManager@AddChatCommand_After";

		public const string Event_RemovedChatCommand = "ChatCommandsManager@RemoveChatCommand_After";

		public const string Event_RegisterEvent = "ScheduledEvents@RegisterEvent";

		public const string Event_TriggerEvent = "ScheduledEvents@TriggerEvent";

		public static void AddSubscribers()
		{
			EventBus.Subscribe("gymmed.chat_commands_manager_*", "ChatCommandsManager@AddChatCommand_After", (Action<EventPayload>)AddedChatCommand);
			EventBus.Subscribe("gymmed.chat_commands_manager_*", "ChatCommandsManager@RemoveChatCommand_After", (Action<EventPayload>)RemovedChatCommand);
			EventBus.Subscribe("gymmed.chat_configs_*", "ScheduledEvents@RegisterEvent", (Action<EventPayload>)OnRegisterEvent);
			EventBus.Subscribe("gymmed.chat_configs_*", "ScheduledEvents@TriggerEvent", (Action<EventPayload>)OnTriggerEvent);
		}

		public static void AddedChatCommand(EventPayload payload)
		{
			if (payload != null)
			{
				(string, Type) tuple = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandName);
				payload.Get<string>(tuple.Item1, (string)null);
				OCC.LogMessage("Added command " + tuple.Item1);
			}
		}

		public static void RemovedChatCommand(EventPayload payload)
		{
			if (payload != null)
			{
				(string, Type) tuple = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandName);
				payload.Get<string>(tuple.Item1, (string)null);
				OCC.LogMessage("Removed command " + tuple.Item1);
			}
		}

		public static void OnRegisterEvent(EventPayload payload)
		{
			if (payload == null)
			{
				return;
			}
			string text = payload.Get<string>("namespace", (string)null);
			if (string.IsNullOrEmpty(text))
			{
				OCC.LogMessage("EventBusSubscriber: namespace is required!");
				return;
			}
			string text2 = payload.Get<string>("eventName", (string)null);
			if (string.IsNullOrEmpty(text2))
			{
				OCC.LogMessage("EventBusSubscriber: eventName is required!");
				return;
			}
			Action action = payload.Get<Action>("action", (Action)null);
			if (action == null)
			{
				OCC.LogMessage("EventBusSubscriber: action callback is required!");
				return;
			}
			string displayName = payload.Get<string>("displayName", text2);
			ScheduledEventsManager.Instance.RegisterEvent(text, text2, action, displayName);
		}

		public static void OnTriggerEvent(EventPayload payload)
		{
			if (payload == null)
			{
				return;
			}
			string text = payload.Get<string>("namespace", (string)null);
			if (string.IsNullOrEmpty(text))
			{
				OCC.LogMessage("EventBusSubscriber: namespace is required for triggering event!");
				return;
			}
			string text2 = payload.Get<string>("eventName", (string)null);
			if (string.IsNullOrEmpty(text2))
			{
				OCC.LogMessage("EventBusSubscriber: eventName is required for triggering event!");
				return;
			}
			string text3 = text + "." + text2;
			RegisteredEvent registeredEvent = ScheduledEventsManager.Instance.GetRegisteredEvent(text3);
			if (registeredEvent != null && registeredEvent.Callback != null)
			{
				try
				{
					registeredEvent.Callback();
				}
				catch (Exception ex)
				{
					OCC.LogMessage("EventBusSubscriber: Error executing callback for " + text3 + ": " + ex.Message);
				}
			}
			EventDispatcher.DispatchEvent(text3);
		}
	}
}
namespace OutwardChatConfigs.Events.Publishers
{
	public static class ExamplePublisher
	{
		public static void SendExampleCommand()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_008d: Expected O, but got Unknown
			Dictionary<string, (string, string)> value = new Dictionary<string, (string, string)> { 
			{
				"yourVar",
				("Optional. Some dynamic data that user can provide in chat with --yourVar='value'.", null)
			} };
			Action<Character, Dictionary<string, string>> value2 = TriggerFunction;
			EventPayload val = new EventPayload { };
			string item;
			((Dictionary<string, object>)val)[item] = "example";
			string item2 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandParameters).key;
			((Dictionary<string, object>)val)[item2] = value;
			string item3 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandAction).key;
			((Dictionary<string, object>)val)[item3] = value2;
			string item4 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandDescription).key;
			((Dictionary<string, object>)val)[item4] = "Example method for user to test. This description can be seen with chat command:/help example";
			EventPayload val2 = val;
			EventBus.Publish("gymmed.chat_commands_manager_*", "ChatCommandsManager@AddChatCommand", val2);
		}

		public static void TriggerFunction(Character caller, Dictionary<string, string> arguments)
		{
			object obj;
			if (caller == null)
			{
				obj = null;
			}
			else
			{
				CharacterUI characterUI = caller.CharacterUI;
				obj = ((characterUI != null) ? characterUI.ChatPanel : null);
			}
			ChatPanel val = (ChatPanel)obj;
			if ((Object)(object)val == (Object)null)
			{
				OCC.LogMessage("ExamplePublisher@TriggerFunction Tried to use missing chatPanel.");
				return;
			}
			arguments.TryGetValue("yourVar", out var value);
			if (string.IsNullOrWhiteSpace(value))
			{
				ChatHelpers.SendChatLog(val, "You didn't provide yourVar variable!", ChatLogStatus.Warning);
			}
			ChatHelpers.SendChatLog(val, "Finished executing trigger method!", ChatLogStatus.Success);
		}
	}
}