Decompiled source of ShrinkCart v0.2.33

BepInEx/plugins/ShrinkCart/ShrinkCart.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using ScalerCore;
using ScalerCore.Handlers;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ShrinkCart;

internal static class Authority
{
	private const float CheckIntervalSeconds = 0.25f;

	private static bool _cachedIsHostOrSingleplayer = true;

	private static float _nextCheckTime;

	internal static bool IsHostOrSingleplayer()
	{
		float unscaledTime = Time.unscaledTime;
		if (unscaledTime < _nextCheckTime)
		{
			return _cachedIsHostOrSingleplayer;
		}
		_nextCheckTime = unscaledTime + 0.25f;
		try
		{
			_cachedIsHostOrSingleplayer = SemiFunc.IsMasterClientOrSingleplayer();
		}
		catch
		{
			_cachedIsHostOrSingleplayer = true;
		}
		return _cachedIsHostOrSingleplayer;
	}

	internal static void Reset()
	{
		_nextCheckTime = 0f;
		_cachedIsHostOrSingleplayer = true;
	}
}
internal static class CartObjectGuard
{
	private static readonly HashSet<int> CartLikeObjectIds = new HashSet<int>();

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

	private static readonly FieldInfo ItemAttributesItemTypeField = typeof(ItemAttributes).GetField("itemType", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	internal static bool IsCartLike(PhysGrabObject item)
	{
		if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null)
		{
			return false;
		}
		int instanceID = ((Object)((Component)item).gameObject).GetInstanceID();
		if (CartLikeObjectIds.Contains(instanceID))
		{
			return true;
		}
		if (NonCartLikeObjectIds.Contains(instanceID))
		{
			return false;
		}
		if (HasCartLikeComponent(item) || HasCartLikeItemType(item))
		{
			CartLikeObjectIds.Add(instanceID);
			return true;
		}
		NonCartLikeObjectIds.Add(instanceID);
		return false;
	}

	internal static void Reset()
	{
		CartLikeObjectIds.Clear();
		NonCartLikeObjectIds.Clear();
	}

	internal static bool ShouldBlockCartInCart(PhysGrabInCart destination, PhysGrabObject item)
	{
		if ((Object)(object)destination == (Object)null || (Object)(object)destination.cart == (Object)null || (Object)(object)item == (Object)null)
		{
			return false;
		}
		if (!IsCartLike(item))
		{
			return false;
		}
		return true;
	}

	private static bool HasCartLikeComponent(PhysGrabObject item)
	{
		if (!((Object)(object)((Component)item).GetComponent<PhysGrabCart>() != (Object)null) && !((Object)(object)((Component)item).GetComponentInParent<PhysGrabCart>() != (Object)null) && !((Object)(object)((Component)item).GetComponentInChildren<PhysGrabCart>(true) != (Object)null) && !((Object)(object)((Component)item).GetComponent<ItemVehicle>() != (Object)null) && !((Object)(object)((Component)item).GetComponentInParent<ItemVehicle>() != (Object)null) && !((Object)(object)((Component)item).GetComponentInChildren<ItemVehicle>(true) != (Object)null) && !((Object)(object)((Component)item).GetComponent<ItemCartCannon>() != (Object)null) && !((Object)(object)((Component)item).GetComponent<ItemCartCannonMain>() != (Object)null) && !((Object)(object)((Component)item).GetComponent<ItemCartLaser>() != (Object)null) && !((Object)(object)((Component)item).GetComponentInParent<ItemCartCannon>() != (Object)null) && !((Object)(object)((Component)item).GetComponentInParent<ItemCartCannonMain>() != (Object)null) && !((Object)(object)((Component)item).GetComponentInParent<ItemCartLaser>() != (Object)null) && !((Object)(object)((Component)item).GetComponentInChildren<ItemCartCannon>(true) != (Object)null) && !((Object)(object)((Component)item).GetComponentInChildren<ItemCartCannonMain>(true) != (Object)null))
		{
			return (Object)(object)((Component)item).GetComponentInChildren<ItemCartLaser>(true) != (Object)null;
		}
		return true;
	}

	private static bool HasCartLikeItemType(PhysGrabObject item)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Invalid comparison between Unknown and I4
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Invalid comparison between Unknown and I4
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Invalid comparison between Unknown and I4
		ItemAttributes component = ((Component)item).GetComponent<ItemAttributes>();
		if ((Object)(object)component == (Object)null || ItemAttributesItemTypeField == null)
		{
			return false;
		}
		if (!(ItemAttributesItemTypeField.GetValue(component) is itemType val))
		{
			return false;
		}
		if ((int)val != 2 && (int)val != 14)
		{
			return (int)val == 12;
		}
		return true;
	}
}
internal static class CartRegistry
{
	private sealed class CartState
	{
		internal PhysGrabCart Cart;
	}

	private static readonly Dictionary<int, CartState> Carts = new Dictionary<int, CartState>();

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

	private static readonly FieldInfo PhysGrabCartItemsInCartField = typeof(PhysGrabCart).GetField("itemsInCart", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PhysGrabCartItemsInCartCountField = typeof(PhysGrabCart).GetField("itemsInCartCount", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PhysGrabCartHaulCurrentField = typeof(PhysGrabCart).GetField("haulCurrent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo ValuableObjectDollarValueCurrentField = typeof(ValuableObject).GetField("dollarValueCurrent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	internal static void RegisterCart(PhysGrabCart cart)
	{
		if (IsHostOrSingleplayer() && !((Object)(object)cart == (Object)null))
		{
			Carts[((Object)cart).GetInstanceID()] = new CartState
			{
				Cart = cart
			};
			DebugLog("Registered cart content guard target: " + ((Object)cart).name);
		}
	}

	internal static void RegisterExistingCarts()
	{
		if (IsHostOrSingleplayer())
		{
			PhysGrabCart[] array = Object.FindObjectsOfType<PhysGrabCart>();
			for (int i = 0; i < array.Length; i++)
			{
				RegisterCart(array[i]);
			}
		}
	}

	internal static void CleanCartContents(PhysGrabCart cart)
	{
		if (IsHostOrSingleplayer())
		{
			CartState orCreateState = GetOrCreateState(cart);
			List<PhysGrabObject> itemsInCart = GetItemsInCart(orCreateState?.Cart);
			if (orCreateState != null && !((Object)(object)orCreateState.Cart == (Object)null) && itemsInCart != null)
			{
				RemoveCartLikeItems(orCreateState, itemsInCart);
				ShrinkerCartController.MarkObjectsSeenInCart(orCreateState.Cart, itemsInCart);
			}
		}
	}

	internal static void Reset()
	{
		Carts.Clear();
		RemoveCartIds.Clear();
		CartObjectGuard.Reset();
	}

	internal static void HandleBlockedCartInCart(PhysGrabInCart destination, PhysGrabObject item)
	{
		if ((Object)(object)destination == (Object)null || (Object)(object)destination.cart == (Object)null || (Object)(object)item == (Object)null)
		{
			return;
		}
		CartState orCreateState = GetOrCreateState(destination.cart);
		if (orCreateState != null)
		{
			List<PhysGrabObject> itemsInCart = GetItemsInCart(orCreateState.Cart);
			if (itemsInCart != null)
			{
				RemoveCartLikeItems(orCreateState, itemsInCart);
			}
			DebugLog("Blocked cart-like object from cart Add: " + ((Object)item).name);
		}
	}

	private static CartState GetOrCreateState(PhysGrabCart cart)
	{
		if ((Object)(object)cart == (Object)null)
		{
			return null;
		}
		if (!Carts.TryGetValue(((Object)cart).GetInstanceID(), out var value) || value == null)
		{
			RegisterCart(cart);
			Carts.TryGetValue(((Object)cart).GetInstanceID(), out value);
		}
		return value;
	}

	private static void PruneInvalidCarts()
	{
		RemoveCartIds.Clear();
		foreach (KeyValuePair<int, CartState> cart in Carts)
		{
			if (cart.Value == null || (Object)(object)cart.Value.Cart == (Object)null)
			{
				RemoveCartIds.Add(cart.Key);
			}
		}
		for (int i = 0; i < RemoveCartIds.Count; i++)
		{
			Carts.Remove(RemoveCartIds[i]);
		}
		RemoveCartIds.Clear();
	}

	private static void RemoveCartLikeItems(CartState state, List<PhysGrabObject> items)
	{
		if (state == null || (Object)(object)state.Cart == (Object)null || items == null)
		{
			return;
		}
		bool flag = false;
		for (int num = items.Count - 1; num >= 0; num--)
		{
			PhysGrabObject val = items[num];
			if ((Object)(object)val == (Object)null)
			{
				items.RemoveAt(num);
				flag = true;
			}
			else if (CartObjectGuard.IsCartLike(val))
			{
				items.RemoveAt(num);
				flag = true;
			}
		}
		if (flag)
		{
			RecalculateCartCounts(state.Cart);
			DebugLog("Removed cart-like object from cart contents: " + ((Object)state.Cart).name);
		}
	}

	private static void RecalculateCartCounts(PhysGrabCart cart)
	{
		List<PhysGrabObject> itemsInCart = GetItemsInCart(cart);
		if ((Object)(object)cart == (Object)null || itemsInCart == null)
		{
			return;
		}
		int num = 0;
		int num2 = 0;
		for (int i = 0; i < itemsInCart.Count; i++)
		{
			PhysGrabObject val = itemsInCart[i];
			if (!((Object)(object)val == (Object)null))
			{
				num++;
				ValuableObject val2 = ((Component)val).GetComponent<ValuableObject>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = ((Component)val).GetComponentInParent<ValuableObject>();
				}
				if ((Object)(object)val2 != (Object)null)
				{
					num2 += GetValuableDollarValueCurrent(val2);
				}
			}
		}
		if (PhysGrabCartItemsInCartCountField != null)
		{
			PhysGrabCartItemsInCartCountField.SetValue(cart, num);
		}
		if (PhysGrabCartHaulCurrentField != null)
		{
			PhysGrabCartHaulCurrentField.SetValue(cart, num2);
		}
		if ((Object)(object)cart.valueScreen != (Object)null)
		{
			cart.valueScreen.UpdateValue(num2);
		}
	}

	private static List<PhysGrabObject> GetItemsInCart(PhysGrabCart cart)
	{
		if ((Object)(object)cart == (Object)null || PhysGrabCartItemsInCartField == null)
		{
			return null;
		}
		return PhysGrabCartItemsInCartField.GetValue(cart) as List<PhysGrabObject>;
	}

	private static int GetValuableDollarValueCurrent(ValuableObject valuable)
	{
		if ((Object)(object)valuable == (Object)null || ValuableObjectDollarValueCurrentField == null)
		{
			return 0;
		}
		object value = ValuableObjectDollarValueCurrentField.GetValue(valuable);
		if (value is float)
		{
			return (int)(float)value;
		}
		if (value is int)
		{
			return (int)value;
		}
		return 0;
	}

	private static void DebugLog(string message)
	{
		if (ModConfig.DebugLogging != null && ModConfig.DebugLogging.Value)
		{
			Plugin.Log.LogInfo((object)message);
		}
	}

	private static bool IsHostOrSingleplayer()
	{
		return Authority.IsHostOrSingleplayer();
	}
}
internal static class EnemyInCartKillController
{
	private static readonly HashSet<int> ExecutedEnemies = new HashSet<int>();

	private static readonly FieldInfo EnemyHealthField = typeof(Enemy).GetField("Health", BindingFlags.Instance | BindingFlags.NonPublic);

	private static readonly FieldInfo EnemyHealthCurrentField = typeof(EnemyHealth).GetField("healthCurrent", BindingFlags.Instance | BindingFlags.NonPublic);

	internal static void Reset()
	{
		ExecutedEnemies.Clear();
	}

	internal static bool TryKill(PhysGrabObject item)
	{
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		if (!ModConfig.EnemyInCartInstantKill.Value || (Object)(object)item == (Object)null)
		{
			return false;
		}
		Enemy val = FindEnemy(item);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		int instanceID = ((Object)val).GetInstanceID();
		if (ExecutedEnemies.Contains(instanceID))
		{
			return true;
		}
		EnemyHealth health = GetHealth(val);
		if ((Object)(object)health == (Object)null)
		{
			return false;
		}
		int currentHealth = GetCurrentHealth(health);
		if (currentHealth <= 0)
		{
			ExecutedEnemies.Add(instanceID);
			return true;
		}
		ExecutedEnemies.Add(instanceID);
		try
		{
			int num = Math.Max(currentHealth, health.health) + 1;
			health.Hurt(num, Vector3.up);
			DebugLog("Instant killed enemy entering cart: " + ((Object)val).name);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Failed to instant kill enemy entering cart: " + ex.Message));
			ExecutedEnemies.Remove(instanceID);
			return false;
		}
		return true;
	}

	private static Enemy FindEnemy(PhysGrabObject item)
	{
		EnemyRigidbody componentInParent = ((Component)item).GetComponentInParent<EnemyRigidbody>();
		if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.enemy != (Object)null)
		{
			return componentInParent.enemy;
		}
		return ((Component)item).GetComponentInParent<Enemy>();
	}

	private static EnemyHealth GetHealth(Enemy enemy)
	{
		if (EnemyHealthField == null)
		{
			return null;
		}
		object? value = EnemyHealthField.GetValue(enemy);
		return (EnemyHealth)((value is EnemyHealth) ? value : null);
	}

	private static int GetCurrentHealth(EnemyHealth health)
	{
		if (EnemyHealthCurrentField == null)
		{
			return health.health;
		}
		object value = EnemyHealthCurrentField.GetValue(health);
		if (value is int)
		{
			return (int)value;
		}
		return health.health;
	}

	private static void DebugLog(string message)
	{
		if (ModConfig.DebugLogging.Value)
		{
			Plugin.Log.LogInfo((object)message);
		}
	}
}
internal static class HostConfigSync
{
	private sealed class Snapshot
	{
		internal bool CartEnabled;

