using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using HarmonyLib; using MelonLoader; using SledChatEmojis; using SledChatEmojis.Util; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("SledChatEmojis")] [assembly: AssemblyFileVersion("0.1.0")] [assembly: MelonInfo(typeof(Mod), "SledChatEmojis", "0.1.0", "Natebag", null)] [assembly: MelonGame("The Sledding Corporation", "Sledding Game")] [assembly: MelonColor(255, 0, 255, 102)] [assembly: MelonAuthorColor(255, 80, 160, 255)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyVersion("0.1.0.0")] namespace SledChatEmojis { public sealed class Mod : MelonMod { public const string Name = "SledChatEmojis"; public const string Version = "0.1.0"; public const string Author = "Natebag"; private static readonly Dictionary Map = new Dictionary { { ":smile:", ":)" }, { ":grin:", ":D" }, { ":joy:", "xD" }, { ":rofl:", "xDDD" }, { ":sob:", ":'(" }, { ":cry:", ":(" }, { ":angry:", ">:(" }, { ":sunglasses:", "B)" }, { ":tongue:", ":P" }, { ":wink:", ";)" }, { ":heart:", "<3" }, { ":broken:", "<(((*>" }, { ":whale:", ".'(\\" }, { ":mountain:", "/^^^\\" }, { ":pumpkin:", "{O_O}" }, { ":party:", "\\(^o^)/" }, { ":skull:", "x_x" }, { ":poop:", "(_!_)" }, { ":fingerguns:", "(>'.')>" }, { ":shrug:", "\\_(--)_/" }, { ":lenny:", "( . Y . )" }, { ":table:", "(.□.)__" } }; public override void OnInitializeMelon() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown SafeLog.Bind(((MelonBase)this).LoggerInstance); try { Harmony val = new Harmony("Natebag.SledChatEmojis"); Type type = Refl.FindType("Assembly-CSharp", "_Scripts.Systems.Chat.ChatManager"); if (type == null) { ((MelonBase)this).LoggerInstance.Warning("SledChatEmojis: ChatManager type not found"); return; } MethodInfo method = type.GetMethod("SendChatMessage", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null); if (method == null) { ((MelonBase)this).LoggerInstance.Warning("SledChatEmojis: SendChatMessage method not found. Dumping ChatManager methods:"); MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { ((MelonBase)this).LoggerInstance.Warning($" - {methodInfo.ReturnType.Name} {methodInfo.Name}({string.Join(", ", Array.ConvertAll(methodInfo.GetParameters(), (ParameterInfo p) => p.ParameterType.Name + " " + p.Name))})"); } } else { MethodInfo method2 = typeof(Mod).GetMethod("SendChatMessage_Prefix", BindingFlags.Static | BindingFlags.NonPublic); val.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((MelonBase)this).LoggerInstance.Msg($"SledChatEmojis v{"0.1.0"} ready — {Map.Count} shortcodes installed."); } } catch (Exception value) { ((MelonBase)this).LoggerInstance.Error($"SledChatEmojis init failed: {value}"); } } private static void SendChatMessage_Prefix(ref string cleanedString) { try { if (string.IsNullOrEmpty(cleanedString)) { return; } foreach (KeyValuePair item in Map) { cleanedString = cleanedString.Replace(item.Key, item.Value); } } catch { } } } } namespace SledChatEmojis.Util { internal static class Refl { private static readonly Dictionary _typeCache = new Dictionary(); private static bool _loggedAssemblies = false; private static MethodInfo _il2cppCastGeneric; public static Type FindType(string assemblyHint, string fullName) { if (_typeCache.TryGetValue(fullName, out var value)) { return value; } try { string[] array = new string[2] { fullName, "Il2Cpp." + fullName }; string[] array2 = new string[3] { assemblyHint, "Il2Cpp" + assemblyHint, assemblyHint + "-firstpass" }; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { string name = assembly.GetName().Name; string[] array3 = array2; foreach (string text in array3) { if (name != text) { continue; } string[] array4 = array; foreach (string name2 in array4) { Type type = assembly.GetType(name2); if (type != null) { _typeCache[fullName] = type; return type; } } } } assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly2 in assemblies) { string[] array3 = array; foreach (string name3 in array3) { Type type2; try { type2 = assembly2.GetType(name3); } catch { continue; } if (type2 != null) { _typeCache[fullName] = type2; return type2; } } } assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly3 in assemblies) { Type[] types; try { types = assembly3.GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types; } catch { continue; } string text2 = fullName; int num = fullName.LastIndexOf('.'); if (num >= 0 && num < fullName.Length - 1) { text2 = fullName.Substring(num + 1); } Type[] array5 = types; foreach (Type type3 in array5) { if (!(type3 == null) && (type3.FullName == fullName || type3.FullName == "Il2Cpp." + fullName || (type3.FullName != null && type3.FullName.EndsWith("." + fullName)) || type3.Name == fullName || type3.Name == text2)) { _typeCache[fullName] = type3; SafeLog.Info($"Refl.FindType: '{fullName}' resolved via full scan as '{type3.FullName}' in {assembly3.GetName().Name}"); return type3; } } } if (!_loggedAssemblies) { SafeLog.Warn("Refl.FindType: '" + fullName + "' not found. Loaded assemblies:"); assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly4 in assemblies) { SafeLog.Warn(" - " + assembly4.GetName().Name); } _loggedAssemblies = true; } return null; } catch (Exception ex2) { SafeLog.Error($"Refl.FindType({assemblyHint},{fullName})", ex2); return null; } } public static MethodInfo Method(Type t, string name, params Type[] argTypes) { if (t == null) { return null; } try { BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; if (argTypes.Length == 0) { MethodInfo[] methods = t.GetMethods(bindingAttr); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == name) { return methodInfo; } } return null; } return t.GetMethod(name, bindingAttr, null, argTypes, null); } catch (Exception ex) { SafeLog.Error($"Refl.Method({t.Name}.{name})", ex); return null; } } public static FieldInfo Field(Type t, string name) { if (t == null) { return null; } try { return t.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch (Exception ex) { SafeLog.Error($"Refl.Field({t.Name}.{name})", ex); return null; } } public static object CastToIl2Cpp(object obj, Type targetType) { if (obj == null || targetType == null) { return null; } if (targetType.IsInstanceOfType(obj)) { return obj; } try { if (_il2cppCastGeneric == null) { Type type = FindType("Il2CppInterop.Runtime", "Il2CppInterop.Runtime.InteropTypes.Il2CppObjectBase"); if (type == null) { type = obj.GetType(); } while (type != null) { MethodInfo method = type.GetMethod("Cast", BindingFlags.Instance | BindingFlags.Public); if (method != null && method.IsGenericMethodDefinition) { _il2cppCastGeneric = method; break; } type = type.BaseType; } } if (_il2cppCastGeneric == null) { return null; } return _il2cppCastGeneric.MakeGenericMethod(targetType).Invoke(obj, null); } catch (Exception ex) { SafeLog.Error("Refl.CastToIl2Cpp(" + targetType.FullName + ")", ex); return null; } } } internal static class SafeLog { private static Instance _logger; private static readonly LinkedList _ring = new LinkedList(); private const int RingMax = 200; public static IEnumerable Recent => _ring; public static void Bind(Instance logger) { _logger = logger; } public static void Info(string msg) { Instance logger = _logger; if (logger != null) { logger.Msg(msg); } Push("INFO " + msg); } public static void Warn(string msg) { Instance logger = _logger; if (logger != null) { logger.Warning(msg); } Push("WARN " + msg); } public static void Error(string msg, Exception ex = null) { if (_logger != null) { if (ex != null) { _logger.Error($"{msg}: {ex.GetType().Name}: {ex.Message}\n{ex.StackTrace}"); } else { _logger.Error(msg); } } Push("ERROR " + ((ex != null) ? (msg + ": " + ex.Message) : msg)); } private static void Push(string line) { _ring.AddLast(line); while (_ring.Count > 200) { _ring.RemoveFirst(); } } } }