Decompiled source of PlayerTradingChest v1.0.2

marchiori.playertradingchest.dll

Decompiled 20 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Marchiori.PlayerTradingChest.Configuration;
using Marchiori.PlayerTradingChest.Rules;
using Marchiori.PlayerTradingChest.ValheimData;
using Marchiori.Utils.Localization;
using Marchiori.Utils.Notificator;
using Marchiori.Utils.SignTextManager;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("marchiori.playertradingchest")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ee52b2bfcab53d7e96836822c3d6ec6f3c6f91ae")]
[assembly: AssemblyProduct("marchiori.playertradingchest")]
[assembly: AssemblyTitle("marchiori.playertradingchest")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Marchiori.PlayerTradingChest
{
	[BepInPlugin("marchiori.playertradingchest", "Player Trading Chest", "1.0.2")]
	public sealed class BepinexPlugin : BaseUnityPlugin
	{
		public const string Guid = "marchiori.playertradingchest";

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Load(((BaseUnityPlugin)this).Config);
			new Harmony("marchiori.playertradingchest").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Player Trading Chest loaded.");
		}
	}
}
namespace Marchiori.PlayerTradingChest.ValheimPatches
{
	[HarmonyPatch(typeof(Container), "GetHoverText")]
	internal static class Container_GetHoverText_Patch
	{
		private static bool Prefix(Container __instance, ref string __result)
		{
			if (!ShopLink.IsLinked(((Component)__instance).gameObject))
			{
				return true;
			}
			__result = ((Localization.instance != null) ? Localization.instance.Localize("$ptc_22") : "Interact with the sign to perform the transaction");
			return false;
		}
	}
	[HarmonyPatch(typeof(Container), "Interact")]
	internal static class Container_Interact_Patch
	{
		private static bool Prefix(Container __instance, Humanoid character, bool hold, ref bool __result)
		{
			if (hold || !ShopLink.IsLinked(((Component)__instance).gameObject))
			{
				return true;
			}
			Player player = (Player)(object)((character is Player) ? character : null);
			if (ShopAccess.MayOpen(player, __instance))
			{
				return true;
			}
			ShopMessages.Show(player, "$ptc_11");
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Container), "SetInUse")]
	internal static class Container_SetInUse_Patch
	{
		private static void Postfix(Container __instance, bool inUse)
		{
			ShopState.SetOpen(__instance, inUse);
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	internal static class InventoryGrid_UpdateGui_Patch
	{
		private static void Postfix(InventoryGrid __instance)
		{
			SlotTint.Apply(__instance);
		}
	}
	[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
	internal static class Inventory_AddItem_Patch
	{
		private static bool Prefix(Inventory __instance, ItemData item, ref bool __result)
		{
			return !ShopInventory.TryRedirect(__instance, item, ref __result);
		}
	}
	[HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[]
	{
		typeof(ItemData),
		typeof(int)
	})]
	internal static class Inventory_CanAddItem_Item_Patch
	{
		private static bool Prefix(Inventory __instance, ItemData item, int stack, ref bool __result)
		{
			if ((Object)(object)ShopLink.FindChest(__instance) == (Object)null)
			{
				return true;
			}
			__result = ShopInventory.CanAccept(__instance, item, stack);
			return false;
		}
	}
	[HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[]
	{
		typeof(GameObject),
		typeof(int)
	})]
	internal static class Inventory_CanAddItem_Prefab_Patch
	{
		private static bool Prefix(Inventory __instance, GameObject prefab, int stack, ref bool __result)
		{
			if ((Object)(object)ShopLink.FindChest(__instance) == (Object)null)
			{
				return true;
			}
			__result = ShopInventory.CanAcceptPrefab(__instance, prefab, stack);
			return false;
		}
	}
	[HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[]
	{
		typeof(Inventory),
		typeof(ItemData),
		typeof(int),
		typeof(int),
		typeof(int)
	})]
	internal static class Inventory_MoveItemAmount_Patch
	{
		private static int _before;

		private static int _index = -1;

		private static bool Prefix(Inventory __instance, ItemData item, int x, int y, ref bool __result)
		{
			_index = -1;
			if ((Object)(object)ShopLink.FindChest(__instance) == (Object)null)
			{
				return true;
			}
			int width = __instance.GetWidth();
			int index = ((width > 0) ? (y * width + x) : (-1));
			StackState[] slots = ShopInventory.ReadChest(__instance);
			if (!ShopRules.MayPlace(slots, index, ShopInventory.FromItem(item), ShopRules.WithdrawOnly(ModConfig.Enable, hasSign: true, slots)))
			{
				__result = false;
				return false;
			}
			_index = index;
			_before = ShopInventory.StackAt(__instance, x, y);
			return true;
		}

		private static void Postfix(Inventory __instance)
		{
			if (_index >= 0)
			{
				int index = _index;
				int before = _before;
				_index = -1;
				ShopInventory.Touch(__instance, index, before);
			}
		}
	}
	[HarmonyPatch(typeof(Inventory))]
	internal static class Inventory_RemoveItem_Patch
	{
		[HarmonyPatch("RemoveItem", new Type[]
		{
			typeof(ItemData),
			typeof(int)
		})]
		[HarmonyPostfix]
		private static void ByAmount(Inventory __instance)
		{
			ShopInventory.Changed(__instance);
		}

		[HarmonyPatch("RemoveItem", new Type[] { typeof(ItemData) })]
		[HarmonyPostfix]
		private static void Whole(Inventory __instance)
		{
			ShopInventory.Changed(__instance);
		}

		[HarmonyPatch("RemoveItem", new Type[] { typeof(int) })]
		[HarmonyPostfix]
		private static void ByIndex(Inventory __instance)
		{
			ShopInventory.Changed(__instance);
		}
	}
	[HarmonyPatch(typeof(Localization), "SetupLanguage")]
	internal static class Localization_SetupLanguage_Patch
	{
		private static void Postfix(Localization __instance)
		{
			Localization.OnLanguageChange = (Action)Delegate.Remove(Localization.OnLanguageChange, new Action(OnLanguageChanged));
			Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, new Action(OnLanguageChanged));
			Apply(__instance, __instance.GetSelectedLanguage());
		}

		private static void OnLanguageChanged()
		{
			if (Localization.instance != null)
			{
				Apply(Localization.instance, Localization.instance.GetSelectedLanguage());
			}
		}

		private static void Apply(Localization localization, string language)
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			LanguageFiles.Apply(localization, language, directoryName, "ptc");
			ShopSign.RefreshAll();
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDB_Awake_Patch
	{
		private static void Postfix(ObjectDB __instance)
		{
			GemPrefabs.RegisterItems(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "CheckCanRemovePiece")]
	internal static class Player_CheckCanRemovePiece_Patch
	{
		private static bool Prefix(Player __instance, Piece piece, ref bool __result)
		{
			if ((Object)(object)piece == (Object)null || !ShopLink.IsLinked(((Component)piece).gameObject))
			{
				return true;
			}
			__result = ShopAccess.MayBreak(__instance, (Component)(object)piece);
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "RemovePiece")]
	internal static class Player_RemovePiece_Patch
	{
		private static bool Prefix(Player __instance, ref bool __result)
		{
			Piece hoveringPiece = __instance.GetHoveringPiece();
			if ((Object)(object)hoveringPiece == (Object)null || !ShopLink.IsLinked(((Component)hoveringPiece).gameObject))
			{
				return true;
			}
			if (ShopAccess.MayBreak(__instance, (Component)(object)hoveringPiece))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	internal static class Player_TryPlacePiece_Patch
	{
		private static bool Prefix(Player __instance, Piece piece, ref bool __result)
		{
			return ShopPlacement.TryHandle(__instance, piece, ref __result);
		}
	}
	[HarmonyPatch(typeof(Sign), "Interact")]
	internal static class Sign_Interact_Patch
	{
		private static bool Prefix(Sign __instance, Humanoid character, bool hold, ref bool __result)
		{
			if (!ShopLink.IsLinked(((Component)__instance).gameObject))
			{
				return true;
			}
			if (hold)
			{
				__result = false;
				return false;
			}
			Player player = (Player)(object)((character is Player) ? character : null);
			Container chest = ShopLink.ChestOf(((Component)__instance).gameObject);
			__result = ShopTrade.Try(player, chest);
			return false;
		}
	}
	[HarmonyPatch(typeof(Sign), "UseItem")]
	internal static class Sign_UseItem_Patch
	{
		private static bool Prefix(Sign __instance, ref bool __result)
		{
			if (!ShopLink.IsLinked(((Component)__instance).gameObject))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(StoreGui), "GetSellableItem")]
	internal static class StoreGui_GetSellableItem_Patch
	{
		private static void Postfix(StoreGui __instance, ref ItemData __result)
		{
			if (HaldorStock.BlocksSale(__instance, __result))
			{
				__result = null;
			}
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
	internal static class TeleportWorld_Teleport_Patch
	{
		private static void Prefix(Player player, ref bool __state)
		{
			__state = (Object)(object)player != (Object)null && ((Character)player).IsTeleporting();
		}

		private static void Postfix(Player player, bool __state)
		{
			if (!((Object)(object)player == (Object)null || __state) && ((Character)player).IsTeleporting())
			{
				GemPortal.Apply(player);
			}
		}
	}
	[HarmonyPatch(typeof(Trader), "GetAvailableItems")]
	internal static class Trader_GetAvailableItems_Patch
	{
		private static void Postfix(Trader __instance, List<TradeItem> __result)
		{
			HaldorStock.Append(__instance, __result);
		}
	}
	[HarmonyPatch(typeof(WearNTear), "Destroy")]
	internal static class WearNTear_Destroy_Patch
	{
		private static void Prefix(WearNTear __instance)
		{
			ShopBreak.OnDestroying(__instance);
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetScene_Awake_Patch
	{
		private static void Postfix(ZNetScene __instance)
		{
			GemPrefabs.RegisterDrops(__instance);
		}
	}
	[HarmonyPatch(typeof(ZNetView), "Awake")]
	internal static class ZNetView_Awake_Patch
	{
		private static void Postfix(ZNetView __instance)
		{
			if ((Object)(object)__instance == (Object)null || !__instance.IsValid())
			{
				return;
			}
			ZDO zDO = __instance.GetZDO();
			if (zDO != null && zDO.GetLong("ptc_link", 0L) != 0)
			{
				if ((Object)(object)((Component)__instance).GetComponent<ShopWatch>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<ShopWatch>();
				}
				ShopLink.Register(((Component)__instance).gameObject);
			}
		}
	}
}
namespace Marchiori.PlayerTradingChest.ValheimData
{
	internal static class EnglishItems
	{
		private static readonly FieldInfo SettingsField = AccessTools.Field(typeof(Localization), "m_localizationSettings");

		private static Dictionary<string, string> _words;

		private static bool _ready;

		internal static string Name(string prefab)
		{
			string token = Token(prefab);
			string text = Word(token);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return prefab ?? "";
		}

		internal static string FromToken(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return "";
			}
			if (token.StartsWith("$", StringComparison.Ordinal))
			{
				token = token.Substring(1);
			}
			string text = Word(token);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return token;
		}

		private static string Token(string prefab)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || string.IsNullOrEmpty(prefab))
			{
				return "";
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
			ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null)
			{
				return "";
			}
			string text = val.m_itemData.m_shared.m_name ?? "";
			if (text.StartsWith("$", StringComparison.Ordinal))
			{
				return text.Substring(1);
			}
			return text;
		}

		private static string Word(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return "";
			}
			if (!_ready)
			{
				Dictionary<string, string> dictionary = Load();
				if (dictionary == null)
				{
					return "";
				}
				_words = dictionary;
				_ready = true;
			}
			if (_words != null && _words.TryGetValue(token, out var value))
			{
				return value;
			}
			return "";
		}

		private static Dictionary<string, string> Load()
		{
			Localization instance = Localization.instance;
			if (instance == null || SettingsField == null)
			{
				return null;
			}
			object? value = SettingsField.GetValue(instance);
			LocalizationSettings val = (LocalizationSettings)((value is LocalizationSettings) ? value : null);
			if ((Object)(object)val == (Object)null || val.Localizations == null)
			{
				return null;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			for (int i = 0; i < val.Localizations.Count; i++)
			{
				TextAsset val2 = val.Localizations[i];
				if ((Object)(object)val2 == (Object)null || string.IsNullOrEmpty(val2.text))
				{
					continue;
				}
				Dictionary<string, string> dictionary2 = EnglishSheet.Read(val2.text);
				foreach (KeyValuePair<string, string> item in dictionary2)
				{
					if (!dictionary.ContainsKey(item.Key))
					{
						dictionary[item.Key] = item.Value;
					}
				}
			}
			return dictionary;
		}
	}
	internal static class GemPortal
	{
		internal static void Apply(Player player)
		{
			if ((Object)(object)player == (Object)null || ((Humanoid)player).GetInventory() == null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<ItemData> list = new List<ItemData>(inventory.GetAllItems());
			int[] array = new int[GemCatalog.All.Length];
			for (int i = 0; i < list.Count; i++)
			{
				ItemData val = list[i];
				if (val == null || val.m_equipped || (Object)(object)val.m_dropPrefab == (Object)null)
				{
					continue;
				}
				string text = ShopRules.Normalize(((Object)val.m_dropPrefab).name);
				for (int j = 0; j < GemCatalog.All.Length; j++)
				{
					if (!(GemCatalog.All[j].PrefabName != text))
					{
						int num = ShopRules.PortalLoss(val.m_stack, GemCatalog.All[j].PortalLoss);
						if (num > 0)
						{
							inventory.RemoveItem(val, num);
							array[j] += num;
						}
						break;
					}
				}
			}
			for (int k = 0; k < array.Length; k++)
			{
				if (array[k] > 0)
				{
					ShopMessages.Show(player, "$ptc_19", array[k], -1, null, null, ShopMessages.PrefabName(GemCatalog.All[k].PrefabName));
				}
			}
		}
	}
	internal static class GemPrefabs
	{
		private const string RubyName = "Ruby";

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

		private static GameObject _holder;

		private static bool _logged;

		private static bool _warned;

		internal static void RegisterItems(ObjectDB database)
		{
			Ensure(database, ZNetScene.instance);
			AddToObjectDb(database);
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				AddToScene(ZNetScene.instance);
			}
			LogOnce();
		}

		internal static void RegisterDrops(ZNetScene scene)
		{
			Ensure(ObjectDB.instance, scene);
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				AddToObjectDb(ObjectDB.instance);
			}
			AddToScene(scene);
			LogOnce();
		}

		private static void Ensure(ObjectDB database, ZNetScene scene)
		{
			if (Prefabs.Count == GemCatalog.All.Length)
			{
				return;
			}
			GameObject val = FindRuby(database, scene);
			if ((Object)(object)val == (Object)null)
			{
				if (!_warned)
				{
					_warned = true;
					ManualLogSource log = BepinexPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"Ruby was not found, so Emerald, Sapphire, and Diamond were not created.");
					}
				}
				return;
			}
			GameObject holder = Holder();
			bool activeSelf = val.activeSelf;
			if (activeSelf)
			{
				val.SetActive(false);
			}
			try
			{
				GemDefinition[] all = GemCatalog.All;
				for (int i = 0; i < all.Length; i++)
				{
					if (!((Object)(object)FindPrefab(all[i].PrefabName) != (Object)null))
					{
						Create(val, holder, all[i]);
					}
				}
			}
			finally
			{
				if (activeSelf)
				{
					val.SetActive(true);
				}
			}
		}

		private static void Create(GameObject ruby, GameObject holder, GemDefinition gem)
		{
			GameObject val = null;
			try
			{
				val = Object.Instantiate<GameObject>(ruby, holder.transform, false);
				((Object)val).name = gem.PrefabName;
				Prepare(val, gem);
				val.SetActive(true);
				Prefabs.Add(val);
				val = null;
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				ManualLogSource log = BepinexPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not create " + gem.PrefabName + ". " + ex.Message));
				}
			}
		}

		private static void Prepare(GameObject clone, GemDefinition gem)
		{
			ItemDrop component = clone.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
			{
				throw new InvalidOperationException(gem.PrefabName + " has no item data.");
			}
			component.m_itemData = component.m_itemData.Clone();
			SharedData val = CopyShared(component.m_itemData.m_shared);
			val.m_name = gem.NameToken;
			val.m_description = "";
			val.m_value = gem.Value;
			val.m_weight = gem.Weight;
			val.m_maxStackSize = gem.StackSize;
			val.m_teleportable = true;
			component.m_itemData.m_shared = val;
			component.m_itemData.m_dropPrefab = clone;
			GemVisuals.Apply(val, clone, gem);
		}

		private static SharedData CopyShared(SharedData source)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			SharedData val = new SharedData();
			FieldInfo[] sharedDataFields = ValheimMembers.SharedDataFields;
			foreach (FieldInfo fieldInfo in sharedDataFields)
			{
				fieldInfo.SetValue(val, Detach(fieldInfo.GetValue(source)));
			}
			return val;
		}

		private static object Detach(object value)
		{
			if (value == null)
			{
				return null;
			}
			if (value is Array array)
			{
				return array.Clone();
			}
			if (!(value is IList list))
			{
				return value;
			}
			try
			{
				IList list2 = (IList)Activator.CreateInstance(list.GetType());
				for (int i = 0; i < list.Count; i++)
				{
					list2.Add(list[i]);
				}
				return list2;
			}
			catch (Exception)
			{
				return value;
			}
		}

		private static void AddToObjectDb(ObjectDB database)
		{
			if ((Object)(object)database == (Object)null || database.m_items == null || Prefabs.Count == 0)
			{
				return;
			}
			for (int i = 0; i < Prefabs.Count; i++)
			{
				GameObject val = Prefabs[i];
				if ((Object)(object)val != (Object)null && !database.m_items.Contains(val))
				{
					database.m_items.Add(val);
				}
			}
			ValheimMembers.RebuildItems(database);
		}

		private static void AddToScene(ZNetScene scene)
		{
			if ((Object)(object)scene == (Object)null || scene.m_prefabs == null || Prefabs.Count == 0)
			{
				return;
			}
			Dictionary<int, GameObject> dictionary = ValheimMembers.NamedPrefabs(scene);
			for (int i = 0; i < Prefabs.Count; i++)
			{
				GameObject val = Prefabs[i];
				if (!((Object)(object)val == (Object)null))
				{
					if (!scene.m_prefabs.Contains(val))
					{
						scene.m_prefabs.Add(val);
					}
					if (dictionary != null)
					{
						dictionary[scene.GetPrefabHash(val)] = val;
					}
				}
			}
		}

		private static GameObject FindRuby(ObjectDB database, ZNetScene scene)
		{
			if ((Object)(object)database != (Object)null)
			{
				GameObject itemPrefab = database.GetItemPrefab("Ruby");
				if ((Object)(object)itemPrefab != (Object)null)
				{
					return itemPrefab;
				}
				if (database.m_items != null)
				{
					for (int i = 0; i < database.m_items.Count; i++)
					{
						GameObject val = database.m_items[i];
						if ((Object)(object)val != (Object)null && ((Object)val).name == "Ruby")
						{
							return val;
						}
					}
				}
			}
			if ((Object)(object)scene != (Object)null && scene.m_prefabs != null)
			{
				for (int j = 0; j < scene.m_prefabs.Count; j++)
				{
					GameObject val2 = scene.m_prefabs[j];
					if ((Object)(object)val2 != (Object)null && ((Object)val2).name == "Ruby" && (Object)(object)val2.GetComponent<ItemDrop>() != (Object)null)
					{
						return val2;
					}
				}
			}
			return null;
		}

		private static GameObject FindPrefab(string name)
		{
			for (int i = 0; i < Prefabs.Count; i++)
			{
				GameObject val = Prefabs[i];
				if ((Object)(object)val != (Object)null && ((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}

		private static GameObject Holder()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if ((Object)(object)_holder != (Object)null)
			{
				return _holder;
			}
			_holder = new GameObject("playertradingchest gems");
			_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_holder);
			return _holder;
		}

		internal static void ApplyNumbers()
		{
			for (int i = 0; i < Prefabs.Count; i++)
			{
				GameObject val = Prefabs[i];
				if (!((Object)(object)val == (Object)null))
				{
					GemDefinition gemDefinition = GemCatalog.Find(((Object)val).name);
					ItemDrop component = val.GetComponent<ItemDrop>();
					if (gemDefinition != null && !((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null)
					{
						component.m_itemData.m_shared.m_value = gemDefinition.Value;
						component.m_itemData.m_shared.m_weight = gemDefinition.Weight;
						component.m_itemData.m_shared.m_maxStackSize = gemDefinition.StackSize;
					}
				}
			}
		}

		private static void LogOnce()
		{
			if (!_logged && Prefabs.Count == GemCatalog.All.Length)
			{
				_logged = true;
				ManualLogSource log = BepinexPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"Registered Emerald, Sapphire, and Diamond.");
				}
			}
		}
	}
	internal static class GemVisuals
	{
		private static readonly Dictionary<string, Texture2D> Cache = new Dictionary<string, Texture2D>();

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

		internal static void Apply(SharedData shared, GameObject root, GemDefinition gem)
		{
			if (shared == null || (Object)(object)root == (Object)null || gem == null)
			{
				return;
			}
			try
			{
				RecolorIcons(shared, gem);
				RecolorRenderers(root, gem);
			}
			catch (Exception ex)
			{
				ManualLogSource log = BepinexPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not recolor " + gem.PrefabName + ". It keeps Ruby's look. " + ex.Message));
				}
			}
		}

		private static void RecolorIcons(SharedData shared, GemDefinition gem)
		{
			Sprite[] icons = shared.m_icons;
			if (icons == null)
			{
				return;
			}
			for (int i = 0; i < icons.Length; i++)
			{
				Sprite val = RecolorSprite(icons[i], gem);
				if ((Object)(object)val != (Object)null)
				{
					icons[i] = val;
				}
			}
		}

		private static void RecolorRenderers(GameObject root, GemDefinition gem)
		{
			//IL_00ce: 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)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] materials = componentsInChildren[i].materials;
				foreach (Material val in materials)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					bool shifted = false;
					Texture mainTexture = val.mainTexture;
					if ((Object)(object)mainTexture != (Object)null)
					{
						Texture2D val2 = RecolorTexture(mainTexture, gem, out shifted);
						if ((Object)(object)val2 != (Object)null)
						{
							val.mainTexture = (Texture)(object)val2;
						}
					}
					if (val.HasProperty("_Color"))
					{
						if (gem.White || shifted)
						{
							val.color = new Color(1f, 1f, 1f, val.color.a);
						}
						else
						{
							val.color = RecolorColor(val.color, gem);
						}
					}
				}
			}
		}

		private static Sprite RecolorSprite(Sprite sprite, GemDefinition gem)
		{
			//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)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sprite == (Object)null || (Object)(object)sprite.texture == (Object)null)
			{
				return null;
			}
			Rect textureRect = sprite.textureRect;
			int x = (int)((Rect)(ref textureRect)).x;
			int y = (int)((Rect)(ref textureRect)).y;
			int num = (int)((Rect)(ref textureRect)).width;
			int num2 = (int)((Rect)(ref textureRect)).height;
			if (num <= 0 || num2 <= 0)
			{
				return null;
			}
			Texture2D val = ReadTexture((Texture)(object)sprite.texture);
			try
			{
				byte[] rgba = Crop(val, x, y, num, num2);
				GemTint.Recolor(rgba, gem.HueDegrees, gem.Saturation, gem.White);
				Texture2D val2 = new Texture2D(num, num2, (TextureFormat)4, false);
				((Object)val2).name = gem.PrefabName + " icon";
				((Texture)val2).filterMode = ((Texture)sprite.texture).filterMode;
				((Texture)val2).wrapMode = (TextureWrapMode)1;
				val2.SetPixels32(ToPixels(rgba));
				val2.Apply();
				Vector2 val3 = default(Vector2);
				((Vector2)(ref val3))..ctor(0.5f, 0.5f);
				Rect rect = sprite.rect;
				if (((Rect)(ref rect)).width > 0f)
				{
					rect = sprite.rect;
					if (((Rect)(ref rect)).height > 0f)
					{
						float x2 = sprite.pivot.x;
						rect = sprite.rect;
						float num3 = x2 / ((Rect)(ref rect)).width;
						float y2 = sprite.pivot.y;
						rect = sprite.rect;
						((Vector2)(ref val3))..ctor(num3, y2 / ((Rect)(ref rect)).height);
					}
				}
				float num4 = ((sprite.pixelsPerUnit > 0f) ? sprite.pixelsPerUnit : 100f);
				return Sprite.Create(val2, new Rect(0f, 0f, (float)num, (float)num2), val3, num4);
			}
			finally
			{
				Object.DestroyImmediate((Object)(object)val);
			}
		}

		private static Texture2D RecolorTexture(Texture source, GemDefinition gem, out bool shifted)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			string text = gem.PrefabName + ":" + ((Object)source).GetInstanceID();
			if (Cache.TryGetValue(text, out var value))
			{
				shifted = ShiftedKeys.Contains(text);
				return value;
			}
			Texture2D val = ReadTexture(source);
			try
			{
				Color32[] pixels = val.GetPixels32();
				byte[] rgba = FromPixels(pixels);
				bool flag = GemTint.Recolor(rgba, gem.HueDegrees, gem.Saturation, gem.White);
				Texture2D val2 = new Texture2D(((Texture)val).width, ((Texture)val).height, (TextureFormat)4, false);
				((Object)val2).name = gem.PrefabName + " " + ((Object)source).name;
				((Texture)val2).filterMode = source.filterMode;
				((Texture)val2).wrapMode = source.wrapMode;
				val2.SetPixels32(ToPixels(rgba));
				val2.Apply();
				Cache[text] = val2;
				if (flag)
				{
					ShiftedKeys.Add(text);
				}
				shifted = flag;
				return val2;
			}
			finally
			{
				Object.DestroyImmediate((Object)(object)val);
			}
		}

		private static Texture2D ReadTexture(Texture source)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0, (RenderTextureFormat)0);
			RenderTexture active = RenderTexture.active;
			try
			{
				Graphics.Blit(source, temporary);
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(source.width, source.height, (TextureFormat)4, false);
				val.ReadPixels(new Rect(0f, 0f, (float)source.width, (float)source.height), 0, 0);
				val.Apply();
				return val;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		private static byte[] Crop(Texture2D readable, int x, int y, int width, int height)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			Color32[] pixels = readable.GetPixels32();
			byte[] array = new byte[width * height * 4];
			int width2 = ((Texture)readable).width;
			for (int i = 0; i < height; i++)
			{
				int num = y + i;
				if (num < 0 || num >= ((Texture)readable).height)
				{
					continue;
				}
				for (int j = 0; j < width; j++)
				{
					int num2 = x + j;
					if (num2 >= 0 && num2 < width2)
					{
						Color32 val = pixels[num * width2 + num2];
						int num3 = (i * width + j) * 4;
						array[num3] = val.r;
						array[num3 + 1] = val.g;
						array[num3 + 2] = val.b;
						array[num3 + 3] = val.a;
					}
				}
			}
			return array;
		}

		private static byte[] FromPixels(Color32[] pixels)
		{
			byte[] array = new byte[pixels.Length * 4];
			for (int i = 0; i < pixels.Length; i++)
			{
				int num = i * 4;
				array[num] = pixels[i].r;
				array[num + 1] = pixels[i].g;
				array[num + 2] = pixels[i].b;
				array[num + 3] = pixels[i].a;
			}
			return array;
		}

		private static Color32[] ToPixels(byte[] rgba)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			Color32[] array = (Color32[])(object)new Color32[rgba.Length / 4];
			for (int i = 0; i < array.Length; i++)
			{
				int num = i * 4;
				array[i] = new Color32(rgba[num], rgba[num + 1], rgba[num + 2], rgba[num + 3]);
			}
			return array;
		}

		private static Color RecolorColor(Color color, GemDefinition gem)
		{
			//IL_0009: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			byte[] array = new byte[4]
			{
				ToByte(color.r),
				ToByte(color.g),
				ToByte(color.b),
				255
			};
			GemTint.Recolor(array, gem.HueDegrees, gem.Saturation, gem.White);
			return Color32.op_Implicit(new Color32(array[0], array[1], array[2], ToByte(color.a)));
		}

		private static byte ToByte(float channel)
		{
			if (channel <= 0f)
			{
				return 0;
			}
			if (channel >= 1f)
			{
				return byte.MaxValue;
			}
			return (byte)Math.Round(channel * 255f, MidpointRounding.AwayFromZero);
		}
	}
	internal static class HaldorStock
	{
		internal static bool IsHaldor(Trader trader)
		{
			if ((Object)(object)trader == (Object)null)
			{
				return false;
			}
			string text = ShopRules.Normalize(((Object)((Component)trader).gameObject).name);
			return text.IndexOf("Haldor", StringComparison.OrdinalIgnoreCase) >= 0 && text.IndexOf("Hildir", StringComparison.OrdinalIgnoreCase) < 0;
		}

		internal static void Append(Trader trader, List<TradeItem> items)
		{
			//IL_006a: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			if (!ModConfig.HaldorSells || !IsHaldor(trader) || items == null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			for (int i = 0; i < GemCatalog.All.Length; i++)
			{
				GemDefinition gemDefinition = GemCatalog.All[i];
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(gemDefinition.PrefabName);
				ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if (!((Object)(object)val == (Object)null))
				{
					items.Add(new TradeItem
					{
						m_prefab = val,
						m_stack = 1,
						m_price = gemDefinition.Value
					});
				}
			}
		}

		internal static bool BlocksSale(StoreGui gui, ItemData item)
		{
			if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
			{
				return false;
			}
			if (GemCatalog.Find(ShopRules.Normalize(((Object)item.m_dropPrefab).name)) == null)
			{
				return false;
			}
			Trader trader = (Trader)(((Object)(object)gui != (Object)null && ValheimMembers.TraderField != null) ? /*isinst with value type is only supported in some contexts*/: null);
			return !ModConfig.HaldorBuys || !IsHaldor(trader);
		}
	}
	internal static class ShopAccess
	{
		internal static bool MayOpen(Player player, Container chest)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)chest == (Object)null)
			{
				return false;
			}
			if (WardCovers(((Component)chest).transform.position, out var allowed))
			{
				return allowed;
			}
			Piece component = ((Component)chest).GetComponent<Piece>();
			return (Object)(object)component != (Object)null && component.GetCreator() == player.GetPlayerID();
		}

		internal static bool MayBreak(Player player, Component piece)
		{
			return (Object)(object)player != (Object)null && (Object)(object)piece != (Object)null && ShopLink.IsLinked(piece.gameObject);
		}

		internal static bool WardCovers(Vector3 point, out bool allowed)
		{
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			allowed = true;
			bool flag = false;
			List<PrivateArea> list = ((ValheimMembers.AllAreas != null) ? (ValheimMembers.AllAreas.GetValue(null) as List<PrivateArea>) : null);
			if (list == null || ValheimMembers.AreaEnabled == null || ValheimMembers.AreaInside == null)
			{
				return false;
			}
			for (int i = 0; i < list.Count; i++)
			{
				PrivateArea val = list[i];
				if (!((Object)(object)val == (Object)null) && (bool)ValheimMembers.AreaEnabled.Invoke(val, null) && (bool)ValheimMembers.AreaInside.Invoke(val, new object[2] { point, 0f }))
				{
					flag = true;
				}
			}
			if (!flag)
			{
				allowed = false;
				return false;
			}
			allowed = PrivateArea.CheckAccess(point, 0f, false, false);
			return true;
		}
	}
	internal static class ShopBreak
	{
		private static readonly HashSet<long> Busy = new HashSet<long>();

		internal static void Break(GameObject piece)
		{
			if ((Object)(object)piece == (Object)null || !ShopLink.IsLinked(piece))
			{
				return;
			}
			if ((Object)(object)piece.GetComponent<Container>() != (Object)null)
			{
				DropSign(piece);
				return;
			}
			long item = ShopLink.LinkId(piece);
			if (!Busy.Add(item))
			{
				return;
			}
			try
			{
				Remove(piece);
			}
			finally
			{
				Busy.Remove(item);
			}
		}

		internal static void DropSign(GameObject chestObject)
		{
			Container val = (((Object)(object)chestObject != (Object)null) ? chestObject.GetComponent<Container>() : null);
			if ((Object)(object)val == (Object)null)
			{
				val = ShopLink.ChestOf(chestObject);
			}
			if ((Object)(object)val == (Object)null || !ShopLink.IsLinked(((Component)val).gameObject))
			{
				return;
			}
			long item = ShopLink.LinkId(((Component)val).gameObject);
			if (!Busy.Add(item))
			{
				return;
			}
			try
			{
				GameObject val2 = ShopLink.Partner(((Component)val).gameObject);
				ReleaseChest(((Component)val).gameObject);
				if ((Object)(object)val2 != (Object)null)
				{
					Remove(val2);
				}
			}
			finally
			{
				Busy.Remove(item);
			}
		}

		internal static void OnDestroying(WearNTear wear)
		{
			if ((Object)(object)wear == (Object)null || !ShopLink.IsLinked(((Component)wear).gameObject))
			{
				return;
			}
			long item = ShopLink.LinkId(((Component)wear).gameObject);
			if (!Busy.Add(item))
			{
				return;
			}
			try
			{
				if ((Object)(object)((Component)wear).GetComponent<Container>() != (Object)null)
				{
					GameObject val = ShopLink.Partner(((Component)wear).gameObject);
					if ((Object)(object)val != (Object)null)
					{
						Remove(val);
					}
				}
				else
				{
					ReleaseChest(ShopLink.Partner(((Component)wear).gameObject));
				}
			}
			finally
			{
				Busy.Remove(item);
			}
		}

		private static void ReleaseChest(GameObject chestObject)
		{
			if (!((Object)(object)chestObject == (Object)null))
			{
				ShopState.Relax(chestObject);
				Container component = chestObject.GetComponent<Container>();
				if ((Object)(object)component != (Object)null)
				{
					ShopLink.Unlink(component);
				}
			}
		}

		private static void Remove(GameObject gameObject)
		{
			if (!((Object)(object)gameObject == (Object)null))
			{
				if ((Object)(object)gameObject.transform.parent != (Object)null)
				{
					gameObject.transform.SetParent((Transform)null, true);
				}
				ZNetView component = gameObject.GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.IsValid() && !component.IsOwner())
				{
					component.ClaimOwnership();
				}
				WearNTear component2 = gameObject.GetComponent<WearNTear>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.Remove(false);
				}
				else if ((Object)(object)ZNetScene.instance != (Object)null)
				{
					ZNetScene.instance.Destroy(gameObject);
				}
			}
		}
	}
	internal static class ShopInventory
	{
		internal static StackState[] ReadChest(Inventory inventory)
		{
			if (inventory == null)
			{
				return new StackState[0];
			}
			int width = inventory.GetWidth();
			int height = inventory.GetHeight();
			StackState[] array = new StackState[width * height];
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					ItemData itemAt = inventory.GetItemAt(j, i);
					if (itemAt != null)
					{
						array[i * width + j] = FromItem(itemAt);
					}
				}
			}
			return array;
		}

		internal static List<StackState> ReadPlayer(Player player)
		{
			List<StackState> list = new List<StackState>();
			Inventory val = (((Object)(object)player != (Object)null) ? ((Humanoid)player).GetInventory() : null);
			if (val == null)
			{
				return list;
			}
			List<ItemData> allItems = val.GetAllItems();
			for (int i = 0; i < allItems.Count; i++)
			{
				list.Add(FromItem(allItems[i]));
			}
			return list;
		}

		internal static StackState FromItem(ItemData item)
		{
			StackState stackState = new StackState();
			if (item == null)
			{
				return stackState;
			}
			stackState.Amount = item.m_stack;
			stackState.Quality = item.m_quality;
			stackState.Equipped = item.m_equipped;
			float maxDurability = item.GetMaxDurability();
			stackState.Durability = ((maxDurability > 0.001f) ? item.GetDurabilityPercentage() : 1f);
			stackState.MaxStack = ((item.m_shared == null || item.m_shared.m_maxStackSize <= 0) ? 1 : item.m_shared.m_maxStackSize);
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				stackState.Prefab = ShopRules.Normalize(((Object)item.m_dropPrefab).name);
			}
			return stackState;
		}

		internal static int PrefabMax(string prefabName)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || string.IsNullOrEmpty(prefabName))
			{
				return 999;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
			ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null)
			{
				return 999;
			}
			return (val.m_itemData.m_shared.m_maxStackSize > 0) ? val.m_itemData.m_shared.m_maxStackSize : 999;
		}

		internal static bool CanAccept(Inventory inventory, ItemData item, int stack)
		{
			Container val = ShopLink.FindChest(inventory);
			if ((Object)(object)val == (Object)null || item == null)
			{
				return false;
			}
			StackState stackState = FromItem(item);
			if (stack > 0)
			{
				stackState.Amount = stack;
			}
			return ShopRules.FindAutoSlot(ReadChest(inventory), stackState, Withdraw(val)) >= 0;
		}

		internal static bool CanAcceptPrefab(Inventory inventory, GameObject prefab, int stack)
		{
			ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			return CanAccept(inventory, val.m_itemData, stack);
		}

		internal static bool TryRedirect(Inventory inventory, ItemData item, ref bool result)
		{
			Container val = ShopLink.FindChest(inventory);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			result = false;
			if (item == null || item.m_shared == null)
			{
				return true;
			}
			StackState[] slots = ReadChest(inventory);
			int num = ShopRules.FindAutoSlot(slots, FromItem(item), Withdraw(val));
			if (num < 0)
			{
				return true;
			}
			int width = inventory.GetWidth();
			if (width <= 0)
			{
				return true;
			}
			int x = num % width;
			int y = num / width;
			int num2 = StackAt(inventory, x, y);
			result = MoveInto(inventory, item, x, y, item.m_stack);
			if (StackAt(inventory, x, y) > num2)
			{
				Touch(inventory, num, num2);
			}
			else
			{
				Changed(inventory);
			}
			return true;
		}

		internal static int StackAt(Inventory inventory, int x, int y)
		{
			if (inventory == null)
			{
				return 0;
			}
			return inventory.GetItemAt(x, y)?.m_stack ?? 0;
		}

		internal static void Touch(Inventory inventory, int index, int previous)
		{
			if (ShopState.RunningTrade || inventory == null)
			{
				return;
			}
			Container val = ShopLink.FindChest(inventory);
			if (!((Object)(object)val == (Object)null))
			{
				ShopState.OnInventoryChanged(val);
				int width = inventory.GetWidth();
				if (index >= 0 && width > 0 && StackAt(inventory, index % width, index / width) > previous)
				{
					Announce(Player.m_localPlayer, inventory, index);
				}
			}
		}

		internal static void Changed(Inventory inventory)
		{
			Touch(inventory, -1, 0);
		}

		internal static bool Execute(Container chest, Player player, TradePlan plan)
		{
			if ((Object)(object)chest == (Object)null || (Object)(object)player == (Object)null || plan == null || plan.Result != TradeResult.Done)
			{
				return false;
			}
			Inventory inventory = chest.GetInventory();
			Inventory inventory2 = ((Humanoid)player).GetInventory();
			if (inventory == null || inventory2 == null || !Ready(chest, plan))
			{
				return false;
			}
			ItemData[] array = inventory2.GetAllItems().ToArray();
			for (int i = 0; i < plan.PlayerRemovals.Length; i++)
			{
				Removal removal = plan.PlayerRemovals[i];
				if (removal.Index < 0 || removal.Index >= array.Length || array[removal.Index] == null)
				{
					return false;
				}
			}
			ShopState.RunningTrade = true;
			try
			{
				for (int j = 0; j < plan.PlayerRemovals.Length; j++)
				{
					Removal removal2 = plan.PlayerRemovals[j];
					inventory2.RemoveItem(array[removal2.Index], removal2.Amount);
				}
				if (!Give(chest, plan))
				{
					return false;
				}
				int width = inventory.GetWidth();
				if (width <= 0)
				{
					return false;
				}
				for (int k = 0; k < plan.ChestRemovals.Length; k++)
				{
					Removal removal3 = plan.ChestRemovals[k];
					ItemData itemAt = inventory.GetItemAt(removal3.Index % width, removal3.Index / width);
					if (itemAt == null)
					{
						return false;
					}
					inventory.RemoveItem(itemAt, removal3.Amount);
				}
				Drop(chest, plan);
				Save(chest);
				return true;
			}
			finally
			{
				ShopState.RunningTrade = false;
			}
		}

		internal static void RepairPrefabs(Container chest)
		{
			if ((Object)(object)chest == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			Inventory inventory = chest.GetInventory();
			if (inventory == null)
			{
				return;
			}
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null)
			{
				return;
			}
			bool flag = false;
			for (int i = 0; i < allItems.Count; i++)
			{
				ItemData val = allItems[i];
				if (val != null && !((Object)(object)val.m_dropPrefab != (Object)null) && val.m_shared != null)
				{
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(val.m_shared);
					if (!((Object)(object)itemPrefab == (Object)null))
					{
						val.m_dropPrefab = itemPrefab;
						flag = true;
					}
				}
			}
			if (flag)
			{
				Save(chest);
			}
		}

		private static bool Withdraw(Container chest)
		{
			return ShopRules.WithdrawOnly(ModConfig.Enable, hasSign: true, ReadChest(chest.GetInventory()));
		}

		private static bool MoveInto(Inventory inventory, ItemData item, int x, int y, int amount)
		{
			if (ValheimMembers.InventoryAddAt == null || amount <= 0 || inventory == null)
			{
				return false;
			}
			int num = Room(inventory, x, y, item);
			int num2 = ((amount < num) ? amount : num);
			if (num2 <= 0)
			{
				return false;
			}
			object obj = ValheimMembers.InventoryAddAt.Invoke(inventory, new object[5] { item, num2, x, y, false });
			return obj is bool && (bool)obj && item.m_stack <= 0;
		}

		private static int Room(Inventory inventory, int x, int y, ItemData incoming)
		{
			ItemData itemAt = inventory.GetItemAt(x, y);
			int num = ((incoming.m_shared == null || incoming.m_shared.m_maxStackSize <= 0) ? 1 : incoming.m_shared.m_maxStackSize);
			if (itemAt == null)
			{
				return num;
			}
			int num2 = ((itemAt.m_shared != null && itemAt.m_shared.m_maxStackSize > 0) ? itemAt.m_shared.m_maxStackSize : num);
			int num3 = num2 - itemAt.m_stack;
			return (num3 > 0) ? num3 : 0;
		}

		private static void Announce(Player player, Inventory inventory, int index)
		{
			if ((Object)(object)player == (Object)null || ShopState.RunningTrade || inventory == null || (index != 0 && index != 1))
			{
				return;
			}
			int width = inventory.GetWidth();
			if (width <= 0)
			{
				return;
			}
			ItemData itemAt = inventory.GetItemAt(index % width, index / width);
			if (itemAt != null)
			{
				bool flag = ShopRules.Normalize(((Object)(object)itemAt.m_dropPrefab != (Object)null) ? ((Object)itemAt.m_dropPrefab).name : "") == "Coins";
				string item = ShopMessages.ItemName(itemAt);
				string currency = ShopMessages.CoinName();
				if (index == 0 && !flag)
				{
					ShopMessages.Show(player, "$ptc_4", itemAt.m_stack, -1, item, null, null);
				}
				else if (index == 0)
				{
					ShopMessages.Show(player, "$ptc_6", itemAt.m_stack, -1, null, currency, null);
				}
				else if (flag)
				{
					ShopMessages.Show(player, "$ptc_5", itemAt.m_stack, -1, null, currency, null);
				}
				else
				{
					ShopMessages.Show(player, "$ptc_7", itemAt.m_stack, -1, item, null, null);
				}
			}
		}

		internal static void Spill(Container chest)
		{
			if ((Object)(object)chest == (Object)null)
			{
				return;
			}
			Inventory inventory = chest.GetInventory();
			if (inventory == null)
			{
				return;
			}
			StackState[] array = ReadChest(inventory);
			int width = inventory.GetWidth();
			if (width <= 0)
			{
				return;
			}
			bool flag = false;
			for (int i = 2; i < array.Length; i++)
			{
				if (!ShopRules.MiddleBelongs(array, i))
				{
					ItemData itemAt = inventory.GetItemAt(i % width, i / width);
					if (itemAt != null)
					{
						DropItem(((Component)chest).transform, itemAt.Clone(), 0.15f * (float)(i - 2));
						inventory.RemoveItem(itemAt, itemAt.m_stack);
						flag = true;
					}
				}
			}
			if (flag)
			{
				Save(chest);
			}
		}

		private static void Save(Container chest)
		{
			if ((Object)(object)chest != (Object)null && ValheimMembers.ContainerSave != null)
			{
				ValheimMembers.ContainerSave.Invoke(chest, null);
			}
		}

		private static bool Ready(Container chest, TradePlan plan)
		{
			if (plan.Payouts == null || plan.Payouts.Length == 0)
			{
				return false;
			}
			if (string.IsNullOrEmpty(plan.DropPrefab))
			{
				return false;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ObjectDB.instance.GetItemPrefab(plan.DropPrefab) == (Object)null)
			{
				return false;
			}
			bool flag = plan.Placements != null && plan.Placements.Length != 0;
			if (flag && (string.IsNullOrEmpty(plan.ReceivePrefab) || (Object)(object)ObjectDB.instance.GetItemPrefab(plan.ReceivePrefab) == (Object)null))
			{
				return false;
			}
			Inventory inventory = chest.GetInventory();
			if (inventory == null)
			{
				return false;
			}
			int width = inventory.GetWidth();
			if (width <= 0)
			{
				return false;
			}
			if (!flag)
			{
				return true;
			}
			StackState[] array = ReadChest(inventory);
			for (int i = 0; i < plan.Placements.Length; i++)
			{
				Placement placement = plan.Placements[i];
				if (placement.Slot < 2 || placement.Slot >= array.Length || placement.Amount <= 0)
				{
					return false;
				}
				ItemData itemAt = inventory.GetItemAt(placement.Slot % width, placement.Slot / width);
				if (placement.StackOnExisting)
				{
					if (itemAt == null || itemAt.m_shared == null)
					{
						return false;
					}
					if (itemAt.m_stack + placement.Amount > itemAt.m_shared.m_maxStackSize)
					{
						return false;
					}
				}
				else if (itemAt != null || placement.Amount > PrefabMax(plan.ReceivePrefab))
				{
					return false;
				}
			}
			return true;
		}

		private static bool Give(Container chest, TradePlan plan)
		{
			if (plan.Placements == null || plan.Placements.Length == 0)
			{
				return true;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(plan.ReceivePrefab);
			ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			Inventory inventory = chest.GetInventory();
			if ((Object)(object)val == (Object)null || val.m_itemData == null || inventory == null || ValheimMembers.InventoryAddAt == null)
			{
				return false;
			}
			int width = inventory.GetWidth();
			if (width <= 0)
			{
				return false;
			}
			for (int i = 0; i < plan.Placements.Length; i++)
			{
				Placement placement = plan.Placements[i];
				int num = placement.Slot % width;
				int num2 = placement.Slot / width;
				ItemData itemAt = inventory.GetItemAt(num, num2);
				ItemData val2 = val.m_itemData.Clone();
				val2.m_dropPrefab = itemPrefab;
				val2.m_stack = placement.Amount;
				val2.m_quality = plan.ReceiveQuality;
				val2.m_equipped = false;
				float maxDurability = val2.GetMaxDurability();
				val2.m_durability = ((placement.StackOnExisting && itemAt != null) ? itemAt.m_durability : (maxDurability * placement.Durability));
				object obj = ValheimMembers.InventoryAddAt.Invoke(inventory, new object[5] { val2, placement.Amount, num, num2, false });
				if (!(obj is bool) || !(bool)obj)
				{
					return false;
				}
				ItemData itemAt2 = inventory.GetItemAt(num, num2);
				if (itemAt2 != null && (Object)(object)itemAt2.m_dropPrefab == (Object)null)
				{
					itemAt2.m_dropPrefab = itemPrefab;
				}
			}
			return true;
		}

		private static void Drop(Container chest, TradePlan plan)
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(plan.DropPrefab);
			ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null || val.m_itemData == null || (Object)(object)chest == (Object)null)
			{
				return;
			}
			Sign val2 = ShopLink.SignOf(((Component)chest).gameObject);
			Transform origin = (((Object)(object)val2 != (Object)null) ? ((Component)val2).transform : ((Component)chest).transform);
			int num = 0;
			for (int i = 0; i < plan.Payouts.Length; i++)
			{
				Payout payout = plan.Payouts[i];
				if (payout.Amount > 0)
				{
					Spawn(origin, itemPrefab, val, payout.Amount, plan.DropQuality, payout.Durability, num);
					num++;
				}
			}
		}

		private static void Spawn(Transform origin, GameObject prefab, ItemDrop drop, int amount, int quality, float durability, int index)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)origin == (Object)null || (Object)(object)drop == (Object)null || drop.m_itemData == null || amount <= 0)
			{
				return;
			}
			ItemData val = drop.m_itemData.Clone();
			val.m_dropPrefab = prefab;
			val.m_stack = amount;
			val.m_quality = quality;
			val.m_durability = val.GetMaxDurability() * durability;
			val.m_equipped = false;
			val.m_worldLevel = (byte)Game.m_worldLevel;
			Vector3 val2 = origin.position + origin.forward * (1.1f + 0.15f * (float)index) + Vector3.up * 0.25f;
			ItemDrop val3 = ItemDrop.DropItem(val, amount, val2, Quaternion.identity);
			if (!((Object)(object)val3 == (Object)null) && val3.m_itemData != null)
			{
				val3.m_itemData.m_dropPrefab = prefab;
				val3.m_itemData.m_stack = amount;
				val3.m_itemData.m_quality = quality;
				val3.m_itemData.m_durability = val3.m_itemData.GetMaxDurability() * durability;
				val3.m_itemData.m_worldLevel = val.m_worldLevel;
				if (ValheimMembers.ItemDropSave != null)
				{
					ValheimMembers.ItemDropSave.Invoke(val3, null);
				}
			}
		}

		private static void DropItem(Transform origin, ItemData data, float extra)
		{
			//IL_0022: 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_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_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_0052: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)origin == (Object)null || data == null)
			{
				return;
			}
			int stack = data.m_stack;
			Vector3 val = origin.position + origin.forward * (1.1f + extra) + Vector3.up * 0.25f;
			ItemDrop val2 = ItemDrop.DropItem(data, stack, val, Quaternion.identity);
			if (!((Object)(object)val2 == (Object)null) && val2.m_itemData != null)
			{
				val2.m_itemData.m_stack = stack;
				val2.m_itemData.m_quality = data.m_quality;
				val2.m_itemData.m_durability = data.m_durability;
				if (ValheimMembers.ItemDropSave != null)
				{
					ValheimMembers.ItemDropSave.Invoke(val2, null);
				}
			}
		}
	}
	internal static class ShopLink
	{
		private const float PairDistance = 2.5f;

		private static readonly Dictionary<long, Container> Chests = new Dictionary<long, Container>();

		private static readonly Dictionary<long, Sign> Signs = new Dictionary<long, Sign>();

		private static readonly Dictionary<Inventory, Container> ByInventory = new Dictionary<Inventory, Container>();

		internal static void Register(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return;
			}
			ZDO val = ReadZdo(gameObject);
			if (val == null)
			{
				return;
			}
			long num = val.GetLong("ptc_link", 0L);
			if (num == 0)
			{
				return;
			}
			Container component = gameObject.GetComponent<Container>();
			Sign component2 = gameObject.GetComponent<Sign>();
			if ((Object)(object)component != (Object)null)
			{
				Chests[num] = component;
				Inventory inventory = component.GetInventory();
				if (inventory != null)
				{
					ByInventory[inventory] = component;
				}
			}
			if ((Object)(object)component2 != (Object)null)
			{
				Signs[num] = component2;
			}
			ShopState.Reinforce(gameObject);
			ParentIfLoose(num);
		}

		internal static Container FindChest(Inventory inventory)
		{
			if (inventory == null)
			{
				return null;
			}
			Container value;
			return ByInventory.TryGetValue(inventory, out value) ? value : null;
		}

		internal static bool IsLinked(GameObject gameObject)
		{
			return LinkId(gameObject) != 0;
		}

		internal static long LinkId(GameObject gameObject)
		{
			ZDO val = ReadZdo(gameObject);
			return (val == null) ? 0 : val.GetLong("ptc_link", 0L);
		}

		internal static bool HasSign(Container chest)
		{
			long num = LinkId(((Object)(object)chest != (Object)null) ? ((Component)chest).gameObject : null);
			if (num == 0)
			{
				return false;
			}
			Sign value;
			return Signs.TryGetValue(num, out value) && (Object)(object)value != (Object)null;
		}

		internal static Container ChestOf(GameObject gameObject)
		{
			Container val = (((Object)(object)gameObject != (Object)null) ? gameObject.GetComponent<Container>() : null);
			if ((Object)(object)val != (Object)null && IsLinked(gameObject))
			{
				return val;
			}
			long num = LinkId(gameObject);
			if (num != 0L && Chests.TryGetValue(num, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			return null;
		}

		internal static Sign SignOf(GameObject gameObject)
		{
			Sign val = (((Object)(object)gameObject != (Object)null) ? gameObject.GetComponent<Sign>() : null);
			if ((Object)(object)val != (Object)null && IsLinked(gameObject))
			{
				return val;
			}
			long num = LinkId(gameObject);
			if (num != 0L && Signs.TryGetValue(num, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			return null;
		}

		internal static GameObject Partner(GameObject gameObject)
		{
			long num = LinkId(gameObject);
			if (num == 0)
			{
				return null;
			}
			Sign value;
			if ((Object)(object)gameObject.GetComponent<Container>() != (Object)null)
			{
				return (Signs.TryGetValue(num, out value) && (Object)(object)value != (Object)null) ? ((Component)value).gameObject : null;
			}
			Container value2;
			return (Chests.TryGetValue(num, out value2) && (Object)(object)value2 != (Object)null) ? ((Component)value2).gameObject : null;
		}

		internal static void Bind(Container chest, Sign sign, int face, long deadline)
		{
			ZDO val = ReadZdo(((Component)chest).gameObject);
			ZDO val2 = ReadZdo(((Component)sign).gameObject);
			if (val != null && val2 != null)
			{
				long num = NewLink();
				val.Set("ptc_link", num);
				val2.Set("ptc_link", num);
				val2.Set("ptc_face", face);
				val.Set("ptc_deadline", deadline);
				val2.Set("ptc_deadline", deadline);
				val.Set("ptc_committed", false);
				val2.Set("ptc_committed", false);
				Register(((Component)chest).gameObject);
				Register(((Component)sign).gameObject);
			}
		}

		internal static void PairByPosition(GameObject gameObject)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			long num = LinkId(gameObject);
			if (num == 0L || (Object)(object)Partner(gameObject) != (Object)null)
			{
				return;
			}
			bool flag = (Object)(object)gameObject.GetComponent<Container>() == (Object)null;
			Collider[] array = Physics.OverlapSphere(gameObject.transform.position, 2.5f);
			Component val = null;
			float num2 = 2.5f;
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] == (Object)null)
				{
					continue;
				}
				Component val2 = (Component)(flag ? ((object)((Component)array[i]).GetComponentInParent<Container>()) : ((object)((Component)array[i]).GetComponentInParent<Sign>()));
				if ((Object)(object)val2 == (Object)null || (Object)(object)val2.gameObject == (Object)(object)gameObject)
				{
					continue;
				}
				long num3 = LinkId(val2.gameObject);
				if ((num3 == 0L || num3 == num) && (!flag || ShopRules.Listed(ShopRules.Normalize(((Object)val2.gameObject).name), ModConfig.AllowedChests())))
				{
					float num4 = Vector3.Distance(val2.transform.position, gameObject.transform.position);
					if (!(num4 >= num2))
					{
						num2 = num4;
						val = val2;
					}
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				ZDO val3 = ReadZdo(val.gameObject);
				if (val3 != null)
				{
					val3.Set("ptc_link", num);
					Register(val.gameObject);
				}
			}
		}

		internal static void ForEachSign(Action<Sign> action)
		{
			if (action == null)
			{
				return;
			}
			List<long> list = new List<long>(Signs.Keys);
			for (int i = 0; i < list.Count; i++)
			{
				if (Signs.TryGetValue(list[i], out var value) && (Object)(object)value != (Object)null)
				{
					action(value);
				}
			}
		}

		internal static void Unlink(Container chest)
		{
			if (!((Object)(object)chest == (Object)null))
			{
				long num = LinkId(((Component)chest).gameObject);
				Sign value = null;
				if (num != 0)
				{
					Signs.TryGetValue(num, out value);
				}
				ClearShop(ReadZdo(((Component)chest).gameObject));
				if ((Object)(object)value != (Object)null)
				{
					ClearShop(ReadZdo(((Component)value).gameObject));
				}
				Inventory inventory = chest.GetInventory();
				if (inventory != null)
				{
					ByInventory.Remove(inventory);
				}
				if (num != 0)
				{
					Chests.Remove(num);
					Signs.Remove(num);
				}
			}
		}

		private static void ClearShop(ZDO zdo)
		{
			if (zdo != null)
			{
				zdo.Set("ptc_link", 0L);
				zdo.Set("ptc_deadline", 0L);
				zdo.Set("ptc_frozen", false);
				zdo.Set("ptc_remaining", 0L);
				zdo.Set("ptc_committed", false);
				zdo.Set("ptc_inuse", false);
			}
		}

		internal static ZDO ReadZdo(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return null;
			}
			ZNetView component = gameObject.GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return null;
			}
			return component.GetZDO();
		}

		private static void ParentIfLoose(long link)
		{
			if (Chests.TryGetValue(link, out var value) && !((Object)(object)value == (Object)null) && Signs.TryGetValue(link, out var value2) && !((Object)(object)value2 == (Object)null) && !((Object)(object)((Component)value2).transform.parent == (Object)(object)((Component)value).transform))
			{
				Parent(link);
			}
		}

		private static void Parent(long link)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			if (Chests.TryGetValue(link, out var value) && !((Object)(object)value == (Object)null) && Signs.TryGetValue(link, out var value2) && !((Object)(object)value2 == (Object)null))
			{
				ZDO val = ReadZdo(((Component)value2).gameObject);
				int face = ((val != null) ? val.GetInt("ptc_face", 0) : 0);
				ShopPose.Place(((Component)value).transform, ((Component)value2).transform, face, out var position, out var rotation);
				((Component)value2).transform.SetParent(((Component)value).transform, true);
				((Component)value2).transform.SetPositionAndRotation(position, rotation);
				if (val != null)
				{
					val.SetPosition(position);
				}
			}
		}

		private static long NewLink()
		{
			long num;
			do
			{
				num = ((long)Random.Range(1, int.MaxValue) << 32) | (uint)Random.Range(1, int.MaxValue);
			}
			while (num == 0L || Chests.ContainsKey(num) || Signs.ContainsKey(num));
			return num;
		}
	}
	internal static class ShopLog
	{
		internal static void Write(Player player, Container chest, Offer offer, TradeResult result, bool succeeded, bool moveFailed = false)
		{
			if (!ModConfig.VerboseLogs)
			{
				return;
			}
			try
			{
				string item = (offer.Valid ? EnglishItems.Name(offer.ItemPrefab) : "");
				string text = TradeLog.Line(CharacterName(player), offer.Selling, succeeded, result, offer.ItemAmount, item, offer.CoinAmount, offer.Valid, moveFailed);
				string text2 = Describe(chest, offer, item);
				if (BepinexPlugin.Log != null)
				{
					BepinexPlugin.Log.LogInfo((object)text);
					BepinexPlugin.Log.LogInfo((object)text2);
				}
			}
			catch (Exception ex)
			{
				if (BepinexPlugin.Log != null)
				{
					BepinexPlugin.Log.LogWarning((object)("Could not write the shop trade log. " + ex.Message));
				}
			}
		}

		private static string Describe(Container chest, Offer offer, string item)
		{
			Inventory val = (((Object)(object)chest != (Object)null) ? chest.GetInventory() : null);
			TradeLog.LogSlot[] slots = Slots(val);
			int gridWidth = ((val != null) ? val.GetWidth() : 0);
			int gridHeight = ((val != null) ? val.GetHeight() : 0);
			int stockItem = -1;
			int stockCoins = -1;
			if (offer.Valid && val != null)
			{
				StackState[] slots2 = ShopInventory.ReadChest(val);
				stockItem = ShopRules.MiddleAmount(slots2, offer.ItemPrefab, offer.ItemQuality, coins: false);
				stockCoins = ShopRules.MiddleAmount(slots2, "Coins", 0, coins: true);
			}
			return TradeLog.Contents(offer.Selling, item, offer.CoinAmount, offer.Valid, slots, stockItem, stockCoins, gridWidth, gridHeight);
		}

		private static TradeLog.LogSlot[] Slots(Inventory inventory)
		{
			if (inventory == null)
			{
				return new TradeLog.LogSlot[0];
			}
			int width = inventory.GetWidth();
			int height = inventory.GetHeight();
			List<ItemData> list = new List<ItemData>();
			List<TradeLog.LogSlot> list2 = new List<TradeLog.LogSlot>();
			if (width > 0 && height > 0)
			{
				for (int i = 0; i < height; i++)
				{
					for (int j = 0; j < width; j++)
					{
						ItemData itemAt = inventory.GetItemAt(j, i);
						if (itemAt != null && itemAt.m_stack > 0)
						{
							list.Add(itemAt);
							list2.Add(Make(itemAt, i * width + j, hidden: false));
						}
					}
				}
			}
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems != null)
			{
				for (int k = 0; k < allItems.Count; k++)
				{
					ItemData val = allItems[k];
					if (val != null && val.m_stack > 0 && !Contains(list, val))
					{
						list2.Add(Make(val, -1, hidden: true));
					}
				}
			}
			Sort(list2);
			return list2.ToArray();
		}

		private static TradeLog.LogSlot Make(ItemData item, int slot, bool hidden)
		{
			bool missingPrefab;
			string name = Label(item, out missingPrefab);
			string note = NoteFor(item, missingPrefab);
			if (hidden)
			{
				note = AppendNote(note, "not-on-grid");
			}
			return new TradeLog.LogSlot(slot, item.m_stack, name, note);
		}

		private static bool Contains(List<ItemData> items, ItemData item)
		{
			for (int i = 0; i < items.Count; i++)
			{
				if (items[i] == item)
				{
					return true;
				}
			}
			return false;
		}

		private static string Label(ItemData item, out bool missingPrefab)
		{
			string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ShopRules.Normalize(((Object)item.m_dropPrefab).name) : "");
			missingPrefab = text.Length == 0;
			if (!missingPrefab)
			{
				return EnglishItems.Name(text);
			}
			string token = ((item.m_shared != null) ? item.m_shared.m_name : "");
			string text2 = EnglishItems.FromToken(token);
			return (text2.Length > 0) ? text2 : "item";
		}

		private static string NoteFor(ItemData item, bool missingPrefab)
		{
			string text = "";
			if (missingPrefab)
			{
				text = AppendNote(text, "no-prefab");
			}
			if (item.m_quality > 1)
			{
				text = AppendNote(text, "q" + item.m_quality.ToString(CultureInfo.InvariantCulture));
			}
			float maxDurability = item.GetMaxDurability();
			if (maxDurability > 0.001f)
			{
				float durabilityPercentage = item.GetDurabilityPercentage();
				if (durabilityPercentage + 0.0005f < 0.95f)
				{
					text = AppendNote(text, ((int)(durabilityPercentage * 100f + 0.5f)).ToString(CultureInfo.InvariantCulture) + "%");
				}
			}
			if (item.m_worldLevel != 0)
			{
				text = AppendNote(text, "world " + item.m_worldLevel.ToString(CultureInfo.InvariantCulture));
			}
			return text;
		}

		private static string AppendNote(string note, string part)
		{
			if (note.Length == 0)
			{
				return part;
			}
			return note + " " + part;
		}

		private static void Sort(List<TradeLog.LogSlot> slots)
		{
			for (int i = 1; i < slots.Count; i++)
			{
				TradeLog.LogSlot logSlot = slots[i];
				int num = i;
				while (num > 0 && Order(slots[num - 1]) > Order(logSlot))
				{
					slots[num] = slots[num - 1];
					num--;
				}
				slots[num] = logSlot;
			}
		}

		private static int Order(TradeLog.LogSlot slot)
		{
			return (slot.Slot < 0) ? int.MaxValue : slot.Slot;
		}

		internal static Offer Peek(Container chest)
		{
			if ((Object)(object)chest == (Object)null)
			{
				return default(Offer);
			}
			Inventory inventory = chest.GetInventory();
			if (inventory == null)
			{
				return default(Offer);
			}
			return ShopRules.ReadOffer(ShopInventory.ReadChest(inventory));
		}

		private static string CharacterName(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return "";
			}
			return player.GetPlayerName();
		}
	}
	internal static class ShopMessages
	{
		internal static void Show(Player player, string token)
		{
			Show(player, token, -1, -1, null, null, null);
		}

		internal static void Show(Player player, string token, int firstAmount, int secondAmount, string item, string currency, string valuable)
		{
			if (!((Object)(object)player == (Object)null) && Localization.instance != null && !string.IsNullOrEmpty(token) && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				string template = Localization.instance.Localize(token);
				string text = SignLine.Fill(template, firstAmount, secondAmount, item, currency, valuable);
				Notice.Show(text);
			}
		}

		internal static string ItemName(ItemData item)
		{
			if (item == null || item.m_shared == null || Localization.instance == null)
			{
				return "";
			}
			return Localization.instance.Localize(item.m_shared.m_name);
		}

		internal static string CoinName()
		{
			if (Localization.instance == null)
			{
				return "Coins";
			}
			return Localization.instance.Localize("$item_coins");
		}

		internal static string PrefabName(string prefab)
		{
			if (Localization.instance == null || (Object)(object)ObjectDB.instance == (Object)null || string.IsNullOrEmpty(prefab))
			{
				return prefab ?? "";
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
			ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null || val.m_itemData == null)
			{
				return prefab;
			}
			return ItemName(val.m_itemData);
		}
	}
	internal static class ShopPlacement
	{
		internal static bool TryHandle(Player player, Piece piece, ref bool result)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null)
			{
				return true;
			}
			if (ShopRules.Normalize(((Object)((Component)piece).gameObject).name) != "sign")
			{
				return true;
			}
			if (!TryHitChest(player, out var chest, out var hit))
			{
				return true;
			}
			string text = Refusal(player, chest);
			if (text != null)
			{
				ManualLogSource log = BepinexPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("Shop sign was not attached: " + text));
				}
				result = false;
				return false;
			}
			result = Attach(player, piece, chest, ((RaycastHit)(ref hit)).point);
			return false;
		}

		private static bool TryHitChest(Player player, out Container chest, out RaycastHit hit)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			chest = null;
			hit = default(RaycastHit);
			if ((Object)(object)GameCamera.instance == (Object)null || ValheimMembers.PlaceRayMask == null)
			{
				return false;
			}
			int num = (int)ValheimMembers.PlaceRayMask.GetValue(player);
			Transform val = (Transform)((ValheimMembers.Eye != null) ? /*isinst with value type is only supported in some contexts*/: null);
			Vector3 val2 = (((Object)(object)val != (Object)null) ? val.position : ((Component)player).transform.position);
			if (!Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref hit, 50f, num))
			{
				return false;
			}
			if (Vector3.Distance(val2, ((RaycastHit)(ref hit)).point) >= player.m_maxPlaceDistance || (Object)(object)((RaycastHit)(ref hit)).collider == (Object)null)
			{
				return false;
			}
			chest = ((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<Container>();
			if ((Object)(object)chest == (Object)null)
			{
				return false;
			}
			return ShopRules.Listed(((Object)((Component)chest).gameObject).name, ModConfig.AllowedChests());
		}

		private static string Refusal(Player player, Container chest)
		{
			if (!ModConfig.Enable)
			{
				return "new shops are disabled";
			}
			if (ShopLink.LinkId(((Component)chest).gameObject) != 0)
			{
				return "this chest already has a sign";
			}
			Piece component = ((Component)chest).GetComponent<Piece>();
			if ((Object)(object)component == (Object)null || component.GetCreator() != player.GetPlayerID())
			{
				return "only the player who built the chest can attach a sign";
			}
			if (ValheimMembers.ContainerLoad != null)
			{
				ValheimMembers.ContainerLoad.Invoke(chest, null);
			}
			if (!ShopRules.IsEmpty(ShopInventory.ReadChest(chest.GetInventory())))
			{
				return "the chest is not empty";
			}
			ZNetView component2 = ((Component)chest).GetComponent<ZNetView>();
			if ((Object)(object)component2 == (Object)null || !component2.IsValid())
			{
				return "the chest is not ready";
			}
			return null;
		}

		private static bool Attach(Player player, Piece piece, Container chest, Vector3 point)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			int face = ShopPose.FaceFrom(((Component)chest).transform, point);
			ShopPose.World(((Component)chest).transform, face, out var position, out var rotation);
			GameObject val = Object.Instantiate<GameObject>(((Component)piece).gameObject, position, rotation);
			Sign component = val.GetComponent<Sign>();
			Piece component2 = val.GetComponent<Piece>();
			ZNetView component3 = val.GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null || !component3.IsValid())
			{
				Discard(val);
				return false;
			}
			component2.SetCreator(player.GetPlayerID(), LocalUser());
			WearNTear component4 = val.GetComponent<WearNTear>();
			if ((Object)(object)component4 != (Object)null)
			{
				component4.OnPlaced();
			}
			long deadline = DateTime.UtcNow.Ticks + TimeSpan.FromSeconds(10.0).Ticks;
			GameObject gameObject = ((Component)chest).gameObject;
			ShopLink.Bind(chest, component, face, deadline);
			if (ShopLink.LinkId(val) == 0)
			{
				Discard(val);
				return false;
			}
			if (player.PlacementCostDisabled)
			{
				ZDO val2 = ShopLink.ReadZdo(val);
				if (val2 != null)
				{
					val2.Set(ZDOVars.s_cheated, true);
				}
			}
			if ((Object)(object)val.GetComponent<ShopWatch>() == (Object)null)
			{
				val.AddComponent<ShopWatch>();
			}
			if ((Object)(object)gameObject.GetComponent<ShopWatch>() == (Object)null)
			{
				gameObject.AddComponent<ShopWatch>();
			}
			ShopSign.ShowCount(chest);
			if (piece.m_placeEffect != null)
			{
				piece.m_placeEffect.Create(position, rotation, val.transform, 1f, -1, ((Character)player).GetZDOID());
			}
			ManualLogSource log = BepinexPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"Attached a shop sign.");
			}
			return true;
		}

		private static void Discard(GameObject gameObject)
		{
			if (!((Object)(object)gameObject == (Object)null))
			{
				if ((Object)(object)ZNetScene.instance != (Object)null)
				{
					ZNetScene.instance.Destroy(gameObject);
				}
				else
				{
					Object.Destroy((Object)(object)gameObject);
				}
			}
		}

		private static PlatformUserID LocalUser()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			if (PlatformManager.DistributionPlatform == null || PlatformManager.DistributionPlatform.LocalUser == null)
			{
				return default(PlatformUserID);
			}
			return ((IUser)PlatformManager.DistributionPlatform.LocalUser).PlatformUserID;
		}
	}
	internal static class ShopPose
	{
		internal static int FaceFrom(Transform chest, Vector3 point)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = chest.InverseTransformPoint(point);
			if (Mathf.Abs(val.x) > Mathf.Abs(val.z))
			{
				return (val.x >= 0f) ? 2 : 3;
			}
			return (!(val.z >= 0f)) ? 1 : 0;
		}

		internal static void World(Transform chest, int face, out Vector3 position, out Quaternion rotation)
		{
			Place(chest, null, face, out position, out rotation);
		}

		internal static void Place(Transform chest, Transform sign, int face, out Vector3 position, out Quaternion rotation)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0042: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Outward(face);
			Vector3 val2 = chest.TransformDirection(val);
			if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f)
			{
				val2 = val;
			}
			((Vector3)(ref val2)).Normalize();
			rotation = Quaternion.LookRotation(val2, chest.up);
			Bounds val3 = ChestBounds(chest);
			Vector3 val4 = chest.TransformPoint(((Bounds)(ref val3)).center + Vector3.Scale(((Bounds)(ref val3)).extents, val));
			if ((Object)(object)sign != (Object)null && TryBounds(sign, sign, skipSigns: false, out var bounds))
			{
				float z = ((Bounds)(ref bounds)).extents.z;
				Vector3 val5 = val4 + val2 * (z + 0.03f);
				position = val5 - rotation * ((Bounds)(ref bounds)).center;
			}
			else
			{
				position = val4 + val2 * 0.05f;
			}
		}

		private static Bounds ChestBounds(Transform chest)
		{
			//IL_000f: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//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 missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (TryBounds(chest, chest, skipSigns: true, out var bounds))
			{
				return bounds;
			}
			BoxCollider val = ((Component)chest).GetComponent<BoxCollider>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)chest).GetComponentInChildren<BoxCollider>();
			}
			if ((Object)(object)val != (Object)null)
			{
				return ColliderBounds(chest, val);
			}
			return new Bounds(new Vector3(0f, 0.5f, 0f), new Vector3(1.2f, 1f, 0.8f));
		}

		private static Bounds ColliderBounds(Transform chest, BoxCollider box)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_0030: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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)
			//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_0073: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			Vector3 center = box.center;
			Vector3 val = box.size * 0.5f;
			Bounds bounds = default(Bounds);
			bool any = false;
			for (int i = 0; i < 8; i++)
			{
				Vector3 val2 = center + new Vector3(((i & 1) == 0) ? (0f - val.x) : val.x, ((i & 2) == 0) ? (0f - val.y) : val.y, ((i & 4) == 0) ? (0f - val.z) : val.z);
				Include(chest.InverseTransformPoint(((Component)box).transform.TransformPoint(val2)), ref bounds, ref any);
			}
			return bounds;
		}

		private static bool TryBounds(Transform space, Transform root, bool skipSigns, out Bounds bounds)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_0067: 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)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_008e: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			bounds = default(Bounds);
			bool any = false;
			Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((val is MeshRenderer || val is SkinnedMeshRenderer) && (!skipSigns || !((Object)(object)((Component)val).GetComponentInParent<Sign>() != (Object)null)))
				{
					Bounds localBounds = val.localBounds;
					Vector3 center = ((Bounds)(ref localBounds)).center;
					Vector3 extents = ((Bounds)(ref localBounds)).extents;
					for (int j = 0; j < 8; j++)
					{
						Vector3 val2 = center + new Vector3(((j & 1) == 0) ? (0f - extents.x) : extents.x, ((j & 2) == 0) ? (0f - extents.y) : extents.y, ((j & 4) == 0) ? (0f - extents.z) : extents.z);
						Include(space.InverseTransformPoint(((Component)val).transform.TransformPoint(val2)), ref bounds, ref any);
					}
				}
			}
			return any;
		}

		private static void Include(Vector3 point, ref Bounds bounds, ref bool any)
		{
			//IL_0022: 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)
			//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)
			if (!any)
			{
				bounds = new Bounds(point, Vector3.zero);
				any = true;
			}
			else
			{
				((Bounds)(ref bounds)).Encapsulate(point);
			}
		}

		private static Vector3 Outward(int face)
		{
			//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_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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			return (Vector3)(face switch
			{
				1 => Vector3.back, 
				2 => Vector3.right, 
				3 => Vector3.left, 
				_ => Vector3.forward, 
			});
		}
	}
	internal static class ShopSign
	{
		private static readonly Dictionary<int, int> Shown = new Dictionary<int, int>();

		internal static void ShowCount(Container chest)
		{
			if ((Object)(object)chest == (Object)null)
			{
				return;
			}
			Sign val = ShopLink.SignOf(((Component)chest).gameObject);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			int num = ShopState.SecondsLeft(((Component)chest).gameObject);
			if (num >= 1)
			{
				int instanceID = ((Object)val).GetInstanceID();
				if (!Shown.TryGetValue(instanceID, out var value) || value != num)
				{
					Shown[instanceID] = num;
					SignText.Present(val, ShopRules.CountdownText(num));
				}
			}
		}

		internal static void Update(Container chest)
		{
			if ((Object)(object)chest == (Object)null)
			{
				return;
			}
			Sign val = ShopLink.SignOf(((Component)chest).gameObject);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (ShopState.Counting(chest))
			{
				ShowCount(chest);
				return;
			}
			Shown.Remove(((Object)val).GetInstanceID());
			if (Localization.instance != null)
			{
				StackState[] slots = ShopInventory.ReadChest(chest.GetInventory());
				bool withdrawOnly = ShopRules.WithdrawOnly(ModConfig.Enable, hasSign: true, slots);
				Offer offer = ShopRules.ReadOffer(slots);
				int num = ShopInventory.PrefabMax("Coins");
				int itemMax = (offer.Valid ? ShopInventory.PrefabMax(offer.ItemPrefab) : num);
				bool covers = ShopRules.CoversTrade(slots, offer);
				bool hasSpace = offer.Valid && ShopRules.CanHoldDelivery(slots, offer, itemMax, num);
				bool endsEmpty = ShopRules.EndsEmpty(slots);
				SignKind signKind = ShopRules.ChooseSign(ShopState.Committed(((Component)chest).gameObject), withdrawOnly, offer, covers, hasSpace, endsEmpty);
				string text = ". . .";
				if (signKind == SignKind.OutOfStock)
				{
					text = Localization.instance.Localize("$ptc_10");
				}
				else if (signKind == SignKind.OutOfSpace)
				{
					text = Localization.instance.Localize("$ptc_20");
				}
				else if (signKind == SignKind.Selling || signKind == SignKind.Buying)
				{
					text = SignLine.OfferLine(offer.Selling, offer.ItemAmount, ShopMessages.PrefabName(offer.ItemPrefab), offer.ItemQuality, ShowsQuality(offer.ItemPrefab, offer.ItemQuality), offer.CoinAmount);
				}
				SignText.Present(val, text);
			}
		}

		private static bool ShowsQuality(string prefab, int quality)
		{
			int num = 1;
			if ((Object)(object)ObjectDB.instance != (Object)null && !string.IsNullOrEmpty(prefab))
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
				ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null)
				{
					num = val.m_itemData.m_shared.m_maxQuality;
				}
			}
			return num > 1 || quality > 1;
		}

		internal static void RefreshAll()
		{
			ShopLink.ForEachSign(delegate(Sign sign)
			{
				Container val = ShopLink.ChestOf(((Component)sign).gameObject);
				if ((Object)(object)val != (Object)null)
				{
					Update(val);
				}
			});
		}
	}
	internal static class ShopState
	{
		private static readonly HashSet<int> Scaled = new HashSet<int>();

		internal static bool RunningTrade;

		internal static bool Committed(GameObject gameObject)
		{
			ZDO val = ShopLink.ReadZdo(gameObject);
			return val != null && val.GetBool("ptc_committed", false);
		}

		internal static bool InUse(Container chest)
		{
			if ((Object)(object)chest == (Object)null)
			{
				return false;
			}
			if (chest.IsInUse())
			{
				return true;
			}
			ZDO val = ShopLink.ReadZdo(((Component)chest).gameObject);
			return val != null && val.GetBool("ptc_inuse", false);
		}

		internal static void Reinforce(GameObject gameObject)
		{
			WearNTear val = Wear(gameObject);
			ZDO val2 = ShopLink.ReadZdo(gameObject);
			if ((Object)(object)val == (Object)null || val2 == null || (Object)(object)gameObject == (Object)null)
			{
				return;
			}
			if ((Object)(object)gameObject.GetComponent<Sign>() != (Object)null)
			{
				val.m_noSupportWear = false;
				val.m_noRoofWear = false;
			}
			int instanceID = ((Object)gameObject).GetInstanceID();
			if (!Scaled.Contains(instanceID))
			{
				Scaled.Add(instanceID);
				val.m_health *= 10f;
				if (!val2.GetBool("ptc_scaled", false))
				{
					val2.Set(ZDOVars.s_health, val.m_health);
					val2.Set("ptc_scaled", true);
				}
			}
		}

		private static WearNTear Wear(GameObject gameObject)
		{
			return ((Object)(object)gameObject != (Object)null) ? gameObject.GetComponent<WearNTear>() : null;
		}

		internal static void OnInventoryChanged(Container chest)
		{
			if (!((Object)(object)chest == (Object)null) && ShopLink.IsLinked(((Component)chest).gameObject))
			{
				StackState[] slots = ShopInventory.ReadChest(chest.GetInventory());
				if (ShopRules.ReadOffer(slots).Valid && !Committed(((Component)chest).gameObject))
				{
					Commit(chest);
				}
				if (!InUse(chest) && !RunningTrade)
				{
					HoldClosed(chest, slots);
					ShopSign.Update(chest);
				}
			}
		}

		internal static void SetOpen(Container chest, bool open)
		{
			if ((Object)(object)chest == (Object)null || !ShopLink.IsLinked(((Component)chest).gameObject))
			{
				return;
			}
			ZNetView component = ((Component)chest).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
			{
				return;
			}
			ZDO zDO = component.GetZDO();
			if (zDO != null)
			{
				zDO.Set("ptc_inuse", open);
			}
			if (open)
			{
				Stop(chest);
				return;
			}
			ShopInventory.RepairPrefabs(chest);
			ShopInventory.Spill(chest);
			StackState[] slots = ShopInventory.ReadChest(chest.GetInventory());
			if (ShopRules.EndsEmpty(slots))
			{
				Begin(chest);
			}
			else
			{
				Stop(chest);
				if (ShopRules.ReadOffer(slots).Valid && !Committed(((Component)chest).gameObject))
				{
					Commit(chest);
				}
			}
			ShopSign.Update(chest);
		}

		internal static void Expire(ZNetView view)
		{
			if ((Object)(object)view == (Object)null || !view.IsValid() || !view.IsOwner() || !ShopLink.IsLinked(((Component)view).gameObject))
			{
				return;

marchiori.utils.localization.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using HarmonyLib;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("marchiori.utils.localization")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ee52b2bfcab53d7e96836822c3d6ec6f3c6f91ae")]
[assembly: AssemblyProduct("marchiori.utils.localization")]
[assembly: AssemblyTitle("marchiori.utils.localization")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Marchiori.Utils.Localization
{
	public static class LanguageFiles
	{
		private const string EnglishFile = "English.csv";

		private static readonly MethodInfo AddWord = AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null);

		public static void Apply(Localization localization, string language, string modDirectory, string tokenPrefix)
		{
			if (localization == null || AddWord == null || string.IsNullOrEmpty(modDirectory) || string.IsNullOrEmpty(tokenPrefix))
			{
				return;
			}
			string text = Find(modDirectory, SafeFileName(language) + ".csv");
			if (text == null)
			{
				text = Find(modDirectory, "English.csv");
			}
			if (text == null)
			{
				return;
			}
			foreach (KeyValuePair<int, string> item in Read(text))
			{
				AddWord.Invoke(localization, new object[2]
				{
					tokenPrefix + "_" + item.Key.ToString(CultureInfo.InvariantCulture),
					item.Value
				});
			}
		}

		public static IEnumerable<KeyValuePair<int, string>> Read(string path)
		{
			string[] array = File.ReadAllLines(path, Encoding.UTF8);
			foreach (string raw in array)
			{
				string line = raw.Trim();
				if (line.Length != 0 && line[0] != '#')
				{
					int split = line.IndexOf('=');
					if (split > 0 && int.TryParse(line.Substring(0, split).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var id))
					{
						yield return new KeyValuePair<int, string>(value: Unquote(line.Substring(split + 1).Trim()), key: id);
					}
				}
			}
		}

		private static string Unquote(string value)
		{
			if (value.Length >= 2 && value[0] == '"' && value[value.Length - 1] == '"')
			{
				return value.Substring(1, value.Length - 2).Replace("\"\"", "\"");
			}
			return value;
		}

		private static string Find(string root, string fileName)
		{
			if (!Directory.Exists(root))
			{
				return null;
			}
			try
			{
				using IEnumerator<string> enumerator = Directory.EnumerateFiles(root, fileName, SearchOption.AllDirectories).GetEnumerator();
				if (enumerator.MoveNext())
				{
					return enumerator.Current;
				}
			}
			catch (IOException)
			{
				return null;
			}
			catch (UnauthorizedAccessException)
			{
				return null;
			}
			return null;
		}

		private static string SafeFileName(string language)
		{
			if (string.IsNullOrEmpty(language))
			{
				return "English";
			}
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char c in invalidFileNameChars)
			{
				language = language.Replace(c.ToString(), "");
			}
			return (language.Length == 0) ? "English" : language;
		}
	}
}

marchiori.utils.notificator.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("marchiori.utils.notificator")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ee52b2bfcab53d7e96836822c3d6ec6f3c6f91ae")]
[assembly: AssemblyProduct("marchiori.utils.notificator")]
[assembly: AssemblyTitle("marchiori.utils.notificator")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Marchiori.Utils.Notificator
{
	public static class Notice
	{
		private sealed class NoticeView : MonoBehaviour
		{
			private CanvasGroup _group;

			private RectTransform _rect;

			private TextMeshProUGUI _label;

			private float _width;

			private float _age;

			private float _y;

			private float _fromY;

			private float _targetY;

			private float _slide = 0.2f;

			private bool _settled;

			public float Height { get; private set; }

			public float FontSize { get; private set; }

			public bool Fresh { get; set; }

			public bool JustShown => _age <= 0f;

			private void Awake()
			{
				_group = ((Component)this).GetComponent<CanvasGroup>();
				_rect = ((Component)this).GetComponent<RectTransform>();
			}

			public void Prepare(TextMeshProUGUI label, float width, float height, float fontSize)
			{
				_label = label;
				_width = width;
				Height = height;
				FontSize = fontSize;
				Fresh = true;
				((Component)this).transform.SetAsLastSibling();
			}

			public void Place(float targetY, bool snap)
			{
				if (snap)
				{
					_y = targetY;
					_fromY = targetY;
					_targetY = targetY;
					_slide = 0.2f;
					Apply();
				}
				else if (!Mathf.Approximately(_targetY, targetY))
				{
					_fromY = _y;
					_targetY = targetY;
					_slide = 0f;
				}
			}

			private void Update()
			{
				Settle();
				if (Hud.IsUserHidden())
				{
					_group.alpha = 0f;
					return;
				}
				float unscaledDeltaTime = Time.unscaledDeltaTime;
				if (_slide < 0.2f)
				{
					_slide += unscaledDeltaTime;
					float num = Mathf.Clamp01(_slide / 0.2f);
					_y = Mathf.Lerp(_fromY, _targetY, num);
					Apply();
				}
				_age += unscaledDeltaTime;
				if (_age <= 4f)
				{
					_group.alpha = 1f;
					return;
				}
				float num2 = (_age - 4f) / 1f;
				if (num2 >= 1f)
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
				else
				{
					_group.alpha = 1f - num2;
				}
			}

			private void Settle()
			{
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: 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)
				if (!_settled && !((Object)(object)_label == (Object)null) && !((Object)(object)_rect == (Object)null))
				{
					_settled = true;
					Rect rect = _rect.rect;
					float width = ((Rect)(ref rect)).width;
					if (width < 1f)
					{
						width = _width;
					}
					float num = Measure(_label, width);
					if (!(num <= Height + 0.5f))
					{
						Height = num;
						Vector2 sizeDelta = _rect.sizeDelta;
						sizeDelta.y = num;
						_rect.sizeDelta = sizeDelta;
						Layout();
					}
				}
			}

			private void Apply()
			{
				//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)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				Vector2 anchoredPosition = _rect.anchoredPosition;
				anchoredPosition.y = _y;
				_rect.anchoredPosition = anchoredPosition;
			}

			private void OnDestroy()
			{
				if (Lines.Remove(this))
				{
					Layout();
				}
			}
		}

		private const float HoldSeconds = 4f;

		private const float FadeSeconds = 1f;

		private const float SlideSeconds = 0.2f;

		private const float GapFactor = 0.35f;

		private const float FromTop = 2f / 3f;

		private static readonly List<NoticeView> Lines = new List<NoticeView>();

		public static void Show(string text)
		{
			if (string.IsNullOrEmpty(text) || Hud.IsUserHidden())
			{
				return;
			}
			MessageHud instance = MessageHud.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.m_messageCenterText == (Object)null))
			{
				NoticeView noticeView = Create(instance.m_messageCenterText, text);
				if (!((Object)(object)noticeView == (Object)null))
				{
					Lines.Add(noticeView);
					Layout();
				}
			}
		}

		private static NoticeView Create(TMP_Text source, string text)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			Canvas canvas = ((Graphic)source).canvas;
			if ((Object)(object)canvas == (Object)null || (Object)(object)source.font == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("MarchioriNotice");
			val.layer = ((Component)canvas).gameObject.layer;
			val.SetActive(false);
			val.transform.SetParent(((Component)canvas).transform, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			float num = 0.3333333f;
			val2.anchorMin = new Vector2(0.5f, num);
			val2.anchorMax = new Vector2(0.5f, num);
			val2.pivot = new Vector2(0.5f, 0.5f);
			val2.anchoredPosition = Vector2.zero;
			TextMeshProUGUI val3 = val.AddComponent<TextMeshProUGUI>();
			((Graphic)val3).raycastTarget = false;
			CopyStyle(val3, source);
			((TMP_Text)val3).text = text;
			float num2 = Width(source, canvas);
			val2.sizeDelta = new Vector2(num2, ((TMP_Text)val3).fontSize);
			val.SetActive(true);
			float num3 = Measure(val3, num2);
			val2.sizeDelta = new Vector2(num2, num3);
			CanvasGroup val4 = val.AddComponent<CanvasGroup>();
			val4.blocksRaycasts = false;
			val4.interactable = false;
			val4.alpha = 1f;
			NoticeView noticeView = val.AddComponent<NoticeView>();
			noticeView.Prepare(val3, num2, num3, ((TMP_Text)val3).fontSize);
			return noticeView;
		}

		private static float Measure(TextMeshProUGUI label, float width)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			if (width < 1f)
			{
				width = 600f;
			}
			Vector2 preferredValues = ((TMP_Text)label).GetPreferredValues(((TMP_Text)label).text, width, 0f);
			float num = preferredValues.y;
			((TMP_Text)label).ForceMeshUpdate(true, true);
			TMP_TextInfo textInfo = ((TMP_Text)label).textInfo;
			if (textInfo != null && textInfo.lineCount > 0 && textInfo.lineInfo != null)
			{
				float num2 = 0f;
				int num3 = textInfo.lineCount;
				if (num3 > textInfo.lineInfo.Length)
				{
					num3 = textInfo.lineInfo.Length;
				}
				for (int i = 0; i < num3; i++)
				{
					num2 += textInfo.lineInfo[i].lineHeight;
				}
				if (num2 > num)
				{
					num = num2;
				}
				Bounds textBounds = ((TMP_Text)label).textBounds;
				float y = ((Bounds)(ref textBounds)).size.y;
				if (y > num)
				{
					num = y;
				}
				float num4 = ((TMP_Text)label).fontSize * 1.2f;
				if (textInfo.lineCount > 1 && num <= num4)
				{
					num = (float)textInfo.lineCount * ((TMP_Text)label).fontSize * 1.25f;
				}
			}
			if (float.IsNaN(num) || num < ((TMP_Text)label).fontSize)
			{
				num = ((TMP_Text)label).fontSize;
			}
			return num;
		}

		private static void Layout()
		{
			float num = 0f;
			for (int i = 0; i < Lines.Count; i++)
			{
				NoticeView noticeView = Lines[i];
				if ((Object)(object)noticeView == (Object)null)
				{
					continue;
				}
				if (i > 0)
				{
					NoticeView noticeView2 = Lines[i - 1];
					if ((Object)(object)noticeView2 != (Object)null)
					{
						num -= (noticeView2.Height + noticeView.Height) * 0.5f + noticeView2.FontSize * 0.35f;
					}
				}
				noticeView.Place(num, noticeView.Fresh || noticeView.JustShown);
				noticeView.Fresh = false;
			}
		}

		private static void CopyStyle(TextMeshProUGUI label, TMP_Text source)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			((TMP_Text)label).font = source.font;
			((TMP_Text)label).fontSharedMaterial = source.fontSharedMaterial;
			((Graphic)label).color = ((Graphic)source).color;
			((TMP_Text)label).enableVertexGradient = source.enableVertexGradient;
			((TMP_Text)label).colorGradient = source.colorGradient;
			((TMP_Text)label).fontStyle = source.fontStyle;
			float num = source.fontSize;
			if (num <= 0f)
			{
				num = source.fontSizeMax;
			}
			if (num <= 0f)
			{
				num = 48f;
			}
			((TMP_Text)label).enableAutoSizing = false;
			((TMP_Text)label).fontSize = num * 0.5f;
			((TMP_Text)label).richText = source.richText;
			((TMP_Text)label).alignment = (TextAlignmentOptions)514;
			((TMP_Text)label).textWrappingMode = (TextWrappingModes)1;
			((TMP_Text)label).overflowMode = (TextOverflowModes)0;
			((TMP_Text)label).characterSpacing = source.characterSpacing;
			((TMP_Text)label).wordSpacing = source.wordSpacing;
			((TMP_Text)label).lineSpacing = source.lineSpacing;
			((TMP_Text)label).paragraphSpacing = source.paragraphSpacing;
		}

		private static float Width(TMP_Text source, Canvas canvas)
		{
			//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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			Rect val = source.rectTransform.rect;
			float width = ((Rect)(ref val)).width;
			if (width >= 100f)
			{
				return width;
			}
			float num = ((canvas.scaleFactor > 0.01f) ? canvas.scaleFactor : 1f);
			val = canvas.pixelRect;
			return ((Rect)(ref val)).width / num * 0.7f;
		}
	}
}