		internal bool ShrinkShopPlayerItems;

		internal bool PlayerScalingModuleEnabled;

		internal bool RestorePlayerOnDamage;

		internal bool EnemyInCartInstantKill;

		internal bool PreserveMass;

		internal bool SuppressValuableDamageRestore;

		internal float CartLeaveDebounceSeconds;

		internal float ReshrinkCooldownSeconds;

		internal float ScaleSpeed;

		internal float RestoreScaleSpeed;

		internal float PlayerCartScaleFactor;

		internal float PlayerCartStandTriggerSeconds;

		internal float PlayerCartExitGraceSeconds;

		internal float PlayerCartDetectionIntervalSeconds;

		internal readonly bool[] Enabled = new bool[14];

		internal readonly float[] Factors = new float[14];
	}

	private const string ConfigKey = "ShrinkCart.HostConfig.v2";

	private const string PayloadVersion = "SC0232";

	private const float SyncIntervalSeconds = 0.5f;

	private const int CategoryCount = 14;

	private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture;

	private static readonly StringBuilder Builder = new StringBuilder(640);

	private static Snapshot _remoteSnapshot;

	private static string _lastPublishedPayload;

	private static string _lastReadPayload;

	private static float _nextSyncTime;

	private static bool _lastWasMasterClient;

	private static int _lastPublishedConfigVersion = int.MinValue;

	internal static void Reset()
	{
		_remoteSnapshot = null;
		_lastPublishedPayload = null;
		_lastReadPayload = null;
		_nextSyncTime = 0f;
		_lastWasMasterClient = false;
		_lastPublishedConfigVersion = int.MinValue;
	}

	internal static void Tick()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			_remoteSnapshot = null;
			_lastReadPayload = null;
			_lastWasMasterClient = false;
			_lastPublishedPayload = null;
			_lastPublishedConfigVersion = int.MinValue;
		}
		else if (PhotonNetwork.IsMasterClient)
		{
			if (!_lastWasMasterClient)
			{
				_lastPublishedPayload = null;
				_lastPublishedConfigVersion = int.MinValue;
			}
			PublishIfChanged();
			_lastWasMasterClient = true;
		}
		else
		{
			_lastWasMasterClient = false;
			if (!(Time.time < _nextSyncTime))
			{
				_nextSyncTime = Time.time + 0.5f;
				ReadRemoteSnapshot();
			}
		}
	}

	private static void PublishIfChanged()
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Expected O, but got Unknown
		if (_lastPublishedPayload == null || _lastPublishedConfigVersion != ModConfig.ScalingConfigVersion)
		{
			string text = BuildLocalPayload();
			if (text == _lastPublishedPayload)
			{
				_lastPublishedConfigVersion = ModConfig.ScalingConfigVersion;
				return;
			}
			Hashtable val = new Hashtable();
			val[(object)"ShrinkCart.HostConfig.v2"] = text;
			PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			_lastPublishedPayload = text;
			_lastPublishedConfigVersion = ModConfig.ScalingConfigVersion;
		}
	}

	private static void ReadRemoteSnapshot()
	{
		if (!((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"ShrinkCart.HostConfig.v2", out object value))
		{
			_remoteSnapshot = null;
			_lastReadPayload = null;
			return;
		}
		string text = value as string;
		if (!string.IsNullOrEmpty(text) && !(text == _lastReadPayload) && TryParseSnapshot(text, out var snapshot))
		{
			_remoteSnapshot = snapshot;
			_lastReadPayload = text;
		}
	}

	private static string BuildLocalPayload()
	{
		Builder.Length = 0;
		Builder.Append("SC0232");
		Append(ModConfig.CartShrinkingEnabled.Value);
		Append(ModConfig.ShrinkShopPlayerItems.Value);
		Append(ModConfig.PlayerScalingModuleEnabled.Value);
		Append(ModConfig.RestorePlayerOnDamage.Value);
		Append(ModConfig.EnemyInCartInstantKill.Value);
		Append(ModConfig.ShouldPreserveMass());
		Append(ModConfig.SuppressValuableDamageRestore.Value);
		Append(ModConfig.SafeCartLeaveDebounceSeconds());
		Append(ModConfig.SafeReshrinkCooldownSeconds());
		Append(ModConfig.SafeScaleSpeed());
		Append(ModConfig.SafeRestoreScaleSpeed());
		Append(ModConfig.SafePlayerCartScaleFactor());
		Append(ModConfig.SafePlayerCartStandTriggerSeconds());
		Append(ModConfig.SafePlayerCartExitGraceSeconds());
		Append(ModConfig.SafePlayerCartDetectionIntervalSeconds());
		for (int i = 0; i < 14; i++)
		{
			GetLocalCategoryConfig((ShrinkCategory)i, out var enabled, out var factor);
			Append(enabled);
			Append(factor);
		}
		return Builder.ToString();
	}

	private static bool TryParseSnapshot(string payload, out Snapshot snapshot)
	{
		snapshot = null;
		string[] array = payload.Split(new char[1] { '|' });
		int num = 44;
		if (array.Length != num || array[0] != "SC0232")
		{
			return false;
		}
		Snapshot snapshot2 = new Snapshot();
		int num2 = 1;
		if (!TryParseBool(array[num2++], out snapshot2.CartEnabled) || !TryParseBool(array[num2++], out snapshot2.ShrinkShopPlayerItems) || !TryParseBool(array[num2++], out snapshot2.PlayerScalingModuleEnabled) || !TryParseBool(array[num2++], out snapshot2.RestorePlayerOnDamage) || !TryParseBool(array[num2++], out snapshot2.EnemyInCartInstantKill) || !TryParseBool(array[num2++], out snapshot2.PreserveMass) || !TryParseBool(array[num2++], out snapshot2.SuppressValuableDamageRestore) || !TryParseFloat(array[num2++], out snapshot2.CartLeaveDebounceSeconds) || !TryParseFloat(array[num2++], out snapshot2.ReshrinkCooldownSeconds) || !TryParseFloat(array[num2++], out snapshot2.ScaleSpeed) || !TryParseFloat(array[num2++], out snapshot2.RestoreScaleSpeed) || !TryParseFloat(array[num2++], out snapshot2.PlayerCartScaleFactor) || !TryParseFloat(array[num2++], out snapshot2.PlayerCartStandTriggerSeconds) || !TryParseFloat(array[num2++], out snapshot2.PlayerCartExitGraceSeconds) || !TryParseFloat(array[num2++], out snapshot2.PlayerCartDetectionIntervalSeconds))
		{
			return false;
		}
		for (int i = 0; i < 14; i++)
		{
			if (!TryParseBool(array[num2++], out snapshot2.Enabled[i]) || !TryParseFloat(array[num2++], out snapshot2.Factors[i]))
			{
				return false;
			}
		}
		_remoteSnapshot = snapshot2;
		snapshot = snapshot2;
		return true;
	}

	private static void GetLocalCategoryConfig(ShrinkCategory category, out bool enabled, out float factor)
	{
		switch (category)
		{
		case ShrinkCategory.Tiny:
			enabled = ModConfig.TinyEnabled.Value;
			factor = ModConfig.TinyScaleFactor.Value;
			break;
		case ShrinkCategory.Small:
			enabled = ModConfig.SmallEnabled.Value;
			factor = ModConfig.SmallScaleFactor.Value;
			break;
		case ShrinkCategory.Medium:
			enabled = ModConfig.MediumEnabled.Value;
			factor = ModConfig.MediumScaleFactor.Value;
			break;
		case ShrinkCategory.Big:
			enabled = ModConfig.BigEnabled.Value;
			factor = ModConfig.BigScaleFactor.Value;
			break;
		case ShrinkCategory.Wide:
			enabled = ModConfig.WideEnabled.Value;
			factor = ModConfig.WideScaleFactor.Value;
			break;
		case ShrinkCategory.Tall:
			enabled = ModConfig.TallEnabled.Value;
			factor = ModConfig.TallScaleFactor.Value;
			break;
		case ShrinkCategory.VeryTall:
			enabled = ModConfig.VeryTallEnabled.Value;
			factor = ModConfig.VeryTallScaleFactor.Value;
			break;
		case ShrinkCategory.EnemyOrbSmall:
			enabled = ModConfig.EnemyOrbEnabled.Value;
			factor = ModConfig.EnemyOrbSmallScaleFactor.Value;
			break;
		case ShrinkCategory.EnemyOrbMedium:
			enabled = ModConfig.EnemyOrbEnabled.Value;
			factor = ModConfig.EnemyOrbMediumScaleFactor.Value;
			break;
		case ShrinkCategory.EnemyOrbBig:
			enabled = ModConfig.EnemyOrbEnabled.Value;
			factor = ModConfig.EnemyOrbBigScaleFactor.Value;
			break;
		case ShrinkCategory.EnemyOrbBerserker:
			enabled = ModConfig.EnemyOrbEnabled.Value;
			factor = ModConfig.EnemyOrbBerserkerScaleFactor.Value;
			break;
		case ShrinkCategory.Surplus:
			enabled = ModConfig.SurplusEnabled.Value;
			factor = ModConfig.SurplusScaleFactor.Value;
			break;
		case ShrinkCategory.ValuableBox:
			enabled = ModConfig.ValuableBoxEnabled.Value;
			factor = ModConfig.ValuableBoxScaleFactor.Value;
			break;
		default:
			enabled = true;
			factor = ModConfig.FallbackScaleFactor.Value;
			break;
		}
		factor = Mathf.Clamp(factor, 0.05f, 1f);
	}

	private static void Append(bool value)
	{
		Builder.Append('|');
		Builder.Append(value ? "1" : "0");
	}

	private static void Append(float value)
	{
		Builder.Append('|');
		Builder.Append(value.ToString("R", Invariant));
	}

	private static bool TryParseBool(string value, out bool result)
	{
		if (value == "1")
		{
			result = true;
			return true;
		}
		if (value == "0")
		{
			result = false;
			return true;
		}
		result = false;
		return false;
	}

	private static bool TryParseFloat(string value, out float result)
	{
		return float.TryParse(value, NumberStyles.Float, Invariant, out result);
	}
}
internal enum ShrinkCategory
{
	Tiny,
	Small,
	Medium,
	Big,
	Wide,
	Tall,
	VeryTall,
	EnemyOrbSmall,
	EnemyOrbMedium,
	EnemyOrbBig,
	EnemyOrbBerserker,
	Surplus,
	ValuableBox,
	Fallback
}
internal static class ModConfig
{
	internal static ConfigEntry<bool> CartShrinkingEnabled;

