Decompiled source of ElixDrax TamedCreatureXP v0.5.7

BepInEx/plugins/TamedCreatureXP.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TamedCreatureXP
{
	internal static class CreatureBackpack
	{
		private sealed class WispVisualState
		{
			public Character Creature;

			public Transform Root;

			public Vector3 Center;

			public float Radius;

			public float Height;

			public float Phase;

			public float Speed;
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDbAwakePatch
		{
			private static void Postfix()
			{
				Initialize();
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UseItem", new Type[]
		{
			typeof(Inventory),
			typeof(ItemData),
			typeof(bool)
		})]
		private static class UseBackpackItemPatch
		{
			private static bool Prefix(Humanoid __instance, Inventory __0, ItemData __1)
			{
				try
				{
					return UseBackpackItem(__instance, __0, __1);
				}
				catch (Exception ex)
				{
					Plugin.ModLog.LogError((object)("Could not equip creature backpack: " + ex));
					return false;
				}
			}
		}

		[HarmonyPatch(typeof(Container), "Awake")]
		private static class VirtualContainerAwakePatch
		{
			private static bool Prefix(Container __instance)
			{
				return VirtualContainerAwakePrefix(__instance);
			}
		}

		[HarmonyPatch(typeof(Container), "GetInventory")]
		private static class VirtualGetInventoryPatch
		{
			private static bool Prefix(Container __instance, ref Inventory __result)
			{
				return GetInventoryPrefix(__instance, ref __result);
			}
		}

		[HarmonyPatch(typeof(Container), "Load")]
		private static class VirtualContainerLoadPatch
		{
			private static bool Prefix(Container __instance, ref bool __result)
			{
				return ContainerLoadPrefix(__instance, ref __result);
			}
		}

		[HarmonyPatch(typeof(Container), "Save")]
		private static class VirtualContainerSavePatch
		{
			private static bool Prefix(Container __instance)
			{
				return ContainerSavePrefix(__instance);
			}
		}

		[HarmonyPatch(typeof(Container), "SetInUse")]
		private static class VirtualContainerUsePatch
		{
			[HarmonyPriority(800)]
			private static bool Prefix(Container __instance, bool __0)
			{
				return SetInUsePrefix(__instance, __0);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		private static class SaveBackpackOnGuiClosePatch
		{
			private static void Prefix()
			{
				OnGuiClosing();
			}

			private static void Postfix()
			{
				OnGuiClosed();
				HideBackpackPanelFrame();
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static class KeepVirtualContainerInRangePatch
		{
			private static void Prefix(InventoryGui __instance, Player __0)
			{
				try
				{
					FollowPlayerWhileOpen(__instance, __0);
				}
				catch (Exception ex)
				{
					Plugin.ModLog.LogDebug((object)("Could not keep the backpack container within interaction range: " + ex.Message));
				}
			}

			private static void Postfix(InventoryGui __instance)
			{
				try
				{
					UpdateBackpackInventoryStyle(__instance);
				}
				catch (Exception ex)
				{
					Plugin.ModLog.LogDebug((object)("Could not style the backpack inventory panel: " + ex.Message));
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "CloseContainer")]
		private static class HideBackpackPanelFramePatch
		{
			private static void Postfix()
			{
				HideBackpackPanelFrame();
			}
		}

		private const string ItemPrefabName = "TamedCreatureXP_CreatureBackpack";

		private const string ItemInternalName = "$item_tamedcreaturexp_creaturebackpack";

		private const string ContainerObjectName = "TamedCreatureXP_VirtualCreatureBackpack";

		private const string VisualObjectName = "TamedCreatureXP_CreatureBackpackVisual_v3";

		private const string LegacyVisualObjectName = "TamedCreatureXP_CreatureBackpackVisual";

		private const string PreviousVisualObjectName = "TamedCreatureXP_CreatureBackpackVisual_v2";

		private const string BackpackPanelFrameName = "TamedCreatureXP_CreatureBackpackPanelFrame";

		private const string HasPackKey = "TamedCreatureXP.HasBackpack";

		private const string ContentsKey = "TamedCreatureXP.BackpackContents";

		private const int UnlockLevel = 4;

		private const int BackpackWidth = 5;

		private const int BackpackHeight = 3;

		private static ObjectDB _registeredObjectDb;

		private static GameObject _itemPrefab;

		private static Recipe _recipe;

		private static bool _recipeUnlocked;

		private static Container _virtualContainer;

		private static Inventory _virtualInventory;

		private static Character _openCreature;

		private static ZDO _openZdo;

		private static Sprite _backpackSprite;

		private static Sprite _panelFrameSprite;

		private static Transform _panelFrame;

		private static Material _violetTrailMaterial;

		private static readonly List<WispVisualState> WispVisuals = new List<WispVisualState>();

		private static bool _saving;

		private static bool _closingVirtualContainer;

		private static float _nextPeriodicSave;

		private static bool _warnedRegistration;

		private static bool _warnedSave;

		private static bool _warnedVisual;

		private static bool _warnedJotunn;

		private static bool _warnedPanelStyle;

		private static bool _azuAutoStoreCompatibilityPatched;

		private static bool _warnedAzuAutoStorePatch;

		private static object _jotunnCustomItem;

		private static object _jotunnCustomRecipe;

		private static bool _jotunnItemAdded;

		internal static void Initialize()
		{
			try
			{
				EnsureObjectDbRegistration();
			}
			catch (Exception ex)
			{
				if (!_warnedRegistration)
				{
					_warnedRegistration = true;
					Plugin.ModLog.LogWarning((object)("Creature backpack registration is waiting for Valheim: " + ex.Message));
				}
			}
		}

		private static List<Character> SnapshotLoadedCharacters()
		{
			List<Character> list = new List<Character>();
			FieldInfo fieldInfo = AccessTools.Field(typeof(Character), "s_characters");
			IEnumerable enumerable = ((fieldInfo == null) ? null : (fieldInfo.GetValue(null) as IEnumerable));
			if (enumerable == null)
			{
				return list;
			}
			try
			{
				foreach (object item in enumerable)
				{
					Character val = (Character)((item is Character) ? item : null);
					if ((Object)(object)val != (Object)null)
					{
						list.Add(val);
					}
				}
			}
			catch (InvalidOperationException ex)
			{
				Plugin.ModLog.LogDebug((object)("Creature list changed while being copied for backpack refresh: " + ex.Message));
			}
			return list;
		}

		internal static void TryPatchAzuAutoStore(Harmony harmony)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			if (_azuAutoStoreCompatibilityPatched || harmony == null)
			{
				return;
			}
			Type type = AccessTools.TypeByName("AzuAutoStore.Patches.ContainerSetInUseClearWithoutOwnershipPatch");
			MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null));
			MethodInfo methodInfo2 = AccessTools.Method(typeof(CreatureBackpack), "AzuAutoStoreContainerPrefixGuard", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				return;
			}
			try
			{
				HarmonyMethod val = new HarmonyMethod(methodInfo2);
				val.priority = 800;
				harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_azuAutoStoreCompatibilityPatched = true;
				Plugin.ModLog.LogInfo((object)"AzuAutoStore compatibility enabled for the virtual creature backpack.");
			}
			catch (Exception ex)
			{
				if (!_warnedAzuAutoStorePatch)
				{
					_warnedAzuAutoStorePatch = true;
					Plugin.ModLog.LogWarning((object)("Could not isolate the virtual creature backpack from AzuAutoStore: " + ex.Message));
				}
			}
		}

		private static bool AzuAutoStoreContainerPrefixGuard(Container __0)
		{
			return !IsVirtual(__0);
		}

		internal static void RefreshRecipeUnlock()
		{
			Initialize();
			if ((Object)(object)_recipe == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			bool flag = Plugin.BackpackUnlocked != null && Plugin.BackpackUnlocked.Value;
			try
			{
				foreach (Character item in SnapshotLoadedCharacters())
				{
					if (!Plugin.IsAllowedTamedCreature(item) || item.GetLevel() < 4)
					{
						continue;
					}
					flag = true;
					if (Plugin.BackpackUnlocked != null && !Plugin.BackpackUnlocked.Value)
					{
						Plugin.BackpackUnlocked.Value = true;
						if ((Object)(object)Plugin.Instance != (Object)null)
						{
							((BaseUnityPlugin)Plugin.Instance).Config.Save();
						}
					}
					break;
				}
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogDebug((object)("Could not inspect tamed creatures for backpack recipe unlock: " + ex.Message));
			}
			if (_recipeUnlocked == flag && _recipe.m_enabled == flag)
			{
				return;
			}
			_recipeUnlocked = flag;
			_recipe.m_enabled = flag;
			try
			{
				AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null)?.Invoke(ObjectDB.instance, null);
			}
			catch (Exception ex2)
			{
				Plugin.ModLog.LogDebug((object)("Could not refresh backpack recipe: " + ex2.Message));
			}
		}

		internal static void RefreshAttachedBackpacks()
		{
			try
			{
				foreach (Character item in SnapshotLoadedCharacters())
				{
					if ((Object)(object)item == (Object)null || !item.IsTamed() || item.IsDead())
					{
						continue;
					}
					ZNetView nView = Plugin.GetNView(item);
					ZDO val = (((Object)(object)nView != (Object)null && nView.IsValid()) ? nView.GetZDO() : null);
					if (val != null)
					{
						if (val.GetBool("TamedCreatureXP.HasBackpack", false))
						{
							EnsureBackpackVisual(item);
						}
						else
						{
							RemoveBackpackVisual(item);
						}
					}
				}
			}
			catch (Exception ex)
			{
				if (!_warnedVisual)
				{
					_warnedVisual = true;
					Plugin.ModLog.LogWarning((object)("Could not refresh visible creature backpacks: " + ex));
				}
			}
		}

		internal static void TickBackpackWisps()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			for (int num = WispVisuals.Count - 1; num >= 0; num--)
			{
				WispVisualState wispVisualState = WispVisuals[num];
				if (wispVisualState == null || (Object)(object)wispVisualState.Creature == (Object)null || (Object)(object)wispVisualState.Root == (Object)null || wispVisualState.Creature.IsDead())
				{
					WispVisuals.RemoveAt(num);
				}
				else
				{
					float num2 = Time.time * wispVisualState.Speed + wispVisualState.Phase;
					wispVisualState.Root.localPosition = wispVisualState.Center + new Vector3(Mathf.Cos(num2) * wispVisualState.Radius, Mathf.Sin(num2 * 2f) * wispVisualState.Height, Mathf.Sin(num2) * wispVisualState.Radius);
					wispVisualState.Root.localRotation = Quaternion.Euler(0f, (0f - num2) * 57.29578f, 0f);
					TickWispSparks(wispVisualState, num2);
				}
			}
			if ((Object)(object)_openCreature != (Object)null && Time.unscaledTime >= _nextPeriodicSave)
			{
				_nextPeriodicSave = Time.unscaledTime + 0.75f;
				SaveIfOpen();
			}
		}

		internal static void EnsureAttachedBackpack(Character creature)
		{
			if (!((Object)(object)creature == (Object)null) && creature.IsTamed() && !creature.IsDead())
			{
				ZNetView nView = Plugin.GetNView(creature);
				ZDO val = (((Object)(object)nView != (Object)null && nView.IsValid()) ? nView.GetZDO() : null);
				if (val != null && val.GetBool("TamedCreatureXP.HasBackpack", false))
				{
					EnsureBackpackVisual(creature);
				}
				else
				{
					RemoveBackpackVisual(creature);
				}
			}
		}

		internal static bool HasBackpack(Character creature)
		{
			if ((Object)(object)creature == (Object)null)
			{
				return false;
			}
			ZNetView nView = Plugin.GetNView(creature);
			ZDO val = (((Object)(object)nView != (Object)null && nView.IsValid()) ? nView.GetZDO() : null);
			if (val != null)
			{
				return val.GetBool("TamedCreatureXP.HasBackpack", false);
			}
			return false;
		}

		private static byte[] SerializeInventory(Inventory inventory)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			if (inventory == null)
			{
				return null;
			}
			ZPackage val = new ZPackage();
			inventory.Save(val);
			return val.GetArray();
		}

		private static void EnsureBackpackVisual(Character creature)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Transform val = FindChild(((Component)creature).transform, "TamedCreatureXP_CreatureBackpackVisual");
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
				Transform val2 = FindChild(((Component)creature).transform, "TamedCreatureXP_CreatureBackpackVisual_v2");
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)val2).gameObject);
				}
				Transform val3 = FindChild(((Component)creature).transform, "TamedCreatureXP_CreatureBackpackVisual_v3");
				if ((Object)(object)val3 == (Object)null)
				{
					val3 = new GameObject("TamedCreatureXP_CreatureBackpackVisual_v3").transform;
					val3.SetParent(((Component)creature).transform, false);
					BuildBackpackWisp(val3, creature);
				}
				FitBackpackWisp(creature, val3);
			}
			catch (Exception ex)
			{
				if (!_warnedVisual)
				{
					_warnedVisual = true;
					Plugin.ModLog.LogWarning((object)("Could not create visible backpack on " + ((Object)((Component)creature).gameObject).name + ": " + ex));
				}
			}
		}

		private static void BuildBackpackWisp(Transform root, Character creature)
		{
			//IL_0035: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = FindWispVisualSource();
			GameObject val2 = null;
			if ((Object)(object)val != (Object)null)
			{
				try
				{
					val2 = Object.Instantiate<GameObject>(val, root, false);
					((Object)val2).name = "VioletWispTexturedModel";
					val2.SetActive(true);
					val2.transform.localPosition = Vector3.zero;
					val2.transform.localRotation = Quaternion.identity;
					val2.transform.localScale = Vector3.one;
					StripNonVisualComponents(val2);
					TintWispRenderers(val2, new Color(0.76f, 0.4f, 1f, 1f));
					TuneWispEffects(val2);
					NormalizeWispSize(val2);
					PlayWispParticles(val2);
				}
				catch (Exception ex)
				{
					Plugin.ModLog.LogDebug((object)("Could not reuse an in-game wisp visual: " + ex.Message));
					if ((Object)(object)val2 != (Object)null)
					{
						Object.Destroy((Object)(object)val2);
					}
					val2 = null;
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				BuildTexturedFallbackWisp(root, creature);
			}
			AddVioletWispTrails(root);
			if (!HasParticleVisual(root))
			{
				AddWispSparkMotes(root);
			}
		}

		private static void AddVioletWispTrails(Transform root)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)root == (Object)null) && !((Object)(object)FindChild(root, "VioletWispTrailGlow") != (Object)null))
			{
				Material violetTrailMaterial = GetVioletTrailMaterial();
				if (!((Object)(object)violetTrailMaterial == (Object)null))
				{
					CreateWispTrail(root, "VioletWispTrailGlow", violetTrailMaterial, 0.06f, 0.38f, new Color(0.68f, 0.36f, 1f, 1f), new Color(0.42f, 0.18f, 0.82f, 1f), 0.18f);
					CreateWispTrail(root, "VioletWispTrailCore", violetTrailMaterial, 0.024f, 0.32f, new Color(0.91f, 0.76f, 1f, 1f), new Color(0.66f, 0.38f, 1f, 1f), 0.68f);
				}
			}
		}

		private static Material GetVioletTrailMaterial()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_violetTrailMaterial != (Object)null)
			{
				return _violetTrailMaterial;
			}
			Shader val = Shader.Find("Particles/Standard Unlit");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Sprites/Default");
			}
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Legacy Shaders/Particles/Alpha Blended");
			}
			if ((Object)(object)val == (Object)null)
			{
				if (!_warnedVisual)
				{
					_warnedVisual = true;
					Plugin.ModLog.LogWarning((object)"Could not find a transparent shader for the violet backpack wisp trail.");
				}
				return null;
			}
			_violetTrailMaterial = new Material(val);
			string[] array = new string[3] { "_Color", "_BaseColor", "_TintColor" };
			foreach (string text in array)
			{
				if (_violetTrailMaterial.HasProperty(text))
				{
					_violetTrailMaterial.SetColor(text, Color.white);
				}
			}
			return _violetTrailMaterial;
		}

		private static void CreateWispTrail(Transform root, string name, Material material, float width, float duration, Color startColor, Color endColor, float alpha)
		{
			//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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(root, false);
			TrailRenderer val2 = val.AddComponent<TrailRenderer>();
			((Renderer)val2).material = material;
			val2.time = duration;
			val2.widthMultiplier = width;
			val2.widthCurve = new AnimationCurve((Keyframe[])(object)new Keyframe[2]
			{
				new Keyframe(0f, 1f),
				new Keyframe(1f, 0.08f)
			});
			val2.minVertexDistance = 0.012f;
			val2.numCornerVertices = 8;
			val2.numCapVertices = 8;
			val2.emitting = true;
			val2.autodestruct = false;
			Gradient val3 = new Gradient();
			val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2]
			{
				new GradientColorKey(startColor, 0f),
				new GradientColorKey(endColor, 1f)
			}, (GradientAlphaKey[])(object)new GradientAlphaKey[3]
			{
				new GradientAlphaKey(alpha, 0f),
				new GradientAlphaKey(alpha * 0.28f, 0.55f),
				new GradientAlphaKey(0f, 1f)
			});
			val2.colorGradient = val3;
		}

		private static GameObject FindWispVisualSource()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				Transform[] componentsInChildren = ((Component)localPlayer).GetComponentsInChildren<Transform>(true);
				GameObject val = null;
				int num = 0;
				Transform[] array = componentsInChildren;
				foreach (Transform val2 in array)
				{
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)((Component)localPlayer).transform) && ((Object)val2).name.ToLowerInvariant().IndexOf("wisp", StringComparison.Ordinal) >= 0 && ((Component)val2).GetComponentsInChildren<Renderer>(true).Length != 0 && IsVisualOnlyTree(((Component)val2).gameObject))
					{
						int num2 = ScoreWispVisualSource(val2);
						if (num2 > num)
						{
							num = num2;
							val = ((Component)val2).gameObject;
						}
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static int ScoreWispVisualSource(Transform candidate)
		{
			Renderer[] componentsInChildren = ((Component)candidate).GetComponentsInChildren<Renderer>(true);
			MeshFilter[] componentsInChildren2 = ((Component)candidate).GetComponentsInChildren<MeshFilter>(true);
			Component[] componentsInChildren3 = ((Component)candidate).GetComponentsInChildren<Component>(true);
			int num = componentsInChildren.Length * 10 + componentsInChildren2.Length * 4;
			Component[] array = componentsInChildren3;
			foreach (Component val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					switch (((object)val).GetType().Name)
					{
					case "ParticleSystem":
						num += 4;
						break;
					case "TrailRenderer":
						num += 5;
						break;
					case "Light":
						num += 3;
						break;
					}
				}
			}
			string text = ((Object)candidate).name.ToLowerInvariant();
			if (text.Contains("wisplight"))
			{
				num += 80;
			}
			else if (text == "wisp")
			{
				num += 24;
			}
			return num;
		}

		private static bool IsVisualOnlyTree(GameObject root)
		{
			Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !(val is Transform) && !(val is Renderer) && !(val is MeshFilter) && !(((object)val).GetType().Name == "Animator") && !(((object)val).GetType().Name == "Animation") && !(((object)val).GetType().Name == "ParticleSystem") && !(((object)val).GetType().Name == "Light"))
				{
					return false;
				}
			}
			return true;
		}

		private static void StripNonVisualComponents(GameObject root)
		{
			Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !(val is Transform) && !(val is Renderer) && !(val is MeshFilter) && !(((object)val).GetType().Name == "Animator") && !(((object)val).GetType().Name == "Animation") && !(((object)val).GetType().Name == "ParticleSystem") && !(((object)val).GetType().Name == "Light"))
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}

		private static void TintWispRenderers(GameObject root, Color tint)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Material[] materials = val.materials;
				Material[] array = materials;
				foreach (Material val2 in array)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					string[] array2 = new string[3] { "_Color", "_BaseColor", "_TintColor" };
					foreach (string text in array2)
					{
						if (val2.HasProperty(text))
						{
							Color color = val2.GetColor(text);
							val2.SetColor(text, new Color(color.r * tint.r, color.g * tint.g, color.b * tint.b, color.a * tint.a));
						}
					}
					if (val2.HasProperty("_EmissionColor"))
					{
						val2.SetColor("_EmissionColor", tint * 1.6f);
						val2.EnableKeyword("_EMISSION");
					}
				}
				val.materials = materials;
			}
		}

		private static void NormalizeWispSize(GameObject root)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			if (componentsInChildren.Length == 0)
			{
				return;
			}
			List<Renderer> list = new List<Renderer>();
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				if ((Object)(object)val != (Object)null && ((object)val).GetType().Name != "ParticleSystemRenderer" && ((object)val).GetType().Name != "TrailRenderer")
				{
					list.Add(val);
				}
			}
			if (list.Count != 0)
			{
				Bounds bounds = list[0].bounds;
				for (int j = 1; j < list.Count; j++)
				{
					((Bounds)(ref bounds)).Encapsulate(list[j].bounds);
				}
				float num = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z));
				if (num > 0.001f)
				{
					Transform transform = root.transform;
					transform.localScale *= 0.82f / num;
				}
			}
		}

		private static void PlayWispParticles(GameObject root)
		{
			Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !(((object)val).GetType().Name != "ParticleSystem"))
				{
					try
					{
						AccessTools.Method(((object)val).GetType(), "Play", new Type[1] { typeof(bool) }, (Type[])null)?.Invoke(val, new object[1] { true });
					}
					catch (Exception ex)
					{
						Plugin.ModLog.LogDebug((object)("Could not start a cloned wisp particle system: " + ex.Message));
					}
				}
			}
		}

		private static void TuneWispEffects(GameObject root)
		{
			Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
			Type type = AccessTools.TypeByName("UnityEngine.TrailRenderer");
			Component[] array = componentsInChildren;
			foreach (Component val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				try
				{
					if (type != null && type.IsInstanceOfType(val))
					{
						SetFloatProperty(val, "time", 0.28f, onlyReduce: true);
						float floatProperty = GetFloatProperty(val, "widthMultiplier", 0.1f);
						SetFloatProperty(val, "widthMultiplier", Mathf.Max(0.008f, floatProperty * 0.48f), onlyReduce: false);
						SetFloatProperty(val, "minVertexDistance", 0.025f, onlyReduce: true);
						SetIntProperty(val, "numCornerVertices", 5);
						SetIntProperty(val, "numCapVertices", 5);
						AccessTools.Method(((object)val).GetType(), "Clear", (Type[])null, (Type[])null)?.Invoke(val, null);
					}
					else if (((object)val).GetType().Name == "ParticleSystem")
					{
						ReduceParticleCurve(val, "startLifetime", 0.55f, 0.65f);
						ReduceParticleCurve(val, "startSize", 0.15f, 0.65f);
					}
				}
				catch (Exception ex)
				{
					Plugin.ModLog.LogDebug((object)("Could not tune a cloned wisp effect: " + ex.Message));
				}
			}
		}

		private static void ReduceParticleCurve(Component particleSystem, string propertyName, float maximum, float factor)
		{
			PropertyInfo propertyInfo = AccessTools.Property(((object)particleSystem).GetType(), "main");
			if (propertyInfo == null)
			{
				return;
			}
			object value = propertyInfo.GetValue(particleSystem, null);
			if (value == null)
			{
				return;
			}
			PropertyInfo propertyInfo2 = AccessTools.Property(value.GetType(), propertyName);
			if (!(propertyInfo2 == null) && propertyInfo2.CanWrite)
			{
				object value2 = propertyInfo2.GetValue(value, null);
				PropertyInfo propertyInfo3 = ((value2 == null) ? null : AccessTools.Property(value2.GetType(), "constantMax"));
				float num = ((propertyInfo3 == null) ? maximum : Convert.ToSingle(propertyInfo3.GetValue(value2, null)));
				float num2 = Mathf.Min(maximum, num * factor);
				if (!(num2 <= 0f))
				{
					object value3 = Activator.CreateInstance(propertyInfo2.PropertyType, num2);
					propertyInfo2.SetValue(value, value3, null);
				}
			}
		}

		private static float GetFloatProperty(Component component, string name, float fallback)
		{
			PropertyInfo propertyInfo = AccessTools.Property(((object)component).GetType(), name);
			if (propertyInfo == null)
			{
				return fallback;
			}
			object value = propertyInfo.GetValue(component, null);
			if (value != null)
			{
				return Convert.ToSingle(value);
			}
			return fallback;
		}

		private static void SetFloatProperty(Component component, string name, float value, bool onlyReduce)
		{
			PropertyInfo propertyInfo = AccessTools.Property(((object)component).GetType(), name);
			if (!(propertyInfo == null) && propertyInfo.CanWrite)
			{
				float num = value;
				if (onlyReduce)
				{
					num = Mathf.Min(GetFloatProperty(component, name, value), value);
				}
				propertyInfo.SetValue(component, num, null);
			}
		}

		private static void SetIntProperty(Component component, string name, int value)
		{
			PropertyInfo propertyInfo = AccessTools.Property(((object)component).GetType(), name);
			if (propertyInfo != null && propertyInfo.CanWrite)
			{
				propertyInfo.SetValue(component, value, null);
			}
		}

		private static bool HasParticleVisual(Transform root)
		{
			Component[] componentsInChildren = ((Component)root).GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "ParticleSystem")
				{
					return true;
				}
			}
			return false;
		}

		private static void BuildTexturedFallbackWisp(Transform root, Character creature)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)val).name = "VioletWispFallback";
			val.transform.SetParent(root, false);
			val.transform.localScale = Vector3.one;
			Renderer component = val.GetComponent<Renderer>();
			Type type = AccessTools.TypeByName("UnityEngine.Collider");
			Component val2 = ((type == null) ? null : val.GetComponent(type));
			PropertyInfo propertyInfo = ((type == null) ? null : AccessTools.Property(type, "enabled"));
			if ((Object)(object)val2 != (Object)null && propertyInfo != null)
			{
				propertyInfo.SetValue(val2, false, null);
			}
			Material val3 = FindCreatureMaterial(creature);
			if ((Object)(object)component != (Object)null && (Object)(object)val3 != (Object)null)
			{
				component.material = new Material(val3);
				TintWispRenderers(val, new Color(0.76f, 0.4f, 1f, 1f));
			}
			else
			{
				if (!((Object)(object)component != (Object)null))
				{
					return;
				}
				Material material = component.material;
				if (!((Object)(object)material != (Object)null))
				{
					return;
				}
				Color val4 = default(Color);
				((Color)(ref val4))..ctor(0.76f, 0.4f, 1f, 1f);
				string[] array = new string[3] { "_Color", "_BaseColor", "_TintColor" };
				foreach (string text in array)
				{
					if (material.HasProperty(text))
					{
						material.SetColor(text, val4);
					}
				}
				if (material.HasProperty("_EmissionColor"))
				{
					material.SetColor("_EmissionColor", val4 * 1.6f);
					material.EnableKeyword("_EMISSION");
				}
			}
		}

		private static Material FindCreatureMaterial(Character creature)
		{
			if ((Object)(object)creature == (Object)null)
			{
				return null;
			}
			Renderer[] componentsInChildren = ((Component)creature).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || IsChildOfNamedTransform(((Component)val).transform, "TamedCreatureXP_CreatureBackpackVisual_v3"))
				{
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				if (sharedMaterials == null)
				{
					continue;
				}
				Material[] array = sharedMaterials;
				foreach (Material val2 in array)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						return val2;
					}
				}
			}
			return null;
		}

		private static void AddWispSparkMotes(Transform root)
		{
			//IL_0038: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: 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_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 5; i++)
			{
				GameObject val = GameObject.CreatePrimitive((PrimitiveType)0);
				((Object)val).name = "VioletWispMote_" + i;
				val.transform.SetParent(root, false);
				val.transform.localScale = Vector3.one * ((i % 2 == 0) ? 0.11f : 0.075f);
				val.transform.localPosition = Vector3.zero;
				Renderer component = val.GetComponent<Renderer>();
				Type type = AccessTools.TypeByName("UnityEngine.Collider");
				Component val2 = ((type == null) ? null : val.GetComponent(type));
				PropertyInfo propertyInfo = ((type == null) ? null : AccessTools.Property(type, "enabled"));
				if ((Object)(object)val2 != (Object)null && propertyInfo != null)
				{
					propertyInfo.SetValue(val2, false, null);
				}
				if ((Object)(object)component != (Object)null)
				{
					Material material = component.material;
					if ((Object)(object)material != (Object)null && material.HasProperty("_Color"))
					{
						material.SetColor("_Color", (i % 2 == 0) ? new Color(0.9f, 0.72f, 1f, 1f) : new Color(0.55f, 0.18f, 0.95f, 1f));
					}
					if ((Object)(object)material != (Object)null && material.HasProperty("_EmissionColor"))
					{
						material.SetColor("_EmissionColor", new Color(0.65f, 0.2f, 1f, 1f) * 1.7f);
						material.EnableKeyword("_EMISSION");
					}
				}
			}
		}

		private static void TickWispSparks(WispVisualState state, float angle)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < state.Root.childCount; i++)
			{
				Transform child = state.Root.GetChild(i);
				if (!((Object)(object)child == (Object)null) && ((Object)child).name.IndexOf("VioletWispMote_", StringComparison.Ordinal) == 0)
				{
					float num = (float)i * (float)Math.PI * 0.4f;
					float num2 = 1f + (float)(i % 2) * 0.25f;
					child.localPosition = new Vector3(Mathf.Cos(angle * num2 + num) * 0.72f, Mathf.Sin(angle * 1.7f + num) * 0.55f, Mathf.Sin(angle * num2 + num) * 0.72f);
				}
			}
		}

		private static void FitBackpackWisp(Character creature, Transform visual)
		{
			//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)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Renderer[] componentsInChildren = ((Component)creature).GetComponentsInChildren<Renderer>();
				Bounds bounds = default(Bounds);
				((Bounds)(ref bounds))..ctor(((Component)creature).transform.position + Vector3.up, Vector3.one);
				bool flag = false;
				Renderer[] array = componentsInChildren;
				foreach (Renderer val in array)
				{
					if (!((Object)(object)val == (Object)null) && !IsChildOfNamedTransform(((Component)val).transform, "TamedCreatureXP_CreatureBackpackVisual_v3") && (val is SkinnedMeshRenderer || val is MeshRenderer))
					{
						if (!flag)
						{
							bounds = val.bounds;
							flag = true;
						}
						else
						{
							((Bounds)(ref bounds)).Encapsulate(val.bounds);
						}
					}
				}
				float num = (flag ? Mathf.Max(0.5f, ((Bounds)(ref bounds)).size.y) : 1.5f);
				Vector3 val2 = ((Component)creature).transform.InverseTransformPoint(flag ? ((Bounds)(ref bounds)).center : (((Component)creature).transform.position + Vector3.up * num * 0.5f));
				float num2 = Mathf.Max(0.1f, Mathf.Abs(((Component)creature).transform.lossyScale.y));
				float num3 = num / num2;
				float num4 = Mathf.Clamp(num3 * 0.04f, 0.09f, 0.15f);
				WispVisualState wispVisualState = FindWispState(visual);
				if (wispVisualState == null)
				{
					wispVisualState = new WispVisualState
					{
						Creature = creature,
						Root = visual,
						Phase = (float)(((Object)creature).GetInstanceID() % 1000) * 0.013f,
						Speed = 2f
					};
					WispVisuals.Add(wispVisualState);
				}
				wispVisualState.Creature = creature;
				wispVisualState.Root = visual;
				wispVisualState.Center = val2 + Vector3.up * (num3 * 0.16f);
				wispVisualState.Radius = Mathf.Clamp(num3 * 0.35f, 0.38f, 1.05f);
				wispVisualState.Height = Mathf.Clamp(num3 * 0.055f, 0.045f, 0.16f);
				visual.localScale = Vector3.one * num4;
				TickSingleWisp(wispVisualState);
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogDebug((object)("Could not position backpack wisp on " + ((Object)((Component)creature).gameObject).name + ": " + ex.Message));
			}
		}

		private static WispVisualState FindWispState(Transform visual)
		{
			for (int i = 0; i < WispVisuals.Count; i++)
			{
				if (WispVisuals[i] != null && (Object)(object)WispVisuals[i].Root == (Object)(object)visual)
				{
					return WispVisuals[i];
				}
			}
			return null;
		}

		private static void TickSingleWisp(WispVisualState state)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			float num = Time.time * state.Speed + state.Phase;
			state.Root.localPosition = state.Center + new Vector3(Mathf.Cos(num) * state.Radius, Mathf.Sin(num * 2f) * state.Height, Mathf.Sin(num) * state.Radius);
			state.Root.localRotation = Quaternion.Euler(0f, (0f - num) * 57.29578f, 0f);
		}

		private static bool IsChildOfNamedTransform(Transform transform, string name)
		{
			while ((Object)(object)transform != (Object)null)
			{
				if (((Object)transform).name == name)
				{
					return true;
				}
				transform = transform.parent;
			}
			return false;
		}

		private static Transform FindChild(Transform parent, string name)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			if (((Object)parent).name == name)
			{
				return parent;
			}
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform val = FindChild(parent.GetChild(i), name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static void RemoveBackpackVisual(Character creature)
		{
			Transform val = (((Object)(object)creature == (Object)null) ? null : FindChild(((Component)creature).transform, "TamedCreatureXP_CreatureBackpackVisual_v3"));
			if ((Object)(object)val != (Object)null)
			{
				for (int num = WispVisuals.Count - 1; num >= 0; num--)
				{
					if (WispVisuals[num] != null && (Object)(object)WispVisuals[num].Root == (Object)(object)val)
					{
						WispVisuals.RemoveAt(num);
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			Transform val2 = (((Object)(object)creature == (Object)null) ? null : FindChild(((Component)creature).transform, "TamedCreatureXP_CreatureBackpackVisual"));
			if ((Object)(object)val2 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val2).gameObject);
			}
			Transform val3 = (((Object)(object)creature == (Object)null) ? null : FindChild(((Component)creature).transform, "TamedCreatureXP_CreatureBackpackVisual_v2"));
			if ((Object)(object)val3 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val3).gameObject);
			}
		}

		internal static void SaveForPortablePals(Character creature)
		{
			if ((Object)(object)creature != (Object)null && (Object)(object)creature == (Object)(object)_openCreature)
			{
				SaveIfOpen();
			}
		}

		internal static void WritePortablePalsData(ZDO zdo, IDictionary<string, string> customData)
		{
			if (zdo != null && customData != null)
			{
				customData["TamedCreatureXP.HasBackpack"] = zdo.GetBool("TamedCreatureXP.HasBackpack", false).ToString();
				byte[] byteArray = zdo.GetByteArray("TamedCreatureXP.BackpackContents", (byte[])null);
				customData["TamedCreatureXP.BackpackContents"] = ((byteArray == null) ? string.Empty : Convert.ToBase64String(byteArray));
			}
		}

		internal static void RestoreFromPortablePals(ZDO zdo, IDictionary<string, string> customData)
		{
			if (zdo == null || customData == null)
			{
				return;
			}
			if (customData.TryGetValue("TamedCreatureXP.HasBackpack", out var value) && bool.TryParse(value, out var result))
			{
				zdo.Set("TamedCreatureXP.HasBackpack", result);
			}
			if (!customData.TryGetValue("TamedCreatureXP.BackpackContents", out var value2))
			{
				return;
			}
			try
			{
				zdo.Set("TamedCreatureXP.BackpackContents", string.IsNullOrEmpty(value2) ? new byte[0] : Convert.FromBase64String(value2));
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogWarning((object)("Could not restore Pal Stone backpack contents: " + ex.Message));
			}
		}

		private static void EnsureObjectDbRegistration()
		{
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if (_registeredObjectDb == instance)
			{
				EnsureRecipe(instance);
				return;
			}
			_registeredObjectDb = instance;
			_itemPrefab = null;
			_recipe = null;
			_recipeUnlocked = false;
			RegisterLocalization();
			GameObject itemPrefab = instance.GetItemPrefab("TamedCreatureXP_CreatureBackpack");
			if ((Object)(object)itemPrefab != (Object)null)
			{
				_itemPrefab = itemPrefab;
				if ((Object)(object)_backpackSprite == (Object)null)
				{
					_backpackSprite = CreateBackpackSprite(instance);
				}
				ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
				if ((Object)(object)component != (Object)null && component.m_itemData != null && component.m_itemData.m_shared != null)
				{
					component.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { _backpackSprite };
				}
				RegisterItemWithJotunn(instance, itemPrefab);
				EnsureRecipe(instance);
				return;
			}
			GameObject itemPrefab2 = instance.GetItemPrefab("TrophyWolf");
			if ((Object)(object)itemPrefab2 == (Object)null)
			{
				_registeredObjectDb = null;
				return;
			}
			_itemPrefab = Object.Instantiate<GameObject>(itemPrefab2);
			((Object)_itemPrefab).name = "TamedCreatureXP_CreatureBackpack";
			_itemPrefab.SetActive(false);
			ItemDrop component2 = _itemPrefab.GetComponent<ItemDrop>();
			if ((Object)(object)component2 == (Object)null || component2.m_itemData == null || component2.m_itemData.m_shared == null)
			{
				Object.Destroy((Object)(object)_itemPrefab);
				_itemPrefab = null;
				_registeredObjectDb = null;
				throw new InvalidOperationException("TrophyWolf template has no usable ItemDrop component.");
			}
			component2.m_itemData.m_dropPrefab = _itemPrefab;
			SharedData shared = component2.m_itemData.m_shared;
			shared.m_name = "$item_tamedcreaturexp_creaturebackpack";
			shared.m_description = "$item_tamedcreaturexp_creaturebackpack_desc";
			shared.m_itemType = (ItemType)19;
			shared.m_maxStackSize = 1;
			shared.m_weight = 1f;
			shared.m_teleportable = true;
			shared.m_useDurability = false;
			_backpackSprite = CreateBackpackSprite(instance);
			shared.m_icons = (Sprite[])(object)new Sprite[1] { _backpackSprite };
			RegisterLocalization();
			RegisterItemWithJotunn(instance, _itemPrefab);
			EnsureRecipe(instance);
			Plugin.ModLog.LogInfo((object)(((Object)(object)_recipe == (Object)null) ? "Registered creature backpack item; recipe is waiting for its crafting station and materials." : "Registered universal creature backpack item and Black Forge recipe."));
		}

		internal static void RegisterLocalization()
		{
			try
			{
				Type type = AccessTools.TypeByName("Jotunn.Managers.LocalizationManager");
				object obj = ((type == null) ? null : AccessTools.Property(type, "Instance")?.GetValue(null, null));
				MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "GetLocalization", Type.EmptyTypes, (Type[])null));
				object obj2 = ((obj == null || methodInfo == null) ? null : methodInfo.Invoke(obj, null));
				if (obj2 == null)
				{
					return;
				}
				MethodInfo methodInfo2 = null;
				MethodInfo[] methods = obj2.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo3 in methods)
				{
					if (!(methodInfo3.Name != "AddTranslation"))
					{
						ParameterInfo[] parameters = methodInfo3.GetParameters();
						if (parameters.Length == 3 && IsStringParameter(parameters[0]) && IsStringParameter(parameters[1]) && IsStringParameter(parameters[2]))
						{
							methodInfo2 = methodInfo3;
							break;
						}
					}
				}
				if (!(methodInfo2 == null))
				{
					methodInfo2.Invoke(obj2, new object[3] { "English", "item_tamedcreaturexp_creaturebackpack", "Creature Backpack" });
					methodInfo2.Invoke(obj2, new object[3] { "French", "item_tamedcreaturexp_creaturebackpack", "Sac à dos de créature" });
					methodInfo2.Invoke(obj2, new object[3] { "English", "item_tamedcreaturexp_creaturebackpack_desc", "Equip on a level 4 or higher tamed creature. Press the configured key while targeting it to open its 15-slot backpack." });
					methodInfo2.Invoke(obj2, new object[3] { "French", "item_tamedcreaturexp_creaturebackpack_desc", "Équipe ce sac sur une créature apprivoisée de niveau 4 ou plus. Vise-la et appuie sur la touche configurée pour ouvrir son sac de 15 emplacements." });
				}
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogDebug((object)("Could not register backpack translations through Jotunn: " + ex.Message));
			}
		}

		private static bool IsStringParameter(ParameterInfo parameter)
		{
			if (!(parameter.ParameterType == typeof(string)))
			{
				if (parameter.ParameterType.IsByRef)
				{
					return parameter.ParameterType.GetElementType() == typeof(string);
				}
				return false;
			}
			return true;
		}

		private static void RegisterItemWithJotunn(ObjectDB database, GameObject prefab)
		{
			Type type = AccessTools.TypeByName("Jotunn.Managers.ItemManager");
			object obj = ((type == null) ? null : AccessTools.Property(type, "Instance")?.GetValue(null, null));
			if (obj == null)
			{
				if (!_warnedJotunn)
				{
					_warnedJotunn = true;
					Plugin.ModLog.LogWarning((object)"Jotunn ItemManager is unavailable; the creature backpack is disabled because it cannot be registered safely.");
				}
				return;
			}
			try
			{
				if (_jotunnCustomItem == null)
				{
					Type type2 = AccessTools.TypeByName("Jotunn.Entities.CustomItem");
					ConstructorInfo constructorInfo = ((type2 == null) ? null : type2.GetConstructor(new Type[2]
					{
						typeof(GameObject),
						typeof(bool)
					}));
					MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type, "AddItem", new Type[1] { type2 }, (Type[])null));
					if (constructorInfo != null && methodInfo != null)
					{
						_jotunnCustomItem = constructorInfo.Invoke(new object[2] { prefab, false });
						_jotunnItemAdded = Convert.ToBoolean(methodInfo.Invoke(obj, new object[1] { _jotunnCustomItem }));
					}
				}
				if (_jotunnCustomItem == null || !_jotunnItemAdded)
				{
					if (!_warnedJotunn)
					{
						_warnedJotunn = true;
						Plugin.ModLog.LogWarning((object)"Jotunn did not accept the creature backpack item; it will not be inserted into Valheim's prefab lists directly.");
					}
				}
				else if ((Object)(object)database != (Object)null)
				{
					MethodInfo methodInfo2 = AccessTools.Method(type, "RegisterItemInObjectDB", new Type[1] { typeof(GameObject) }, (Type[])null);
					if (methodInfo2 == null)
					{
						throw new MissingMethodException(type.FullName, "RegisterItemInObjectDB(GameObject)");
					}
					methodInfo2.Invoke(obj, new object[1] { prefab });
				}
			}
			catch (Exception ex)
			{
				if (!_warnedJotunn)
				{
					_warnedJotunn = true;
					Plugin.ModLog.LogWarning((object)("Could not register the creature backpack through Jotunn: " + ex));
				}
			}
		}

		private static void EnsureRecipe(ObjectDB database)
		{
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Expected O, but got Unknown
			if ((Object)(object)_recipe != (Object)null || (Object)(object)database == (Object)null || (Object)(object)_itemPrefab == (Object)null || !(AccessTools.Field(typeof(ObjectDB), "m_recipes")?.GetValue(database) is IList list))
			{
				return;
			}
			foreach (object item in list)
			{
				Recipe val = (Recipe)((item is Recipe) ? item : null);
				if ((Object)(object)val != (Object)null && (Object)(object)val.m_item != (Object)null && (Object)(object)((Component)val.m_item).gameObject != (Object)null && ((Object)((Component)val.m_item).gameObject).name == "TamedCreatureXP_CreatureBackpack")
				{
					_recipe = val;
					return;
				}
			}
			ZNetScene instance = ZNetScene.instance;
			GameObject val2 = (((Object)(object)instance == (Object)null) ? null : instance.GetPrefab("blackforge"));
			CraftingStation val3 = (((Object)(object)val2 == (Object)null) ? null : val2.GetComponent<CraftingStation>());
			ItemDrop component = _itemPrefab.GetComponent<ItemDrop>();
			if ((Object)(object)val3 == (Object)null || (Object)(object)component == (Object)null)
			{
				Plugin.ModLog.LogDebug((object)"Black Forge or backpack item is not registered yet; will retry.");
				return;
			}
			Requirement[] array = (Requirement[])(object)new Requirement[3];
			string[] array2 = new string[3] { "BlackMetal", "LinenThread", "FineWood" };
			int[] array3 = new int[3] { 4, 4, 4 };
			for (int i = 0; i < array.Length; i++)
			{
				GameObject itemPrefab = database.GetItemPrefab(array2[i]);
				ItemDrop val4 = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>());
				if ((Object)(object)val4 == (Object)null)
				{
					Plugin.ModLog.LogWarning((object)("Black Forge backpack recipe ingredient is missing: " + array2[i]));
					return;
				}
				array[i] = new Requirement
				{
					m_resItem = val4,
					m_amount = array3[i],
					m_amountPerLevel = 0
				};
			}
			Recipe val5 = ScriptableObject.CreateInstance<Recipe>();
			((Object)val5).name = "Recipe_TamedCreatureXP_CreatureBackpack";
			val5.m_item = component;
			val5.m_amount = 1;
			val5.m_enabled = false;
			val5.m_craftingStation = val3;
			val5.m_resources = array;
			Type type = AccessTools.TypeByName("Jotunn.Managers.ItemManager");
			object obj = ((type == null) ? null : AccessTools.Property(type, "Instance")?.GetValue(null, null));
			Type type2 = AccessTools.TypeByName("Jotunn.Entities.CustomRecipe");
			ConstructorInfo constructorInfo = ((type2 == null) ? null : type2.GetConstructor(new Type[3]
			{
				typeof(Recipe),
				typeof(bool),
				typeof(bool)
			}));
			MethodInfo methodInfo = ((type == null || type2 == null) ? null : AccessTools.Method(type, "AddRecipe", new Type[1] { type2 }, (Type[])null));
			if (obj == null || constructorInfo == null || methodInfo == null)
			{
				Plugin.ModLog.LogWarning((object)"Jotunn recipe registration is unavailable; the creature backpack recipe was not added.");
				return;
			}
			_jotunnCustomRecipe = constructorInfo.Invoke(new object[3] { val5, false, false });
			bool flag = Convert.ToBoolean(methodInfo.Invoke(obj, new object[1] { _jotunnCustomRecipe }));
			if (!list.Contains(val5))
			{
				list.Add(val5);
			}
			_recipe = val5;
			try
			{
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Player), "UpdateKnownRecipesList", (Type[])null, (Type[])null);
				if ((Object)(object)Player.m_localPlayer != (Object)null && methodInfo2 != null)
				{
					methodInfo2.Invoke(Player.m_localPlayer, null);
				}
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogDebug((object)("Could not refresh the local player's recipe list for the creature backpack: " + ex.Message));
			}
			Plugin.ModLog.LogInfo((object)(flag ? "Registered creature backpack recipe at Black Forge (4 Black Metal, 4 Linen Thread, 4 Fine Wood)." : "Creature backpack recipe was already registered with Jotunn."));
		}

		internal static bool UseBackpackItem(Humanoid user, Inventory inventory, ItemData item)
		{
			if (!IsBackpackItem(item))
			{
				return true;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			Character val2 = (((Object)(object)val == (Object)null) ? null : val.GetHoverCreature());
			if (!Plugin.IsAllowedTamedCreature(val2) || val2.GetLevel() < 4)
			{
				Plugin.ShowMessage(Plugin.IsFrench ? "Cible une créature apprivoisée de niveau 4 ou plus pour lui donner le sac." : "Target a level 4 or higher tamed creature to give it the backpack.", levelUp: false);
				return false;
			}
			ZNetView nView = Plugin.GetNView(val2);
			ZDO val3 = (((Object)(object)nView != (Object)null && nView.IsValid()) ? nView.GetZDO() : null);
			if (val3 == null || !ClaimOwnership(nView))
			{
				Plugin.ShowMessage(Plugin.IsFrench ? "Impossible d'accéder aux données de cette créature." : "Could not access this creature's data.", levelUp: false);
				return false;
			}
			if (val3.GetBool("TamedCreatureXP.HasBackpack", false))
			{
				Plugin.ShowMessage(Plugin.IsFrench ? "Cette créature a déjà un sac." : "This creature already has a backpack.", levelUp: false);
				return false;
			}
			val3.Set("TamedCreatureXP.HasBackpack", true);
			EnsureBackpackVisual(val2);
			if (inventory != null && item != null)
			{
				inventory.RemoveItem(item, 1);
			}
			Plugin.ShowMessage(Plugin.IsFrench ? "Sac de bât équipé. Utilise la touche configurée en ciblant la créature pour l'ouvrir." : "Backpack equipped. Use the configured key while targeting the creature to open it.", levelUp: false);
			Plugin.ModLog.LogInfo((object)("Backpack equipped on " + ((Object)((Component)val2).gameObject).name + "."));
			return false;
		}

		private static bool IsBackpackItem(ItemData item)
		{
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			if (!string.Equals(item.m_shared.m_name, "$item_tamedcreaturexp_creaturebackpack", StringComparison.Ordinal))
			{
				if ((Object)(object)item.m_dropPrefab != (Object)null)
				{
					return ((Object)item.m_dropPrefab).name == "TamedCreatureXP_CreatureBackpack";
				}
				return false;
			}
			return true;
		}

		internal static void TryOpenTargetedCreature()
		{
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)InventoryGui.instance == (Object)null)
			{
				return;
			}
			Character hoverCreature = localPlayer.GetHoverCreature();
			if ((Object)(object)hoverCreature == (Object)null)
			{
				Plugin.ShowMessage(Plugin.IsFrench ? "Vise le compagnon portant le sac, puis appuie sur la touche configurée." : "Aim at the creature wearing the backpack, then press the configured key.", levelUp: false);
			}
			else
			{
				if (!Plugin.IsAllowedTamedCreature(hoverCreature))
				{
					return;
				}
				if (hoverCreature.GetLevel() < 4)
				{
					Plugin.ShowMessage(Plugin.IsFrench ? "Le sac est disponible à partir du niveau 4." : "The backpack unlocks at level 4.", levelUp: false);
					return;
				}
				ZNetView nView = Plugin.GetNView(hoverCreature);
				ZDO val = (((Object)(object)nView != (Object)null && nView.IsValid()) ? nView.GetZDO() : null);
				if (val == null || !val.GetBool("TamedCreatureXP.HasBackpack", false))
				{
					Plugin.ShowMessage(Plugin.IsFrench ? "Cette créature n'a pas de sac de bât." : "This creature has no backpack.", levelUp: false);
					return;
				}
				if (ClaimOwnership(nView))
				{
					try
					{
						SaveIfOpen();
						if ((Object)(object)_openCreature != (Object)null && (Object)(object)_openCreature != (Object)(object)hoverCreature && (Object)(object)_virtualContainer != (Object)null && (Object)/*isinst with value type is only supported in some contexts*/ == (Object)(object)_virtualContainer)
						{
							AccessTools.Method(typeof(InventoryGui), "CloseContainer", (Type[])null, (Type[])null)?.Invoke(InventoryGui.instance, null);
						}
						EnsureVirtualContainer();
						_virtualInventory = new Inventory(Plugin.IsFrench ? "Sac de bât" : "Creature Backpack", _backpackSprite, 5, 3);
						SetField(_virtualContainer, "m_inventory", _virtualInventory);
						((Component)_virtualContainer).transform.position = ((Component)localPlayer).transform.position;
						_openCreature = hoverCreature;
						_openZdo = val;
						LoadFromZdo(val);
						InventoryGui.instance.Show(_virtualContainer, 0);
						_nextPeriodicSave = Time.unscaledTime + 0.75f;
						object? obj = AccessTools.Field(typeof(InventoryGui), "m_currentContainer")?.GetValue(InventoryGui.instance);
						if ((Object)((obj is Container) ? obj : null) == (Object)(object)_virtualContainer)
						{
							Plugin.ModLog.LogInfo((object)("Opened the backpack inventory for " + Plugin.SafeName(hoverCreature) + "."));
						}
						else
						{
							Plugin.ModLog.LogWarning((object)"Valheim's inventory window did not select the virtual creature backpack after Show().");
							Plugin.ShowMessage(Plugin.IsFrench ? "Le sac ne s'est pas affiché. Ferme l'inventaire, vise le compagnon et réessaie." : "The backpack did not appear. Close the inventory, target the creature and try again.", levelUp: false);
						}
						return;
					}
					catch (Exception ex)
					{
						_openCreature = null;
						_openZdo = null;
						Plugin.ModLog.LogError((object)("Could not open creature backpack: " + ex));
						Plugin.ShowMessage(Plugin.IsFrench ? "Erreur lors de l'ouverture du sac." : "Could not open the backpack.", levelUp: false);
						return;
					}
				}
				Plugin.ShowMessage(Plugin.IsFrench ? "Impossible d'ouvrir le sac pour le moment." : "Could not open the backpack right now.", levelUp: false);
			}
		}

		private static bool ClaimOwnership(ZNetView nview)
		{
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return false;
			}
			if (!nview.IsOwner())
			{
				try
				{
					nview.ClaimOwnership();
				}
				catch (Exception ex)
				{
					Plugin.ModLog.LogDebug((object)("Could not claim backpack owner: " + ex.Message));
				}
			}
			return nview.IsOwner();
		}

		private static void EnsureVirtualContainer()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			if (!((Object)(object)_virtualContainer != (Object)null) || _virtualInventory == null)
			{
				GameObject val = new GameObject("TamedCreatureXP_VirtualCreatureBackpack");
				Object.DontDestroyOnLoad((Object)val);
				_virtualContainer = val.AddComponent<Container>();
				_virtualInventory = new Inventory("Creature Backpack", _backpackSprite, 5, 3);
				SetField(_virtualContainer, "m_name", Plugin.IsFrench ? "Sac de bât" : "Creature Backpack");
				SetField(_virtualContainer, "m_width", 5);
				SetField(_virtualContainer, "m_height", 3);
				SetField(_virtualContainer, "m_inventory", _virtualInventory);
				((Behaviour)_virtualContainer).enabled = false;
			}
		}

		private static void LoadFromZdo(ZDO zdo)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (zdo == null || _virtualInventory == null)
			{
				return;
			}
			byte[] byteArray = zdo.GetByteArray("TamedCreatureXP.BackpackContents", (byte[])null);
			if (byteArray == null || byteArray.Length == 0)
			{
				return;
			}
			try
			{
				ZPackage val = new ZPackage(byteArray);
				_virtualInventory.Load(val);
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogWarning((object)("Could not load creature backpack contents; the stored data was left untouched: " + ex.Message));
			}
		}

		internal static void SaveIfOpen()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			if (_saving || (Object)(object)_virtualContainer == (Object)null || _virtualInventory == null || _openZdo == null)
			{
				return;
			}
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance != (Object)null && (Object)/*isinst with value type is only supported in some contexts*/ != (Object)(object)_virtualContainer)
			{
				return;
			}
			try
			{
				_saving = true;
				ZPackage val = new ZPackage();
				_virtualInventory.Save(val);
				_openZdo.Set("TamedCreatureXP.BackpackContents", val.GetArray());
			}
			catch (Exception ex)
			{
				if (!_warnedSave)
				{
					_warnedSave = true;
					Plugin.ModLog.LogWarning((object)("Could not save creature backpack contents: " + ex.Message));
				}
			}
			finally
			{
				_saving = false;
			}
		}

		private static void OnGuiClosed()
		{
			if (_closingVirtualContainer)
			{
				_closingVirtualContainer = false;
				_openCreature = null;
				_openZdo = null;
			}
		}

		private static void OnGuiClosing()
		{
			_closingVirtualContainer = false;
			if (!((Object)(object)_virtualContainer == (Object)null) && !((Object)(object)InventoryGui.instance == (Object)null) && !((Object)/*isinst with value type is only supported in some contexts*/ != (Object)(object)_virtualContainer))
			{
				SaveIfOpen();
				_closingVirtualContainer = true;
			}
		}

		private static bool IsVirtual(Container container)
		{
			if ((Object)(object)container != (Object)null)
			{
				return (Object)(object)container == (Object)(object)_virtualContainer;
			}
			return false;
		}

		internal static bool IsVirtualContainerName(string name)
		{
			return string.Equals(name, "TamedCreatureXP_VirtualCreatureBackpack", StringComparison.Ordinal);
		}

		internal static bool VirtualContainerAwakePrefix(Container instance)
		{
			return !IsVirtualContainerName(((Object)(object)instance != (Object)null && (Object)(object)((Component)instance).gameObject != (Object)null) ? ((Object)((Component)instance).gameObject).name : string.Empty);
		}

		internal static bool GetInventoryPrefix(Container __instance, ref Inventory __result)
		{
			if (!IsVirtual(__instance))
			{
				return true;
			}
			__result = _virtualInventory;
			return false;
		}

		internal static bool ContainerLoadPrefix(Container __instance, ref bool __result)
		{
			if (!IsVirtual(__instance))
			{
				return true;
			}
			__result = true;
			return false;
		}

		internal static bool ContainerSavePrefix(Container __instance)
		{
			if (!IsVirtual(__instance))
			{
				return true;
			}
			SaveIfOpen();
			return false;
		}

		internal static bool SetInUsePrefix(Container __instance, bool inUse)
		{
			if (!IsVirtual(__instance))
			{
				return true;
			}
			SetField(__instance, "m_inUse", inUse);
			if (!inUse)
			{
				SaveIfOpen();
			}
			return false;
		}

		internal static void FollowPlayerWhileOpen(InventoryGui gui, Player player)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_virtualContainer == (Object)null) && !((Object)(object)gui == (Object)null) && !((Object)/*isinst with value type is only supported in some contexts*/ != (Object)(object)_virtualContainer))
			{
				Player val = (((Object)(object)player != (Object)null) ? player : Player.m_localPlayer);
				if ((Object)(object)val != (Object)null)
				{
					((Component)_virtualContainer).transform.position = ((Component)val).transform.position;
				}
			}
		}

		private static void SetField(object instance, string name, object value)
		{
			FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), name);
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(instance, value);
			}
		}

		private static void SetProperty(object instance, string name, object value)
		{
			if (instance != null)
			{
				PropertyInfo propertyInfo = AccessTools.Property(instance.GetType(), name);
				if (propertyInfo != null && propertyInfo.CanWrite)
				{
					propertyInfo.SetValue(instance, value, null);
				}
			}
		}

		internal static void UpdateBackpackInventoryStyle(InventoryGui gui)
		{
			if ((Object)(object)gui == (Object)null)
			{
				return;
			}
			object? obj = AccessTools.Field(typeof(InventoryGui), "m_currentContainer")?.GetValue(gui);
			Container val = (Container)((obj is Container) ? obj : null);
			object? obj2 = AccessTools.Field(typeof(InventoryGui), "m_container")?.GetValue(gui);
			RectTransform val2 = (RectTransform)((obj2 is RectTransform) ? obj2 : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			Transform val3 = EnsureBackpackPanelFrame(val2);
			if ((Object)(object)val3 == (Object)null)
			{
				return;
			}
			bool flag = (Object)(object)val == (Object)(object)_virtualContainer;
			if (((Component)val3).gameObject.activeSelf != flag)
			{
				((Component)val3).gameObject.SetActive(flag);
			}
			if (flag)
			{
				val3.SetAsLastSibling();
				object? obj3 = AccessTools.Field(typeof(InventoryGui), "m_containerName")?.GetValue(gui);
				Component val4 = (Component)((obj3 is Component) ? obj3 : null);
				PropertyInfo propertyInfo = (((Object)(object)val4 == (Object)null) ? null : AccessTools.Property(((object)val4).GetType(), "text"));
				if (!(propertyInfo == null) && propertyInfo.CanWrite)
				{
					string text = (Plugin.IsFrench ? "SAC À DOS DE CRÉATURE" : "CREATURE BACKPACK");
					propertyInfo.SetValue(val4, "<color=#B87BEE>★</color> <color=#F3D7FF>" + text + "</color> <color=#B87BEE>★</color>", null);
				}
			}
		}

		private static Transform EnsureBackpackPanelFrame(RectTransform panel)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_panelFrame != (Object)null && (Object)(object)_panelFrame.parent == (Object)(object)panel)
			{
				return _panelFrame;
			}
			_panelFrame = FindChild((Transform)(object)panel, "TamedCreatureXP_CreatureBackpackPanelFrame");
			if ((Object)(object)_panelFrame != (Object)null)
			{
				return _panelFrame;
			}
			Type type = AccessTools.TypeByName("UnityEngine.UI.Image");
			if (type == null)
			{
				if (!_warnedPanelStyle)
				{
					_warnedPanelStyle = true;
					Plugin.ModLog.LogWarning((object)"Could not style the backpack panel because Unity UI Image is unavailable.");
				}
				return null;
			}
			Sprite backpackPanelFrameSprite = GetBackpackPanelFrameSprite();
			if ((Object)(object)backpackPanelFrameSprite == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("TamedCreatureXP_CreatureBackpackPanelFrame", new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)panel, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			Component instance = val.AddComponent(type);
			SetProperty(instance, "sprite", backpackPanelFrameSprite);
			PropertyInfo propertyInfo = AccessTools.Property(type, "type");
			if (propertyInfo != null)
			{
				SetProperty(instance, "type", Enum.ToObject(propertyInfo.PropertyType, 1));
			}
			SetProperty(instance, "color", Color.white);
			SetProperty(instance, "raycastTarget", false);
			_panelFrame = val.transform;
			((Component)_panelFrame).gameObject.SetActive(false);
			return _panelFrame;
		}

		private static Sprite GetBackpackPanelFrameSprite()
		{
			//IL_0017: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Expected O, but got Unknown
			if ((Object)(object)_panelFrameSprite != (Object)null)
			{
				return _panelFrameSprite;
			}
			new Color32((byte)0, (byte)0, (byte)0, (byte)0);
			Color32[] array = (Color32[])(object)new Color32[4096];
			for (int i = 0; i < 64; i++)
			{
				SetFramePixel(array, 64, i, 0, new Color32((byte)22, (byte)16, (byte)24, (byte)250));
				SetFramePixel(array, 64, i, 1, new Color32((byte)171, (byte)119, (byte)68, (byte)245));
				SetFramePixel(array, 64, i, 2, new Color32((byte)74, (byte)48, (byte)48, (byte)238));
				SetFramePixel(array, 64, i, 3, new Color32((byte)126, (byte)69, (byte)164, (byte)208));
				SetFramePixel(array, 64, i, 4, new Color32((byte)55, (byte)38, (byte)42, (byte)155));
				SetFramePixel(array, 64, i, 63, new Color32((byte)22, (byte)16, (byte)24, (byte)250));
				SetFramePixel(array, 64, i, 62, new Color32((byte)171, (byte)119, (byte)68, (byte)245));
				SetFramePixel(array, 64, i, 61, new Color32((byte)74, (byte)48, (byte)48, (byte)238));
				SetFramePixel(array, 64, i, 60, new Color32((byte)126, (byte)69, (byte)164, (byte)208));
				SetFramePixel(array, 64, i, 59, new Color32((byte)55, (byte)38, (byte)42, (byte)155));
				SetFramePixel(array, 64, 0, i, new Color32((byte)22, (byte)16, (byte)24, (byte)250));
				SetFramePixel(array, 64, 1, i, new Color32((byte)171, (byte)119, (byte)68, (byte)245));
				SetFramePixel(array, 64, 2, i, new Color32((byte)74, (byte)48, (byte)48, (byte)238));
				SetFramePixel(array, 64, 3, i, new Color32((byte)126, (byte)69, (byte)164, (byte)208));
				SetFramePixel(array, 64, 4, i, new Color32((byte)55, (byte)38, (byte)42, (byte)155));
				SetFramePixel(array, 64, 63, i, new Color32((byte)22, (byte)16, (byte)24, (byte)250));
				SetFramePixel(array, 64, 62, i, new Color32((byte)171, (byte)119, (byte)68, (byte)245));
				SetFramePixel(array, 64, 61, i, new Color32((byte)74, (byte)48, (byte)48, (byte)238));
				SetFramePixel(array, 64, 60, i, new Color32((byte)126, (byte)69, (byte)164, (byte)208));
				SetFramePixel(array, 64, 59, i, new Color32((byte)55, (byte)38, (byte)42, (byte)155));
			}
			DrawBackpackFrameCorner(array, 64, right: false, top: false);
			DrawBackpackFrameCorner(array, 64, right: true, top: false);
			DrawBackpackFrameCorner(array, 64, right: false, top: true);
			DrawBackpackFrameCorner(array, 64, right: true, top: true);
			AddFrameRivet(array, 64, 9, 9);
			AddFrameRivet(array, 64, 54, 9);
			AddFrameRivet(array, 64, 9, 54);
			AddFrameRivet(array, 64, 54, 54);
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0
			};
			val.SetPixels32(array);
			val.Apply(false, true);
			_panelFrameSprite = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f, 0u, (SpriteMeshType)0, new Vector4(18f, 18f, 18f, 18f));
			return _panelFrameSprite;
		}

		private static void SetFramePixel(Color32[] pixels, int size, int x, int y, Color32 color)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (x >= 0 && y >= 0 && x < size && y < size)
			{
				pixels[y * size + x] = color;
			}
		}

		private static void DrawBackpackFrameCorner(Color32[] pixels, int size, bool right, bool top)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: 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)
			for (int i = 4; i < 18; i++)
			{
				for (int j = 4; j < 18; j++)
				{
					if (j + i >= 12 && j + i <= 26)
					{
						SetOrientedFramePixel(pixels, size, j, i, right, top, new Color32((byte)32, (byte)22, (byte)29, (byte)178));
					}
				}
			}
			DrawOrientedFrameLine(pixels, size, 3, 15, 15, 3, right, top, new Color32((byte)201, (byte)151, (byte)89, (byte)235));
			DrawOrientedFrameLine(pixels, size, 5, 16, 16, 5, right, top, new Color32((byte)101, (byte)63, (byte)56, (byte)225));
			DrawOrientedFrameLine(pixels, size, 8, 16, 16, 8, right, top, new Color32((byte)148, (byte)83, (byte)183, (byte)190));
			DrawOrientedFrameLine(pixels, size, 12, 5, 16, 9, right, top, new Color32((byte)209, (byte)159, (byte)92, (byte)235));
			DrawOrientedFrameLine(pixels, size, 16, 9, 13, 9, right, top, new Color32((byte)121, (byte)75, (byte)55, (byte)230));
			DrawOrientedFrameLine(pixels, size, 6, 5, 8, 7, right, top, new Color32((byte)205, (byte)145, (byte)83, (byte)220));
			DrawOrientedFrameLine(pixels, size, 5, 7, 7, 9, right, top, new Color32((byte)126, (byte)77, (byte)163, (byte)205));
		}

		private static void SetOrientedFramePixel(Color32[] pixels, int size, int x, int y, bool right, bool top, Color32 color)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			int x2 = (right ? (size - 1 - x) : x);
			int y2 = (top ? (size - 1 - y) : y);
			SetFramePixel(pixels, size, x2, y2, color);
		}

		private static void DrawOrientedFrameLine(Color32[] pixels, int size, int x0, int y0, int x1, int y1, bool right, bool top, Color32 color)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			int num = Math.Abs(x1 - x0);
			int num2 = ((x0 < x1) ? 1 : (-1));
			int num3 = -Math.Abs(y1 - y0);
			int num4 = ((y0 < y1) ? 1 : (-1));
			int num5 = num + num3;
			while (true)
			{
				SetOrientedFramePixel(pixels, size, x0, y0, right, top, color);
				if (x0 != x1 || y0 != y1)
				{
					int num6 = 2 * num5;
					if (num6 >= num3)
					{
						num5 += num3;
						x0 += num2;
					}
					if (num6 <= num)
					{
						num5 += num;
						y0 += num4;
					}
					continue;
				}
				break;
			}
		}

		private static void AddFrameRivet(Color32[] pixels, int size, int centerX, int centerY)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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)
			for (int i = -4; i <= 4; i++)
			{
				for (int j = -4; j <= 4; j++)
				{
					int num = j * j + i * i;
					if (num <= 16)
					{
						Color32 color = ((num >= 10) ? new Color32((byte)38, (byte)25, (byte)31, byte.MaxValue) : ((num >= 4) ? new Color32((byte)202, (byte)148, (byte)84, byte.MaxValue) : new Color32((byte)188, (byte)122, (byte)235, byte.MaxValue)));
						SetFramePixel(pixels, size, centerX + j, centerY + i, color);
					}
				}
			}
		}

		private static void HideBackpackPanelFrame()
		{
			if ((Object)(object)_panelFrame != (Object)null && ((Component)_panelFrame).gameObject.activeSelf)
			{
				((Component)_panelFrame).gameObject.SetActive(false);
			}
		}

		private static Sprite CreateBackpackSprite(ObjectDB database)
		{
			Sprite val = FindWispLightIcon(database);
			if ((Object)(object)val != (Object)null)
			{
				try
				{
					Sprite val2 = CreateVioletWispIcon(val);
					if ((Object)(object)val2 != (Object)null)
					{
						Plugin.ModLog.LogInfo((object)"Using a violet-tinted Wisplight icon for the creature backpack.");
						return val2;
					}
				}
				catch (Exception ex)
				{
					Plugin.ModLog.LogWarning((object)("Could not tint the Wisplight icon; using the original icon instead: " + ex.Message));
				}
				return val;
			}
			Plugin.ModLog.LogWarning((object)"Could not find the vanilla Wisplight icon; using the fallback backpack icon.");
			return CreateDefaultBackpackSprite();
		}

		private static Sprite FindWispLightIcon(ObjectDB database)
		{
			if ((Object)(object)database == (Object)null)
			{
				return null;
			}
			if (!(AccessTools.Field(typeof(ObjectDB), "m_items")?.GetValue(database) is IEnumerable enumerable))
			{
				return null;
			}
			GameObject val = null;
			Sprite result = null;
			int num = 0;
			foreach (object item in enumerable)
			{
				GameObject val2 = (GameObject)((item is GameObject) ? item : null);
				ItemDrop val3 = (((Object)(object)val2 == (Object)null) ? null : val2.GetComponent<ItemDrop>());
				SharedData val4 = (((Object)(object)val3 == (Object)null || val3.m_itemData == null) ? null : val3.m_itemData.m_shared);
				if (val4 != null && val4.m_icons != null && val4.m_icons.Length != 0 && !((Object)(object)val4.m_icons[0] == (Object)null))
				{
					string text = ((Object)val2).name ?? string.Empty;
					string text2 = val4.m_name ?? string.Empty;
					int num2 = ((text.IndexOf("wisplight", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("wisplight", StringComparison.OrdinalIgnoreCase) >= 0) ? 2 : ((text.IndexOf("wisp", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("wisp", StringComparison.OrdinalIgnoreCase) >= 0) ? 1 : 0));
					if (num2 > num)
					{
						num = num2;
						val = val2;
						result = val4.m_icons[0];
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				Plugin.ModLog.LogDebug((object)("Selected wisp icon from " + ((Object)val).name + "."));
			}
			return result;
		}

		private static Sprite CreateVioletWispIcon(Sprite source)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null || (Object)(object)source.texture == (Object)null)
			{
				return null;
			}
			Rect textureRect = source.textureRect;
			int num = Mathf.RoundToInt(((Rect)(ref textureRect)).x);
			int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).y);
			int num3 = Mathf.RoundToInt(((Rect)(ref textureRect)).width);
			int num4 = Mathf.RoundToInt(((Rect)(ref textureRect)).height);
			if (num3 <= 0 || num4 <= 0)
			{
				return null;
			}
			Texture2D texture = source.texture;
			Color[] pixels;
			try
			{
				pixels = texture.GetPixels(num, num2, num3, num4);
			}
			catch (UnityException)
			{
				RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0);
				RenderTexture active = RenderTexture.active;
				Texture2D val = null;
				try
				{
					Graphics.Blit((Texture)(object)texture, temporary);
					RenderTexture.active = temporary;
					val = new Texture2D(((Texture)texture).width, ((Texture)texture).height, (TextureFormat)4, false);
					val.ReadPixels(new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), 0, 0);
					val.Apply(false, false);
					pixels = val.GetPixels(num, num2, num3, num4);
				}
				finally
				{
					RenderTexture.active = active;
					RenderTexture.ReleaseTemporary(temporary);
					if ((Object)(object)val != (Object)null)
					{
						Object.Destroy((Object)(object)val);
					}
				}
			}
			Texture2D val2 = new Texture2D(num3, num4, (TextureFormat)4, false);
			((Texture)val2).filterMode = (FilterMode)1;
			for (int i = 0; i < pixels.Length; i++)
			{
				Color val3 = pixels[i];
				pixels[i] = new Color(Mathf.Min(1f, val3.r * 0.55f + 0.08f), val3.g * 0.34f + 0.025f, Mathf.Min(1f, val3.b * 0.7f + 0.12f), val3.a);
			}
			val2.SetPixels(pixels);
			val2.Apply(false, true);
			float x = source.pivot.x;
			Rect rect = source.rect;
			float num5 = x / ((Rect)(ref rect)).width;
			float y = source.pivot.y;
			rect = source.rect;
			Vector2 val4 = default(Vector2);
			((Vector2)(ref val4))..ctor(num5, y / ((Rect)(ref rect)).height);
			return Sprite.Create(val2, new Rect(0f, 0f, (float)num3, (float)num4), val4, source.pixelsPerUnit);
		}

		private static Sprite CreateDefaultBackpackSprite()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)0;
			Color32 val2 = default(Color32);
			((Color32)(ref val2))..ctor((byte)0, (byte)0, (byte)0, (byte)0);
			Color32 val3 = default(Color32);
			((Color32)(ref val3))..ctor((byte)112, (byte)65, (byte)35, byte.MaxValue);
			Color32 val4 = default(Color32);
			((Color32)(ref val4))..ctor((byte)54, (byte)34, (byte)25, byte.MaxValue);
			Color32 val5 = default(Color32);
			((Color32)(ref val5))..ctor((byte)227, (byte)167, (byte)66, byte.MaxValue);
			Color32[] array = (Color32[])(object)new Color32[1024];
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < 32; j++)
				{
					Color32 val6 = val2;
					bool flag = j >= 6 && j <= 25 && i >= 4 && i <= 24;
					bool flag2 = j >= 7 && j <= 24 && i >= 20 && i <= 27;
					bool flag3 = ((j >= 10 && j <= 12) || (j >= 19 && j <= 21)) && i >= 8 && i <= 26;
					bool num = j >= 14 && j <= 17 && i >= 12 && i <= 16;
					bool flag4 = (flag || flag2) && (j == 6 || j == 25 || i == 4 || i == 27);
					if (flag || flag2)
					{
						val6 = (flag4 ? val4 : (flag3 ? val4 : val3));
					}
					if (num)
					{
						val6 = val5;
					}
					array[i * 32 + j] = val6;
				}
			}
			val.SetPixels32(array);
			val.Apply(false, true);
			return Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 32f);
		}
	}
	[BepInPlugin("ElixDrax.TamedCreatureXP", "Tamed Creature XP", "0.5.7")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private sealed class AssistDamageData
		{
			public readonly Dictionary<int, Character> Contributors = new Dictionary<int, Character>();
		}

		private sealed class LocalizedConfigSetting
		{
			public ConfigurationManagerAttributes Attributes;

			public string EnglishName;

			public string FrenchName;

			public string EnglishCategory;

			public string FrenchCategory;

			public string EnglishDescription;

			public string FrenchDescription;
		}

		private sealed class ConfigurationManagerAttributes
		{
			public string DispName;

			public string Category;

			public string Description;

			public bool? Browsable;
		}

		public const string PluginGuid = "ElixDrax.TamedCreatureXP";

		public const string PluginName = "Tamed Creature XP";

		public const string PluginVersion = "0.5.7";

		internal static Plugin Instance;

		internal static ManualLogSource ModLog;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<int> XPPerKill;

		internal static ConfigEntry<int> MaxLevel;

		internal static ConfigEntry<int> XPLevel2;

		internal static ConfigEntry<int> XPLevel3;

		internal static ConfigEntry<int> XPLevel4;

		internal static ConfigEntry<int> XPLevel5;

		internal static ConfigEntry<int> XPLevel6;

		private static ConfigEntry<int> ProgressionDefaultsVersion;

		private static ConfigEntry<int> LevelUpBonusDefaultsVersion;

		internal static ConfigEntry<string> HigherLevelThresholds;

		internal static ConfigEntry<bool> BossesAllowed;

		internal static ConfigEntry<bool> AwardXPForAssistDamage;

		internal static ConfigEntry<bool> ShowXPGained;

		internal static ConfigEntry<bool> ShowLevelUp;

		internal static ConfigEntry<bool> ShowProgress;

		internal static ConfigEntry<bool> ShowStarsAboveVanillaCap;

		internal static ConfigEntry<string> CreatureMultipliers;

		internal static ConfigEntry<string> VictimMultipliers;

		internal static ConfigEntry<string> VictimXPValues;

		internal static ConfigEntry<string> WizardryVictimXPValues;

		internal static ConfigEntry<bool> ShowCreatureStatusOnHover;

		internal static ConfigEntry<bool> FrenchInterface;

		internal static ConfigEntry<int> LevelUpHealAmount;

		internal static ConfigEntry<float> LevelUpShieldSeconds;

		internal static ConfigEntry<KeyboardShortcut> OpenBackpackKey;

		internal static ConfigEntry<bool> BackpackUnlocked;

		internal static bool SuppressNameDecorations;

		private Harmony _harmony;

		private bool _portablePalsPatched;

		private float _portablePalsRetryTimer;

		private float _backpackUpdateTimer;

		private static readonly List<LocalizedConfigSetting> LocalizedConfigSettings = new List<LocalizedConfigSetting>();

		private static readonly HashSet<string> UnmappedVictimPrefabs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static bool WizardryDetected;

		private static readonly ConditionalWeakTable<Character, AssistDamageData> AssistDamageByVictim = new ConditionalWeakTable<Character, AssistDamageData>();

		internal static bool IsFrench
		{
			get
			{
				if (FrenchInterface != null)
				{
					return FrenchInterface.Value;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Expected O, but got Unknown
			//IL_05ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_063b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0645: Expected O, but got Unknown
			Instance = this;
			ModLog = Logger.CreateLogSource("TamedCreatureXP");
			WizardryDetected = DetectWizardryPlugin();
			Enabled = BindSetting("General", "Enabled", defaultValue: true, "Enabled", "Activé", "Enable tamed creature XP.", "Active les gains d'XP des créatures apprivoisées.");
			XPPerKill = BindSetting("Advanced XP", "XP Per Kill", 25, "XP Per Kill", "XP de secours par élimination", "Fallback XP for a creature without a per-creature XP entry.", "XP de secours si une créature n'a pas de valeur individuelle.");
			CreatureMultipliers = BindSetting("XP", "Creature Multipliers", "", "Creature Multipliers", "Multiplicateurs des créatures apprivoisées", "Optional multipliers for the tamed killer, e.g. Wolf=1.2;Lox=0.8.", "Multiplicateurs facultatifs pour la créature apprivoisée qui tue, ex. Wolf=1.2;Lox=0.8.");
			VictimMultipliers = BindSetting("XP", "Defeated Creature Multipliers", "", "Defeated Creature Multipliers", "Multiplicateurs des cibles vaincues", "Optional multipliers by defeated creature, e.g. Troll=2;Eikthyr=4.", "Multiplicateurs selon la créature vaincue, ex. Troll=2;Eikthyr=4.");
			VictimXPValues = BindSetting("XP", "Defeated Creature XP", GetDefaultVictimXPValues(), "Defeated Creature XP", "XP par créature vaincue", "Base XP awarded for each vanilla creature at level 1. Format: Prefab=XP;Prefab=XP. Other creatures use XP Per Kill.", "XP de base accordée pour chaque créature vanilla de niveau 1. Format : Préfab=XP;Préfab=XP. Les autres créatures utilisent XP par élimination.");
			EnsureKnownPrefabXP("TrollFrost", 50);
			EnsureKnownPrefabXP("Fenring_Cultist_Hildir_nochest", 300);
			EnsureKnownPrefabXP("Skeleton_Swamps", 18);
			EnsureKnownPrefabXP("Draugr_Ranged", 18);
			if (WizardryDetected)
			{
				WizardryVictimXPValues = BindSetting("Wizardry XP", "Defeated Wizardry Creature XP", GetDefaultWizardryXPValues(), "Defeated Wizardry Creature XP", "XP par créature Wizardry vaincue", "Base XP for Wizardry creature prefabs at level 1. Format: Prefab=XP;Prefab=XP.", "XP de base pour les prefabs de créatures Wizardry au niveau 1. Format : Préfab=XP;Préfab=XP.");
			}
			MaxLevel = BindSetting("Advanced XP", "Max Level", 100, "Max Level", "Niveau maximal", "Optional upper cap from 1 to 100. Without extra thresholds, the effective max remains level 6.", "Plafond facultatif de 1 à 100. Sans seuils supplémentaires, le niveau maximal effectif reste 6.");
			XPLevel2 = BindSetting("XP", "XP To Level 2", 700, "XP To Level 2", "XP pour le niveau 2", "Total XP required to reach level 2.", "Total d'XP requis pour atteindre le niveau 2.");
			XPLevel3 = BindSetting("XP", "XP To Level 3", 1700, "XP To Level 3", "XP pour le niveau 3", "Total XP required to reach level 3.", "Total d'XP requis pour atteindre le niveau 3.");
			XPLevel4 = BindSetting("XP", "XP To Level 4", 3200, "XP To Level 4", "XP pour le niveau 4", "Total XP required to reach level 4.", "Total d'XP requis pour atteindre le niveau 4.");
			XPLevel5 = BindSetting("XP", "XP To Level 5", 5200, "XP To Level 5", "XP pour le niveau 5", "Total XP required to reach level 5.", "Total d'XP requis pour atteindre le niveau 5.");
			XPLevel6 = BindSetting("XP", "XP To Level 6", 8000, "XP To Level 6", "XP pour le niveau 6", "Total XP required to reach level 6.", "Total d'XP requis pour atteindre le niveau 6.");
			HigherLevelThresholds = BindSetting("Advanced XP", "XP Thresholds for Levels 7+", "", "XP Thresholds for Levels 7+", "Seuils d'XP des niveaux 7 et +", "Optional cumulative XP thresholds. Example: 7=11000;8=15000;9=20000. Add consecutive levels with each total higher than the previous level. Maximum supported level: 100.", "Seuils d'XP totaux facultatifs. Exemple : 7=11000;8=15000;9=20000. Ajoute les niveaux à la suite avec un total supérieur au précédent. Niveau maximal pris en charge : 100.");
			ProgressionDefaultsVersion = ((BaseUnityPlugin)this).Config.Bind<int>("Internal", "Progression Defaults Version", 0, new ConfigDescription("Internal one-time migration marker.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			if (ProgressionDefaultsVersion.Value < 1)
			{
				XPLevel2.Value = 700;
				XPLevel3.Value = 1700;
				XPLevel4.Value = 3200;
				XPLevel5.Value = 5200;
				XPLevel6.Value = 8000;
				ProgressionDefaultsVersion.Value = 1;
				((BaseUnityPlugin)this).Config.Save();
			}
			if (ProgressionDefaultsVersion.Value < 2)
			{
				MaxLevel.Value = 100;
				ProgressionDefaultsVersion.Value = 2;
				((BaseUnityPlugin)this).Config.Save();
			}
			BossesAllowed = BindSetting("Rules", "Bosses Allowed",