Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CorpseRunHelper v1.0.1
plugins/CorpseRunHelper.dll
Decompiled 5 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CorpseRunHelper")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+583b781092ca24d11342d85f694475f0e38738d3")] [assembly: AssemblyProduct("CorpseRunHelper")] [assembly: AssemblyTitle("CorpseRunHelper")] [assembly: AssemblyVersion("1.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 PlayToDate.CorpseRunHelper { [BepInPlugin("it.playtodate.corpserunhelper", "Corpse Run Helper", "1.0.1")] public class Plugin : BaseUnityPlugin { private sealed class Entry { public string Slot; public string Name; public int Quality; public int Variant; public long Crafter; public float Durability; } public const string Guid = "it.playtodate.corpserunhelper"; public const string Name = "Corpse Run Helper"; public const string Version = "1.0.1"; private const string DataKey = "PlayToDate.CorpseRun"; private static readonly string[] Slots = new string[9] { "m_helmetItem", "m_chestItem", "m_legItem", "m_shoulderItem", "m_utilityItem", "m_trinketItem", "m_rightItem", "m_leftItem", "m_ammoItem" }; private static ConfigEntry<bool> _enabled; private static ConfigEntry<bool> _message; private static Plugin _self; private static Type _tPlayer; private static Type _tHumanoid; private static FieldInfo _localPlayer; private static FieldInfo _customData; private static FieldInfo _inventory; private static readonly Dictionary<string, FieldInfo> _slotFields = new Dictionary<string, FieldInfo>(); private static MethodInfo _equip; private static MethodInfo _getAllItems; private static MethodInfo _message0; private static float _watchUntil; private static float _nextCheck; private static float _nextSync; private static MethodInfo _getLanguage; private static List<Entry> _memory = new List<Entry>(); private void Awake() { //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Expected O, but got Unknown //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Expected O, but got Unknown //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Expected O, but got Unknown _self = this; _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Re-equip the gear you were wearing when you died, as soon as you loot your tombstone. / Rimette addosso l'equipaggiamento quando recuperi la tomba."); _message = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show message", true, "Show a short message when your gear is re-equipped. / Mostra un breve messaggio quando l'equipaggiamento torna addosso."); _tPlayer = AccessTools.TypeByName("Player"); _tHumanoid = AccessTools.TypeByName("Humanoid"); Type type = AccessTools.TypeByName("TombStone"); if (_tPlayer == null || _tHumanoid == null || type == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Corpse Run Helper: game types not found, mod disabled"); return; } _localPlayer = AccessTools.Field(_tPlayer, "m_localPlayer"); _customData = AccessTools.Field(_tPlayer, "m_customData"); _inventory = AccessTools.Field(_tHumanoid, "m_inventory"); string[] slots = Slots; foreach (string text in slots) { FieldInfo fieldInfo = AccessTools.Field(_tHumanoid, text); if (fieldInfo != null) { _slotFields[text] = fieldInfo; } } MethodInfo[] methods = _tHumanoid.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == "EquipItem" && methodInfo.GetParameters().Length >= 1 && (_equip == null || methodInfo.GetParameters().Length > _equip.GetParameters().Length)) { _equip = methodInfo; } } if (_localPlayer == null || _inventory == null || _equip == null || !_slotFields.ContainsKey("m_rightItem")) { ((BaseUnityPlugin)this).Logger.LogError((object)"Corpse Run Helper: the game changed (missing m_localPlayer, m_inventory, EquipItem or equipment slots), mod disabled"); return; } if (_customData == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Corpse Run Helper: no m_customData on Player: the gear list is kept only until you quit the game"); } Harmony val = new Harmony("it.playtodate.corpserunhelper"); int num = 0; HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin).GetMethod("DeathPrefix", BindingFlags.Static | BindingFlags.NonPublic)); HarmonyMethod val3 = new HarmonyMethod(typeof(Plugin).GetMethod("TombPostfix", BindingFlags.Static | BindingFlags.NonPublic)); methods = _tPlayer.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2.Name == "OnDeath") { try { val.Patch((MethodBase)methodInfo2, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Corpse Run Helper: could not patch Player.OnDeath (" + ex.Message + ")")); } } } methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo3 in methods) { if (methodInfo3.Name == "Interact" || methodInfo3.Name == "GiveBoost") { try { val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Corpse Run Helper: could not patch TombStone." + methodInfo3.Name + " (" + ex2.Message + ")")); } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Corpse Run Helper 1.0.1 ready (" + num + " patches)")); } private static object LocalPlayer() { try { return _localPlayer.GetValue(null); } catch { return null; } } private static void DeathPrefix(object __instance) { try { if (!_enabled.Value || __instance == null || __instance != LocalPlayer()) { return; } List<Entry> list = new List<Entry>(); foreach (KeyValuePair<string, FieldInfo> slotField in _slotFields) { object value = slotField.Value.GetValue(__instance); Entry e = Fingerprint(value); if (e != null) { e.Slot = slotField.Key; if (!list.Exists((Entry x) => x.Name == e.Name && x.Crafter == e.Crafter && Math.Abs(x.Durability - e.Durability) < 0.05f && x.Slot != "m_ammoItem")) { list.Add(e); } } } if (list.Count != 0) { Save(__instance, list); } } catch (Exception ex) { ((BaseUnityPlugin)_self).Logger.LogWarning((object)("Corpse Run Helper: could not read your gear at death (" + ex.Message + ")")); } } private static void TombPostfix() { if (_enabled.Value) { _watchUntil = Time.time + 6f; _nextCheck = 0f; } } private void Update() { if (_memory.Count > 0 && Time.time > _nextSync) { _nextSync = Time.time + 5f; try { object obj = LocalPlayer(); if (obj != null && _customData?.GetValue(obj) is IDictionary<string, string> dictionary && !dictionary.ContainsKey("PlayToDate.CorpseRun")) { Save(obj, _memory); } } catch { } } if (_watchUntil <= 0f) { return; } if (Time.time > _watchUntil) { _watchUntil = 0f; } else if (!(Time.time < _nextCheck)) { _nextCheck = Time.time + 0.25f; try { Restore(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Corpse Run Helper: could not re-equip (" + ex.Message + ")")); _watchUntil = 0f; } } } private static void Restore() { object obj = LocalPlayer(); if (obj == null) { return; } List<Entry> list = Load(obj); if (list.Count == 0) { _watchUntil = 0f; return; } List<object> list2 = Items(obj); if (list2 == null) { return; } int num = 0; List<Entry> list3 = new List<Entry>(); foreach (Entry item in list) { if (_slotFields.TryGetValue(item.Slot, out var value) && value.GetValue(obj) != null) { continue; } object obj2 = null; foreach (object item2 in list2) { if (!IsEquipped(item2)) { Entry entry = Fingerprint(item2); if (entry != null && !(entry.Name != item.Name) && (item.Slot == "m_ammoItem" || (entry.Quality == item.Quality && entry.Variant == item.Variant && entry.Crafter == item.Crafter && Math.Abs(entry.Durability - item.Durability) < 0.05f))) { obj2 = item2; break; } } } if (obj2 == null) { list3.Add(item); continue; } ParameterInfo[] parameters = _equip.GetParameters(); object[] array = new object[parameters.Length]; array[0] = obj2; for (int i = 1; i < parameters.Length; i++) { array[i] = ((parameters[i].ParameterType == typeof(bool)) ? ((object)false) : (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : null)); } object obj3 = _equip.Invoke(obj, array); if (obj3 is bool && !(bool)obj3) { list3.Add(item); } else { num++; } } Save(obj, list3); if (num > 0) { if (_message.Value) { Say(obj, (!Italian()) ? ((num == 1) ? "Gear re-equipped" : ("Gear re-equipped (" + num + ")")) : ((num == 1) ? "Equipaggiamento rimesso" : ("Equipaggiamento rimesso (" + num + ")"))); } if (list3.Count == 0) { _watchUntil = 0f; } } } private static Entry Fingerprint(object item) { if (item == null) { return null; } Type type = item.GetType(); object obj = AccessTools.Field(type, "m_shared")?.GetValue(item); string text = ((obj != null) ? (AccessTools.Field(obj.GetType(), "m_name")?.GetValue(obj) as string) : null); if (string.IsNullOrEmpty(text)) { return null; } return new Entry { Name = text, Quality = ToInt(AccessTools.Field(type, "m_quality")?.GetValue(item)), Variant = ToInt(AccessTools.Field(type, "m_variant")?.GetValue(item)), Crafter = ((AccessTools.Field(type, "m_crafterID")?.GetValue(item) is long num) ? num : 0), Durability = ((AccessTools.Field(type, "m_durability")?.GetValue(item) is float num2) ? num2 : 0f) }; } private static bool IsEquipped(object item) { object obj = AccessTools.Field(item.GetType(), "m_equipped")?.GetValue(item); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static int ToInt(object v) { try { return (v != null) ? Convert.ToInt32(v) : 0; } catch { return 0; } } private static List<object> Items(object player) { object value = _inventory.GetValue(player); if (value == null) { return null; } if (_getAllItems == null) { _getAllItems = AccessTools.Method(value.GetType(), "GetAllItems", Type.EmptyTypes, (Type[])null); } List<object> list = new List<object>(); if (_getAllItems?.Invoke(value, null) is IEnumerable enumerable) { foreach (object item in enumerable) { list.Add(item); } } return list; } private static bool Italian() { try { Type type = AccessTools.TypeByName("Localization"); object obj = type?.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null); if (obj == null) { return false; } if (_getLanguage == null) { _getLanguage = AccessTools.Method(type, "GetSelectedLanguage", (Type[])null, (Type[])null); } return string.Equals(_getLanguage?.Invoke(obj, null) as string, "Italian", StringComparison.OrdinalIgnoreCase); } catch { return false; } } private static void Say(object player, string text) { try { if (_message0 == null) { MethodInfo[] methods = AccessTools.TypeByName("Character").GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == "Message" && methodInfo.GetParameters().Length >= 2) { _message0 = methodInfo; break; } } } if (!(_message0 == null)) { ParameterInfo[] parameters = _message0.GetParameters(); object[] array = new object[parameters.Length]; array[0] = Enum.ToObject(parameters[0].ParameterType, 1); array[1] = text; for (int j = 2; j < parameters.Length; j++) { array[j] = (parameters[j].HasDefaultValue ? parameters[j].DefaultValue : (parameters[j].ParameterType.IsValueType ? Activator.CreateInstance(parameters[j].ParameterType) : null)); } _message0.Invoke(player, array); } } catch { } } private static void Save(object player, List<Entry> list) { _memory = list; if (!(_customData?.GetValue(player) is IDictionary<string, string> dictionary)) { return; } if (list.Count == 0) { dictionary.Remove("PlayToDate.CorpseRun"); return; } StringBuilder stringBuilder = new StringBuilder(); foreach (Entry item in list) { if (stringBuilder.Length > 0) { stringBuilder.Append(';'); } stringBuilder.Append(item.Slot).Append('|').Append(Uri.EscapeDataString(item.Name)) .Append('|') .Append(item.Quality) .Append('|') .Append(item.Variant) .Append('|') .Append(item.Crafter) .Append('|') .Append(item.Durability.ToString("R", CultureInfo.InvariantCulture)); } dictionary["PlayToDate.CorpseRun"] = stringBuilder.ToString(); } private static List<Entry> Load(object player) { if (!(_customData?.GetValue(player) is IDictionary<string, string> dictionary)) { return _memory; } List<Entry> list = new List<Entry>(); if (!dictionary.TryGetValue("PlayToDate.CorpseRun", out var value) || string.IsNullOrEmpty(value)) { return new List<Entry>(_memory); } string[] array = value.Split(';'); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split('|'); if (array2.Length >= 6) { long.TryParse(array2[4], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result); float.TryParse(array2[5], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2); list.Add(new Entry { Slot = array2[0], Name = Uri.UnescapeDataString(array2[1]), Quality = ToInt(array2[2]), Variant = ToInt(array2[3]), Crafter = result, Durability = result2 }); } } return list; } } }