	internal static ConfigEntry<float> CartScaleSpeed;

	internal static ConfigEntry<float> RestoreScaleSpeed;

	internal static ConfigEntry<float> CartLeaveDebounceSeconds;

	internal static ConfigEntry<float> ReshrinkCooldownSeconds;

	internal static ConfigEntry<bool> ScaleMassWithSize;

	internal static ConfigEntry<bool> ShrinkShopPlayerItems;

	internal static ConfigEntry<bool> PlayerScalingModuleEnabled;

	internal static ConfigEntry<float> PlayerCartScaleFactor;

	internal static ConfigEntry<float> PlayerCartStandTriggerSeconds;

	internal static ConfigEntry<float> PlayerCartExitGraceSeconds;

	internal static ConfigEntry<float> PlayerCartDetectionIntervalSeconds;

	internal static ConfigEntry<bool> RestorePlayerOnDamage;

	internal static ConfigEntry<bool> SuppressValuableDamageRestore;

	internal static ConfigEntry<bool> TinyEnabled;

	internal static ConfigEntry<float> TinyScaleFactor;

	internal static ConfigEntry<bool> SmallEnabled;

	internal static ConfigEntry<float> SmallScaleFactor;

	internal static ConfigEntry<bool> MediumEnabled;

	internal static ConfigEntry<float> MediumScaleFactor;

	internal static ConfigEntry<bool> BigEnabled;

	internal static ConfigEntry<float> BigScaleFactor;

	internal static ConfigEntry<bool> WideEnabled;

	internal static ConfigEntry<float> WideScaleFactor;

	internal static ConfigEntry<bool> TallEnabled;

	internal static ConfigEntry<float> TallScaleFactor;

	internal static ConfigEntry<bool> VeryTallEnabled;

	internal static ConfigEntry<float> VeryTallScaleFactor;

	internal static ConfigEntry<bool> EnemyOrbEnabled;

	internal static ConfigEntry<float> EnemyOrbSmallScaleFactor;

	internal static ConfigEntry<float> EnemyOrbMediumScaleFactor;

	internal static ConfigEntry<float> EnemyOrbBigScaleFactor;

	internal static ConfigEntry<float> EnemyOrbBerserkerScaleFactor;

	internal static ConfigEntry<bool> SurplusEnabled;

	internal static ConfigEntry<float> SurplusScaleFactor;

	internal static ConfigEntry<bool> ValuableBoxEnabled;

	internal static ConfigEntry<float> ValuableBoxScaleFactor;

	internal static ConfigEntry<float> FallbackScaleFactor;

	internal static ConfigEntry<bool> EnemyInCartInstantKill;

	internal static ConfigEntry<bool> DynamicItemScanEnabled;

	internal static ConfigEntry<float> MinimumItemScanIntervalSeconds;

	internal static ConfigEntry<float> MaximumItemScanIntervalSeconds;

	internal static ConfigEntry<bool> DebugLogging;

	internal static int ScalingConfigVersion;

	internal static void Bind(ConfigFile config)
	{
		CartShrinkingEnabled = config.Bind<bool>("购物车", "启用购物车缩小", true, "启用后,放进 C.A.R.T / 购物车的支持物品会自动缩小,取出后恢复。");
		CartScaleSpeed = config.Bind<float>("购物车", "放入时缩小速度", 0.5f, Ranged("ScalerCore 缩小动画速度。数值越大越快。", 0.1f, 20f));
		RestoreScaleSpeed = config.Bind<float>("购物车", "取出后放大速度", 0.2f, Ranged("正常取出购物车后的 ScalerCore 放大动画速度。数值越小越慢。", 0.1f, 20f));
		CartLeaveDebounceSeconds = config.Bind<float>("购物车", "离车防抖延迟", 0.5f, Ranged("物品触发缩小后,离开购物车检测范围多久才开始恢复原尺寸。调高可减少车边缘抽搐。", 0.1f, 10f));
		ReshrinkCooldownSeconds = config.Bind<float>("购物车", "恢复后重新缩小冷却", LegacyFloat(config, 0.5f, "购物车", "取出后恢复延迟", "Cart", "RestoreGraceSeconds"), Ranged("物品开始恢复后,等待多少秒才允许再次被购物车缩小。", 0.05f, 10f));
		ScaleMassWithSize = config.Bind<bool>("购物车", "启用重量随缩放降低", !LegacyBool(config, true, "购物车", "保持原始重量", "Cart", "PreserveMass"), "启用后通过 ScalerCore 的 PreserveMass 选项允许支持对象按缩放倍率降低质量;关闭则只改变视觉尺寸并保持原始重量。");
		ShrinkShopPlayerItems = config.Bind<bool>("购物车", "启用商店用品缩小", false, "启用后,枪、血包、近战、手雷、工具、无人机、宝珠、升级、追踪器、地雷等商店购买类实用品会使用默认缩小倍率。大小推车、C.A.R.T. Cannon 和 C.A.R.T. Laser 始终不会缩小。");
		PlayerScalingModuleEnabled = config.Bind<bool>("玩家缩放", "启用玩家缩放", true, "默认开启。启用后才会运行玩家站车检测和玩家缩放;关闭时 ShrinkCart 不参与任何玩家缩放逻辑。");
		PlayerCartScaleFactor = config.Bind<float>("玩家缩放", "玩家进车缩放倍率", 0.55f, Ranged("开启“启用玩家缩放”后,玩家站在购物车中心区域触发缩放时的目标尺寸比例。", 0.05f, 1f));
		PlayerCartStandTriggerSeconds = config.Bind<float>("玩家缩放", "玩家站车触发时间", 2f, Ranged("开启“启用玩家缩放”后,玩家站在购物车中心区域多久才切换缩小/恢复。离开中心区域会重置计时。", 0.25f, 10f));
		PlayerCartExitGraceSeconds = config.Bind<float>("玩家缩放", "玩家离车判定宽容时间", 0.6f, Ranged("玩家仍在购物车中心区域附近但短暂跳起、踩到车内物品或被货物顶起时,保留车内状态多久后才判定离开。设为 0 可恢复严格判定。", 0f, 2f));
		PlayerCartDetectionIntervalSeconds = config.Bind<float>("玩家缩放", "玩家检测间隔", 0.75f, Ranged("玩家缩放开启时,主机多久检测一次玩家是否位于正式购物车底面投影范围内。数值越大越省性能,也越能防误触发。", 0.25f, 2f));
		RestorePlayerOnDamage = config.Bind<bool>("玩家缩放", "启用玩家受伤后自动恢复", true, "启用后,玩家缩小时使用 ScalerCore 的受伤/碰撞恢复链路;关闭后,玩家只会通过再次站车切换恢复。");
		SuppressValuableDamageRestore = config.Bind<bool>("购物车", "防止碰撞弹回原尺寸", true, "启用后,贵重物品在购物车里轻微碰撞时不会立刻弹回原尺寸。ScalerCore 的安全恢复仍会保留。");
		TinyEnabled = BindCategoryEnabled(config, "Tiny 微型贵重物", defaultValue: true);
		TinyScaleFactor = BindCategoryFactor(config, "Tiny 微型贵重物", 0.8f);
		SmallEnabled = BindCategoryEnabled(config, "Small 小贵重物", defaultValue: true);
		SmallScaleFactor = BindCategoryFactor(config, "Small 小贵重物", 0.6f);
		MediumEnabled = BindCategoryEnabled(config, "Medium 中贵重物", defaultValue: true);
		MediumScaleFactor = BindCategoryFactor(config, "Medium 中贵重物", 0.45f);
		BigEnabled = BindCategoryEnabled(config, "Big 大贵重物", defaultValue: true);
		BigScaleFactor = BindCategoryFactor(config, "Big 大贵重物", 0.4f);
		WideEnabled = BindCategoryEnabled(config, "Wide 宽贵重物", defaultValue: true);
		WideScaleFactor = BindCategoryFactor(config, "Wide 宽贵重物", 0.35f);
		TallEnabled = BindCategoryEnabled(config, "Tall 高贵重物", defaultValue: true);
		TallScaleFactor = BindCategoryFactor(config, "Tall 高贵重物", 0.35f);
		VeryTallEnabled = BindCategoryEnabled(config, "VeryTall 超高贵重物", defaultValue: true);
		VeryTallScaleFactor = BindCategoryFactor(config, "VeryTall 超高贵重物", 0.25f);
		EnemyOrbEnabled = config.Bind<bool>("敌人球", "启用敌人球缩小", true, "启用后,Enemy - Small/Medium/Big/Berserker 类贵重物会按下方倍率缩小。");
		EnemyOrbSmallScaleFactor = config.Bind<float>("敌人球", "Small 敌人球倍率", 0.8f, Ranged("Small 敌人球放入购物车后的目标尺寸比例。", 0.05f, 1f));
		EnemyOrbMediumScaleFactor = config.Bind<float>("敌人球", "Medium 敌人球倍率", 0.65f, Ranged("Medium 敌人球放入购物车后的目标尺寸比例。", 0.05f, 1f));
		EnemyOrbBigScaleFactor = config.Bind<float>("敌人球", "Big 敌人球倍率", 0.45f, Ranged("Big 敌人球放入购物车后的目标尺寸比例。", 0.05f, 1f));
		EnemyOrbBerserkerScaleFactor = config.Bind<float>("敌人球", "Berserker 敌人球倍率", 0.45f, Ranged("Berserker 敌人球放入购物车后的目标尺寸比例。", 0.05f, 1f));
		SurplusEnabled = config.Bind<bool>("特殊物品", "启用钱袋/Surplus 缩小", LegacyBool(config, true, "特殊物品", "启用 Surplus 缩小"), "启用后,钱袋/SurplusValuable 会使用单独倍率。");
		SurplusScaleFactor = config.Bind<float>("特殊物品", "钱袋/Surplus 倍率", LegacyFloat(config, 0.25f, "特殊物品", "Surplus 倍率"), Ranged("钱袋/SurplusValuable 放入购物车后的目标尺寸比例。", 0.05f, 1f));
		ValuableBoxEnabled = config.Bind<bool>("特殊物品", "启用代币箱缩小", true, "启用后,新版本抽奖用代币箱 ItemValuableBox 会使用单独倍率。");
		ValuableBoxScaleFactor = config.Bind<float>("特殊物品", "代币箱倍率", 0.4f, Ranged("抽奖用代币箱 ItemValuableBox 放入购物车后的目标尺寸比例。", 0.05f, 1f));
		FallbackScaleFactor = config.Bind<float>("商店用品", "商店用品缩小倍率", LegacyFloat(config, 0.5f, "普通或未知物品", "默认缩小倍率"), Ranged("开启“启用商店用品缩小”后,枪、血包、工具等实用品放入购物车后的目标尺寸比例。也作为未知贵重物分类的兜底倍率。", 0.05f, 1f));
		EnemyInCartInstantKill = config.Bind<bool>("车辆碾压", "敌人进车秒杀", LegacyBool(config, true, "车辆碾压", "车辆碾压秒杀敌人", "VehicleCrush", "InstantKillEnemies"), "启用后,敌人或敌人刚体进入购物车时会立刻死亡。此功能复刻 ShrinkerCartPlus 的敌人进车秒杀逻辑。");
		DynamicItemScanEnabled = config.Bind<bool>("性能", "启用动态物品扫描", true, "启用后,ShrinkCart 会根据当前跟踪的缩小物品数量自动拉长状态扫描间隔,减少车内物品很多时的卡顿。");
		MinimumItemScanIntervalSeconds = config.Bind<float>("性能", "最小物品扫描间隔", 0.15f, Ranged("少量物品时的最短状态扫描间隔。数值越小,离车恢复越灵敏,但开销更高。", 0.05f, 1f));
		MaximumItemScanIntervalSeconds = config.Bind<float>("性能", "最大物品扫描间隔", 1f, Ranged("大量物品时允许使用的最长状态扫描间隔。数值越大越省性能,但离车恢复最多会延后一个扫描间隔。", 0.1f, 2f));
		DebugLogging = config.Bind<bool>("诊断", "启用调试日志", false, "启用后,在 BepInEx 日志中写入更多缩小、恢复、敌人进车和碾压识别信息。");
		WatchScaling<bool>(CartShrinkingEnabled);
		WatchScaling<float>(CartScaleSpeed);
		WatchScaling<float>(RestoreScaleSpeed);
		WatchScaling<float>(CartLeaveDebounceSeconds);
		WatchScaling<float>(ReshrinkCooldownSeconds);
		WatchScaling<bool>(ScaleMassWithSize);
		WatchScaling<bool>(ShrinkShopPlayerItems);
		WatchScaling<bool>(PlayerScalingModuleEnabled);
		WatchScaling<float>(PlayerCartScaleFactor);
		WatchScaling<float>(PlayerCartStandTriggerSeconds);
		WatchScaling<float>(PlayerCartExitGraceSeconds);
		WatchScaling<float>(PlayerCartDetectionIntervalSeconds);
		WatchScaling<bool>(RestorePlayerOnDamage);
		WatchScaling<bool>(SuppressValuableDamageRestore);
		WatchScaling<bool>(TinyEnabled);
		WatchScaling<float>(TinyScaleFactor);
		WatchScaling<bool>(SmallEnabled);
		WatchScaling<float>(SmallScaleFactor);
		WatchScaling<bool>(MediumEnabled);
		WatchScaling<float>(MediumScaleFactor);
		WatchScaling<bool>(BigEnabled);
		WatchScaling<float>(BigScaleFactor);
		WatchScaling<bool>(WideEnabled);
		WatchScaling<float>(WideScaleFactor);
		WatchScaling<bool>(TallEnabled);
		WatchScaling<float>(TallScaleFactor);
		WatchScaling<bool>(VeryTallEnabled);
		WatchScaling<float>(VeryTallScaleFactor);
		WatchScaling<bool>(EnemyOrbEnabled);
		WatchScaling<float>(EnemyOrbSmallScaleFactor);
		WatchScaling<float>(EnemyOrbMediumScaleFactor);
		WatchScaling<float>(EnemyOrbBigScaleFactor);
		WatchScaling<float>(EnemyOrbBerserkerScaleFactor);
		WatchScaling<bool>(SurplusEnabled);
		WatchScaling<float>(SurplusScaleFactor);
		WatchScaling<bool>(ValuableBoxEnabled);
		WatchScaling<float>(ValuableBoxScaleFactor);
		WatchScaling<float>(FallbackScaleFactor);
		RemoveDeprecatedEntries(config);
	}

