Decompiled source of PitSave v1.1.0

plugins/PitSave.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[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("PitSave")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PitSave")]
[assembly: AssemblyTitle("PitSave")]
[assembly: AssemblyVersion("1.0.0.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 YanPitSave
{
	internal static class Cfg
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<float> PitY;

		public static ConfigEntry<float> SafeMinY;

		public static ConfigEntry<float> SafeMaxY;

		public static ConfigEntry<float> LiftY;

		public static ConfigEntry<float> SaveCooldown;

		public static ConfigEntry<float> FallDepth;

		public static ConfigEntry<float> BounceSpeed;

		public static ConfigEntry<float> PushInterval;

		public static ConfigEntry<float> PushRise;

		public static ConfigEntry<bool> NativePitBounce;

		public static ConfigEntry<bool> IncludeEnemyValuable;

		public static ConfigEntry<bool> ShowToast;

		public static ConfigEntry<float> ScanInterval;

		public static ConfigEntry<bool> DebugLog;

		private static AcceptableValueBase F(float min, float max)
		{
			return (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max);
		}

		public static void Bind(ConfigFile c)
		{
			Lang.Init(c, delegate(string s)
			{
				if (Plugin.Log != null)
				{
					Plugin.Log.LogInfo((object)s);
				}
			});
			Enabled = Lang.B(c, "en", def: true);
			PitY = Lang.B(c, "pity", -25f, F(-80f, -10f));
			SafeMinY = Lang.B(c, "safemin", -2f, F(-20f, 10f));
			SafeMaxY = Lang.B(c, "safemax", 60f, F(10f, 150f));
			LiftY = Lang.B(c, "lift", 1.5f, F(0f, 8f));
			SaveCooldown = Lang.B(c, "cooldown", 2f, F(0f, 10f));
			FallDepth = Lang.B(c, "falldepth", 4f, F(1f, 20f));
			BounceSpeed = Lang.B(c, "bounce", 40f, F(2f, 60f));
			PushInterval = Lang.B(c, "pushint", 0.35f, F(0.1f, 2f));
			PushRise = Lang.B(c, "pushrise", 2f, F(0.3f, 3f));
			NativePitBounce = Lang.B(c, "native", def: true);
			IncludeEnemyValuable = Lang.B(c, "enemyval", def: true);
			ShowToast = Lang.B(c, "toast", def: true);
			ScanInterval = Lang.B(c, "scan", 0.15f, F(0.05f, 1f));
			DebugLog = Lang.B(c, "dbg", def: false);
			if (Mathf.Approximately(BounceSpeed.Value, 14f))
			{
				BounceSpeed.Value = 40f;
			}
			if (Mathf.Approximately(PushRise.Value, 1.25f))
			{
				PushRise.Value = 2f;
			}
			Lang.PurgeOther(c);
		}
	}
	internal static class Lang
	{
		public const string SecLang = "0.Language";

		public const string KeyLang = "Language";

		public static ConfigFile Cfg;

		public static ConfigEntry<string> E;

		public static bool En;

		private static Action<string> _out;

		private static float _uiAt;

		private const string SA = "1.掉坑救回";

		private const string SB = "1. Pit rescue";

		private const string SC = "3.显示与调试";

		private const string SD = "3. Display";

		private static readonly string[][] T;

		public static readonly string[] Ids;

		private static FieldInfo _fEntries;

		static Lang()
		{
			T = new string[15][]
			{
				new string[7] { "en", "1.掉坑救回", "1. Pit rescue", "启用掉落救回", "Enable rescue", "值钱物掉出地图时把它捞回来,不让它凭空消失。", "Valuables that fall out of the map are brought back instead of vanishing." },
				new string[7] { "pity", "1.掉坑救回", "1. Pit rescue", "判定掉坑高度", "Pit Y threshold", "世界 Y 低于这个值就算掉出地图。游戏本体在 -50 才销毁,这里留了缓冲。", "World Y below this counts as fallen out of the map. The game itself only destroys things at -50, so there is room to spare." },
				new string[7] { "safemin", "1.掉坑救回", "1. Pit rescue", "安全位置下限", "Safe min Y", "只有高于这个高度才记安全点,防止把坑里的位置当成安全点。", "Only record a safe spot above this height, so a position inside the pit is never taken as safe." },
				new string[7] { "safemax", "1.掉坑救回", "1. Pit rescue", "安全位置上限", "Safe max Y", "高于这个高度不记录,防止飞在天上的位置被当成安全点。", "Nothing above this height is recorded, so a spot up in the air is never taken as safe." },
				new string[7] { "lift", "1.掉坑救回", "1. Pit rescue", "救回抬高", "Rescue lift", "米。救回时在安全位置上再抬这么高,避免卡进地面。", "Meters. Raised this much above the safe spot on rescue, so it does not clip into the floor." },
				new string[7] { "cooldown", "1.掉坑救回", "1. Pit rescue", "同物品冷却", "Same-item cooldown", "秒。同一件东西两次救回之间的最短间隔,防止来回弹。", "Seconds. Shortest gap between two rescues of the same object, so it cannot ping-pong." },
				new string[7] { "falldepth", "1.掉坑救回", "1. Pit rescue", "掉坑判定落差", "Fall depth", "米。比记录的安全点低这么多而且还在往下掉,就算掉坑。调大更容易忽略小落差。", "Meters. This far below the recorded safe spot and still falling counts as fallen. Raise it to ignore small drops." },
				new string[7] { "bounce", "1.掉坑救回", "1. Pit rescue", "弹回水平速度", "Horizontal bounce speed", "米/秒。掉坑后朝安全点方向弹出去的水平速度,填多少就是多少,不再打折。2-60。", "m/s. Horizontal speed fired back toward the safe spot after falling. The number is the speed itself, no scaling. 2-60." },
				new string[7] { "pushint", "1.掉坑救回", "1. Pit rescue", "坑内续推间隔秒", "Re-push interval", "秒。掉坑后每隔这么久再给一次推力,直到它自己爬出来。0.1-2。", "Seconds. Another push is given this often while it is still down there, until it climbs out. 0.1-2." },
				new string[7] { "pushrise", "1.掉坑救回", "1. Pit rescue", "抬升力度倍率", "Rise multiplier", "倍。往上弹的速度按坑深自动算,这里是倍率:1 差不多刚好,2 弹得高一截。0.3-3。", "Multiplier. The upward speed is derived from how deep it fell; this scales it. 1 is about right, 2 throws it clearly higher. 0.3-3." },
				new string[7] { "native", "1.掉坑救回", "1. Pit rescue", "掉坑时闪原生特效", "Native pit effect", "掉坑那一刻点亮和死头一样的绿色烟雾/电弧,落地或被拿起就熄。", "Flashes the game's own green smoke / arc effect on the fall, same as the death head. Goes out on landing or pickup." },
				new string[7] { "enemyval", "3.显示与调试", "3. Display", "含怪物掉落物", "Include enemy valuables", "怪物掉的值钱物也算。", "Valuables dropped by monsters count too." },
				new string[7] { "toast", "3.显示与调试", "3. Display", "救回时屏幕提示", "Screen toast", "救回一件东西时屏幕角落显示一行字。", "Show a one-line message in the corner of the screen when something is saved." },
				new string[7] { "scan", "3.显示与调试", "3. Display", "扫描间隔秒", "Scan interval", "秒。每帧扫很费,0.15 秒一次已经足够。0.05-1。", "Seconds. Scanning every frame is wasteful; once per 0.15s is plenty. 0.05-1." },
				new string[7] { "dbg", "3.显示与调试", "3. Display", "调试日志", "Debug log", "开 = 往控制台打详细日志,排查用。", "On = verbose logging to the console, for troubleshooting." }
			};
			Ids = new string[T.Length];
			for (int i = 0; i < T.Length; i++)
			{
				Ids[i] = T[i][0];
			}
		}

		private static int ix(bool en, int zh, int enIx)
		{
			if (!en)
			{
				return zh;
			}
			return enIx;
		}

		public static string Sec(string id, bool en)
		{
			return Row(id)[ix(en, 1, 2)];
		}

		public static string Key(string id, bool en)
		{
			return Row(id)[ix(en, 3, 4)];
		}

		public static string Desc(string id, bool en)
		{
			return Row(id)[ix(en, 5, 6)];
		}

		private static string[] Row(string id)
		{
			for (int i = 0; i < T.Length; i++)
			{
				if (T[i][0] == id)
				{
					return T[i];
				}
			}
			return T[0];
		}

		internal static void Log(string m)
		{
			try
			{
				if (_out != null)
				{
					_out(m);
				}
			}
			catch
			{
			}
		}

		public static void Init(ConfigFile c, Action<string> log)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			Cfg = c;
			_out = log;
			E = c.Bind<string>("0.Language", "Language", "中文", new ConfigDescription("界面语言 / Interface language(改完立即生效,不用重启 / applies immediately, no restart needed)", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "中文", "English" }), Array.Empty<object>()));
			En = E.Value == "English";
		}

		public static void Hook()
		{
			if (E != null)
			{
				E.SettingChanged += OnLangChanged;
			}
		}

		private static void OnLangChanged(object sender, EventArgs e)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			try
			{
				bool flag = E != null && E.Value == "English";
				if (flag == En)
				{
					return;
				}
				En = flag;
				ConfigFile cfg = Cfg;
				int num = 0;
				int num2 = 0;
				foreach (DictionaryEntry item in EntriesDict(cfg))
				{
					object? value = item.Value;
					ConfigEntryBase val = (ConfigEntryBase)((value is ConfigEntryBase) ? value : null);
					if (val == null || (object)val == E)
					{
						continue;
					}
					string text = IdOf(val.Definition);
					if (text == null)
					{
						num2++;
						continue;
					}
					try
					{
						SetBacking(val, "Definition", typeof(ConfigDefinition), (object)new ConfigDefinition(Sec(text, flag), Key(text, flag)));
						SetBacking(val, "Description", typeof(ConfigDescription), BuildDesc(text, flag, val.Description));
						num++;
					}
					catch (Exception ex)
					{
						Log("relabel " + text + " fail: " + ex.Message);
					}
				}
				bool flag2 = RebuildEntries(cfg);
				try
				{
					cfg.Save();
				}
				catch (Exception ex2)
				{
					Log("save fail: " + ex2.Message);
				}
				PurgeOther(cfg);
				Log("switch -> " + (flag ? "English" : "Chinese") + " relabeled=" + num + " skipped=" + num2 + " dict=" + (flag2 ? "ok" : "FAIL"));
				_uiAt = Time.time + 0.15f;
			}
			catch (Exception ex3)
			{
				Log("switch fail: " + ex3);
			}
		}

		public static void RefreshTick()
		{
			if (!(_uiAt <= 0f) && !(Time.time < _uiAt))
			{
				_uiAt = 0f;
				RefreshMenu();
			}
		}

		private static void RefreshMenu()
		{
			try
			{
				Type type = FindType("MenuLib.MenuAPI");
				Type type2 = FindType("REPOConfig.ConfigMenu");
				if (type2 == null)
				{
					Log("menu: ConfigMenu not found");
					return;
				}
				FieldInfo field = type2.GetField("hasPopupMenuOpened", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				bool flag = false;
				try
				{
					flag = field != null && field.GetValue(null) is bool && (bool)field.GetValue(null);
				}
				catch
				{
				}
				if (!flag)
				{
					Log("menu closed, skip refresh");
					return;
				}
				if (type != null)
				{
					MethodInfo method = type.GetMethod("CloseAllPagesAddedOnTop", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					if (method != null)
					{
						method.Invoke(null, DefArgs(method));
					}
				}
				MethodInfo method2 = type2.GetMethod("CreateModMenu", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method2 != null && method2.GetParameters().Length == 0)
				{
					method2.Invoke(null, null);
				}
				Log("menu rebuilt");
			}
			catch (Exception ex)
			{
				Log("menu refresh fail: " + ex.Message);
			}
		}

		private static object[] DefArgs(MethodInfo m)
		{
			ParameterInfo[] parameters = m.GetParameters();
			object[] array = new object[parameters.Length];
			for (int i = 0; i < parameters.Length; i++)
			{
				Type parameterType = parameters[i].ParameterType;
				if (parameterType == typeof(bool))
				{
					array[i] = true;
				}
				else if (parameterType.IsValueType)
				{
					array[i] = Activator.CreateInstance(parameterType);
				}
				else
				{
					array[i] = null;
				}
			}
			return array;
		}

		private static Type FindType(string fullName)
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (!(assembly == null))
					{
						Type type = assembly.GetType(fullName, throwOnError: false);
						if (type != null)
						{
							return type;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static string IdOf(ConfigDefinition d)
		{
			if (d == (ConfigDefinition)null)
			{
				return null;
			}
			for (int i = 0; i < Ids.Length; i++)
			{
				string text = Ids[i];
				if ((!(d.Key != Key(text, en: true)) || !(d.Key != Key(text, en: false))) && (d.Section == Sec(text, en: true) || d.Section == Sec(text, en: false)))
				{
					return text;
				}
			}
			return null;
		}

		private static ConfigDescription BuildDesc(string id, bool en, ConfigDescription old)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			string text = Desc(id, en);
			AcceptableValueBase val = ((old != null) ? old.AcceptableValues : null);
			object[] array = ((old != null) ? old.Tags : null);
			if (val == null && (array == null || array.Length == 0))
			{
				return new ConfigDescription(text, (AcceptableValueBase)null, Array.Empty<object>());
			}
			return new ConfigDescription(text, val, (array == null) ? new object[0] : array);
		}

		private static void SetBacking(object entry, string hint, Type fieldType, object value)
		{
			Type type = entry.GetType();
			while (type != null)
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!(fieldInfo.FieldType != fieldType) && fieldInfo.Name.IndexOf(hint, StringComparison.Ordinal) >= 0)
					{
						fieldInfo.SetValue(entry, value);
						return;
					}
				}
				type = type.BaseType;
			}
			throw new Exception(hint + " backing field not found");
		}

		private static FieldInfo EntriesField(ConfigFile c)
		{
			if (_fEntries != null)
			{
				return _fEntries;
			}
			Type typeFromHandle = typeof(ConfigFile);
			FieldInfo fieldInfo = typeFromHandle.GetField("<Entries>k__BackingField", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (fieldInfo == null)
			{
				FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				for (int i = 0; i < fields.Length; i++)
				{
					if (typeof(IDictionary).IsAssignableFrom(fields[i].FieldType))
					{
						fieldInfo = fields[i];
						break;
					}
				}
			}
			_fEntries = fieldInfo;
			return fieldInfo;
		}

		private static IDictionary EntriesDict(ConfigFile c)
		{
			FieldInfo fieldInfo = EntriesField(c);
			if (fieldInfo == null)
			{
				return new Hashtable();
			}
			if (!(fieldInfo.GetValue(c) is IDictionary result))
			{
				return new Hashtable();
			}
			return result;
		}

		private static bool RebuildEntries(ConfigFile c)
		{
			FieldInfo fieldInfo = EntriesField(c);
			if (fieldInfo == null)
			{
				return false;
			}
			try
			{
				if (!(fieldInfo.GetValue(c) is IDictionary dictionary))
				{
					return false;
				}
				IDictionary dictionary2 = (IDictionary)Activator.CreateInstance(dictionary.GetType());
				foreach (DictionaryEntry item in dictionary)
				{
					object? value = item.Value;
					ConfigEntryBase val = (ConfigEntryBase)((value is ConfigEntryBase) ? value : null);
					if (val != null)
					{
						dictionary2[val.Definition] = val;
					}
				}
				fieldInfo.SetValue(c, dictionary2);
				return dictionary2.Count == dictionary.Count;
			}
			catch (Exception ex)
			{
				Log("rebuild entries fail " + ex.Message);
				return false;
			}
		}

		public static ConfigEntry<T> B<T>(ConfigFile c, string id, T def, AcceptableValueBase range = null)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			ConfigDefinition val = new ConfigDefinition(Sec(id, En), Key(id, En));
			ConfigDefinition key = new ConfigDefinition(Sec(id, !En), Key(id, !En));
			string text = null;
			IDictionary dictionary = Orphans(c);
			if (dictionary != null)
			{
				if (dictionary.Contains(val))
				{
					text = dictionary[val] as string;
				}
				else if (dictionary.Contains(key))
				{
					text = dictionary[key] as string;
				}
			}
			ConfigDescription val2 = ((range != null) ? new ConfigDescription(Desc(id, En), range, Array.Empty<object>()) : new ConfigDescription(Desc(id, En), (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigEntry<T> val3 = c.Bind<T>(val, def, val2);
			if (!string.IsNullOrEmpty(text))
			{
				try
				{
					((ConfigEntryBase)val3).SetSerializedValue(text);
				}
				catch (Exception ex)
				{
					Log("migrate " + id + " fail: " + ex.Message);
				}
			}
			return val3;
		}

		public static void PurgeOther(ConfigFile c)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			IDictionary dictionary = Orphans(c);
			if (dictionary == null)
			{
				return;
			}
			bool flag = false;
			for (int i = 0; i < Ids.Length; i++)
			{
				string id = Ids[i];
				ConfigDefinition key = new ConfigDefinition(Sec(id, !En), Key(id, !En));
				if (dictionary.Contains(key))
				{
					dictionary.Remove(key);
					flag = true;
				}
			}
			ArrayList arrayList = new ArrayList();
			foreach (DictionaryEntry item in dictionary)
			{
				object key2 = item.Key;
				ConfigDefinition val = (ConfigDefinition)((key2 is ConfigDefinition) ? key2 : null);
				if (!(val == (ConfigDefinition)null) && val.Section != null && val.Section.StartsWith("2.旧无敌"))
				{
					arrayList.Add(val);
				}
			}
			for (int j = 0; j < arrayList.Count; j++)
			{
				dictionary.Remove(arrayList[j]);
				flag = true;
			}
			if (!flag)
			{
				return;
			}
			try
			{
				c.Save();
			}
			catch (Exception ex)
			{
				Log("purge save fail " + ex.Message);
			}
		}

		private static IDictionary Orphans(ConfigFile c)
		{
			try
			{
				PropertyInfo property = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property == null)
				{
					return null;
				}
				return property.GetValue(c, null) as IDictionary;
			}
			catch
			{
				return null;
			}
		}
	}
	internal class Tracked
	{
		public Component Pgo;

		public Vector3 SafePos;

		public float SafeAt;

		public float LastGrab;

		public float NextPush;

		public bool Guarded;

		public bool OrigDisable;

		public float LastSave;

		public float LastPit;

		public float CalmAt;

		public bool HasSafe;

		public bool WasHeld;

		public int Saves;

		public float MinY = 9999f;

		public string Label = "item";
	}
	internal class FxState
	{
		public GameObject Go;

		public Component Eff;

		public ParticleSystem[] Ps;

		public float Until;

		public float NextReset;
	}
	internal static class Pit
	{
		private static readonly Dictionary<int, Tracked> _map = new Dictionary<int, Tracked>();

		private static readonly List<int> _gone = new List<int>();

		private static float _nextScan;

		private static float _nextClean;

		private static Type TPgo;

		private static Type TVal;

		private static Type TEnemyVal;

		private static Type TEffect;

		private static MethodInfo MFindType;

		private static bool _ready;

		private static Type TSemi;

		private static MethodInfo MIsHost;

		private static bool _host;

		private static float _hostNext;

		private static bool _hostLogged;

		private static readonly Dictionary<int, FxState> _fx = new Dictionary<int, FxState>();

		private static readonly List<int> _fxGone = new List<int>();

		private static int _fxOn;

		private static bool _fxWarned;

		private static readonly Dictionary<int, float> _protUntil = new Dictionary<int, float>();

		private static readonly List<int> _protGone = new List<int>();

		private static Type TImp;

		private static bool _gWarned;

		public static bool IsHost()
		{
			if (Time.unscaledTime < _hostNext)
			{
				return _host;
			}
			_hostNext = Time.unscaledTime + 1f;
			try
			{
				if (TSemi == null)
				{
					TSemi = R.FindType("SemiFunc");
				}
				if (MIsHost == null && TSemi != null)
				{
					MIsHost = TSemi.GetMethod("IsMasterClientOrSingleplayer", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null);
				}
				if (MIsHost == null)
				{
					_host = true;
					return true;
				}
				_host = (bool)MIsHost.Invoke(null, null);
			}
			catch
			{
				_host = true;
			}
			return _host;
		}

		public static void SetGuard(Component pgo, Tracked tr, bool on)
		{
			if ((Object)(object)pgo == (Object)null || tr == null)
			{
				return;
			}
			try
			{
				GameObject gameObject = pgo.gameObject;
				if ((Object)(object)gameObject == (Object)null)
				{
					return;
				}
				if (TImp == null)
				{
					TImp = R.FindType("PhysGrabObjectImpactDetector");
				}
				object obj = null;
				try
				{
					obj = R.Get(pgo, "impactDetector");
				}
				catch
				{
				}
				if (obj == null && TImp != null)
				{
					obj = gameObject.GetComponent(TImp);
				}
				if (obj == null)
				{
					return;
				}
				if (on)
				{
					if (!tr.Guarded)
					{
						tr.Guarded = true;
						tr.OrigDisable = R.Bool(R.Get(obj, "destroyDisable"));
						R.Set(obj, "destroyDisable", true);
						Plugin.Log.LogInfo((object)("[guard] " + tr.Label + " ON was=" + tr.OrigDisable));
					}
				}
				else if (tr.Guarded)
				{
					tr.Guarded = false;
					R.Set(obj, "destroyDisable", tr.OrigDisable);
					Plugin.Log.LogInfo((object)("[guard] " + tr.Label + " off"));
				}
			}
			catch (Exception ex)
			{
				if (!_gWarned)
				{
					_gWarned = true;
					Plugin.Log.LogWarning((object)("[guard] FAIL " + ex.GetType().Name + " " + ex.Message));
				}
			}
		}

		public static void Protect(Component pgo, float seconds)
		{
			if ((Object)(object)pgo == (Object)null || seconds <= 0f)
			{
				return;
			}
			try
			{
				GameObject gameObject = pgo.gameObject;
				if (!((Object)(object)gameObject == (Object)null))
				{
					int instanceID = ((Object)gameObject).GetInstanceID();
					float num = Time.time + seconds;
					if (!_protUntil.TryGetValue(instanceID, out var value) || !(value > num - 0.05f))
					{
						_protUntil[instanceID] = num;
						R.Call(pgo, "OverrideIndestructible", seconds);
					}
				}
			}
			catch
			{
			}
		}

		public static void ProtectTick()
		{
			if (_protUntil.Count == 0)
			{
				return;
			}
			_protGone.Clear();
			foreach (KeyValuePair<int, float> item in _protUntil)
			{
				if (Time.time >= item.Value)
				{
					_protGone.Add(item.Key);
				}
			}
			for (int i = 0; i < _protGone.Count; i++)
			{
				_protUntil.Remove(_protGone[i]);
			}
		}

		private static void Ready()
		{
			if (!_ready)
			{
				TPgo = R.FindType("PhysGrabObject");
				TVal = R.FindType("ValuableObject");
				TEnemyVal = R.FindType("EnemyValuable");
				try
				{
					MFindType = typeof(Object).GetMethod("FindObjectsOfType", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Type) }, null);
				}
				catch
				{
					MFindType = null;
				}
				_ready = TPgo != null && TVal != null;
			}
		}

		private static Object[] FindAll(Type t)
		{
			try
			{
				if (MFindType != null && MFindType.Invoke(null, new object[1] { t }) is Object[] result)
				{
					return result;
				}
			}
			catch
			{
			}
			try
			{
				return Resources.FindObjectsOfTypeAll(t);
			}
			catch
			{
			}
			return (Object[])(object)new Object[0];
		}

		public static void Tick()
		{
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			if (Cfg.Enabled == null || !Cfg.Enabled.Value)
			{
				return;
			}
			if (!IsHost())
			{
				if (!_hostLogged)
				{
					_hostLogged = true;
					Plugin.Log.LogWarning((object)"[host] NOT host, idle");
				}
				return;
			}
			if (!_hostLogged)
			{
				_hostLogged = true;
				Plugin.Log.LogInfo((object)("[host] active isHost=true enabled=" + Cfg.Enabled.Value));
			}
			ProtectTick();
			Ready();
			if (!_ready)
			{
				return;
			}
			FxTick(Time.time);
			float num = Mathf.Clamp(Cfg.ScanInterval.Value, 0.05f, 1f);
			if (Time.unscaledTime < _nextScan)
			{
				return;
			}
			_nextScan = Time.unscaledTime + num;
			Object[] array = FindAll(TPgo);
			if (array == null || array.Length == 0)
			{
				return;
			}
			float time = Time.time;
			float num2 = Mathf.Max(1.5f, Cfg.FallDepth.Value);
			float num3 = Mathf.Max(Cfg.PitY.Value, -30f);
			foreach (Object obj in array)
			{
				Component val = (Component)(object)((obj is Component) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				GameObject gameObject = val.gameObject;
				if ((Object)(object)gameObject == (Object)null || !gameObject.activeInHierarchy)
				{
					continue;
				}
				bool flag = (Object)(object)gameObject.GetComponent(TVal) != (Object)null;
				if (!flag && Cfg.IncludeEnemyValuable.Value && TEnemyVal != null)
				{
					flag = (Object)(object)gameObject.GetComponent(TEnemyVal) != (Object)null;
				}
				if (!flag)
				{
					continue;
				}
				int instanceID = ((Object)gameObject).GetInstanceID();
				if (!_map.TryGetValue(instanceID, out var value))
				{
					value = new Tracked();
					value.Label = LabelOf(val);
					_map[instanceID] = value;
				}
				value.Pgo = val;
				Vector3 position = val.transform.position;
				if (position.y < value.MinY)
				{
					value.MinY = position.y;
				}
				if (position.y > Cfg.SafeMinY.Value && position.y < Cfg.SafeMaxY.Value && time - value.SafeAt > 0.4f)
				{
					value.SafePos = position;
					value.SafeAt = time;
					value.HasSafe = true;
				}
				float num4 = 0f;
				object obj2 = R.Get(val, "rb");
				Rigidbody val2 = (Rigidbody)((obj2 is Rigidbody) ? obj2 : null);
				if ((Object)(object)val2 != (Object)null)
				{
					num4 = val2.velocity.y;
				}
				bool flag2 = GrabCount(val) > 0;
				if (flag2 && !value.WasHeld)
				{
					value.LastGrab = time;
				}
				value.WasHeld = flag2;
				bool num5 = value.HasSafe && position.y < value.SafePos.y - num2;
				bool flag3 = position.y < num3;
				if ((num5 || flag3) && !flag2)
				{
					SetGuard(val, value, on: true);
					value.LastPit = time;
					value.CalmAt = 0f;
					if (time >= value.NextPush && num4 < 1f)
					{
						value.NextPush = time + Mathf.Clamp(Cfg.PushInterval.Value, 0.6f, 1.5f);
						value.LastSave = time;
						value.Saves++;
						Bounce(val, value, position);
					}
					continue;
				}
				bool flag4 = !value.HasSafe || position.y >= value.SafePos.y - 1f;
				if (flag4)
				{
					value.Saves = 0;
				}
				float num6 = 0f;
				if ((Object)(object)val2 != (Object)null)
				{
					Vector3 velocity = val2.velocity;
					num6 = Mathf.Sqrt(velocity.x * velocity.x + velocity.z * velocity.z);
				}
				bool flag5 = !flag2 && flag4 && Mathf.Abs(num4) < 0.6f && num6 < 1.2f;
				if (flag5)
				{
					if (value.CalmAt <= 0f)
					{
						value.CalmAt = time;
					}
				}
				else
				{
					value.CalmAt = 0f;
				}
				if (flag2)
				{
					SetGuard(val, value, on: false);
				}
				else if (flag5 && time - value.CalmAt > 1.2f)
				{
					SetGuard(val, value, on: false);
				}
				if (flag2 || flag4)
				{
					FxOff(instanceID);
				}
			}
			Cleanup(time);
		}

		private static int GrabCount(Component pgo)
		{
			object obj = R.Get(pgo, "playerGrabbing");
			if (obj == null)
			{
				return 0;
			}
			if (obj is IList list)
			{
				return list.Count;
			}
			try
			{
				PropertyInfo property = obj.GetType().GetProperty("Count");
				if (property != null)
				{
					return R.Int(property.GetValue(obj));
				}
			}
			catch
			{
			}
			return 0;
		}

		public static void Bounce(Component pgo, Tracked tr, Vector3 cur)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Vector3 val = ((tr != null && tr.HasSafe) ? tr.SafePos : FallbackPos());
				Vector3 val2 = val - cur;
				val2.y = 0f;
				float magnitude = ((Vector3)(ref val2)).magnitude;
				if (magnitude < 0.01f)
				{
					val2 = Vector3.forward;
				}
				val2 = ((Vector3)(ref val2)).normalized;
				if (Cfg.NativePitBounce != null && Cfg.NativePitBounce.Value)
				{
					try
					{
						R.Call(pgo, "DeathPitEffectCreate");
					}
					catch
					{
					}
				}
				object obj2 = R.Get(pgo, "rb");
				Rigidbody val3 = (Rigidbody)((obj2 is Rigidbody) ? obj2 : null);
				if ((Object)(object)val3 == (Object)null)
				{
					Vector3 val4 = val;
					val4.y += Mathf.Max(0.5f, Cfg.LiftY.Value);
					try
					{
						R.Call(pgo, "Teleport", val4, pgo.transform.rotation);
					}
					catch
					{
					}
					pgo.transform.position = val4;
					Plugin.Log.LogInfo((object)("[tp] " + LabelOf(pgo) + " y=" + cur.y.ToString("F1") + " (no rigidbody)"));
					return;
				}
				float num = Mathf.Clamp(Cfg.BounceSpeed.Value, 2f, 60f);
				float num2 = Mathf.Max(0f, val.y - cur.y);
				float num3 = Mathf.Clamp(Cfg.PushRise.Value, 0.3f, 3f);
				float num4 = (6f + Mathf.Min(num2, 10f) * 0.25f) * num3;
				num4 = Mathf.Clamp(num4, 4f, 26f);
				Vector3 velocity = val2 * num;
				velocity.y = num4;
				if (val3.isKinematic)
				{
					val3.isKinematic = false;
				}
				val3.velocity = velocity;
				val3.angularVelocity = Vector3.zero;
				if (Cfg.ShowToast.Value)
				{
					Toast.Push(LabelOf(pgo));
				}
				Plugin.Log.LogInfo((object)("[bounce] " + LabelOf(pgo) + " y=" + cur.y.ToString("F1") + " need=" + num2.ToString("F1") + " up=" + num4.ToString("F1") + " flat=" + magnitude.ToString("F1") + " saves=" + (tr?.Saves ?? 0)));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[bounce] FAIL " + ex.GetType().Name + " " + ex.Message));
			}
		}

		private static string LabelOf(Component pgo)
		{
			try
			{
				Component component = pgo.gameObject.GetComponent(TVal);
				if ((Object)(object)component != (Object)null)
				{
					float num = R.Num(R.Get(component, "dollarValueCurrent"));
					if (num > 0.5f)
					{
						return "$" + Mathf.RoundToInt(num);
					}
				}
				return ((Object)pgo.gameObject).name;
			}
			catch
			{
			}
			return "item";
		}

		private static Vector3 FallbackPos()
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Type type = R.FindType("TruckSafetySpawnPoint");
				if (type != null)
				{
					object obj = R.Static(type, "instance");
					Component val = (Component)((obj is Component) ? obj : null);
					if ((Object)(object)val != (Object)null)
					{
						return val.transform.position;
					}
				}
			}
			catch
			{
			}
			try
			{
				Type type2 = R.FindType("PlayerController");
				if (type2 != null)
				{
					object obj3 = R.Static(type2, "instance");
					Component val2 = (Component)((obj3 is Component) ? obj3 : null);
					if ((Object)(object)val2 != (Object)null)
					{
						return val2.transform.position + Vector3.up * 2f;
					}
				}
			}
			catch
			{
			}
			return new Vector3(0f, 2f, 0f);
		}

		private static FxState FxGet(Component pgo, int id)
		{
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_fx.TryGetValue(id, out var value) && value != null && (Object)(object)value.Go != (Object)null)
				{
					return value;
				}
				object obj = R.Get(pgo, "deathPitEffect");
				GameObject val = (GameObject)((obj is GameObject) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					R.Call(pgo, "DeathPitEffectCreate");
					object obj2 = R.Get(pgo, "deathPitEffect");
					val = (GameObject)((obj2 is GameObject) ? obj2 : null);
				}
				if ((Object)(object)val == (Object)null)
				{
					if (!_fxWarned)
					{
						_fxWarned = true;
						Plugin.Log.LogWarning((object)"[fx] 没建出特效");
					}
					return null;
				}
				if (TEffect == null)
				{
					TEffect = R.FindType("DeathPitSaveEffect");
				}
				value = new FxState();
				value.Go = val;
				if (TEffect != null)
				{
					value.Eff = val.GetComponent(TEffect);
				}
				try
				{
					value.Ps = val.GetComponentsInChildren<ParticleSystem>(true);
				}
				catch
				{
					value.Ps = null;
				}
				try
				{
					val.transform.localPosition = Vector3.zero;
					val.transform.localRotation = Quaternion.identity;
				}
				catch
				{
				}
				FxMute(value);
				_fx[id] = value;
				return value;
			}
			catch (Exception ex)
			{
				if (!_fxWarned)
				{
					_fxWarned = true;
					Plugin.Log.LogWarning((object)("[fx] get-fail " + ex.GetType().Name + " " + ex.Message));
				}
				return null;
			}
		}

		private static void FxMute(FxState st)
		{
			if (st == null)
			{
				return;
			}
			try
			{
				if ((Object)(object)st.Eff != (Object)null)
				{
					R.Set(st.Eff, "timeCurrent", 0f);
				}
			}
			catch
			{
			}
			try
			{
				if (st.Ps == null)
				{
					return;
				}
				for (int i = 0; i < st.Ps.Length; i++)
				{
					ParticleSystem val = st.Ps[i];
					if ((Object)(object)val != (Object)null)
					{
						val.Stop(true, (ParticleSystemStopBehavior)0);
					}
				}
			}
			catch
			{
			}
		}

		private static void LightFx(Component pgo, int id)
		{
			try
			{
				if (Cfg.NativePitBounce != null && !Cfg.NativePitBounce.Value)
				{
					return;
				}
				FxState fxState = FxGet(pgo, id);
				if (fxState == null)
				{
					return;
				}
				fxState.Until = Time.time + 15f;
				fxState.NextReset = 0f;
				try
				{
					if ((Object)(object)fxState.Eff != (Object)null)
					{
						R.Call(fxState.Eff, "Reset");
					}
				}
				catch
				{
				}
				try
				{
					if (fxState.Ps != null)
					{
						for (int i = 0; i < fxState.Ps.Length; i++)
						{
							ParticleSystem val = fxState.Ps[i];
							if ((Object)(object)val != (Object)null && !val.isPlaying)
							{
								val.Play();
							}
						}
					}
				}
				catch
				{
				}
				_fxOn++;
				if (_fxOn <= 3)
				{
					Plugin.Log.LogInfo((object)("[fx] on #" + _fxOn + " " + ((Object)pgo.gameObject).name));
				}
			}
			catch (Exception ex)
			{
				if (!_fxWarned)
				{
					_fxWarned = true;
					Plugin.Log.LogWarning((object)("[fx] on-fail " + ex.GetType().Name + " " + ex.Message));
				}
			}
		}

		private static void FxOff(int id)
		{
			if (_fx.TryGetValue(id, out var value))
			{
				FxMute(value);
				_fx.Remove(id);
				if (_fxOn <= 3)
				{
					Plugin.Log.LogInfo((object)"[fx] off");
				}
			}
		}

		public static void FxTick(float now)
		{
			if (_fx.Count == 0)
			{
				return;
			}
			_fxGone.Clear();
			foreach (KeyValuePair<int, FxState> item in _fx)
			{
				FxState value = item.Value;
				if (value == null || (Object)(object)value.Go == (Object)null || now > value.Until)
				{
					if (value != null)
					{
						FxMute(value);
					}
					_fxGone.Add(item.Key);
					continue;
				}
				try
				{
					if ((Object)(object)value.Eff != (Object)null)
					{
						R.Set(value.Eff, "timeCurrent", 2.5f);
						if (now >= value.NextReset)
						{
							value.NextReset = now + 1f;
							R.Call(value.Eff, "Reset");
						}
					}
				}
				catch
				{
				}
				try
				{
					if (value.Ps == null)
					{
						continue;
					}
					for (int i = 0; i < value.Ps.Length; i++)
					{
						ParticleSystem val = value.Ps[i];
						if ((Object)(object)val != (Object)null && !val.isPlaying)
						{
							val.Play();
						}
					}
				}
				catch
				{
				}
			}
			for (int j = 0; j < _fxGone.Count; j++)
			{
				_fx.Remove(_fxGone[j]);
			}
		}

		private static void Cleanup(float now)
		{
			if (now < _nextClean)
			{
				return;
			}
			_nextClean = now + 10f;
			if (_map.Count == 0)
			{
				return;
			}
			_gone.Clear();
			foreach (KeyValuePair<int, Tracked> item in _map)
			{
				Tracked value = item.Value;
				if (value == null || (Object)(object)value.Pgo == (Object)null)
				{
					if (value != null)
					{
						if (value.Guarded)
						{
							try
							{
								SetGuard(value.Pgo, value, on: false);
							}
							catch
							{
							}
						}
						Plugin.Log.LogInfo((object)("[gone] " + value.Label + " minY=" + value.MinY.ToString("F1") + " saves=" + value.Saves));
					}
					_gone.Add(item.Key);
				}
				else if ((Object)(object)value.Pgo.gameObject == (Object)null)
				{
					_gone.Add(item.Key);
				}
			}
			for (int i = 0; i < _gone.Count; i++)
			{
				_map.Remove(_gone[i]);
			}
		}
	}
	[BepInPlugin("com.yanyan.pitsave", "PitSave", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.yanyan.pitsave";

		public const string NAME = "PitSave";

		public const string VERSION = "1.1.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private float _hbNext;

		private float _errNext;

		private int _tickCount;

		private void Awake()
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				Cfg.Bind(((BaseUnityPlugin)this).Config);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[awake] cfg ex " + ex.Message));
			}
			try
			{
				Lang.Hook();
			}
			catch (Exception ex2)
			{
				Log.LogError((object)("[awake] lang hook ex " + ex2.Message));
			}
			GameObject gameObject = ((Component)this).gameObject;
			PitRunner pitRunner = null;
			try
			{
				pitRunner = gameObject.AddComponent<PitRunner>();
			}
			catch (Exception ex3)
			{
				Log.LogError((object)("[awake] add runner ex " + ex3.Message));
			}
			ManualLogSource log = Log;
			string[] obj = new string[10]
			{
				"PitSave 1.1.0 loaded runner=",
				((Object)(object)pitRunner != (Object)null).ToString(),
				" goAct=",
				gameObject.activeInHierarchy.ToString(),
				" hide=",
				((object)((Object)gameObject).hideFlags/*cast due to .constrained prefix*/).ToString(),
				" selfEn=",
				((Behaviour)this).enabled.ToString(),
				" scene=",
				null
			};
			Scene activeScene = SceneManager.GetActiveScene();
			obj[9] = ((Scene)(ref activeScene)).name;
			log.LogInfo((object)string.Concat(obj));
		}

		private void Start()
		{
			Log.LogInfo((object)"[start] plugin Start fired");
		}

		private void Update()
		{
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			_tickCount++;
			try
			{
				Lang.RefreshTick();
			}
			catch
			{
			}
			try
			{
				Pit.Tick();
			}
			catch (Exception ex)
			{
				if (Time.unscaledTime > _errNext)
				{
					_errNext = Time.unscaledTime + 5f;
					if (Log != null)
					{
						Log.LogError((object)("[tick-ex] " + ex.GetType().Name + " " + ex.Message));
					}
				}
			}
			if (Time.unscaledTime > _hbNext)
			{
				_hbNext = Time.unscaledTime + 15f;
				bool flag = Cfg.Enabled != null && Cfg.Enabled.Value;
				bool flag2 = false;
				try
				{
					flag2 = Pit.IsHost();
				}
				catch
				{
				}
				ManualLogSource log = Log;
				string[] obj3 = new string[8]
				{
					"[hb] alive en=",
					flag.ToString(),
					" host=",
					flag2.ToString(),
					" ticks=",
					_tickCount.ToString(),
					" lvl=",
					null
				};
				Scene activeScene = SceneManager.GetActiveScene();
				obj3[7] = ((Scene)(ref activeScene)).name;
				log.LogInfo((object)string.Concat(obj3));
			}
		}

		private void OnGUI()
		{
			try
			{
				Toast.Draw();
			}
			catch
			{
			}
		}
	}
	public class PitRunner : MonoBehaviour
	{
		private bool _said;

		private void Update()
		{
			if (!_said)
			{
				_said = true;
				if (Plugin.Log != null)
				{
					Plugin.Log.LogInfo((object)"[runner] own Update fired");
				}
			}
		}
	}
	internal static class R
	{
		private const BindingFlags BF = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly Dictionary<string, Type> _types = new Dictionary<string, Type>();

		public static Type FindType(string simpleName)
		{
			if (string.IsNullOrEmpty(simpleName))
			{
				return null;
			}
			if (_types.TryGetValue(simpleName, out var value))
			{
				return value;
			}
			Type type = null;
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					Type[] types;
					try
					{
						types = assembly.GetTypes();
					}
					catch
					{
						continue;
					}
					Type[] array = types;
					foreach (Type type2 in array)
					{
						if (type2.Name == simpleName)
						{
							type = type2;
							break;
						}
					}
					if (type != null)
					{
						break;
					}
				}
			}
			catch
			{
			}
			_types[simpleName] = type;
			return type;
		}

		public static object Get(object o, string name)
		{
			if (o == null)
			{
				return null;
			}
			try
			{
				Type type = o.GetType();
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field.GetValue(field.IsStatic ? null : o);
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanRead)
				{
					MethodInfo getMethod = property.GetGetMethod(nonPublic: true);
					if (getMethod != null)
					{
						return property.GetValue(getMethod.IsStatic ? null : o);
					}
				}
			}
			catch
			{
			}
			return null;
		}

		public static void Set(object o, string name, object v)
		{
			if (o == null)
			{
				return;
			}
			try
			{
				Type type = o.GetType();
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					field.SetValue(field.IsStatic ? null : o, v);
					return;
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanWrite)
				{
					MethodInfo setMethod = property.GetSetMethod(nonPublic: true);
					if (setMethod != null)
					{
						property.SetValue(setMethod.IsStatic ? null : o, v);
					}
				}
			}
			catch
			{
			}
		}

		public static object Static(Type t, string name)
		{
			if (t == null)
			{
				return null;
			}
			try
			{
				FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (fieldInfo.Name == name && fieldInfo.IsStatic)
					{
						return fieldInfo.GetValue(null);
					}
				}
				PropertyInfo[] properties = t.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (PropertyInfo propertyInfo in properties)
				{
					MethodInfo getMethod = propertyInfo.GetGetMethod(nonPublic: true);
					if (propertyInfo.Name == name && getMethod != null && getMethod.IsStatic)
					{
						return propertyInfo.GetValue(null);
					}
				}
			}
			catch
			{
			}
			return null;
		}

		public static object Call(object o, string name, params object[] args)
		{
			if (o == null)
			{
				return null;
			}
			try
			{
				MethodInfo[] methods = o.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (!(methodInfo.Name != name) && methodInfo.GetParameters().Length == args.Length)
					{
						try
						{
							return methodInfo.Invoke(methodInfo.IsStatic ? null : o, args);
						}
						catch
						{
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		public static int Int(object o)
		{
			try
			{
				if (o == null)
				{
					return 0;
				}
				if (o is int result)
				{
					return result;
				}
				return Convert.ToInt32(o);
			}
			catch
			{
				return 0;
			}
		}

		public static float Num(object o)
		{
			try
			{
				if (o == null)
				{
					return 0f;
				}
				if (o is float result)
				{
					return result;
				}
				return Convert.ToSingle(o);
			}
			catch
			{
				return 0f;
			}
		}

		public static string Str(object o)
		{
			return o as string;
		}

		public static bool Bool(object o)
		{
			bool flag = default(bool);
			int num;
			if (o is bool)
			{
				flag = (bool)o;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}
	}
	internal static class Toast
	{
		private class Item
		{
			public string Text;

			public float Until;
		}

		private static readonly List<Item> _items = new List<Item>();

		private static GUIStyle _st;

		public static void Push(string name)
		{
			_items.Add(new Item
			{
				Text = name,
				Until = Time.unscaledTime + 2.6f
			});
			if (_items.Count > 5)
			{
				_items.RemoveAt(0);
			}
		}

		public static void Draw()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			float unscaledTime = Time.unscaledTime;
			for (int num = _items.Count - 1; num >= 0; num--)
			{
				if (_items[num].Until < unscaledTime)
				{
					_items.RemoveAt(num);
				}
			}
			if (_items.Count != 0)
			{
				if (_st == null)
				{
					_st = new GUIStyle(GUI.skin.label);
					_st.fontSize = 17;
					_st.alignment = (TextAnchor)5;
				}
				float num2 = (float)Screen.height * 0.64f;
				for (int i = 0; i < _items.Count; i++)
				{
					Item item = _items[i];
					float num3 = item.Until - unscaledTime;
					float num4 = ((num3 > 0.6f) ? 0.95f : (Mathf.Clamp01(num3 / 0.6f) * 0.95f));
					_st.normal.textColor = new Color(0.55f, 1f, 0.62f, num4);
					GUI.Label(new Rect((float)Screen.width - 340f, num2 + (float)i * 23f, 320f, 23f), "PitSave  saved " + item.Text, _st);
				}
			}
		}
	}
}