Decompiled source of PaintYourBuild v1.0.0

BepInEx/plugins/PaintYourBuild/PaintYourBuild.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using NaturalPaintLogic;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyVersion("0.1.2.0")]
[BepInPlugin("com.lesly.valheim.paintyourbuild", "Paint Your Build", "0.1.2")]
public sealed class NaturalPaintPlugin : BaseUnityPlugin
{
	internal struct BrushTarget
	{
		internal Piece Piece;

		internal WearNTear Wear;

		internal Vector3 Point;
	}

	private sealed class NetworkPaintStore : IPaintStore
	{
		private readonly ZNetView _view;

		public bool CanWrite
		{
			get
			{
				if (Object.op_Implicit((Object)(object)_view) && _view.IsValid())
				{
					return _view.IsOwner();
				}
				return false;
			}
		}

		public int FinishId
		{
			get
			{
				return _view.GetZDO().GetInt(PaintHash, 0);
			}
			set
			{
				if (!CanWrite)
				{
					throw new InvalidOperationException("Piece ownership changed");
				}
				_view.GetZDO().Set(PaintHash, value, false);
			}
		}

		internal NetworkPaintStore(ZNetView view)
		{
			_view = view;
		}
	}

	private sealed class PaintedPiece
	{
		internal WearNTear Wear;

		internal ZNetView View;

		internal int Saved;

		internal bool Highlighted;

		internal bool Built;

		internal readonly List<Surface> Surfaces = new List<Surface>();
	}

	private sealed class Slot
	{
		internal int Index;

		internal int Property;

		internal Color Base;
	}

	private sealed class Surface
	{
		internal Renderer Renderer;

		internal PaintedPiece Piece;

		internal readonly List<Slot> Slots = new List<Slot>();

		internal readonly MaterialPropertyBlock Block = new MaterialPropertyBlock();

		internal bool Applied;
	}

	private sealed class GameInventory : IBrushInventory
	{
		private sealed class Snapshot
		{
			internal List<ItemData> Items;

			internal int[] Stacks;
		}

		private readonly Player _player;

		private readonly Inventory _inventory;

		internal bool LastCreatedCheated;

		public int FreeSlots => _inventory.GetEmptySlots();

		internal GameInventory(Player player)
		{
			_player = player;
			_inventory = ((Humanoid)player).GetInventory();
		}

		private static string ResourceName(string prefab)
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
			if (!Object.op_Implicit((Object)(object)itemPrefab))
			{
				throw new InvalidOperationException("Missing resource prefab " + prefab);
			}
			return itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_name;
		}

		public int Count(string resource)
		{
			return _inventory.CountItems(ResourceName(resource), -1, true);
		}

		public object Capture()
		{
			List<ItemData> list = new List<ItemData>(_inventory.GetAllItems());
			return new Snapshot
			{
				Items = list,
				Stacks = list.Select((ItemData item) => item.m_stack).ToArray()
			};
		}

		public void Restore(object state)
		{
			Snapshot snapshot = (Snapshot)state;
			List<ItemData> allItems = _inventory.GetAllItems();
			allItems.Clear();
			allItems.AddRange(snapshot.Items);
			for (int i = 0; i < allItems.Count; i++)
			{
				allItems[i].m_stack = snapshot.Stacks[i];
			}
			try
			{
				NotifyInventory.Invoke(_inventory, new object[2] { false, false });
			}
			catch (Exception ex)
			{
				Instance.ReportOnce("rollback.notify", ex);
			}
		}

		public bool AddBrush()
		{
			ItemData val = CreateBrushItem();
			LastCreatedCheated |= Instance._craftCompatibility.IsItemCheated(val);
			if (_inventory.AddItem(val))
			{
				return _inventory.ContainsItem(val);
			}
			return false;
		}

		internal ItemData CreateBrushItem()
		{
			//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)
			ItemData val = BrushPrefab.GetComponent<ItemDrop>().m_itemData.Clone();
			val.m_dropPrefab = BrushPrefab;
			val.m_stack = 1;
			val.m_quality = 1;
			val.m_variant = 0;
			val.m_worldLevel = (byte)Game.m_worldLevel;
			val.m_crafterID = _player.GetPlayerID();
			val.m_crafterName = _player.GetPlayerName();
			val.m_gridPos = new Vector2i(-1, -1);
			val.m_equipped = false;
			val.m_durability = 100f;
			CraftCompatibility compatibility = Instance._craftCompatibility;
			if (compatibility.HasItemFlag)
			{
				string woodName = ResourceName("Wood");
				bool resourceCheated = _inventory.GetAllItems().Any((ItemData resource) => resource.m_shared.m_name == woodName && resource.m_worldLevel >= Game.m_worldLevel && compatibility.IsItemCheated(resource));
				int? stationCheatedKey = compatibility.StationCheatedKey;
				CraftingStation currentCraftingStation = _player.GetCurrentCraftingStation();
				object obj;
				if (currentCraftingStation == null)
				{
					obj = null;
				}
				else
				{
					ZNetView component = ((Component)currentCraftingStation).GetComponent<ZNetView>();
					obj = ((component != null) ? component.GetZDO() : null);
				}
				ZDO val2 = (ZDO)obj;
				bool stationCheated = stationCheatedKey.HasValue && val2 != null && val2.GetBool(stationCheatedKey.Value, false);
				compatibility.SetItemMetadata(val, _player.NoCostCheat(), resourceCheated, stationCheated);
			}
			return val;
		}