	internal static float SafeScaleSpeed()
	{
		return Mathf.Clamp(CartScaleSpeed.Value, 0.1f, 20f);
	}

	internal static float SafeRestoreScaleSpeed()
	{
		return Mathf.Clamp(RestoreScaleSpeed.Value, 0.1f, 20f);
	}

	internal static float SafeCartLeaveDebounceSeconds()
	{
		return Mathf.Clamp(CartLeaveDebounceSeconds.Value, 0.1f, 10f);
	}

	internal static float SafeReshrinkCooldownSeconds()
	{
		return Mathf.Clamp(ReshrinkCooldownSeconds.Value, 0.05f, 10f);
	}

	internal static bool PlayerScalingEnabled()
	{
		if (CartShrinkingEnabled != null && PlayerScalingModuleEnabled != null && CartShrinkingEnabled.Value)
		{
			return PlayerScalingModuleEnabled.Value;
		}
		return false;
	}

	internal static bool ShouldPreserveMass()
	{
		if (ScaleMassWithSize != null)
		{
			return !ScaleMassWithSize.Value;
		}
		return true;
	}

	internal static float SafePlayerCartScaleFactor()
	{
		return Mathf.Clamp(PlayerCartScaleFactor.Value, 0.05f, 1f);
	}

	internal static float SafePlayerCartStandTriggerSeconds()
	{
		return Mathf.Clamp(PlayerCartStandTriggerSeconds.Value, 0.25f, 10f);
	}

	internal static float SafePlayerCartExitGraceSeconds()
	{
		return Mathf.Clamp(PlayerCartExitGraceSeconds.Value, 0f, 2f);
	}

	internal static float SafePlayerCartDetectionIntervalSeconds()
	{
		return Mathf.Clamp(PlayerCartDetectionIntervalSeconds.Value, 0.25f, 2f);
	}

	internal static bool DynamicItemScanEnabledValue()
	{
		if (DynamicItemScanEnabled != null)
		{
			return DynamicItemScanEnabled.Value;
		}
		return false;
	}

	internal static float SafeMinimumItemScanIntervalSeconds()
	{
		if (MinimumItemScanIntervalSeconds != null)
		{
			return Mathf.Clamp(MinimumItemScanIntervalSeconds.Value, 0.05f, 1f);
		}
		return 0.15f;
	}

	internal static float SafeMaximumItemScanIntervalSeconds()
	{
		float num = SafeMinimumItemScanIntervalSeconds();
		float num2 = ((MaximumItemScanIntervalSeconds == null) ? 1f : Mathf.Clamp(MaximumItemScanIntervalSeconds.Value, 0.1f, 2f));
		return Mathf.Max(num, num2);
	}

	internal static bool TryGetScaleFactor(ShrinkCategory category, out float factor)
	{
		switch (category)
		{
		case ShrinkCategory.Tiny:
			return TryCategory(TinyEnabled, TinyScaleFactor, out factor);
		case ShrinkCategory.Small:
			return TryCategory(SmallEnabled, SmallScaleFactor, out factor);
		case ShrinkCategory.Medium:
			return TryCategory(MediumEnabled, MediumScaleFactor, out factor);
		case ShrinkCategory.Big:
			return TryCategory(BigEnabled, BigScaleFactor, out factor);
		case ShrinkCategory.Wide:
			return TryCategory(WideEnabled, WideScaleFactor, out factor);
		case ShrinkCategory.Tall:
			return TryCategory(TallEnabled, TallScaleFactor, out factor);
		case ShrinkCategory.VeryTall:
			return TryCategory(VeryTallEnabled, VeryTallScaleFactor, out factor);
		case ShrinkCategory.EnemyOrbSmall:
			return TryEnemyOrb(EnemyOrbSmallScaleFactor, out factor);
		case ShrinkCategory.EnemyOrbMedium:
			return TryEnemyOrb(EnemyOrbMediumScaleFactor, out factor);
		case ShrinkCategory.EnemyOrbBig:
			return TryEnemyOrb(EnemyOrbBigScaleFactor, out factor);
		case ShrinkCategory.EnemyOrbBerserker:
			return TryEnemyOrb(EnemyOrbBerserkerScaleFactor, out factor);
		case ShrinkCategory.Surplus:
			return TryCategory(SurplusEnabled, SurplusScaleFactor, out factor);
		case ShrinkCategory.ValuableBox:
			return TryCategory(ValuableBoxEnabled, ValuableBoxScaleFactor, out factor);
		default:
			factor = SafeFactor(FallbackScaleFactor.Value);
			return true;
		}
	}

	private static ConfigEntry<bool> BindCategoryEnabled(ConfigFile config, string section, bool defaultValue)
	{
		return config.Bind<bool>(section, "启用此分类缩小", defaultValue, "启用后,该分类物品放入购物车时会自动缩小。");
	}

	private static ConfigEntry<float> BindCategoryFactor(ConfigFile config, string section, float defaultValue)
	{
		return config.Bind<float>(section, "缩小倍率", defaultValue, Ranged("该分类物品放入购物车后的目标尺寸比例。0.4 表示原尺寸的 40%。", 0.05f, 1f));
	}

	private static ConfigDescription Ranged(string description, float min, float max)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Expected O, but got Unknown
		return new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), new object[0]);
	}

	private static bool TryCategory(ConfigEntry<bool> enabled, ConfigEntry<float> factorEntry, out float factor)
	{
		factor = SafeFactor(factorEntry.Value);
		return enabled.Value;
	}

	private static bool TryEnemyOrb(ConfigEntry<float> factorEntry, out float factor)
	{
		factor = SafeFactor(factorEntry.Value);
		return EnemyOrbEnabled.Value;
	}

	private static float SafeFactor(float value)
	{
		return Mathf.Clamp(value, 0.05f, 1f);
	}

	private static bool LegacyBool(ConfigFile config, bool defaultValue, params string[] sectionKeyPairs)
	{
		ConfigEntry<bool> val = default(ConfigEntry<bool>);
		for (int i = 0; i + 1 < sectionKeyPairs.Length; i += 2)
		{
			if (config.TryGetEntry<bool>(sectionKeyPairs[i], sectionKeyPairs[i + 1], ref val))
			{
				return val.Value;
			}
		}
		return defaultValue;
	}

	private static float LegacyFloat(ConfigFile config, float defaultValue, params string[] sectionKeyPairs)
	{
		ConfigEntry<float> val = default(ConfigEntry<float>);
		for (int i = 0; i + 1 < sectionKeyPairs.Length; i += 2)
		{
			if (config.TryGetEntry<float>(sectionKeyPairs[i], sectionKeyPairs[i + 1], ref val))
			{
				return val.Value;
			}
		}
		return defaultValue;
	}

	private static void RemoveDeprecatedEntries(ConfigFile config)
	{
		bool flag = false;
		flag |= RemoveDeprecatedEntry(config, "Cart", "Enabled");
		flag |= RemoveDeprecatedEntry(config, "Cart", "ScaleFactor");
		flag |= RemoveDeprecatedEntry(config, "Cart", "ScaleSpeed");
		flag |= RemoveDeprecatedEntry(config, "Cart", "RestoreGraceSeconds");
		flag |= RemoveDeprecatedEntry(config, "Cart", "PreserveMass");
		flag |= RemoveDeprecatedEntry(config, "Cart", "ShrinkNonValuableItems");
		flag |= RemoveDeprecatedEntry(config, "Cart", "SuppressValuableDamageRestore");
		flag |= RemoveDeprecatedEntry(config, "Diagnostics", "DebugLogging");
		flag |= RemoveDeprecatedEntry(config, "购物车", "保持原始重量");
		flag |= RemoveDeprecatedEntry(config, "VehicleCrush", "InstantKillPlayers");
		flag |= RemoveDeprecatedEntry(config, "VehicleCrush", "InstantKillEnemies");
		flag |= RemoveDeprecatedEntry(config, "视觉", "隐藏缩放闪光");
		flag |= RemoveDeprecatedEntry(config, "车辆碾压", "车辆碾压秒杀玩家");
		flag |= RemoveDeprecatedEntry(config, "提取点复活兼容", "启用提取点复活");
		flag |= RemoveDeprecatedEntry(config, "提取点复活兼容", "复活前稳定检测时间");
		flag |= RemoveDeprecatedEntry(config, "提取点复活兼容", "复活检测间隔");
		flag |= RemoveDeprecatedEntry(config, "提取点复活兼容", "拦截外部立即复活调用");
		flag |= RemoveDeprecatedEntry(config, "购物车", "商店用品也缩小");
		flag |= RemoveDeprecatedEntry(config, "购物车", "玩家也缩小");
		flag |= RemoveDeprecatedEntry(config, "购物车", "启用实验性玩家缩放");
		flag |= RemoveDeprecatedEntry(config, "购物车", "玩家死亡前自动恢复");
		flag |= RemoveDeprecatedEntry(config, "购物车", "启用玩家缩放");
		flag |= RemoveDeprecatedEntry(config, "购物车", "玩家进车缩放倍率");
		flag |= RemoveDeprecatedEntry(config, "购物车", "玩家站车触发时间");
		flag |= RemoveDeprecatedEntry(config, "购物车", "玩家离车判定宽容时间");
		flag |= RemoveDeprecatedEntry(config, "购物车", "玩家进车切换间隔");
		flag |= RemoveDeprecatedEntry(config, "购物车", "普通物品也缩小");
		flag |= RemoveDeprecatedEntry(config, "购物车", "商店/人物用品也缩小");
		flag |= RemoveDeprecatedEntry(config, "购物车", "防止车辆互相重叠");
		flag |= RemoveDeprecatedEntry(config, "购物车", "车辆硬碰撞修正强度");
		flag |= RemoveDeprecatedEntry(config, "购物车", "车辆最大单帧修正距离");
		flag |= RemoveDeprecatedEntry(config, "购物车", "车辆挤压速度清除");
		flag |= RemoveDeprecatedEntry(config, "购物车", "车辆临时忽略碰撞时间(已废弃)");
		flag |= RemoveDeprecatedEntry(config, "购物车", "车辆临时忽略碰撞时间");
		flag |= RemoveDeprecatedEntry(config, "购物车", "车辆脱困强度");
		if (flag | RemoveDeprecatedEntry(config, "玩家缩放", "旧版玩家缩放开关(已停用)"))
		{
			config.Save();
		}
	}

	private static bool RemoveDeprecatedEntry(ConfigFile config, string section, string key)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Expected O, but got Unknown
		return config.Remove(new ConfigDefinition(section, key));
	}

	private static void WatchScaling<T>(ConfigEntry<T> entry)
	{
		entry.SettingChanged += OnScalingSettingChanged;
	}

	private static void OnScalingSettingChanged(object sender, EventArgs args)
	{
		ScalingConfigVersion++;
	}
}
internal static class PlayerCartScaleController
{
	private sealed class PlayerState
	{
		internal PlayerAvatar Player;

