Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Fylgja v0.3.0
Fylgja.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
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