Decompiled source of Mods Communicator v1.2.0

OutwardModsCommunicator.dll

Decompiled a month ago
using System;
using System.Collections;
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.Permissions;
using System.Xml.Serialization;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using OutwardModsCommunicator.Enums;
using OutwardModsCommunicator.EventBus;
using OutwardModsCommunicator.Managers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("OutwardModsCommunicator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OutwardModsCommunicator")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("35f7bd74-9a7e-40c3-992f-6e85dc4d12a3")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.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 OutwardModsCommunicator
{
	[XmlRoot("ConfigOverrides")]
	public class ConfigOverrides
	{
		[XmlElement("Mod")]
		public List<ModOverride> Mods { get; set; } = new List<ModOverride>();

	}
	public class ModOverride
	{
		[XmlAttribute("GUID")]
		public string ModGUID { get; set; } = "";


		[XmlElement("Section")]
		public List<SectionOverride> Sections { get; set; } = new List<SectionOverride>();

	}
	public class SectionOverride
	{
		[XmlAttribute("Name")]
		public string Name { get; set; } = "";


		[XmlElement("Entry")]
		public List<EntryOverride> Entries { get; set; } = new List<EntryOverride>();

	}
	public class EntryOverride
	{
		[XmlAttribute("Key")]
		public string Key { get; set; } = "";


		[XmlAttribute("Value")]
		public string Value { get; set; } = "";

	}
	public static class ConfigProfileLoader
	{
		public static ConfigOverrides? LoadFromXml(string filePath)
		{
			if (!File.Exists(filePath))
			{
				return null;
			}
			try
			{
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(ConfigOverrides));
				using FileStream stream = File.OpenRead(filePath);
				return xmlSerializer.Deserialize(stream) as ConfigOverrides;
			}
			catch
			{
				return null;
			}
		}
	}
	[BepInPlugin("gymmed.outward_mods_communicator", "Outward Mods Communicator", "1.2.0")]
	public class OMC : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(ResourcesPrefabManager), "Load")]
		public class ResourcesPrefabManager_Load
		{
			private static void Postfix(ResourcesPrefabManager __instance)
			{
				if (!string.IsNullOrEmpty(xmlFilePath))
				{
					ConfigOverrideManager.OverrideConfigsFromFile(xmlFilePath);
				}
				string playerOverrideLocation = PathsManager.GetPlayerOverrideLocation();
				if (!string.IsNullOrEmpty(playerOverrideLocation))
				{
					ConfigOverrideManager.OverrideConfigsFromFile(playerOverrideLocation);
				}
			}
		}

		public const string GUID = "gymmed.outward_mods_communicator";

		public const string NAME = "Outward Mods Communicator";

		public const string VERSION = "1.2.0";

		public static ConfigEntry<bool> EnableEventsProfiler = null;

		public static ConfigEntry<bool> InstantLogEventsProfileData = null;

		public static string xmlFilePath { get; set; } = "";


		internal void Awake()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			LogManager.InitializeLogger(((BaseUnityPlugin)this).Logger);
			EnableEventsProfiler = ((BaseUnityPlugin)this).Config.Bind<bool>("Event Profiler", "EnableEventsProfiler", false, "Enable events profiler for inspecting events timers?(You still need to call it for logging)");
			InstantLogEventsProfileData = ((BaseUnityPlugin)this).Config.Bind<bool>("Event Profiler", "InstantLogEventsProfileData", false, "If enabled, logs each event profiling record immediately when it happens.");
			EventProfiler.Initialize();
			new Harmony("gymmed.outward_mods_communicator").PatchAll();
		}

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

		public static void Log(string message, ENUM_LOG_LEVELS logType = ENUM_LOG_LEVELS.Info)
		{
			LogManager.Log(message, logType);
		}
	}
}
namespace OutwardModsCommunicator.Managers
{
	public class ConfigOverrideManager
	{
		public static void ChangeOriginalConfigs(ConfigOverrides overrides)
		{
			foreach (ModOverride mod in overrides.Mods)
			{
				ChangeOriginalModConfig(mod);
			}
		}

		public static void ChangeOriginalModConfig(ModOverride mod)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			string text = Path.Combine(Paths.ConfigPath, mod.ModGUID + ".cfg");
			if (!File.Exists(text))
			{
				OMC.Log("Skipping " + mod.ModGUID + " — config file not found.");
				return;
			}
			ConfigFile val = new ConfigFile(text, true);
			foreach (SectionOverride section in mod.Sections)
			{
				foreach (EntryOverride entry in section.Entries)
				{
					try
					{
						ConfigEntryBase val2 = val[section.Name, entry.Key];
						if (val2 == null)
						{
							OMC.Log("Missing key " + section.Name + ":" + entry.Key + " in " + mod.ModGUID + ", skipping.");
						}
						else
						{
							object boxedValue = Convert.ChangeType(entry.Value, val2.SettingType);
							val2.BoxedValue = boxedValue;
							OMC.Log("Updated " + mod.ModGUID + ":" + section.Name + ":" + entry.Key + " = " + entry.Value);
						}
					}
					catch (Exception ex)
					{
						OMC.Log("Error updating " + mod.ModGUID + ":" + section.Name + ":" + entry.Key + ": " + ex.Message);
					}
				}
			}
			val.Save();
		}