		internal bool ShrinkCartScaled;

		internal bool WasInCartRange;

		internal bool WasInTriggerZone;

		internal bool TriggeredThisStay;

		internal float TriggerZoneEnteredTime;

		internal float LastInsideCenterTime;
	}

	private sealed class CartState
	{
		internal PhysGrabCart Cart;

		internal Transform InCart;
	}

	private struct CartZoneResult
	{
		internal bool InCartRange;

		internal bool InTriggerZone;
	}

	private const float CenterZoneHorizontalScale = 0.45f;

	private const float FloorProjectionPaddingBelow = 0.25f;

	private const float FloorProjectionStandingHeightAbove = 1.4f;

	private const float MinimumCenterHalfExtent = 0.15f;

	private const float StandPointYOffset = 0.05f;

	private static readonly Dictionary<int, CartState> RegisteredCarts = new Dictionary<int, CartState>();

	private static readonly Dictionary<int, PlayerState> PlayerStates = new Dictionary<int, PlayerState>();

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

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

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

	private static readonly FieldInfo PhysGrabCartInCartField = typeof(PhysGrabCart).GetField("inCart", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PlayerAvatarColliderField = typeof(PlayerAvatar).GetField("collider", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static float _nextTickTime;

	internal static void Reset()
	{
		RegisteredCarts.Clear();
		PlayerStates.Clear();
		ExcludedCartIds.Clear();
		RemoveCartIds.Clear();
		RemovePlayerIds.Clear();
		_nextTickTime = 0f;
	}

	internal static void RegisterCart(PhysGrabCart cart)
	{
		if (IsHostOrSingleplayer() && !((Object)(object)cart == (Object)null) && !IsExcludedPlayerScaleCart(cart))
		{
			RegisteredCarts[((Object)cart).GetInstanceID()] = new CartState
			{
				Cart = cart,
				InCart = GetInCartTransform(cart)
			};
			DebugLog("Registered regular cart for player stand-toggle: " + ((Object)cart).name);
		}
	}

	internal static void RegisterExistingCarts()
	{
		PhysGrabCart[] array = Object.FindObjectsOfType<PhysGrabCart>();
		for (int i = 0; i < array.Length; i++)
		{
			RegisterCart(array[i]);
		}
	}

	internal static void Tick()
	{
		if (!IsHostOrSingleplayer())
		{
			return;
		}
		float time = Time.time;
		if (time < _nextTickTime)
		{
			return;
		}
		_nextTickTime = time + ModConfig.SafePlayerCartDetectionIntervalSeconds();
		if (!ModConfig.PlayerScalingEnabled())
		{
			RestoreAll();
		}
		else
		{
			if (RegisteredCarts.Count == 0)
			{
				return;
			}
			PruneInvalidCarts();
			List<PlayerAvatar> players = GetPlayers();
			if (players != null && players.Count != 0)
			{
				for (int i = 0; i < players.Count; i++)
				{
					ProcessPlayer(players[i], time);
				}
				PruneMissingPlayers();
			}
		}
	}

	internal static void RestoreAll()
	{
		if (PlayerStates.Count == 0)
		{
			return;
		}
		foreach (PlayerState value in PlayerStates.Values)
		{
			if (value != null && value.ShrinkCartScaled && (Object)(object)value.Player != (Object)null)
			{
				RestorePlayer(((Component)value.Player).gameObject);
			}
		}
		PlayerStates.Clear();
	}

	internal static void Disable()
	{
		RestoreAll();
		Reset();
	}

	private static void ProcessPlayer(PlayerAvatar player, float now)
	{
		if ((Object)(object)player == (Object)null || (Object)(object)((Component)player).gameObject == (Object)null || !((Component)player).gameObject.activeInHierarchy)
		{
			return;
		}
		int instanceID = ((Object)player).GetInstanceID();
		if (!PlayerStates.TryGetValue(instanceID, out var value))
		{
			PlayerState playerState = new PlayerState();
			playerState.Player = player;
			value = playerState;
			PlayerStates[instanceID] = value;
		}
		else
		{
			value.Player = player;
		}
		if (value.ShrinkCartScaled && !ScaleManager.IsScaled(((Component)player).gameObject))
		{
			value.ShrinkCartScaled = false;
		}
		CartZoneResult playerCartZone = GetPlayerCartZone(player);
		bool flag = playerCartZone.InCartRange;
		bool inTriggerZone = playerCartZone.InTriggerZone;
		if (flag)
		{
			value.LastInsideCenterTime = now;
		}
		else if (value.WasInCartRange && now - value.LastInsideCenterTime <= ModConfig.SafePlayerCartExitGraceSeconds())
		{
			flag = true;
		}
		if (!flag)
		{
			if (value.WasInCartRange)
			{
				DebugLog("Player left cart floor range: " + ((Object)player).name);
			}
			value.WasInCartRange = false;
			value.WasInTriggerZone = false;
			value.TriggeredThisStay = false;
			value.TriggerZoneEnteredTime = 0f;
			value.LastInsideCenterTime = 0f;
			return;
		}
		value.WasInCartRange = true;
		if (!inTriggerZone)
		{
			value.WasInTriggerZone = false;
			value.TriggerZoneEnteredTime = 0f;
		}
		else if (!value.WasInTriggerZone)
		{
			value.WasInTriggerZone = true;
			value.TriggerZoneEnteredTime = now;
			value.LastInsideCenterTime = now;
			DebugLog("Player entered cart floor trigger zone: " + ((Object)player).name);
		}
		else
		{
			if (value.TriggeredThisStay || now - value.TriggerZoneEnteredTime < ModConfig.SafePlayerCartStandTriggerSeconds())
			{
				return;
			}
			value.TriggeredThisStay = true;
			DebugLog("Player cart floor trigger timer completed: " + ((Object)player).name);
			if (value.ShrinkCartScaled)
			{
				if (RestorePlayer(((Component)player).gameObject))
				{
					value.ShrinkCartScaled = false;
					DebugLog("Restored player after standing in cart center: " + ((Object)player).name);
				}
			}
			else if (ScaleManager.IsScaled(((Component)player).gameObject))
			{
				DebugLog("Skipped player cart shrink because another scale session is active: " + ((Object)player).name);
			}
			else if (ShrinkPlayer(((Component)player).gameObject))
			{
				value.ShrinkCartScaled = true;
				DebugLog("Shrunk player after standing in cart center: " + ((Object)player).name);
			}
		}
	}

	private static bool ShrinkPlayer(GameObject target)
	{
		//IL_000b: 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_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)target == (Object)null)
		{
			return false;
		}
		ScaleOptions @default = ScaleOptions.Default;
		@default.Factor = ModConfig.SafePlayerCartScaleFactor();
		@default.Speed = ModConfig.SafeScaleSpeed();
		@default.RestoreSpeed = ModConfig.SafeRestoreScaleSpeed();
		@default.Duration = 0f;
		@default.AllowedTargets = (ScaleTargets)1;
		@default.SuppressImpactFlash = true;
		@default.SuppressCameraShake = true;
		@default.IgnoreBonkExpand = ModConfig.RestorePlayerOnDamage != null && !ModConfig.RestorePlayerOnDamage.Value;
		@default.RejectExternalApply = false;
		try
		{
			bool flag = ScaleManager.ApplyIfNotScaled(target, @default);
			if (!flag)
			{
				DebugLog("ScalerCore rejected player cart shrink: " + ((Object)target).name);
			}
			return flag;
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Failed to shrink player standing in cart: " + ex.Message));
			return false;
		}
	}

	private static bool RestorePlayer(GameObject target)
	{
		//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_0053: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)target == (Object)null)
		{
			return false;
		}
		try
		{
			if (!ScaleManager.IsScaled(target))
			{
				return true;
			}
			ScaleController controller = ScaleManager.GetController(target);
			if ((Object)(object)controller != (Object)null && controller.IsScaled)
			{
				ScaleOptions currentOptions = controller.CurrentOptions;
				currentOptions.RestoreSpeed = ModConfig.SafeRestoreScaleSpeed();
				currentOptions.SuppressImpactFlash = true;
				currentOptions.SuppressCameraShake = true;
				ScaleManager.ForceUpdateOptions(target, currentOptions);
			}
			ScaleManager.ForceRestore(target);
			return true;
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Failed to restore player from cart toggle: " + ex.Message));
			return false;
		}
	}

	private static CartZoneResult GetPlayerCartZone(PlayerAvatar player)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: 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)
		CartZoneResult result = default(CartZoneResult);
		Vector3 playerStandPoint = GetPlayerStandPoint(player);
		foreach (CartState value in RegisteredCarts.Values)
		{
			if (value != null)
			{
				CartZoneResult playerCartZone = GetPlayerCartZone(player, value, playerStandPoint);
				if (playerCartZone.InCartRange)
				{
					result.InCartRange = true;
				}
				if (playerCartZone.InTriggerZone)
				{
					result.InTriggerZone = true;
					return result;
				}
			}
		}
		return result;
	}

