Decompiled source of SledAutoAFK v0.1.0

SledAutoAFK.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using MelonLoader;
using MelonLoader.Preferences;
using SledAutoAFK;
using SledAutoAFK.Util;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("SledAutoAFK")]
[assembly: AssemblyFileVersion("0.1.0")]
[assembly: MelonInfo(typeof(Mod), "SledAutoAFK", "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 SledAutoAFK
{
	public sealed class Mod : MelonMod
	{
		public const string Name = "SledAutoAFK";

		public const string Version = "0.1.0";

		public const string Author = "Natebag";

		private static MelonPreferences_Category _prefCat;

		private static MelonPreferences_Entry<float> _thresholdEntry;

		private static float _lastInputTime;

		private static bool _isAfk;

		private static string _originalName = "";

		private static bool _hasOriginalName;

		private static readonly string[] _frames = new string[6] { "[A]", "[AF]", "[AFK]", "[AFK.]", "[AFK..]", "[AFK...]" };

		private static int _frameIndex;

		private static float _lastFrameTime;

		private const float FrameInterval = 0.5f;

		private static Type _playerUsernameControllerType;

		private static bool _hookInstalled;

		public override void OnInitializeMelon()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			SafeLog.Bind(((MelonBase)this).LoggerInstance);
			try
			{
				_prefCat = MelonPreferences.CreateCategory("SledAutoAFK", "SledAutoAFK");
				_thresholdEntry = _prefCat.CreateEntry<float>("ThresholdSeconds", 60f, "ThresholdSeconds", "Seconds of no input before marking as AFK (default: 60)", false, false, (ValueValidator)null, (string)null);
				_lastInputTime = Time.time;
				_playerUsernameControllerType = Refl.FindType("Assembly-CSharp", "PlayerUsernameController");
				if (_playerUsernameControllerType == null)
				{
					SafeLog.Warn("SledAutoAFK: PlayerUsernameController not found at init — will retry on first frame");
				}
				if (!_hookInstalled)
				{
					((MelonEventBase<LemonAction>)(object)MelonEvents.OnUpdate).Subscribe(new LemonAction(OnFrame), 0, false);
					_hookInstalled = true;
				}
				SafeLog.Info($"SledAutoAFK v{"0.1.0"} ready — threshold {_thresholdEntry.Value}s.");
			}
			catch (Exception value)
			{
				((MelonBase)this).LoggerInstance.Error($"SledAutoAFK init failed: {value}");
			}
		}

		private static void OnFrame()
		{
			try
			{
				float time = Time.time;
				bool anyKey = Input.anyKey;
				bool flag = Mathf.Abs(Input.GetAxis("Mouse X")) > 0.01f;
				bool flag2 = Mathf.Abs(Input.GetAxis("Mouse Y")) > 0.01f;
				if (anyKey || flag || flag2)
				{
					_lastInputTime = time;
					if (_isAfk)
					{
						_isAfk = false;
						_frameIndex = 0;
						if (_hasOriginalName)
						{
							WriteSyncUsername(_originalName);
							SafeLog.Info("SledAutoAFK: AFK ended — restored name '" + _originalName + "'");
						}
					}
					return;
				}
				float num = ((_thresholdEntry != null) ? _thresholdEntry.Value : 60f);
				float num2 = time - _lastInputTime;
				if (!(num2 < num))
				{
					if (!_isAfk)
					{
						_isAfk = true;
						_originalName = ReadSyncUsername();
						_hasOriginalName = !string.IsNullOrEmpty(_originalName);
						SafeLog.Info($"SledAutoAFK: AFK triggered after {num2:F0}s idle. Original name: '{_originalName}'");
					}
					if (time - _lastFrameTime >= 0.5f)
					{
						_lastFrameTime = time;
						_frameIndex = (_frameIndex + 1) % _frames.Length;
						WriteSyncUsername((_hasOriginalName ? (_originalName + " ") : "") + _frames[_frameIndex]);
					}
				}
			}
			catch (Exception ex)
			{
				SafeLog.Error("SledAutoAFK.OnFrame", ex);
			}
		}

		private static string ReadSyncUsername()
		{
			try
			{
				EnsureControllerType();
				if (_playerUsernameControllerType == null)
				{
					return "";
				}
				Il2CppReferenceArray<Object> val = Object.FindObjectsOfType(Il2CppType.From(_playerUsernameControllerType));
				if (val == null)
				{
					return "";
				}
				foreach (Object item in (Il2CppArrayBase<Object>)(object)val)
				{
					if (item == (Object)null)
					{
						continue;
					}
					object obj = Refl.CastToIl2Cpp(item, _playerUsernameControllerType);
					if (obj == null)
					{
						continue;
					}
					PropertyInfo property = obj.GetType().GetProperty("IsOwner", BindingFlags.Instance | BindingFlags.Public);
					if (property == null)
					{
						continue;
					}
					object value = property.GetValue(obj);
					if (value != null && (bool)value)
					{
						FieldInfo field = obj.GetType().GetField("sync_Username", BindingFlags.Instance | BindingFlags.Public);
						object obj2 = ((field != null) ? field.GetValue(obj) : null);
						if (obj2 != null)
						{
							PropertyInfo property2 = obj2.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public);
							return ((property2 != null) ? (property2.GetValue(obj2) as string) : null) ?? "";
						}
					}
				}
			}
			catch (Exception ex)
			{
				SafeLog.Error("SledAutoAFK.ReadSyncUsername", ex);
			}
			return "";
		}

		private static void WriteSyncUsername(string value)
		{
			try
			{
				EnsureControllerType();
				if (_playerUsernameControllerType == null)
				{
					SafeLog.Warn("SledAutoAFK: PlayerUsernameController type not found");
					return;
				}
				Il2CppReferenceArray<Object> val = Object.FindObjectsOfType(Il2CppType.From(_playerUsernameControllerType));
				if (val == null || ((Il2CppArrayBase<Object>)(object)val).Length == 0)
				{
					return;
				}
				object obj = null;
				foreach (Object item in (Il2CppArrayBase<Object>)(object)val)
				{
					if (item == (Object)null)
					{
						continue;
					}
					object obj2 = Refl.CastToIl2Cpp(item, _playerUsernameControllerType);
					if (obj2 == null)
					{
						continue;
					}
					PropertyInfo property = obj2.GetType().GetProperty("IsOwner", BindingFlags.Instance | BindingFlags.Public);
					if (!(property == null))
					{
						object value2 = property.GetValue(obj2);
						if (value2 != null && (bool)value2)
						{
							obj = obj2;
							break;
						}
					}
				}
				if (obj == null)
				{
					obj = Refl.CastToIl2Cpp(((Il2CppArrayBase<Object>)(object)val)[0], _playerUsernameControllerType);
				}
				if (obj == null)
				{
					return;
				}
				FieldInfo field = obj.GetType().GetField("sync_Username", BindingFlags.Instance | BindingFlags.Public);
				if (field == null)
				{
					return;
				}
				object value3 = field.GetValue(obj);
				if (value3 != null)
				{
					PropertyInfo property2 = value3.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public);
					if (!(property2 == null))
					{
						property2.SetValue(value3, value);
					}
				}
			}
			catch (Exception ex)
			{
				SafeLog.Error("SledAutoAFK.WriteSyncUsername", ex);
			}
		}

		private static void EnsureControllerType()
		{
			if (!(_playerUsernameControllerType != null))
			{
				_playerUsernameControllerType = Refl.FindType("Assembly-CSharp", "PlayerUsernameController");
			}
		}
	}
}
namespace SledAutoAFK.Util
{
	internal static class Refl
	{
		private static readonly Dictionary<string, Type> _typeCache = new Dictionary<string, Type>();

		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<string> _ring = new LinkedList<string>();

		private const int RingMax = 200;

		public static IEnumerable<string> 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();
			}
		}
	}
}