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 BepInEx; using BepInEx.Logging; using HarmonyLib; using OutwardModsCommunicator.EventBus; using OutwardModsCommunicator.Managers; using OutwardModsCommunicatorChatControl.Events; using OutwardModsCommunicatorChatControl.Events.Publishers; using OutwardModsCommunicatorChatControl.Utility.Enums; using OutwardModsCommunicatorChatControl.Utility.Helpers; using SideLoader; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("OutwardModsCommunicatorChatControl")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("OutwardModsCommunicatorChatControl")] [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 OutwardModsCommunicatorChatControl { [BepInPlugin("gymmed.mods_communicator_chat_control", "Mods Communicator Chat Control", "0.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class OMCCC : BaseUnityPlugin { public const string GUID = "gymmed.mods_communicator_chat_control"; public const string NAME = "Mods Communicator Chat Control"; public const string VERSION = "0.0.2"; public static string prefix = "[Mods-Communicator-Chat-Control]"; public const string EVENTS_LISTENER_GUID = "gymmed.mods_communicator_chat_control_*"; internal static ManualLogSource Log; internal void Awake() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; LogMessage("Hello world from Mods Communicator Chat Control 0.0.2!"); new Harmony("gymmed.mods_communicator_chat_control").PatchAll(); EventBusPublisher.SendCommands(); } internal void Update() { } 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); } } } namespace OutwardModsCommunicatorChatControl.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) { OMCCC.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) { OMCCC.LogStatusMessage(message, status); } else { SendChatLog(character.CharacterUI.ChatPanel, message, status); } } } public static class CollectionValueParser { public static (object result, string error) TryParse(Type collectionType, string valueString) { if (collectionType == null || string.IsNullOrWhiteSpace(valueString)) { return (null, "Type or value is null/empty"); } if (!IsCollectionType(collectionType)) { return (null, "Type '" + collectionType.Name + "' is not a collection type"); } Type elementType = GetElementType(collectionType); if (elementType == null) { return (null, "Cannot determine element type for '" + collectionType.Name + "'"); } string[] array = valueString.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return (null, "No values provided"); } if (collectionType.IsArray) { return TryParseArray(elementType, array); } return TryParseCollection(collectionType, elementType, array); } private static (object result, string error) TryParseArray(Type elementType, string[] values) { List list = new List(); for (int i = 0; i < values.Length; i++) { var (item, text) = ParseValue(elementType, values[i]); if (text != null) { return (null, $"Invalid value at position {i + 1}: {text}"); } list.Add(item); } try { Array array = Array.CreateInstance(elementType, list.Count); for (int j = 0; j < list.Count; j++) { array.SetValue(list[j], j); } return (array, null); } catch (Exception ex) { return (null, "Failed to create array: " + ex.Message); } } private static (object result, string error) TryParseCollection(Type collectionType, Type elementType, string[] values) { List list = new List(); for (int i = 0; i < values.Length; i++) { var (item, text) = ParseValue(elementType, values[i]); if (text != null) { return (null, $"Invalid value at position {i + 1}: {text}"); } list.Add(item); } try { bool num = IsSetType(collectionType); bool flag = IsListType(collectionType); bool flag2 = typeof(ICollection).IsAssignableFrom(collectionType); bool flag3 = typeof(IEnumerable).IsAssignableFrom(collectionType); object obj; if (num || (flag3 && !flag && collectionType.GetConstructor(Type.EmptyTypes) != null)) { Type type = typeof(HashSet<>).MakeGenericType(elementType); obj = Activator.CreateInstance(type); MethodInfo method = type.GetMethod("Add"); foreach (object item2 in list) { method.Invoke(obj, new object[1] { item2 }); } } else if (flag || (flag2 && collectionType.GetConstructor(Type.EmptyTypes) != null)) { Type type2 = typeof(List<>).MakeGenericType(elementType); obj = Activator.CreateInstance(type2); MethodInfo method2 = type2.GetMethod("Add"); foreach (object item3 in list) { method2.Invoke(obj, new object[1] { item3 }); } } else { if (!collectionType.IsAssignableFrom(typeof(List<>).MakeGenericType(elementType))) { return (null, "Cannot instantiate collection type '" + collectionType.Name + "'"); } Type type3 = typeof(List<>).MakeGenericType(elementType); obj = Activator.CreateInstance(type3); MethodInfo method3 = type3.GetMethod("Add"); foreach (object item4 in list) { method3.Invoke(obj, new object[1] { item4 }); } } return (obj, null); } catch (Exception ex) { return (null, "Failed to create collection: " + ex.Message); } } private static (object result, string error) ParseValue(Type targetType, string valueString) { if (string.IsNullOrWhiteSpace(valueString)) { return (null, "Empty value"); } valueString = valueString.Trim(); if (targetType.IsEnum) { try { return (Enum.Parse(targetType, valueString, ignoreCase: true), null); } catch { string text = string.Join(", ", Enum.GetNames(targetType)); return (null, "Invalid enum value. Expected one of: " + text); } } (object value, string error) tuple = EventArgumentParser.TryParseScalar(targetType, valueString); var (item, _) = tuple; if (tuple.error == null) { return (item, null); } return (null, "Cannot convert '" + valueString + "' to " + targetType.Name); } public static bool IsCollectionType(Type type) { if (type == null) { return false; } if (type.IsArray) { return true; } if (typeof(IEnumerable).IsAssignableFrom(type)) { if (type.IsGenericType) { Type genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(HashSet<>) || genericTypeDefinition == typeof(List<>) || genericTypeDefinition == typeof(IList<>) || genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) { return true; } } if (typeof(ICollection).IsAssignableFrom(type) && type.GetConstructor(Type.EmptyTypes) != null) { return true; } } return false; } public static Type GetElementType(Type collectionType) { if (collectionType == null) { return null; } if (collectionType.IsArray) { return collectionType.GetElementType(); } if (collectionType.IsGenericType) { Type[] genericArguments = collectionType.GetGenericArguments(); if (genericArguments.Length != 0) { return genericArguments[0]; } } Type[] interfaces = collectionType.GetInterfaces(); foreach (Type type in interfaces) { if (!type.IsGenericType) { continue; } Type genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(IEnumerable<>) || genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IList<>)) { Type[] genericArguments2 = type.GetGenericArguments(); if (genericArguments2.Length != 0) { return genericArguments2[0]; } } } return null; } private static bool IsSetType(Type type) { if (type == null) { return false; } if (type.IsGenericType) { Type genericTypeDefinition = type.GetGenericTypeDefinition(); if (!(genericTypeDefinition == typeof(HashSet<>))) { return genericTypeDefinition == typeof(ISet<>); } return true; } return false; } private static bool IsListType(Type type) { if (type == null) { return false; } if (type.IsGenericType) { Type genericTypeDefinition = type.GetGenericTypeDefinition(); if (!(genericTypeDefinition == typeof(List<>)) && !(genericTypeDefinition == typeof(IList<>))) { return genericTypeDefinition == typeof(IList<>); } return true; } return typeof(IList).IsAssignableFrom(type); } } public static class EventArgumentParser { private static readonly HashSet WhitelistedScalarTypes = new HashSet { typeof(string), typeof(int), typeof(float), typeof(bool), typeof(double), typeof(long), typeof(decimal), typeof(char) }; public static bool CanParse(Type type) { if (type == null) { return false; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { return CanParse(Nullable.GetUnderlyingType(type)); } if (WhitelistedScalarTypes.Contains(type)) { return true; } if (type.IsEnum) { return true; } if (CollectionValueParser.IsCollectionType(type)) { Type elementType = CollectionValueParser.GetElementType(type); if (elementType != null) { return CanParseScalar(elementType); } return false; } return false; } private static bool CanParseScalar(Type type) { if (type == null) { return false; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { return CanParseScalar(Nullable.GetUnderlyingType(type)); } if (WhitelistedScalarTypes.Contains(type)) { return true; } if (type.IsEnum) { return true; } return false; } public static bool IsEventPublishable(EventDefinition eventDef, out string unsupportedParam) { unsupportedParam = null; object obj; if (eventDef == null) { obj = null; } else { EventSchema schema = eventDef.Schema; obj = ((schema != null) ? schema.Fields : null); } if (obj == null) { return true; } foreach (KeyValuePair field in eventDef.Schema.Fields) { if (!CanParse(field.Value)) { unsupportedParam = field.Key; return false; } } return true; } public static (bool success, object value, string error) TryParseWithDetails(Type targetType, string valueString) { if (targetType == null) { return (false, null, "Target type is null"); } if (string.IsNullOrEmpty(valueString)) { return (false, null, "Value is null or empty"); } if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>)) { return TryParseWithDetails(Nullable.GetUnderlyingType(targetType), valueString); } if (CollectionValueParser.IsCollectionType(targetType)) { var (item, text) = CollectionValueParser.TryParse(targetType, valueString); return (text == null, item, text); } var (item2, text2) = TryParseScalar(targetType, valueString); return (text2 == null, item2, text2); } public static bool TryParse(Type targetType, string value, out object result) { result = null; if (value == null) { return false; } var (flag, obj, _) = TryParseWithDetails(targetType, value); if (flag) { result = obj; return true; } return false; } internal static (object value, string error) TryParseScalar(Type targetType, string valueString) { if (string.IsNullOrWhiteSpace(valueString)) { return (null, "Empty value"); } valueString = valueString.Trim(); if (targetType == typeof(string)) { return (valueString, null); } if (targetType == typeof(int)) { if (int.TryParse(valueString, out var result)) { return (result, null); } return (null, "Cannot convert '" + valueString + "' to int"); } if (targetType == typeof(float)) { if (float.TryParse(valueString, out var result2)) { return (result2, null); } return (null, "Cannot convert '" + valueString + "' to float"); } if (targetType == typeof(double)) { if (double.TryParse(valueString, out var result3)) { return (result3, null); } return (null, "Cannot convert '" + valueString + "' to double"); } if (targetType == typeof(long)) { if (long.TryParse(valueString, out var result4)) { return (result4, null); } return (null, "Cannot convert '" + valueString + "' to long"); } if (targetType == typeof(decimal)) { if (decimal.TryParse(valueString, out var result5)) { return (result5, null); } return (null, "Cannot convert '" + valueString + "' to decimal"); } if (targetType == typeof(bool)) { switch (valueString.ToLowerInvariant()) { case "true": case "1": case "yes": case "on": return (true, null); case "false": case "0": case "no": case "off": return (false, null); default: return (null, "Cannot convert '" + valueString + "' to bool. Expected: true/false, 1/0, yes/no, on/off"); } } if (targetType == typeof(char)) { if (char.TryParse(valueString, out var result6)) { return (result6, null); } return (null, "Cannot convert '" + valueString + "' to char"); } if (targetType.IsEnum) { try { return (Enum.Parse(targetType, valueString, ignoreCase: true), null); } catch { string text = string.Join(", ", Enum.GetNames(targetType)); return (null, "Invalid enum value. Expected one of: " + text); } } return (null, "Cannot parse type " + targetType.Name); } } public static class EventBusHelpers { public static IReadOnlyDictionary> GetRegisteredEvents() { return EventBus.GetRegisteredEvents(); } public static bool TryGetEvent(string modNamespace, string eventName, out EventDefinition eventDef) { eventDef = null; IReadOnlyDictionary> registeredEvents = GetRegisteredEvents(); if (registeredEvents == null) { return false; } if (!registeredEvents.TryGetValue(modNamespace, out var value)) { return false; } return value.TryGetValue(eventName, out eventDef); } public static bool TryFindEvent(string eventName, out string foundNamespace, out EventDefinition eventDef) { eventDef = null; foundNamespace = null; IReadOnlyDictionary> registeredEvents = GetRegisteredEvents(); if (registeredEvents == null) { return false; } foreach (KeyValuePair> item in registeredEvents) { if (item.Value.TryGetValue(eventName, out eventDef)) { foundNamespace = item.Key; return true; } } return false; } public static void SendEventNotFound(ChatPanel panel, string modNamespace, string eventName) { ChatHelpers.SendChatLog(panel, "Event '" + eventName + "' not found in mod '" + modNamespace + "'", ChatLogStatus.Error); } public static void SendModNotFound(ChatPanel panel, string modNamespace) { ChatHelpers.SendChatLog(panel, "Mod '" + modNamespace + "' not found", ChatLogStatus.Error); } public static void SendMissingParams(ChatPanel panel) { ChatHelpers.SendChatLog(panel, "Missing --mod or --event parameter. Usage: /event --mod= --event=", ChatLogStatus.Warning); } public static void SendEventInfo(ChatPanel panel, string modNamespace, string eventName, EventDefinition eventDef) { ChatHelpers.SendChatLog(panel, modNamespace + "." + eventName, ChatLogStatus.Success); string text = (string.IsNullOrEmpty(eventDef.Description) ? "(no description)" : eventDef.Description); ChatHelpers.SendChatLog(panel, "Description: " + text); if (eventDef.Schema.Fields.Count > 0) { ChatHelpers.SendChatLog(panel, "Parameters:"); { foreach (KeyValuePair field in eventDef.Schema.Fields) { string text2 = eventDef.Schema.GetDescription(field.Key) ?? "(no description)"; ChatHelpers.SendChatLog(panel, " - " + field.Key + " (" + GetTypeName(field.Value) + "): " + text2); } return; } } ChatHelpers.SendChatLog(panel, "No parameters defined."); } private static string GetTypeName(Type type) { if (type == null) { return "Unknown"; } if (type.IsGenericType) { string obj = type.Name.Split(new char[1] { '`' })[0]; string text = string.Join(", ", from t in type.GetGenericArguments() select t.Name); return obj + "<" + text + ">"; } return type.Name; } } public static class GenericTypeParser { private static readonly Dictionary SimpleTypeMap = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "string", typeof(string) }, { "int", typeof(int) }, { "bool", typeof(bool) }, { "float", typeof(float) }, { "double", typeof(double) }, { "decimal", typeof(decimal) }, { "long", typeof(long) }, { "short", typeof(short) }, { "byte", typeof(byte) }, { "char", typeof(char) }, { "object", typeof(object) }, { "void", typeof(void) }, { "hashset", typeof(HashSet<>) }, { "list", typeof(List<>) }, { "dictionary", typeof(Dictionary<, >) }, { "queue", typeof(Queue<>) }, { "stack", typeof(Stack<>) }, { "set", typeof(HashSet<>) } }; public static Type Parse(string typeString) { if (string.IsNullOrWhiteSpace(typeString)) { return null; } typeString = typeString.Trim(); int num = typeString.IndexOf('['); int num2 = typeString.IndexOf('<'); if (num >= 0 && (num2 < 0 || num < num2)) { return ParseArrayType(typeString); } if (num2 >= 0) { return ParseGenericType(typeString); } return ParseSimpleType(typeString); } private static Type ParseArrayType(string typeString) { int num = typeString.IndexOf('['); if (num < 0) { return null; } string typeString2 = typeString.Substring(0, num); string text = typeString.Substring(num); Type type = Parse(typeString2); if (type == null) { return null; } if (text == "[]") { return type.MakeArrayType(); } int num2 = 1; for (int i = 1; i < text.Length; i++) { if (text[i] == ',') { num2++; } } return type.MakeArrayType(num2); } private static Type ParseGenericType(string typeString) { int num = typeString.IndexOf('<'); int num2 = typeString.LastIndexOf('>'); if (num < 0 || num2 < 0 || num2 <= num) { return null; } string typeName = typeString.Substring(0, num); List list = ParseGenericArguments(typeString.Substring(num + 1, num2 - num - 1)); if (list == null || list.Count == 0) { return null; } Type type = ParseSimpleType(typeName); if (type == null) { return null; } try { return type.MakeGenericType(list.ToArray()); } catch (Exception) { return null; } } private static List ParseGenericArguments(string argsString) { List list = new List(); int num = 0; int num2 = 0; for (int i = 0; i <= argsString.Length; i++) { switch ((i < argsString.Length) ? argsString[i] : ',') { case '<': case '[': num++; break; case '>': case ']': num--; break; case ',': { if (num != 0) { break; } string text = argsString.Substring(num2, i - num2).Trim(); if (!string.IsNullOrEmpty(text)) { Type type = Parse(text); if (type == null) { return null; } list.Add(type); } num2 = i + 1; break; } } } if (num2 < argsString.Length) { string text2 = argsString.Substring(num2).Trim(); if (!string.IsNullOrEmpty(text2)) { Type type2 = Parse(text2); if (type2 == null) { return null; } list.Add(type2); } } return list; } private static Type ParseSimpleType(string typeName) { if (string.IsNullOrWhiteSpace(typeName)) { return null; } typeName = typeName.Trim(); if (SimpleTypeMap.TryGetValue(typeName, out var value)) { return value; } if (typeName.EndsWith("?")) { Type type = ParseSimpleType(typeName.Substring(0, typeName.Length - 1)); if (type != null) { return typeof(Nullable<>).MakeGenericType(type); } return null; } return FindTypeInAssemblies(typeName); } private static Type FindTypeInAssemblies(string typeName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); if (Enumerable.Contains(typeName, '.') || Enumerable.Contains(typeName, '+')) { Type type = TryResolveNestedClass(typeName); if (type != null) { return type; } } Assembly[] array = assemblies; foreach (Assembly assembly in array) { try { Type type2 = assembly.GetType(typeName, throwOnError: false, ignoreCase: true); if (type2 != null) { return type2; } } catch { } } array = assemblies; foreach (Assembly assembly2 in array) { try { string name = typeName; int num = typeName.LastIndexOf('.'); if (num >= 0) { name = typeName.Substring(num + 1); } Type type3 = assembly2.GetType(name, throwOnError: false, ignoreCase: true); if (type3 != null) { return type3; } } catch { } } array = assemblies; foreach (Assembly assembly3 in array) { try { Type[] types = assembly3.GetTypes(); foreach (Type type4 in types) { if (string.Equals(type4.Name, typeName, StringComparison.OrdinalIgnoreCase) || string.Equals(type4.FullName, typeName, StringComparison.OrdinalIgnoreCase)) { return type4; } } } catch { } } return null; } private static Type TryResolveNestedClass(string typeName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); List list = new List(); list.Add(typeName); if (Enumerable.Contains(typeName, '.')) { string[] array = typeName.Split(new char[1] { '.' }); for (int i = 1; i < array.Length; i++) { string item = string.Join(".", array, 0, array.Length - i) + "+" + string.Join("+", array, array.Length - i, i); if (!list.Contains(item)) { list.Add(item); } } list.Add(typeName.Replace(".", "+")); } if (Enumerable.Contains(typeName, '+')) { string item2 = typeName.Replace("+", "."); if (!list.Contains(item2)) { list.Add(item2); } string[] array2 = typeName.Split(new char[1] { '+' }); for (int j = 1; j < array2.Length; j++) { string item3 = string.Join("+", array2, 0, array2.Length - j) + "." + string.Join(".", array2, array2.Length - j, j); if (!list.Contains(item3)) { list.Add(item3); } } } Assembly[] array3 = assemblies; foreach (Assembly assembly in array3) { try { foreach (string item4 in list) { try { Type type = assembly.GetType(item4, throwOnError: false, ignoreCase: true); if (type != null) { return type; } } catch { } } } catch { } } array3 = assemblies; foreach (Assembly assembly2 in array3) { try { Type[] types = assembly2.GetTypes(); foreach (Type type2 in types) { string fullName = type2.FullName; if (fullName != null) { string a = (Enumerable.Contains(fullName, '+') ? fullName.Substring(fullName.LastIndexOf('+') + 1) : (Enumerable.Contains(fullName, '.') ? fullName.Substring(fullName.LastIndexOf('.') + 1) : fullName)); string b = (Enumerable.Contains(typeName, '+') ? typeName.Substring(typeName.LastIndexOf('+') + 1) : (Enumerable.Contains(typeName, '.') ? typeName.Substring(typeName.LastIndexOf('.') + 1) : typeName)); if (string.Equals(a, b, StringComparison.OrdinalIgnoreCase)) { return type2; } } } } catch { } } return null; } public static bool IsGenericType(string typeString) { if (!string.IsNullOrWhiteSpace(typeString) && Enumerable.Contains(typeString, '<')) { return Enumerable.Contains(typeString, '>'); } return false; } public static bool IsArrayType(string typeString) { if (!string.IsNullOrWhiteSpace(typeString) && Enumerable.Contains(typeString, '[')) { return Enumerable.Contains(typeString, ']'); } return false; } } } namespace OutwardModsCommunicatorChatControl.Utility.Enums { public enum ChatCommandsManagerParams { CommandName, CommandParameters, CommandAction, IsCheatCommand, CommandDescription, CommandRequiresDebugMode } public static class ChatCommandsManagerParamsHelper { private static readonly Dictionary _registry = new Dictionary { [ChatCommandsManagerParams.CommandName] = ("command", typeof(string)), [ChatCommandsManagerParams.CommandParameters] = ("parameters", typeof(Dictionary)), [ChatCommandsManagerParams.CommandAction] = ("function", typeof(Action>)), [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 => "" + message + "", _ => message, }; } } } namespace OutwardModsCommunicatorChatControl.Tests { public static class EventArgumentParserTests { public static void RunAllTests() { try { OMCCC.LogMessage("[TEST] Starting EventArgumentParser tests..."); TestScalarInt(); TestScalarFloat(); TestScalarBool(); TestScalarString(); TestScalarChar(); TestScalarEnum(); TestArrayInt(); TestArrayString(); TestArrayEnum(); TestListInt(); TestHashSetInt(); TestIEnumerableInt(); TestScalarIntError(); TestArrayIntError(); TestEnumError(); OMCCC.LogMessage("[TEST] All EventArgumentParser tests completed successfully!"); } catch (Exception ex) { OMCCC.LogMessage("[TEST ERROR] Test suite failed: " + ex.Message + "\n" + ex.StackTrace); } } private static void TestScalarInt() { var (condition, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(int), "42"); Assert(condition, "int parsing should succeed"); Assert(obj is int && (int)obj == 42, "int value should be 42"); OMCCC.LogMessage("[PASS] Scalar int test"); } private static void TestScalarFloat() { var (condition, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(float), "3.14"); Assert(condition, "float parsing should succeed"); Assert(obj is float && Math.Abs((float)obj - 3.14f) < 0.01f, "float value should be ~3.14"); OMCCC.LogMessage("[PASS] Scalar float test"); } private static void TestScalarBool() { var (flag, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(bool), "true"); Assert(flag && (bool)obj, "bool 'true' should parse"); var (flag2, obj2, _) = EventArgumentParser.TryParseWithDetails(typeof(bool), "yes"); Assert(flag2 && (bool)obj2, "bool 'yes' should parse"); var (flag3, obj3, _) = EventArgumentParser.TryParseWithDetails(typeof(bool), "false"); Assert(flag3 && !(bool)obj3, "bool 'false' should parse"); var (flag4, obj4, _) = EventArgumentParser.TryParseWithDetails(typeof(bool), "0"); Assert(flag4 && !(bool)obj4, "bool '0' should parse as false"); OMCCC.LogMessage("[PASS] Scalar bool test"); } private static void TestScalarString() { var (flag, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(string), "hello"); Assert(flag && (string)obj == "hello", "string parsing should succeed"); OMCCC.LogMessage("[PASS] Scalar string test"); } private static void TestScalarChar() { var (flag, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(char), "A"); Assert(flag && (char)obj == 'A', "char parsing should succeed"); OMCCC.LogMessage("[PASS] Scalar char test"); } private static void TestScalarEnum() { var (flag, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(DayOfWeek), "Monday"); Assert(flag && (DayOfWeek)obj == DayOfWeek.Monday, "enum parsing should succeed"); var (flag2, obj2, _) = EventArgumentParser.TryParseWithDetails(typeof(DayOfWeek), "monday"); Assert(flag2 && (DayOfWeek)obj2 == DayOfWeek.Monday, "enum parsing should be case-insensitive"); OMCCC.LogMessage("[PASS] Scalar enum test"); } private static void TestArrayInt() { var (condition, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(int[]), "1 2 3"); Assert(condition, "int array parsing should succeed"); Assert(obj is int[] array && array.Length == 3 && array[0] == 1 && array[1] == 2 && array[2] == 3, "int array should be [1,2,3]"); OMCCC.LogMessage("[PASS] Array int test"); } private static void TestArrayString() { var (condition, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(string[]), "hello world test"); Assert(condition, "string array parsing should succeed"); Assert(obj is string[] array && array.Length == 3 && array[0] == "hello" && array[1] == "world" && array[2] == "test", "string array should be correct"); OMCCC.LogMessage("[PASS] Array string test"); } private static void TestArrayEnum() { var (condition, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(DayOfWeek[]), "Monday Wednesday Friday"); Assert(condition, "enum array parsing should succeed"); Assert(obj is DayOfWeek[] array && array.Length == 3 && array[0] == DayOfWeek.Monday && array[1] == DayOfWeek.Wednesday, "enum array should be correct"); OMCCC.LogMessage("[PASS] Array enum test"); } private static void TestListInt() { var (condition, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(List), "10 20 30"); Assert(condition, "List parsing should succeed"); Assert(obj is List list && list.Count == 3 && list[0] == 10 && list[1] == 20, "List should contain correct values"); OMCCC.LogMessage("[PASS] Collection List test"); } private static void TestHashSetInt() { var (condition, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(HashSet), "5 10 15"); Assert(condition, "HashSet parsing should succeed"); Assert(obj is HashSet hashSet && hashSet.Count == 3 && hashSet.Contains(5) && hashSet.Contains(10), "HashSet should contain correct values"); OMCCC.LogMessage("[PASS] Collection HashSet test"); } private static void TestIEnumerableInt() { var (condition, obj, _) = EventArgumentParser.TryParseWithDetails(typeof(IEnumerable), "7 8 9"); Assert(condition, "IEnumerable parsing should succeed"); Assert(obj != null, "IEnumerable should not be null"); List list = ((IEnumerable)obj).ToList(); Assert(list.Count == 3 && list[0] == 7 && list[1] == 8, "IEnumerable should contain correct values"); OMCCC.LogMessage("[PASS] Collection IEnumerable test"); } private static void TestScalarIntError() { var (flag, _, text) = EventArgumentParser.TryParseWithDetails(typeof(int), "abc"); Assert(!flag, "int parsing of 'abc' should fail"); Assert(text != null && !string.IsNullOrEmpty(text), "error message should be provided"); OMCCC.LogMessage("[PASS] Scalar int error test (error: " + text + ")"); } private static void TestArrayIntError() { var (flag, _, text) = EventArgumentParser.TryParseWithDetails(typeof(int[]), "1 2 abc 4"); Assert(!flag, "int array parsing with invalid element should fail"); Assert(text?.Contains("position") ?? false, "error should indicate position"); OMCCC.LogMessage("[PASS] Array int error test (error: " + text + ")"); } private static void TestEnumError() { var (flag, _, text) = EventArgumentParser.TryParseWithDetails(typeof(DayOfWeek), "InvalidDay"); Assert(!flag, "enum parsing of invalid value should fail"); Assert(text?.Contains("Expected one of") ?? false, "error should list valid options"); OMCCC.LogMessage("[PASS] Enum error test (error: " + text + ")"); } private static void Assert(bool condition, string message) { if (!condition) { throw new Exception("Assertion failed: " + message); } } } } namespace OutwardModsCommunicatorChatControl.Managers { public class PathsManager { private static PathsManager _instance; public string configPath = ""; public string xmlFilePath = ""; public static PathsManager Instance { get { if (_instance == null) { _instance = new PathsManager(); } return _instance; } } private PathsManager() { configPath = Path.Combine(PathsManager.ConfigPath, "Chat_Commands_Template"); xmlFilePath = Path.Combine(configPath, "MyDocument.xml"); } } } namespace OutwardModsCommunicatorChatControl.Events { 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() { ListEventsPublisher.SendListEventsCommand(); GetEventPublisher.SendGetEventCommand(); PublishEventPublisher.SendPublishCommand(); } } public static class EventBusRegister { public static void RegisterEvents() { } } public static class EventBusSubscriber { public const string Event_AddedChatCommand = "ChatCommandsManager@AddChatCommand_After"; public const string Event_RemovedChatCommand = "ChatCommandsManager@RemoveChatCommand_After"; public static void AddSubscribers() { EventBus.Subscribe("gymmed.chat_commands_manager_*", "ChatCommandsManager@AddChatCommand_After", (Action)AddedChatCommand); EventBus.Subscribe("gymmed.chat_commands_manager_*", "ChatCommandsManager@RemoveChatCommand_After", (Action)RemovedChatCommand); } public static void AddedChatCommand(EventPayload payload) { if (payload != null) { (string, Type) tuple = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandName); payload.Get(tuple.Item1, (string)null); OMCCC.LogMessage("Added command " + tuple.Item1); } } public static void RemovedChatCommand(EventPayload payload) { if (payload != null) { (string, Type) tuple = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandName); payload.Get(tuple.Item1, (string)null); OMCCC.LogMessage("Removed command " + tuple.Item1); } } } } namespace OutwardModsCommunicatorChatControl.Events.Publishers { public static class GetEventPublisher { public static void SendGetEventCommand() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_009f: Expected O, but got Unknown Action> value = TriggerFunction; EventPayload val = new EventPayload { }; string item; ((Dictionary)val)[item] = "event"; string item2 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandParameters).key; ((Dictionary)val)[item2] = new Dictionary { { "mod", ("Mod namespace (optional if searching all mods).", null) }, { "event", ("Event name to look up.", null) } }; string item3 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandAction).key; ((Dictionary)val)[item3] = value; string item4 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandDescription).key; ((Dictionary)val)[item4] = "Gets detailed information about a specific event, including proper type information for collections (HashSet, List, arrays), enums, and other supported types."; EventPayload val2 = val; EventBus.Publish("gymmed.chat_commands_manager_*", "ChatCommandsManager@AddChatCommand", val2); } public static void TriggerFunction(Character caller, Dictionary 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) { OMCCC.LogMessage("GetEventPublisher@TriggerFunction: No chat panel found"); return; } arguments.TryGetValue("mod", out var value); arguments.TryGetValue("event", out var value2); if (string.IsNullOrEmpty(value2)) { EventBusHelpers.SendMissingParams(val); return; } EventDefinition eventDef; string foundNamespace; if (!string.IsNullOrEmpty(value)) { if (!EventBusHelpers.TryGetEvent(value, value2, out eventDef)) { EventBusHelpers.SendEventNotFound(val, value, value2); return; } foundNamespace = value; } else if (!EventBusHelpers.TryFindEvent(value2, out foundNamespace, out eventDef)) { ChatHelpers.SendChatLog(val, "Event '" + value2 + "' not found in any mod", ChatLogStatus.Error); return; } EventBusHelpers.SendEventInfo(val, foundNamespace, value2, eventDef); } } public static class ListEventsPublisher { public static void SendListEventsCommand() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0036: 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_0072: Expected O, but got Unknown //IL_0073: Expected O, but got Unknown Action> value = TriggerFunction; EventPayload val = new EventPayload { }; string item; ((Dictionary)val)[item] = "events"; string item2 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandParameters).key; ((Dictionary)val)[item2] = new Dictionary(); string item3 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandAction).key; ((Dictionary)val)[item3] = value; string item4 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandDescription).key; ((Dictionary)val)[item4] = "Lists all registered events from OutwardModsCommunicator."; EventPayload val2 = val; EventBus.Publish("gymmed.chat_commands_manager_*", "ChatCommandsManager@AddChatCommand", val2); } public static void TriggerFunction(Character caller, Dictionary 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) { OMCCC.LogMessage("ListEventsPublisher@TriggerFunction: No chat panel found"); return; } IReadOnlyDictionary> registeredEvents = EventBusHelpers.GetRegisteredEvents(); if (registeredEvents == null || registeredEvents.Count == 0) { ChatHelpers.SendChatLog(val, "0 events registered"); return; } int num = registeredEvents.Values.Sum((Dictionary modEvents) => modEvents.Count); ChatHelpers.SendChatLog(val, $"{num} events registered", ChatLogStatus.Success); foreach (KeyValuePair> item in registeredEvents) { ChatHelpers.SendChatLog(val, "Mod: " + item.Key); foreach (KeyValuePair item2 in item.Value) { string key = item2.Key; string text = (string.IsNullOrEmpty(item2.Value.Description) ? "(no description)" : item2.Value.Description); ChatHelpers.SendChatLog(val, " - " + key + ": " + text); } } } } public static class PublishEventPublisher { public static void SendPublishCommand() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //IL_00ba: Expected O, but got Unknown Action> value = TriggerFunction; EventPayload val = new EventPayload { }; string item; ((Dictionary)val)[item] = "publish"; string item2 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandParameters).key; ((Dictionary)val)[item2] = new Dictionary { { "mod", ("Mod namespace (optional if searching all mods).", null) }, { "event", ("Event name.", null) } }; string item3 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandAction).key; ((Dictionary)val)[item3] = value; string item4 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandDescription).key; ((Dictionary)val)[item4] = "Publishes an event to OutwardModsCommunicator with proper type casting for collections (HashSet, List, arrays), enums, and other types. Usage: /publish [mod] event [--param=value...]"; string item5 = ChatCommandsManagerParamsHelper.Get(ChatCommandsManagerParams.CommandRequiresDebugMode).key; ((Dictionary)val)[item5] = true; EventPayload val2 = val; EventBus.Publish("gymmed.chat_commands_manager_*", "ChatCommandsManager@AddChatCommand", val2); } public static void TriggerFunction(Character caller, Dictionary arguments) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown 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) { OMCCC.LogMessage("PublishEventPublisher@TriggerFunction: No chat panel found"); return; } arguments.TryGetValue("mod", out var value); arguments.TryGetValue("event", out var value2); if (string.IsNullOrEmpty(value2)) { SendUsageError(val); return; } EventDefinition eventDef; string foundNamespace; if (!string.IsNullOrEmpty(value)) { if (!EventBusHelpers.TryGetEvent(value, value2, out eventDef)) { ChatHelpers.SendChatLog(val, "Event '" + value2 + "' not found in mod '" + value + "'", ChatLogStatus.Error); return; } foundNamespace = value; } else if (!EventBusHelpers.TryFindEvent(value2, out foundNamespace, out eventDef)) { ChatHelpers.SendChatLog(val, "Event '" + value2 + "' not found in any mod", ChatLogStatus.Error); return; } EventPayload val2 = new EventPayload(); List list = new List(); EventSchema schema = eventDef.Schema; Dictionary.KeyCollection source = ((schema == null) ? null : schema.Fields?.Keys) ?? new Dictionary().Keys; foreach (KeyValuePair argument in arguments) { string key = argument.Key; string value3 = argument.Value; if (key == "mod" || key == "event") { continue; } if (source.Contains(key)) { Type type = eventDef.Schema.Fields[key]; var (flag, value4, text) = EventArgumentParser.TryParseWithDetails(type, value3); if (flag) { ((Dictionary)(object)val2)[key] = value4; continue; } list.Add("Parameter '" + key + "' (" + type.Name + "): " + (text ?? "Unknown error")); } else { object obj2 = TryAutoDetectAndParse(value3); if (obj2 != null) { ((Dictionary)(object)val2)[key] = obj2; ChatHelpers.SendChatLog(val, "Dynamic parameter '" + key + "' auto-detected as " + obj2.GetType().Name); } } } if (list.Count > 0) { foreach (string item in list) { ChatHelpers.SendChatLog(val, item, ChatLogStatus.Error); } return; } EventBus.Publish(foundNamespace, value2, val2); ChatHelpers.SendChatLog(val, "Published event '" + foundNamespace + "." + value2 + "'", ChatLogStatus.Success); } private static object TryAutoDetectAndParse(string valueString) { if (string.IsNullOrWhiteSpace(valueString)) { return null; } valueString = valueString.Trim(); string[] array = valueString.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length > 1) { if (array.All((string p) => int.TryParse(p, out var _))) { int[] array2 = new int[array.Length]; for (int i = 0; i < array.Length; i++) { int.TryParse(array[i], out array2[i]); } return array2; } return array; } if (int.TryParse(valueString, out var result)) { return result; } if (bool.TryParse(valueString, out var result2)) { return result2; } return valueString; } private static void SendUsageError(ChatPanel panel) { ChatHelpers.SendChatLog(panel, "Missing --event parameter. Usage: /publish [--param=value...]", ChatLogStatus.Warning); } } }