	private static CartZoneResult GetPlayerCartZone(PlayerAvatar player, CartState cartState, Vector3 standPoint)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		CartZoneResult result = default(CartZoneResult);
		Transform val = cartState.InCart;
		if ((Object)(object)val == (Object)null && (Object)(object)cartState.Cart != (Object)null)
		{
			val = (cartState.InCart = GetInCartTransform(cartState.Cart));
		}
		if ((Object)(object)player == (Object)null || (Object)(object)val == (Object)null)
		{
			return result;
		}
		result.InCartRange = IsPointInsideCartFloorProjection(standPoint, val, 1f);
		result.InTriggerZone = result.InCartRange && IsPointInsideCartFloorProjection(standPoint, val, 0.45f);
		return result;
	}

	private static bool IsPointInsideCartFloorProjection(Vector3 point, Transform inCart, float horizontalScale)
	{
		//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_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: 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_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = Quaternion.Inverse(inCart.rotation) * (point - inCart.position);
		Vector3 val2 = inCart.localScale * 0.5f;
		float num = Mathf.Max(Mathf.Abs(val2.x) * horizontalScale, 0.15f);
		float num2 = Mathf.Max(Mathf.Abs(val2.z) * horizontalScale, 0.15f);
		float num3 = 0f - Mathf.Abs(val2.y);
		if (Mathf.Abs(val.x) <= num && Mathf.Abs(val.z) <= num2 && val.y >= num3 - 0.25f)
		{
			return val.y <= num3 + 1.4f;
		}
		return false;
	}

	private static Transform GetInCartTransform(PhysGrabCart cart)
	{
		if ((Object)(object)cart == (Object)null || PhysGrabCartInCartField == null)
		{
			return null;
		}
		object? value = PhysGrabCartInCartField.GetValue(cart);
		return (Transform)((value is Transform) ? value : null);
	}

	private static void PruneInvalidCarts()
	{
		RemoveCartIds.Clear();
		foreach (KeyValuePair<int, CartState> registeredCart in RegisteredCarts)
		{
			if (registeredCart.Value == null || (Object)(object)registeredCart.Value.Cart == (Object)null || (Object)(object)registeredCart.Value.InCart == (Object)null || IsExcludedPlayerScaleCart(registeredCart.Value.Cart))
			{
				RemoveCartIds.Add(registeredCart.Key);
			}
		}
		for (int i = 0; i < RemoveCartIds.Count; i++)
		{
			RegisteredCarts.Remove(RemoveCartIds[i]);
		}
		RemoveCartIds.Clear();
	}

	private static bool IsExcludedPlayerScaleCart(PhysGrabCart cart)
	{
		if ((Object)(object)cart == (Object)null)
		{
			return true;
		}
		int instanceID = ((Object)cart).GetInstanceID();
		if (ExcludedCartIds.Contains(instanceID))
		{
			return true;
		}
		if (cart.isSmallCart)
		{
			ExcludedCartIds.Add(instanceID);
			DebugLog("Excluded small cart from player stand-toggle: " + ((Object)cart).name);
			return true;
		}
		return false;
	}

	private static Vector3 GetPlayerStandPoint(PlayerAvatar player)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: 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)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		Collider val = null;
		if ((Object)(object)player != (Object)null && PlayerAvatarColliderField != null)
		{
			object? value = PlayerAvatarColliderField.GetValue(player);
			val = (Collider)((value is Collider) ? value : null);
		}
		if ((Object)(object)val != (Object)null)
		{
			Bounds bounds = val.bounds;
			return new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).min.y + 0.05f, ((Bounds)(ref bounds)).center.z);
		}
		Vector3 val2 = (((Object)(object)player.playerTransform != (Object)null) ? player.playerTransform.position : ((Component)player).transform.position);
		return val2 + Vector3.up * 0.05f;
	}

	private static void PruneMissingPlayers()
	{
		if (PlayerStates.Count == 0)
		{
			return;
		}
		RemovePlayerIds.Clear();
		foreach (KeyValuePair<int, PlayerState> playerState in PlayerStates)
		{
			if (playerState.Value == null || (Object)(object)playerState.Value.Player == (Object)null)
			{
				RemovePlayerIds.Add(playerState.Key);
			}
		}
		for (int i = 0; i < RemovePlayerIds.Count; i++)
		{
			PlayerStates.Remove(RemovePlayerIds[i]);
		}
		RemovePlayerIds.Clear();
	}

	private static List<PlayerAvatar> GetPlayers()
	{
		try
		{
			if ((Object)(object)GameDirector.instance != (Object)null && GameDirector.instance.PlayerList != null)
			{
				return GameDirector.instance.PlayerList;
			}
		}
		catch
		{
		}
		try
		{
			return SemiFunc.PlayerGetAll();
		}
		catch
		{
			return null;
		}
	}

	private static bool IsHostOrSingleplayer()
	{
		return Authority.IsHostOrSingleplayer();
	}

	private static void DebugLog(string message)
	{
		if (ModConfig.DebugLogging.Value)
		{
			Plugin.Log.LogInfo((object)message);
		}
	}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("AngelcoMilk.ShrinkCart", "ShrinkCart", "0.2.33")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "AngelcoMilk.ShrinkCart";

	public const string PluginName = "ShrinkCart";

	public const string PluginVersion = "0.2.33";

	internal static Plugin Instance;

	internal static ManualLogSource Log;

	private Harmony _harmony;

	private bool _playerScalingWasEnabled;

	private bool _wasHostOrSingleplayer;

	private void Awake()
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		Authority.Reset();
		ModConfig.Bind(((BaseUnityPlugin)this).Config);
		ValuableBoxScaleAdapter.Reset();
		ValuableBoxScaleAdapter.RegisterHandler();
		ShrinkerCartController.Reset();
		PlayerCartScaleController.Reset();
		EnemyInCartKillController.Reset();
		HostConfigSync.Reset();
		_harmony = new Harmony("AngelcoMilk.ShrinkCart");
		_harmony.PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ShrinkCart 0.2.33 loaded.");
	}

	private void Update()
	{
		bool flag = Authority.IsHostOrSingleplayer();
		if (flag && !_wasHostOrSingleplayer)
		{
			CartRegistry.RegisterExistingCarts();
			if (ModConfig.PlayerScalingEnabled())
			{
				PlayerCartScaleController.Reset();
				PlayerCartScaleController.RegisterExistingCarts();
				_playerScalingWasEnabled = true;
			}
		}
		HostConfigSync.Tick();
		ShrinkerCartController.Tick();
		bool flag2 = ModConfig.PlayerScalingEnabled();
		if (flag2)
		{
			if (!_playerScalingWasEnabled)
			{
				PlayerCartScaleController.Reset();
				PlayerCartScaleController.RegisterExistingCarts();
			}
			PlayerCartScaleController.Tick();
		}
		else if (_playerScalingWasEnabled)
		{
			PlayerCartScaleController.Disable();
		}
		_playerScalingWasEnabled = flag2;
		_wasHostOrSingleplayer = flag;
	}

	private void OnDestroy()
	{
		ShrinkerCartController.RestoreAll();
		PlayerCartScaleController.RestoreAll();
		CartRegistry.Reset();
		HostConfigSync.Reset();
		Authority.Reset();
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
			_harmony = null;
		}
	}
}
internal static class ShrinkerCartController
{
	private sealed class TrackedObject
	{
		internal GameObject Target;

		internal float LastSeenInCartTime;

		internal float RestoreCheckDueTime;

		internal int LastSeenCartId;

		internal bool MarkedInCartThisPass;

		internal ShrinkCategory Category;
	}

	private sealed class CachedShrinkData
	{
		internal int ConfigVersion;

		internal bool CanShrink;

		internal ShrinkCategory Category;

		internal float Factor;
	}

	private const float LowTrackedObjectIntervalSeconds = 0.35f;

	private const float MediumTrackedObjectIntervalSeconds = 0.75f;

	private static readonly Dictionary<int, TrackedObject> TrackedObjects = new Dictionary<int, TrackedObject>();

	private static readonly Dictionary<int, CachedShrinkData> ShrinkDataCache = new Dictionary<int, CachedShrinkData>();

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

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

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

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

	private static readonly List<GameObject> RestoreTargets = new List<GameObject>(16);

	private static readonly FieldInfo ItemAttributesItemTypeField = typeof(ItemAttributes).GetField("itemType", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PhysGrabObjectIsGunField = typeof(PhysGrabObject).GetField("isGun", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly FieldInfo PhysGrabCartPhysGrabObjectField = typeof(PhysGrabCart).GetField("physGrabObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

	private static float _nextTickTime;

	private static float _nextRestoreCheckTime = float.PositiveInfinity;

	private static float _nextCooldownCheckTime = float.PositiveInfinity;

	internal static void Reset()
	{
		TrackedObjects.Clear();
		ShrinkDataCache.Clear();
		ReshrinkCooldownUntil.Clear();
		PermanentlyExcludedObjectIds.Clear();
		RestoreIds.Clear();
		ExpiredCooldownIds.Clear();
		RestoreTargets.Clear();
		_nextTickTime = 0f;
		_nextRestoreCheckTime = float.PositiveInfinity;
		_nextCooldownCheckTime = float.PositiveInfinity;
	}

	internal static void ProcessCartObject(PhysGrabInCart inCart, PhysGrabObject item)
	{
		if (!((Object)(object)inCart == (Object)null) && !((Object)(object)inCart.cart == (Object)null) && !((Object)(object)item == (Object)null) && IsHostOrSingleplayer() && !EnemyInCartKillController.TryKill(item))
		{
			ShrinkCategory category = ShrinkCategory.Fallback;
			float factor = 1f;
			if (ModConfig.CartShrinkingEnabled.Value && TryGetShrinkData(item, out category, out factor))
			{
				TrackOrShrink(item, category, factor, inCart.cart);
			}
		}
	}

	internal static void MarkObjectsSeenInCart(PhysGrabCart cart, List<PhysGrabObject> items)
	{
		if (!IsHostOrSingleplayer() || items == null || TrackedObjects.Count == 0)
		{
			return;
		}
		float time = Time.time;
		int cartId = ((!((Object)(object)cart == (Object)null)) ? ((Object)cart).GetInstanceID() : 0);
		for (int i = 0; i < items.Count; i++)
		{
			PhysGrabObject val = items[i];
			GameObject val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).gameObject);
			if (!((Object)(object)val2 == (Object)null) && TrackedObjects.TryGetValue(((Object)val2).GetInstanceID(), out var value))
			{
				MarkTrackedInCart(value, time, cartId);
			}
		}
	}

	internal static void Tick()
	{
		if (!IsHostOrSingleplayer())
		{
			return;
		}
		float time = Time.time;
		if (time < _nextTickTime && time < _nextRestoreCheckTime && time < _nextCooldownCheckTime)
		{
			return;
		}
		_nextTickTime = time + GetCurrentTickInterval();
		if (!ModConfig.CartShrinkingEnabled.Value)
		{
			RestoreAll();
			ClearExpiredCooldowns(time);
			return;
		}
		if (TrackedObjects.Count == 0)
		{
			ClearExpiredCooldowns(time);
			_nextRestoreCheckTime = float.PositiveInfinity;
			return;
		}
		ClearExpiredCooldowns(time);
		if (time < _nextRestoreCheckTime)
		{
			return;
		}
		RestoreIds.Clear();
		float num = float.PositiveInfinity;
		foreach (KeyValuePair<int, TrackedObject> trackedObject in TrackedObjects)
		{
			TrackedObject value = trackedObject.Value;
			bool flag = (Object)(object)value.Target != (Object)null && IsTrackedEquipped(value.Target);
			if ((Object)(object)value.Target == (Object)null || flag || time >= value.RestoreCheckDueTime)
			{
				if (flag)
				{
					DebugLog("Restoring tracked equippable before equipped use: " + ((Object)value.Target).name);
				}
				RestoreIds.Add(trackedObject.Key);
			}
			else if (value.RestoreCheckDueTime < num)
			{
				num = value.RestoreCheckDueTime;
			}
		}
		for (int i = 0; i < RestoreIds.Count; i++)
		{
			int num2 = RestoreIds[i];
			if (TrackedObjects.TryGetValue(num2, out var value2))
			{
				RestoreTrackedObject(num2, value2.Target);
				TrackedObjects.Remove(num2);
			}
		}
		_nextRestoreCheckTime = ((TrackedObjects.Count == 0) ? float.PositiveInfinity : num);
	}

	internal static void RestoreAll()
	{
		if (TrackedObjects.Count == 0)
		{
			return;
		}
		RestoreTargets.Clear();
		foreach (TrackedObject value in TrackedObjects.Values)
		{
			if ((Object)(object)value.Target != (Object)null)
			{
				RestoreTargets.Add(value.Target);
			}
		}
		TrackedObjects.Clear();
		_nextRestoreCheckTime = float.PositiveInfinity;
		for (int i = 0; i < RestoreTargets.Count; i++)
		{
			RestoreTrackedObject(((Object)RestoreTargets[i]).GetInstanceID(), RestoreTargets[i]);
		}
		RestoreTargets.Clear();
	}

	private static float GetCurrentTickInterval()
	{
		float num = ModConfig.SafeMinimumItemScanIntervalSeconds();
		if (!ModConfig.DynamicItemScanEnabledValue())
		{
			return num;
		}
		float num2 = ModConfig.SafeMaximumItemScanIntervalSeconds();
		int count = TrackedObjects.Count;
		float num3 = ((count <= 0) ? num2 : ((count <= 6) ? num : ((count <= 15) ? 0.35f : ((count > 30) ? num2 : 0.75f))));
		return Mathf.Clamp(num3, num, num2);
	}

	private static void TrackOrShrink(PhysGrabObject item, ShrinkCategory category, float factor, PhysGrabCart cart)
	{
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = (((Object)(object)item == (Object)null) ? null : ((Component)item).gameObject);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)val).GetInstanceID();
		float time = Time.time;
		if (TrackedObjects.TryGetValue(instanceID, out var value))
		{
			MarkTrackedInCart(value, time, (!((Object)(object)cart == (Object)null)) ? ((Object)cart).GetInstanceID() : 0);
			value.Category = category;
		}
		else
		{
			if (IsInReshrinkCooldown(instanceID) || ScaleManager.IsScaled(val))
			{
				return;
			}
			if (category == ShrinkCategory.ValuableBox && !ValuableBoxScaleAdapter.EnsureController(val))
			{
				DebugLog("Prepared token/cosmetic box controller, waiting for ScalerCore initialization: " + ((Object)val).name + " kind=" + ValuableBoxScaleAdapter.DescribeSpecialBox(item));
				return;
			}
			ScaleOptions @default = ScaleOptions.Default;
			@default.Factor = factor;
			@default.Speed = ModConfig.SafeScaleSpeed();
			@default.Duration = 0f;
			@default.AllowedTargets = (ScaleTargets)((category == ShrinkCategory.ValuableBox) ? 15 : 12);
			@default.SuppressValueDropExpand = ModConfig.SuppressValuableDamageRestore.Value;
			@default.PreserveMass = ModConfig.ShouldPreserveMass();
			@default.RestoreSpeed = ModConfig.SafeRestoreScaleSpeed();
			@default.SuppressImpactFlash = true;
			@default.SuppressCameraShake = true;
			try
			{
				if (!ScaleManager.ApplyIfNotScaled(val, @default))
				{
					if (category == ShrinkCategory.ValuableBox)
					{
						DebugLog("ScalerCore rejected token/cosmetic box shrink for " + ((Object)val).name + " kind=" + ValuableBoxScaleAdapter.DescribeSpecialBox(item) + " controller=" + ((Object)(object)ScaleManager.GetController(val) != (Object)null));
					}
					return;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to shrink " + ((Object)val).name + ": " + ex.Message));
				return;
			}
			float num = time + ModConfig.SafeCartLeaveDebounceSeconds();
			TrackedObjects[instanceID] = new TrackedObject
			{
				Target = val,
				LastSeenInCartTime = time,
				RestoreCheckDueTime = num,
				LastSeenCartId = ((!((Object)(object)cart == (Object)null)) ? ((Object)cart).GetInstanceID() : 0),
				MarkedInCartThisPass = true,
				Category = category
			};
			ScheduleRestoreCheck(num);
			DebugLog(string.Concat("Shrunk ", ((Object)val).name, " as ", category, " factor=", factor.ToString("0.###")));
		}
	}

