using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Lamplighter.Config; using Lamplighter.Creatures; using Lamplighter.Pieces; using Lamplighter.Systems; using Lamplighter.Visuals; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Greguru")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Greguru 2026")] [assembly: AssemblyDescription("\r\n A Valheim mod that summons a fire spirit to tend nearby fires and lights.\r\n ")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Lamplighter")] [assembly: AssemblyTitle("Lamplighter")] [assembly: AssemblyVersion("1.0.0.0")] namespace Lamplighter { [BepInPlugin("com.g.lamplighter", "Lamplighter", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.g.lamplighter"; public const string PluginName = "Lamplighter"; public const string PluginVersion = "1.0.0"; private void Awake() { ModConfig.Bind(((BaseUnityPlugin)this).Config); LamplighterPiece.Register(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Lamplighter 1.0.0 loaded. The fires of Valheim can be tended."); } } } namespace Lamplighter.Visuals { internal sealed class RangeIndicator : MonoBehaviour { private const int Segments = 96; private const float Width = 0.12f; private const float HeightOffset = 0.08f; private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); private LineRenderer _line; private float _lastRadius = -1f; private void Awake() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown _line = ((Component)this).GetComponent(); if ((Object)(object)_line == (Object)null) { _line = ((Component)this).gameObject.AddComponent(); } _line.useWorldSpace = false; _line.loop = true; _line.positionCount = 96; _line.startWidth = 0.12f; _line.endWidth = 0.12f; ((Renderer)_line).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)_line).receiveShadows = false; Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val != (Object)null) { ((Renderer)_line).material = new Material(val); } ((Renderer)_line).enabled = false; RebuildCircle(); } private void Update() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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 (!ModConfig.ShowRangeWhilePlacing.Value) { ((Renderer)_line).enabled = false; return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || PlacementGhostField == null) { ((Renderer)_line).enabled = false; return; } object? value = PlacementGhostField.GetValue(localPlayer); if (!((Object)((value is GameObject) ? value : null) == (Object)(object)((Component)this).gameObject)) { ((Renderer)_line).enabled = false; return; } ((Renderer)_line).enabled = true; if (!Mathf.Approximately(ModConfig.WorkRadius.Value, _lastRadius)) { RebuildCircle(); } Color value2 = ModConfig.WispColor.Value; value2.a = 0.85f; _line.startColor = value2; _line.endColor = value2; if ((Object)(object)((Renderer)_line).material != (Object)null) { ((Renderer)_line).material.color = value2; } } private void RebuildCircle() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) float num = (_lastRadius = ModConfig.WorkRadius.Value); for (int i = 0; i < 96; i++) { float num2 = (float)i * (float)Math.PI * 2f / 96f; _line.SetPosition(i, new Vector3(Mathf.Cos(num2) * num, 0.08f, Mathf.Sin(num2) * num)); } } private void OnDestroy() { if ((Object)(object)_line != (Object)null && (Object)(object)((Renderer)_line).material != (Object)null) { Object.Destroy((Object)(object)((Renderer)_line).material); } } } internal sealed class ShrineVisuals : MonoBehaviour { private readonly List _shrineMaterials = new List(); private readonly List _oozeMaterials = new List(); private bool _initialized; private bool _subscribed; private void Awake() { Initialize(); } private void OnEnable() { Initialize(); ApplyColors(); } private void Initialize() { if (!_initialized) { CacheMaterials(); _initialized = true; } Subscribe(); ApplyColors(); } private void CacheMaterials() { _shrineMaterials.Clear(); _oozeMaterials.Clear(); Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] materials = componentsInChildren[i].materials; foreach (Material val in materials) { if (!((Object)(object)val == (Object)null)) { if (((Object)val).name.StartsWith("WispLure_mat")) { _shrineMaterials.Add(val); } else if (((Object)val).name.StartsWith("Ooze_mat")) { _oozeMaterials.Add(val); } } } } } private void Subscribe() { if (!_subscribed) { if (ModConfig.ShrineColor != null) { ModConfig.ShrineColor.SettingChanged += OnAppearanceChanged; } if (ModConfig.OozeColor != null) { ModConfig.OozeColor.SettingChanged += OnAppearanceChanged; } _subscribed = true; } } private void OnAppearanceChanged(object sender, EventArgs e) { ApplyColors(); } private void ApplyColors() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) if (ModConfig.ShrineColor != null) { Color value = ModConfig.ShrineColor.Value; foreach (Material shrineMaterial in _shrineMaterials) { ApplyMaterialColor(shrineMaterial, value); } } if (ModConfig.OozeColor == null) { return; } Color value2 = ModConfig.OozeColor.Value; foreach (Material oozeMaterial in _oozeMaterials) { ApplyMaterialColor(oozeMaterial, value2); } } private static void ApplyMaterialColor(Material material, Color color) { //IL_001d: 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) if (!((Object)(object)material == (Object)null)) { if (material.HasProperty("_Color")) { material.SetColor("_Color", color); } if (material.HasProperty("_EmissionColor")) { material.SetColor("_EmissionColor", color); } } } private void OnDestroy() { if (_subscribed) { if (ModConfig.ShrineColor != null) { ModConfig.ShrineColor.SettingChanged -= OnAppearanceChanged; } if (ModConfig.OozeColor != null) { ModConfig.OozeColor.SettingChanged -= OnAppearanceChanged; } _subscribed = false; } } } internal sealed class WispVisuals : MonoBehaviour { private Color _lastColor; private void Start() { //IL_0015: 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) _lastColor = new Color(-1f, -1f, -1f, -1f); ApplyColor(); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.WispColor.Value != _lastColor) { ApplyColor(); } } private void ApplyColor() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) Color val = (_lastColor = ModConfig.WispColor.Value); Light[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].color = val; } ParticleSystem[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { MainModule main = componentsInChildren2[i].main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(val); } Renderer[] componentsInChildren3 = ((Component)this).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Material[] materials = componentsInChildren3[i].materials; foreach (Material val2 in materials) { if (val2.HasProperty("_Color")) { val2.color = val; } if (val2.HasProperty("_EmissionColor")) { val2.SetColor("_EmissionColor", new Color(val.r * 2f, val.g * 2f, val.b * 2f, 1f)); } } } } } internal static class WispVisualsFactory { public static GameObject Prefab { get; private set; } public static void Create() { if ((Object)(object)Prefab != (Object)null) { return; } Prefab = PrefabManager.Instance.CreateClonedPrefab("lamplighter_wisp_visual", "LuredWisp"); if ((Object)(object)Prefab == (Object)null) { Logger.LogError((object)"Could not clone LuredWisp prefab."); return; } RemoveComponent(); RemoveComponent(); RemoveComponent(); RemoveComponent(); RemoveComponent(); Collider[] componentsInChildren = Prefab.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } if ((Object)(object)Prefab.GetComponent() == (Object)null) { Prefab.AddComponent(); } Prefab.SetActive(false); ModConfig.DebugLog("Created Lamplighter wisp visual."); } private static void RemoveComponent() where T : Component { T component = Prefab.GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } } } } namespace Lamplighter.Systems { internal static class ContainerScanner { public static Container FindNearestContaining(Vector3 origin, string itemName) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(itemName)) { return null; } float value = ModConfig.WorkRadius.Value; float num = value * value; Container result = null; float num2 = float.MaxValue; Container[] array = Object.FindObjectsOfType(); foreach (Container val in array) { if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled) { continue; } Vector3 val2 = ((Component)val).transform.position - origin; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude > num) && (!(itemName == "$item_wood") || !IsWoodStack(val) || ModConfig.TakeWoodFromWoodStacks.Value)) { Inventory inventory = val.GetInventory(); if (inventory != null && inventory.CountItems(itemName, -1, true) > 0 && sqrMagnitude < num2) { result = val; num2 = sqrMagnitude; } } } return result; } public static bool IsWoodStack(Container container) { if ((Object)(object)container == (Object)null) { return false; } Piece componentInParent = ((Component)container).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { return false; } string name = ((Object)((Component)componentInParent).gameObject).name; if (!(name == "wood_stack")) { return name.StartsWith("wood_stack("); } return true; } } internal static class FireScanner { private static readonly FieldInfo NViewField = AccessTools.Field(typeof(Fireplace), "m_nview"); private static readonly FieldInfo MaxFuelField = AccessTools.Field(typeof(Fireplace), "m_maxFuel"); private static readonly FieldInfo StartFuelField = AccessTools.Field(typeof(Fireplace), "m_startFuel"); private static readonly FieldInfo InfiniteFuelField = AccessTools.Field(typeof(Fireplace), "m_infiniteFuel"); private static readonly FieldInfo FuelItemField = AccessTools.Field(typeof(Fireplace), "m_fuelItem"); public static Fireplace FindNearestNeedingFuel(Vector3 origin) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) float value = ModConfig.WorkRadius.Value; float num = value * value; Fireplace result = null; float num2 = float.MaxValue; Fireplace[] array = Object.FindObjectsOfType(); foreach (Fireplace val in array) { if (IsValidPlacedFireplace(val)) { Vector3 val2 = ((Component)val).transform.position - origin; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude > num) && NeedsFuel(val) && sqrMagnitude < num2) { result = val; num2 = sqrMagnitude; } } } return result; } public static Fireplace FindNearestServiceable(Vector3 origin, IDictionary carriedFuel) { //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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (carriedFuel == null || carriedFuel.Count == 0) { return null; } float value = ModConfig.WorkRadius.Value; float num = value * value; Fireplace result = null; float num2 = float.MaxValue; Fireplace[] array = Object.FindObjectsOfType(); foreach (Fireplace val in array) { if (!IsValidPlacedFireplace(val)) { continue; } Vector3 val2 = ((Component)val).transform.position - origin; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude > num) && NeedsFuel(val) && CanAcceptFuel(val)) { string fuelItemName = GetFuelItemName(val); if (!string.IsNullOrEmpty(fuelItemName) && carriedFuel.TryGetValue(fuelItemName, out var value2) && value2 > 0 && sqrMagnitude < num2) { result = val; num2 = sqrMagnitude; } } } return result; } public static Dictionary GetFuelTypesInRadius(Vector3 origin) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); float value = ModConfig.WorkRadius.Value; float num = value * value; Fireplace[] array = Object.FindObjectsOfType(); foreach (Fireplace val in array) { if (!IsValidPlacedFireplace(val)) { continue; } Vector3 val2 = ((Component)val).transform.position - origin; if (((Vector3)(ref val2)).sqrMagnitude > num) { continue; } string fuelItemName = GetFuelItemName(val); if (!string.IsNullOrEmpty(fuelItemName)) { int fuelStackLimit = GetFuelStackLimit(val); if (!dictionary.TryGetValue(fuelItemName, out var value2) || fuelStackLimit > value2) { dictionary[fuelItemName] = fuelStackLimit; } } } return dictionary; } public static bool NeedsFuel(Fireplace fireplace) { if (!IsValidPlacedFireplace(fireplace)) { return false; } if (InfiniteFuelField != null && (bool)InfiniteFuelField.GetValue(fireplace)) { return false; } float maxFuel = GetMaxFuel(fireplace); if (maxFuel <= 0f) { return false; } if (GetFuelNeededToMax(fireplace) <= 0) { return false; } return GetFuel(fireplace) / maxFuel < ModConfig.RefillThreshold; } public static bool CanAcceptFuel(Fireplace fireplace) { if (!IsValidPlacedFireplace(fireplace)) { return false; } return GetFuelNeededToMax(fireplace) > 0; } public static int GetFuelNeededToMax(Fireplace fireplace) { if (!IsValidPlacedFireplace(fireplace)) { return 0; } float maxFuel = GetMaxFuel(fireplace); if (maxFuel <= 0f) { return 0; } float fuel = GetFuel(fireplace); float num = maxFuel - fuel; if (num < 1f) { return 0; } return Mathf.Max(0, Mathf.FloorToInt(num + 0.0001f)); } public static float GetMaxFuel(Fireplace fireplace) { if ((Object)(object)fireplace == (Object)null || MaxFuelField == null) { return 0f; } return (float)MaxFuelField.GetValue(fireplace); } public static float GetFuel(Fireplace fireplace) { if (!IsValidPlacedFireplace(fireplace)) { return 0f; } ZNetView networkView = GetNetworkView(fireplace); if ((Object)(object)networkView == (Object)null) { return 0f; } ZDO zDO = networkView.GetZDO(); if (zDO == null) { return 0f; } float num = zDO.GetFloat("fuel", -1f); if (num < 0f) { num = ((StartFuelField != null) ? ((float)StartFuelField.GetValue(fireplace)) : 0f); } return num; } public static string GetFuelItemName(Fireplace fireplace) { return GetFuelItem(fireplace)?.m_itemData?.m_shared?.m_name; } public static int GetFuelStackLimit(Fireplace fireplace) { ItemDrop fuelItem = GetFuelItem(fireplace); if (fuelItem?.m_itemData?.m_shared == null) { return 1; } return Mathf.Max(1, fuelItem.m_itemData.m_shared.m_maxStackSize); } public static bool IsValidPlacedFireplace(Fireplace fireplace) { if ((Object)(object)fireplace == (Object)null || !((Behaviour)fireplace).isActiveAndEnabled || !((Component)fireplace).gameObject.activeInHierarchy) { return false; } ZNetView networkView = GetNetworkView(fireplace); if ((Object)(object)networkView == (Object)null || !networkView.IsValid()) { return false; } if (networkView.GetZDO() == null) { return false; } return true; } private static ZNetView GetNetworkView(Fireplace fireplace) { if ((Object)(object)fireplace == (Object)null || NViewField == null) { return null; } object? value = NViewField.GetValue(fireplace); return (ZNetView)((value is ZNetView) ? value : null); } private static ItemDrop GetFuelItem(Fireplace fireplace) { if ((Object)(object)fireplace == (Object)null || FuelItemField == null) { return null; } object? value = FuelItemField.GetValue(fireplace); return (ItemDrop)((value is ItemDrop) ? value : null); } } internal static class FuelService { private static readonly FieldInfo ContainerNViewField = AccessTools.Field(typeof(Container), "m_nview"); private static readonly FieldInfo FireplaceNViewField = AccessTools.Field(typeof(Fireplace), "m_nview"); private static readonly MethodInfo InventoryChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null); private static readonly MethodInfo ContainerSaveMethod = AccessTools.Method(typeof(Container), "Save", (Type[])null, (Type[])null); private static readonly MethodInfo RemoveItemMethod = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[1] { typeof(ItemData) }, (Type[])null); public static int TakeFuel(Container container, string fuelName, int maximumAmount) { if ((Object)(object)container == (Object)null || string.IsNullOrEmpty(fuelName) || maximumAmount <= 0) { return 0; } Inventory inventory = container.GetInventory(); if (inventory == null) { return 0; } object? obj = ContainerNViewField?.GetValue(container); ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null); if ((Object)(object)val != (Object)null && val.IsValid() && !val.IsOwner()) { val.ClaimOwnership(); } int num = maximumAmount; int num2 = 0; foreach (ItemData item in new List(inventory.GetAllItems())) { if (num <= 0) { break; } if (item == null || item.m_shared == null || item.m_shared.m_name != fuelName || item.m_stack <= 0) { continue; } int num3 = Mathf.Min(item.m_stack, num); if (num3 == item.m_stack) { if (RemoveItemMethod == null) { continue; } RemoveItemMethod.Invoke(inventory, new object[1] { item }); } else { item.m_stack -= num3; } num2 += num3; num -= num3; } if (num2 <= 0) { return 0; } InventoryChangedMethod?.Invoke(inventory, null); ContainerSaveMethod?.Invoke(container, null); HandleEmptyWoodStack(container, fuelName); ModConfig.DebugLog($"Lamplighter: picked up {num2} x {fuelName}"); return num2; } public static int AddFuelToMax(Fireplace fireplace, int availableAmount) { if ((Object)(object)fireplace == (Object)null || availableAmount <= 0) { return 0; } int fuelNeededToMax = FireScanner.GetFuelNeededToMax(fireplace); if (fuelNeededToMax <= 0) { return 0; } int num = Mathf.Min(fuelNeededToMax, availableAmount); object? obj = FireplaceNViewField?.GetValue(fireplace); ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null); if ((Object)(object)val == (Object)null || !val.IsValid()) { return 0; } if (!val.IsOwner()) { val.ClaimOwnership(); } for (int i = 0; i < num; i++) { val.InvokeRPC("RPC_AddFuel", Array.Empty()); } ModConfig.DebugLog($"Lamplighter: delivered {num} fuel to {((Object)fireplace).name}"); return num; } private static void HandleEmptyWoodStack(Container container, string fuelName) { if (!ModConfig.TakeWoodFromWoodStacks.Value || fuelName != "$item_wood" || !ContainerScanner.IsWoodStack(container)) { return; } Inventory inventory = container.GetInventory(); if (inventory != null && inventory.CountItems("$item_wood", -1, true) > 0) { return; } Piece componentInParent = ((Component)container).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null)) { ZNetView component = ((Component)componentInParent).GetComponent(); if ((Object)(object)component != (Object)null && component.IsValid() && !component.IsOwner()) { component.ClaimOwnership(); } if ((Object)(object)ZNetScene.instance != (Object)null) { ZNetScene.instance.Destroy(((Component)componentInParent).gameObject); } } } } } namespace Lamplighter.Pieces { internal static class LamplighterPiece { public const string PrefabName = "piece_lamplighter"; private const string SourcePrefab = "piece_wisplure"; private static CustomPiece _customPiece; public static void Register() { PrefabManager.OnVanillaPrefabsAvailable += CreatePiece; } private static void CreatePiece() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_0053: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown PrefabManager.OnVanillaPrefabsAvailable -= CreatePiece; WispVisualsFactory.Create(); PieceConfig val = new PieceConfig { Name = "Lamplighter", Description = "Summons a fire spirit that tends nearby fires and lights.", PieceTable = PieceTables.Hammer, Category = PieceCategories.Misc, CraftingStation = CraftingStations.Workbench }; val.AddRequirement("Stone", 10, true); val.AddRequirement("Resin", 5, true); val.AddRequirement("SurtlingCore", 1, true); _customPiece = new CustomPiece("piece_lamplighter", "piece_wisplure", val); GameObject piecePrefab = _customPiece.PiecePrefab; if ((Object)(object)piecePrefab.GetComponent() == (Object)null) { piecePrefab.AddComponent(); } if ((Object)(object)piecePrefab.GetComponent() == (Object)null) { piecePrefab.AddComponent(); } if ((Object)(object)piecePrefab.GetComponent() == (Object)null) { piecePrefab.AddComponent(); } WispSpawner component = piecePrefab.GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } PieceManager.Instance.AddPiece(_customPiece); ModConfig.DebugLog("Registered Lamplighter build piece."); } } } namespace Lamplighter.Creatures { internal sealed class LamplighterWisp : MonoBehaviour, Hoverable { private enum WispState { Idle, ToChest, AtChest, ToFire, AtFire } private const float HoverHeight = 1.8f; private const float BobAmount = 0.15f; private const float BobSpeed = 1.5f; private const float DriftAmount = 0.18f; private const float DriftSpeed = 0.65f; private const float MoveSpeed = 3.5f; private const float ChestHoverHeight = 1.1f; private const float ChestArrivalDistance = 0.35f; private const float FireHoverDistance = 0.8f; private const float FireHoverHeight = 0.7f; private const float FireArrivalDistance = 0.3f; private const float ChestPauseTime = 0.6f; private const float FirePauseTime = 0.4f; private const float RestingScanInterval = 3f; private const float RemoteSyncInterval = 0.5f; private const string InventoryZdoKey = "com.g.lamplighter.carried_inventory"; private const string VisualStateZdoKey = "com.g.lamplighter.visual_state"; private static readonly FieldInfo ObjectDbItemsField = AccessTools.Field(typeof(ObjectDB), "m_items"); private GameObject _wisp; private ZNetView _nview; private WearNTear _wearNTear; private Fireplace _targetFire; private Container _targetContainer; private readonly Dictionary _inventory = new Dictionary(); private readonly Dictionary _stackLimits = new Dictionary(); private readonly List _restockQueue = new List(); private int _restockIndex; private string _restockFuelName; private WispState _state; private float _timeOffset; private float _nextScanTime; private float _stateTimer; private bool _isResting; private bool _restockDidWork; private bool _inventoryReturned; private bool _wasOwner; private char _remoteVisualMode = 'H'; private Vector3 _remoteVisualTarget; private float _nextRemoteSyncTime; private void Start() { _timeOffset = Random.Range(0f, 100f); _nview = ((Component)this).GetComponent(); _wearNTear = ((Component)this).GetComponent(); if ((Object)(object)_wearNTear != (Object)null) { WearNTear wearNTear = _wearNTear; wearNTear.m_onDestroyed = (Action)Delegate.Combine(wearNTear.m_onDestroyed, new Action(OnShrineDestroyed)); } CreateWisp(); if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { LoadInventoryFromZdo(); _wasOwner = _nview.IsOwner(); if (_wasOwner) { SaveVisualHome(); } else { LoadVisualStateFromZdo(); } } } private void CreateWisp() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_wisp != (Object)null) && !((Object)(object)WispVisualsFactory.Prefab == (Object)null)) { _wisp = Object.Instantiate(WispVisualsFactory.Prefab, ((Component)this).transform); ((Object)_wisp).name = "LamplighterWisp"; _wisp.transform.localScale = Vector3.one * 0.65f; _wisp.transform.localPosition = new Vector3(0f, 1.8f, 0f); _wisp.SetActive(true); } } private void Update() { if ((Object)(object)_wisp == (Object)null) { CreateWisp(); return; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { MoveHome(); return; } bool flag = _nview.IsOwner(); if (flag != _wasOwner) { _wasOwner = flag; LoadInventoryFromZdo(); ResetWorkState(); if (flag) { SaveVisualHome(); ModConfig.DebugLog("Lamplighter: acquired network ownership."); } } if (!flag) { UpdateRemoteVisual(); return; } switch (_state) { case WispState.Idle: UpdateIdle(); break; case WispState.ToChest: UpdateToChest(); break; case WispState.AtChest: UpdateAtChest(); break; case WispState.ToFire: UpdateToFire(); break; case WispState.AtFire: UpdateAtFire(); break; } } private void UpdateIdle() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) MoveHome(); if (!(Time.time < _nextScanTime)) { Fireplace val = FireScanner.FindNearestServiceable(((Component)this).transform.position, _inventory); if ((Object)(object)val != (Object)null) { LeaveResting(); BeginFireJob(val); } else if (StartRestockRun()) { LeaveResting(); } else { EnterResting(); } } } private void BeginFireJob(Fireplace fireplace) { //IL_002d: 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_0036: Unknown result type (might be due to invalid IL or missing references) if (FireScanner.IsValidPlacedFireplace(fireplace)) { string fuelItemName = FireScanner.GetFuelItemName(fireplace); int carried = GetCarried(fuelItemName); if (carried > 0) { _targetFire = fireplace; _state = WispState.ToFire; Vector3 fireHoverPosition = GetFireHoverPosition(fireplace); SaveVisualTarget('F', fireHoverPosition); ModConfig.DebugLog($"Lamplighter: servicing {((Object)fireplace).name} with {fuelItemName} ({carried} carried)"); } } } private bool StartRestockRun() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Dictionary fuelTypesInRadius = FireScanner.GetFuelTypesInRadius(((Component)this).transform.position); if (fuelTypesInRadius.Count == 0) { return false; } foreach (KeyValuePair item in fuelTypesInRadius) { _stackLimits[item.Key] = item.Value; } _restockQueue.Clear(); _restockIndex = 0; _restockDidWork = false; foreach (KeyValuePair item2 in fuelTypesInRadius) { string key = item2.Key; int value = item2.Value; if (GetCarried(key) < value) { _restockQueue.Add(key); } } if (_restockQueue.Count == 0) { return false; } if (!BeginNextRestockFuel()) { return false; } ModConfig.DebugLog($"Lamplighter: beginning restock run for {_restockQueue.Count} fuel type(s)"); return true; } private bool BeginNextRestockFuel() { _targetContainer = null; _restockFuelName = null; while (_restockIndex < _restockQueue.Count) { string text = _restockQueue[_restockIndex]; _restockIndex++; int stackLimit = GetStackLimit(text); if (GetCarried(text) < stackLimit) { _restockFuelName = text; if (FindContainerForCurrentFuel()) { return true; } _restockFuelName = null; } } FinishRestockRun(); return false; } private bool FindContainerForCurrentFuel() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(_restockFuelName)) { return false; } int stackLimit = GetStackLimit(_restockFuelName); if (GetCarried(_restockFuelName) >= stackLimit) { return false; } Container val = ContainerScanner.FindNearestContaining(((Component)this).transform.position, _restockFuelName); if ((Object)(object)val == (Object)null) { return false; } _targetContainer = val; _state = WispState.ToChest; LeaveResting(); Vector3 chestHoverPosition = GetChestHoverPosition(val); SaveVisualTarget('C', chestHoverPosition); ModConfig.DebugLog("Lamplighter: fetching " + _restockFuelName + " from " + ((Object)val).name); return true; } private void UpdateToChest() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_targetContainer == (Object)null) { HandleFailedChest(); return; } if (!IsInsideWorkRadius(((Component)_targetContainer).transform.position)) { HandleFailedChest(); return; } Vector3 chestHoverPosition = GetChestHoverPosition(_targetContainer); MoveWisp(chestHoverPosition); if (Vector3.Distance(_wisp.transform.position, chestHoverPosition) <= 0.35f) { _stateTimer = 0.6f; _state = WispState.AtChest; } } private void UpdateAtChest() { //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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_targetContainer == (Object)null || string.IsNullOrEmpty(_restockFuelName)) { HandleFailedChest(); return; } Vector3 chestHoverPosition = GetChestHoverPosition(_targetContainer); BobAround(chestHoverPosition, 0.08f); _stateTimer -= Time.deltaTime; if (!(_stateTimer > 0f)) { string restockFuelName = _restockFuelName; int stackLimit = GetStackLimit(restockFuelName); int carried = GetCarried(restockFuelName); int num = Mathf.Max(0, stackLimit - carried); int num2 = 0; if (num > 0) { num2 = FuelService.TakeFuel(_targetContainer, restockFuelName, num); } if (num2 > 0) { _restockDidWork = true; SetCarried(restockFuelName, carried + num2); ModConfig.DebugLog($"Lamplighter: carrying {GetCarried(restockFuelName)}/{stackLimit} x {restockFuelName}"); } _targetContainer = null; if (GetCarried(restockFuelName) >= stackLimit || !FindContainerForCurrentFuel()) { _restockFuelName = null; BeginNextRestockFuel(); } } } private void HandleFailedChest() { _targetContainer = null; if (!FindContainerForCurrentFuel()) { _restockFuelName = null; BeginNextRestockFuel(); } } private void FinishRestockRun() { _targetContainer = null; _restockFuelName = null; _restockQueue.Clear(); _restockIndex = 0; _state = WispState.Idle; SaveVisualHome(); if (_restockDidWork) { ModConfig.DebugLog("Lamplighter: restock complete."); _nextScanTime = Time.time + 0.25f; } else { EnterResting(); } } private void UpdateToFire() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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) if ((Object)(object)_targetFire == (Object)null) { FinishFireJob(); return; } if (!FireScanner.IsValidPlacedFireplace(_targetFire)) { FinishFireJob(); return; } if (!IsInsideWorkRadius(((Component)_targetFire).transform.position)) { FinishFireJob(); return; } string fuelItemName = FireScanner.GetFuelItemName(_targetFire); if (GetCarried(fuelItemName) <= 0) { FinishFireJob(); return; } if (!FireScanner.CanAcceptFuel(_targetFire)) { FinishFireJob(); return; } Vector3 fireHoverPosition = GetFireHoverPosition(_targetFire); MoveWisp(fireHoverPosition); if (Vector3.Distance(_wisp.transform.position, fireHoverPosition) <= 0.3f) { _stateTimer = 0.4f; _state = WispState.AtFire; } } private void UpdateAtFire() { //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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_targetFire == (Object)null || !FireScanner.IsValidPlacedFireplace(_targetFire)) { FinishFireJob(); return; } Vector3 fireHoverPosition = GetFireHoverPosition(_targetFire); BobAround(fireHoverPosition, 0.08f); _stateTimer -= Time.deltaTime; if (_stateTimer > 0f) { return; } string fuelItemName = FireScanner.GetFuelItemName(_targetFire); int carried = GetCarried(fuelItemName); if (carried <= 0) { FinishFireJob(); return; } int num = FuelService.AddFuelToMax(_targetFire, carried); if (num > 0) { SetCarried(fuelItemName, carried - num); ModConfig.DebugLog($"Lamplighter: {GetCarried(fuelItemName)} x {fuelItemName} remaining"); } FinishFireJob(); } private void FinishFireJob() { _targetFire = null; _state = WispState.Idle; SaveVisualHome(); _nextScanTime = Time.time + 0.15f; } private void EnterResting() { _state = WispState.Idle; _nextScanTime = Time.time + 3f; SaveVisualHome(); if (!_isResting) { _isResting = true; ModConfig.DebugLog("Lamplighter: resting."); } } private void LeaveResting() { _isResting = false; } private void ResetWorkState() { _targetFire = null; _targetContainer = null; _restockFuelName = null; _restockQueue.Clear(); _restockIndex = 0; _restockDidWork = false; _state = WispState.Idle; _isResting = false; _nextScanTime = Time.time + 0.15f; } private int GetCarried(string fuelName) { if (string.IsNullOrEmpty(fuelName)) { return 0; } if (_inventory.TryGetValue(fuelName, out var value)) { return value; } return 0; } private void SetCarried(string fuelName, int amount) { if (string.IsNullOrEmpty(fuelName)) { return; } if (amount <= 0) { if (_inventory.Remove(fuelName)) { SaveInventoryToZdo(); } return; } int stackLimit = GetStackLimit(fuelName); int num = Mathf.Clamp(amount, 0, stackLimit); if (!_inventory.TryGetValue(fuelName, out var value) || value != num) { _inventory[fuelName] = num; SaveInventoryToZdo(); } } private int GetStackLimit(string fuelName) { if (_stackLimits.TryGetValue(fuelName, out var value)) { return Mathf.Max(1, value); } return 1; } private void SaveInventoryToZdo() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner()) { return; } ZDO zDO = _nview.GetZDO(); if (zDO == null) { return; } StringBuilder stringBuilder = new StringBuilder(); List list = new List(_inventory.Keys); list.Sort(StringComparer.Ordinal); foreach (string item in list) { int carried = GetCarried(item); if (carried > 0) { int stackLimit = GetStackLimit(item); string value = Convert.ToBase64String(Encoding.UTF8.GetBytes(item)); if (stringBuilder.Length > 0) { stringBuilder.Append(';'); } stringBuilder.Append(value); stringBuilder.Append(','); stringBuilder.Append(carried); stringBuilder.Append(','); stringBuilder.Append(stackLimit); } } zDO.Set("com.g.lamplighter.carried_inventory", stringBuilder.ToString()); ModConfig.DebugLog($"Lamplighter: saved {_inventory.Count} carried fuel type(s)."); } private void LoadInventoryFromZdo() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return; } ZDO zDO = _nview.GetZDO(); if (zDO == null) { return; } string text = zDO.GetString("com.g.lamplighter.carried_inventory", string.Empty); _inventory.Clear(); _stackLimits.Clear(); if (string.IsNullOrEmpty(text)) { return; } string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ',' }); if (array2.Length != 3) { Logger.LogWarning((object)"Lamplighter: invalid saved inventory entry."); continue; } try { string text2 = Encoding.UTF8.GetString(Convert.FromBase64String(array2[0])); if (!int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { Logger.LogWarning((object)"Lamplighter: invalid saved inventory amount."); } else if (!string.IsNullOrEmpty(text2) && result > 0) { result2 = Mathf.Max(1, result2); result = Mathf.Clamp(result, 1, result2); _stackLimits[text2] = result2; _inventory[text2] = result; } } catch (FormatException) { Logger.LogWarning((object)"Lamplighter: invalid saved fuel name."); } } ModConfig.DebugLog($"Lamplighter: restored {_inventory.Count} carried fuel type(s)."); } private void SaveVisualHome() { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { ZDO zDO = _nview.GetZDO(); if (zDO != null) { zDO.Set("com.g.lamplighter.visual_state", "H"); } } } private void SaveVisualTarget(char mode, Vector3 position) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { ZDO zDO = _nview.GetZDO(); if (zDO != null) { string text = string.Format(CultureInfo.InvariantCulture, "{0}|{1:R}|{2:R}|{3:R}", mode, position.x, position.y, position.z); zDO.Set("com.g.lamplighter.visual_state", text); } } } private void UpdateRemoteVisual() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (Time.time >= _nextRemoteSyncTime) { _nextRemoteSyncTime = Time.time + 0.5f; LoadInventoryFromZdo(); LoadVisualStateFromZdo(); } if (_remoteVisualMode == 'H') { MoveHome(); } else { MoveWisp(_remoteVisualTarget); } } private void LoadVisualStateFromZdo() { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return; } ZDO zDO = _nview.GetZDO(); if (zDO == null) { return; } string text = zDO.GetString("com.g.lamplighter.visual_state", "H"); if (string.IsNullOrEmpty(text) || text == "H") { _remoteVisualMode = 'H'; return; } string[] array = text.Split(new char[1] { '|' }); if (array.Length != 4 || string.IsNullOrEmpty(array[0])) { _remoteVisualMode = 'H'; return; } if (!float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { _remoteVisualMode = 'H'; return; } char c = array[0][0]; if (c != 'C' && c != 'F') { _remoteVisualMode = 'H'; return; } _remoteVisualMode = c; _remoteVisualTarget = new Vector3(result, result2, result3); } private bool IsInsideWorkRadius(Vector3 position) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) float value = ModConfig.WorkRadius.Value; Vector3 val = position - ((Component)this).transform.position; return ((Vector3)(ref val)).sqrMagnitude <= value * value; } private Vector3 GetChestHoverPosition(Container container) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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) return ((Component)container).transform.position + Vector3.up * 1.1f; } private Vector3 GetFireHoverPosition(Fireplace fireplace) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)fireplace).transform.position; Vector3 val = ((Component)this).transform.position - position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = Vector3.right; } ((Vector3)(ref val)).Normalize(); return position + val * 0.8f + Vector3.up * 0.7f; } private void MoveWisp(Vector3 destination) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) _wisp.transform.position = Vector3.MoveTowards(_wisp.transform.position, destination, 3.5f * Time.deltaTime); } private void BobAround(Vector3 center, float amount) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) float num = Time.time + _timeOffset; Vector3 destination = center + new Vector3(Mathf.Cos(num * 2f) * amount, Mathf.Sin(num * 2.5f) * amount, Mathf.Sin(num * 2f) * amount); MoveWisp(destination); } private void MoveHome() { //IL_0013: 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_0059: 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_0060: Unknown result type (might be due to invalid IL or missing references) float num = Time.time + _timeOffset; Vector3 destination = ((Component)this).transform.position + new Vector3(Mathf.Cos(num * 0.65f) * 0.18f, 1.8f + Mathf.Sin(num * 1.5f) * 0.15f, Mathf.Sin(num * 0.65f) * 0.18f); MoveWisp(destination); } private void OnShrineDestroyed() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) if (_inventoryReturned || (Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner()) { return; } _inventoryReturned = true; if (_inventory.Count == 0) { return; } Vector3 position = ((Component)this).transform.position + Vector3.up * 0.75f; foreach (KeyValuePair item in new List>(_inventory)) { if (item.Value > 0) { DropCarriedItem(item.Key, item.Value, position); } } _inventory.Clear(); SaveInventoryToZdo(); ModConfig.DebugLog("Lamplighter: returned carried inventory."); } private void DropCarriedItem(string sharedName, int amount, Vector3 position) { //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ObjectDB.instance == (Object)null || amount <= 0) { return; } if (!(ObjectDbItemsField?.GetValue(ObjectDB.instance) is List list)) { Logger.LogWarning((object)$"Lamplighter: couldn't return {amount} x {sharedName}; ObjectDB item list unavailable."); return; } GameObject val = null; ItemDrop val2 = null; foreach (GameObject item in list) { if (!((Object)(object)item == (Object)null)) { ItemDrop component = item.GetComponent(); if (!((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null && !(component.m_itemData.m_shared.m_name != sharedName)) { val = item; val2 = component; break; } } } if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { Logger.LogWarning((object)$"Lamplighter: couldn't return {amount} x {sharedName}; item prefab not found."); return; } int num = Mathf.Max(1, val2.m_itemData.m_shared.m_maxStackSize); int num2 = amount; Vector3 val3 = default(Vector3); while (num2 > 0) { int num3 = Mathf.Min(num2, num); ItemData obj = val2.m_itemData.Clone(); obj.m_dropPrefab = val; ((Vector3)(ref val3))..ctor(Random.Range(-0.35f, 0.35f), 0f, Random.Range(-0.35f, 0.35f)); ItemDrop.DropItem(obj, num3, position + val3, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); num2 -= num3; } } public string GetHoverName() { return "Lamplighter"; } public string GetHoverText() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Lamplighter"); stringBuilder.Append("\n"); stringBuilder.Append("Status: "); stringBuilder.Append(GetStatusText()); stringBuilder.Append("\n"); if (_inventory.Count == 0) { stringBuilder.Append("Carrying: Nothing"); return stringBuilder.ToString(); } stringBuilder.Append("Carrying:"); List list = new List(_inventory.Keys); list.Sort(); foreach (string item in list) { int carried = GetCarried(item); if (carried > 0) { int stackLimit = GetStackLimit(item); string value = item; if (Localization.instance != null) { value = Localization.instance.Localize(item); } stringBuilder.Append("\n"); stringBuilder.Append(value); stringBuilder.Append(": "); stringBuilder.Append(carried); stringBuilder.Append("/"); stringBuilder.Append(stackLimit); } } return stringBuilder.ToString(); } private string GetStatusText() { if ((Object)(object)_nview != (Object)null && _nview.IsValid() && !_nview.IsOwner()) { return _remoteVisualMode switch { 'C' => "Restocking", 'F' => "Working", _ => "Resting", }; } switch (_state) { case WispState.ToChest: case WispState.AtChest: return "Restocking"; case WispState.ToFire: case WispState.AtFire: return "Working"; default: if (!_isResting) { return "Looking for work"; } return "Resting"; } } private void OnDestroy() { if ((Object)(object)_wearNTear != (Object)null) { WearNTear wearNTear = _wearNTear; wearNTear.m_onDestroyed = (Action)Delegate.Remove(wearNTear.m_onDestroyed, new Action(OnShrineDestroyed)); } } } } namespace Lamplighter.Config { internal static class ModConfig { public static ConfigEntry WorkRadius { get; private set; } public static ConfigEntry RefillBelowPercent { get; private set; } public static ConfigEntry WispColor { get; private set; } public static ConfigEntry OozeColor { get; private set; } public static ConfigEntry ShrineColor { get; private set; } public static ConfigEntry TakeWoodFromWoodStacks { get; private set; } public static ConfigEntry DetailedLogging { get; private set; } public static ConfigEntry ShowRangeWhilePlacing { get; private set; } public static ConfigEntry ShowRangeOnHover { get; private set; } public static float RefillThreshold => (float)RefillBelowPercent.Value / 100f; public static void Bind(ConfigFile config) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Expected O, but got Unknown WorkRadius = config.Bind("Lamplighter", "Work Radius", 40f, new ConfigDescription("Maximum distance in meters for servicing fires and searching fuel containers.", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 100f), new object[1] { AdminOnly() })); RefillBelowPercent = config.Bind("Lamplighter", "Refill Below", 25, new ConfigDescription("Refill a fire when its fuel falls below this percentage.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), new object[1] { AdminOnly() })); TakeWoodFromWoodStacks = config.Bind("Lamplighter", "Take Wood From Wood Stacks", true, "Allow the Lamplighter to use placed Wood Stacks as a fuel source."); WispColor = config.Bind("Appearance", "Wisp Color", new Color(1f, 0.25f, 0.03f, 1f), "Color of the Lamplighter fire spirit."); OozeColor = config.Bind("Appearance", "Ooze Color", new Color(1f, 0.25f, 0.03f, 1f), "Color of the glowing flowing material on the Lamplighter shrine."); ShrineColor = config.Bind("Appearance", "Shrine Color", new Color(0.85f, 0.72f, 0.4f, 1f), "Color of the Lamplighter shrine structure."); DetailedLogging = config.Bind("Advanced", "Detailed Logging", false, "Log Lamplighter jobs, fuel transfers, restocking, and other diagnostic activity."); ShowRangeWhilePlacing = config.Bind("Advanced", "Show Range While Placing", true, new ConfigDescription("Show the Lamplighter work radius while placing it.", (AcceptableValueBase)null, new object[1] { Hidden() })); ShowRangeOnHover = config.Bind("Advanced", "Show Range On Hover", false, new ConfigDescription("Show the work radius while hovering over an existing Lamplighter.", (AcceptableValueBase)null, new object[1] { Hidden() })); } public static void DebugLog(string message) { if (DetailedLogging != null && DetailedLogging.Value) { Logger.LogInfo((object)message); } } private static ConfigurationManagerAttributes AdminOnly() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown return new ConfigurationManagerAttributes { IsAdminOnly = true }; } private static ConfigurationManagerAttributes Hidden() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return new ConfigurationManagerAttributes { Browsable = false }; } } }