		public void Spend(string resource, int amount)
		{
			_inventory.RemoveItem(ResourceName(resource), amount, -1, true);
		}
	}

	private GameObject _prefabRoot;

	private string _brushAnimation;

	private ObjectDB _registeredDb;

	private ZNetScene _registeredScene;

	private bool _registering;

	private Sprite _icon;

	private readonly List<Material> _materials = new List<Material>();

	private ConfigEntry<float> _soundVolume;

	private Hud _brushHud;

	private readonly AudioSource[] _brushSources = (AudioSource[])(object)new AudioSource[4];

	private AudioClip _brushSound;

	private AudioMixerGroup _brushMixer;

	private int _nextBrushSource;

	private const string HotbarIndicatorName = "PaintYourBuild_EquipmentIndicator";

	private static FieldInfo HotbarElements;

	private static FieldInfo HotbarElementObject;

	private static MethodInfo UpdateHotbarIcons;

	private readonly List<GameObject> _hotbarIndicators = new List<GameObject>();

	private BrushTarget _hoverTarget;

	private readonly Dictionary<WearNTear, PaintedPiece> _painted = new Dictionary<WearNTear, PaintedPiece>();

	private readonly Dictionary<Renderer, Surface> _surfaces = new Dictionary<Renderer, Surface>();

	private readonly List<WearNTear> _deadPieces = new List<WearNTear>();

	private WearNTear _previewPiece;

	private int _previewFinish;

	private float _nextPaintSync;

	private static readonly string[] ExcludedMaterials = new string[15]
	{
		"iron", "metal", "bronze", "copper", "nail", "chain", "rope", "glass", "crystal", "snow",
		"wet", "flame", "particle", "fire", "smoke"
	};

	private ConfigEntry<KeyboardShortcut> _paletteKey;

	private ConfigEntry<int> _selectedId;

	private GameObject _paletteCanvas;

	private readonly Button[] _paletteButtons = (Button[])(object)new Button[15];

	private readonly Image[] _swatchImages = (Image[])(object)new Image[12];

	private readonly TMP_Text[] _swatchLabels = (TMP_Text[])(object)new TMP_Text[12];

	private readonly Button[] _paletteTabs = (Button[])(object)new Button[2];

	private readonly PaletteReleaseGuard _releaseGuard = new PaletteReleaseGuard();

	private static readonly string[] PaletteButtonsHeld = new string[13]
	{
		"JoyButtonA", "JoyButtonB", "JoyButtonX", "JoyButtonY", "JoyBuildMenu", "JoyDPadLeft", "JoyDPadRight", "JoyDPadUp", "JoyDPadDown", "JoyLBumper",
		"JoyRBumper", "JoyLTrigger", "JoyRTrigger"
	};

	private TMP_Text _paletteCaption;

	private WearNTear _paletteTarget;

	private int _focusSlot;

	private int _pageIndex;

	private int _openedFrame;

	public const string PluginGuid = "com.lesly.valheim.paintyourbuild";

	public const string PluginName = "Paint Your Build";

	public const string PluginVersion = "0.1.2";

	internal const string BrushPrefabName = "Lesly_Paintbrush";

	internal const string PaintKey = "Lesly_PaintYourBuild_Finish_v1";

	internal static readonly int PaintHash = StringExtensionMethods.GetStableHashCode("Lesly_PaintYourBuild_Finish_v1");

	internal static NaturalPaintPlugin Instance;

	internal static GameObject BrushPrefab;

	internal static Recipe BrushRecipe;

	internal static bool Ready;

	private Harmony _harmony;

	private float _nextMaintenance;

	private float _nextUse;

	private int _lastCraftFrame = -1;

	private Recipe _lastSelected;

	private ObjectDB _selfTestDb;

	private bool _selfTestPassed;

	private ConfigEntry<KeyboardShortcut> _diagnosticKey;

	private CraftCompatibility _craftCompatibility;

	private readonly HashSet<string> _reportedErrors = new HashSet<string>();

	internal static FieldInfo SelectedRecipeField;

	internal static PropertyInfo SelectedRecipeProperty;

	internal static PropertyInfo SelectedItemProperty;

	internal static MethodInfo NativeCraftComplete;

	internal static MethodInfo RefreshPanel;

	internal static MethodInfo NotifyInventory;

	private static MethodInfo AddKnownRecipe;

	private static FieldInfo DbByHash;

	private static FieldInfo DbByData;

	private static FieldInfo SceneByHash;

	private static FieldInfo RemoveRayMask;

	private static FieldInfo SnappingIcon;

	internal static bool PaletteOpen
	{
		get
		{
			if (Object.op_Implicit((Object)(object)Instance) && Object.op_Implicit((Object)(object)Instance._paletteCanvas))
			{
				return Instance._paletteCanvas.activeSelf;
			}
			return false;
		}
	}

	internal static bool OverlayBlocksInput
	{
		get
		{
			if (Ready && Object.op_Implicit((Object)(object)Instance))
			{
				if (!PaletteOpen)
				{
					return Instance._releaseGuard.Blocked;
				}
				return true;
			}
			return false;
		}
	}

	private Finish SelectedFinish => Palette.Get(_selectedId.Value);

	internal static void SafeRegister(ObjectDB db)
	{
		if (!Ready || !Object.op_Implicit((Object)(object)Instance) || !Object.op_Implicit((Object)(object)db))
		{
			return;
		}
		try
		{
			Instance.Register(db);
		}
		catch (Exception ex)
		{
			Instance.ReportOnce("registration", ex);
		}
	}

	private void Register(ObjectDB db)
	{
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0299: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02af: Expected O, but got Unknown
		if (_registering || ((Object)(object)_registeredDb == (Object)(object)db && (Object)(object)_registeredScene == (Object)(object)ZNetScene.instance && Object.op_Implicit((Object)(object)BrushPrefab) && Object.op_Implicit((Object)(object)BrushRecipe) && (Object)(object)db.GetItemPrefab("Lesly_Paintbrush") == (Object)(object)BrushPrefab && db.m_recipes.Contains(BrushRecipe)))
		{
			return;
		}
		_registering = true;
		try
		{
			GameObject itemPrefab = db.GetItemPrefab("Hammer");
			GameObject itemPrefab2 = db.GetItemPrefab("Wood");
			if (!Object.op_Implicit((Object)(object)itemPrefab) || !Object.op_Implicit((Object)(object)itemPrefab2))
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)BrushPrefab))
			{
				CreatePrefab(itemPrefab);
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode("Lesly_Paintbrush");
			Dictionary<int, GameObject> obj = (Dictionary<int, GameObject>)DbByHash.GetValue(db);
			if (obj.TryGetValue(stableHashCode, out var value) && Object.op_Implicit((Object)(object)value) && (Object)(object)value != (Object)(object)BrushPrefab)
			{
				throw new InvalidOperationException("Brush hash already belongs to " + ((Object)value).name + ". Remove duplicate mod copies.");
			}
			if (!db.m_items.Contains(BrushPrefab))
			{
				db.m_items.Add(BrushPrefab);
			}
			obj[stableHashCode] = BrushPrefab;
			ItemDrop component = BrushPrefab.GetComponent<ItemDrop>();
			((Dictionary<SharedData, GameObject>)DbByData.GetValue(db))[component.m_itemData.m_shared] = BrushPrefab;
			ZNetScene instance = ZNetScene.instance;
			if (Object.op_Implicit((Object)(object)instance))
			{
				Dictionary<int, GameObject> obj2 = (Dictionary<int, GameObject>)SceneByHash.GetValue(instance);
				if (obj2.TryGetValue(stableHashCode, out value) && Object.op_Implicit((Object)(object)value) && (Object)(object)value != (Object)(object)BrushPrefab)
				{
					throw new InvalidOperationException("Duplicate brush network prefab");
				}
				if (!instance.m_prefabs.Contains(BrushPrefab))
				{
					instance.m_prefabs.Add(BrushPrefab);
				}
				obj2[stableHashCode] = BrushPrefab;
			}
			CraftingStation val = FindWorkbench(db, itemPrefab, instance);
			if (Object.op_Implicit((Object)(object)val))
			{
				if (!Object.op_Implicit((Object)(object)BrushRecipe))
				{
					BrushRecipe = ScriptableObject.CreateInstance<Recipe>();
					((Object)BrushRecipe).name = "Recipe_Paintbrush";
				}
				BrushRecipe.m_item = component;
				BrushRecipe.m_amount = 1;
				BrushRecipe.m_enabled = true;
				BrushRecipe.m_noCraftOnlyUpgrade = false;
				BrushRecipe.m_minStationLevel = 1;
				BrushRecipe.m_craftingStation = val;
				BrushRecipe.m_repairStation = val;
				BrushRecipe.m_requireOnlyOneIngredient = false;
				BrushRecipe.m_resources = (Requirement[])(object)new Requirement[1]
				{
					new Requirement
					{
						m_resItem = itemPrefab2.GetComponent<ItemDrop>(),
						m_amount = 2,
						m_amountPerLevel = 0,
						m_recover = true
					}
				};
				db.m_recipes.RemoveAll((Recipe r) => Object.op_Implicit((Object)(object)r) && (Object)(object)r != (Object)(object)BrushRecipe && IsBrushRecipe(r));
				if (!db.m_recipes.Contains(BrushRecipe))
				{
					db.m_recipes.Add(BrushRecipe);
				}
				_registeredDb = db;
				_registeredScene = instance;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[register.ok] prefab=Lesly_Paintbrush; hash=" + stableHashCode + "; activeSelf=" + BrushPrefab.activeSelf + "; activeInHierarchy=" + BrushPrefab.activeInHierarchy + "; station=" + val.m_name + "; cost=2 Wood; network=" + ((Object)(object)instance != (Object)null)));
			}
		}
		finally
		{
			_registering = false;
		}
	}

	private static CraftingStation FindWorkbench(ObjectDB db, GameObject hammer, ZNetScene scene)
	{
		GameObject val = (Object.op_Implicit((Object)(object)scene) ? scene.GetPrefab("piece_workbench") : null);
		if (Object.op_Implicit((Object)(object)val))
		{
			return val.GetComponent<CraftingStation>();
		}
		PieceTable buildPieces = hammer.GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces;
		if (Object.op_Implicit((Object)(object)buildPieces))
		{
			foreach (GameObject piece in buildPieces.m_pieces)
			{
				if (Object.op_Implicit((Object)(object)piece) && ((Object)piece).name == "piece_workbench")
				{
					return piece.GetComponent<CraftingStation>();
				}
			}
		}
		foreach (Recipe recipe in db.m_recipes)
		{
			if (Object.op_Implicit((Object)(object)recipe) && Object.op_Implicit((Object)(object)recipe.m_craftingStation) && recipe.m_craftingStation.m_name == "$piece_workbench")
			{
				return recipe.m_craftingStation;
			}
		}
		return null;
	}

	private void CreatePrefab(GameObject hammer)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Expected O, but got Unknown
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Expected O, but got Unknown
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Expected O, but got Unknown
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Expected O, but got Unknown
		//IL_0290: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_030e: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0343: Unknown result type (might be due to invalid IL or missing references)
		//IL_039c: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)_prefabRoot))
		{
			_prefabRoot = new GameObject("NaturalPaint_PrefabRoot");
			_prefabRoot.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_prefabRoot);
		}
		GameObject val = Object.Instantiate<GameObject>(hammer, _prefabRoot.transform, false);
		try
		{
			((Object)val).name = "Lesly_Paintbrush";
			val.SetActive(true);
			ItemDrop component = val.GetComponent<ItemDrop>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new InvalidOperationException("Hammer has no ItemDrop");
			}
			_brushAnimation = hammer.GetComponent<ItemDrop>().m_itemData.m_shared.m_attack.m_attackAnimation;
			component.m_itemData = new ItemData();
			ItemData itemData = component.m_itemData;
			SharedData val2 = new SharedData();
			val2.m_name = "Paintbrush";
			val2.m_description = "Paint wooden and stone building pieces in natural shades. Right-click or P opens the palette; left-click paints. Includes a live preview and Restore original.";
			val2.m_itemType = (ItemType)19;
			val2.m_animationState = (AnimationState)1;
			val2.m_maxStackSize = 1;
			val2.m_maxQuality = 1;
			val2.m_weight = 0.5f;
			val2.m_useDurability = false;
			val2.m_maxDurability = 100f;
			val2.m_equipDuration = 0.25f;
			val2.m_buildPieces = null;
			val2.m_dlc = "";
			val2.m_attackForce = 0f;
			val2.m_variants = 1;
			val2.m_attack = new Attack();
			val2.m_secondaryAttack = new Attack();
			val2.m_icons = (Sprite[])(Application.isBatchMode ? ((Array)hammer.GetComponent<ItemDrop>().m_itemData.m_shared.m_icons) : ((Array)new Sprite[1] { LoadIcon() }));
			itemData.m_shared = val2;
			component.m_itemData.m_dropPrefab = val;
			component.m_itemData.m_quality = 1;
			component.m_itemData.m_stack = 1;
			component.m_itemData.m_durability = 100f;
			if (Application.isBatchMode)
			{
				BrushPrefab = val;
				return;
			}
			Transform val3 = val.transform.Find("attach");
			if (!Object.op_Implicit((Object)(object)val3))
			{
				throw new InvalidOperationException("Hammer attach transform missing");
			}
			Material val4 = (from r in ((Component)val3).GetComponentsInChildren<Renderer>(true)
				select r.sharedMaterial).FirstOrDefault((Func<Material, bool>)((Material m) => Object.op_Implicit((Object)(object)m) && Object.op_Implicit((Object)(object)m.shader)));
			if (!Object.op_Implicit((Object)(object)val4))
			{
				throw new InvalidOperationException("No supported material on Hammer");
			}
			Renderer[] componentsInChildren = ((Component)val3).GetComponentsInChildren<Renderer>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				componentsInChildren[num].enabled = false;
			}
			Material material = ColoredMaterial(val4, new Color(0.6f, 0.4f, 0.2f), "BrushWood");
			Material material2 = ColoredMaterial(val4, new Color(0.4f, 0.26f, 0.13f), "BrushBinding");
			Material material3 = ColoredMaterial(val4, new Color(0.68f, 0.55f, 0.36f), "BrushBristles");
			MakePart(val3, "Handle", new Vector3(0f, 0.1f, 0f), new Vector3(0.035f, 0.17f, 0.035f), material);
			MakePart(val3, "Binding", new Vector3(0f, 0.285f, 0f), new Vector3(0.067f, 0.04f, 0.067f), material2);
			for (int num2 = 0; num2 < 7; num2++)
			{
				float num3 = (float)num2 * (float)Math.PI * 2f / 7f;
				MakePart(val3, "Bristle" + num2, new Vector3(Mathf.Cos(num3) * 0.023f, 0.355f, Mathf.Sin(num3) * 0.023f), new Vector3(0.019f, 0.055f + (float)(num2 % 3) * 0.003f, 0.019f), material3);
			}
			BrushPrefab = val;
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			throw;
		}
	}

	private Material ColoredMaterial(Material source, Color color, string name)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_003e: 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)
		Material val = new Material(source)
		{
			name = name
		};
		if (val.HasProperty("_MainTex"))
		{
			val.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture);
		}
		if (val.HasProperty("_Color"))
		{
			val.SetColor("_Color", color);
		}
		if (val.HasProperty("_BaseColor"))
		{
			val.SetColor("_BaseColor", color);
		}
		_materials.Add(val);
		return val;
	}

	private static void MakePart(Transform parent, string name, Vector3 position, Vector3 scale, Material material)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		GameObject obj = GameObject.CreatePrimitive((PrimitiveType)2);
		((Object)obj).name = name;
		obj.transform.SetParent(parent, false);
		obj.transform.localPosition = position;
		obj.transform.localScale = scale;
		Collider component = obj.GetComponent<Collider>();
		component.enabled = false;
		Object.Destroy((Object)(object)component);
		obj.GetComponent<Renderer>().sharedMaterial = material;
		obj.layer = ((Component)parent).gameObject.layer;
	}

	private Sprite LoadIcon()
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Expected O, but got Unknown
		//IL_0098: 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)
		if (Object.op_Implicit((Object)(object)_icon))
		{
			return _icon;
		}
		using Stream stream = typeof(NaturalPaintPlugin).Assembly.GetManifestResourceStream("Lesly.PaintYourBuild.NaturalPaintIcon.png");
		if (stream == null)
		{
			throw new InvalidOperationException("Embedded brush icon missing");
		}
		using MemoryStream memoryStream = new MemoryStream();
		stream.CopyTo(memoryStream);
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
		if (!ImageConversion.LoadImage(val, memoryStream.ToArray(), true))
		{
			Object.Destroy((Object)(object)val);
			throw new InvalidOperationException("Invalid brush PNG");
		}
		((Object)val).name = "NaturalPaintIcon";
		_icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 128f);
		return _icon;
	}

	private void ReleaseAssets()
	{
		foreach (Material material in _materials)
		{
			if (Object.op_Implicit((Object)(object)material))
			{
				Object.Destroy((Object)(object)material);
			}
		}
		if (Object.op_Implicit((Object)(object)_icon))
		{
			Object.Destroy((Object)(object)_icon.texture);
			Object.Destroy((Object)(object)_icon);
		}
		if (Object.op_Implicit((Object)(object)_prefabRoot))
		{
			Object.Destroy((Object)(object)_prefabRoot);
		}
		if (Object.op_Implicit((Object)(object)BrushRecipe))
		{
			Object.Destroy((Object)(object)BrushRecipe);
		}
		BrushRecipe = null;
		BrushPrefab = null;
	}

	private void BindFeedbackConfig()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		_soundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "BrushVolume", 0.65f, new ConfigDescription("Brushing sound volume; follows the game's effects volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
	}

	internal static bool BrushSelected(Player player)
	{
		if (Ready && Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer)
		{
			return IsBrush(((Humanoid)player).RightItem);
		}
		return false;
	}

	private static bool CanShowBrush(Player player)
	{
		if (BrushSelected(player))
		{
			return CanUseTool(player);
		}
		return false;
	}

	internal void UpdateBrushHud(Hud hud, Player player)
	{
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			_brushHud = hud;
			bool flag = CanShowBrush(player) && !PaletteOpen;
			hud.m_buildHud.SetActive(flag);
			if (!flag)
			{
				if (!PaletteOpen)
				{
					ClearPreview();
				}
				return;
			}
			if (Object.op_Implicit((Object)(object)hud.m_buildUi) && ((Component)hud.m_buildUi).gameObject.activeSelf)
			{
				hud.m_buildUi.Close();
			}
			if (Object.op_Implicit((Object)(object)hud.m_closePieceSelectionButton))
			{
				((Component)hud.m_closePieceSelectionButton).gameObject.SetActive(false);
			}
			object? value = SnappingIcon.GetValue(hud);
			Image val = (Image)((value is Image) ? value : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				((Behaviour)val).enabled = false;
			}
			hud.m_buildSelection.text = "Paint · " + SelectedFinish.Name;
			((Behaviour)hud.m_buildIcon).enabled = true;
			hud.m_buildIcon.sprite = _icon;
			if (TryGetBrushTarget(player, out var target))
			{
				_hoverTarget = target;
				if (PrivateArea.CheckAccess(((Component)target.Piece).transform.position, 0f, false, false))
				{
					SetPreview(target.Wear, SelectedFinish.Id);
					hud.m_pieceDescription.text = "Preview · Click / attack to apply\nRight-click / P / build menu: palette";
				}
				else
				{
					ClearPreview();
					hud.m_pieceDescription.text = "Protected by a ward";
				}
			}
			else
			{
				ClearHover();
				hud.m_pieceDescription.text = "Aim at wood or stone within 5 metres\nRight-click / P / build menu: palette";
			}
			GameObject[] requirementItems = hud.m_requirementItems;
			for (int i = 0; i < requirementItems.Length; i++)
			{
				requirementItems[i].SetActive(false);
			}
		}
		catch (Exception ex)
		{
			ReportOnce("paint.hud", ex);
		}
	}

	internal void UpdateBrushCrosshair(Hud hud, Player player)
	{
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		if (CanShowBrush(player) && !PaletteOpen && Object.op_Implicit((Object)(object)_hoverTarget.Wear) && Object.op_Implicit((Object)(object)_hoverTarget.Piece))
		{
			string name = ReadFinish(_hoverTarget.Wear).Name;
			((TMP_Text)hud.m_hoverName).text = Localization.instance.Localize(_hoverTarget.Piece.m_name) + "\n<color=#F3DCAD>" + name + "</color> · Preview: " + SelectedFinish.Name;
			((Graphic)hud.m_crosshair).color = new Color(0.95f, 0.86f, 0.68f);
			((Component)hud.m_pieceHealthRoot).gameObject.SetActive(true);
			hud.m_pieceHealthBar.SetValue(_hoverTarget.Wear.GetHealthPercentage());
		}
	}

	internal void ClearHover()
	{
		_hoverTarget = default(BrushTarget);
		ClearPreview();
	}

	internal void PlayBrushSound(Vector3 point)
	{
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		if (Application.isBatchMode || _soundVolume.Value <= 0f)
		{
			return;
		}
		try
		{
			if (!Object.op_Implicit((Object)(object)_brushSound))
			{
				using Stream stream = typeof(NaturalPaintPlugin).Assembly.GetManifestResourceStream("Lesly.PaintYourBuild.BrushRub.wav");
				PcmWave pcmWave = PcmWave.Read(stream);
				_brushSound = AudioClip.Create("NaturalPaint_ResinRub", pcmWave.Samples.Length / pcmWave.Channels, pcmWave.Channels, pcmWave.SampleRate, false);
				if (!_brushSound.SetData(pcmWave.Samples, 0))
				{
					Object.Destroy((Object)(object)_brushSound);
					_brushSound = null;
					throw new InvalidDataException("AudioClip.SetData failed");
				}
			}
			if (!Object.op_Implicit((Object)(object)_brushMixer) && Object.op_Implicit((Object)(object)AudioMan.instance))
			{
				AudioMixer masterMixer = AudioMan.instance.m_masterMixer;
				if (Object.op_Implicit((Object)(object)masterMixer))
				{
					_brushMixer = ((IEnumerable<AudioMixerGroup>)masterMixer.FindMatchingGroups("")).FirstOrDefault((Func<AudioMixerGroup, bool>)((AudioMixerGroup group) => string.Equals(((Object)group).name, "SFX", StringComparison.OrdinalIgnoreCase)));
				}
				if (!Object.op_Implicit((Object)(object)_brushMixer))
				{
					_brushMixer = AudioMan.instance.m_guiMixer;
				}
			}
			int num = _nextBrushSource++ % _brushSources.Length;
			AudioSource val = _brushSources[num];
			if (!Object.op_Implicit((Object)(object)val))
			{
				GameObject val2 = new GameObject("NaturalPaint_RubAudio" + num);
				val2.transform.SetParent(((Component)this).transform, false);
				val = val2.AddComponent<AudioSource>();
				val.playOnAwake = false;
				val.loop = false;
				val.spatialBlend = 1f;
				val.minDistance = 4f;
				val.maxDistance = 18f;
				val.rolloffMode = (AudioRolloffMode)1;
				val.dopplerLevel = 0f;
				_brushSources[num] = val;
			}
			((Component)val).transform.position = point;
			val.outputAudioMixerGroup = _brushMixer;
			val.pitch = Random.Range(0.96f, 1.04f);
			val.PlayOneShot(_brushSound, _soundVolume.Value * (Object.op_Implicit((Object)(object)_brushMixer) ? 1f : AudioMan.GetSFXVolume()));
		}
		catch (Exception ex)
		{
			ReportOnce("brush.audio", ex);
		}
	}

	private void ReleaseFeedback()
	{
		ClearHover();
		if (Object.op_Implicit((Object)(object)_brushHud) && Object.op_Implicit((Object)(object)Player.m_localPlayer) && IsBrush(((Humanoid)Player.m_localPlayer).RightItem))
		{
			_brushHud.m_buildHud.SetActive(false);
		}
		AudioSource[] brushSources = _brushSources;
		foreach (AudioSource val in brushSources)
		{
			if (Object.op_Implicit((Object)(object)val))
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}
		if (Object.op_Implicit((Object)(object)_brushSound))
		{
			Object.Destroy((Object)(object)_brushSound);
		}
	}

	private static void ResolveHotbarApis()
	{
		UpdateHotbarIcons = Method(typeof(HotkeyBar), "UpdateIcons", typeof(Player));
		HotbarElements = Field(typeof(HotkeyBar), "m_elements");
		HotbarElementObject = Field(HotbarElements.FieldType.GetGenericArguments()[0], "m_go");
	}

	internal static void RefreshBlockedHotbar(HotkeyBar bar)
	{
		if (!Ready || !Object.op_Implicit((Object)(object)Instance))
		{
			return;
		}
		try
		{
			UpdateHotbarIcons.Invoke(bar, new object[1] { Player.m_localPlayer });
		}
		catch (Exception ex)
		{
			Instance.ReportOnce("hotbar.refresh", ex);
		}
	}

	internal void UpdateBrushHotbar(HotkeyBar bar, Player player, int selectedSlot)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Expected O, but got Unknown
		try
		{
			IList list = (IList)HotbarElements.GetValue(bar);
			Inventory val = ((Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead()) ? ((Humanoid)player).GetInventory() : null);
			bool flag = ZInput.IsGamepadActive();
			for (int i = 0; i < list.Count; i++)
			{
				GameObject val2 = (GameObject)HotbarElementObject.GetValue(list[i]);
				if (!Object.op_Implicit((Object)(object)val2))
				{
					continue;
				}
				ItemData val3 = ((val != null) ? val.GetItemAt(i, 0) : null);
				bool num = IsBrush(val3);
				bool flag2 = num && ((Humanoid)player).RightItem == val3;
				bool flag3 = num && flag && selectedSlot == i;
				Transform val4 = val2.transform.Find("PaintYourBuild_EquipmentIndicator");
				if (Object.op_Implicit((Object)(object)val4) || flag2 || flag3)
				{
					if (!Object.op_Implicit((Object)(object)val4))
					{
						val4 = CreateHotbarIndicator(val2.transform);
					}
					((Component)val4).gameObject.SetActive(flag2 || flag3);
					((Component)val4.GetChild(0)).gameObject.SetActive(flag3);
					((Component)val4.GetChild(1)).gameObject.SetActive(flag2);
					val4.SetAsLastSibling();
				}
			}
		}
		catch (Exception ex)
		{
			ReportOnce("hotbar.indicator", ex);
		}
	}

	private Transform CreateHotbarIndicator(Transform parent)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: 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)
		RectTransform val = HotbarRect(parent, "PaintYourBuild_EquipmentIndicator", Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
		AddHotbarFrame((Transform)(object)val, "Controller focus", 0f, new Color(0.95f, 0.95f, 0.9f, 1f));
		AddHotbarFrame((Transform)(object)val, "Equipped", 3f, new Color(1f, 0.77f, 0.28f, 1f));
		_hotbarIndicators.RemoveAll((GameObject item) => !Object.op_Implicit((Object)(object)item));
		_hotbarIndicators.Add(((Component)val).gameObject);
		return (Transform)(object)val;
	}

	private static RectTransform HotbarRect(Transform parent, string name, Vector2 min, Vector2 max, Vector2 offsetMin, Vector2 offsetMax)
	{
		//IL_0014: 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_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		RectTransform component = new GameObject(name, new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
		((Transform)component).SetParent(parent, false);
		component.anchorMin = min;
		component.anchorMax = max;
		component.offsetMin = offsetMin;
		component.offsetMax = offsetMax;
		return component;
	}

	private static void AddHotbarFrame(Transform parent, string name, float inset, Color color)
	{
		//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_000e: 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_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_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//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_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)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		RectTransform parent2 = HotbarRect(parent, name, Vector2.zero, Vector2.one, new Vector2(inset, inset), new Vector2(0f - inset, 0f - inset));
		AddHotbarEdge((Transform)(object)parent2, "Top", new Vector2(0f, 1f), Vector2.one, new Vector2(0f, -2f), Vector2.zero, color);
		AddHotbarEdge((Transform)(object)parent2, "Bottom", Vector2.zero, new Vector2(1f, 0f), Vector2.zero, new Vector2(0f, 2f), color);
		AddHotbarEdge((Transform)(object)parent2, "Left", Vector2.zero, new Vector2(0f, 1f), Vector2.zero, new Vector2(2f, 0f), color);
		AddHotbarEdge((Transform)(object)parent2, "Right", new Vector2(1f, 0f), Vector2.one, new Vector2(-2f, 0f), Vector2.zero, color);
	}

	private static void AddHotbarEdge(Transform parent, string name, Vector2 min, Vector2 max, Vector2 offsetMin, Vector2 offsetMax, Color color)
	{
		//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_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		Image obj = ((Component)HotbarRect(parent, name, min, max, offsetMin, offsetMax)).gameObject.AddComponent<Image>();
		((Graphic)obj).color = color;
		((Graphic)obj).raycastTarget = false;
	}

	private void ReleaseHotbarIndicators()
	{
		foreach (GameObject hotbarIndicator in _hotbarIndicators)
		{
			if (Object.op_Implicit((Object)(object)hotbarIndicator))
			{
				Object.Destroy((Object)(object)hotbarIndicator);
			}
		}
		_hotbarIndicators.Clear();
	}

	internal static bool CanUseTool(Player player)
	{
		if (Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Character)player).InCutscene() && !InventoryGui.IsVisible() && !Hud.InRadial() && !Menu.IsVisible() && !Console.IsVisible() && !StoreGui.IsVisible() && !TextInput.IsVisible() && !Minimap.IsOpen() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()))
		{
			return !GameCamera.InFreeFly();
		}
		return false;
	}

	internal static bool IsSupported(WearNTear wear)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Expected I4, but got Unknown
		if (!Object.op_Implicit((Object)(object)wear))
		{
			return false;
		}
		MaterialType materialType = wear.m_materialType;
		switch ((int)materialType)
		{
		case 0:
		case 1:
		case 3:
		case 4:
		case 5:
		case 6:
		case 8:
			return true;
		case 2:
			return ((Object)((Component)wear).gameObject).name.StartsWith("wood_iron", StringComparison.OrdinalIgnoreCase);
		default:
			return false;
		}
	}

	internal static bool TryGetBrushTarget(Player player, out BrushTarget target)
	{
		//IL_0025: 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_0057: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		target = default(BrushTarget);
		GameCamera instance = GameCamera.instance;
		if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)instance))
		{
			return false;
		}
		RaycastHit val = default(RaycastHit);
		if (!Physics.Raycast(((Component)instance).transform.position, ((Component)instance).transform.forward, ref val, 50f, (int)RemoveRayMask.GetValue(player), (QueryTriggerInteraction)1))
		{
			return false;
		}
		if (Vector3.Distance(((Character)player).GetEyePoint(), ((RaycastHit)(ref val)).point) > Math.Min(5f, player.m_maxPlaceDistance))
		{
			return false;
		}
		Piece componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>();
		WearNTear wear = (Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent).GetComponent<WearNTear>() : null);
		if (!Object.op_Implicit((Object)(object)componentInParent) || !IsSupported(wear))
		{
			return false;
		}
		ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
		if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
		{
			return false;
		}
		target = new BrushTarget
		{
			Piece = componentInParent,
			Wear = wear,
			Point = ((RaycastHit)(ref val)).point
		};
		return true;
	}

	internal static Finish ReadFinish(WearNTear wear)
	{
		ZNetView val = (Object.op_Implicit((Object)(object)wear) ? ((Component)wear).GetComponent<ZNetView>() : null);
		return Palette.Get((Object.op_Implicit((Object)(object)val) && val.IsValid()) ? val.GetZDO().GetInt(PaintHash, 0) : 0);
	}

	internal unsafe void UseBrush(Player player)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		if (!Ready || OverlayBlocksInput || Time.unscaledTime < _nextUse || (Object)(object)player != (Object)(object)Player.m_localPlayer || !CanUseTool(player))
		{
			return;
		}
		_nextUse = Time.unscaledTime + 0.3f;
		try
		{
			if (!TryGetBrushTarget(player, out var target))
			{
				Tell(player, "Aim at a wooden or stone building piece within 5 metres.");
				return;
			}
			if (!PrivateArea.CheckAccess(((Component)target.Piece).transform.position, 0f, true, false))
			{
				Tell(player, "A ward prevents you from painting this piece.");
				return;
			}
			Track(target.Wear);
			if (!HasPaintableSurfaces(target.Wear))
			{
				Tell(player, "This piece has no supported paint surface yet. Press F10 for details.");
				return;
			}
			ZNetView component = ((Component)target.Wear).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
			{
				return;
			}
			component.ClaimOwnership();
			switch (PaintCommit.Apply(new NetworkPaintStore(component), SelectedFinish.Id))
			{
			case PaintResult.NotOwner:
				Tell(player, "Could not acquire the piece. Please try again.");
				break;
			case PaintResult.Unchanged:
				Tell(player, "This piece already uses " + SelectedFinish.Name + ".");
				break;
			case PaintResult.Success:
			{
				RefreshSaved(target.Wear);
				PlayBrushSound(target.Point);
				ZSyncAnimation component2 = ((Component)player).GetComponent<ZSyncAnimation>();
				if (Object.op_Implicit((Object)(object)component2) && !string.IsNullOrEmpty(_brushAnimation))
				{
					component2.SetTrigger(_brushAnimation);
				}
				ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
				string[] obj = new string[8]
				{
					"[paint.ok] piece=",
					((Object)((Component)target.Piece).gameObject).name,
					"; zdo=",
					null,
					null,
					null,
					null,
					null
				};
				ZDOID uid = component.GetZDO().m_uid;
				obj[3] = ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
				obj[4] = "; finish=";
				obj[5] = SelectedFinish.Id.ToString();
				obj[6] = ":";
				obj[7] = SelectedFinish.Name;
				logger.LogInfo((object)string.Concat(obj));
				break;
			}
			}
		}
		catch (Exception ex)
		{
			ReportOnce("paint.apply", ex);
			Tell(player, "Painting failed. Please send BepInEx/LogOutput.log.");
		}
	}

	private void DumpPaintTarget()
	{
		if (!TryGetBrushTarget(Player.m_localPlayer, out var target))
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[paint.target] No supported target");
			return;
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[paint.target] " + ((Object)((Component)target.Piece).gameObject).name + "; material=" + ((object)Unsafe.As<MaterialType, MaterialType>(ref target.Wear.m_materialType)/*cast due to .constrained prefix*/).ToString() + "; saved=" + ReadFinish(target.Wear).Name));
		Renderer[] componentsInChildren = ((Component)target.Wear).GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val in componentsInChildren)
		{
			Material[] sharedMaterials = val.sharedMaterials;
			foreach (Material val2 in sharedMaterials)
			{
				if (Object.op_Implicit((Object)(object)val2))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("[paint.material] renderer=" + ((Object)val).name + "; material=" + ((Object)val2).name + "; shader=" + (Object.op_Implicit((Object)(object)val2.shader) ? ((Object)val2.shader).name : "none") + "; color=" + val2.HasProperty("_Color") + "; baseColor=" + val2.HasProperty("_BaseColor")));
				}
			}
		}
	}

	internal void Track(WearNTear wear)
	{
		if (!Ready || Application.isBatchMode || !IsSupported(wear) || _painted.ContainsKey(wear) || !Object.op_Implicit((Object)(object)((Component)wear).GetComponent<Piece>()))
		{
			return;
		}
		ZNetView component = ((Component)wear).GetComponent<ZNetView>();
		if (Object.op_Implicit((Object)(object)component) && component.IsValid())
		{
			PaintedPiece paintedPiece = new PaintedPiece
			{
				Wear = wear,
				View = component,
				Saved = component.GetZDO().GetInt(PaintHash, 0)
			};
			_painted.Add(wear, paintedPiece);
			if (Palette.IsValid(paintedPiece.Saved) && paintedPiece.Saved != 0)
			{
				ApplyPiece(paintedPiece);
			}
		}
	}

	internal void RefreshSaved(WearNTear wear)
	{
		if (_painted.TryGetValue(wear, out var value))
		{
			value.Saved = value.View.GetZDO().GetInt(PaintHash, 0);
			ApplyPiece(value);
		}
	}

	private void TickPaintSync()
	{
		if (Application.isBatchMode || Time.unscaledTime < _nextPaintSync)
		{
			return;
		}
		_nextPaintSync = Time.unscaledTime + 0.5f;
		_deadPieces.Clear();
		foreach (KeyValuePair<WearNTear, PaintedPiece> item in _painted)
		{
			PaintedPiece value = item.Value;
			if (!Object.op_Implicit((Object)(object)value.Wear) || !Object.op_Implicit((Object)(object)value.View) || !value.View.IsValid())
			{
				_deadPieces.Add(item.Key);
				continue;
			}
			int num = value.View.GetZDO().GetInt(PaintHash, 0);
			if (num != value.Saved)
			{
				value.Saved = num;
				ApplyPiece(value);
			}
		}
		foreach (WearNTear deadPiece in _deadPieces)
		{
			Forget(deadPiece);
		}
		if (!BrushSelected(Player.m_localPlayer) || !CanUseTool(Player.m_localPlayer))
		{
			ClearPreview();
		}
	}

	internal void SetPreview(WearNTear wear, int finish)
	{
		if (!((Object)(object)_previewPiece == (Object)(object)wear) || _previewFinish != finish)
		{
			ClearPreview();
			Track(wear);
			if (_painted.TryGetValue(wear, out var value))
			{
				_previewPiece = wear;
				_previewFinish = finish;
				ApplyPiece(value);
			}
		}
	}

	internal void ClearPreview()
	{
		WearNTear previewPiece = _previewPiece;
		_previewPiece = null;
		if (Object.op_Implicit((Object)(object)previewPiece) && _painted.TryGetValue(previewPiece, out var value))
		{
			ApplyPiece(value);
		}
	}

	internal bool HasPaintableSurfaces(WearNTear wear)
	{
		if (!_painted.TryGetValue(wear, out var value))
		{
			return false;
		}
		BuildSurfaces(value);
		return value.Surfaces.Count > 0;
	}

	private void BuildSurfaces(PaintedPiece entry)
	{
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		if (entry.Built)
		{
			return;
		}
		entry.Built = true;
		Renderer[] componentsInChildren = ((Component)entry.Wear).GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val in componentsInChildren)
		{
			if ((!(val is MeshRenderer) && !(val is SkinnedMeshRenderer)) || (Object)(object)((Component)val).GetComponentInParent<WearNTear>() != (Object)(object)entry.Wear || (Object)(object)val == (Object)(object)entry.Wear.m_snow || (Object)(object)val == (Object)(object)entry.Wear.m_snowWorn || (Object)(object)val == (Object)(object)entry.Wear.m_snowBroken || (Object.op_Implicit((Object)(object)entry.Wear.m_wet) && ((Component)val).transform.IsChildOf(entry.Wear.m_wet.transform)))
			{
				continue;
			}
			Surface surface = new Surface
			{
				Renderer = val,
				Piece = entry
			};
			Material[] sharedMaterials = val.sharedMaterials;
			for (int j = 0; j < sharedMaterials.Length; j++)
			{
				Material val2 = sharedMaterials[j];
				if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val2.shader))
				{
					continue;
				}
				string text = ((Object)val2).name.ToLowerInvariant() + " " + ((Object)val).name.ToLowerInvariant();
				bool flag = false;
				string[] excludedMaterials = ExcludedMaterials;
				foreach (string value in excludedMaterials)
				{
					if (text.Contains(value))
					{
						flag = true;
						break;
					}
				}
				if (flag && ((Object)val2).name.ToLowerInvariant().Contains("wood") && !((Object)val2).name.ToLowerInvariant().Contains("snow"))
				{
					flag = false;
				}
				if (flag || val2.renderQueue >= 3000)
				{
					continue;
				}
				int num = (val2.HasProperty("_Color") ? Shader.PropertyToID("_Color") : (val2.HasProperty("_BaseColor") ? Shader.PropertyToID("_BaseColor") : (-1)));
				if (num != -1)
				{
					val.GetPropertyBlock(surface.Block, j);
					if (surface.Block.isEmpty)
					{
						surface.Slots.Add(new Slot
						{
							Index = j,
							Property = num,
							Base = val2.GetColor(num)
						});
					}
				}
			}
			if (surface.Slots.Count != 0)
			{
				entry.Surfaces.Add(surface);
				_surfaces[val] = surface;
			}
		}
	}

	private void ApplyPiece(PaintedPiece entry)
	{
		int num = (((Object)(object)entry.Wear == (Object)(object)_previewPiece) ? _previewFinish : entry.Saved);
		if (num != 0 && Palette.IsValid(num))
		{
			BuildSurfaces(entry);
		}
		foreach (Surface surface in entry.Surfaces)
		{
			ApplySurface(surface);
		}
	}

	private void ApplySurface(Surface surface)
	{
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)surface.Renderer))
		{
			return;
		}
		int num = (((Object)(object)surface.Piece.Wear == (Object)(object)_previewPiece) ? _previewFinish : surface.Piece.Saved);
		if (num == 0 || !Palette.IsValid(num) || surface.Piece.Highlighted)
		{
			RestoreSurface(surface);
			return;
		}
		Finish finish = Palette.Get(num);
		foreach (Slot slot in surface.Slots)
		{
			surface.Renderer.GetPropertyBlock(surface.Block);
			surface.Block.SetColor(slot.Property, new Color(slot.Base.r * finish.R, slot.Base.g * finish.G, slot.Base.b * finish.B, slot.Base.a));
			surface.Renderer.SetPropertyBlock(surface.Block, slot.Index);
		}
		surface.Applied = true;
	}

	private static void RestoreSurface(Surface surface)
	{
		if (!surface.Applied || !Object.op_Implicit((Object)(object)surface.Renderer))
		{
			return;
		}
		foreach (Slot slot in surface.Slots)
		{
			surface.Renderer.SetPropertyBlock((MaterialPropertyBlock)null, slot.Index);
		}
		surface.Applied = false;
	}

	internal void NativeMaterialsUpdated(List<Renderer> renderers)
	{
		if (_surfaces.Count == 0)
		{
			return;
		}
		foreach (Renderer renderer in renderers)
		{
			if (Object.op_Implicit((Object)(object)renderer) && _surfaces.TryGetValue(renderer, out var value))
			{
				ApplySurface(value);
			}
		}
	}

	internal void SetHighlight(WearNTear wear, bool highlighted)
	{
		if (_painted.TryGetValue(wear, out var value))
		{
			value.Highlighted = highlighted;
			ApplyPiece(value);
		}
	}

	internal void Forget(WearNTear wear)
	{
		if (!_painted.TryGetValue(wear, out var value))
		{
			return;
		}
		foreach (Surface surface in value.Surfaces)
		{
			RestoreSurface(surface);
			_surfaces.Remove(surface.Renderer);
		}
		_painted.Remove(wear);
		if ((Object)(object)_previewPiece == (Object)(object)wear)
		{
			_previewPiece = null;
		}
	}

	private void ReleasePaint()
	{
		_previewPiece = null;
		foreach (Surface value in _surfaces.Values)
		{
			RestoreSurface(value);
		}
		_surfaces.Clear();
		_painted.Clear();
	}

	private void BindPaintConfig()
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		_paletteKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "PaletteKey", new KeyboardShortcut((KeyCode)112, Array.Empty<KeyCode>()), "Open the natural colour palette while the paintbrush is equipped.");
		_selectedId = ((BaseUnityPlugin)this).Config.Bind<int>("Palette", "SelectedFinish", 2, "Last selected natural finish. IDs 0 through 24; 0 restores the original appearance.");
	}

	private bool PaletteInputHeld()
	{
		//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_0044: Unknown result type (might be due to invalid IL or missing references)
		string[] paletteButtonsHeld = PaletteButtonsHeld;
		for (int i = 0; i < paletteButtonsHeld.Length; i++)
		{
			if (ZInput.GetButton(paletteButtonsHeld[i]))
			{
				return true;
			}
		}
		if (!ZInput.GetMouseButton(0) && !ZInput.GetMouseButton(1))
		{
			KeyboardShortcut value = _paletteKey.Value;
			if (!ZInput.GetKey(((KeyboardShortcut)(ref value)).MainKey, true) && !ZInput.GetKey((KeyCode)13, true) && !ZInput.GetKey((KeyCode)271, true) && !ZInput.GetKey((KeyCode)27, true) && !ZInput.GetKey((KeyCode)276, true) && !ZInput.GetKey((KeyCode)275, true) && !ZInput.GetKey((KeyCode)273, true) && !ZInput.GetKey((KeyCode)274, true) && !(Mathf.Abs(ZInput.GetJoyLeftStickX(false)) > 0.25f))
			{
				return Mathf.Abs(ZInput.GetJoyLeftStickY(false)) > 0.25f;
			}
		}
		return true;
	}

	private void TickPalette()
	{
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		if (Application.isBatchMode)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		try
		{
			if (!PaletteOpen && _releaseGuard.Blocked)
			{
				if (!Object.op_Implicit((Object)(object)localPlayer))
				{
					_releaseGuard.Reset();
				}
				else
				{
					_releaseGuard.Tick(Time.frameCount, PaletteInputHeld());
				}
			}
			KeyboardShortcut value;
			if (!BrushSelected(localPlayer) || !CanUseTool(localPlayer))
			{
				if (PaletteOpen)
				{
					ClosePalette();
				}
			}
			else if (PaletteOpen)
			{
				if (Time.frameCount == _openedFrame)
				{
					return;
				}
				value = _paletteKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() || ZInput.GetKeyDown((KeyCode)27, true) || ZInput.GetButtonDown("JoyButtonB"))
				{
					ClosePalette();
					return;
				}
				if (ZInput.GetButtonDown("JoyLBumper") || ZInput.GetKeyDown((KeyCode)280, true))
				{
					SetPalettePage(0);
				}
				else if (ZInput.GetButtonDown("JoyRBumper") || ZInput.GetKeyDown((KeyCode)281, true))
				{
					SetPalettePage(1);
				}
				if (ZInput.GetKeyDown((KeyCode)276, true) || ZInput.GetButtonDown("JoyDPadLeft") || ZInput.GetButtonDown("JoyLStickLeft"))
				{
					FocusSlot(PaletteLayout.Move(_focusSlot, -1, 0));
				}
				else if (ZInput.GetKeyDown((KeyCode)275, true) || ZInput.GetButtonDown("JoyDPadRight") || ZInput.GetButtonDown("JoyLStickRight"))
				{
					FocusSlot(PaletteLayout.Move(_focusSlot, 1, 0));
				}
				else if (ZInput.GetKeyDown((KeyCode)273, true) || ZInput.GetButtonDown("JoyDPadUp") || ZInput.GetButtonDown("JoyLStickUp"))
				{
					FocusSlot(PaletteLayout.Move(_focusSlot, 0, -1));
				}
				else if (ZInput.GetKeyDown((KeyCode)274, true) || ZInput.GetButtonDown("JoyDPadDown") || ZInput.GetButtonDown("JoyLStickDown"))
				{
					FocusSlot(PaletteLayout.Move(_focusSlot, 0, 1));
				}
				if (ZInput.GetKeyDown((KeyCode)13, true) || ZInput.GetKeyDown((KeyCode)271, true) || ZInput.GetButtonDown("JoyButtonA"))
				{
					ActivateSlot(_focusSlot);
				}
			}
			else if (!_releaseGuard.Blocked && !(Time.unscaledTime < _nextUse))
			{
				value = _paletteKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() || ZInput.GetButtonDown("BuildMenu") || ZInput.GetButtonDown("JoyBuildMenu"))
				{
					OpenPalette();
				}
			}
		}
		catch (Exception ex)
		{
			ReportOnce("paint.palette", ex);
			ClosePalette();
		}
	}

	private void OpenPalette()
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)_paletteCanvas))
		{
			CreatePalette();
		}
		_paletteTarget = ((TryGetBrushTarget(Player.m_localPlayer, out var target) && PrivateArea.CheckAccess(((Component)target.Piece).transform.position, 0f, false, false)) ? target.Wear : null);
		_releaseGuard.Reset();
		_paletteCanvas.SetActive(true);
		_openedFrame = Time.frameCount;
		_nextUse = Time.unscaledTime + 0.3f;
		_pageIndex = PaletteLayout.PageFor(SelectedFinish.Id);
		_focusSlot = PaletteLayout.SlotFor(_pageIndex, SelectedFinish.Id);
		SetPalettePage(_pageIndex);
		if (Object.op_Implicit((Object)(object)EventSystem.current))
		{
			EventSystem.current.SetSelectedGameObject((GameObject)null);
		}
		ZCursor.LockState = (CursorLockMode)0;
		ZCursor.Show();
	}

	internal void ClosePalette()
	{
		if (Object.op_Implicit((Object)(object)_paletteCanvas) && _paletteCanvas.activeSelf)
		{
			_paletteCanvas.SetActive(false);
			_releaseGuard.Arm(Time.frameCount);
			_nextUse = Time.unscaledTime + 0.3f;
			_paletteTarget = null;
			ClearPreview();
			if (Object.op_Implicit((Object)(object)EventSystem.current))
			{
				EventSystem.current.SetSelectedGameObject((GameObject)null);
			}
		}
	}

	private void SetPalettePage(int page)
	{
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		if (page >= 0 && page < PaletteLayout.Pages.Length)
		{
			_pageIndex = page;
			Color color = default(Color);
			for (int i = 0; i < 12; i++)
			{
				Finish finish = Palette.Get(PaletteLayout.Pages[page][i]);
				_swatchLabels[i].text = finish.Name;
				ColorUtility.TryParseHtmlString(finish.Swatch, ref color);
				((Graphic)_swatchImages[i]).color = color;
			}
			for (int j = 0; j < _paletteTabs.Length; j++)
			{
				((Graphic)((Component)_paletteTabs[j]).GetComponent<Image>()).color = ((j == page) ? new Color(0.38f, 0.3f, 0.18f) : new Color(0.16f, 0.15f, 0.13f));
			}
			FocusSlot(_focusSlot);
		}
	}

	internal void FocusSlot(int slot)
	{
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		if (slot >= 0 && slot < 15)
		{
			_focusSlot = slot;
			int num = ((slot < 12) ? PaletteLayout.Pages[_pageIndex][slot] : 0);
			Finish finish = Palette.Get(num);
			switch (slot)
			{
			case 13:
				_paletteCaption.text = (Object.op_Implicit((Object)(object)_paletteTarget) ? ("Copy saved finish: " + ReadFinish(_paletteTarget).Name) : "Aim at a piece before opening the palette");
				break;
			case 14:
				_paletteCaption.text = "Close the palette";
				break;
			default:
				_paletteCaption.text = ((num == 0) ? "Restore this piece's original finish" : (finish.Name + " · " + ((finish.Group == "Wood") ? "Natural wood stain" : "Natural stone finish")));
				break;
			}
			for (int i = 0; i < _paletteButtons.Length; i++)
			{
				((Graphic)((Component)_paletteButtons[i]).GetComponent<Image>()).color = ((i == slot) ? new Color(0.38f, 0.3f, 0.18f, 1f) : new Color(0.16f, 0.15f, 0.13f, 1f));
			}
			if (Object.op_Implicit((Object)(object)_paletteTarget) && slot <= 12)
			{
				SetPreview(_paletteTarget, num);
			}
			else
			{
				ClearPreview();
			}
		}
	}

	private void ActivateSlot(int slot)
	{
		if (!PaletteOpen)
		{
			return;
		}
		if (slot >= 0 && slot < 12)
		{
			SelectFinish(PaletteLayout.Pages[_pageIndex][slot]);
			return;
		}
		switch (slot)
		{
		case 12:
			SelectFinish(0);
			break;
		case 13:
			CopyTarget();
			break;
		case 14:
			ClosePalette();
			break;
		}
	}

	private void SelectFinish(int id)
	{
		if (Palette.IsValid(id))
		{
			_selectedId.Value = id;
			((BaseUnityPlugin)this).Config.Save();
			ClosePalette();
			Tell(Player.m_localPlayer, "Selected: " + Palette.Get(id).Name);
		}
	}

	private void CopyTarget()
	{
		if (!Object.op_Implicit((Object)(object)_paletteTarget))
		{
			_paletteCaption.text = "Aim at a building piece before opening the palette";
		}
		else
		{
			SelectFinish(ReadFinish(_paletteTarget).Id);
		}
	}

	private RectTransform Box(Transform parent, string name, Vector2 size, Vector2 pos, Color color)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: 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_007e: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject(name, new Type[2]
		{
			typeof(RectTransform),
			typeof(Image)
		});
		RectTransform component = val.GetComponent<RectTransform>();
		((Transform)component).SetParent(parent, false);
		Vector2 val2 = default(Vector2);
		((Vector2)(ref val2))..ctor(0.5f, 1f);
		component.anchorMax = val2;
		component.anchorMin = val2;
		component.pivot = new Vector2(0.5f, 1f);
		component.sizeDelta = size;
		component.anchoredPosition = pos;
		((Graphic)val.GetComponent<Image>()).color = color;
		return component;
	}

	private TMP_Text Label(Transform parent, string text, float size, Vector2 dimensions, Vector2 position, TextAlignmentOptions align = (TextAlignmentOptions)513)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: 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_006d: 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)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("Label", new Type[2]
		{
			typeof(RectTransform),
			typeof(TextMeshProUGUI)
		});
		RectTransform component = val.GetComponent<RectTransform>();
		((Transform)component).SetParent(parent, false);
		Vector2 val2 = default(Vector2);
		((Vector2)(ref val2))..ctor(0.5f, 1f);
		component.anchorMax = val2;
		component.anchorMin = val2;
		component.pivot = new Vector2(0.5f, 1f);
		component.sizeDelta = dimensions;
		component.anchoredPosition = position;
		TextMeshProUGUI component2 = val.GetComponent<TextMeshProUGUI>();
		((TMP_Text)component2).font = ((Object.op_Implicit((Object)(object)Hud.instance) && Object.op_Implicit((Object)(object)Hud.instance.m_pieceDescription)) ? Hud.instance.m_pieceDescription.font : TMP_Settings.defaultFontAsset);
		((TMP_Text)component2).text = text;
		((TMP_Text)component2).fontSize = size;
		((Graphic)component2).color = new Color(0.94f, 0.9f, 0.82f);
		((TMP_Text)component2).alignment = align;
		((Graphic)component2).raycastTarget = false;
		return (TMP_Text)(object)component2;
	}

	private Button ActionButton(Transform parent, string name, Vector2 size, Vector2 pos, Action action)
	{
		//IL_0011: 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_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: 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_007a: Expected O, but got Unknown
		//IL_0082: 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)
		RectTransform val = Box(parent, name, size, pos, new Color(0.23f, 0.21f, 0.17f));
		Button obj = ((Component)val).gameObject.AddComponent<Button>();
		((Selectable)obj).targetGraphic = (Graphic)(object)((Component)val).GetComponent<Image>();
		((Selectable)obj).transition = (Transition)0;
		Navigation navigation = default(Navigation);
		((Navigation)(ref navigation)).mode = (Mode)0;
		((Selectable)obj).navigation = navigation;
		((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
		{
			if (Object.op_Implicit((Object)(object)EventSystem.current))
			{
				EventSystem.current.SetSelectedGameObject((GameObject)null);
			}
			action();
		});
		Label((Transform)(object)val, name, 20f, size, Vector2.zero, (TextAlignmentOptions)514);
		return obj;
	}

	private void CreatePalette()
	{
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Expected O, but got Unknown
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: 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_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: 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_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0219: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_0257: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0329: Unknown result type (might be due to invalid IL or missing references)
		//IL_033f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0349: Expected O, but got Unknown
		//IL_036e: Unknown result type (might be due to invalid IL or missing references)
		//IL_037d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0382: Unknown result type (might be due to invalid IL or missing references)
		//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_03db: Unknown result type (might be due to invalid IL or missing references)
		//IL_041c: Unknown result type (might be due to invalid IL or missing references)
		//IL_042b: Unknown result type (might be due to invalid IL or missing references)
		//IL_049d: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_050a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0519: Unknown result type (might be due to invalid IL or missing references)
		_paletteCanvas = new GameObject("PaintYourBuild_Palette", new Type[4]
		{
			typeof(RectTransform),
			typeof(Canvas),
			typeof(CanvasScaler),
			typeof(GraphicRaycaster)
		});
		_paletteCanvas.transform.SetParent(((Component)this).transform, false);
		_paletteCanvas.SetActive(false);
		Canvas component = _paletteCanvas.GetComponent<Canvas>();
		component.renderMode = (RenderMode)0;
		component.sortingOrder = 30000;
		CanvasScaler component2 = _paletteCanvas.GetComponent<CanvasScaler>();
		component2.uiScaleMode = (ScaleMode)1;
		component2.referenceResolution = new Vector2(1600f, 900f);
		component2.matchWidthOrHeight = 0.5f;
		RectTransform obj = Box(_paletteCanvas.transform, "Shade", Vector2.zero, Vector2.zero, new Color(0f, 0f, 0f, 0.48f));
		obj.anchorMin = Vector2.zero;
		obj.anchorMax = Vector2.one;
		Vector2 offsetMin = (obj.offsetMax = Vector2.zero);
		obj.offsetMin = offsetMin;
		RectTransform val = Box(_paletteCanvas.transform, "Natural finishes", new Vector2(770f, 720f), Vector2.zero, new Color(0.09f, 0.085f, 0.072f, 0.99f));
		Vector2 val2 = default(Vector2);
		((Vector2)(ref val2))..ctor(0.5f, 0.5f);
		val.pivot = val2;
		offsetMin = (val.anchorMax = val2);
		val.anchorMin = offsetMin;
		Label((Transform)(object)val, "PAINT YOUR BUILD", 32f, new Vector2(690f, 48f), new Vector2(0f, -24f), (TextAlignmentOptions)513);
		Label((Transform)(object)val, "Natural finishes", 21f, new Vector2(690f, 32f), new Vector2(0f, -71f), (TextAlignmentOptions)513);
		_paletteTabs[0] = ActionButton((Transform)(object)val, "Wood stains · LB", new Vector2(336f, 40f), new Vector2(-177f, -110f), delegate
		{
			SetPalettePage(0);
		});
		_paletteTabs[1] = ActionButton((Transform)(object)val, "Stone finishes · RB", new Vector2(336f, 40f), new Vector2(177f, -110f), delegate
		{
			SetPalettePage(1);
		});
		for (int num = 0; num < 12; num++)
		{
			int captured = num;
			float num2 = (num % 3 - 1) * 232;
			float num3 = -168 - num / 3 * 78;
			RectTransform val4 = Box((Transform)(object)val, "Finish " + num, new Vector2(220f, 66f), new Vector2(num2, num3), new Color(0.16f, 0.15f, 0.13f));
			Button val5 = ((Component)val4).gameObject.AddComponent<Button>();
			((Selectable)val5).targetGraphic = (Graphic)(object)((Component)val4).GetComponent<Image>();
			((Selectable)val5).transition = (Transition)0;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)val5).navigation = navigation;
			((UnityEvent)val5.onClick).AddListener((UnityAction)delegate
			{
				ActivateSlot(captured);
			});
			((Component)val4).gameObject.AddComponent<PaintPaletteHover>().SlotIndex = num;
			RectTransform val6 = Box((Transform)(object)val4, "Colour", new Vector2(24f, 36f), new Vector2(-85f, -15f), Color.white);
			_swatchImages[num] = ((Component)val6).GetComponent<Image>();
			((Graphic)_swatchImages[num]).raycastTarget = false;
			_swatchLabels[num] = Label((Transform)(object)val4, "", 19f, new Vector2(162f, 58f), new Vector2(21f, -4f), (TextAlignmentOptions)4097);
			_paletteButtons[num] = val5;
		}
		_paletteCaption = Label((Transform)(object)val, "", 21f, new Vector2(690f, 52f), new Vector2(0f, -495f), (TextAlignmentOptions)514);
		string[] array = new string[3] { "Restore original", "Copy target colour", "Close" };
		for (int num4 = 0; num4 < array.Length; num4++)
		{
			int captured2;
			int num5 = (captured2 = 12 + num4);
			_paletteButtons[num5] = ActionButton((Transform)(object)val, array[num4], new Vector2(220f, 47f), new Vector2((float)((num4 - 1) * 232), -570f), delegate
			{
				ActivateSlot(captured2);
			});
			((Component)_paletteButtons[num5]).gameObject.AddComponent<PaintPaletteHover>().SlotIndex = num5;
		}
		Label((Transform)(object)val, "Left stick / D-pad: browse   ·   A: select   ·   B: close\nLB / RB: wood / stone   ·   Keyboard: arrows, Enter, Esc, PgUp / PgDn", 18f, new Vector2(690f, 66f), new Vector2(0f, -642f), (TextAlignmentOptions)514);
	}

	private void Awake()
	{
		//IL_0021: 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)
		//IL_00c7: Expected O, but got Unknown
		Instance = this;
		_diagnosticKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Diagnostics", "DumpStatus", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Write brush registration, selected recipe, UI state and patch owners to BepInEx/LogOutput.log.");
		BindFeedbackConfig();
		BindPaintConfig();
		try
		{
			ResolveApis();
			Assembly assembly = typeof(PlayerProfile).Assembly;
			_craftCompatibility = new CraftCompatibility(typeof(ItemData), typeof(PlayerProfile), assembly.GetType("PlayerStatType"), assembly.GetType("ZDOVars"), ReportOnce);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[compat.craft] " + _craftCompatibility.Description));
			_harmony = new Harmony("com.lesly.valheim.paintyourbuild");
			_harmony.PatchAll(typeof(NaturalPaintPlugin).Assembly);
			VerifyPatches();
			Ready = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[startup.ok] Paint Your Build 0.1.2; game=" + Application.version + "; unity=" + Application.unityVersion + "; plugin=" + ((BaseUnityPlugin)this).Info.Location));
		}
		catch (Exception ex)
		{
			Ready = false;
			if (_harmony != null)
			{
				_harmony.UnpatchAll("com.lesly.valheim.paintyourbuild");
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("[startup.failed] Brush disabled; critical API/patch missing. " + ex));
		}
	}

	private static FieldInfo Field(Type type, string name)
	{
		return AccessTools.Field(type, name) ?? throw new MissingFieldException(type.FullName, name);
	}

	private static MethodInfo Method(Type type, string name, params Type[] arguments)
	{
		return AccessTools.Method(type, name, arguments, (Type[])null) ?? throw new MissingMethodException(type.FullName, name);
	}

	private static void ResolveApis()
	{
		SelectedRecipeField = Field(typeof(InventoryGui), "m_selectedRecipe");
		Type fieldType = SelectedRecipeField.FieldType;
		SelectedRecipeProperty = fieldType.GetProperty("Recipe") ?? throw new MissingMemberException(fieldType.FullName, "Recipe");
		SelectedItemProperty = fieldType.GetProperty("ItemData") ?? throw new MissingMemberException(fieldType.FullName, "ItemData");
		NativeCraftComplete = Method(typeof(InventoryGui), "DoCrafting", typeof(Player));
		RefreshPanel = Method(typeof(InventoryGui), "UpdateCraftingPanel", typeof(bool));
		NotifyInventory = Method(typeof(Inventory), "Changed", typeof(bool), typeof(bool));
		AddKnownRecipe = Method(typeof(Player), "AddKnownRecipe", typeof(Recipe));
		DbByHash = Field(typeof(ObjectDB), "m_itemByHash");
		DbByData = Field(typeof(ObjectDB), "m_itemByData");
		SceneByHash = Field(typeof(ZNetScene), "m_namedPrefabs");
		RemoveRayMask = Field(typeof(Player), "m_removeRayMask");
		SnappingIcon = Field(typeof(Hud), "m_snappingIcon");
		ResolveHotbarApis();
	}

	private void VerifyPatches()
	{
		int num = Harmony.GetAllPatchedMethods().Count((MethodBase m) => Harmony.GetPatchInfo(m).Owners.Contains("com.lesly.valheim.paintyourbuild"));
		if (num != 23)
		{
			throw new InvalidOperationException("Incomplete paint patch set: " + num);
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[patches.ok] " + num + " methods patched"));
	}

	private void Update()
	{
		//IL_000e: 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)
		if (!Ready)
		{
			return;
		}
		KeyboardShortcut value = _diagnosticKey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			DumpStatus();
			DumpPaintTarget();
		}
		TickPalette();
		try
		{
			TickPaintSync();
		}
		catch (Exception ex)
		{
			ReportOnce("paint.sync", ex);
		}
		if (Time.unscaledTime < _nextMaintenance)
		{
			return;
		}
		_nextMaintenance = Time.unscaledTime + 0.5f;
		SafeRegister(ObjectDB.instance);
		try
		{
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)BrushRecipe) && (Object)(object)_selfTestDb != (Object)(object)ObjectDB.instance)
			{
				RunInventorySelfTest();
			}
			if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)BrushRecipe) && AtWorkbench(localPlayer) && !localPlayer.IsRecipeKnown("Paintbrush") && localPlayer.HaveRequirements(BrushRecipe, true, 1, 1))
			{
				AddKnownRecipe.Invoke(localPlayer, new object[1] { BrushRecipe });
			}
			if (!Object.op_Implicit((Object)(object)instance) || !InventoryGui.IsVisible())
			{
				return;
			}
			Recipe val = Selected(instance);
			if ((Object)(object)val != (Object)(object)_lastSelected)
			{
				_lastSelected = val;
				if (IsBrushRecipe(val))
				{
					DumpStatus();
				}
			}
		}
		catch (Exception ex2)
		{
			ReportOnce("maintenance", ex2);
		}
	}

	internal static bool IsBrush(ItemData item)
	{
		if (item != null && Object.op_Implicit((Object)(object)item.m_dropPrefab))
		{
			return ((Object)item.m_dropPrefab).name == "Lesly_Paintbrush";
		}
		return false;
	}

	internal static bool IsBrushRecipe(Recipe recipe)
	{
		if (Object.op_Implicit((Object)(object)recipe) && Object.op_Implicit((Object)(object)recipe.m_item))
		{
			return ((Object)((Component)recipe.m_item).gameObject).name == "Lesly_Paintbrush";
		}
		return false;
	}

	internal static Recipe Selected(InventoryGui gui)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		return (Recipe)SelectedRecipeProperty.GetValue(SelectedRecipeField.GetValue(gui), null);
	}

	internal static bool AtWorkbench(Player player)
	{
		CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
		if (Object.op_Implicit((Object)(object)currentCraftingStation) && currentCraftingStation.m_name == "$piece_workbench")
		{
			return !currentCraftingStation.m_upgrader;
		}
		return false;
	}

	internal void CompleteCraft(InventoryGui gui, Player player, Recipe recipe, ItemData upgrade, bool multi, int batchAmount)
	{
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
		if (!Ready || _lastCraftFrame == Time.frameCount)
		{
			return;
		}
		_lastCraftFrame = Time.frameCount;
		try
		{
			if (!Object.op_Implicit((Object)(object)player) || !IsBrushRecipe(recipe))
			{
				return;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[craft.complete] recipe=" + ((Object)recipe).name));
			if ((Object)(object)_selfTestDb != (Object)(object)ObjectDB.instance)
			{
				RunInventorySelfTest();
			}
			if (!_selfTestPassed)
			{
				Tell(player, "Brush inventory self-test failed. Please send BepInEx/LogOutput.log.");
				return;
			}
			if (upgrade != null)
			{
				Tell(player, "The Paintbrush has no upgrades.");
				return;
			}
			if (!AtWorkbench(player))
			{
				Tell(player, "Use a workbench to craft the Paintbrush.");
				return;
			}
			CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
			if (currentCraftingStation.GetLevel(true) < 1 || !currentCraftingStation.CheckUsable(player, true))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[craft.blocked] Workbench is not usable.");
				return;
			}
			int num = ((!multi) ? 1 : Math.Max(1, Math.Min(100, batchAmount)));
			bool free = player.NoCostCheat() || (Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.GetGlobalKey((GlobalKeys)25));
			GameInventory gameInventory = new GameInventory(player);
			int num2 = gameInventory.Count("Wood");
			Exception error;
			Outcome outcome = Transactions.Craft(gameInventory, num, free, out error);
			if (outcome == Outcome.Success)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[craft.ok] brushes=" + num + "; wood=" + num2 + "->" + gameInventory.Count("Wood")));
				try
				{
					currentCraftingStation.m_craftItemDoneEffects.Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
					_craftCompatibility.RecordCraft(Game.instance.GetPlayerProfile(), recipe.m_item.m_itemData.m_shared.m_name, num, gameInventory.LastCreatedCheated);
				}
				catch (Exception ex)
				{
					ReportOnce("craft.feedback", ex);
				}
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[craft.blocked] result=" + outcome.ToString() + "; wood=" + num2 + "; slots=" + gameInventory.FreeSlots + "; amount=" + num));
				if (error != null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)error);
				}
				Tell(player, outcome switch
				{
					Outcome.FullInventory => "You need " + num + " empty inventory slot(s).", 
					Outcome.MissingResource => "You need " + num * 2 + " Wood.", 
					_ => "Craft failed; inventory restored. See BepInEx/LogOutput.log.", 
				});
			}
			try
			{
				RefreshPanel.Invoke(gui, new object[1] { false });
			}
			catch (Exception ex2)
			{
				ReportOnce("ui.refresh", ex2);
			}
		}
		catch (Exception ex3)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[craft.error] " + ex3));
			Tell(Player.m_localPlayer, "Brush crafting error. See BepInEx/LogOutput.log.");
		}
	}

	internal void ReportOnce(string context, Exception ex)
	{
		if (_reportedErrors.Add(context + ":" + ex.GetType().FullName + ":" + ex.Message))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[" + context + ".error] " + ex));
		}
	}

	internal static void Tell(Player player, string message)
	{
		if (Object.op_Implicit((Object)(object)player))
		{
			((Character)player).Message((MessageType)2, message, 0, (Sprite)null, false);
		}
	}

	private void RunInventorySelfTest()
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Expected O, but got Unknown
		//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_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		_selfTestDb = ObjectDB.instance;
		_selfTestPassed = false;
		bool forceDisableInit = ZNetView.m_forceDisableInit;
		try
		{
			Inventory val = new Inventory("NaturalPaint self-test", (Sprite)null, 2, 1);
			ItemData val2 = new GameInventory(Player.m_localPlayer).CreateBrushItem();
			if (!val.AddItem(val2) || !val.ContainsItem(val2))
			{
				throw new InvalidOperationException("Native AddItem rejected the test brush");
			}
			ZPackage val3 = new ZPackage();
			val.Save(val3);
			Inventory val4 = new Inventory("NaturalPaint restore self-test", (Sprite)null, 2, 1);
			val4.Load(new ZPackage(val3.GetArray()));
			List<ItemData> allItems = val4.GetAllItems();
			if (allItems.Count != 1 || !IsBrush(allItems[0]) || allItems[0].m_stack != 1 || (Object)(object)allItems[0].m_shared.m_buildPieces != (Object)null || !Object.op_Implicit((Object)(object)allItems[0].GetIcon()) || allItems[0].HavePrimaryAttack() || allItems[0].HaveSecondaryAttack())
			{
				throw new InvalidOperationException("Native save/load did not restore a valid brush tool");
			}
			_selfTestPassed = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[selftest.ok] Craft item factory + metadata + native Inventory.AddItem + Save + Load passed in throwaway inventories; player inventory untouched.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[selftest.failed] " + ex));
		}
		finally
		{
			ZNetView.m_forceDisableInit = forceDisableInit;
		}
	}

	private void DumpStatus()
	{
		//IL_028e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d6: Expected O, but got Unknown
		try
		{
			InventoryGui gui = InventoryGui.instance;
			Recipe val = (Object.op_Implicit((Object)(object)gui) ? Selected(gui) : null);
			Player localPlayer = Player.m_localPlayer;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[status] version=0.1.2; ready=" + Ready + "; prefab=" + ((Object)(object)BrushPrefab != (Object)null) + "; recipe=" + ((Object)(object)BrushRecipe != (Object)null) + "; selected=" + (Object.op_Implicit((Object)(object)val) ? ((Object)val).name : "none") + "; selectedIsBrush=" + IsBrushRecipe(val) + "; buttonActive=" + (Object.op_Implicit((Object)(object)gui) && Object.op_Implicit((Object)(object)gui.m_craftButton) && ((Component)gui.m_craftButton).gameObject.activeInHierarchy) + "; buttonInteractable=" + (Object.op_Implicit((Object)(object)gui) && Object.op_Implicit((Object)(object)gui.m_craftButton) && ((Selectable)gui.m_craftButton).interactable) + "; nativeCraftProgress=true; inventorySelfTest=" + _selfTestPassed + "; workbench=" + (Object.op_Implicit((Object)(object)localPlayer) && AtWorkbench(localPlayer)) + "; wood=" + (Object.op_Implicit((Object)(object)localPlayer) ? new GameInventory(localPlayer).Count("Wood") : (-1))));
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)NativeCraftComplete);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[status.patches] DoCrafting owners=" + ((patchInfo == null) ? "NONE" : string.Join(",", patchInfo.Owners.ToArray()))));
			if (Object.op_Implicit((Object)(object)gui) && Object.op_Implicit((Object)(object)gui.m_craftButton) && InventoryGui.IsVisible() && Object.op_Implicit((Object)(object)EventSystem.current))
			{
				Transform transform = ((Component)gui.m_craftButton).transform;
				RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				Canvas componentInParent = ((Component)gui.m_craftButton).GetComponentInParent<Canvas>();
				Camera val3 = ((Object.op_Implicit((Object)(object)componentInParent) && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
				PointerEventData val4 = new PointerEventData(EventSystem.current);
				Rect rect = val2.rect;
				val4.position = RectTransformUtility.WorldToScreenPoint(val3, ((Transform)val2).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center)));
				PointerEventData val5 = val4;
				List<RaycastResult> list = new List<RaycastResult>();
				EventSystem.current.RaycastAll(val5, list);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[status.raycast] Craft button centre hits=" + string.Join(" | ", (from hit in list.Take(5)
					select ((Object)((RaycastResult)(ref hit)).gameObject).name + " (routesToCraft=" + ((Object)(object)((RaycastResult)(ref hit)).gameObject.GetComponentInParent<Button>() == (Object)(object)gui.m_craftButton) + ")").ToArray())));
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[status.error] " + ex));
		}
	}

	private void OnDestroy()
	{
		Ready = false;
		ClosePalette();
		ReleasePaint();
		ReleaseFeedback();
		ReleaseHotbarIndicators();
		if (_harmony != null)
		{
			_harmony.UnpatchAll("com.lesly.valheim.paintyourbuild");
		}
		ReleaseAssets();
		Instance = null;
	}
}
[HarmonyPatch(typeof(Player), "EquipInventoryItems")]
internal static class PaintLoginEquipmentPatch
{
	private static void Prefix(Player __instance)
	{
		if (!NaturalPaintPlugin.Ready || !Object.op_Implicit((Object)(object)__instance))
		{
			return;
		}
		foreach (ItemData allItem in ((Humanoid)__instance).GetInventory().GetAllItems())
		{
			if (NaturalPaintPlugin.IsBrush(allItem))
			{
				allItem.m_equipped = false;
			}
		}
	}
}
[HarmonyPatch(typeof(Hud), "UpdateBuild")]
internal static class PaintHudPatch
{
	private static bool Prefix(Hud __instance, Player player)
	{
		if (!NaturalPaintPlugin.BrushSelected(player))
		{
			if (Object.op_Implicit((Object)(object)NaturalPaintPlugin.Instance))
			{
				NaturalPaintPlugin.Instance.ClearHover();
			}
			return true;
		}
		NaturalPaintPlugin.Instance.UpdateBrushHud(__instance, player);
		return false;
	}
}
[HarmonyPatch(typeof(Hud), "UpdateCrosshair")]
internal static class PaintCrosshairPatch
{
	private static void Postfix(Hud __instance, Player player)
	{
		if (NaturalPaintPlugin.BrushSelected(player))
		{
			NaturalPaintPlugin.Instance.UpdateBrushCrosshair(__instance, player);
		}
	}
}
[HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")]
internal static class PaintHotbarIndicatorPatch
{
	private static void Postfix(HotkeyBar __instance, Player player, int ___m_selected)
	{
		if (NaturalPaintPlugin.Ready && Object.op_Implicit((Object)(object)NaturalPaintPlugin.Instance))
		{
			NaturalPaintPlugin.Instance.UpdateBrushHotbar(__instance, player, ___m_selected);
		}
	}
}
[HarmonyPatch]
internal static class PaintMaterialUpdatePatch
{
	private static MethodBase TargetMethod()
	{
		return AccessTools.Method(typeof(MaterialMan).GetNestedType("PropertyContainer", BindingFlags.NonPublic), "UpdateBlock", (Type[])null, (Type[])null) ?? throw new MissingMethodException("MaterialMan.PropertyContainer.UpdateBlock");
	}

	private static void Postfix(List<Renderer> ___m_assignedRenderers)
	{
		if (!NaturalPaintPlugin.Ready || !Object.op_Implicit((Object)(object)NaturalPaintPlugin.Instance))
		{
			return;
		}
		try
		{
			NaturalPaintPlugin.Instance.NativeMaterialsUpdated(___m_assignedRenderers);
		}
		catch (Exception ex)
		{
			NaturalPaintPlugin.Instance.ReportOnce("paint.materials", ex);
		}
	}
}
[HarmonyPatch(typeof(WearNTear), "Highlight")]
internal static class PaintHighlightPatch
{
	private static void Postfix(WearNTear __instance)
	{
		if (NaturalPaintPlugin.Ready)
		{
			NaturalPaintPlugin.Instance.SetHighlight(__instance, highlighted: true);
		}
	}
}
[HarmonyPatch(typeof(WearNTear), "ResetHighlight")]
internal static class PaintHighlightResetPatch
{
	private static void Postfix(WearNTear __instance)
	{
		if (NaturalPaintPlugin.Ready)
		{
			NaturalPaintPlugin.Instance.SetHighlight(__instance, highlighted: false);
		}
	}
}
[HarmonyPatch(typeof(HotkeyBar), "Update")]
internal static class PaintHotbarInputPatch
{
	private static bool Prefix(HotkeyBar __instance)
	{
		if (!NaturalPaintPlugin.OverlayBlocksInput)
		{
			return true;
		}
		NaturalPaintPlugin.RefreshBlockedHotbar(__instance);
		return false;
	}
}
[HarmonyPatch(typeof(Player), "UseHotbarItem")]
internal static class PaintHotbarUsePatch
{
	private static bool Prefix(Player __instance)
	{
		if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
		{
			return !NaturalPaintPlugin.OverlayBlocksInput;
		}
		return true;
	}
}
[HarmonyPatch(typeof(InventoryGui), "Update")]
internal static class PaintInventoryInputPatch
{
	private static bool Prefix()
	{
		return !NaturalPaintPlugin.OverlayBlocksInput;
	}
}
internal sealed class PaintPaletteHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler
{
	internal int SlotIndex;

	public void OnPointerEnter(PointerEventData eventData)
	{
		if (NaturalPaintPlugin.PaletteOpen)
		{
			NaturalPaintPlugin.Instance.FocusSlot(SlotIndex);
		}
	}
}
[HarmonyPatch(typeof(PlayerController), "TakeInput")]
internal static class PaintControllerInputPatch
{
	private static void Postfix(ref bool __result)
	{
		if (NaturalPaintPlugin.OverlayBlocksInput)
		{
			__result = false;
		}
	}
}
[HarmonyPatch(typeof(Player), "TakeInput")]
internal static class PaintPlayerInputPatch
{
	private static void Postfix(ref bool __result)
	{
		if (NaturalPaintPlugin.OverlayBlocksInput)
		{
			__result = false;
		}
	}
}
[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
internal static class PaintCursorPatch
{
	private static bool Prefix()
	{
		if (!NaturalPaintPlugin.PaletteOpen)
		{
			return true;
		}
		ZCursor.LockState = (CursorLockMode)0;
		ZCursor.Show();
		return false;
	}
}
[HarmonyPatch(typeof(Menu), "Update")]
internal static class PaintMenuPatch
{
	private static bool Prefix()
	{
		return !NaturalPaintPlugin.OverlayBlocksInput;
	}
}
[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
internal static class PaintCameraPatch
{
	private static bool Prefix()
	{
		return !NaturalPaintPlugin.PaletteOpen;
	}
}
[HarmonyPatch(typeof(ObjectDB), "Awake")]
internal static class BrushDbAwakePatch
{
	private static void Postfix(ObjectDB __instance)
	{
		NaturalPaintPlugin.SafeRegister(__instance);
	}
}
[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
internal static class BrushDbCopyPatch
{
	private static void Postfix(ObjectDB __instance)
	{
		NaturalPaintPlugin.SafeRegister(__instance);
	}
}
[HarmonyPatch(typeof(ZNetScene), "Awake")]
internal static class BrushScenePatch
{
	private static void Postfix()
	{
		NaturalPaintPlugin.SafeRegister(ObjectDB.instance);
	}
}
[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
internal static class BrushCraftPatch
{
	private static bool Prefix(InventoryGui __instance, Player player, Recipe ___m_craftRecipe, ItemData ___m_craftUpgradeItem, bool ___m_multiCrafting, int ___m_multiCraftAmount)
	{
		if (!NaturalPaintPlugin.Ready || !NaturalPaintPlugin.IsBrushRecipe(___m_craftRecipe))
		{
			return true;
		}
		NaturalPaintPlugin.Instance.CompleteCraft(__instance, player, ___m_craftRecipe, ___m_craftUpgradeItem, ___m_multiCrafting, ___m_multiCraftAmount);
		return false;
	}
}
[HarmonyPatch(typeof(Player), "SetControls")]
internal static class PaintControlsPatch
{
	private static void Prefix(Player __instance, ref Vector3 movedir, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold, ref bool jump, ref bool crouch, ref bool run, ref bool autoRun, ref bool dodge)
	{
		//IL_0024: 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)
		if (!NaturalPaintPlugin.Ready || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		if (NaturalPaintPlugin.OverlayBlocksInput)
		{
			__instance.m_autoRun = false;
			movedir = Vector3.zero;
			attack = (attackHold = (secondaryAttack = (secondaryAttackHold = (block = (blockHold = false)))));
			jump = (crouch = (run = (autoRun = (dodge = false))));
		}
		else if (NaturalPaintPlugin.IsBrush(((Humanoid)__instance).RightItem))
		{
			if (attack)
			{
				NaturalPaintPlugin.Instance.UseBrush(__instance);
			}
			attack = (attackHold = (secondaryAttack = (secondaryAttackHold = (block = (blockHold = false)))));
		}
	}
}
[HarmonyPatch(typeof(Player), "PlayerAttackInput")]
internal static class PaintNoAttackPatch
{
	private static bool Prefix(Player __instance)
	{
		if (NaturalPaintPlugin.Ready)
		{
			return !NaturalPaintPlugin.IsBrush(((Humanoid)__instance).RightItem);
		}
		return true;
	}
}
[HarmonyPatch(typeof(WearNTear), "Start")]
internal static class BrushPieceStartPatch
{
	private static void Postfix(WearNTear __instance)
	{
		if (!NaturalPaintPlugin.Ready)
		{
			return;
		}
		try
		{
			NaturalPaintPlugin.Instance.Track(__instance);
		}
		catch (Exception ex)
		{
			NaturalPaintPlugin.Instance.ReportOnce("paint.track", ex);
		}
	}
}
[HarmonyPatch(typeof(WearNTear), "OnDestroy")]
internal static class BrushPieceDestroyPatch
{
	private static void Prefix(WearNTear __instance)
	{
		if (Object.op_Implicit((Object)(object)NaturalPaintPlugin.Instance))
		{
			NaturalPaintPlugin.Instance.Forget(__instance);
		}
	}
}
namespace NaturalPaintLogic;

internal sealed class CraftCompatibility
{
	private const BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private const BindingFlags StaticFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

	private readonly FieldInfo _itemFlag;

	private readonly FieldInfo _bypassChecks;

	private readonly FieldInfo _stationKey;

	private readonly Type _statType;

	private readonly MethodInfo _incrementStat;

	private readonly MethodInfo _incrementItemCraft;

	private readonly Action<string, Exception> _report;

	internal bool HasItemFlag => _itemFlag != null;

	internal string Description => "itemFlag=" + (_itemFlag != null) + "; bypassField=" + (_bypassChecks != null) + "; stationFlag=" + (_stationKey != null) + "; craftStats=" + (_incrementStat != null);

	internal int? StationCheatedKey
	{
		get
		{
			if (!(_stationKey == null))
			{
				return (int)_stationKey.GetValue(null);
			}
			return null;
		}
	}

	internal CraftCompatibility(Type itemType, Type profileType, Type statType, Type zdoVarsType, Action<string, Exception> report)
	{
		_report = report;
		_itemFlag = FindField(itemType, "m_cheated", typeof(bool), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		_bypassChecks = FindField(profileType, "s_bypassCheatChecks", typeof(bool), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		_stationKey = FindField(zdoVarsType, "s_cheated", typeof(int), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		_statType = ((statType != null && statType.IsEnum) ? statType : null);
		if (_statType != null)
		{
			_incrementStat = FindMethod(profileType, "IncrementStat", _statType, typeof(float), typeof(bool)) ?? FindMethod(profileType, "IncrementStat", _statType, typeof(float));
		}
		_incrementItemCraft = FindMethod(profileType, "IncrementStatItemCraft", typeof(string), typeof(int), typeof(bool)) ?? FindMethod(profileType, "IncrementStatItemCraft", typeof(string), typeof(int));
	}

	private static FieldInfo FindField(Type type, string name, Type fieldType, BindingFlags flags)
	{
		FieldInfo fieldInfo = ((type == null) ? null : type.GetField(name, flags));
		if (!(fieldInfo != null) || !(fieldInfo.FieldType == fieldType))
		{
			return null;
		}
		return fieldInfo;
	}

	private static MethodInfo FindMethod(Type type, string name, params Type[] args)
	{
		if (!(type == null))
		{
			return type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, args, null);
		}
		return null;
	}

	internal bool IsItemCheated(object item)
	{
		if (item != null && _itemFlag != null)
		{
			return (bool)_itemFlag.GetValue(item);
		}
		return false;
	}

	internal bool SetItemMetadata(object item, bool noCost, bool resourceCheated, bool stationCheated)
	{
		if (_itemFlag == null)
		{
			return false;
		}
		bool flag = _bypassChecks != null && (bool)_bypassChecks.GetValue(null);
		bool flag2 = IsItemCheated(item) || (!flag && (noCost || resourceCheated || stationCheated));
		_itemFlag.SetValue(item, flag2);
		return flag2;
	}

	internal void RecordCraft(object profile, string itemName, int amount, bool cheated)
	{
		if (profile != null)
		{
			Increment(profile, "CraftsOrUpgrades", 1f, cheated);
			Increment(profile, "Crafts", amount, cheated);
			if (_incrementItemCraft != null)
			{
				InvokeStat(_incrementItemCraft, profile, (_incrementItemCraft.GetParameters().Length != 3) ? new obje