	private static void MarkTrackedInCart(TrackedObject tracked, float now, int cartId)
	{
		if (tracked != null)
		{
			tracked.LastSeenInCartTime = now;
			tracked.RestoreCheckDueTime = now + ModConfig.SafeCartLeaveDebounceSeconds();
			tracked.LastSeenCartId = cartId;
			tracked.MarkedInCartThisPass = true;
			ScheduleRestoreCheck(tracked.RestoreCheckDueTime);
		}
	}

	private static void ScheduleRestoreCheck(float dueTime)
	{
		if (dueTime < _nextRestoreCheckTime)
		{
			_nextRestoreCheckTime = dueTime;
		}
	}

	private static void RestoreTrackedObject(int id, GameObject target)
	{
		if ((Object)(object)target == (Object)null)
		{
			return;
		}
		BeginReshrinkCooldown(id);
		try
		{
			if (ScaleManager.IsScaled(target))
			{
				RefreshRestoreOptions(target);
				ScaleManager.Restore(target);
				DebugLog("Restored " + ((Object)target).name + " speed=" + ModConfig.SafeRestoreScaleSpeed().ToString("0.###"));
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Failed to restore " + ((Object)target).name + ": " + ex.Message));
		}
	}

	private static void RefreshRestoreOptions(GameObject target)
	{
		//IL_001a: 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)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		ScaleController controller = ScaleManager.GetController(target);
		if (!((Object)(object)controller == (Object)null) && controller.IsScaled)
		{
			ScaleOptions currentOptions = controller.CurrentOptions;
			currentOptions.RestoreSpeed = ModConfig.SafeRestoreScaleSpeed();
			currentOptions.SuppressImpactFlash = true;
			currentOptions.SuppressCameraShake = true;
			ScaleManager.UpdateOptions(target, currentOptions);
		}
	}

	private static bool IsTrackedEquipped(GameObject target)
	{
		if ((Object)(object)target == (Object)null)
		{
			return false;
		}
		ItemEquippable component = target.GetComponent<ItemEquippable>();
		if ((Object)(object)component != (Object)null)
		{
			return component.IsEquipped();
		}
		return false;
	}

	private static bool TryGetShrinkData(PhysGrabObject item, out ShrinkCategory category, out float factor)
	{
		category = ShrinkCategory.Fallback;
		factor = 1f;
		if (!PassesFastCandidateChecks(item))
		{
			return false;
		}
		int instanceID = ((Object)((Component)item).gameObject).GetInstanceID();
		if (IsInReshrinkCooldown(instanceID))
		{
			return false;
		}
		if (ShrinkDataCache.TryGetValue(instanceID, out var value) && value.ConfigVersion == ModConfig.ScalingConfigVersion)
		{
			category = value.Category;
			factor = value.Factor;
			return value.CanShrink;
		}
		bool flag = ResolveShrinkData(item, out category, out factor);
		ShrinkDataCache[instanceID] = new CachedShrinkData
		{
			ConfigVersion = ModConfig.ScalingConfigVersion,
			CanShrink = flag,
			Category = category,
			Factor = factor
		};
		return flag;
	}

	private static bool PassesFastCandidateChecks(PhysGrabObject item)
	{
		if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null)
		{
			return false;
		}
		if (item.dead)
		{
			return false;
		}
		int instanceID = ((Object)((Component)item).gameObject).GetInstanceID();
		if (PermanentlyExcludedObjectIds.Contains(instanceID))
		{
			return false;
		}
		if (CartObjectGuard.IsCartLike(item))
		{
			PermanentlyExcludedObjectIds.Add(instanceID);
			return false;
		}
		string cleanName = CleanName(((Object)item).name);
		if (IsPermanentlyExcludedCartItem(item, cleanName))
		{
			PermanentlyExcludedObjectIds.Add(instanceID);
			return false;
		}
		ItemEquippable component = ((Component)item).GetComponent<ItemEquippable>();
		if ((Object)(object)component != (Object)null && component.IsEquipped())
		{
			return false;
		}
		if ((Object)(object)item.rb != (Object)null && item.rb.isKinematic)
		{
			return false;
		}
		return true;
	}

	private static bool ResolveShrinkData(PhysGrabObject item, out ShrinkCategory category, out float factor)
	{
		category = ShrinkCategory.Fallback;
		factor = 1f;
		string cleanName = CleanName(((Object)item).name);
		if (!TryResolveCategory(item, cleanName, out category))
		{
			if (IsShopPlayerItem(item))
			{
				if (!ModConfig.ShrinkShopPlayerItems.Value)
				{
					return false;
				}
				category = ShrinkCategory.Fallback;
				return ModConfig.TryGetScaleFactor(category, out factor);
			}
			return false;
		}
		return ModConfig.TryGetScaleFactor(category, out factor);
	}

	private static bool IsPermanentlyExcludedCartItem(PhysGrabObject item, string cleanName)
	{
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Invalid comparison between Unknown and I4
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Invalid comparison between Unknown and I4
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Invalid comparison between Unknown and I4
		PhysGrabCart component = ((Component)item).GetComponent<PhysGrabCart>();
		if ((Object)(object)component != (Object)null)
		{
			return true;
		}
		component = ((Component)item).GetComponentInParent<PhysGrabCart>();
		if ((Object)(object)component != (Object)null && IsCartRootPhysObject(component, item))
		{
			return true;
		}
		if ((Object)(object)((Component)item).GetComponent<ItemVehicle>() != (Object)null || (Object)(object)((Component)item).GetComponentInParent<ItemVehicle>() != (Object)null)
		{
			return true;
		}
		if ((Object)(object)((Component)item).GetComponent<ItemCartCannon>() != (Object)null || (Object)(object)((Component)item).GetComponent<ItemCartCannonMain>() != (Object)null || (Object)(object)((Component)item).GetComponent<ItemCartLaser>() != (Object)null || (Object)(object)((Component)item).GetComponentInParent<ItemCartCannon>() != (Object)null || (Object)(object)((Component)item).GetComponentInParent<ItemCartCannonMain>() != (Object)null || (Object)(object)((Component)item).GetComponentInParent<ItemCartLaser>() != (Object)null)
		{
			return true;
		}
		if (cleanName == "Item Cart Cannon" || cleanName == "Item Cart Laser")
		{
			return true;
		}
		ItemAttributes component2 = ((Component)item).GetComponent<ItemAttributes>();
		if ((Object)(object)component2 == (Object)null)
		{
			return false;
		}
		if (!TryGetItemType(component2, out var itemType))
		{
			return false;
		}
		if ((int)itemType != 2 && (int)itemType != 14)
		{
			return (int)itemType == 12;
		}
		return true;
	}

	private static bool IsCartRootPhysObject(PhysGrabCart cart, PhysGrabObject item)
	{
		if ((Object)(object)cart == (Object)null || (Object)(object)item == (Object)null || PhysGrabCartPhysGrabObjectField == null)
		{
			return false;
		}
		object? value = PhysGrabCartPhysGrabObjectField.GetValue(cart);
		return (Object)((value is PhysGrabObject) ? value : null) == (Object)(object)item;
	}

	private static bool IsShopPlayerItem(PhysGrabObject item)
	{
		ItemAttributes component = ((Component)item).GetComponent<ItemAttributes>();
		if ((Object)(object)component != (Object)null)
		{
			return true;
		}
		ItemEquippable component2 = ((Component)item).GetComponent<ItemEquippable>();
		if ((Object)(object)component2 != (Object)null)
		{
			return true;
		}
		if (TryGetIsGun(item))
		{
			return true;
		}
		return (Object)(object)((Component)item).GetComponent<ItemBattery>() != (Object)null;
	}