		public static void OverrideConfigsFromFile(string filePath = "MyModpackOverrides.xml")
		{
			ConfigOverrides configOverrides = ConfigProfileLoader.LoadFromXml(filePath);
			if (configOverrides == null)
			{
				OMC.Log("Couldn't open \"" + filePath + "\". You are sure that provided path is correct?", ENUM_LOG_LEVELS.Error);
			}
			else
			{
				OverrideConfigsValues(configOverrides);
			}
		}

		public static void OverrideConfigsValues(ConfigOverrides overrides)
		{
			try
			{
				if (overrides?.Mods == null || overrides.Mods.Count == 0)
				{
					OMC.Log("No overrides provided.");
					return;
				}
				foreach (ModOverride mod in overrides.Mods)
				{
					ApplyOverridesToMod(mod);
				}
			}
			catch (Exception ex)
			{
				OMC.Log("ConfigOverrideManager@OverrideConfigsValues:" + ex.Message, ENUM_LOG_LEVELS.Error);
			}
		}

		private static void ApplyOverridesToMod(ModOverride mod)
		{
			if (string.IsNullOrWhiteSpace(mod.ModGUID))
			{
				OMC.Log("Skipping mod with empty GUID.", ENUM_LOG_LEVELS.Warning);
				return;
			}
			if (!Chainloader.PluginInfos.TryGetValue(mod.ModGUID, out var value))
			{
				OMC.Log("Plugin not found: " + mod.ModGUID, ENUM_LOG_LEVELS.Warning);
				return;
			}
			BaseUnityPlugin instance = value.Instance;
			ConfigFile val = ((instance != null) ? instance.Config : null);
			if (val == null)
			{
				OMC.Log("Plugin has no ConfigFile: " + mod.ModGUID, ENUM_LOG_LEVELS.Warning);
				return;
			}
			if (mod.Sections == null || mod.Sections.Count == 0)
			{
				OMC.Log("No sections for " + mod.ModGUID + " — nothing to apply.");
				return;
			}
			foreach (SectionOverride section in mod.Sections)
			{
				ApplyOverridesToSection(mod.ModGUID, val, section);
			}
		}

		private static void ApplyOverridesToSection(string modGUID, ConfigFile configFile, SectionOverride section)
		{
			if (string.IsNullOrWhiteSpace(section.Name))
			{
				OMC.Log("Sections without name in " + modGUID, ENUM_LOG_LEVELS.Warning);
				return;
			}
			if (section.Entries == null || section.Entries.Count == 0)
			{
				OMC.Log("Sections without entries in " + modGUID, ENUM_LOG_LEVELS.Warning);
				return;
			}
			foreach (EntryOverride entry in section.Entries)
			{
				ApplyOverrideToEntry(modGUID, configFile, section.Name, entry);
			}
		}

		private static void ApplyOverrideToEntry(string modGUID, ConfigFile configFile, string sectionName, EntryOverride entry)
		{
			if (string.IsNullOrWhiteSpace(entry.Key))
			{
				OMC.Log("Mod:\"" + modGUID + "\" Section: \"" + sectionName + "\" has empty entry key", ENUM_LOG_LEVELS.Warning);
				return;
			}
			object obj = FindConfigEntry(configFile, sectionName, entry.Key);
			if (obj == null)
			{
				OMC.Log("Config entry not found: " + modGUID + " " + sectionName + ":" + entry.Key, ENUM_LOG_LEVELS.Warning);
				return;
			}
			Type type = GetSettingType(obj);
			if (type == null)
			{
				type = typeof(string);
			}
			if (!TryConvertValue(entry.Value, type, out object result))
			{
				OMC.Log("Failed to convert '" + entry.Value + "' to " + type.Name + " for " + modGUID + ":" + sectionName + ":" + entry.Key, ENUM_LOG_LEVELS.Warning);
			}
			else if (SetBoxedValue(obj, result))
			{
				OMC.Log("Applied " + modGUID + " " + sectionName + ":" + entry.Key + " = " + entry.Value);
			}
			else
			{
				OMC.Log("Cannot set BoxedValue for " + modGUID + ":" + sectionName + ":" + entry.Key, ENUM_LOG_LEVELS.Warning);
			}
		}