marchiori.utils.signtextmanager.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("marchiori.utils.signtextmanager")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ee52b2bfcab53d7e96836822c3d6ec6f3c6f91ae")]
[assembly: AssemblyProduct("marchiori.utils.signtextmanager")]
[assembly: AssemblyTitle("marchiori.utils.signtextmanager")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Marchiori.Utils.SignTextManager
{
	public static class SignText
	{
		private static readonly Dictionary<int, float> MaxFonts = new Dictionary<int, float>();

		public static void Present(Sign sign, string text)
		{
			if (!((Object)(object)sign == (Object)null))
			{
				string text2 = text ?? "";
				sign.m_characterLimit = 240;
				Fit(sign.m_textWidget, text2);
				sign.SetText(text2);
				Fit(sign.m_textWidget, text2);
			}
		}

		public static void Fit(TextMeshProUGUI widget, string text)
		{
			//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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)widget == (Object)null))
			{
				Rect rect = ((TMP_Text)widget).rectTransform.rect;
				float num = ((Rect)(ref rect)).width;
				float num2 = ((Rect)(ref rect)).height;
				if (num < 1f || num2 < 1f)
				{
					Vector2 sizeDelta = ((TMP_Text)widget).rectTransform.sizeDelta;
					num = Mathf.Abs(sizeDelta.x);
					num2 = Mathf.Abs(sizeDelta.y);
				}
				((TMP_Text)widget).textWrappingMode = (TextWrappingModes)1;
				((TMP_Text)widget).overflowMode = (TextOverflowModes)3;
				((TMP_Text)widget).enableAutoSizing = false;
				((TMP_Text)widget).fontSize = SignTextFit.FontSize(text, num, num2, Maximum(widget));
			}
		}

		private static float Maximum(TextMeshProUGUI widget)
		{
			int instanceID = ((Object)widget).GetInstanceID();
			if (MaxFonts.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			float num = ((TMP_Text)widget).fontSize;
			if (num <= 1f)
			{
				num = ((TMP_Text)widget).fontSizeMax;
			}
			if (num <= 1f)
			{
				num = 36f;
			}
			MaxFonts[instanceID] = num;
			return num;
		}
	}
	public static class SignTextFit
	{
		public const int Lines = 3;

		public const int CharacterLimit = 240;

		public const float GlyphWidthFactor = 0.6f;

		public const float LineHeightFactor = 1.25f;

		public static string Visible(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			for (int i = 0; i < text.Length; i++)
			{
				if (text[i] == '<')
				{
					int num = text.IndexOf('>', i + 1);
					if (num > i && IsTag(text, i, num))
					{
						i = num;
						continue;
					}
				}
				stringBuilder.Append(text[i]);
			}
			return stringBuilder.ToString();
		}

		public static float FontSize(string text, float width, float height, float maxSize)
		{
			if (maxSize < 1f)
			{
				maxSize = 1f;
			}
			if (width < 1f || height < 1f)
			{
				return maxSize;
			}
			string visible = Visible(text);
			if (Fits(visible, width, height, maxSize))
			{
				return maxSize;
			}
			float num = 1f;
			float num2 = maxSize;
			for (int i = 0; i < 16; i++)
			{
				float num3 = (num + num2) * 0.5f;
				if (Fits(visible, width, height, num3))
				{
					num = num3;
				}
				else
				{
					num2 = num3;
				}
			}
			return num;
		}

		private static bool IsTag(string text, int start, int end)
		{
			if (end <= start + 1 || end - start > 48)
			{
				return false;
			}
			for (int i = start + 1; i < end; i++)
			{
				char c = text[i];
				if (c == ' ' || c == '<' || c == '\n' || c == '\r')
				{
					return false;
				}
			}
			return true;
		}

		private static bool Fits(string visible, float width, float height, float font)
		{
			float num = font * 0.6f;
			float num2 = font * 1.25f;
			if (num < 0.01f || num2 < 0.01f)
			{
				return true;
			}
			if (num2 > height + 0.5f)
			{
				return false;
			}
			int num3 = (int)(width / num);
			if (num3 < 1)
			{
				return false;
			}
			if (LongestWord(visible) > num3)
			{
				return false;
			}
			int num4 = WrapLines(visible, num3);
			if (num4 > 3)
			{
				return false;
			}
			return (float)num4 * num2 <= height + 0.5f;
		}

		private static int LongestWord(string text)
		{
			int num = 0;
			int num2 = 0;
			foreach (char c in text)
			{
				if (c == ' ' || c == '\n' || c == '\r')
				{
					if (num2 > num)
					{
						num = num2;
					}
					num2 = 0;
				}
				else
				{
					num2++;
				}
			}
			return (num2 > num) ? num2 : num;
		}

		private static int WrapLines(string text, int perLine)
		{
			if (string.IsNullOrEmpty(text))
			{
				return 1;
			}
			int num = 1;
			int num2 = 0;
			int i = 0;
			while (i < text.Length)
			{
				if (text[i] == '\r')
				{
					i++;
					continue;
				}
				if (text[i] == '\n')
				{
					num++;
					num2 = 0;
					i++;
					continue;
				}
				int num3 = i;
				for (; i < text.Length && text[i] != ' ' && text[i] != '\n' && text[i] != '\r'; i++)
				{
				}
				int num4 = i - num3;
				if (num2 > 0 && num2 + 1 + num4 > perLine)
				{
					num++;
					num2 = num4;
				}
				else
				{
					num2 += ((num2 != 0) ? 1 : 0) + num4;
				}
				if (i < text.Length && text[i] == ' ')
				{
					i++;
				}
			}
			return num;
		}
	}
}