	private static bool TryGetItemType(ItemAttributes attributes, out itemType itemType)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected I4, but got Unknown
		itemType = (itemType)0;
		if ((Object)(object)attributes == (Object)null || ItemAttributesItemTypeField == null)
		{
			return false;
		}
		object value = ItemAttributesItemTypeField.GetValue(attributes);
		if (!(value is itemType))
		{
			return false;
		}
		itemType = (itemType)(int)(itemType)value;
		return true;
	}

	private static bool TryGetIsGun(PhysGrabObject item)
	{
		if ((Object)(object)item == (Object)null || PhysGrabObjectIsGunField == null)
		{
			return false;
		}
		object value = PhysGrabObjectIsGunField.GetValue(item);
		if (value is bool)
		{
			return (bool)value;
		}
		return false;
	}

	private static bool TryResolveCategory(PhysGrabObject item, string cleanName, out ShrinkCategory category)
	{
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		category = ShrinkCategory.Fallback;
		if ((Object)(object)((Component)item).GetComponent<SurplusValuable>() != (Object)null)
		{
			category = ShrinkCategory.Surplus;
			return true;
		}
		if (ValuableBoxScaleAdapter.IsValuableBox(item))
		{
			category = ShrinkCategory.ValuableBox;
			DebugLog("Resolved token/cosmetic box category for " + ((Object)item).name + " kind=" + ValuableBoxScaleAdapter.DescribeSpecialBox(item));
			return true;
		}
		if (TryResolveEnemyOrb(cleanName, out category))
		{
			return true;
		}
		ValuableObject component = ((Component)item).GetComponent<ValuableObject>();
		if ((Object)(object)component == (Object)null)
		{
			return false;
		}
		category = FromVolumeType(component.volumeType);
		return true;
	}

	private static ShrinkCategory FromVolumeType(Type volumeType)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected I4, but got Unknown
		return (int)volumeType switch
		{
			0 => ShrinkCategory.Tiny, 
			1 => ShrinkCategory.Small, 
			2 => ShrinkCategory.Medium, 
			3 => ShrinkCategory.Big, 
			4 => ShrinkCategory.Wide, 
			5 => ShrinkCategory.Tall, 
			6 => ShrinkCategory.VeryTall, 
			_ => ShrinkCategory.Fallback, 
		};
	}

	private static bool TryResolveEnemyOrb(string cleanName, out ShrinkCategory category)
	{
		category = ShrinkCategory.Fallback;
		if (string.IsNullOrEmpty(cleanName))
		{
			return false;
		}
		if (!cleanName.StartsWith("Enemy", StringComparison.OrdinalIgnoreCase))
		{
			return false;
		}
		string[] array = cleanName.Split(new char[1] { '-' });
		if (array.Length < 2)
		{
			return false;
		}
		string text = array[1].Trim();
		if (text.Equals("Small", StringComparison.OrdinalIgnoreCase))
		{
			category = ShrinkCategory.EnemyOrbSmall;
			return true;
		}
		if (text.Equals("Medium", StringComparison.OrdinalIgnoreCase))
		{
			category = ShrinkCategory.EnemyOrbMedium;
			return true;
		}
		if (text.Equals("Big", StringComparison.OrdinalIgnoreCase))
		{
			category = ShrinkCategory.EnemyOrbBig;
			return true;
		}
		if (text.Equals("Berserker", StringComparison.OrdinalIgnoreCase))
		{
			category = ShrinkCategory.EnemyOrbBerserker;
			return true;
		}
		return false;
	}

	private static void BeginReshrinkCooldown(int id)
	{
		float num = Time.time + ModConfig.SafeReshrinkCooldownSeconds();
		ReshrinkCooldownUntil[id] = num;
		if (num < _nextCooldownCheckTime)
		{
			_nextCooldownCheckTime = num;
		}
	}

	private static bool IsInReshrinkCooldown(int id)
	{
		if (!ReshrinkCooldownUntil.TryGetValue(id, out var value))
		{
			return false;
		}
		if (Time.time < value)
		{
			return true;
		}
		ReshrinkCooldownUntil.Remove(id);
		return false;
	}

	private static void ClearExpiredCooldowns(float now)
	{
		if (ReshrinkCooldownUntil.Count == 0)
		{
			_nextCooldownCheckTime = float.PositiveInfinity;
		}
		else
		{
			if (now < _nextCooldownCheckTime)
			{
				return;
			}
			ExpiredCooldownIds.Clear();
			float num = float.PositiveInfinity;
			foreach (KeyValuePair<int, float> item in ReshrinkCooldownUntil)
			{
				if (now >= item.Value)
				{
					ExpiredCooldownIds.Add(item.Key);
				}
				else if (item.Value < num)
				{
					num = item.Value;
				}
			}
			for (int i = 0; i < ExpiredCooldownIds.Count; i++)
			{
				ReshrinkCooldownUntil.Remove(ExpiredCooldownIds[i]);
			}
			ExpiredCooldownIds.Clear();
			_nextCooldownCheckTime = ((ReshrinkCooldownUntil.Count == 0) ? float.PositiveInfinity : num);
		}
	}

	private static string CleanName(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return string.Empty;
		}
		return name.Replace("Valuable ", string.Empty).Replace("(Clone)", string.Empty).Trim();
	}

	private static bool IsHostOrSingleplayer()
	{
		return Authority.IsHostOrSingleplayer();
	}

	private static void DebugLog(string message)
	{
		if (ModConfig.DebugLogging.Value)
		{
			Plugin.Log.LogInfo((object)message);
		}
	}
}
[HarmonyPatch(typeof(PhysGrabInCart), "Add")]
internal static class PhysGrabInCartAddPatch
{
	private static bool Prefix(PhysGrabInCart __instance, PhysGrabObject _physGrabObject)
	{
		if (!Authority.IsHostOrSingleplayer())
		{
			return true;
		}
		if (CartObjectGuard.ShouldBlockCartInCart(__instance, _physGrabObject))
		{
			CartRegistry.HandleBlockedCartInCart(__instance, _physGrabObject);
			return false;
		}
		return true;
	}

	private static void Postfix(PhysGrabInCart __instance, PhysGrabObject _physGrabObject)
	{
		ShrinkerCartController.ProcessCartObject(__instance, _physGrabObject);
	}
}
[HarmonyPatch(typeof(PhysGrabCart), "Start")]
internal static class PhysGrabCartStartPatch
{
	private static void Postfix(PhysGrabCart __instance)
	{
		CartRegistry.RegisterCart(__instance);
		if (ModConfig.PlayerScalingEnabled())
		{
			PlayerCartScaleController.RegisterCart(__instance);
		}
	}
}
[HarmonyPatch(typeof(PhysGrabCart), "ObjectsInCart")]
internal static class PhysGrabCartObjectsInCartPatch
{
	private static void Postfix(PhysGrabCart __instance)
	{
		CartRegistry.CleanCartContents(__instance);
	}
}
[HarmonyPatch(typeof(RunManager), "ChangeLevel")]
internal static class RunManagerChangeLevelPatch
{
	private static void Prefix()
	{
		ShrinkerCartController.RestoreAll();
		PlayerCartScaleController.RestoreAll();
		PlayerCartScaleController.Reset();
		CartRegistry.Reset();
		ValuableBoxScaleAdapter.Reset();
		EnemyInCartKillController.Reset();
		HostConfigSync.Reset();
	}
}
internal static class ValuableBoxScaleAdapter
{
	private sealed class ValuableBoxHandler : IScaleHandler
	{
		public void Setup(ScaleController ctrl)
		{
		}

		public void OnScale(ScaleController ctrl)
		{
		}

		public void OnRestore(ScaleController ctrl, bool isBonk)
		{
		}

		public void OnUpdate(ScaleController ctrl)
		{
		}

		public void OnLateUpdate(ScaleController ctrl)
		{
		}

		public void OnDestroy(ScaleController ctrl)
		{
		}
	}

	private const int HandlerPriority = -10;

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

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

	private static bool _registered;

	internal static void Reset()
	{
		ValuableBoxObjectIds.Clear();
		NonValuableBoxObjectIds.Clear();
	}

	internal static void RegisterHandler()
	{
		if (!_registered)
		{
			ScaleHandlerRegistry.Register((IScaleHandler)(object)new ValuableBoxHandler(), (Func<GameObject, bool>)IsValuableBoxScaleTarget, -10);
			_registered = true;
		}
	}

	internal static bool IsValuableBox(PhysGrabObject item)
	{
		if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null)
		{
			return false;
		}
		int instanceID = ((Object)((Component)item).gameObject).GetInstanceID();
		if (ValuableBoxObjectIds.Contains(instanceID))
		{
			return true;
		}
		if (NonValuableBoxObjectIds.Contains(instanceID))
		{
			return false;
		}
		bool flag = (Object)(object)FindCosmeticWorldObject(item) != (Object)null || (Object)(object)FindValuableBox(item) != (Object)null;
		if (flag)
		{
			ValuableBoxObjectIds.Add(instanceID);
		}
		else
		{
			NonValuableBoxObjectIds.Add(instanceID);
		}
		return flag;
	}

	internal static bool EnsureController(GameObject target)
	{
		if ((Object)(object)target == (Object)null)
		{
			return false;
		}
		if ((Object)(object)target.GetComponent<ScaleController>() != (Object)null)
		{
			return true;
		}
		if ((Object)(object)target.GetComponent<CosmeticWorldObject>() != (Object)null || (Object)(object)target.GetComponentInParent<CosmeticWorldObject>() != (Object)null || (Object)(object)target.GetComponentInChildren<CosmeticWorldObject>(true) != (Object)null)
		{
			DebugLog("Token/cosmetic box is waiting for ScalerCore cosmetic controller: " + ((Object)target).name);
			return false;
		}
		if (!IsValuableBoxScaleTarget(target))
		{
			return false;
		}
		target.AddComponent<ScaleController>();
		DebugLog("Attached ScalerCore controller to ItemValuableBox token box: " + ((Object)target).name);
		return false;
	}

	internal static void EnsureController(ItemValuableBox box)
	{
		PhysGrabObject val = FindOwnerPhysGrabObject(box);
		if ((Object)(object)val != (Object)null)
		{
			EnsureController(((Component)val).gameObject);
		}
	}

	private static bool IsValuableBoxScaleTarget(GameObject target)
	{
		if ((Object)(object)target == (Object)null)
		{
			return false;
		}
		PhysGrabObject component = target.GetComponent<PhysGrabObject>();
		if ((Object)(object)component == (Object)null)
		{
			return false;
		}
		ItemValuableBox val = FindValuableBox(component);
		if ((Object)(object)val != (Object)null)
		{
			return (Object)(object)FindOwnerPhysGrabObject(val) == (Object)(object)component;
		}
		return false;
	}

	internal static string DescribeSpecialBox(PhysGrabObject item)
	{
		if ((Object)(object)FindCosmeticWorldObject(item) != (Object)null)
		{
			return "CosmeticWorldObject";
		}
		if ((Object)(object)FindValuableBox(item) != (Object)null)
		{
			return "ItemValuableBox";
		}
		return "none";
	}

	private static CosmeticWorldObject FindCosmeticWorldObject(PhysGrabObject item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return null;
		}
		CosmeticWorldObject component = ((Component)item).GetComponent<CosmeticWorldObject>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		component = ((Component)item).GetComponentInParent<CosmeticWorldObject>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		return ((Component)item).GetComponentInChildren<CosmeticWorldObject>(true);
	}

	private static ItemValuableBox FindValuableBox(PhysGrabObject item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return null;
		}
		ItemValuableBox component = ((Component)item).GetComponent<ItemValuableBox>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		component = ((Component)item).GetComponentInParent<ItemValuableBox>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		return ((Component)item).GetComponentInChildren<ItemValuableBox>(true);
	}

	private static PhysGrabObject FindOwnerPhysGrabObject(ItemValuableBox box)
	{
		if ((Object)(object)box == (Object)null)
		{
			return null;
		}
		PhysGrabObject component = ((Component)box).GetComponent<PhysGrabObject>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		component = ((Component)box).GetComponentInParent<PhysGrabObject>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		return ((Component)box).GetComponentInChildren<PhysGrabObject>(true);
	}

	private static void DebugLog(string message)
	{
		if (ModConfig.DebugLogging != null && ModConfig.DebugLogging.Value)
		{
			Plugin.Log.LogInfo((object)message);
		}
	}
}
[HarmonyPatch(typeof(ItemValuableBox), "Start")]
internal static class ItemValuableBoxStartPatch
{
	private static void Postfix(ItemValuableBox __instance)
	{
		if ((Object)(object)__instance != (Object)null)
		{
			ValuableBoxScaleAdapter.EnsureController(__instance);
		}
	}
}
[HarmonyPatch(typeof(PhysGrabObject), "Start")]
internal static class PhysGrabObjectStartValuableBoxPatch
{
	private static void Postfix(PhysGrabObject __instance)
	{
		if ((Object)(object)__instance != (Object)null)
		{
			ValuableBoxScaleAdapter.EnsureController(((Component)__instance).gameObject);
		}
	}
}