		private static object? FindConfigEntry(ConfigFile configFile, string sectionName, string key)
		{
			try
			{
				return configFile[sectionName, key];
			}
			catch
			{
				try
				{
					if (!(((object)configFile).GetType().GetProperty("Values", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(configFile) is IEnumerable enumerable))
					{
						return null;
					}
					foreach (object item in enumerable)
					{
						object obj = item.GetType().GetProperty("Definition")?.GetValue(item);
						if (obj != null)
						{
							string obj2 = obj.GetType().GetProperty("Key")?.GetValue(obj) as string;
							string text = obj.GetType().GetProperty("Section")?.GetValue(obj) as string;
							if (obj2 == key && text == sectionName)
							{
								return item;
							}
						}
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static Type GetSettingType(object configEntryObj)
		{
			try
			{
				PropertyInfo property = configEntryObj.GetType().GetProperty("SettingType");
				if (property != null)
				{
					Type type = property.GetValue(configEntryObj) as Type;
					if (type != null)
					{
						return type;
					}
				}
				return (configEntryObj.GetType().GetProperty("BoxedValue")?.GetValue(configEntryObj))?.GetType() ?? typeof(string);
			}
			catch
			{
				return typeof(string);
			}
		}

		private static bool TryConvertValue(string value, Type targetType, out object? result)
		{
			try
			{
				if (targetType.IsEnum)
				{
					result = Enum.Parse(targetType, value, ignoreCase: true);
				}
				else
				{
					result = Convert.ChangeType(value, targetType);
				}
				return true;
			}
			catch
			{
				result = null;
				return false;
			}
		}

		private static bool SetBoxedValue(object configEntryObj, object? value)
		{
			try
			{
				PropertyInfo property = configEntryObj.GetType().GetProperty("BoxedValue", BindingFlags.Instance | BindingFlags.Public);
				if (property != null && property.CanWrite)
				{
					property.SetValue(configEntryObj, value);
					return true;
				}
			}
			catch
			{
			}
			return false;
		}
	}
	public static class LogManager
	{
		public static string prefix = "[GymMed-Mods-Communicator]";

		internal static ManualLogSource? Logger;

		public static void InitializeLogger(ManualLogSource logger)
		{
			Logger = logger;
		}

		public static void Log(string message, ENUM_LOG_LEVELS logType = ENUM_LOG_LEVELS.Info)
		{
			switch (logType)
			{
			case ENUM_LOG_LEVELS.Info:
				LogInfo(message);
				break;
			case ENUM_LOG_LEVELS.Warning:
				LogWarning(message);
				break;
			case ENUM_LOG_LEVELS.Error:
				LogError(message);
				break;
			default:
				LogInfo(message);
				break;
			}
		}

		public static void LogInfo(string message)
		{
			if (Logger != null)
			{
				Logger.LogInfo((object)(prefix + " " + message));
			}
			else
			{
				Console.WriteLine(prefix + " " + message);
			}
		}

		public static void LogWarning(string message)
		{
			if (Logger != null)
			{
				Logger.LogWarning((object)(prefix + " " + message));
			}
			else
			{
				Console.WriteLine(prefix + "[WARNING] " + message);
			}
		}

		public static void LogError(string message)
		{
			if (Logger != null)
			{
				Logger.LogError((object)(prefix + " " + message));
			}
			else
			{
				Console.WriteLine(prefix + "[ERROR] " + message);
			}
		}
	}
	public static class PathsManager
	{
		public static string ConfigDirectoryName = "gymmed.Mods_Communicator";

		public static string ConfigPath = Path.Combine(Paths.ConfigPath, ConfigDirectoryName);

		public static string PlayerOverrideFileName = "PlayerModsOverrides.xml";

		public static string GetPlayerOverrideLocation()
		{
			return Path.Combine(ConfigPath, PlayerOverrideFileName);
		}
	}
}
namespace OutwardModsCommunicator.EventBus
{
	public static class EventBus
	{
		private static string _logPrefix = "[EventBus]";

		private static readonly Dictionary<string, Dictionary<string, List<Action<EventPayload?>>>> _modSubscribers = new Dictionary<string, Dictionary<string, List<Action<EventPayload>>>>();

		private static readonly Dictionary<string, Dictionary<string, EventPayload>> _publishedPayloads = new Dictionary<string, Dictionary<string, EventPayload>>();

		private static readonly Dictionary<string, Dictionary<string, EventDefinition>> _registeredEvents = new Dictionary<string, Dictionary<string, EventDefinition>>();

		public static IReadOnlyDictionary<string, Dictionary<string, List<Action<EventPayload?>>>> GetModSubscribers()
		{
			return _modSubscribers;
		}

		public static IReadOnlyDictionary<string, Dictionary<string, EventPayload>> GetModPublishedPayloads()
		{
			return _publishedPayloads;
		}

		public static IReadOnlyDictionary<string, Dictionary<string, EventDefinition>> GetRegisteredEvents()
		{
			return _registeredEvents;
		}

		private static void Log(string message, ENUM_LOG_LEVELS logLevel = ENUM_LOG_LEVELS.Info)
		{
			OMC.Log(_logPrefix + " " + message, logLevel);
		}

		public static void RegisterEvent(string modNamespace, string eventName, EventSchema? schema = null)
		{
			if (!_registeredEvents.TryGetValue(modNamespace, out Dictionary<string, EventDefinition> value))
			{
				value = (_registeredEvents[modNamespace] = new Dictionary<string, EventDefinition>());
			}
			value[eventName] = new EventDefinition(schema ?? new EventSchema());
			if (!_publishedPayloads.TryGetValue(modNamespace, out Dictionary<string, EventPayload> value2))
			{
				value2 = (_publishedPayloads[modNamespace] = new Dictionary<string, EventPayload>());
			}
			if (!value2.ContainsKey(eventName))
			{
				value2[eventName] = new EventPayload();
			}
			Log("Registered event '" + modNamespace + "." + eventName + "'");
		}

		public static void RegisterEvent(string modNamespace, string eventName, string description, EventSchema? schema = null)
		{
			if (!_registeredEvents.TryGetValue(modNamespace, out Dictionary<string, EventDefinition> value))
			{
				value = (_registeredEvents[modNamespace] = new Dictionary<string, EventDefinition>());
			}
			value[eventName] = new EventDefinition(schema ?? new EventSchema(), description);
			if (!_publishedPayloads.TryGetValue(modNamespace, out Dictionary<string, EventPayload> value2))
			{
				value2 = (_publishedPayloads[modNamespace] = new Dictionary<string, EventPayload>());
			}
			if (!value2.ContainsKey(eventName))
			{
				value2[eventName] = new EventPayload();
			}
			Log("Registered event '" + modNamespace + "." + eventName + "'");
		}

		public static void RegisterEvent(string modNamespace, string eventName, params (string key, Type type)[] fields)
		{
			EventSchema eventSchema = new EventSchema();
			for (int i = 0; i < fields.Length; i++)
			{
				var (name, type) = fields[i];
				eventSchema.AddField(name, type);
			}
			RegisterEvent(modNamespace, eventName, eventSchema);
		}

		public static void RegisterEvent(string modNamespace, string eventName, string eventDescription, params (string key, Type type)[] fields)
		{
			EventSchema eventSchema = new EventSchema();
			for (int i = 0; i < fields.Length; i++)
			{
				var (name, type) = fields[i];
				eventSchema.AddField(name, type);
			}
			RegisterEvent(modNamespace, eventName, eventDescription, eventSchema);
		}

		public static void RegisterEvent(string modNamespace, string eventName, params (string key, Type type, string? description)[] fields)
		{
			EventSchema eventSchema = new EventSchema();
			for (int i = 0; i < fields.Length; i++)
			{
				var (name, type, description) = fields[i];
				eventSchema.AddField(name, type, description);
			}
			RegisterEvent(modNamespace, eventName, eventSchema);
		}

		public static void RegisterEvent(string modNamespace, string eventName, string eventDescription, params (string key, Type type, string? description)[] fields)
		{
			EventSchema eventSchema = new EventSchema();
			for (int i = 0; i < fields.Length; i++)
			{
				var (name, type, description) = fields[i];
				eventSchema.AddField(name, type, description);
			}
			RegisterEvent(modNamespace, eventName, eventDescription, eventSchema);
		}

		public static void RegisterEventFromPayloadTypes(string modNamespace, string eventName, EventPayload payloadWithTypes)
		{
			EventSchema schema = new EventSchema(payloadWithTypes, treatValuesAsTypes: true);
			RegisterEvent(modNamespace, eventName, schema);
		}

		public static void Subscribe(string modNamespace, string eventName, Action<EventPayload?> callback)
		{
			if (!_modSubscribers.TryGetValue(modNamespace, out Dictionary<string, List<Action<EventPayload>>> value))
			{
				value = (_modSubscribers[modNamespace] = new Dictionary<string, List<Action<EventPayload>>>());
			}
			if (!value.TryGetValue(eventName, out var value2))
			{
				value2 = (value[eventName] = new List<Action<EventPayload>>());
			}
			value2.Add(callback);
		}

		public static void Unsubscribe(string modNamespace, string eventName, Action<EventPayload?> callback)
		{
			if (_modSubscribers.TryGetValue(modNamespace, out Dictionary<string, List<Action<EventPayload>>> value) && value.TryGetValue(eventName, out var value2))
			{
				value2.Remove(callback);
			}
		}

		public static void Publish(string modNamespace, string eventName, EventPayload? payload = null)
		{
			if (!_publishedPayloads.TryGetValue(modNamespace, out Dictionary<string, EventPayload> value))
			{
				value = (_publishedPayloads[modNamespace] = new Dictionary<string, EventPayload>());
			}
			value[eventName] = ((payload != null) ? new EventPayload(payload) : new EventPayload());
			if (!_modSubscribers.TryGetValue(modNamespace, out Dictionary<string, List<Action<EventPayload>>> value2) || !value2.TryGetValue(eventName, out var value3))
			{
				return;
			}
			Stopwatch stopwatch = null;
			if (OMC.EnableEventsProfiler.Value)
			{
				stopwatch = Stopwatch.StartNew();
			}
			foreach (Action<EventPayload> item in value3)
			{
				Stopwatch stopwatch2 = null;
				if (OMC.EnableEventsProfiler.Value)
				{
					stopwatch2 = Stopwatch.StartNew();
				}
				try
				{
					item(payload);
				}
				catch (Exception arg)
				{
					Log($"Error in '{modNamespace}.{eventName}' subscriber: {arg}", ENUM_LOG_LEVELS.Error);
				}
				if (OMC.EnableEventsProfiler.Value && stopwatch2 != null)
				{
					stopwatch2.Stop();
					string subscriberId = item.Method.DeclaringType?.Name + "." + item.Method.Name;
					EventProfiler.RecordSubscriber(modNamespace, eventName, subscriberId, stopwatch2.Elapsed.TotalMilliseconds);
				}
			}
			if (OMC.EnableEventsProfiler.Value && stopwatch != null)
			{
				stopwatch.Stop();
				EventProfiler.Record(modNamespace, eventName, stopwatch.Elapsed.TotalMilliseconds);
			}
		}

		public static void ClearNamespace(string modNamespace)
		{
			_modSubscribers.Remove(modNamespace);
		}
	}
	public class EventBusDataPresenter
	{
		public static void LogRegisteredEvents()
		{
			IReadOnlyDictionary<string, Dictionary<string, EventDefinition>> registeredEvents = EventBus.GetRegisteredEvents();
			OMC.Log("==== EventBus Registered Events (ALL MODS) ====");
			foreach (KeyValuePair<string, Dictionary<string, EventDefinition>> item in registeredEvents)
			{
				LogRegisteredEventsForModInternal(item.Key, item.Value);
			}
			OMC.Log("==== End of Registered Events ====");
		}

		public static void LogModRegisteredEvents(string modNamespace)
		{
			if (!EventBus.GetRegisteredEvents().TryGetValue(modNamespace, out Dictionary<string, EventDefinition> value))
			{
				logForMod(modNamespace, "No registered events found for mod '" + modNamespace + "'");
			}
			else
			{
				LogRegisteredEventsForModInternal(modNamespace, value);
			}
		}

		private static void LogRegisteredEventsForModInternal(string modNamespace, Dictionary<string, EventDefinition> modEvents)
		{
			logForMod(modNamespace, "==== EventBus Registered Events for Mod '" + modNamespace + "' ====");
			foreach (KeyValuePair<string, EventDefinition> modEvent in modEvents)
			{
				string key = modEvent.Key;
				EventDefinition value = modEvent.Value;
				EventSchema schema = value.Schema;
				logEmptyEventLine(modNamespace, key);
				if (!string.IsNullOrEmpty(value.Description))
				{
					logForEvent(modNamespace, key, "  Event '" + key + "' Description:'" + value.Description + "'");
				}
				logForEvent(modNamespace, key, "  Event '" + key + "' fields:");
				if (schema.Fields.Count == 0)
				{
					logForEvent(modNamespace, key, "    (no fields declared)");
					logEmptyEventLine(modNamespace, key);
					continue;
				}
				foreach (KeyValuePair<string, Type> field in schema.Fields)
				{
					string key2 = field.Key;
					string text = field.Value?.Name ?? "null";
					logForEvent(modNamespace, key, "    Parameter " + key2 + " : Type " + text);
					if (schema.Descriptions.TryGetValue(key2, out string value2) && !string.IsNullOrWhiteSpace(value2))
					{
						logForEvent(modNamespace, key, "    Description of parameter " + key2 + ": " + value2);
					}
					logEmptyEventLine(modNamespace, key);
				}
			}
			logForMod(modNamespace, "==== End of Registered Events for Mod '" + modNamespace + "' ====");
		}

		public static void LogPublishers()
		{
			IReadOnlyDictionary<string, Dictionary<string, EventPayload>> modPublishedPayloads = EventBus.GetModPublishedPayloads();
			OMC.Log("==== EventBus Publishers ====");
			foreach (KeyValuePair<string, Dictionary<string, EventPayload>> item in modPublishedPayloads)
			{
				LogPublishersEvents(item.Key, item.Value);
			}
			OMC.Log("==== End of Publishers ====");
		}

		public static void LogModPublishers(string modNamespace)
		{
			if (!EventBus.GetModPublishedPayloads().TryGetValue(modNamespace, out Dictionary<string, EventPayload> value))
			{
				logForMod(modNamespace, "No published events found for mod '" + modNamespace + "'");
			}
			else
			{
				LogPublishersEvents(modNamespace, value);
			}
		}

		public static void LogPublishersEvents(string modNamespace, Dictionary<string, EventPayload> modEvents)
		{
			logForMod(modNamespace, "==== EventBus Publishers for Mod '" + modNamespace + "' ====");
			foreach (KeyValuePair<string, EventPayload> modEvent in modEvents)
			{
				LogPublishersEventsVariables(modNamespace, modEvent.Key, modEvent.Value);
			}
			logForMod(modNamespace, "==== End of Publishers for Mod '" + modNamespace + "' ====");
		}

		public static void LogPublishersEventsVariables(string modName, string eventName, EventPayload payload)
		{
			logForEvent(modName, eventName, "  Event '" + eventName + "' publishes keys:");
			foreach (KeyValuePair<string, object> item in payload)
			{
				string key = item.Key;
				string text = item.Value?.GetType().Name ?? "null";
				string text2 = item.Value?.ToString() ?? "null";
				logForEvent(modName, eventName, "    " + key + " : " + text + " | Value=" + text2);
			}
		}

		public static void LogAllModsSubsribers()
		{
			IReadOnlyDictionary<string, Dictionary<string, List<Action<EventPayload?>>>> modSubscribers = EventBus.GetModSubscribers();
			OMC.Log("==== EventBus Data: ALL MODS ====");
			foreach (KeyValuePair<string, Dictionary<string, List<Action<EventPayload>>>> item in modSubscribers)
			{
				LogModEventSubscribers(item.Key, item.Value);
			}
			OMC.Log("==== End of ALL MODS ====");
		}

		public static void LogModSubscribers(string modNamespace)
		{
			if (!EventBus.GetModSubscribers().TryGetValue(modNamespace, out Dictionary<string, List<Action<EventPayload>>> value))
			{
				logForMod(modNamespace, "No subscribers found for mod '" + modNamespace + "'");
			}
			else
			{
				LogModEventSubscribers(modNamespace, value);
			}
		}

		private static void LogModEventSubscribers(string modNamespace, Dictionary<string, List<Action<EventPayload?>>> modEvents)
		{
			logForMod(modNamespace, "==== EventBus Data: Mod '" + modNamespace + "' ====");
			foreach (KeyValuePair<string, List<Action<EventPayload>>> modEvent in modEvents)
			{
				string key = modEvent.Key;
				List<Action<EventPayload>> value = modEvent.Value;
				logEmptyEventLine(modNamespace, key);
				logForEvent(modNamespace, key, $"Event: '{key}' | Subscriber Count: {value.Count}");
				int num = 0;
				foreach (Action<EventPayload> item in value)
				{
					MethodInfo method = item.Method;
					Type? declaringType = method.DeclaringType;
					string text = declaringType?.FullName ?? "UnknownType";
					string text2 = declaringType?.Assembly.GetName().Name ?? "UnknownAssembly";
					string text3 = item.Target?.GetType().Name ?? "static";
					logForEvent(modNamespace, key, $"  Subscriber {++num}: Assembly={text2}, DeclaringType={text}, TargetType={text3}, Method={method.Name}");
				}
				logEmptyEventLine(modNamespace, key);
			}
			logForMod(modNamespace, "==== End of Mod '" + modNamespace + "' ====");
		}

		public static void LogAllSubscribers()
		{
			IReadOnlyDictionary<string, Dictionary<string, List<Action<EventPayload?>>>> modSubscribers = EventBus.GetModSubscribers();
			OMC.Log("==== EventBus: All Subscribers ====");
			logEmptyLine();
			foreach (KeyValuePair<string, Dictionary<string, List<Action<EventPayload>>>> item in modSubscribers)
			{
				string key = item.Key;
				foreach (KeyValuePair<string, List<Action<EventPayload>>> item2 in item.Value)
				{
					string key2 = item2.Key;
					int count = item2.Value.Count;
					OMC.Log($"Mod: {key} | Event: {key2} | Subscribers: {count}");
				}
			}
			logEmptyLine();
			OMC.Log("==== End of Subscribers ====");
		}

		public static void LogEventSubscribers(string modNamespace, string eventName)
		{
			if (!EventBus.GetModSubscribers().TryGetValue(modNamespace, out Dictionary<string, List<Action<EventPayload>>> value))
			{
				logForMod(modNamespace, "Mod '" + modNamespace + "' not found.");
				return;
			}
			if (!value.TryGetValue(eventName, out var value2))
			{
				logForEvent(modNamespace, eventName, "Event '" + eventName + "' not found in mod '" + modNamespace + "'.");
				return;
			}
			logForEvent(modNamespace, eventName, "==== EventBus: Subscribers for '" + modNamespace + "." + eventName + "' ====");
			logEmptyEventLine(modNamespace, eventName);
			int num = 0;
			foreach (Action<EventPayload> item in value2)
			{
				string name = item.Method.Name;
				string arg = item.Target?.GetType().Name ?? "static";
				OMC.Log($"Subscriber {++num}: TargetType={arg}, Method={name}");
			}
			logEmptyEventLine(modNamespace, eventName);
			logForEvent(modNamespace, eventName, "==== End of Event Subscribers ====");
		}

		public static void LogPayload(EventPayload? payload)
		{
			if (payload == null)
			{
				OMC.Log("[EventBusDataPresenter@LogPayload] Payload is null.");
				return;
			}
			OMC.Log("---- Payload Contents ----");
			foreach (KeyValuePair<string, object> item in payload)
			{
				string key = item.Key;
				string text = item.Value?.GetType().Name ?? "null";
				string text2 = item.Value?.ToString() ?? "null";
				OMC.Log("Key='" + key + "' | Type=" + text + " | Value=" + text2);
			}
			OMC.Log("--------------------------");
		}

		private static void logForMod(string modName, string message)
		{
			OMC.Log("[" + modName + "] " + message);
		}

		private static void logForEvent(string modName, string eventName, string message)
		{
			OMC.Log("[" + modName + "] [" + eventName + "] " + message);
		}

		private static void logEmptyModLine(string modName)
		{
			logForMod(modName, "");
		}

		private static void logEmptyEventLine(string modName, string eventName)
		{
			logForEvent(modName, eventName, "");
		}

		private static void logEmptyLine()
		{
			OMC.Log("");
		}
	}
	public class EventDefinition
	{
		public EventSchema Schema { get; set; }

		public string Description { get; set; } = "";


		public EventDefinition(EventSchema? schema = null, string description = "")
		{
			Schema = schema ?? new EventSchema();
			Description = description;
		}
	}
	public class EventPayload : Dictionary<string, object>
	{
		public EventPayload()
		{
		}

		public EventPayload(EventPayload other)
		{
			if (other == null)
			{
				return;
			}
			foreach (KeyValuePair<string, object> item in other)
			{
				base[item.Key] = item.Value;
			}
		}

		public T Get<T>(string key, T? defaultValue = default(T?))
		{
			if (TryGetValue(key, out object value) && value is T)
			{
				return (T)value;
			}
			return defaultValue;
		}

		public void Set(string key, object value)
		{
			base[key] = value;
		}
	}
	public static class EventProfiler
	{
		public class EventProfileData
		{
			public readonly Dictionary<string, SubscriberProfile> SubscriberTimes = new Dictionary<string, SubscriberProfile>();

			public string ModNamespace { get; }

			public string EventName { get; }

			public int CallCount { get; private set; }

			public double TotalMs { get; private set; }

			public double MaxMs { get; private set; }

			public EventProfileData(string modNamespace, string eventName)
			{
				ModNamespace = modNamespace;
				EventName = eventName;
			}

			public void Record(double elapsedMs)
			{
				CallCount++;
				TotalMs += elapsedMs;
				if (elapsedMs > MaxMs)
				{
					MaxMs = elapsedMs;
				}
			}

			public void RecordSubscriber(string subscriberId, double elapsedMs)
			{
				if (!SubscriberTimes.TryGetValue(subscriberId, out SubscriberProfile value))
				{
					value = (SubscriberTimes[subscriberId] = new SubscriberProfile());
				}
				value.Record(elapsedMs);
			}
		}

		public class SubscriberProfile
		{
			public int CallCount { get; private set; }

			public double TotalMs { get; private set; }

			public double MaxMs { get; private set; }

			public void Record(double elapsedMs)
			{
				CallCount++;
				TotalMs += elapsedMs;
				if (elapsedMs > MaxMs)
				{
					MaxMs = elapsedMs;
				}
			}
		}

		private static readonly Dictionary<string, EventProfileData> _profiles = new Dictionary<string, EventProfileData>();

		public static bool Enabled { get; private set; }

		public static bool InstantLogging { get; private set; }

		public static void Initialize()
		{
			OMC.EnableEventsProfiler.SettingChanged += delegate
			{
				Enabled = OMC.EnableEventsProfiler.Value;
				OMC.Log("[EventProfiler] " + (Enabled ? "Enabled" : "Disabled") + " via config.");
			};
			if (OMC.InstantLogEventsProfileData != null)
			{
				OMC.InstantLogEventsProfileData.SettingChanged += delegate
				{
					InstantLogging = OMC.InstantLogEventsProfileData.Value;
					OMC.Log("[EventProfiler] Instant logging " + (InstantLogging ? "enabled" : "disabled") + " via config.");
				};
				InstantLogging = OMC.InstantLogEventsProfileData.Value;
			}
			Enabled = OMC.EnableEventsProfiler.Value;
		}

		public static void Record(string modNamespace, string eventName, double elapsedMs)
		{
			if (Enabled)
			{
				string text = modNamespace + "." + eventName;
				if (!_profiles.TryGetValue(text, out EventProfileData value))
				{
					value = (_profiles[text] = new EventProfileData(modNamespace, eventName));
				}
				value.Record(elapsedMs);
				if (InstantLogging)
				{
					OMC.Log($"[EventProfiler] {text} subscribers executed in {elapsedMs:F2} ms");
				}
			}
		}

		public static void RecordSubscriber(string modNamespace, string eventName, string subscriberId, double elapsedMs)
		{
			if (Enabled)
			{
				string text = modNamespace + "." + eventName;
				if (!_profiles.TryGetValue(text, out EventProfileData value))
				{
					value = (_profiles[text] = new EventProfileData(modNamespace, eventName));
				}
				value.RecordSubscriber(subscriberId, elapsedMs);
				if (InstantLogging)
				{
					OMC.Log($"[EventProfiler] {text} subscriber '{subscriberId}' took {elapsedMs:F2} ms");
				}
			}
		}

		public static void LogProfiles()
		{
			if (!Enabled)
			{
				OMC.Log("[EventProfiler] Profiler is disabled.");
				return;
			}
			OMC.Log("==== EventBus Profiler Summary ====");
			foreach (EventProfileData item in _profiles.Values.OrderByDescending((EventProfileData p) => p.TotalMs))
			{
				OMC.Log($"Event '{item.ModNamespace}.{item.EventName}' — Calls: {item.CallCount}, Total: {item.TotalMs:F2} ms, Max: {item.MaxMs:F2} ms, Avg: {item.TotalMs / (double)item.CallCount:F2} ms");
				if (item.SubscriberTimes.Count <= 0)
				{
					continue;
				}
				foreach (KeyValuePair<string, SubscriberProfile> subscriberTime in item.SubscriberTimes)
				{
					OMC.Log($"    Subscriber {subscriberTime.Key} — Calls: {subscriberTime.Value.CallCount}, Total: {subscriberTime.Value.TotalMs:F2} ms, Max: {subscriberTime.Value.MaxMs:F2} ms, Avg: {subscriberTime.Value.TotalMs / (double)subscriberTime.Value.CallCount:F2} ms");
				}
			}
			OMC.Log("==== End of Profiler Summary ====");
		}
	}
	public class EventSchema
	{
		public Dictionary<string, Type> Fields { get; } = new Dictionary<string, Type>();


		public Dictionary<string, string> Descriptions { get; } = new Dictionary<string, string>();


		public EventSchema()
		{
		}

		public EventSchema(EventPayload payload, bool treatValuesAsTypes = false)
		{
			if (payload == null)
			{
				return;
			}
			foreach (KeyValuePair<string, object> item in payload)
			{
				if (treatValuesAsTypes && item.Value is Type value)
				{
					Fields[item.Key] = value;
				}
				else if (item.Value is Type value2)
				{
					Fields[item.Key] = value2;
				}
				else if (item.Value != null)
				{
					Fields[item.Key] = item.Value.GetType();
				}
				else
				{
					Fields[item.Key] = typeof(object);
				}
			}
		}

		public void AddField(string name, Type type, string? description = null)
		{
			Fields[name] = type;
			if (!string.IsNullOrWhiteSpace(description))
			{
				Descriptions[name] = description;
			}
		}

		public string? GetDescription(string field)
		{
			if (!Descriptions.TryGetValue(field, out string value))
			{
				return null;
			}
			return value;
		}
	}
}
namespace OutwardModsCommunicator.Enums
{
	public enum ENUM_LOG_LEVELS
	{
		Info,
		Warning,
		Error
	}
}