Decompiled source of PEAK MX v1.0.0

PEAK-MX.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using Steamworks;
using UnityEngine;
using Zorro.Core;
using Zorro.Core.Serizalization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[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 PeakMX
{
	public static class ActionTracker
	{
		private const string EventUrl = "https://peak-mx.rkngov.com/api/event";

		public static void Track(string name, double? value = null, Dictionary<string, object> meta = null)
		{
			if (!ModConfig.AllowAnonymousStats.Value)
			{
				return;
			}
			string id = ModConfig.InstallId.Value;
			if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(name))
			{
				return;
			}
			Task.Run(delegate
			{
				try
				{
					ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
					using WebClient webClient = new WebClient
					{
						Encoding = Encoding.UTF8
					};
					webClient.Headers[HttpRequestHeader.ContentType] = "application/json";
					webClient.UploadString("https://peak-mx.rkngov.com/api/event", "POST", BuildJson(id, name, value, meta));
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogDebug((object)("[ActionTracker] " + name + ": " + ex.Message));
					}
				}
			});
		}

		private static string BuildJson(string id, string name, double? value, Dictionary<string, object> meta)
		{
			StringBuilder stringBuilder = new StringBuilder(256);
			stringBuilder.Append('{');
			WriteProp(stringBuilder, "id", id);
			stringBuilder.Append(',');
			WriteProp(stringBuilder, "type", "action");
			stringBuilder.Append(',');
			WriteProp(stringBuilder, "name", name);
			stringBuilder.Append(',');
			WriteProp(stringBuilder, "t", "peak-mx-public-v1");
			if (value.HasValue)
			{
				stringBuilder.Append(',');
				stringBuilder.Append("\"value\":").Append(value.Value.ToString(CultureInfo.InvariantCulture));
			}
			if (meta != null && meta.Count > 0)
			{
				stringBuilder.Append(',');
				stringBuilder.Append("\"meta\":");
				WriteObject(stringBuilder, meta);
			}
			stringBuilder.Append('}');
			return stringBuilder.ToString();
		}

		private static void WriteObject(StringBuilder sb, Dictionary<string, object> values)
		{
			sb.Append('{');
			bool flag = true;
			foreach (KeyValuePair<string, object> value in values)
			{
				if (!string.IsNullOrEmpty(value.Key) && value.Value != null)
				{
					if (!flag)
					{
						sb.Append(',');
					}
					flag = false;
					WritePropName(sb, value.Key);
					WriteValue(sb, value.Value);
				}
			}
			sb.Append('}');
		}

		private static void WriteValue(StringBuilder sb, object value)
		{
			if (value != null)
			{
				if (!(value is string value2))
				{
					if (!(value is bool flag))
					{
						if (!(value is int value3))
						{
							if (!(value is long value4))
							{
								if (!(value is float num))
								{
									if (!(value is double num2))
									{
										if (value is Dictionary<string, object> values)
										{
											WriteObject(sb, values);
										}
										else
										{
											WriteString(sb, value.ToString());
										}
									}
									else
									{
										sb.Append(num2.ToString(CultureInfo.InvariantCulture));
									}
								}
								else
								{
									sb.Append(num.ToString(CultureInfo.InvariantCulture));
								}
							}
							else
							{
								sb.Append(value4);
							}
						}
						else
						{
							sb.Append(value3);
						}
					}
					else
					{
						sb.Append(flag ? "true" : "false");
					}
				}
				else
				{
					WriteString(sb, value2);
				}
			}
			else
			{
				sb.Append("null");
			}
		}

		private static void WriteProp(StringBuilder sb, string key, string value)
		{
			WritePropName(sb, key);
			WriteString(sb, value);
		}

		private static void WritePropName(StringBuilder sb, string key)
		{
			WriteString(sb, key);
			sb.Append(':');
		}

		private static void WriteString(StringBuilder sb, string value)
		{
			if (value == null)
			{
				sb.Append("null");
				return;
			}
			sb.Append('"');
			foreach (char c in value)
			{
				switch (c)
				{
				case '"':
					sb.Append("\\\"");
					continue;
				case '\\':
					sb.Append("\\\\");
					continue;
				case '\n':
					sb.Append("\\n");
					continue;
				case '\r':
					sb.Append("\\r");
					continue;
				case '\t':
					sb.Append("\\t");
					continue;
				}
				if (c < ' ')
				{
					StringBuilder stringBuilder = sb.Append("\\u");
					int num = c;
					stringBuilder.Append(num.ToString("x4"));
				}
				else
				{
					sb.Append(c);
				}
			}
			sb.Append('"');
		}
	}
	public static class CheatTracker
	{
		private const string EventUrl = "https://peak-mx.rkngov.com/api/event";

		private static readonly Dictionary<string, bool> _prev = new Dictionary<string, bool>();

		private static readonly Dictionary<string, float> _since = new Dictionary<string, float>();

		private static (string name, Func<bool> get)[] _cheats;

		public static void Tick()
		{
			if (!ModConfig.AllowAnonymousStats.Value)
			{
				return;
			}
			if (_cheats == null)
			{
				Build();
			}
			(string, Func<bool>)[] cheats = _cheats;
			for (int i = 0; i < cheats.Length; i++)
			{
				(string, Func<bool>) tuple = cheats[i];
				string item = tuple.Item1;
				bool flag = tuple.Item2();
				bool value;
				bool flag2 = _prev.TryGetValue(item, out value) && value;
				if (flag != flag2)
				{
					_prev[item] = flag;
					if (flag)
					{
						_since[item] = Time.realtimeSinceStartup;
						Send(item, null);
					}
					else
					{
						float value2;
						float num = (_since.TryGetValue(item, out value2) ? (Time.realtimeSinceStartup - value2) : 0f);
						Send(item, Math.Max(0, (int)num));
					}
				}
			}
		}

		private static void Build()
		{
			_cheats = new(string, Func<bool>)[30]
			{
				("speed", () => ModConfig.SpeedMod),
				("jump", () => ModConfig.JumpMod),
				("infinitejumps", () => ModConfig.InfiniteJumps),
				("climb", () => ModConfig.ClimbMod),
				("vineclimb", () => ModConfig.VineClimbMod),
				("ropeclimb", () => ModConfig.RopeClimbMod),
				("god", () => ModConfig.GodMode),
				("infstamina", () => ModConfig.InfiniteStamina),
				("nofall", () => ModConfig.NoFallDamage),
				("nofallingragdoll", () => ModConfig.NoFallingRagdoll),
				("noweight", () => ModConfig.NoWeight),
				("lockstatus", () => ModConfig.LockStatus),
				("nostatus", () => ModConfig.NoStatusEffects),
				("noinjury", () => ModConfig.NoInjury),
				("nohunger", () => ModConfig.NoHunger),
				("nocold", () => ModConfig.NoCold),
				("nopoison", () => ModConfig.NoPoison),
				("nocurse", () => ModConfig.NoCurse),
				("nodrowsy", () => ModConfig.NoDrowsy),
				("nohot", () => ModConfig.NoHot),
				("staminaregendelay", () => ModConfig.StaminaRegenDelayMod),
				("longinteract", () => ModConfig.LongInteraction),
				("cinematiccam", () => ModConfig.CinematicCamera),
				("noslippery", () => ModConfig.NoSlipperySurfaces),
				("gamespeed", () => ModConfig.GameSpeedMod),
				("unlimitedlantern", () => ModConfig.UnlimitedLanternFuel),
				("unlimiteditems", () => ModConfig.UnlimitedItemUses),
				("infiniteitems", () => ModConfig.InfiniteItems),
				("teleportping", () => ModConfig.TeleportToPing),
				("fly", () => ModConfig.Fly)
			};
		}

		private static void Send(string name, int? value)
		{
			string value2 = ModConfig.InstallId.Value;
			if (string.IsNullOrEmpty(value2))
			{
				return;
			}
			string url = "https://peak-mx.rkngov.com/api/event?id=" + Uri.EscapeDataString(value2) + "&type=cheat&name=" + Uri.EscapeDataString(name) + "&t=" + Uri.EscapeDataString("peak-mx-public-v1");
			if (value.HasValue)
			{
				url += $"&value={value.Value}";
			}
			Task.Run(delegate
			{
				try
				{
					ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
					using WebClient webClient = new WebClient();
					webClient.DownloadString(url);
				}
				catch
				{
				}
			});
		}
	}
	public static class Diagnostics
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static LogCallback <0>__OnLog;
		}

		private const string DiagUrl = "https://peak-mx.rkngov.com/api/diag";

		private const string CrashUrl = "https://peak-mx.rkngov.com/api/crash";

		private const string LobbyUrl = "https://peak-mx.rkngov.com/api/lobby";

		private static bool _diagSent;

		private static readonly HashSet<string> _seenCrashes = new HashSet<string>();

		private static int _crashCount;

		private static string _lastLobby;

		public static void SendDiagOnce()
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			if (_diagSent || !ModConfig.AllowAnonymousStats.Value || string.IsNullOrEmpty(ModConfig.InstallId.Value))
			{
				return;
			}
			_diagSent = true;
			string id = ModConfig.InstallId.Value;
			string os = SystemInfo.operatingSystem;
			string cpu = $"{SystemInfo.processorType} ({SystemInfo.processorCount} cores)";
			string gpu = $"{SystemInfo.graphicsDeviceName} ({SystemInfo.graphicsMemorySize} MB)";
			int ram = SystemInfo.systemMemorySize;
			Resolution currentResolution = Screen.currentResolution;
			object arg = ((Resolution)(ref currentResolution)).width;
			currentResolution = Screen.currentResolution;
			string screen = $"{arg}x{((Resolution)(ref currentResolution)).height}";
			string gameVer = SafeStr(() => Application.version);
			string bepinex = SafeBepInEx();
			string mods = string.Join(", ", SafePlugins());
			string steamid = SafeSteamId();
			string nick = SafeStr(() => PhotonNetwork.NickName);
			Task.Run(delegate
			{
				try
				{
					StringBuilder stringBuilder = new StringBuilder("{");
					JS(stringBuilder, "id", id);
					C(stringBuilder);
					JS(stringBuilder, "t", "peak-mx-public-v1");
					C(stringBuilder);
					JS(stringBuilder, "os", os);
					C(stringBuilder);
					JS(stringBuilder, "cpu", cpu);
					C(stringBuilder);
					JS(stringBuilder, "gpu", gpu);
					C(stringBuilder);
					JN(stringBuilder, "ram", ram);
					C(stringBuilder);
					JS(stringBuilder, "screen", screen);
					C(stringBuilder);
					JS(stringBuilder, "gameVer", gameVer);
					C(stringBuilder);
					JS(stringBuilder, "bepinex", bepinex);
					C(stringBuilder);
					JS(stringBuilder, "steamid", steamid);
					C(stringBuilder);
					JS(stringBuilder, "nick", nick);
					C(stringBuilder);
					JS(stringBuilder, "mods", mods);
					stringBuilder.Append('}');
					Post("https://peak-mx.rkngov.com/api/diag", stringBuilder.ToString());
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogDebug((object)("[Diag] " + ex.Message));
					}
				}
			});
		}

		public static void HookCrashes()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (ModConfig.AllowAnonymousStats.Value)
			{
				object obj = <>O.<0>__OnLog;
				if (obj == null)
				{
					LogCallback val = OnLog;
					<>O.<0>__OnLog = val;
					obj = (object)val;
				}
				Application.logMessageReceived += (LogCallback)obj;
			}
		}

		private static void OnLog(string condition, string stack, LogType type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (((int)type != 4 && (int)type != 0) || _crashCount >= 20 || !ModConfig.AllowAnonymousStats.Value)
			{
				return;
			}
			string text = condition ?? "";
			if (text.Length > 160)
			{
				text = text.Substring(0, 160);
			}
			if (!_seenCrashes.Add(text))
			{
				return;
			}
			_crashCount++;
			string id = ModConfig.InstallId.Value;
			string msg = condition ?? "";
			string st = stack ?? "";
			Task.Run(delegate
			{
				try
				{
					StringBuilder stringBuilder = new StringBuilder("{");
					JS(stringBuilder, "id", id);
					C(stringBuilder);
					JS(stringBuilder, "t", "peak-mx-public-v1");
					C(stringBuilder);
					JS(stringBuilder, "message", msg);
					C(stringBuilder);
					JS(stringBuilder, "stack", st);
					stringBuilder.Append('}');
					Post("https://peak-mx.rkngov.com/api/crash", stringBuilder.ToString());
				}
				catch
				{
				}
			});
		}

		public static void SendLobby(List<string> nicks)
		{
			if (!ModConfig.AllowAnonymousStats.Value || nicks == null || nicks.Count == 0 || string.IsNullOrEmpty(ModConfig.InstallId.Value))
			{
				return;
			}
			string text = string.Join(", ", nicks);
			if (text == _lastLobby)
			{
				return;
			}
			_lastLobby = text;
			string id = ModConfig.InstallId.Value;
			List<string> list = new List<string>(nicks);
			Task.Run(delegate
			{
				try
				{
					StringBuilder stringBuilder = new StringBuilder("{");
					JS(stringBuilder, "id", id);
					C(stringBuilder);
					JS(stringBuilder, "t", "peak-mx-public-v1");
					C(stringBuilder);
					stringBuilder.Append("\"nicks\":[");
					for (int i = 0; i < list.Count; i++)
					{
						if (i > 0)
						{
							stringBuilder.Append(',');
						}
						Str(stringBuilder, list[i]);
					}
					stringBuilder.Append("]}");
					Post("https://peak-mx.rkngov.com/api/lobby", stringBuilder.ToString());
				}
				catch
				{
				}
			});
		}

		private static void Post(string url, string json)
		{
			ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
			using WebClient webClient = new WebClient
			{
				Encoding = Encoding.UTF8
			};
			webClient.Headers[HttpRequestHeader.ContentType] = "application/json";
			webClient.UploadString(url, "POST", json);
		}

		private static void C(StringBuilder sb)
		{
			sb.Append(',');
		}

		private static void JS(StringBuilder sb, string k, string v)
		{
			sb.Append('"').Append(k).Append("\":");
			Str(sb, v);
		}

		private static void JN(StringBuilder sb, string k, int v)
		{
			sb.Append('"').Append(k).Append("\":")
				.Append(v);
		}

		private static void Str(StringBuilder sb, string v)
		{
			if (v == null)
			{
				sb.Append("null");
				return;
			}
			sb.Append('"');
			foreach (char c in v)
			{
				switch (c)
				{
				case '"':
					sb.Append("\\\"");
					continue;
				case '\\':
					sb.Append("\\\\");
					continue;
				case '\n':
					sb.Append("\\n");
					continue;
				case '\r':
					sb.Append("\\r");
					continue;
				case '\t':
					sb.Append("\\t");
					continue;
				}
				if (c < ' ')
				{
					StringBuilder stringBuilder = sb.Append("\\u");
					int num = c;
					stringBuilder.Append(num.ToString("x4"));
				}
				else
				{
					sb.Append(c);
				}
			}
			sb.Append('"');
		}

		private static string SafeStr(Func<string> f)
		{
			try
			{
				return f();
			}
			catch
			{
				return null;
			}
		}

		private static string SafeBepInEx()
		{
			try
			{
				return typeof(BaseUnityPlugin).Assembly.GetName().Version.ToString();
			}
			catch
			{
				return null;
			}
		}

		private static List<string> SafePlugins()
		{
			try
			{
				return (from p in Chainloader.PluginInfos.Values
					select $"{p.Metadata.Name} {p.Metadata.Version}" into s
					orderby s
					select s).ToList();
			}
			catch
			{
				return new List<string>();
			}
		}

		private static string SafeSteamId()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (SteamAPI.IsSteamRunning())
				{
					return SteamUser.GetSteamID().m_SteamID.ToString();
				}
			}
			catch
			{
			}
			return null;
		}
	}
	public static class Features
	{
		private static readonly FieldRef<CharacterData, bool> InvincibleRef = AccessTools.FieldRefAccess<CharacterData, bool>("isInvincible");

		private static readonly FieldInfo ClimbSpeedF = AccessTools.Field(typeof(CharacterClimbing), "climbSpeedMod");

		private static readonly FieldInfo VineSpeedF = AccessTools.Field(typeof(CharacterVineClimbing), "climbSpeedMod");

		private static readonly FieldInfo RopeSpeedF = AccessTools.Field(typeof(CharacterRopeHandling), "climbSpeedMod");

		private static float _baseJumpImpulse = float.NaN;

		private static float[] _lockedStatuses;

		private static bool _godApplied;

		private static bool _speedApplied;

		private static bool _jumpApplied;

		private static bool _climbApplied;

		private static bool _vineApplied;

		private static bool _ropeApplied;

		private static float _itemTimer;

		private static float _timeOverrideTimer;

		private static float _adminTimer;

		private static float _baseInteractionDistance = -1f;

		private static float _baseInteractionArea = -1f;

		private static bool _timeScaleApplied;

		private static readonly Dictionary<PointPing, float> PingBaseFrustumSizes = new Dictionary<PointPing, float>();

		private static GameObject _cinematicObject;

		private static CameraOverride _cinematicOverride;

		private static Vector2 _cinematicLook;

		public static void Tick()
		{
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null)
			{
				return;
			}
			try
			{
				ApplyMovement(localCharacter);
			}
			catch (Exception e)
			{
				Warn("movement", e);
			}
			try
			{
				ApplyCheats(localCharacter);
			}
			catch (Exception e2)
			{
				Warn("cheats", e2);
			}
			try
			{
				ApplyInfiniteItems();
			}
			catch (Exception e3)
			{
				Warn("items", e3);
			}
			try
			{
				ApplyWorldOverrides();
			}
			catch (Exception e4)
			{
				Warn("world", e4);
			}
			try
			{
				ApplyUtilityModifiers(localCharacter);
			}
			catch (Exception e5)
			{
				Warn("utility", e5);
			}
			try
			{
				ApplyAdminProtection();
			}
			catch (Exception e6)
			{
				Warn("admin", e6);
			}
			try
			{
				GameApi.ApplyFrozenPlayers(Time.deltaTime);
			}
			catch (Exception e7)
			{
				Warn("freeze", e7);
			}
			try
			{
				GameApi.ApplyInventoryLocks(Time.deltaTime);
			}
			catch (Exception e8)
			{
				Warn("inventory-lock", e8);
			}
		}

		private static void ApplyInfiniteItems()
		{
			if (!ModConfig.InfiniteItems)
			{
				return;
			}
			_itemTimer += Time.deltaTime;
			if (!(_itemTimer < 0.5f))
			{
				_itemTimer = 0f;
				float value = ((ModConfig.RechargeValue > 0f) ? ModConfig.RechargeValue : 999f);
				int num = GameApi.SlotCount();
				for (int i = 0; i < num; i++)
				{
					GameApi.RechargeSlot(i, value);
				}
			}
		}

		private static void ApplyWorldOverrides()
		{
			if (!ModConfig.OverrideExpeditionTime)
			{
				_timeOverrideTimer = 0f;
				return;
			}
			_timeOverrideTimer += Time.deltaTime;
			if (_timeOverrideTimer < 0.5f)
			{
				return;
			}
			_timeOverrideTimer = 0f;
			if (ModConfig.ExpeditionTimeSeconds <= 0.01f)
			{
				float num = GameApi.ExpeditionTimeSeconds();
				if (!(num > 0.01f))
				{
					return;
				}
				ModConfig.ExpeditionTimeSeconds = num;
			}
			GameApi.SetExpeditionTime(ModConfig.ExpeditionTimeSeconds);
		}

		private static void ApplyAdminProtection()
		{
			_adminTimer += Time.deltaTime;
			if (!(_adminTimer < 2f))
			{
				_adminTimer = 0f;
				GameApi.EnforceAdminProtection();
			}
		}

		private static void ApplyMovement(Character c)
		{
			CharacterMovement val = c.refs?.movement;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (ModConfig.SpeedMod)
			{
				val.movementModifier = ModConfig.SpeedAmount;
				_speedApplied = true;
			}
			else if (_speedApplied)
			{
				val.movementModifier = 1f;
				_speedApplied = false;
			}
			if (ModConfig.JumpMod)
			{
				if (float.IsNaN(_baseJumpImpulse) || _baseJumpImpulse <= 0f)
				{
					_baseJumpImpulse = ((val.jumpImpulse > 0f) ? val.jumpImpulse : 4f);
				}
				val.jumpImpulse = _baseJumpImpulse * ModConfig.JumpAmount;
				_jumpApplied = true;
			}
			else if (_jumpApplied)
			{
				if (!float.IsNaN(_baseJumpImpulse) && _baseJumpImpulse > 0f)
				{
					val.jumpImpulse = _baseJumpImpulse;
				}
				_jumpApplied = false;
			}
			if (ModConfig.InfiniteJumps)
			{
				c.data.jumpsRemaining = Mathf.Max(c.data.jumpsRemaining, 1);
				if (c.data.sinceJump > 0.28f)
				{
					c.data.sinceGrounded = Mathf.Min(c.data.sinceGrounded, 0.18f);
				}
			}
			ApplyClimbField<CharacterClimbing>(c, ClimbSpeedF, ModConfig.ClimbMod, ModConfig.ClimbAmount, ref _climbApplied);
			ApplyClimbField<CharacterVineClimbing>(c, VineSpeedF, ModConfig.VineClimbMod, ModConfig.VineClimbAmount, ref _vineApplied);
			ApplyClimbField<CharacterRopeHandling>(c, RopeSpeedF, ModConfig.RopeClimbMod, ModConfig.RopeClimbAmount, ref _ropeApplied);
		}

		private static void ApplyClimbField<T>(Character c, FieldInfo f, bool on, float amount, ref bool applied) where T : Component
		{
			if (f == null)
			{
				return;
			}
			T component = ((Component)c).GetComponent<T>();
			if (!((Object)(object)component == (Object)null))
			{
				if (on)
				{
					f.SetValue(component, amount);
					applied = true;
				}
				else if (applied)
				{
					f.SetValue(component, 1f);
					applied = false;
				}
			}
		}

		private static void ApplyCheats(Character c)
		{
			CharacterData data = c.data;
			CharacterAfflictions val = ((c.refs != null) ? c.refs.afflictions : null);
			if (ModConfig.GodMode)
			{
				InvincibleRef.Invoke(data) = true;
				_godApplied = true;
			}
			else if (_godApplied)
			{
				InvincibleRef.Invoke(data) = false;
				data.RecalculateInvincibility();
				_godApplied = false;
			}
			if (ModConfig.InfiniteStamina)
			{
				data.currentStamina = 1f;
				data.extraStamina = Mathf.Max(data.extraStamina, 0f);
			}
			if (ModConfig.NoFallDamage)
			{
				data.fallSeconds = 0f;
			}
			if (ModConfig.NoFallingRagdoll)
			{
				data.fallSeconds = 0f;
			}
			if (ModConfig.NoSlipperySurfaces)
			{
				data.slippy = 0f;
				data.sinceFallSlide = Mathf.Max(data.sinceFallSlide, 2f);
			}
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			if (ModConfig.NoStatusEffects)
			{
				for (int i = 0; i < CharacterAfflictions.NumStatusTypes; i++)
				{
					val.SetStatus((STATUSTYPE)i, 0f, false);
				}
			}
			else
			{
				ClearBlockedStatus(val, (STATUSTYPE)0, ModConfig.NoInjury);
				ClearBlockedStatus(val, (STATUSTYPE)1, ModConfig.NoHunger);
				ClearBlockedStatus(val, (STATUSTYPE)2, ModConfig.NoCold);
				ClearBlockedStatus(val, (STATUSTYPE)3, ModConfig.NoPoison);
				ClearBlockedStatus(val, (STATUSTYPE)5, ModConfig.NoCurse);
				ClearBlockedStatus(val, (STATUSTYPE)6, ModConfig.NoDrowsy);
				ClearBlockedStatus(val, (STATUSTYPE)8, ModConfig.NoHot);
			}
			if (ModConfig.NoWeight)
			{
				val.SetStatus((STATUSTYPE)7, 0f, true);
			}
			if (ModConfig.LockStatus)
			{
				if (_lockedStatuses == null && val.currentStatuses != null)
				{
					_lockedStatuses = (float[])val.currentStatuses.Clone();
				}
				if (_lockedStatuses != null && val.currentStatuses != null)
				{
					Array.Copy(_lockedStatuses, val.currentStatuses, Mathf.Min(_lockedStatuses.Length, val.currentStatuses.Length));
				}
			}
			else
			{
				_lockedStatuses = null;
			}
		}

		private static void ClearBlockedStatus(CharacterAfflictions affl, STATUSTYPE type, bool blocked)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			if (blocked)
			{
				affl.SetStatus(type, 0f, false);
			}
		}

		private static void ApplyUtilityModifiers(Character c)
		{
			ApplyInteractionRange();
			ApplyGameSpeed();
			ApplyCinematicCamera(c);
			ApplyPingHandScale();
		}

		private static void ApplyInteractionRange()
		{
			Interaction instance = Interaction.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				if (_baseInteractionDistance < 0f)
				{
					_baseInteractionDistance = instance.distance;
					_baseInteractionArea = instance.area;
				}
				if (ModConfig.LongInteraction)
				{
					instance.distance = Mathf.Max(_baseInteractionDistance, ModConfig.InteractionDistance);
					instance.area = Mathf.Max(_baseInteractionArea, 1.25f);
				}
				else if (_baseInteractionDistance >= 0f)
				{
					instance.distance = _baseInteractionDistance;
					instance.area = _baseInteractionArea;
				}
			}
		}

		private static void ApplyGameSpeed()
		{
			if (ModConfig.GameSpeedMod)
			{
				Time.timeScale = Mathf.Clamp(ModConfig.GameSpeed, 0.05f, 5f);
				_timeScaleApplied = true;
			}
			else if (_timeScaleApplied)
			{
				Time.timeScale = 1f;
				_timeScaleApplied = false;
			}
		}

		private static void ApplyCinematicCamera(Character c)
		{
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.CinematicCamera)
			{
				DisableCinematicCamera();
				return;
			}
			if ((Object)(object)_cinematicObject == (Object)null)
			{
				_cinematicObject = new GameObject("PEAK-MX Cinematic Camera");
				Object.DontDestroyOnLoad((Object)(object)_cinematicObject);
				_cinematicOverride = _cinematicObject.AddComponent<CameraOverride>();
				Transform val = (((Object)(object)MainCamera.instance != (Object)null) ? ((Component)MainCamera.instance).transform : ((Component)c).transform);
				_cinematicObject.transform.position = val.position;
				_cinematicObject.transform.rotation = val.rotation;
				Quaternion rotation = _cinematicObject.transform.rotation;
				Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles;
				_cinematicLook = new Vector2(eulerAngles.y, eulerAngles.x);
				ActionTracker.Track("cinematic_camera_on");
			}
			_cinematicOverride.fov = Mathf.Clamp(ModConfig.CinematicCameraFov, 1f, 120f);
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			_cinematicLook.x += Input.GetAxis("Mouse X") * 140f * unscaledDeltaTime;
			_cinematicLook.y -= Input.GetAxis("Mouse Y") * 140f * unscaledDeltaTime;
			_cinematicLook.y = Mathf.Clamp(_cinematicLook.y, -89f, 89f);
			_cinematicObject.transform.rotation = Quaternion.Euler(_cinematicLook.y, _cinematicLook.x, 0f);
			Vector3 zero = Vector3.zero;
			if (Input.GetKey((KeyCode)119))
			{
				zero.z += 1f;
			}
			if (Input.GetKey((KeyCode)115))
			{
				zero.z -= 1f;
			}
			if (Input.GetKey((KeyCode)100))
			{
				zero.x += 1f;
			}
			if (Input.GetKey((KeyCode)97))
			{
				zero.x -= 1f;
			}
			if (Input.GetKey((KeyCode)32) || Input.GetKey((KeyCode)101))
			{
				zero.y += 1f;
			}
			if (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)113))
			{
				zero.y -= 1f;
			}
			float num = Mathf.Max(0.1f, ModConfig.CinematicCameraSpeed) * (Input.GetKey((KeyCode)304) ? 4f : 1f);
			Transform transform = _cinematicObject.transform;
			transform.position += _cinematicObject.transform.TransformDirection(((Vector3)(ref zero)).normalized) * num * unscaledDeltaTime;
			if ((Object)(object)MainCamera.instance != (Object)null)
			{
				MainCamera.instance.SetCameraOverride(_cinematicOverride);
			}
		}

		private static void DisableCinematicCamera()
		{
			if ((Object)(object)_cinematicObject == (Object)null)
			{
				return;
			}
			try
			{
				if ((Object)(object)MainCamera.instance != (Object)null)
				{
					MainCamera.instance.SetCameraOverride((CameraOverride)null);
				}
			}
			catch
			{
			}
			Object.Destroy((Object)(object)_cinematicObject);
			_cinematicObject = null;
			_cinematicOverride = null;
			ActionTracker.Track("cinematic_camera_off");
		}

		private static void ApplyPingHandScale()
		{
			float num = Mathf.Clamp(ModConfig.PingHandSizeMultiplier, 0.1f, 10f);
			PointPing[] array = Object.FindObjectsByType<PointPing>((FindObjectsSortMode)0);
			foreach (PointPing val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					if (!PingBaseFrustumSizes.ContainsKey(val))
					{
						PingBaseFrustumSizes[val] = Mathf.Max(0.001f, val.sizeOfFrustum);
					}
					val.sizeOfFrustum = PingBaseFrustumSizes[val] * num;
				}
			}
			if (!(Mathf.Abs(num - 1f) < 0.01f) || PingBaseFrustumSizes.Count <= 0)
			{
				return;
			}
			foreach (KeyValuePair<PointPing, float> pingBaseFrustumSize in PingBaseFrustumSizes)
			{
				if ((Object)(object)pingBaseFrustumSize.Key != (Object)null)
				{
					pingBaseFrustumSize.Key.sizeOfFrustum = pingBaseFrustumSize.Value;
				}
			}
			PingBaseFrustumSizes.Clear();
		}

		private static void Warn(string where, Exception e)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("[Features:" + where + "] " + e.Message));
			}
		}
	}
	public static class GameApi
	{
		public enum CosmeticCategory
		{
			Skin,
			Accessory,
			Eyes,
			Mouth,
			Outfit,
			Hat,
			Sash
		}

		public struct AdminListEntry
		{
			public string Key;

			public string Label;

			public AdminListEntry(string key, string label)
			{
				Key = key;
				Label = label;
			}
		}

		private struct AdminMotionSample
		{
			public Vector3 Position;

			public float Time;
		}

		public static readonly List<Item> Items = new List<Item>();

		public static readonly List<string> ItemNames = new List<string>();

		public static readonly List<Character> PlayerChars = new List<Character>();

		public static readonly List<string> PlayerNames = new List<string>();

		private static readonly HashSet<int> LocalCosmeticUnlocks = new HashSet<int>();

		private static readonly HashSet<string> SessionBans = new HashSet<string>();

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

		private static readonly HashSet<string> InventoryLocks = new HashSet<string>();

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

		private static readonly Dictionary<string, Vector3> FrozenPlayers = new Dictionary<string, Vector3>();

		private static readonly Dictionary<string, AdminMotionSample> AdminMotion = new Dictionary<string, AdminMotionSample>();

		private static readonly Dictionary<string, int> AdminStrikes = new Dictionary<string, int>();

		public static readonly List<string> AdminProtectionLog = new List<string>();

		private static float _freezeRpcTimer;

		private static float _inventoryLockTimer;

		private static bool _itemsEverLoaded;

		private static Customization _customizationDb;

		private static readonly MethodInfo CustomGetData = typeof(CharacterCustomization).GetMethod("GetCustomizationData", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo CustomSetData = typeof(CharacterCustomization).GetMethod("SetCustomizationData", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo CustomSetSkin = typeof(CharacterCustomization).GetMethod("SetCharacterSkinColor", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo CustomSetAccessory = typeof(CharacterCustomization).GetMethod("SetCharacterAccessory", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo CustomSetEyes = typeof(CharacterCustomization).GetMethod("SetCharacterEyes", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo CustomSetMouth = typeof(CharacterCustomization).GetMethod("SetCharacterMouth", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo CustomSetOutfit = typeof(CharacterCustomization).GetMethod("SetCharacterOutfit", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo CustomSetHat = typeof(CharacterCustomization).GetMethod("SetCharacterHat", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo CustomSetSash = typeof(CharacterCustomization).GetMethod("SetCharacterSash", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		public static readonly List<string> LuggageLabels = new List<string>();

		public static readonly List<Luggage> LuggageObjects = new List<Luggage>();

		public static readonly string[] StatusEn = new string[12]
		{
			"Injury", "Hunger", "Cold", "Poison", "Crab", "Curse", "Drowsy", "Weight", "Hot", "Thorns",
			"Spores", "Web"
		};

		public static readonly string[] StatusRu = new string[12]
		{
			"Травма", "Голод", "Холод", "Яд", "Краб", "Проклятие", "Сонливость", "Вес", "Жара", "Шипы",
			"Споры", "Паутина"
		};

		public static void LoadItems()
		{
			try
			{
				Items.Clear();
				ItemNames.Clear();
				Object obj = Resources.Load("ItemDatabase", typeof(ItemDatabase));
				ItemDatabase val = (ItemDatabase)(object)((obj is ItemDatabase) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					foreach (Item @object in ((DatabaseAsset<ItemDatabase, Item>)(object)val).Objects)
					{
						Add(@object);
					}
				}
				Object[] array = Resources.LoadAll("0_Items", typeof(Item));
				foreach (Object obj2 in array)
				{
					Add((Item)(object)((obj2 is Item) ? obj2 : null));
				}
				array = Resources.FindObjectsOfTypeAll(typeof(Item));
				foreach (Object obj3 in array)
				{
					Add((Item)(object)((obj3 is Item) ? obj3 : null));
				}
				_itemsEverLoaded = ItemNames.Count > 0;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[GameApi] items loaded: {ItemNames.Count}");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[GameApi] LoadItems: " + ex.Message));
				}
			}
		}

		public static bool EnsureItemsLoaded()
		{
			if (_itemsEverLoaded && ItemNames.Count > 0)
			{
				return false;
			}
			LoadItems();
			if (ItemNames.Count > 0)
			{
				ActionTracker.Track("items_load", ItemNames.Count);
			}
			return ItemNames.Count > 0;
		}

		private static void Add(Item it)
		{
			if ((Object)(object)it == (Object)null)
			{
				return;
			}
			try
			{
				if (IsInventorySpawnableItem(it))
				{
					string name = it.GetName();
					if (!string.IsNullOrEmpty(name) && !HasItemAlready(it, name))
					{
						Items.Add(it);
						ItemNames.Add(name);
					}
				}
			}
			catch
			{
			}
		}

		private static bool HasItemAlready(Item item, string displayName)
		{
			for (int i = 0; i < Items.Count; i++)
			{
				Item val = Items[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				try
				{
					if ((Object)(object)val == (Object)(object)item)
					{
						return true;
					}
					if (val.itemID == item.itemID && (Object)(object)((Component)val).gameObject != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, ((Object)((Component)item).gameObject).name, StringComparison.Ordinal))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			return ItemNames.Contains(displayName);
		}

		private static bool IsInventorySpawnableItem(Item item)
		{
			try
			{
				if ((Object)(object)item == (Object)null || item.UIData == null || (Object)(object)((Component)item).gameObject == (Object)null)
				{
					return false;
				}
				if ((((Object)((Component)item).gameObject).name ?? "").IndexOf("BaseConstructable", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return false;
				}
				if (!HasResourcePrefab(item))
				{
					return false;
				}
				if (!item.UIData.canPocket && !item.UIData.canBackpack)
				{
					return false;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool CanPocketItem(int itemIndex)
		{
			try
			{
				return itemIndex >= 0 && itemIndex < Items.Count && (Object)(object)Items[itemIndex] != (Object)null && Items[itemIndex].UIData != null && Items[itemIndex].UIData.canPocket && HasResourcePrefab(Items[itemIndex]);
			}
			catch
			{
				return false;
			}
		}

		private static bool CanBackpackItem(int itemIndex)
		{
			try
			{
				return itemIndex >= 0 && itemIndex < Items.Count && (Object)(object)Items[itemIndex] != (Object)null && Items[itemIndex].UIData != null && Items[itemIndex].UIData.canBackpack && HasResourcePrefab(Items[itemIndex]);
			}
			catch
			{
				return false;
			}
		}

		private static bool HasResourcePrefab(Item item)
		{
			try
			{
				if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null)
				{
					return false;
				}
				return HasResourcePrefabName(((Object)((Component)item).gameObject).name);
			}
			catch
			{
				return false;
			}
		}

		private static bool HasResourcePrefabName(string prefabName)
		{
			try
			{
				if (string.IsNullOrWhiteSpace(prefabName))
				{
					return false;
				}
				return Resources.Load("0_Items/" + prefabName, typeof(GameObject)) != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static int RandomItemIndexForSlot(bool backpack)
		{
			EnsureItemsLoaded();
			List<int> list = new List<int>();
			for (int i = 0; i < Items.Count; i++)
			{
				if (backpack ? CanBackpackItem(i) : CanPocketItem(i))
				{
					list.Add(i);
				}
			}
			if (list.Count == 0)
			{
				return -1;
			}
			return list[Random.Range(0, list.Count)];
		}

		public static Texture2D ItemIcon(int index)
		{
			try
			{
				Item val = ((index >= 0 && index < Items.Count) ? Items[index] : null);
				if ((Object)(object)val == (Object)null || val.UIData == null)
				{
					return null;
				}
				Texture2D icon = val.UIData.icon;
				if ((Object)(object)icon != (Object)null)
				{
					return icon;
				}
				return TryTextureMember(val.UIData, "altIcon", "colorBlindIcon", "sprite", "smallIcon", "inventoryIcon");
			}
			catch
			{
				return null;
			}
		}

		private static Texture2D TryTextureMember(object source, params string[] names)
		{
			if (source == null || names == null)
			{
				return null;
			}
			Type type = source.GetType();
			foreach (string name in names)
			{
				try
				{
					FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null)
					{
						object value = field.GetValue(source);
						Texture2D val = (Texture2D)((value is Texture2D) ? value : null);
						if (val != null)
						{
							return val;
						}
						Sprite val2 = (Sprite)((value is Sprite) ? value : null);
						if (val2 != null && (Object)(object)val2.texture != (Object)null)
						{
							return val2.texture;
						}
					}
				}
				catch
				{
				}
				try
				{
					PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (property != null)
					{
						object value2 = property.GetValue(source, null);
						Texture2D val3 = (Texture2D)((value2 is Texture2D) ? value2 : null);
						if (val3 != null)
						{
							return val3;
						}
						Sprite val4 = (Sprite)((value2 is Sprite) ? value2 : null);
						if (val4 != null && (Object)(object)val4.texture != (Object)null)
						{
							return val4.texture;
						}
					}
				}
				catch
				{
				}
			}
			return null;
		}

		public static bool SpawnToSlot(int itemIndex, int slot)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			try
			{
				Player localPlayer = Player.localPlayer;
				if ((Object)(object)localPlayer == (Object)null || localPlayer.itemSlots == null)
				{
					return false;
				}
				if (slot < 0 || slot >= localPlayer.itemSlots.Length)
				{
					return false;
				}
				if (itemIndex < 0 || itemIndex >= Items.Count)
				{
					return false;
				}
				if (!CanPocketItem(itemIndex))
				{
					return false;
				}
				ItemSlot obj = localPlayer.itemSlots[slot];
				obj.prefab = Items[itemIndex];
				obj.data = new ItemInstanceData(Guid.NewGuid());
				ItemInstanceDataHandler.AddInstanceData(obj.data);
				SyncInventory(localPlayer);
				ActionTracker.Track("inventory_spawn_local", null, new Dictionary<string, object>
				{
					["slot"] = slot,
					["item"] = ItemNames[itemIndex]
				});
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] SpawnToSlot: " + ex.Message));
				}
				return false;
			}
		}

		public static bool ClearSlot(int slot)
		{
			try
			{
				Player localPlayer = Player.localPlayer;
				if ((Object)(object)localPlayer == (Object)null || localPlayer.itemSlots == null || slot < 0 || slot >= localPlayer.itemSlots.Length)
				{
					return false;
				}
				ItemSlot obj = localPlayer.itemSlots[slot];
				obj.prefab = null;
				obj.data = null;
				SyncInventory(localPlayer);
				ActionTracker.Track("inventory_clear_local", null, new Dictionary<string, object> { ["slot"] = slot });
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] ClearSlot: " + ex.Message));
				}
				return false;
			}
		}

		private static void SyncInventory(Player p)
		{
			SyncInventory(p, (RpcTarget)1);
		}

		private static void SyncInventory(Player p, RpcTarget target)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			byte[] array = IBinarySerializable.ToManagedArray<InventorySyncData>(new InventorySyncData(p.itemSlots, p.backpackSlot, p.tempFullSlot));
			((MonoBehaviourPun)p).photonView.RPC("SyncInventoryRPC", target, new object[2] { array, true });
		}

		private static Player PlayerOf(Character c)
		{
			try
			{
				return ((Object)(object)c != (Object)null) ? c.player : null;
			}
			catch
			{
				return null;
			}
		}

		private static bool IsLocal(Character c)
		{
			try
			{
				return (Object)(object)c == (Object)null || c.IsLocal || (Object)(object)c == (Object)(object)Character.localCharacter;
			}
			catch
			{
				return (Object)(object)c == (Object)null || (Object)(object)c == (Object)(object)Character.localCharacter;
			}
		}

		public static bool IsHost()
		{
			try
			{
				return PhotonNetwork.IsMasterClient;
			}
			catch
			{
				return PhotonNetwork.IsMasterClient;
			}
		}

		private static CharacterCustomization LocalCustomization()
		{
			try
			{
				return (!((Object)(object)Character.localCharacter != (Object)null)) ? null : Character.localCharacter.refs?.customization;
			}
			catch
			{
				return null;
			}
		}

		private static Customization CustomizationDb()
		{
			try
			{
				if ((Object)(object)_customizationDb != (Object)null)
				{
					return _customizationDb;
				}
				_customizationDb = Resources.FindObjectsOfTypeAll<Customization>().FirstOrDefault();
				return _customizationDb;
			}
			catch
			{
				return null;
			}
		}

		public static bool SpawnToSlotFor(Character target, int itemIndex, int slot)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			try
			{
				if (IsLocal(target))
				{
					return SpawnToSlot(itemIndex, slot);
				}
				Player val = PlayerOf(target);
				if ((Object)(object)val == (Object)null || val.itemSlots == null)
				{
					return false;
				}
				if (slot < 0 || slot >= val.itemSlots.Length)
				{
					return false;
				}
				if (itemIndex < 0 || itemIndex >= Items.Count)
				{
					return false;
				}
				if (!CanPocketItem(itemIndex))
				{
					return false;
				}
				ItemSlot obj = val.itemSlots[slot];
				obj.prefab = Items[itemIndex];
				obj.data = new ItemInstanceData(Guid.NewGuid());
				ItemInstanceDataHandler.AddInstanceData(obj.data);
				SyncInventory(val, (RpcTarget)0);
				ActionTracker.Track("inventory_spawn_remote", null, new Dictionary<string, object>
				{
					["slot"] = slot,
					["item"] = ItemNames[itemIndex],
					["target"] = SafeCharacterName(target)
				});
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] SpawnToSlotFor: " + ex.Message));
				}
				return false;
			}
		}

		public static bool ClearSlotFor(Character target, int slot)
		{
			try
			{
				if (IsLocal(target))
				{
					return ClearSlot(slot);
				}
				Player val = PlayerOf(target);
				if ((Object)(object)val == (Object)null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length)
				{
					return false;
				}
				ItemSlot obj = val.itemSlots[slot];
				obj.prefab = null;
				obj.data = null;
				SyncInventory(val, (RpcTarget)0);
				ActionTracker.Track("inventory_clear_remote", null, new Dictionary<string, object>
				{
					["slot"] = slot,
					["target"] = SafeCharacterName(target)
				});
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] ClearSlotFor: " + ex.Message));
				}
				return false;
			}
		}

		public static int SlotCount()
		{
			return SlotCountFor(Player.localPlayer);
		}

		public static int SlotCountFor(Character c)
		{
			return SlotCountFor(PlayerOf(c));
		}

		private static int SlotCountFor(Player p)
		{
			try
			{
				return ((Object)(object)p != (Object)null && p.itemSlots != null) ? p.itemSlots.Length : 0;
			}
			catch
			{
				return 0;
			}
		}

		private static Player TargetPlayer(Character c)
		{
			return PlayerOf(c) ?? Player.localPlayer;
		}

		public static string DescribeSlot(Character c, int slot)
		{
			try
			{
				Player val = TargetPlayer(c);
				if ((Object)(object)val == (Object)null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length)
				{
					return "";
				}
				Item val2 = val.itemSlots[slot]?.prefab;
				if ((Object)(object)val2 == (Object)null)
				{
					return "-";
				}
				string name = val2.GetName();
				return string.IsNullOrWhiteSpace(name) ? ((Object)val2).name : name;
			}
			catch
			{
				return "";
			}
		}

		public static bool HasBackpack(Character c)
		{
			try
			{
				Player val = TargetPlayer(c);
				return (Object)(object)val != (Object)null && val.backpackSlot != null && !((ItemSlot)val.backpackSlot).IsEmpty() && ((ItemSlot)val.backpackSlot).data != null;
			}
			catch
			{
				return false;
			}
		}

		public static int BackpackSlotCount(Character c)
		{
			BackpackData val = BackpackDataFor(c, create: false);
			if (val == null || val.itemSlots == null)
			{
				return 0;
			}
			return val.itemSlots.Length;
		}

		public static string DescribeBackpackSlot(Character c, int slot)
		{
			try
			{
				BackpackData val = BackpackDataFor(c, create: false);
				if (val == null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length)
				{
					return "";
				}
				Item val2 = val.itemSlots[slot]?.prefab;
				if ((Object)(object)val2 == (Object)null)
				{
					return "-";
				}
				string name = val2.GetName();
				return string.IsNullOrWhiteSpace(name) ? ((Object)val2).name : name;
			}
			catch
			{
				return "";
			}
		}

		public static bool SpawnToBackpackSlotFor(Character target, int itemIndex, int slot)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			try
			{
				if (itemIndex < 0 || itemIndex >= Items.Count)
				{
					return false;
				}
				if (!CanBackpackItem(itemIndex))
				{
					return false;
				}
				BackpackData val = BackpackDataFor(target, create: true);
				if (val == null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length)
				{
					return false;
				}
				val.itemSlots[slot].prefab = Items[itemIndex];
				val.itemSlots[slot].data = new ItemInstanceData(Guid.NewGuid());
				ItemInstanceDataHandler.AddInstanceData(val.itemSlots[slot].data);
				SyncTargetInventory(target);
				ActionTracker.Track("inventory_spawn_backpack", null, new Dictionary<string, object>
				{
					["slot"] = slot,
					["item"] = SafeItemName(itemIndex),
					["target"] = SafeCharacterName(target)
				});
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] SpawnToBackpackSlotFor: " + ex.Message));
				}
				return false;
			}
		}

		public static bool ClearBackpackSlotFor(Character target, int slot)
		{
			try
			{
				BackpackData val = BackpackDataFor(target, create: false);
				if (val == null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length)
				{
					return false;
				}
				val.itemSlots[slot].prefab = null;
				val.itemSlots[slot].data = null;
				SyncTargetInventory(target);
				ActionTracker.Track("inventory_clear_backpack", null, new Dictionary<string, object>
				{
					["slot"] = slot,
					["target"] = SafeCharacterName(target)
				});
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] ClearBackpackSlotFor: " + ex.Message));
				}
				return false;
			}
		}

		public static void RechargeBackpackSlotFor(Character target, int slot, float value)
		{
			try
			{
				BackpackData val = BackpackDataFor(target, create: false);
				if (val != null && val.itemSlots != null && slot >= 0 && slot < val.itemSlots.Length)
				{
					RechargeItemSlotData(val.itemSlots[slot], value);
					SyncTargetInventory(target);
					ActionTracker.Track("inventory_recharge_backpack", value, new Dictionary<string, object>
					{
						["slot"] = slot,
						["target"] = SafeCharacterName(target)
					});
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] RechargeBackpackSlotFor: " + ex.Message));
				}
			}
		}

		private static BackpackData BackpackDataFor(Character c, bool create)
		{
			try
			{
				Player val = TargetPlayer(c);
				if ((Object)(object)val == (Object)null || val.backpackSlot == null || ((ItemSlot)val.backpackSlot).IsEmpty() || ((ItemSlot)val.backpackSlot).data == null)
				{
					return null;
				}
				BackpackData result = default(BackpackData);
				if (((ItemSlot)val.backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref result))
				{
					return result;
				}
				return create ? ((ItemSlot)val.backpackSlot).data.RegisterNewEntry<BackpackData>((DataEntryKey)7) : null;
			}
			catch
			{
				return null;
			}
		}

		private static void SyncTargetInventory(Character c)
		{
			Player val = TargetPlayer(c);
			if (!((Object)(object)val == (Object)null))
			{
				SyncInventory(val, (RpcTarget)(IsLocal(c) ? 1 : 0));
			}
		}

		public static CustomizationOption[] GetCosmeticOptions(CosmeticCategory category)
		{
			try
			{
				Customization val = CustomizationDb();
				if ((Object)(object)val == (Object)null)
				{
					return Array.Empty<CustomizationOption>();
				}
				return category switch
				{
					CosmeticCategory.Skin => val.skins ?? Array.Empty<CustomizationOption>(), 
					CosmeticCategory.Accessory => val.accessories ?? Array.Empty<CustomizationOption>(), 
					CosmeticCategory.Eyes => val.eyes ?? Array.Empty<CustomizationOption>(), 
					CosmeticCategory.Mouth => val.mouths ?? Array.Empty<CustomizationOption>(), 
					CosmeticCategory.Outfit => val.fits ?? Array.Empty<CustomizationOption>(), 
					CosmeticCategory.Hat => val.hats ?? Array.Empty<CustomizationOption>(), 
					CosmeticCategory.Sash => val.sashes ?? Array.Empty<CustomizationOption>(), 
					_ => Array.Empty<CustomizationOption>(), 
				};
			}
			catch
			{
				return Array.Empty<CustomizationOption>();
			}
		}

		public static int GetCurrentCosmeticIndex(CosmeticCategory category)
		{
			try
			{
				CharacterCustomization val = LocalCustomization();
				if ((Object)(object)val == (Object)null)
				{
					return -1;
				}
				CharacterCustomizationData customizationData = GetCustomizationData(val);
				return category switch
				{
					CosmeticCategory.Skin => customizationData.currentSkin, 
					CosmeticCategory.Accessory => customizationData.currentAccessory, 
					CosmeticCategory.Eyes => customizationData.currentEyes, 
					CosmeticCategory.Mouth => customizationData.currentMouth, 
					CosmeticCategory.Outfit => customizationData.currentOutfit, 
					CosmeticCategory.Hat => customizationData.currentHat, 
					CosmeticCategory.Sash => customizationData.currentSash, 
					_ => -1, 
				};
			}
			catch
			{
				return -1;
			}
		}

		public static int FindBlankCosmeticIndex(CosmeticCategory category)
		{
			CustomizationOption[] cosmeticOptions = GetCosmeticOptions(category);
			for (int i = 0; i < cosmeticOptions.Length; i++)
			{
				try
				{
					if ((Object)(object)cosmeticOptions[i] != (Object)null && cosmeticOptions[i].isBlank)
					{
						return i;
					}
				}
				catch
				{
				}
			}
			return -1;
		}

		public static bool IsCosmeticOptionGrantable(CosmeticCategory category, int index)
		{
			CustomizationOption[] cosmeticOptions = GetCosmeticOptions(category);
			if (index >= 0 && index < cosmeticOptions.Length)
			{
				return IsCosmeticOptionGrantable(category, cosmeticOptions[index]);
			}
			return false;
		}

		public static bool IsCosmeticOptionGrantable(CosmeticCategory category, CustomizationOption option)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)option == (Object)null)
			{
				return false;
			}
			try
			{
				if (option.isBlank)
				{
					return true;
				}
				if (option.type != ExpectedCosmeticType(category))
				{
					return false;
				}
				if (!HasKnownCosmeticRequirement(option))
				{
					return false;
				}
				if (!HasCosmeticUnlockRequirement(option))
				{
					return false;
				}
				return HasCosmeticVisual(category, option);
			}
			catch
			{
				return false;
			}
		}

		private static Type ExpectedCosmeticType(CosmeticCategory category)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			return (Type)(category switch
			{
				CosmeticCategory.Skin => 0, 
				CosmeticCategory.Accessory => 10, 
				CosmeticCategory.Eyes => 20, 
				CosmeticCategory.Mouth => 30, 
				CosmeticCategory.Outfit => 40, 
				CosmeticCategory.Hat => 50, 
				CosmeticCategory.Sash => 60, 
				_ => 0, 
			});
		}

		private static bool HasCosmeticVisual(CosmeticCategory category, CustomizationOption option)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)option == (Object)null)
			{
				return false;
			}
			if ((Object)(object)option.texture != (Object)null)
			{
				return true;
			}
			if ((Object)(object)option.fitMesh != (Object)null || (Object)(object)option.fitMaterial != (Object)null || (Object)(object)option.fitMaterialShoes != (Object)null)
			{
				return true;
			}
			if ((Object)(object)option.fitMaterialOverridePants != (Object)null || (Object)(object)option.fitMaterialOverrideHat != (Object)null)
			{
				return true;
			}
			if (category == CosmeticCategory.Skin)
			{
				Color color = option.color;
				if (!(color.a > 0.01f) && !(color.r > 0.01f) && !(color.g > 0.01f))
				{
					return color.b > 0.01f;
				}
				return true;
			}
			return false;
		}

		private static bool HasKnownCosmeticRequirement(CustomizationOption option)
		{
			string a = ((object)Unsafe.As<CUSTOMREQUIREMENT, CUSTOMREQUIREMENT>(ref option.customRequirement)/*cast due to .constrained prefix*/).ToString();
			if (!string.Equals(a, "None", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "Goat", StringComparison.OrdinalIgnoreCase))
			{
				return string.Equals(a, "Crown", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private static bool HasCosmeticUnlockRequirement(CustomizationOption option)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)option == (Object)null || option.isBlank)
			{
				return false;
			}
			if (option.requiresAscent)
			{
				return true;
			}
			if (option.requiresSteamStat)
			{
				return true;
			}
			if ((int)option.requiredAchievement != 0)
			{
				return true;
			}
			string a = ((object)Unsafe.As<CUSTOMREQUIREMENT, CUSTOMREQUIREMENT>(ref option.customRequirement)/*cast due to .constrained prefix*/).ToString();
			if (!string.Equals(a, "Goat", StringComparison.OrdinalIgnoreCase))
			{
				return string.Equals(a, "Crown", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		public static bool SetCosmetic(CosmeticCategory category, int index)
		{
			try
			{
				CharacterCustomization val = LocalCustomization();
				CustomizationOption[] cosmeticOptions = GetCosmeticOptions(category);
				if ((Object)(object)val == (Object)null || index < 0 || index >= cosmeticOptions.Length)
				{
					return false;
				}
				if (!IsCosmeticOptionGrantable(category, cosmeticOptions[index]))
				{
					return false;
				}
				CharacterCustomizationData customizationData = GetCustomizationData(val);
				switch (category)
				{
				case CosmeticCategory.Skin:
					customizationData.currentSkin = index;
					InvokeCustomizationSetter(val, CustomSetSkin, index);
					break;
				case CosmeticCategory.Accessory:
					customizationData.currentAccessory = index;
					InvokeCustomizationSetter(val, CustomSetAccessory, index);
					break;
				case CosmeticCategory.Eyes:
					customizationData.currentEyes = index;
					InvokeCustomizationSetter(val, CustomSetEyes, index);
					break;
				case CosmeticCategory.Mouth:
					customizationData.currentMouth = index;
					InvokeCustomizationSetter(val, CustomSetMouth, index);
					break;
				case CosmeticCategory.Outfit:
					customizationData.currentOutfit = index;
					InvokeCustomizationSetter(val, CustomSetOutfit, index);
					break;
				case CosmeticCategory.Hat:
					customizationData.currentHat = index;
					InvokeCustomizationSetter(val, CustomSetHat, index);
					break;
				case CosmeticCategory.Sash:
					customizationData.currentSash = index;
					InvokeCustomizationSetter(val, CustomSetSash, index);
					break;
				default:
					return false;
				}
				customizationData.CorrectValues();
				SetCustomizationData(val, customizationData);
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] SetCosmetic: " + ex.Message));
				}
				return false;
			}
		}

		public static bool UnlockCosmeticOption(CustomizationOption option)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)option == (Object)null)
			{
				return false;
			}
			LocalCosmeticUnlocks.Add(((Object)option).GetInstanceID());
			bool flag = false;
			try
			{
				if (option.requiresAscent)
				{
					SteamAch.SetMaxAscent(Mathf.Max(0, option.requiredAscent));
					flag = true;
				}
			}
			catch
			{
			}
			try
			{
				if (option.requiresSteamStat)
				{
					SteamAch.SetStatValue(option.requiredSteamStat, Mathf.Max(1, option.requiredSteamStatValue));
					flag = true;
				}
			}
			catch
			{
			}
			try
			{
				if ((int)option.requiredAchievement != 0)
				{
					SteamAch.Unlock(option.requiredAchievement);
					flag = true;
				}
			}
			catch
			{
			}
			try
			{
				string a = ((object)Unsafe.As<CUSTOMREQUIREMENT, CUSTOMREQUIREMENT>(ref option.customRequirement)/*cast due to .constrained prefix*/).ToString();
				if (string.Equals(a, "Goat", StringComparison.OrdinalIgnoreCase))
				{
					SteamAch.SetMaxAscent(8);
					flag = true;
				}
				else if (string.Equals(a, "Crown", StringComparison.OrdinalIgnoreCase))
				{
					SteamAch.UnlockAll();
					flag = true;
				}
			}
			catch
			{
			}
			try
			{
				option.testLocked = false;
			}
			catch
			{
			}
			ActionTracker.Track("cosmetic_unlock_one", null, new Dictionary<string, object>
			{
				["name"] = SafeCosmeticName(option),
				["changedRequirement"] = flag
			});
			return true;
		}

		public static bool LockCosmeticOption(CustomizationOption option)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)option == (Object)null)
			{
				return false;
			}
			bool flag = false;
			LocalCosmeticUnlocks.Remove(((Object)option).GetInstanceID());
			try
			{
				if ((int)option.requiredAchievement != 0)
				{
					SteamAch.Revoke(option.requiredAchievement);
					flag = true;
				}
			}
			catch
			{
			}
			try
			{
				if (option.requiresSteamStat)
				{
					SteamAch.SetStatValue(option.requiredSteamStat, 0);
					flag = true;
				}
			}
			catch
			{
			}
			try
			{
				if (option.requiresAscent)
				{
					SteamAch.SetMaxAscent(Mathf.Max(0, option.requiredAscent - 1));
					flag = true;
				}
			}
			catch
			{
			}
			try
			{
				if (string.Equals(((object)Unsafe.As<CUSTOMREQUIREMENT, CUSTOMREQUIREMENT>(ref option.customRequirement)/*cast due to .constrained prefix*/).ToString(), "Goat", StringComparison.OrdinalIgnoreCase))
				{
					SteamAch.SetMaxAscent(0);
					flag = true;
				}
			}
			catch
			{
			}
			try
			{
				option.testLocked = true;
			}
			catch
			{
			}
			ActionTracker.Track("cosmetic_lock_one", null, new Dictionary<string, object>
			{
				["name"] = SafeCosmeticName(option),
				["changedRequirement"] = flag
			});
			return true;
		}

		public static void UnlockAllCosmeticOptions()
		{
			int num = 0;
			try
			{
				foreach (CosmeticCategory value in Enum.GetValues(typeof(CosmeticCategory)))
				{
					CustomizationOption[] cosmeticOptions = GetCosmeticOptions(value);
					foreach (CustomizationOption val in cosmeticOptions)
					{
						if (IsCosmeticOptionGrantable(value, val))
						{
							LocalCosmeticUnlocks.Add(((Object)val).GetInstanceID());
							num++;
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] UnlockAllCosmeticOptions local: " + ex.Message));
				}
			}
			try
			{
				SteamAch.UnlockAllCosmetics();
			}
			catch
			{
			}
			ActionTracker.Track("cosmetic_unlock_all_local", num);
		}

		public static bool IsCosmeticLocallyUnlocked(CustomizationOption option)
		{
			try
			{
				return (Object)(object)option != (Object)null && LocalCosmeticUnlocks.Contains(((Object)option).GetInstanceID());
			}
			catch
			{
				return false;
			}
		}

		private static string SafeCosmeticName(CustomizationOption option)
		{
			try
			{
				return ((Object)(object)option != (Object)null && !string.IsNullOrWhiteSpace(((Object)option).name)) ? ((Object)option).name : "Unknown";
			}
			catch
			{
				return "Unknown";
			}
		}

		private static CharacterCustomizationData GetCustomizationData(CharacterCustomization cc)
		{
			if (CustomGetData == null)
			{
				return null;
			}
			object obj = (CustomGetData.IsStatic ? null : cc);
			object? obj2 = CustomGetData.Invoke(obj, new object[1] { PhotonNetwork.LocalPlayer });
			CharacterCustomizationData val = (CharacterCustomizationData)((obj2 is CharacterCustomizationData) ? obj2 : null);
			if (val == null)
			{
				return null;
			}
			return val;
		}

		private static void SetCustomizationData(CharacterCustomization cc, CharacterCustomizationData data)
		{
			if (!(CustomSetData == null))
			{
				object obj = (CustomSetData.IsStatic ? null : cc);
				CustomSetData.Invoke(obj, new object[2]
				{
					data,
					PhotonNetwork.LocalPlayer
				});
			}
		}

		private static void InvokeCustomizationSetter(CharacterCustomization cc, MethodInfo method, int index)
		{
			if (!(method == null))
			{
				object obj = (method.IsStatic ? null : cc);
				method.Invoke(obj, new object[1] { index });
			}
		}

		public static void RefreshPlayers()
		{
			try
			{
				PlayerChars.Clear();
				PlayerNames.Clear();
				List<Character> allCharacters = Character.AllCharacters;
				if (allCharacters == null)
				{
					return;
				}
				foreach (Character item in allCharacters)
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					bool flag = false;
					try
					{
						flag = (Object)(object)((MonoBehaviourPun)item).photonView != (Object)null;
					}
					catch
					{
					}
					if (!flag)
					{
						continue;
					}
					bool flag2 = false;
					for (int i = 0; i < PlayerChars.Count; i++)
					{
						if ((Object)(object)PlayerChars[i] == (Object)(object)item)
						{
							flag2 = true;
							break;
						}
					}
					if (flag2)
					{
						continue;
					}
					PlayerChars.Add(item);
					string text = null;
					try
					{
						text = item.characterName;
					}
					catch
					{
					}
					if (string.IsNullOrWhiteSpace(text))
					{
						try
						{
							PhotonView photonView = ((MonoBehaviourPun)item).photonView;
							object obj3;
							if (photonView == null)
							{
								obj3 = null;
							}
							else
							{
								Player owner = photonView.Owner;
								obj3 = ((owner != null) ? owner.NickName : null);
							}
							text = (string)obj3;
						}
						catch
						{
						}
					}
					PlayerNames.Add(string.IsNullOrWhiteSpace(text) ? "Unknown" : text);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] RefreshPlayers: " + ex.Message));
				}
			}
		}

		public static void ReviveSelf()
		{
			if ((Object)(object)Character.localCharacter != (Object)null)
			{
				RevivePlayer(Character.localCharacter);
			}
		}

		public static void KillSelf()
		{
			if ((Object)(object)Character.localCharacter != (Object)null)
			{
				KillPlayer(Character.localCharacter);
			}
		}

		public static void WarpToSpawn()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Character localCharacter = Character.localCharacter;
				Transform val = (((Object)(object)localCharacter != (Object)null) ? localCharacter.data.spawnPoint : null);
				if (!((Object)(object)val == (Object)null))
				{
					((MonoBehaviourPun)localCharacter).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2]
					{
						val.position + new Vector3(0f, 2f, 0f),
						true
					});
					ActionTracker.Track("warp_spawn");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] WarpToSpawn: " + ex.Message));
				}
			}
		}

		public static void WarpPlayerToSpawn(Character c)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)c == (Object)null))
				{
					Transform val = (((Object)(object)c.data != (Object)null) ? c.data.spawnPoint : null);
					if (!((Object)(object)val == (Object)null))
					{
						((MonoBehaviourPun)c).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2]
						{
							val.position + new Vector3(0f, 2f, 0f),
							true
						});
						ActionTracker.Track("warp_player_spawn", null, new Dictionary<string, object> { ["target"] = SafeCharacterName(c) });
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] WarpPlayerToSpawn: " + ex.Message));
				}
			}
		}

		public static void TeleportToCoords(float x, float y, float z)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Character localCharacter = Character.localCharacter;
				if (!((Object)(object)localCharacter == (Object)null) && !localCharacter.data.dead)
				{
					((MonoBehaviourPun)localCharacter).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2]
					{
						(object)new Vector3(x, y, z),
						true
					});
					ActionTracker.Track("warp_coords", null, new Dictionary<string, object>
					{
						["x"] = x,
						["y"] = y,
						["z"] = z
					});
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] TeleportToCoords: " + ex.Message));
				}
			}
		}

		public static void KillPlayer(Character c)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)c != (Object)null)
				{
					((MonoBehaviourPun)c).photonView.RPC("RPCA_Die", (RpcTarget)0, new object[1] { ((Component)c).transform.position });
				}
				if ((Object)(object)c != (Object)null)
				{
					ActionTracker.Track("player_kill", null, new Dictionary<string, object> { ["target"] = SafeCharacterName(c) });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] KillPlayer: " + ex.Message));
				}
			}
		}

		public static void RevivePlayer(Character c)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)c == (Object)null))
				{
					Vector3 val = (((Object)(object)c.Ghost != (Object)null) ? ((Component)c.Ghost).transform.position : c.Head) + new Vector3(0f, 4f, 0f);
					((MonoBehaviourPun)c).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val, false, -1 });
					ActionTracker.Track("player_revive", null, new Dictionary<string, object> { ["target"] = SafeCharacterName(c) });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] RevivePlayer: " + ex.Message));
				}
			}
		}

		public static void KickPlayer(Character c)
		{
			try
			{
				if (IsHost() && !((Object)(object)c == (Object)null) && !IsLocal(c))
				{
					Player val = PlayerOf(c);
					PhotonView val2 = (((Object)(object)val != (Object)null) ? ((MonoBehaviourPun)val).photonView : null);
					Player val3 = (((Object)(object)val2 != (Object)null) ? val2.Owner : null);
					if (!((Object)(object)val2 == (Object)null) && val3 != null)
					{
						val2.RPC("RPC_GetKicked", val3, new object[0]);
						ActionTracker.Track("admin_kick", null, new Dictionary<string, object> { ["target"] = SafeCharacterName(c) });
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] KickPlayer: " + ex.Message));
				}
			}
		}

		public static void BanPlayer(Character c)
		{
			try
			{
				if (IsHost() && !((Object)(object)c == (Object)null) && !IsLocal(c))
				{
					string text = PlayerBanId(c);
					if (!string.IsNullOrWhiteSpace(text))
					{
						SessionBans.Add(text);
						SessionBanNames[text] = SafeCharacterName(c);
						AddAdminLog(SafeCharacterName(c) + ": session ban");
					}
					KickPlayer(c);
					ActionTracker.Track("admin_ban_session", null, new Dictionary<string, object> { ["target"] = SafeCharacterName(c) });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] BanPlayer: " + ex.Message));
				}
			}
		}

		public static bool IsSessionBanned(Character c)
		{
			string text = PlayerBanId(c);
			if (!string.IsNullOrWhiteSpace(text))
			{
				return SessionBans.Contains(text);
			}
			return false;
		}

		public static void ToggleSessionBan(Character c)
		{
			try
			{
				if ((Object)(object)c == (Object)null || IsLocal(c))
				{
					return;
				}
				string text = PlayerBanId(c);
				if (string.IsNullOrWhiteSpace(text))
				{
					return;
				}
				if (SessionBans.Contains(text))
				{
					UnbanSession(text);
					return;
				}
				SessionBans.Add(text);
				SessionBanNames[text] = SafeCharacterName(c);
				AddAdminLog(SafeCharacterName(c) + ": session ban");
				if (IsHost())
				{
					KickPlayer(c);
				}
				ActionTracker.Track("admin_toggle_ban", 1.0, new Dictionary<string, object> { ["target"] = SafeCharacterName(c) });
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] ToggleSessionBan: " + ex.Message));
				}
			}
		}

		public static void UnbanSession(string key)
		{
			if (!string.IsNullOrWhiteSpace(key))
			{
				string value;
				string text = (SessionBanNames.TryGetValue(key, out value) ? value : key);
				SessionBans.Remove(key);
				SessionBanNames.Remove(key);
				AddAdminLog(text + ": session unban");
				ActionTracker.Track("admin_unban_session", null, new Dictionary<string, object> { ["target"] = text });
			}
		}

		public static List<AdminListEntry> SessionBanEntries()
		{
			List<AdminListEntry> list = new List<AdminListEntry>();
			foreach (string sessionBan in SessionBans)
			{
				string value;
				string label = ((SessionBanNames.TryGetValue(sessionBan, out value) && !string.IsNullOrWhiteSpace(value)) ? value : sessionBan);
				list.Add(new AdminListEntry(sessionBan, label));
			}
			return list;
		}

		public static void ToggleMute(Character c)
		{
			try
			{
				Player val = OwnerOf(c);
				if (val != null && val != PhotonNetwork.LocalPlayer)
				{
					SetMuted(val, !IsMuted(c));
					ActionTracker.Track("admin_toggle_mute", null, new Dictionary<string, object>
					{
						["target"] = SafeCharacterName(c),
						["muted"] = IsMuted(c)
					});
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] ToggleMute: " + ex.Message));
				}
			}
		}

		public static bool IsMuted(Character c)
		{
			try
			{
				Player val = OwnerOf(c);
				if (val == null)
				{
					return false;
				}
				if (((object)val).GetType().GetProperty("CustomProperties")?.GetValue(val, null) is IDictionary dictionary && dictionary.Contains("mu"))
				{
					object obj = dictionary["mu"];
					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;
				}
				return false;
			}
			catch
			{
				return false;
			}
		}

		private static void SetMuted(Player player, bool muted)
		{
			if (player == null)
			{
				return;
			}
			Type type = Type.GetType("ExitGames.Client.Photon.Hashtable, Photon3Unity3D");
			if (!(type == null))
			{
				object obj = Activator.CreateInstance(type);
				if (obj is IDictionary dictionary)
				{
					dictionary["mu"] = muted;
				}
				((object)player).GetType().GetMethod("SetCustomProperties", new Type[1] { type })?.Invoke(player, new object[1] { obj });
			}
		}

		public static bool IsFrozen(Character c)
		{
			string text = FreezeKey(c);
			if (!string.IsNullOrWhiteSpace(text))
			{
				return FrozenPlayers.ContainsKey(text);
			}
			return false;
		}

		public static void ToggleFreeze(Character c)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)c == (Object)null)
				{
					return;
				}
				string text = FreezeKey(c);
				if (!string.IsNullOrWhiteSpace(text))
				{
					bool flag;
					if (FrozenPlayers.ContainsKey(text))
					{
						FrozenPlayers.Remove(text);
						flag = false;
					}
					else
					{
						FrozenPlayers[text] = SafePosition(c);
						flag = true;
					}
					ActionTracker.Track("admin_toggle_freeze", flag ? 1 : 0, new Dictionary<string, object> { ["target"] = SafeCharacterName(c) });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] ToggleFreeze: " + ex.Message));
				}
			}
		}

		public static void ApplyFrozenPlayers(float deltaTime)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (FrozenPlayers.Count == 0)
				{
					return;
				}
				_freezeRpcTimer += Mathf.Max(0f, deltaTime);
				bool flag = _freezeRpcTimer >= 0.2f;
				if (flag)
				{
					_freezeRpcTimer = 0f;
				}
				KeyValuePair<string, Vector3>[] array = FrozenPlayers.ToArray();
				for (int i = 0; i < array.Length; i++)
				{
					KeyValuePair<string, Vector3> keyValuePair = array[i];
					Character val = FindFrozenCharacter(keyValuePair.Key);
					if (!((Object)(object)val == (Object)null))
					{
						FreezeCharacter(val, keyValuePair.Value, flag);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] ApplyFrozenPlayers: " + ex.Message));
				}
			}
		}

		public static bool IsInventoryLocked(Character c)
		{
			string text = AdminCharacterKey(c);
			if (!string.IsNullOrWhiteSpace(text))
			{
				return InventoryLocks.Contains(text);
			}
			return false;
		}

		public static void ToggleInventoryLock(Character c)
		{
			try
			{
				if ((Object)(object)c == (Object)null)
				{
					return;
				}
				string text = AdminCharacterKey(c);
				if (!string.IsNullOrWhiteSpace(text))
				{
					string text2 = SafeCharacterName(c);
					bool flag;
					if (InventoryLocks.Contains(text))
					{
						InventoryLocks.Remove(text);
						InventoryLockNames.Remove(text);
						flag = false;
						AddAdminLog(text2 + ": inventory unlock");
					}
					else
					{
						InventoryLocks.Add(text);
						InventoryLockNames[text] = text2;
						flag = true;
						AddAdminLog(text2 + ": inventory lock");
						DropAllInventory(c, track: false);
					}
					ActionTracker.Track("admin_toggle_inventory_lock", flag ? 1 : 0, new Dictionary<string, object> { ["target"] = text2 });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] ToggleInventoryLock: " + ex.Message));
				}
			}
		}

		public static void UnlockInventoryLock(string key)
		{
			if (!string.IsNullOrWhiteSpace(key))
			{
				string value;
				string text = (InventoryLockNames.TryGetValue(key, out value) ? value : key);
				InventoryLocks.Remove(key);
				InventoryLockNames.Remove(key);
				AddAdminLog(text + ": inventory unlock");
				ActionTracker.Track("admin_inventory_unlock", null, new Dictionary<string, object> { ["target"] = text });
			}
		}

		public static List<AdminListEntry> InventoryLockEntries()
		{
			List<AdminListEntry> list = new List<AdminListEntry>();
			foreach (string inventoryLock in InventoryLocks)
			{
				string value;
				string label = ((InventoryLockNames.TryGetValue(inventoryLock, out value) && !string.IsNullOrWhiteSpace(value)) ? value : inventoryLock);
				list.Add(new AdminListEntry(inventoryLock, label));
			}
			return list;
		}

		public static void ApplyInventoryLocks(float deltaTime)
		{
			try
			{
				if (InventoryLocks.Count == 0)
				{
					return;
				}
				_inventoryLockTimer += Mathf.Max(0f, deltaTime);
				if (_inventoryLockTimer < 0.45f)
				{
					return;
				}
				_inventoryLockTimer = 0f;
				string[] array = InventoryLocks.ToArray();
				for (int i = 0; i < array.Length; i++)
				{
					Character val = FindFrozenCharacter(array[i]);
					if (!((Object)(object)val == (Object)null))
					{
						DropAllInventory(val, track: false);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] ApplyInventoryLocks: " + ex.Message));
				}
			}
		}

		private static string FreezeKey(Character c)
		{
			return AdminCharacterKey(c);
		}

		private static string AdminCharacterKey(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return "";
			}
			if (IsLocal(c))
			{
				return "local";
			}
			return PlayerBanId(c);
		}

		private static Character FindFrozenCharacter(string key)
		{
			if (string.Equals(key, "local", StringComparison.Ordinal))
			{
				return Character.localCharacter;
			}
			List<Character> allCharacters = Character.AllCharacters;
			if (allCharacters == null)
			{
				return null;
			}
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if ((Object)(object)val != (Object)null && string.Equals(PlayerBanId(val), key, StringComparison.Ordinal))
				{
					return val;
				}
			}
			return null;
		}

		private static Vector3 SafePosition(Character c)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return c.Center;
			}
			catch
			{
				try
				{
					return ((Component)c).transform.position;
				}
				catch
				{
					return Vector3.zero;
				}
			}
		}

		private static void FreezeCharacter(Character c, Vector3 position, bool sendRpc)
		{
			//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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)c == (Object)null)
			{
				return;
			}
			HaltCharacter(c);
			try
			{
				if (Vector3.Distance(c.Center, position) > 0.08f && (Object)(object)c.refs?.ragdoll != (Object)null)
				{
					c.refs.ragdoll.MoveAllRigsInDirection(position - c.Center);
				}
			}
			catch
			{
			}
			if (!(!IsLocal(c) && IsHost() && sendRpc))
			{
				return;
			}
			try
			{
				((MonoBehaviourPun)c).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { position, false });
			}
			catch
			{
			}
		}

		private static void HaltCharacter(Character c)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CharacterRefs refs = c.refs;
				if (refs != null)
				{
					CharacterRagdoll ragdoll = refs.ragdoll;
					if (ragdoll != null)
					{
						ragdoll.HaltBodyVelocity();
					}
				}
			}
			catch
			{
			}
			try
			{
				List<Bodypart> list = c.refs?.ragdoll?.partList;
				if (list == null)
				{
					return;
				}
				for (int i = 0; i < list.Count; i++)
				{
					Rigidbody val = (((Object)(object)list[i] != (Object)null) ? list[i].Rig : null);
					if (!((Object)(object)val == (Object)null) && !val.isKinematic)
					{
						val.linearVelocity = Vector3.zero;
						val.angularVelocity = Vector3.zero;
					}
				}
			}
			catch
			{
			}
		}

		public static void EnforceSessionBans()
		{
			try
			{
				if (!IsHost() || SessionBans.Count == 0)
				{
					return;
				}
				RefreshPlayers();
				for (int i = 0; i < PlayerChars.Count; i++)
				{
					Character val = PlayerChars[i];
					if (!((Object)(object)val == (Object)null) && !IsLocal(val))
					{
						string text = PlayerBanId(val);
						if (!string.IsNullOrWhiteSpace(text) && SessionBans.Contains(text))
						{
							KickPlayer(val);
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] EnforceSessionBans: " + ex.Message));
				}
			}
		}

		public static void EnforceAdminProtection()
		{
			try
			{
				if (ModConfig.AdminProtectionEnabled && IsHost())
				{
					if (ModConfig.AdminAutoKickSessionBans)
					{
						EnforceSessionBans();
					}
					if (ModConfig.AdminDetectExtremeMovement)
					{
						CheckExtremeMovement();
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] EnforceAdminProtection: " + ex.Message));
				}
			}
		}

		private static void CheckExtremeMovement()
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			RefreshPlayers();
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			float num = Mathf.Max(5f, ModConfig.AdminMaxSpeed);
			int num2 = Mathf.Clamp(ModConfig.AdminSpeedStrikes, 1, 10);
			for (int i = 0; i < PlayerChars.Count; i++)
			{
				Character val = PlayerChars[i];
				if ((Object)(object)val == (Object)null || IsLocal(val) || IsFrozen(val))
				{
					continue;
				}
				try
				{
					if ((Object)(object)val.data != (Object)null && val.data.dead)
					{
						continue;
					}
				}
				catch
				{
				}
				string text = PlayerBanId(val);
				if (string.IsNullOrWhiteSpace(text))
				{
					continue;
				}
				Vector3 val2 = SafePosition(val);
				if (AdminMotion.TryGetValue(text, out var value))
				{
					float num3 = Mathf.Max(0.001f, realtimeSinceStartup - value.Time);
					float num4 = Vector3.Distance(val2, value.Position) / num3;
					int value3;
					if (num4 > num)
					{
						int value2;
						int num5 = ((!AdminStrikes.TryGetValue(text, out value2)) ? 1 : (value2 + 1));
						AdminStrikes[text] = num5;
						AddAdminLog($"{SafeCharacterName(val)}: speed {num4:0.0} m/s ({num5}/{num2})");
						if (!ModConfig.AdminWarnOnly && num5 >= num2)
						{
							AddAdminLog(SafeCharacterName(val) + ": auto-kick by admin protection");
							KickPlayer(val);
							AdminStrikes[text] = 0;
						}
					}
					else if (AdminStrikes.TryGetValue(text, out value3) && value3 > 0)
					{
						AdminStrikes[text] = value3 - 1;
					}
				}
				AdminMotion[text] = new AdminMotionSample
				{
					Position = val2,
					Time = realtimeSinceStartup
				};
			}
		}

		public static void AddAdminLog(string message)
		{
			if (!string.IsNullOrWhiteSpace(message))
			{
				string item = DateTime.Now.ToString("HH:mm:ss") + "  " + message;
				AdminProtectionLog.Insert(0, item);
				while (AdminProtectionLog.Count > 18)
				{
					AdminProtectionLog.RemoveAt(AdminProtectionLog.Count - 1);
				}
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("[AdminProtection] " + message));
				}
			}
		}

		private static Player OwnerOf(Character c)
		{
			try
			{
				object result;
				if (!((Object)(object)c != (Object)null))
				{
					result = null;
				}
				else
				{
					PhotonView photonView = ((MonoBehaviourPun)c).photonView;
					result = ((photonView != null) ? photonView.Owner : null);
				}
				return (Player)result;
			}
			catch
			{
				return null;
			}
		}

		private static string PlayerBanId(Character c)
		{
			Player val = OwnerOf(c);
			if (val == null)
			{
				return "";
			}
			if (!string.IsNullOrWhiteSpace(val.UserId))
			{
				return "uid:" + val.UserId;
			}
			if (!string.IsNullOrWhiteSpace(val.NickName))
			{
				return "nick:" + val.NickName;
			}
			return "actor:" + val.ActorNumber;
		}

		public static void WarpToPlayer(Character c)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)c == (Object)null) && !((Object)(object)Character.localCharacter == (Object)null))
				{
					Vector3 val = c.Head + new Vector3(0f, 4f, 0f);
					((MonoBehaviourPun)Character.localCharacter).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, true });
					ActionTracker.Track("warp_to_player", null, new Dictionary<string, object> { ["target"] = SafeCharacterName(c) });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] WarpToPlayer: " + ex.Message));
				}
			}
		}

		public static void BringPlayer(Character c)
		{
			//IL_0020: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)c == (Object)null) && !((Object)(object)Character.localCharacter == (Object)null))
				{
					Vector3 val = Character.localCharacter.Head + new Vector3(0f, 4f, 0f);
					((MonoBehaviourPun)c).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, true });
					ActionTracker.Track("bring_player", null, new Dictionary<string, object> { ["target"] = SafeCharacterName(c) });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] BringPlayer: " + ex.Message));
				}
			}
		}

		public static void ReviveAll()
		{
			RefreshPlayers();
			foreach (Character playerChar in PlayerChars)
			{
				RevivePlayer(playerChar);
			}
			ActionTracker.Track("revive_all", PlayerChars.Count);
		}

		public static void WarpAllToMe()
		{
			RefreshPlayers();
			foreach (Character playerChar in PlayerChars)
			{
				if ((Object)(object)playerChar != (Object)null && !playerChar.IsLocal)
				{
					BringPlayer(playerChar);
				}
			}
			ActionTracker.Track("bring_all", PlayerChars.Count);
		}

		public static void KillAll(bool excludeSelf)
		{
			RefreshPlayers();
			int num = 0;
			foreach (Character playerChar in PlayerChars)
			{
				if ((Object)(object)playerChar == (Object)null)
				{
					continue;
				}
				if (excludeSelf)
				{
					try
					{
						if (playerChar.IsLocal)
						{
							continue;
						}
					}
					catch
					{
					}
				}
				KillPlayer(playerChar);
				num++;
			}
			ActionTracker.Track("kill_all", num, new Dictionary<string, object> { ["excludeSelf"] = excludeSelf });
		}

		public static void RechargeSlot(int slot, float value)
		{
			try
			{
				Player localPlayer = Player.localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && localPlayer.itemSlots != null && slot >= 0 && slot < localPlayer.itemSlots.Length)
				{
					RechargeItemSlotData(localPlayer.itemSlots[slot], value);
					SyncInventory(localPlayer);
					ActionTracker.Track("inventory_recharge", value, new Dictionary<string, object> { ["slot"] = slot });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] RechargeSlot: " + ex.Message));
				}
			}
		}

		public static void RechargeSlotFor(Character target, int slot, float value)
		{
			try
			{
				if (IsLocal(target))
				{
					RechargeSlot(slot, value);
					return;
				}
				Player val = PlayerOf(target);
				if (!((Object)(object)val == (Object)null) && val.itemSlots != null && slot >= 0 && slot < val.itemSlots.Length)
				{
					RechargeItemSlotData(val.itemSlots[slot], value);
					SyncInventory(val, (RpcTarget)0);
					ActionTracker.Track("inventory_recharge_remote", value, new Dictionary<string, object>
					{
						["slot"] = slot,
						["target"] = SafeCharacterName(target)
					});
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] RechargeSlotFor: " + ex.Message));
				}
			}
		}

		private static void RechargeItemSlotData(ItemSlot slot, float value)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected I4, but got Unknown
			Dictionary<DataEntryKey, DataEntryValue> dictionary = slot?.data?.data;
			if (dictionary == null)
			{
				return;
			}
			foreach (KeyValuePair<DataEntryKey, DataEntryValue> item in dictionary)
			{
				int num = (int)item.Key;
				if (num == 12)
				{
					DataEntryValue value2 = item.Value;
					IntItemData val = (IntItemData)(object)((value2 is IntItemData) ? value2 : null);
					if (val != null)
					{
						val.Value = (int)value;
						continue;
					}
				}
				if (num == 10)
				{
					DataEntryValue value3 = item.Value;
					FloatItemData val2 = (FloatItemData)(object)((value3 is FloatItemData) ? value3 : null);
					if (val2 != null)
					{
						val2.Value = value;
						continue;
					}
				}
				if (num == 11)
				{
					DataEntryValue value4 = item.Value;
					FloatItemData val3 = (FloatItemData)(object)((value4 is FloatItemData) ? value4 : null);
					if (val3 != null)
					{
						val3.Value = value;
						continue;
					}
				}
				if (num == 2)
				{
					DataEntryValue value5 = item.Value;
					OptionableIntItemData val4 = (OptionableIntItemData)(object)((value5 is OptionableIntItemData) ? value5 : null);
					if (val4 != null)
					{
						val4.Value = (int)value;
					}
				}
			}
		}

		public static void RefreshLuggage()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				LuggageLabels.Clear();
				LuggageObjects.Clear();
				Character localCharacter = Character.localCharacter;
				if ((Object)(object)localCharacter == (Object)null)
				{
					return;
				}
				List<Luggage> aLL_LUGGAGE = Luggage.ALL_LUGGAGE;
				if (aLL_LUGGAGE == null || aLL_LUGGAGE.Count == 0)
				{
					return;
				}
				Vector3 head = localCharacter.Head;
				List<KeyValuePair<Luggage, float>> list = new List<KeyValuePair<Luggage, float>>();
				foreach (Luggage item in aLL_LUGGAGE)
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					try
					{
						float num = Vector3.Distance(head, item.Center());
						if (num <= 300f)
						{
							list.Add(new KeyValuePair<Luggage, float>(item, num));
						}
					}
					catch
					{
					}
				}
				list.Sort((KeyValuePair<Luggage, float> a, KeyValuePair<Luggage, float> b) => a.Value.CompareTo(b.Value));
				foreach (KeyValuePair<Luggage, float> item2 in list)
				{
					LuggageObjects.Add(item2.Key);
					LuggageLabels.Add(string.Format("{0} [{1:F0}m]", item2.Key.displayName ?? "Container", item2.Value));
				}
				ActionTracker.Track("luggage_refresh", LuggageObjects.Count);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] RefreshLuggage: " + ex.Message));
				}
			}
		}

		public static void OpenLuggage(int index)
		{
			try
			{
				if (index < 0 || index >= LuggageObjects.Count)
				{
					return;
				}
				Luggage val = LuggageObjects[index];
				if (!((Object)(object)val == (Object)null))
				{
					PhotonView component = ((Component)val).GetComponent<PhotonView>();
					if ((Object)(object)component != (Object)null)
					{
						component.RPC("OpenLuggageRPC", (RpcTarget)0, new object[1] { true });
					}
					ActionTracker.Track("luggage_open", null, new Dictionary<string, object> { ["label"] = SafeLuggageName(val) });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GameApi] OpenLuggage: " + ex.Message));
				}
			}
		}

		public static void OpenAllNearbyLuggage()
		{
			for (int i = 0; i < LuggageObjects.Count; i++)
			{
				OpenLuggage(i);
			}
			ActionTracker.Track("luggage_open_all", LuggageObjects.Count);
		}

		public static void WarpToLuggage(int index)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or