Decompiled source of Fylgja v0.3.0

Fylgja.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("Fylgja")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("Fylgja")]
[assembly: AssemblyTitle("Fylgja")]
[assembly: AssemblyVersion("0.1.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 Fylgja
{
	internal enum ActionResult
	{
		Done,
		Retry
	}
	internal static class FylgjaActions
	{
		internal static string Problem;

		internal static bool DidWork;

		private static readonly Collider[] s_hits = (Collider[])(object)new Collider[256];

		private static int s_pieceMask;

		private static int s_itemMask;

		internal static ActionResult Execute(Step step, Dictionary<string, int> carry, ref int progress)
		{
			Problem = null;
			DidWork = false;
			if (s_pieceMask == 0)
			{
				s_pieceMask = LayerMask.GetMask(new string[6] { "piece", "piece_nonsolid", "Default", "Default_small", "static_solid", "vehicle" });
				s_itemMask = LayerMask.GetMask(new string[1] { "item" });
			}
			switch (step.Kind)
			{
			case StepKind.Take:
				return Take(step, carry, ref progress);
			case StepKind.Put:
				return Put(step, carry, ref progress);
			case StepKind.Ore:
			case StepKind.Fuel:
				Problem = "$fylgja_p_rerecord";
				return ActionResult.Done;
			case StepKind.Gather:
				return Gather(step, carry);
			case StepKind.Empty:
				return Empty(step, ref progress);
			case StepKind.Use:
				return Interactions.ReplayUse(step, carry, ref progress);
			case StepKind.Interact:
				return Interactions.ReplayInteract(step, carry);
			case StepKind.Harvest:
				return Harvest.Execute(step, carry, ref progress);
			default:
				return ActionResult.Done;
			}
		}

		private static ActionResult Take(Step step, Dictionary<string, int> carry, ref int progress)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Container val = FylgjaActions.FindNear<Container>(step.Target, 1.5f);
			if (!UsableContainer(val))
			{
				return ActionResult.Retry;
			}
			Inventory inventory = val.GetInventory();
			if (inventory == null)
			{
				return Fail("$fylgja_p_notfound");
			}
			string text = Items.SharedName(step.Prefab);
			int num = FylgjaPlugin.Cfg.CarryCapacity.Value - Total(carry);
			if (num <= 0)
			{
				Problem = "$fylgja_p_carryfull";
			}
			int num2 = Mathf.Min(step.Remaining(progress), Mathf.Min(inventory.CountItems(text, -1, true), num));
			if (num2 > 0)
			{
				inventory.RemoveItem(text, num2, -1, true);
				Add(carry, step.Prefab, num2);
				progress += num2;
				SaveContainer(val);
				DidWork = true;
			}
			return ActionResult.Done;
		}

		private static ActionResult Put(Step step, Dictionary<string, int> carry, ref int progress)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			int num = Get(carry, step.Prefab);
			int num2 = Mathf.Min(step.Remaining(progress), num);
			if (num2 <= 0)
			{
				return ActionResult.Done;
			}
			Container val = FylgjaActions.FindNear<Container>(step.Target, 1.5f);
			if (!UsableContainer(val))
			{
				return ActionResult.Retry;
			}
			int num3 = Items.AddTo(val.GetInventory(), step.Prefab, num2);
			Remove(carry, step.Prefab, num3);
			progress += num3;
			if (num3 > 0)
			{
				SaveContainer(val);
				DidWork = true;
			}
			if (num3 >= num2)
			{
				return ActionResult.Done;
			}
			Problem = "$fylgja_p_full";
			if (!step.All)
			{
				return ActionResult.Retry;
			}
			return ActionResult.Done;
		}

		private static bool UsableContainer(Container container)
		{
			if (!Object.op_Implicit((Object)(object)container))
			{
				Problem = "$fylgja_p_notfound";
				return false;
			}
			if (container.IsInUse())
			{
				Problem = "$fylgja_p_inuse";
				return false;
			}
			if (!ClaimContainer(container))
			{
				Problem = "$fylgja_p_notfound";
				return false;
			}
			return true;
		}

		internal static ActionResult Fail(string problem)
		{
			Problem = problem;
			return ActionResult.Retry;
		}

		private static bool ClaimContainer(Container container)
		{
			ZNetView componentInParent = ((Component)container).GetComponentInParent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)componentInParent) || !componentInParent.IsValid())
			{
				return false;
			}
			if (!componentInParent.IsOwner())
			{
				componentInParent.ClaimOwnership();
			}
			return true;
		}

		private static void SaveContainer(Container container)
		{
			Refl.Call(container, "Save");
		}

		private static ActionResult Empty(Step step, ref int progress)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (progress > 0)
			{
				return ActionResult.Done;
			}
			Smelter val = FylgjaActions.FindNear<Smelter>(step.Target, 2f);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return Fail("$fylgja_p_notfound");
			}
			ZNetView component = ((Component)val).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
			{
				return Fail("$fylgja_p_notfound");
			}
			component.InvokeRPC("RPC_EmptyProcessed", Array.Empty<object>());
			progress = 1;
			return ActionResult.Retry;
		}

		private static ActionResult Gather(Step step, Dictionary<string, int> carry)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> hashSet = new HashSet<string>(from s in step.Prefab.Split(new char[1] { ';' })
				where s.Length > 0
				select s);
			int num = Physics.OverlapSphereNonAlloc(step.Target, FylgjaPlugin.Cfg.GatherRadius.Value, s_hits, s_itemMask, (QueryTriggerInteraction)2);
			HashSet<ItemDrop> hashSet2 = new HashSet<ItemDrop>();
			for (int num2 = 0; num2 < num; num2++)
			{
				ItemDrop val = (Object.op_Implicit((Object)(object)s_hits[num2]) ? ((Component)s_hits[num2]).GetComponentInParent<ItemDrop>() : null);
				if (!Object.op_Implicit((Object)(object)val) || !hashSet2.Add(val))
				{
					continue;
				}
				string text = Items.PrefabName(val);
				if (text == null || !hashSet.Contains(text))
				{
					continue;
				}
				ZNetView component = ((Component)val).GetComponent<ZNetView>();
				if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
				{
					continue;
				}
				int stack = val.m_itemData.m_stack;
				if (Total(carry) + stack <= FylgjaPlugin.Cfg.CarryCapacity.Value)
				{
					if (!component.IsOwner())
					{
						component.ClaimOwnership();
					}
					Add(carry, text, stack);
					ZNetScene.instance.Destroy(((Component)val).gameObject);
					DidWork = true;
				}
			}
			return ActionResult.Done;
		}

		internal static bool SourcesHaveItems(List<Step> program)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (s_pieceMask == 0)
			{
				s_pieceMask = LayerMask.GetMask(new string[6] { "piece", "piece_nonsolid", "Default", "Default_small", "static_solid", "vehicle" });
			}
			foreach (Step item in program)
			{
				if (item.Kind == StepKind.Take)
				{
					Container val = FylgjaActions.FindNear<Container>(item.Target, 1.5f);
					Inventory val2 = (Object.op_Implicit((Object)(object)val) ? val.GetInventory() : null);
					if (val2 != null && val2.CountItems(Items.SharedName(item.Prefab), -1, true) > 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		internal static T FindNear<T>(Vector3 pos, float radius) where T : Component
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapSphereNonAlloc(pos, radius, s_hits, s_pieceMask, (QueryTriggerInteraction)2);
			T result = default(T);
			float num2 = float.MaxValue;
			for (int i = 0; i < num; i++)
			{
				T val = (Object.op_Implicit((Object)(object)s_hits[i]) ? ((Component)s_hits[i]).GetComponentInParent<T>() : default(T));
				if (Object.op_Implicit((Object)(object)val))
				{
					Vector3 val2 = ((Component)val).transform.position - pos;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < num2)
					{
						num2 = sqrMagnitude;
						result = val;
					}
				}
			}
			return result;
		}

		internal static int Total(Dictionary<string, int> carry)
		{
			return carry.Values.Sum();
		}

		private static int Get(Dictionary<string, int> carry, string key)
		{
			if (!carry.TryGetValue(key, out var value))
			{
				return 0;
			}
			return value;
		}

		private static void Add(Dictionary<string, int> carry, string key, int n)
		{
			carry[key] = Get(carry, key) + n;
		}

		private static void Remove(Dictionary<string, int> carry, string key, int n)
		{
			int num = Get(carry, key) - n;
			if (num > 0)
			{
				carry[key] = num;
			}
			else
			{
				carry.Remove(key);
			}
		}
	}
	public class FylgjaStone : MonoBehaviour, Hoverable, Interactable
	{
		internal const string GlowName = "FylgjaGlow";

		private const string ZProgram = "fylgja_program";

		private const string ZRunning = "fylgja_running";

		private const string ZStep = "fylgja_step";

		private const string ZPos = "fylgja_pos";

		private const string ZCarry = "fylgja_carry";

		private const string ZOffering = "fylgja_offering";

		private const string ZStatus = "fylgja_status";

		private const string ZResting = "fylgja_resting";

		private const string RpcSetProgram = "Fylgja_SetProgram";

		private const string RpcSetRunning = "Fylgja_SetRunning";

		private const string RpcOffer = "Fylgja_Offer";

		private ZNetView m_nview;

		private GameObject m_glow;

		private GameObject m_ghost;

		private bool m_loaded;

		private List<Step> m_program;

		private string m_programSource;

		private int m_step;

		private int m_progress;

		private Vector3 m_pos;

		private Dictionary<string, int> m_carry;

		private float m_actionTimer;

		private float m_waitTimer;

		private float m_syncTimer;

		private float m_offeringDrain;

		private bool m_loopWork;

		private bool m_resting;

		private float m_restTimer;

		private float m_probeTimer;

		private string m_problem;

		private string m_lastStatus;

		private string m_hoverSource;

		private List<Step> m_hoverProgram = new List<Step>();

		private int m_hoverActions;

		private readonly RouteView m_route = new RouteView();

		private float m_showRouteUntil;

		internal bool IsValid
		{
			get
			{
				if (Object.op_Implicit((Object)(object)m_nview))
				{
					return m_nview.IsValid();
				}
				return false;
			}
		}

		private ZDO Zdo => m_nview.GetZDO();

		private bool Running
		{
			get
			{
				if (IsValid)
				{
					return Zdo.GetBool("fylgja_running", false);
				}
				return false;
			}
		}

		private string ProgramText
		{
			get
			{
				if (!IsValid)
				{
					return "";
				}
				return Zdo.GetString("fylgja_program", "");
			}
		}

		private bool HasProgram => ProgramText.Length > 0;

		private float Offering
		{
			get
			{
				if (!IsValid)
				{
					return 0f;
				}
				return Zdo.GetFloat("fylgja_offering", 0f);
			}
		}

		private void Awake()
		{
			m_nview = ((Component)this).GetComponent<ZNetView>();
			Transform val = FindDeep(((Component)this).transform, "FylgjaGlow");
			m_glow = (Object.op_Implicit((Object)(object)val) ? ((Component)val).gameObject : null);
		}

		private void Start()
		{
			if (IsValid)
			{
				m_nview.Register<string>("Fylgja_SetProgram", (Action<long, string>)RPC_SetProgram);
				m_nview.Register<bool>("Fylgja_SetRunning", (Action<long, bool>)RPC_SetRunning);
				m_nview.Register<int>("Fylgja_Offer", (Action<long, int>)RPC_Offer);
			}
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)m_ghost))
			{
				Object.Destroy((Object)(object)m_ghost);
			}
			m_route.Destroy();
		}

		private void Update()
		{
			if (IsValid)
			{
				bool running = Running;
				if (Object.op_Implicit((Object)(object)m_glow) && m_glow.activeSelf != running)
				{
					m_glow.SetActive(running);
				}
				if (running && m_nview.IsOwner())
				{
					OwnerTick(Time.deltaTime);
				}
				else
				{
					m_loaded = false;
				}
				UpdateGhost(Running);
				UpdateRoute();
			}
		}

		private void OwnerTick(float dt)
		{
			//IL_00c2: 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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			if (!m_loaded)
			{
				LoadRuntime();
			}
			if (m_program == null || m_program.Count == 0)
			{
				StopRunning();
				return;
			}
			if (m_resting)
			{
				RestTick(dt);
				SyncPosition(dt);
				return;
			}
			m_offeringDrain += dt;
			if (m_offeringDrain >= 1f)
			{
				float num = Zdo.GetFloat("fylgja_offering", 0f) - m_offeringDrain;
				m_offeringDrain = 0f;
				Zdo.Set("fylgja_offering", Mathf.Max(0f, num));
				if (num <= 0f)
				{
					StopRunning();
					return;
				}
			}
			Step step = m_program[m_step];
			m_pos = Vector3.MoveTowards(m_pos, step.Stand, FylgjaPlugin.Cfg.Speed.Value * dt);
			Vector3 val = m_pos - step.Stand;
			if (((Vector3)(ref val)).sqrMagnitude < 0.0025f)
			{
				if (step.Kind == StepKind.Move)
				{
					Advance();
				}
				else
				{
					m_actionTimer += dt;
					if (m_actionTimer >= FylgjaPlugin.Cfg.ActionSeconds.Value)
					{
						ActionResult actionResult;
						try
						{
							actionResult = FylgjaActions.Execute(step, m_carry, ref m_progress);
						}
						catch (Exception ex)
						{
							FylgjaPlugin.Log.LogWarning((object)$"Fylgja step {step.Kind} {step.Prefab} failed, skipping: {ex.GetBaseException().Message}");
							FylgjaActions.Problem = "$fylgja_p_error";
							actionResult = ActionResult.Done;
						}
						if (FylgjaActions.DidWork)
						{
							m_loopWork = true;
						}
						m_problem = FylgjaActions.Problem;
						Zdo.Set("fylgja_carry", ProgramCodec.EncodeCarry(m_carry));
						m_waitTimer += m_actionTimer;
						m_actionTimer = 0f;
						if (actionResult == ActionResult.Done || m_waitTimer >= FylgjaPlugin.Cfg.WaitTimeout.Value)
						{
							Advance();
						}
						else
						{
							WriteStatus();
						}
					}
				}
			}
			SyncPosition(dt);
		}

		private void SyncPosition(float dt)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			m_syncTimer -= dt;
			if (!(m_syncTimer > 0f))
			{
				m_syncTimer = 0.2f;
				Zdo.Set("fylgja_pos", m_pos);
			}
		}

		private void Advance()
		{
			m_step = (m_step + 1) % m_program.Count;
			m_progress = 0;
			m_actionTimer = 0f;
			m_waitTimer = 0f;
			Zdo.Set("fylgja_step", m_step);
			if (m_step == 0)
			{
				if (!m_loopWork)
				{
					EnterRest();
				}
				m_loopWork = false;
			}
			WriteStatus();
		}

		private void EnterRest()
		{
			m_resting = true;
			m_restTimer = 0f;
			m_probeTimer = FylgjaPlugin.Cfg.RestProbeSeconds.Value;
			Zdo.Set("fylgja_resting", true);
		}

		private void RestTick(float dt)
		{
			//IL_0002: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			m_pos = Vector3.MoveTowards(m_pos, m_program[0].Stand, FylgjaPlugin.Cfg.Speed.Value * dt);
			m_restTimer += dt;
			m_probeTimer -= dt;
			if (!(m_probeTimer > 0f))
			{
				m_probeTimer = FylgjaPlugin.Cfg.RestProbeSeconds.Value;
				bool flag = FylgjaActions.Total(m_carry) < FylgjaPlugin.Cfg.CarryCapacity.Value;
				if (m_restTimer >= FylgjaPlugin.Cfg.RestMaxSeconds.Value || (flag && FylgjaActions.SourcesHaveItems(m_program)))
				{
					m_resting = false;
					m_loopWork = false;
					m_step = 0;
					Zdo.Set("fylgja_step", 0);
					Zdo.Set("fylgja_resting", false);
					WriteStatus();
				}
			}
		}

		private void WriteStatus()
		{
			string text = m_step + "|" + m_problem;
			if (!(text == m_lastStatus))
			{
				m_lastStatus = text;
				Zdo.Set("fylgja_status", text);
			}
		}

		private void LoadRuntime()
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			string programText = ProgramText;
			if (programText != m_programSource)
			{
				m_programSource = programText;
				m_program = ProgramCodec.Decode(programText);
			}
			m_step = ((m_program.Count > 0) ? Mathf.Clamp(Zdo.GetInt("fylgja_step", 0), 0, m_program.Count - 1) : 0);
			m_pos = Zdo.GetVec3("fylgja_pos", (m_program.Count > 0) ? m_program[0].Stand : ((Component)this).transform.position);
			m_carry = ProgramCodec.DecodeCarry(Zdo.GetString("fylgja_carry", ""));
			m_progress = 0;
			m_actionTimer = 0f;
			m_waitTimer = 0f;
			m_offeringDrain = 0f;
			m_resting = Zdo.GetBool("fylgja_resting", false);
			m_loopWork = false;
			m_restTimer = 0f;
			m_probeTimer = 0f;
			m_problem = null;
			m_lastStatus = null;
			m_loaded = true;
		}

		private void StopRunning()
		{
			Zdo.Set("fylgja_running", false);
			Zdo.Set("fylgja_resting", false);
			Zdo.Set("fylgja_status", "");
			DropCarry();
			m_loaded = false;
		}

		internal void DropCarry()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if (!IsValid)
			{
				return;
			}
			Dictionary<string, int> dictionary = ProgramCodec.DecodeCarry(Zdo.GetString("fylgja_carry", ""));
			Vector3 origin = ((Component)this).transform.position + ((Component)this).transform.forward * 1.2f;
			foreach (KeyValuePair<string, int> item in dictionary)
			{
				Items.Spawn(item.Key, item.Value, origin);
			}
			Zdo.Set("fylgja_carry", "");
		}

		internal void SendProgram(string program)
		{
			if (IsValid)
			{
				m_nview.InvokeRPC("Fylgja_SetProgram", new object[1] { program });
			}
		}

		private void SetRunning(bool run)
		{
			if (IsValid)
			{
				m_nview.InvokeRPC("Fylgja_SetRunning", new object[1] { run });
			}
		}

		private void RPC_SetProgram(long sender, string program)
		{
			if (m_nview.IsOwner())
			{
				if (Running)
				{
					StopRunning();
				}
				Zdo.Set("fylgja_program", program);
				Zdo.Set("fylgja_step", 0);
				m_loaded = false;
			}
		}

		private void RPC_SetRunning(long sender, bool run)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (!m_nview.IsOwner())
			{
				return;
			}
			if (!run)
			{
				if (Running)
				{
					StopRunning();
				}
				return;
			}
			List<Step> list = ProgramCodec.Decode(ProgramText);
			if (list.Count != 0 && !(Offering <= 0f))
			{
				Zdo.Set("fylgja_step", 0);
				Zdo.Set("fylgja_pos", list[0].Stand);
				Zdo.Set("fylgja_resting", false);
				Zdo.Set("fylgja_status", "");
				Zdo.Set("fylgja_running", true);
				m_loaded = false;
			}
		}

		private void RPC_Offer(long sender, int seconds)
		{
			if (m_nview.IsOwner())
			{
				float num = Mathf.Min(Zdo.GetFloat("fylgja_offering", 0f) + (float)seconds, FylgjaPlugin.Cfg.MaxOfferingSeconds.Value);
				Zdo.Set("fylgja_offering", num);
			}
		}

		private void UpdateGhost(bool running)
		{
			//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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00b4: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			if (!running)
			{
				if (Object.op_Implicit((Object)(object)m_ghost))
				{
					Object.Destroy((Object)(object)m_ghost);
				}
				return;
			}
			Vector3 val = ((m_nview.IsOwner() && m_loaded) ? m_pos : Zdo.GetVec3("fylgja_pos", ((Component)this).transform.position)) + Vector3.up * 0.25f;
			if (!Object.op_Implicit((Object)(object)m_ghost))
			{
				m_ghost = GhostVisual.Create(val);
				return;
			}
			float deltaTime = Time.deltaTime;
			Vector3 position = m_ghost.transform.position;
			Vector3 val2 = Vector3.Lerp(position, val, 1f - Mathf.Exp(-10f * deltaTime));
			Vector3 val3 = val2 - position;
			val3.y = 0f;
			if (((Vector3)(ref val3)).sqrMagnitude > 1E-06f)
			{
				m_ghost.transform.rotation = Quaternion.Slerp(m_ghost.transform.rotation, Quaternion.LookRotation(val3), deltaTime * 8f);
			}
			m_ghost.transform.position = val2;
		}

		private void UpdateRoute()
		{
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer))
			{
				GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
				if (Object.op_Implicit((Object)(object)hoverObject) && (Object)(object)hoverObject.GetComponentInParent<FylgjaStone>() == (Object)(object)this)
				{
					m_showRouteUntil = Time.time + FylgjaPlugin.Cfg.RouteDisplaySeconds.Value;
				}
			}
			if (Recorder.IsRecordingFor(this))
			{
				List<Step> currentSteps = Recorder.CurrentSteps;
				m_route.Show(currentSteps, "rec:" + (currentSteps?.Count ?? 0));
			}
			else if (Time.time < m_showRouteUntil)
			{
				RefreshHoverProgram();
				m_route.Show(m_hoverProgram, m_hoverSource);
			}
			else
			{
				m_route.Hide();
			}
		}

		private void RefreshHoverProgram()
		{
			string programText = ProgramText;
			if ((object)programText != m_hoverSource)
			{
				m_hoverSource = programText;
				m_hoverProgram = ProgramCodec.Decode(programText);
				m_hoverActions = ProgramCodec.ActionCount(m_hoverProgram);
			}
		}

		private static string Describe(Step step)
		{
			string text = (step.All ? "$fylgja_all" : ("x" + step.Amount));
			switch (step.Kind)
			{
			case StepKind.Take:
				return "$fylgja_d_take " + Items.SharedName(step.Prefab) + " " + text;
			case StepKind.Put:
				return "$fylgja_d_put " + Items.SharedName(step.Prefab) + " " + text;
			case StepKind.Use:
			{
				int num = step.Prefab.IndexOf('@');
				string prefabName = ((num > 0) ? step.Prefab.Substring(0, num) : step.Prefab);
				string text2 = ((num > 0) ? step.Prefab.Substring(num + 1) : "?");
				return Items.SharedName(prefabName) + " " + text + " → " + text2;
			}
			case StepKind.Interact:
				return "$fylgja_d_interact " + step.Prefab.Replace("!alt", "");
			case StepKind.Gather:
				return "$fylgja_d_gather " + string.Join(", ", (from n in step.Prefab.Split(new char[1] { ';' })
					where n.Length > 0
					select n).Select(Items.SharedName).ToArray());
			case StepKind.Empty:
				return "$fylgja_d_empty";
			case StepKind.Harvest:
				return "$fylgja_d_harvest " + string.Join(", ", (from n in step.Prefab.Split(new char[1] { ';' })
					where n.Length > 0
					select n).Select(Harvest.CropLabel).ToArray());
			default:
				return "$fylgja_p_rerecord";
			}
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public string GetHoverName()
		{
			return "$piece_fylgjastone";
		}

		public string GetHoverText()
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if (!IsValid)
			{
				return "";
			}
			RefreshHoverProgram();
			bool flag = Recorder.IsRecordingFor(this);
			bool running = Running;
			StringBuilder stringBuilder = new StringBuilder("$piece_fylgjastone\n");
			if (flag)
			{
				stringBuilder.Append("<color=#ff9b6b>$fylgja_state_recording</color>\n");
			}
			else if (running)
			{
				stringBuilder.Append("<color=#9be2ff>$fylgja_state_running</color>\n");
			}
			else if (m_hoverActions > 0)
			{
				stringBuilder.Append("$fylgja_state_idle\n");
			}
			else
			{
				stringBuilder.Append("$fylgja_state_empty\n");
			}
			if (m_hoverActions > 0)
			{
				stringBuilder.Append($"$fylgja_steps: {m_hoverActions}\n");
			}
			int num = Mathf.CeilToInt(Offering);
			stringBuilder.Append($"$fylgja_offering: {num / 60}:{num % 60:00}\n");
			if (running)
			{
				AppendStatus(stringBuilder);
			}
			if (flag)
			{
				string text = ((object)FylgjaPlugin.Cfg.AllModeKey.Value/*cast due to .constrained prefix*/).ToString();
				stringBuilder.Append("$fylgja_allmode: " + (Recorder.AllMode ? "<color=#9be29b>$fylgja_on</color>" : "$fylgja_off") + " [<color=yellow><b>" + text + "</b></color>]\n");
			}
			if (flag)
			{
				stringBuilder.Append("[<color=yellow><b>$KEY_Use</b></color>] $fylgja_finish\n");
				stringBuilder.Append("[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $fylgja_cancel");
			}
			else
			{
				if (m_hoverActions > 0)
				{
					stringBuilder.Append("[<color=yellow><b>$KEY_Use</b></color>] " + (running ? "$fylgja_stop" : "$fylgja_start") + "\n");
				}
				stringBuilder.Append("[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $fylgja_record\n");
				stringBuilder.Append("$fylgja_offer_hint");
			}
			return Localization.instance.Localize(stringBuilder.ToString());
		}

		private void AppendStatus(StringBuilder sb)
		{
			if (Zdo.GetBool("fylgja_resting", false))
			{
				sb.Append("<color=#9be2ff>$fylgja_resting</color>\n");
				return;
			}
			string text = Zdo.GetString("fylgja_status", "");
			int num = text.IndexOf('|');
			if (num < 0 || !int.TryParse(text.Substring(0, num), out var result) || m_hoverProgram.Count == 0)
			{
				return;
			}
			string text2 = text.Substring(num + 1);
			result = Mathf.Clamp(result, 0, m_hoverProgram.Count - 1);
			int num2 = -1;
			for (int i = 0; i < m_hoverProgram.Count; i++)
			{
				int num3 = (result + i) % m_hoverProgram.Count;
				if (m_hoverProgram[num3].Kind != StepKind.Move)
				{
					num2 = num3;
					break;
				}
			}
			if (num2 >= 0)
			{
				int num4 = m_hoverProgram.Take(num2 + 1).Count((Step s) => s.Kind != StepKind.Move);
				sb.Append($"$fylgja_next ({num4}/{m_hoverActions}): {Describe(m_hoverProgram[num2])}\n");
			}
			if (text2.Length > 0)
			{
				sb.Append("<color=#ff8a80>" + text2 + "</color>\n");
			}
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold || !IsValid)
			{
				return false;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (Recorder.IsRecordingFor(this))
			{
				if (alt)
				{
					Recorder.Cancel("$fylgja_cancelled");
				}
				else
				{
					Recorder.Finish();
				}
				return true;
			}
			if (Recorder.Recording)
			{
				Notify(val, "$fylgja_busy");
				return false;
			}
			if (alt)
			{
				if (Running)
				{
					SetRunning(run: false);
				}
				Recorder.Begin(this, val);
				return true;
			}
			if (!HasProgram)
			{
				Notify(val, "$fylgja_noprogram");
				return false;
			}
			if (Running)
			{
				SetRunning(run: false);
				Notify(val, "$fylgja_released");
				return true;
			}
			if (Offering <= 0f)
			{
				Notify(val, "$fylgja_needoffer");
				return false;
			}
			SetRunning(run: true);
			Notify(val, "$fylgja_awakened");
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			Player val = (Player)(object)((user is Player) ? user : null);
			if (!Object.op_Implicit((Object)(object)val) || item == null || !IsValid)
			{
				return false;
			}
			if (Items.PrefabName(item) != FylgjaPlugin.Cfg.OfferingItem.Value)
			{
				return false;
			}
			if (Offering + FylgjaPlugin.Cfg.SecondsPerOffering.Value > FylgjaPlugin.Cfg.MaxOfferingSeconds.Value + 1f)
			{
				Notify(val, "$fylgja_offerfull");
				return true;
			}
			((Humanoid)val).GetInventory().RemoveItem(item.m_shared.m_name, 1, -1, true);
			m_nview.InvokeRPC("Fylgja_Offer", new object[1] { Mathf.RoundToInt(FylgjaPlugin.Cfg.SecondsPerOffering.Value) });
			Notify(val, "$fylgja_offered");
			return true;
		}

		internal static void Notify(Player player, string text)
		{
			if (Object.op_Implicit((Object)(object)player))
			{
				((Character)player).Message((MessageType)2, Localization.instance.Localize(text), 0, (Sprite)null, false);
			}
		}

		private static Transform FindDeep(Transform parent, string name)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			foreach (Transform item in parent)
			{
				Transform val = item;
				if (((Object)val).name == name)
				{
					return val;
				}
				Transform val2 = FindDeep(val, name);
				if (Object.op_Implicit((Object)(object)val2))
				{
					return val2;
				}
			}
			return null;
		}
	}
	internal static class Harvest
	{
		private sealed class Job
		{
			public readonly List<Spot> Spots = new List<Spot>();

			public readonly HashSet<string> Yield = new HashSet<string>();
		}

		private struct Spot
		{
			public string Crop;

			public Vector3 Position;

			public Quaternion Rotation;
		}

		private struct Seedling
		{
			public GameObject Prefab;

			public List<KeyValuePair<string, int>> Cost;
		}

		private static readonly Dictionary<Step, Job> s_jobs = new Dictionary<Step, Job>();

		private static Dictionary<string, Seedling> s_seedlings;

		private static readonly Collider[] s_hits = (Collider[])(object)new Collider[1024];

		internal static float Radius(Step step)
		{
			return (float)step.Amount / 10f + 1f;
		}

		internal static ActionResult Execute(Step step, Dictionary<string, int> carry, ref int progress)
		{
			switch (progress)
			{
			case 0:
				progress = 1;
				return Pick(step);
			case 1:
				progress = 2;
				Collect(step, carry);
				return ActionResult.Retry;
			default:
				Replant(step, carry);
				s_jobs.Remove(step);
				return ActionResult.Done;
			}
		}

		private static ActionResult Pick(Step step)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return FylgjaActions.Fail("$fylgja_p_handsfull");
			}
			HashSet<string> hashSet = new HashSet<string>(from s in step.Prefab.Split(new char[1] { ';' })
				where s.Length > 0
				select s);
			Job job = new Job();
			s_jobs[step] = job;
			foreach (Pickable item in Nearby<Pickable>(step.Target, Radius(step)))
			{
				string text = PrefabName(((Component)item).gameObject);
				if (hashSet.Contains(text) && IsRipe(item))
				{
					object obj = Refl.Get(item, "m_itemPrefab");
					GameObject val = (GameObject)((obj is GameObject) ? obj : null);
					if (val != null && Object.op_Implicit((Object)(object)val))
					{
						job.Yield.Add(((Object)val).name);
					}
					job.Spots.Add(new Spot
					{
						Crop = text,
						Position = ((Component)item).transform.position,
						Rotation = ((Component)item).transform.rotation
					});
					Interactions.Replaying = true;
					try
					{
						((Interactable)item).Interact((Humanoid)(object)localPlayer, false, false);
					}
					finally
					{
						Interactions.Replaying = false;
					}
				}
			}
			if (job.Spots.Count > 0)
			{
				FylgjaActions.DidWork = true;
			}
			return ActionResult.Retry;
		}

		private static bool IsRipe(Pickable pickable)
		{
			object obj = Refl.Call(pickable, "CanBePicked");
			if (obj is bool)
			{
				return (bool)obj;
			}
			ZNetView component = ((Component)pickable).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid())
			{
				return !component.GetZDO().GetBool("picked", false);
			}
			return false;
		}

		private static void Collect(Step step, Dictionary<string, int> carry)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!s_jobs.TryGetValue(step, out var value) || value.Yield.Count == 0)
			{
				return;
			}
			foreach (ItemDrop item in Nearby<ItemDrop>(step.Target, Radius(step) + 1f))
			{
				string text = Items.PrefabName(item);
				if (text == null || !value.Yield.Contains(text))
				{
					continue;
				}
				ZNetView component = ((Component)item).GetComponent<ZNetView>();
				if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
				{
					continue;
				}
				int stack = item.m_itemData.m_stack;
				if (FylgjaActions.Total(carry) + stack > FylgjaPlugin.Cfg.CarryCapacity.Value)
				{
					FylgjaActions.Problem = "$fylgja_p_carryfull";
					continue;
				}
				if (!component.IsOwner())
				{
					component.ClaimOwnership();
				}
				carry[text] = (carry.TryGetValue(text, out var value2) ? value2 : 0) + stack;
				ZNetScene.instance.Destroy(((Component)item).gameObject);
				FylgjaActions.DidWork = true;
			}
		}

		private static void Replant(Step step, Dictionary<string, int> carry)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			if (!FylgjaPlugin.Cfg.Replant.Value || !s_jobs.TryGetValue(step, out var value))
			{
				return;
			}
			LoadSeedlings();
			bool flag = false;
			foreach (Spot spot in value.Spots)
			{
				if (!s_seedlings.TryGetValue(spot.Crop, out var value2) || Occupied(spot.Position))
				{
					continue;
				}
				if (!value2.Cost.All((KeyValuePair<string, int> c) => (carry.TryGetValue(c.Key, out var value3) ? value3 : 0) >= c.Value))
				{
					flag = true;
					continue;
				}
				foreach (KeyValuePair<string, int> item in value2.Cost)
				{
					int num = carry[item.Key] - item.Value;
					if (num > 0)
					{
						carry[item.Key] = num;
					}
					else
					{
						carry.Remove(item.Key);
					}
				}
				Piece component = Object.Instantiate<GameObject>(value2.Prefab, spot.Position, spot.Rotation).GetComponent<Piece>();
				if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)Game.instance))
				{
					Refl.Call(component, "SetCreator", Game.instance.GetPlayerProfile().GetPlayerID());
				}
				FylgjaActions.DidWork = true;
			}
			if (flag)
			{
				FylgjaActions.Problem = "$fylgja_p_noseeds";
			}
		}

		private static bool Occupied(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapSphereNonAlloc(pos, 0.3f, s_hits, -1, (QueryTriggerInteraction)2);
			for (int i = 0; i < num; i++)
			{
				Collider val = s_hits[i];
				if (Object.op_Implicit((Object)(object)val) && (Object.op_Implicit((Object)(object)((Component)val).GetComponentInParent<Pickable>()) || Object.op_Implicit((Object)(object)((Component)val).GetComponentInParent<Plant>())))
				{
					return true;
				}
			}
			return false;
		}

		private static void LoadSeedlings()
		{
			if (s_seedlings != null)
			{
				return;
			}
			s_seedlings = new Dictionary<string, Seedling>();
			if (!(Refl.Get(ZNetScene.instance, "m_prefabs") is List<GameObject> list))
			{
				return;
			}
			foreach (GameObject item in list)
			{
				if (!Object.op_Implicit((Object)(object)item))
				{
					continue;
				}
				Plant component = item.GetComponent<Plant>();
				Piece component2 = item.GetComponent<Piece>();
				if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2))
				{
					continue;
				}
				List<KeyValuePair<string, int>> list2 = new List<KeyValuePair<string, int>>();
				if (Refl.Get(component2, "m_resources") is Array array)
				{
					foreach (object item2 in array)
					{
						object obj = Refl.Get(item2, "m_resItem");
						ItemDrop val = (ItemDrop)((obj is ItemDrop) ? obj : null);
						int num = ((!(Refl.Get(item2, "m_amount") is int num2)) ? 1 : num2);
						if (Object.op_Implicit((Object)(object)val) && num > 0)
						{
							list2.Add(new KeyValuePair<string, int>(((Object)((Component)val).gameObject).name, num));
						}
					}
				}
				if (!(Refl.Get(component, "m_grownPrefabs") is GameObject[] array2))
				{
					continue;
				}
				GameObject[] array3 = array2;
				foreach (GameObject val2 in array3)
				{
					if (Object.op_Implicit((Object)(object)val2) && !s_seedlings.ContainsKey(((Object)val2).name))
					{
						s_seedlings[((Object)val2).name] = new Seedling
						{
							Prefab = item,
							Cost = list2
						};
					}
				}
			}
			FylgjaPlugin.Log.LogInfo((object)$"Fylgja knows {s_seedlings.Count} replantable crops");
		}

		private static List<T> Nearby<T>(Vector3 center, float radius) where T : Component
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapSphereNonAlloc(center, radius, s_hits, -1, (QueryTriggerInteraction)2);
			HashSet<T> hashSet = new HashSet<T>();
			List<T> list = new List<T>();
			for (int i = 0; i < num; i++)
			{
				T val = (Object.op_Implicit((Object)(object)s_hits[i]) ? ((Component)s_hits[i]).GetComponentInParent<T>() : default(T));
				if (Object.op_Implicit((Object)(object)val) && hashSet.Add(val))
				{
					list.Add(val);
				}
			}
			return list;
		}

		internal static string PrefabName(GameObject go)
		{
			if (!Object.op_Implicit((Object)(object)go))
			{
				return "";
			}
			return ((Object)go).name.Replace("(Clone)", "").Trim();
		}

		internal static string CropLabel(string prefab)
		{
			return prefab.Replace("Pickable_", "").Replace("_", " ");
		}
	}
	internal static class Interactions
	{
		private static readonly HashSet<string> s_excluded = new HashSet<string>
		{
			"Container", "FylgjaStone", "Door", "Bed", "Chair", "CraftingStation", "Sign", "ShipControlls", "Ladder", "Vagon",
			"Ship", "TeleportWorld", "Teleport", "Tameable", "MapTable", "OfferingBowl", "PrivateArea", "Trader", "RuneStone", "Vegvisir",
			"Talker", "Player", "Humanoid", "Character"
		};

		internal static bool Replaying;

		private static readonly Collider[] s_hits = (Collider[])(object)new Collider[128];

		private static int s_mask;

		internal static Component Resolve(GameObject hover, out string typeName)
		{
			typeName = null;
			if (!Object.op_Implicit((Object)(object)hover))
			{
				return null;
			}
			Interactable componentInParent = hover.GetComponentInParent<Interactable>();
			Component val = (Component)(object)((componentInParent is Component) ? componentInParent : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			typeName = ((object)val).GetType().Name;
			if (!s_excluded.Contains(typeName))
			{
				return val;
			}
			return null;
		}

		internal static void RecordUse(Player player, GameObject hover, string typeName, string prefab, int amount)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Recorder.AddAction(StepKind.Use, ((Component)player).transform.position, hover.transform.position, prefab + "@" + typeName, amount);
		}

		internal static void RecordInteract(Player player, GameObject hover, string typeName, bool alt)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Recorder.AddAction(StepKind.Interact, ((Component)player).transform.position, hover.transform.position, alt ? (typeName + "!alt") : typeName, 1);
		}

		internal static ActionResult ReplayUse(Step step, Dictionary<string, int> carry, ref int progress)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			int num = step.Prefab.IndexOf('@');
			if (num <= 0)
			{
				return ActionResult.Done;
			}
			string prefab = step.Prefab.Substring(0, num);
			string typeName = step.Prefab.Substring(num + 1);
			int num2 = Mathf.Min(step.Remaining(progress), Get(carry, prefab));
			if (num2 <= 0)
			{
				return ActionResult.Done;
			}
			Player localPlayer = Player.m_localPlayer;
			Component obj = Find(step.Target, typeName);
			Interactable val = (Interactable)(object)((obj is Interactable) ? obj : null);
			if (!Object.op_Implicit((Object)(object)localPlayer) || val == null)
			{
				return FylgjaActions.Fail("$fylgja_p_notfound");
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			int num3 = CountOf(inventory, prefab);
			int num4 = Items.AddTo(inventory, prefab, num2);
			if (num4 <= 0)
			{
				return FylgjaActions.Fail("$fylgja_p_handsfull");
			}
			for (int i = 0; i < num4; i++)
			{
				ItemData val2 = ((IEnumerable<ItemData>)inventory.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData it) => Items.PrefabName(it) == prefab));
				if (val2 == null)
				{
					break;
				}
				int num5 = CountOf(inventory, prefab);
				Replaying = true;
				try
				{
					val.UseItem((Humanoid)(object)localPlayer, val2);
				}
				finally
				{
					Replaying = false;
				}
				if (CountOf(inventory, prefab) >= num5)
				{
					break;
				}
			}
			int num6 = Mathf.Clamp(num3 + num4 - CountOf(inventory, prefab), 0, num4);
			int num7 = num4 - num6;
			if (num7 > 0)
			{
				inventory.RemoveItem(Items.SharedName(prefab), num7, -1, true);
			}
			Remove(carry, prefab, num6);
			progress += num6;
			if (num6 > 0)
			{
				FylgjaActions.DidWork = true;
			}
			if (num6 >= num2)
			{
				return ActionResult.Done;
			}
			FylgjaActions.Problem = "$fylgja_p_full";
			if (!step.All)
			{
				return ActionResult.Retry;
			}
			return ActionResult.Done;
		}

		internal static ActionResult ReplayInteract(Step step, Dictionary<string, int> carry)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			bool flag = step.Prefab.EndsWith("!alt");
			string typeName = (flag ? step.Prefab.Substring(0, step.Prefab.Length - 4) : step.Prefab);
			Player localPlayer = Player.m_localPlayer;
			Component obj = Find(step.Target, typeName);
			Interactable val = (Interactable)(object)((obj is Interactable) ? obj : null);
			if (!Object.op_Implicit((Object)(object)localPlayer) || val == null)
			{
				return FylgjaActions.Fail("$fylgja_p_notfound");
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			Dictionary<string, int> before = Items.Count(inventory);
			int num = Mathf.Clamp(step.Amount, 1, 10);
			Replaying = true;
			try
			{
				for (int i = 0; i < num; i++)
				{
					val.Interact((Humanoid)(object)localPlayer, false, flag);
				}
			}
			finally
			{
				Replaying = false;
			}
			foreach (KeyValuePair<string, int> item in Items.Diff(before, Items.Count(inventory)))
			{
				if (item.Value > 0)
				{
					inventory.RemoveItem(Items.SharedName(item.Key), item.Value, -1, true);
					Add(carry, item.Key, item.Value);
					FylgjaActions.DidWork = true;
				}
			}
			return ActionResult.Done;
		}

		internal static Component Find(Vector3 pos, string typeName)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			if (s_mask == 0)
			{
				s_mask = LayerMask.GetMask(new string[7] { "piece", "piece_nonsolid", "Default", "Default_small", "static_solid", "vehicle", "item" });
			}
			int num = Physics.OverlapSphereNonAlloc(pos, 1f, s_hits, s_mask, (QueryTriggerInteraction)2);
			Component result = null;
			float num2 = float.MaxValue;
			for (int i = 0; i < num; i++)
			{
				Collider val = s_hits[i];
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				GameObject val2 = (Object.op_Implicit((Object)(object)val.attachedRigidbody) ? ((Component)val.attachedRigidbody).gameObject : ((Component)val).gameObject);
				Interactable componentInParent = val2.GetComponentInParent<Interactable>();
				Component val3 = (Component)(object)((componentInParent is Component) ? componentInParent : null);
				if (Object.op_Implicit((Object)(object)val3) && !(((object)val3).GetType().Name != typeName))
				{
					Vector3 val4 = val2.transform.position - pos;
					float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
					if (sqrMagnitude < num2)
					{
						num2 = sqrMagnitude;
						result = val3;
					}
				}
			}
			return result;
		}

		private static int CountOf(Inventory inv, string prefab)
		{
			if (!Items.Count(inv).TryGetValue(prefab, out var value))
			{
				return 0;
			}
			return value;
		}

		private static int Get(Dictionary<string, int> carry, string key)
		{
			if (!carry.TryGetValue(key, out var value))
			{
				return 0;
			}
			return value;
		}

		private static void Add(Dictionary<string, int> carry, string key, int n)
		{
			carry[key] = Get(carry, key) + n;
		}

		private static void Remove(Dictionary<string, int> carry, string key, int n)
		{
			int num = Get(carry, key) - n;
			if (num > 0)
			{
				carry[key] = num;
			}
			else
			{
				carry.Remove(key);
			}
		}
	}
	internal sealed class InteractionRecordState
	{
		public GameObject Hover;

		public Dictionary<string, int> Before;

		public bool Alt;
	}
	[HarmonyPatch]
	internal static class PlayerInteractPatch
	{
		private static MethodBase Target => Refl.FindMethod(typeof(Player), "Interact");

		private static bool Prepare()
		{
			if (Target == null)
			{
				Refl.WarnOnce("Player.Interact (station recording)");
			}
			return Target != null;
		}

		private static MethodBase TargetMethod()
		{
			return Target;
		}

		private static void Prefix(Player __instance, GameObject __0, bool __2, out InteractionRecordState __state)
		{
			__state = null;
			if (Recorder.Recording && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)__0))
			{
				__state = new InteractionRecordState
				{
					Hover = __0,
					Before = Items.Count(((Humanoid)__instance).GetInventory()),
					Alt = __2
				};
			}
		}

		private static void Postfix(Player __instance, bool __1, InteractionRecordState __state)
		{
			if (__state == null || !Object.op_Implicit((Object)(object)__state.Hover) || !Recorder.Recording)
			{
				return;
			}
			string typeName;
			Component val = Interactions.Resolve(__state.Hover, out typeName);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			if (val is Pickable)
			{
				if (!__1)
				{
					Recorder.RecordHarvest(__instance, val.gameObject);
				}
				return;
			}
			bool flag = false;
			foreach (KeyValuePair<string, int> item in Items.Diff(__state.Before, Items.Count(((Humanoid)__instance).GetInventory())))
			{
				if (item.Value < 0)
				{
					Interactions.RecordUse(__instance, __state.Hover, typeName, item.Key, -item.Value);
					flag = true;
				}
			}
			if (!flag && !__1)
			{
				Interactions.RecordInteract(__instance, __state.Hover, typeName, __state.Alt);
			}
		}
	}
	[HarmonyPatch]
	internal static class UseItemPatch
	{
		private static MethodBase Target => Refl.FindMethod(typeof(Humanoid), "UseItem");

		private static bool Prepare()
		{
			if (Target == null)
			{
				Refl.WarnOnce("Humanoid.UseItem (item recording)");
			}
			return Target != null;
		}

		private static MethodBase TargetMethod()
		{
			return Target;
		}

		private static void Prefix(Humanoid __instance, out InteractionRecordState __state)
		{
			__state = null;
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (Recorder.Recording && Object.op_Implicit((Object)(object)val) && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
			{
				GameObject hoverObject = ((Humanoid)val).GetHoverObject();
				if (Object.op_Implicit((Object)(object)hoverObject))
				{
					__state = new InteractionRecordState
					{
						Hover = hoverObject,
						Before = Items.Count(((Humanoid)val).GetInventory())
					};
				}
			}
		}

		private static void Postfix(Humanoid __instance, InteractionRecordState __state)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if (__state == null || !Object.op_Implicit((Object)(object)__state.Hover) || !Recorder.Recording)
			{
				return;
			}
			Player val = (Player)__instance;
			if (!Object.op_Implicit((Object)(object)Interactions.Resolve(__state.Hover, out var typeName)))
			{
				return;
			}
			foreach (KeyValuePair<string, int> item in Items.Diff(__state.Before, Items.Count(((Humanoid)val).GetInventory())))
			{
				if (item.Value < 0)
				{
					Interactions.RecordUse(val, __state.Hover, typeName, item.Key, -item.Value);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class SuppressMessagesPatch
	{
		private static MethodBase Target => Refl.FindMethod(typeof(Player), "Message");

		private static bool Prepare()
		{
			if (Target == null)
			{
				Refl.WarnOnce("Player.Message (message suppression)");
			}
			return Target != null;
		}

		private static MethodBase TargetMethod()
		{
			return Target;
		}

		private static bool Prefix()
		{
			return !Interactions.Replaying;
		}
	}
	internal static class Localizations
	{
		internal static void Register()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "piece_fylgjastone", "Fylgja Stone" },
				{ "piece_fylgjastone_desc", "Binds your fylgja, the spirit that walks behind you. Show it a route and it repeats your work while honey is offered." },
				{ "fylgja_state_empty", "No route bound" },
				{ "fylgja_state_idle", "The fylgja rests" },
				{ "fylgja_state_running", "The fylgja walks" },
				{ "fylgja_state_recording", "The fylgja watches you" },
				{ "fylgja_steps", "Tasks" },
				{ "fylgja_offering", "Offering" },
				{ "fylgja_start", "Awaken the fylgja" },
				{ "fylgja_stop", "Release the fylgja" },
				{ "fylgja_record", "Show a new route" },
				{ "fylgja_finish", "Finish the route" },
				{ "fylgja_cancel", "Abandon the route" },
				{ "fylgja_offer_hint", "Offer honey to sustain it" },
				{ "fylgja_recording_started", "Your fylgja watches. Do the work, then return to the stone." },
				{ "fylgja_recorded", "Route bound. Tasks" },
				{ "fylgja_noactions", "Nothing was done. Move items between chests, smelters or the ground." },
				{ "fylgja_cancelled", "The route fades" },
				{ "fylgja_toofar", "Too far from the stone. The fylgja may not follow here." },
				{ "fylgja_toolong", "The route is too long and fades" },
				{ "fylgja_busy", "Your fylgja already watches you at another stone" },
				{ "fylgja_noprogram", "Show the fylgja a route first" },
				{ "fylgja_needoffer", "The fylgja needs an offering of honey" },
				{ "fylgja_offerfull", "The stone holds all the honey it can" },
				{ "fylgja_offered", "The offering is accepted" },
				{ "fylgja_awakened", "The fylgja rises" },
				{ "fylgja_released", "The fylgja returns to the stone" },
				{ "fylgja_allmode", "All mode" },
				{ "fylgja_on", "on" },
				{ "fylgja_off", "off" },
				{ "fylgja_allmode_on", "All mode on: the fylgja takes everything and fills until full" },
				{ "fylgja_allmode_off", "All mode off: the fylgja moves exact amounts" },
				{ "fylgja_all", "(all)" },
				{ "fylgja_next", "Next" },
				{ "fylgja_resting", "Resting at the stone until there is work" },
				{ "fylgja_d_take", "Take" },
				{ "fylgja_d_put", "Store" },
				{ "fylgja_d_interact", "Use" },
				{ "fylgja_d_gather", "Pick up" },
				{ "fylgja_d_empty", "Empty smelter" },
				{ "fylgja_p_notfound", "Target not found or not loaded" },
				{ "fylgja_p_inuse", "A chest is open, waiting" },
				{ "fylgja_p_full", "Target is full" },
				{ "fylgja_p_carryfull", "The fylgja carries all it can" },
				{ "fylgja_p_handsfull", "Your inventory is full, the fylgja can't borrow your hands" },
				{ "fylgja_p_rerecord", "Old step, record the route again" },
				{ "fylgja_p_error", "A step failed, see the log" },
				{ "fylgja_d_harvest", "Harvest field" },
				{ "fylgja_p_noseeds", "No seeds left to replant" }
			});
			text = "German";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "piece_fylgjastone", "Fylgja-Stein" },
				{ "piece_fylgjastone_desc", "Bindet deine Fylgja, den Geist, der dir folgt. Zeig ihr einen Weg, und sie wiederholt deine Arbeit, solange Honig geopfert wird." },
				{ "fylgja_state_empty", "Kein Weg gebunden" },
				{ "fylgja_state_idle", "Die Fylgja ruht" },
				{ "fylgja_state_running", "Die Fylgja wandelt" },
				{ "fylgja_state_recording", "Die Fylgja beobachtet dich" },
				{ "fylgja_steps", "Aufgaben" },
				{ "fylgja_offering", "Opfergabe" },
				{ "fylgja_start", "Fylgja erwecken" },
				{ "fylgja_stop", "Fylgja entlassen" },
				{ "fylgja_record", "Neuen Weg zeigen" },
				{ "fylgja_finish", "Weg abschließen" },
				{ "fylgja_cancel", "Weg verwerfen" },
				{ "fylgja_offer_hint", "Opfere Honig, um sie zu erhalten" },
				{ "fylgja_recording_started", "Deine Fylgja schaut zu. Erledige die Arbeit und kehre zum Stein zurück." },
				{ "fylgja_recorded", "Weg gebunden. Aufgaben" },
				{ "fylgja_noactions", "Nichts getan. Bewege Gegenstände zwischen Truhen, Schmelzöfen oder vom Boden." },
				{ "fylgja_cancelled", "Der Weg verblasst" },
				{ "fylgja_toofar", "Zu weit vom Stein. Die Fylgja folgt dir hier vielleicht nicht." },
				{ "fylgja_toolong", "Der Weg ist zu lang und verblasst" },
				{ "fylgja_busy", "Deine Fylgja beobachtet dich bereits an einem anderen Stein" },
				{ "fylgja_noprogram", "Zeig der Fylgja zuerst einen Weg" },
				{ "fylgja_needoffer", "Die Fylgja braucht eine Honiggabe" },
				{ "fylgja_offerfull", "Der Stein fasst keinen weiteren Honig" },
				{ "fylgja_offered", "Die Gabe wird angenommen" },
				{ "fylgja_awakened", "Die Fylgja erhebt sich" },
				{ "fylgja_released", "Die Fylgja kehrt zum Stein zurück" },
				{ "fylgja_allmode", "Alles-Modus" },
				{ "fylgja_on", "an" },
				{ "fylgja_off", "aus" },
				{ "fylgja_allmode_on", "Alles-Modus an: Die Fylgja nimmt alles und füllt bis voll" },
				{ "fylgja_allmode_off", "Alles-Modus aus: Die Fylgja bewegt genaue Mengen" },
				{ "fylgja_all", "(alles)" },
				{ "fylgja_next", "Als Nächstes" },
				{ "fylgja_resting", "Ruht am Stein, bis es Arbeit gibt" },
				{ "fylgja_d_take", "Nehmen" },
				{ "fylgja_d_put", "Einlagern" },
				{ "fylgja_d_interact", "Benutzen" },
				{ "fylgja_d_gather", "Aufheben" },
				{ "fylgja_d_empty", "Schmelze leeren" },
				{ "fylgja_p_notfound", "Ziel nicht gefunden oder nicht geladen" },
				{ "fylgja_p_inuse", "Eine Truhe ist offen, wartet" },
				{ "fylgja_p_full", "Ziel ist voll" },
				{ "fylgja_p_carryfull", "Die Fylgja trägt, so viel sie kann" },
				{ "fylgja_p_handsfull", "Dein Inventar ist voll, die Fylgja kann deine Hände nicht leihen" },
				{ "fylgja_p_rerecord", "Alter Schritt, Weg neu aufzeichnen" },
				{ "fylgja_p_error", "Ein Schritt ist fehlgeschlagen, siehe Log" },
				{ "fylgja_d_harvest", "Feld ernten" },
				{ "fylgja_p_noseeds", "Kein Saatgut zum Nachpflanzen" }
			});
		}
	}
	[BepInPlugin("fylgja.valheim", "Fylgja", "0.3.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class FylgjaPlugin : BaseUnityPlugin
	{
		public const string ModGuid = "fylgja.valheim";

		public const string ModName = "Fylgja";

		public const string ModVersion = "0.3.0";

		internal static FylgjaConfig Cfg;

		internal static ManualLogSource Log;

		private Harmony m_harmony;

		private void Awake()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new FylgjaConfig(((BaseUnityPlugin)this).Config);
			Localizations.Register();
			PrefabManager.OnVanillaPrefabsAvailable += RegisterContent;
			m_harmony = new Harmony("fylgja.valheim");
			m_harmony.PatchAll(typeof(FylgjaPlugin).Assembly);
			Log.LogInfo((object)"Fylgja 0.3.0 loaded");
		}

		private void OnDestroy()
		{
			Harmony harmony = m_harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
			Recorder.Tick();
		}

		private void RegisterContent()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= RegisterContent;
			try
			{
				GhostVisual.BuildTemplate();
				RegisterStone();
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to register Fylgja content: {arg}");
			}
		}

		private static void RegisterStone()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("FylgjaStone", "guard_stone");
			if (!Object.op_Implicit((Object)(object)val))
			{
				Log.LogError((object)"Vanilla prefab 'guard_stone' not found, Fylgja stone not registered");
				return;
			}
			object obj = Refl.Get(val.GetComponent("PrivateArea"), "m_enabledEffect");
			GameObject val2 = (GameObject)((obj is GameObject) ? obj : null);
			if (val2 != null && Object.op_Implicit((Object)(object)val2))
			{
				((Object)val2).name = "FylgjaGlow";
				val2.SetActive(false);
			}
			Strip.ByName(val, "PrivateArea", "CircleProjector");
			val.AddComponent<FylgjaStone>();
			PieceConfig val3 = new PieceConfig
			{
				Name = "$piece_fylgjastone",
				Description = "$piece_fylgjastone_desc",
				PieceTable = "Hammer",
				Category = "Misc",
				CraftingStation = "piece_workbench",
				Requirements = ((IEnumerable<KeyValuePair<string, int>>)CostParser.Parse(Cfg.StoneCost.Value)).Select((Func<KeyValuePair<string, int>, RequirementConfig>)((KeyValuePair<string, int> c) => new RequirementConfig(c.Key, c.Value, 0, true))).ToArray()
			};
			PieceManager.Instance.AddPiece(new CustomPiece(val, false, val3));
			Log.LogInfo((object)"Fylgja stone registered on the hammer (Misc tab)");
		}
	}
	internal class FylgjaConfig
	{
		public readonly ConfigEntry<string> StoneCost;

		public readonly ConfigEntry<string> OfferingItem;

		public readonly ConfigEntry<float> SecondsPerOffering;

		public readonly ConfigEntry<float> MaxOfferingSeconds;

		public readonly ConfigEntry<float> Speed;

		public readonly ConfigEntry<float> ActionSeconds;

		public readonly ConfigEntry<float> WaitTimeout;

		public readonly ConfigEntry<int> CarryCapacity;

		public readonly ConfigEntry<float> MaxRange;

		public readonly ConfigEntry<float> WaypointSpacing;

		public readonly ConfigEntry<float> GatherRadius;

		public readonly ConfigEntry<int> MaxSteps;

		public readonly ConfigEntry<KeyboardShortcut> AllModeKey;

		public readonly ConfigEntry<float> RouteDisplaySeconds;

		public readonly ConfigEntry<float> RestProbeSeconds;

		public readonly ConfigEntry<float> RestMaxSeconds;

		public readonly ConfigEntry<bool> Replant;

		public readonly ConfigEntry<float> FieldMaxRadius;

		public FylgjaConfig(ConfigFile f)
		{
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			StoneCost = f.Bind<string>("Stone", "Cost", "Stone:20,SurtlingCore:2,Honey:5", "Prefab:Amount pairs.");
			OfferingItem = f.Bind<string>("Offering", "Item", "Honey", "Item prefab the stone accepts as an offering.");
			SecondsPerOffering = f.Bind<float>("Offering", "SecondsPerOffering", 300f, "Real seconds of binding per offered item.");
			MaxOfferingSeconds = f.Bind<float>("Offering", "MaxSeconds", 3600f, "Upper limit of stored binding time.");
			Speed = f.Bind<float>("Fylgja", "Speed", 3.5f, "Movement speed in m/s.");
			ActionSeconds = f.Bind<float>("Fylgja", "ActionSeconds", 0.8f, "Pause at each action.");
			WaitTimeout = f.Bind<float>("Fylgja", "WaitTimeout", 20f, "Seconds to wait on a blocked action (full chest, busy smelter) before skipping it.");
			CarryCapacity = f.Bind<int>("Fylgja", "CarryCapacity", 250, "Total item units the fylgja can carry.");
			MaxRange = f.Bind<float>("Recording", "MaxRange", 50f, "Warn when recording this far from the stone. The fylgja only works where players keep the area loaded.");
			WaypointSpacing = f.Bind<float>("Recording", "WaypointSpacing", 1.5f, "Distance between recorded path points.");
			GatherRadius = f.Bind<float>("Recording", "GatherRadius", 4f, "Radius for picking up items at a recorded pickup spot.");
			MaxSteps = f.Bind<int>("Recording", "MaxSteps", 1500, "Recording stops beyond this many steps.");
			AllModeKey = f.Bind<KeyboardShortcut>("Recording", "AllModeKey", new KeyboardShortcut((KeyCode)122, Array.Empty<KeyCode>()), "While recording, toggles \"all\" mode: steps take everything or fill the target until full instead of a fixed amount.");
			RestProbeSeconds = f.Bind<float>("Fylgja", "RestProbeSeconds", 5f, "While resting, how often the fylgja checks its source chests for new items.");
			RestMaxSeconds = f.Bind<float>("Fylgja", "RestMaxSeconds", 300f, "After a round without work the fylgja rests at the stone. It gets up after this long even if no chest changed, for beehive, crop or pickup routes.");
			Replant = f.Bind<bool>("Harvest", "Replant", true, "Plant a new seedling on every spot the fylgja harvested, if it carries the seed.");
			FieldMaxRadius = f.Bind<float>("Harvest", "FieldMaxRadius", 15f, "Largest field one harvest step may cover. Picks farther apart become separate steps.");
			RouteDisplaySeconds = f.Bind<float>("Display", "RouteSeconds", 8f, "How long the route stays visible after looking at the stone.");
		}
	}
	internal enum StepKind
	{
		Move,
		Take,
		Put,
		Ore,
		Fuel,
		Gather,
		Empty,
		Use,
		Interact,
		Harvest
	}
	internal sealed class Step
	{
		public StepKind Kind;

		public Vector3 Stand;

		public Vector3 Target;

		public string Prefab = "";

		public int Amount;

		internal bool All => Amount < 0;

		internal int Remaining(int progress)
		{
			if (!All)
			{
				return Amount - progress;
			}
			return int.MaxValue;
		}
	}
	internal static class ProgramCodec
	{
		private const string Codes = "MTPOFGEUIH";

		private static readonly CultureInfo Inv = CultureInfo.InvariantCulture;

		internal static string Encode(List<Step> steps)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (Step step in steps)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append("MTPOFGEUIH"[(int)step.Kind]).Append('|').Append(F(step.Stand.x))
					.Append('|')
					.Append(F(step.Stand.y))
					.Append('|')
					.Append(F(step.Stand.z))
					.Append('|')
					.Append(F(step.Target.x))
					.Append('|')
					.Append(F(step.Target.y))
					.Append('|')
					.Append(F(step.Target.z))
					.Append('|')
					.Append(step.Prefab ?? "")
					.Append('|')
					.Append(step.Amount.ToString(Inv));
			}
			return stringBuilder.ToString();
		}

		internal static List<Step> Decode(string text)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			List<Step> list = new List<Step>();
			if (string.IsNullOrEmpty(text))
			{
				return list;
			}
			string[] array = text.Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '|' });
				if (array2.Length == 9 && array2[0].Length == 1)
				{
					int num = "MTPOFGEUIH".IndexOf(array2[0][0]);
					if (num >= 0 && TryF(array2[1], out var v) && TryF(array2[2], out var v2) && TryF(array2[3], out var v3) && TryF(array2[4], out var v4) && TryF(array2[5], out var v5) && TryF(array2[6], out var v6))
					{
						int.TryParse(array2[8], NumberStyles.Integer, Inv, out var result);
						list.Add(new Step
						{
							Kind = (StepKind)num,
							Stand = new Vector3(v, v2, v3),
							Target = new Vector3(v4, v5, v6),
							Prefab = array2[7],
							Amount = result
						});
					}
				}
			}
			return list;
		}

		internal static int ActionCount(List<Step> steps)
		{
			return steps.Count((Step s) => s.Kind != StepKind.Move);
		}

		internal static Dictionary<string, int> DecodeCarry(string text)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (KeyValuePair<string, int> item in CostParser.Parse(text))
			{
				dictionary[item.Key] = (dictionary.TryGetValue(item.Key, out var value) ? value : 0) + item.Value;
			}
			return dictionary;
		}

		internal static string EncodeCarry(Dictionary<string, int> carry)
		{
			return string.Join(",", (from kv in carry
				where kv.Value > 0
				select kv.Key + ":" + kv.Value.ToString(Inv)).ToArray());
		}

		private static string F(float v)
		{
			return v.ToString("0.###", Inv);
		}

		private static bool TryF(string s, out float v)
		{
			return float.TryParse(s, NumberStyles.Float, Inv, out v);
		}
	}
	internal static class Recorder
	{
		private static FylgjaStone s_stone;

		private static List<Step> s_steps;

		private static Vector3 s_lastPoint;

		private static Container s_container;

		private static Dictionary<string, int> s_snapshot;

		private static bool s_warnedRange;

		private static FieldInfo s_containerField;

		private static bool s_allMode;

		internal static bool Recording
		{
			get
			{
				if (s_steps != null)
				{
					return Object.op_Implicit((Object)(object)s_stone);
				}
				return false;
			}
		}

		internal static bool AllMode
		{
			get
			{
				if (Recording)
				{
					return s_allMode;
				}
				return false;
			}
		}

		internal static List<Step> CurrentSteps => s_steps;

		internal static bool IsRecordingFor(FylgjaStone stone)
		{
			if (Recording)
			{
				return (Object)(object)s_stone == (Object)(object)stone;
			}
			return false;
		}

		internal static void Begin(FylgjaStone stone, Player player)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			s_stone = stone;
			s_steps = new List<Step>();
			s_container = null;
			s_snapshot = null;
			s_warnedRange = false;
			s_allMode = false;
			AddMove(((Component)player).transform.position);
			FylgjaStone.Notify(player, "$fylgja_recording_started");
		}

		internal static void Finish()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (Recording && Object.op_Implicit((Object)(object)localPlayer))
			{
				FlushContainer();
				AddMove(((Component)localPlayer).transform.position);
				AddMove(s_steps[0].Stand);
				int num = ProgramCodec.ActionCount(s_steps);
				if (num == 0)
				{
					Cancel("$fylgja_noactions");
					return;
				}
				s_stone.SendProgram(ProgramCodec.Encode(s_steps));
				FylgjaStone.Notify(localPlayer, Localization.instance.Localize("$fylgja_recorded: ") + num);
				Clear();
			}
		}

		internal static void Cancel(string reason)
		{
			FylgjaStone.Notify(Player.m_localPlayer, reason);
			Clear();
		}

		private static void Clear()
		{
			s_stone = null;
			s_steps = null;
			s_container = null;
			s_snapshot = null;
		}

		internal static void Tick()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if (s_steps == null)
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)s_stone))
			{
				Cancel("$fylgja_cancelled");
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead())
			{
				Cancel("$fylgja_cancelled");
				return;
			}
			KeyboardShortcut value = FylgjaPlugin.Cfg.AllModeKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && TextInputFree())
			{
				s_allMode = !s_allMode;
				FylgjaStone.Notify(localPlayer, s_allMode ? "$fylgja_allmode_on" : "$fylgja_allmode_off");
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			if (Vector3.Distance(position, s_lastPoint) >= FylgjaPlugin.Cfg.WaypointSpacing.Value)
			{
				AddMove(position);
			}
			if (!s_warnedRange && Vector3.Distance(position, ((Component)s_stone).transform.position) > FylgjaPlugin.Cfg.MaxRange.Value)
			{
				s_warnedRange = true;
				FylgjaStone.Notify(localPlayer, "$fylgja_toofar");
			}
			TrackContainer(localPlayer);
			if (s_steps != null && s_steps.Count > FylgjaPlugin.Cfg.MaxSteps.Value)
			{
				Cancel("$fylgja_toolong");
			}
		}

		private static void TrackContainer(Player player)
		{
			if (s_containerField == null)
			{
				s_containerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer");
			}
			if (s_containerField == null)
			{
				Refl.WarnOnce("InventoryGui.m_currentContainer (container recording)");
				return;
			}
			Container val = (Container)(Object.op_Implicit((Object)(object)InventoryGui.instance) ? /*isinst with value type is only supported in some contexts*/: null);
			if (val != s_container)
			{
				FlushContainer();
				if (Object.op_Implicit((Object)(object)val))
				{
					s_container = val;
					s_snapshot = Items.Count(((Humanoid)player).GetInventory());
				}
			}
		}

		private static void FlushContainer()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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)
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)s_container) && s_snapshot != null && Object.op_Implicit((Object)(object)localPlayer))
			{
				Dictionary<string, int> source = Items.Diff(s_snapshot, Items.Count(((Humanoid)localPlayer).GetInventory()));
				Vector3 position = ((Component)localPlayer).transform.position;
				Vector3 position2 = ((Component)s_container).transform.position;
				foreach (KeyValuePair<string, int> item in source.Where((KeyValuePair<string, int> d) => d.Value < 0))
				{
					AddAction(StepKind.Put, position, position2, item.Key, -item.Value);
				}
				foreach (KeyValuePair<string, int> item2 in source.Where((KeyValuePair<string, int> d) => d.Value > 0))
				{
					AddAction(StepKind.Take, position, position2, item2.Key, item2.Value);
				}
			}
			s_container = null;
			s_snapshot = null;
		}

		internal static void RecordSmelter(Smelter smelter, bool fuel, Dictionary<string, int> diff)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Recording || !Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)smelter))
			{
				return;
			}
			foreach (KeyValuePair<string, int> item in diff.Where((KeyValuePair<string, int> d) => d.Value < 0))
			{
				AddAction(fuel ? StepKind.Fuel : StepKind.Ore, ((Component)localPlayer).transform.position, ((Component)smelter).transform.position, item.Key, -item.Value);
			}
		}

		internal static void RecordEmpty(Smelter smelter)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (Recording && Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)smelter))
			{
				AddAction(StepKind.Empty, ((Component)localPlayer).transform.position, ((Component)smelter).transform.position, "", 0);
			}
		}

		internal static void RecordHarvest(Player player, GameObject crop)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (!Recording || !Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)crop))
			{
				return;
			}
			Vector3 position = crop.transform.position;
			string text = Harvest.PrefabName(crop);
			float value = FylgjaPlugin.Cfg.FieldMaxRadius.Value;
			Step step = LastAction();
			if (step != null && step.Kind == StepKind.Harvest)
			{
				float num = (float)step.Amount / 10f;
				Vector3 val = step.Target;
				float num2 = Vector3.Distance(val, position);
				if (num2 > num && num2 > 0.01f)
				{
					float num3 = (num + num2) / 2f;
					val += (position - val) / num2 * (num3 - num);
					num = num3;
				}
				if (num <= value)
				{
					step.Target = val;
					step.Amount = Mathf.CeilToInt(num * 10f);
					if (!step.Prefab.Split(new char[1] { ';' }).Contains(text))
					{
						step.Prefab = step.Prefab + ";" + text;
					}
					return;
				}
			}
			AddAction(StepKind.Harvest, ((Component)player).transform.position, position, text, 15);
		}

		private static Step LastAction()
		{
			for (int num = s_steps.Count - 1; num >= 0; num--)
			{
				if (s_steps[num].Kind != StepKind.Move)
				{
					return s_steps[num];
				}
			}
			return null;
		}

		internal static void RecordPickup(Vector3 itemPos, string prefab)
		{
			//IL_00c6: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Recording || !Object.op_Implicit((Object)(object)localPlayer) || string.IsNullOrEmpty(prefab))
			{
				return;
			}
			Step step = LastAction();
			if (step != null && step.Kind == StepKind.Harvest && Vector3.Distance(step.Target, itemPos) <= Harvest.Radius(step) + 2f)
			{
				return;
			}
			Step step2 = s_steps[s_steps.Count - 1];
			if (step2.Kind == StepKind.Gather && Vector3.Distance(step2.Target, itemPos) < FylgjaPlugin.Cfg.GatherRadius.Value)
			{
				if (!step2.Prefab.Split(new char[1] { ';' }).Contains(prefab))
				{
					step2.Prefab = step2.Prefab + ";" + prefab;
				}
			}
			else
			{
				AddAction(StepKind.Gather, ((Component)localPlayer).transform.position, itemPos, prefab, 0);
			}
		}

		private static bool TextInputFree()
		{
			if (Object.op_Implicit((Object)(object)Chat.instance) && Chat.instance.HasFocus())
			{
				return false;
			}
			if (Console.IsVisible() || Menu.IsVisible() || TextInput.IsVisible())
			{
				return false;
			}
			return true;
		}

		private static void AddMove(Vector3 pos)
		{
			//IL_0012: 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_0019: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			s_steps.Add(new Step
			{
				Kind = StepKind.Move,
				Stand = pos,
				Target = pos
			});
			s_lastPoint = pos;
		}

		internal static void AddAction(StepKind kind, Vector3 stand, Vector3 target, string prefab, int amount)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (s_allMode && (kind == StepKind.Take || kind == StepKind.Put || kind == StepKind.Use))
			{
				amount = -1;
			}
			Step step = s_steps[s_steps.Count - 1];
			if (step.Kind == kind && step.Prefab == prefab && Vector3.Distance(step.Target, target) < 0.5f)
			{
				step.Amount = ((step.All || amount < 0) ? (-1) : (step.Amount + amount));
				return;
			}
			s_steps.Add(new Step
			{
				Kind = kind,
				Stand = stand,
				Target = target,
				Prefab = prefab,
				Amount = amount
			});
			s_lastPoint = stand;
		}
	}
	[HarmonyPatch]
	internal static class PickupPatch
	{
		internal sealed class Info
		{
			public Vector3 Position;

			public string Prefab;
		}

		private static MethodBase Target => Refl.FindMethod(typeof(Humanoid), "Pickup");

		private static bool Prepare()
		{
			if (Target == null)
			{
				Refl.WarnOnce("Humanoid.Pickup (pickup recording)");
			}
			return Target != null;
		}

		private static MethodBase TargetMethod()
		{
			return Target;
		}

		private static void Prefix(Humanoid __instance, GameObject __0, out Info __state)
		{
			//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)
			__state = null;
			if (Recorder.Recording && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)__0))
			{
				ItemDrop component = __0.GetComponent<ItemDrop>();
				if (Object.op_Implicit((Object)(object)component) && component.m_itemData != null && component.m_itemData.m_shared.m_maxStackSize > 1)
				{
					__state = new Info
					{
						Position = __0.transform.position,
						Prefab = Items.PrefabName(component)
					};
				}
			}
		}

		private static void Postfix(bool __result, Info __state)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (__result && __state != null)
			{
				Recorder.RecordPickup(__state.Position, __state.Prefab);
			}
		}
	}
	[HarmonyPatch]
	internal static class StoneDropPatch
	{
		private static MethodBase Target => Refl.FindMethod(typeof(Piece), "DropResources");

		private static bool Prepare()
		{
			if (Target == null)
			{
				Refl.WarnOnce("Piece.DropResources (carry refund)");
			}
			return Target != null;
		}

		private static MethodBase TargetMethod()
		{
			return Target;
		}

		private static void Postfix(Piece __instance)
		{
			FylgjaStone component = ((Component)__instance).GetComponent<FylgjaStone>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.DropCarry();
			}
		}
	}
	internal sealed class RouteView
	{
		private const int MaxMarkers = 120;

		private static Material s_material;

		private static bool s_materialTried;

		private static readonly Dictionary<StepKind, Material> s_markerMaterials = new Dictionary<StepKind, Material>();

		private GameObject m_root;

		private LineRenderer m_line;

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

		private string m_builtFor;

		internal void Show(List<Step> steps, string key)
		{
			if (steps == null || steps.Count < 2)
			{
				Hide();
				return;
			}
			if (!Object.op_Implicit((Object)(object)m_root) || key != m_builtFor)
			{
				if (!Build(steps))
				{
					return;
				}
				m_builtFor = key;
			}
			if (!m_root.activeSelf)
			{
				m_root.SetActive(true);
			}
		}

		internal void Hide()
		{
			if (Object.op_Implicit((Object)(object)m_root) && m_root.activeSelf)
			{
				m_root.SetActive(false);
			}
		}

		internal void Destroy()
		{
			if (Object.op_Implicit((Object)(object)m_root))
			{
				Object.Destroy((Object)(object)m_root);
			}
			m_root = null;
		}

		private bool Build(List<Step> steps)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_008f: 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_01e6: 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_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			Material material = GetMaterial();
			if (!Object.op_Implicit((Object)(object)material))
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)m_root))
			{
				m_root = new GameObject("FylgjaRoute");
				m_line = m_root.AddComponent<LineRenderer>();
				m_line.useWorldSpace = true;
				((Renderer)m_line).material = material;
				m_line.widthMultiplier = 0.06f;
				m_line.numCornerVertices = 2;
				m_line.startColor = new Color(0.6f, 0.85f, 1f, 0.7f);
				m_line.endColor = new Color(0.6f, 0.85f, 1f, 0.7f);
				((Renderer)m_line).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)m_line).receiveShadows = false;
			}
			Vector3[] array = steps.Select((Step s) => s.Stand + Vector3.up * 0.15f).ToArray();
			m_line.positionCount = array.Length;
			m_line.SetPositions(array);
			foreach (GameObject marker in m_markers)
			{
				if (Object.op_Implicit((Object)(object)marker))
				{
					Object.Destroy((Object)(object)marker);
				}
			}
			m_markers.Clear();
			foreach (Step step in steps)
			{
				if (step.Kind != StepKind.Move)
				{
					if (m_markers.Count >= 120)
					{
						break;
					}
					GameObject val = GameObject.CreatePrimitive((PrimitiveType)0);
					Collider component = val.GetComponent<Collider>();
					if (Object.op_Implicit((Object)(object)component))
					{
						Object.Destroy((Object)(object)component);
					}
					((Object)val).name = "FylgjaRouteMarker";
					val.transform.SetParent(m_root.transform, false);
					val.transform.position = step.Target + Vector3.up * 0.4f;
					val.transform.localScale = Vector3.one * 0.25f;
					Renderer component2 = val.GetComponent<Renderer>();
					if (Object.op_Implicit((Object)(object)component2))
					{
						component2.sharedMaterial = MarkerMaterial(step.Kind, material);
						component2.shadowCastingMode = (ShadowCastingMode)0;
					}
					m_markers.Add(val);
				}
			}
			return true;
		}

		private static Material GetMaterial()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			if (Object.op_Implicit((Object)(object)s_material) || s_materialTried)
			{
				return s_material;
			}
			s_materialTried = true;
			string[] array = new string[3] { "Sprites/Default", "Unlit/Color", "Legacy Shaders/Particles/Alpha Blended" };
			for (int i = 0; i < array.Length; i++)
			{
				Shader val = Shader.Find(array[i]);
				if (Object.op_Implicit((Object)(object)val))
				{
					s_material = new Material(val);
					return s_material;
				}
			}
			FylgjaPlugin.Log.LogWarning((object)"No shader found for the route display, it stays hidden");
			return null;
		}

		private static Material MarkerMaterial(StepKind kind, Material baseMaterial)
		{
			//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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			if (s_markerMaterials.TryGetValue(kind, out var value) && Object.op_Implicit((Object)(object)value))
			{
				return value;
			}
			value = new Material(baseMaterial)
			{
				color = ColorFor(kind)
			};
			s_markerMaterials[kind] = value;
			return value;
		}

		private static Color ColorFor(StepKind kind)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_0079: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(kind switch
			{
				StepKind.Take => new Color(0.4f, 0.9f, 0.4f, 0.9f), 
				StepKind.Put => new Color(1f, 0.6f, 0.2f, 0.9f), 
				StepKind.Use => new Color(1f, 0.9f, 0.3f, 0.9f), 
				StepKind.Interact => new Color(0.75f, 0.5f, 1f, 0.9f), 
				StepKind.Gather => new Color(0.4f, 0.9f, 1f, 0.9f), 
				StepKind.Harvest => new Color(0.7f, 1f, 0.3f, 0.9f), 
				_ => new Color(0.8f, 0.8f, 0.8f, 0.9f), 
			});
		}
	}
	internal static class Refl
	{
		private const BindingFlags AllDeclared = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

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

		internal static MethodInfo FindMethod(Type type, string name)
		{
			Type type2 = type;
			while (type2 != null)
			{
				MethodInfo[] methods = type2.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name == name)
					{
						return methodInfo;
					}
				}
				type2 = type2.BaseType;
			}
			return null;
		}

		internal static object Get(object obj, string field)
		{
			if (obj == null)
			{
				return null;
			}
			FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), field);
			if (fieldInfo == null)
			{
				WarnOnce(obj.GetType().Name + "." + field);
				return null;
			}
			return fieldInfo.GetValue(fieldInfo.IsStatic ? null : obj);
		}

		internal static object Call(object obj, string method, params object[] args)
		{
			if (obj == null)
			{
				return null;
			}
			MethodInfo methodInfo = FindMethod(obj.GetType(), method);
			if (methodInfo == null)
			{
				WarnOnce(obj.GetType().Name + "." + method + "()");
				return null;
			}
			try
			{
				return methodInfo.Invoke(methodInfo.IsStatic ? null : obj, args);
			}
			catch (Exception ex)
			{
				WarnOnce(obj.GetType().Name + "." + method + "() failed: " + ex.Message);
				return null;
			}
		}

		internal static void WarnOnce(string what)
		{
			if (s_warned.Add(what))
			{
				FylgjaPlugin.Log.LogWarning((object)(what + " not available in this game version"));
			}
		}
	}
	internal static class Items
	{
		internal static ItemDrop Prefab(string prefabName)
		{
			if (!Object.op_Implicit((Object)(object)ObjectDB.instance) || string.IsNullOrEmpty(prefabName))
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
			if (!Object.op_Implicit((Object)(object)itemPrefab))
			{
				return null;
			}
			return itemPrefab.GetComponent<ItemDrop>();
		}

		internal static string SharedName(string prefabName)
		{
			ItemDrop val = Prefab(prefabName);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return prefabName;
			}
			return val.m_itemData.m_shared.m_name;
		}

		internal static string PrefabName(ItemData item)
		{
			if (item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				return null;
			}
			return ((Object)item.m_dropPrefab).name;
		}

		internal static string PrefabName(ItemDrop drop)
		{
			if (!Object.op_Implicit((Object)(object)drop))
			{
				return null;
			}
			return PrefabName(drop.m_itemData) ?? ((Object)((Component)drop).gameObject).name.Replace("(Clone)", "").Trim();
		}

		internal static bool IsStackable(ItemData item)
		{
			if (item != null && Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				return item.m_shared.m_maxStackSize > 1;
			}
			return false;
		}

		internal static Dictionary<string, int> Count(Inventory inv)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			if (inv == null)
			{
				return dictionary;
			}
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if (IsStackable(allItem))
				{
					string key = PrefabName(allItem);
					dictionary[key] = (dictionary.TryGetValue(key, out var value) ? value : 0) + allItem.m_stack;
				}
			}
			return dictionary;
		}

		internal static Dictionary<string, int> Diff(Dictionary<string, int> before, Dictionary<string, int> after)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (string item in before.Keys.Union(after.Keys))
			{
				int value;
				int value2;
				int num = (after.TryGetValue(item, out value) ? value : 0) - (before.TryGetValue(item, out value2) ? value2 : 0);
				if (num != 0)
				{
					dictionary[item] = num;
				}
			}
			return dictionary;
		}

		internal static int AddTo(Inventory inv, string prefabName, int amount)
		{
			ItemDrop val = Prefab(prefabName);
			if (!Object.op_Implicit((Object)(object)val) || inv == null)
			{
				return 0;
			}
			int num = Mathf.Max(1, val.m_itemData.m_shared.m_maxStackSize);
			int i;
			int num2;
			for (i = 0; i < amount; i += num2)
			{
				num2 = Mathf.Min(num, amount - i);
				ItemData val2 = val.m_itemData.Clone();
				val2.m_dropPrefab = ((Component)val).gameObject;
				val2.m_stack = num2;
				while (num2 > 0 && !inv.CanAddItem(val2, num2))
				{
					num2 = (val2.m_stack = num2 - 1);
				}
				if (num2 <= 0 || !inv.AddItem(val2))
				{
					break;
				}
			}
			return i;
		}

		internal static void Spawn(string prefabName, int amount, Vector3 origin)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			ItemDrop val = Prefab(prefabName);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			int num = Mathf.Max(1, val.m_itemData.m_shared.m_maxStackSize);
			while (amount > 0)
			{
				int num2 = Mathf.Min(num, amount);
				amount -= num2;
				Vector3 val2 = origin + Vector3.up * 0.5f + Random.insideUnitSphere * 0.4f;
				ItemDrop component = Object.Instantiate<GameObject>(((Component)val).gameObject, val2, Quaternion.identity).GetComponent<ItemDrop>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.SetStack(num2);
				}
			}
		}
	}
	internal static class CostParser
	{
		internal static List<KeyValuePair<string, int>> Parse(string text)
		{
			List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>();
			if (string.IsNullOrWhiteSpace(text))
			{
				return list;
			}
			string[] array = text.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ':' });
				if (array2.Length == 2 && int.TryParse(array2[1].Trim(), out var result) && result > 0)
				{
					list.Add(new KeyValuePair<string, int>(array2[0].Trim(), result));
				}
			}
			return list;
		}
	}
	internal static class Strip
	{
		internal static void ByName(GameObject go, params string[] typeNames)
		{
			HashSet<string> hashSet = new HashSet<string>(typeNames);
			MonoBehaviour[] componentsInChildren = go.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)val) && hashSet.Contains(((object)val).GetType().Name))
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
		}

		internal static void ToVisualOnly(GameObject go)
		{
			for (int i = 0; i < 6; i++)
			{
				List<MonoBehaviour> list = (from c in go.GetComponentsInChildren<MonoBehaviour>(true)
					where Object.op_Implicit((Object)(object)c) && ((object)c).GetType().Assembly.GetName().Name.StartsWith("assembly_")
					select c).ToList();
				if (list.Count == 0)
				{
					break;
				}
				foreach (MonoBehaviour item in list)
				{
					Object.DestroyImmediate((Object)(object)item);
				}
			}
			Collider[] componentsInChildren = go.GetComponentsInChildren<Collider>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[num]);
			}
			Rigidbody[] componentsInChildren2 = go.GetComponentsInChildren<Rigidbody>(true);
			for (int num = 0; num < componentsInChildren2.Length; num++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[num]);
			}
		}
	}
	internal static class GhostVisual
	{
		private static GameObject s_holder;

		private static GameObject s_template;

		internal static readonly Color Spirit = new Color(0.6f, 0.8f, 1f);

		internal static void BuildTemplate()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			s_holder = new GameObject("FylgjaTemplateHolder");
			s_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)s_holder);
			GameObject prefab = PrefabManager.Instance.GetPrefab("Ghost");
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				FylgjaPlugin.Log.LogWarning((object)"Vanilla prefab 'Ghost' not found, the fylgja will appear as a wisp");
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, s_holder.transform, false);
			((Object)val).name = "FylgjaGhostTemplate";
			Strip.ToVisualOnly(val);
			Animator[] componentsInChildren = val.GetComponentsInChildren<Animator>(true);
			foreach (Animator obj in componentsInChildren)
			{
				obj.applyRootMotion = false;
				obj.cullingMode = (AnimatorCullingMode)0;
			}
			s_template = val;
		}

		internal static GameObject Create(Vector3 position)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid I