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 AutoOven v1.0.15
AutoOven.dll
Decompiled 2 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using ConditionalConfigSync; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MrGay")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AutoOven")] [assembly: AssemblyTitle("AutoOven")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 AutoOven { [BepInPlugin("mrgay.autoven", "Auto Oven", "1.0.15")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class AutoOvenPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(CookingStation), "UpdateCooking")] private static class CookingStationUpdatePatch { private static void Prefix(CookingStation __instance) { instance?.ProcessCookingStation(__instance); } } private sealed class PersistedContainer { public ZDO Zdo { get; } public Container Prefab { get; } public PersistedContainer(ZDO zdo, Container prefab) { Zdo = zdo; Prefab = prefab; } } private sealed class OvenSlots { public static bool HasFreeSlot(CookingStation oven) { return FindFreeSlot(oven) >= 0; } public static int FindFreeSlot(CookingStation oven) { for (int i = 0; i < oven.m_slots.Length; i++) { if (!TryGetSlot(oven, i, out string _, out object _)) { return i; } } return -1; } public static bool SlotContainsItem(CookingStation oven, int slot, string itemName) { if (TryGetSlot(oven, slot, out string itemName2, out object _)) { return itemName2 == itemName; } return false; } public static bool TryTakeFinished(CookingStation oven, out ItemData? item, out int slot) { item = null; slot = -1; for (int i = 0; i < oven.m_slots.Length; i++) { if (TryGetSlot(oven, i, out string itemName, out object status) && !(status?.ToString() != "Done")) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(itemName); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if (!((Object)(object)val == (Object)null)) { item = val.m_itemData.Clone(); item.m_stack = 1; slot = i; return true; } } } return false; } public static bool RemoveFinished(CookingStation oven, int slot) { ZNetView component = ((Component)oven).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } component.ClaimOwnership(); MethodInfo method = ((object)oven).GetType().GetMethod("SetSlot", BindingFlags.Instance | BindingFlags.NonPublic); if (method == null) { return false; } object obj = Enum.Parse(method.GetParameters()[3].ParameterType, "NotDone"); method.Invoke(oven, new object[5] { slot, "", 0f, obj, false }); ((object)oven).GetType().GetMethod("RPC_SetSlotVisual", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(oven, new object[3] { 0L, slot, "" }); return true; } public static bool ContainsItem(CookingStation oven, string itemName) { for (int i = 0; i < oven.m_slots.Length; i++) { if (TryGetSlot(oven, i, out string itemName2, out object _) && itemName2 == itemName) { return true; } } return false; } private static bool TryGetSlot(CookingStation oven, int slot, out string itemName, out object? status) { itemName = ""; status = null; MethodInfo method = ((object)oven).GetType().GetMethod("GetSlot", BindingFlags.Instance | BindingFlags.NonPublic); if (method == null) { return false; } object[] array = new object[5] { slot, null, 0f, null, false }; method.Invoke(oven, array); itemName = (array[1] as string) ?? ""; status = array[3]; return itemName.Length > 0; } } public const string PluginGuid = "mrgay.autoven"; public const string PluginName = "Auto Oven"; public const string PluginVersion = "1.0.15"; private const string StoneOvenPrefabName = "piece_oven"; private readonly List<CookingStation> ovens = new List<CookingStation>(); private readonly Dictionary<int, float> nextStationScans = new Dictionary<int, float>(); private ConfigEntry<float> scanDistance; private ConfigEntry<float> scanInterval; private ConfigEntry<bool> enforceServerConfigSync; private ConfigEntry<bool> logScanSummary; private ConfigEntry<bool> enableAutoFueling; private ConfigSync configSync; private float nextScan; private bool adapterWarningLogged; private int scanCount; private int persistedOvenCount; private int persistedChestCount; private int liveSkippedOvenCount; private int hookedStationCount; private int stoneOvenPrefabHash; private static AutoOvenPlugin? instance; private bool stoneOvenHashInitializationFailed; private void Awake() { //IL_00b9: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown instance = this; scanDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Automation", "distance", 10f, "Maximum distance in meters between an oven and a chest used for input or output."); scanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Automation", "interval", 3f, "Seconds between server-side oven scans."); enforceServerConfigSync = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enforce_Server_Config_Sync", true, "When enabled, the server controls the automation settings for connected clients."); logScanSummary = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Log_Scan_Summary", false, "When enabled, periodically log the number of active ovens found by Auto Oven."); enableAutoFueling = ((BaseUnityPlugin)this).Config.Bind<bool>("Automation", "Enable_Auto_Fueling", true, "When enabled, nearby chests supply the oven's configured fuel item automatically. Required for unattended ovens to actually finish cooking and free up their slots."); configSync = new ConfigSync("mrgay.autoven") { DisplayName = "Auto Oven", CurrentVersion = "1.0.15", MinimumRequiredVersion = "1.0.15", ModRequired = true }; ((ConditionalConfigSync)configSync).AllowClientConfigUpdatesWhenUnlocked = true; ((ConditionalConfigSync)configSync).AddLockingConfigEntry<bool>(enforceServerConfigSync); ((ConditionalConfigSync)configSync).AddConfigEntry<bool>(logScanSummary, (ConfigSyncMode)0); ((ConditionalConfigSync)configSync).AddConfigEntry<bool>(enableAutoFueling, (ConfigSyncMode)0); ((ConditionalConfigSync)configSync).AddConfigEntry<float>(scanDistance, (ConfigSyncMode)1, true); ((ConditionalConfigSync)configSync).AddConfigEntry<float>(scanInterval, (ConfigSyncMode)1, true); Harmony.CreateAndPatchAll(typeof(AutoOvenPlugin).Assembly, "mrgay.autoven"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Auto Oven 1.0.15 loaded. Automation runs on the server only."); } private void Update() { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { InitializeStoneOvenHash(); if (ZNet.instance.GetNrOfPlayers() > 0 && !(Time.time < nextScan)) { nextScan = Time.time + Mathf.Max(0.25f, scanInterval.Value); ScanOvens(); } } } private void ScanOvens() { scanCount++; ovens.Clear(); ovens.AddRange(Object.FindObjectsOfType<CookingStation>()); foreach (CookingStation oven in ovens) { if (!((Object)(object)oven == (Object)null) && ((Behaviour)oven).isActiveAndEnabled) { ProcessCookingStation(oven); } } ProcessPersistedCookingStations(); LogPlayerProximityDiagnostics(); if (logScanSummary.Value && scanCount % 20 == 0) { int num = GetAllPersistedZdos().Count((ZDO zdo) => zdo.GetPrefab() == stoneOvenPrefabHash); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Scan {scanCount}: found {ovens.Count} active Cooking Stations; CookingStation update hook processed {hookedStationCount} stations. " + $"Persisted: {persistedOvenCount} oven(s) processed, {liveSkippedOvenCount} skipped as live, {num} total Stone Oven ZDO(s) in world, " + $"{persistedChestCount} chest(s), Enable_Auto_Fueling={enableAutoFueling.Value}.")); hookedStationCount = 0; } } private void LogPlayerProximityDiagnostics() { //IL_0090: 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_009b: 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) //IL_0117: 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) if (!logScanSummary.Value || scanCount % 5 != 0 || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return; } List<PlayerInfo> playerList = ZNet.instance.GetPlayerList(); if (playerList.Count == 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Diagnostics: ZNet.GetPlayerList() returned 0 players server-side."); return; } foreach (ZDO allPersistedZdo in GetAllPersistedZdos()) { if (allPersistedZdo.GetPrefab() != stoneOvenPrefabHash) { continue; } float num = float.MaxValue; foreach (PlayerInfo item in playerList) { float num2 = Vector3.Distance(item.m_position, allPersistedZdo.GetPosition()); if (num2 < num) { num = num2; } } bool flag = ZNetScene.instance.HaveInstance(allPersistedZdo); GameObject val = (flag ? ZNetScene.instance.FindInstance(allPersistedZdo.m_uid) : null); bool flag2 = (Object)(object)val != (Object)null && (Object)(object)val.GetComponentInChildren<CookingStation>(true) != (Object)null; ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Diagnostics: Stone Oven {allPersistedZdo.m_uid} at {allPersistedZdo.GetPosition()} - nearest player {num:F1}m away, " + $"ZNetScene.HaveInstance={flag}, hasLiveCookingStation={flag2}.")); } } private void ProcessCookingStation(CookingStation oven) { //IL_00bd: 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) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)oven == (Object)null || !((Behaviour)oven).isActiveAndEnabled) { return; } ZNetView component = ((Component)oven).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || stoneOvenPrefabHash == 0 || component.GetZDO().GetPrefab() != stoneOvenPrefabHash) { return; } int instanceID = ((Object)oven).GetInstanceID(); if (!nextStationScans.TryGetValue(instanceID, out var value) || !(Time.time < value)) { nextStationScans[instanceID] = Time.time + Mathf.Max(0.25f, scanInterval.Value); hookedStationCount++; List<Container> list = FindNearbyChests(((Component)oven).transform.position); if (logScanSummary.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Processing Stone Oven '{((Object)oven).name}' at {((Component)oven).transform.position}: found {list.Count} nearby chest(s) within {scanDistance.Value}m."); } UnloadFinishedItems(oven, list); if (enableAutoFueling.Value) { FuelOven(oven, list); } LoadBakeableItems(oven, list); } } private void InitializeStoneOvenHash() { if (stoneOvenPrefabHash == 0 && !stoneOvenHashInitializationFailed && !((Object)(object)ZNetScene.instance == (Object)null)) { GameObject prefab = ZNetScene.instance.GetPrefab("piece_oven"); CookingStation val = ((prefab != null) ? prefab.GetComponentInChildren<CookingStation>(true) : null); if ((Object)(object)val == (Object)null) { stoneOvenHashInitializationFailed = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not verify Stone Oven prefab 'piece_oven'. Stone Oven automation remains disabled."); } else { stoneOvenPrefabHash = ZNetScene.instance.GetPrefabHash(prefab); ((BaseUnityPlugin)this).Logger.LogInfo((object)(string.Format("Detected Stone Oven prefab '{0}' with hash {1} for this server session. ", "piece_oven", stoneOvenPrefabHash) + $"m_requireFire={val.m_requireFire}, m_useFuel={val.m_useFuel}, m_useFueldWhileEmpty={val.m_useFueldWhileEmpty}, " + string.Format("m_fuelItem={0}, m_maxFuel={1}, m_secPerFuel={2}, ", ((Object)(object)val.m_fuelItem != (Object)null) ? ((Object)val.m_fuelItem).name : "null", val.m_maxFuel, val.m_secPerFuel) + $"slots={val.m_slots.Length}.")); } } } private void ProcessPersistedCookingStations() { if (stoneOvenPrefabHash == 0 || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return; } List<PersistedContainer> list = FindPersistedContainers(); persistedOvenCount = 0; persistedChestCount = list.Count; liveSkippedOvenCount = 0; foreach (ZDO oven in GetAllPersistedZdos()) { if (oven.GetPrefab() != stoneOvenPrefabHash) { continue; } if (IsCookingStationLive(oven)) { liveSkippedOvenCount++; continue; } GameObject prefab = ZNetScene.instance.GetPrefab(stoneOvenPrefabHash); CookingStation val = ((prefab != null) ? prefab.GetComponentInChildren<CookingStation>(true) : null); if ((Object)(object)val == (Object)null) { continue; } List<PersistedContainer> chests = (from container in list where Vector3.Distance(oven.GetPosition(), container.Zdo.GetPosition()) <= Mathf.Max(0f, scanDistance.Value) orderby Vector3.Distance(oven.GetPosition(), container.Zdo.GetPosition()) select container).ToList(); if (ClaimZdoOwnership(oven)) { persistedOvenCount++; LogPersistedCookingStationState(oven, val); AdvancePersistedCooking(oven, val); UnloadPersistedCookingStationItems(oven, val, chests); if (enableAutoFueling.Value) { FuelPersistedCookingStation(oven, val, chests); } LoadPersistedCookingStationItems(oven, val, chests); } } } private void AdvancePersistedCooking(ZDO oven, CookingStation station) { DateTime time = ZNet.instance.GetTime(); DateTime dateTime = new DateTime(oven.GetLong(ZDOVars.s_startTime, time.Ticks)); float num = (float)(time - dateTime).TotalSeconds; oven.Set(ZDOVars.s_startTime, time.Ticks); if (num <= 0f) { return; } float num2 = oven.GetFloat(ZDOVars.s_fuel, 0f); bool flag = HasUncookedPersistedItem(oven, station); if (station.m_useFuel && station.m_secPerFuel > 0) { num2 = Mathf.Max(0f, num2 - num / (float)station.m_secPerFuel); oven.Set(ZDOVars.s_fuel, num2); } bool requireFire = station.m_requireFire; bool flag2 = station.m_useFuel && num2 > 0f && (station.m_useFueldWhileEmpty || flag); bool flag3 = requireFire || flag2; if (logScanSummary.Value && scanCount % 20 == 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Persisted Stone Oven fuel={num2:F2}/{station.m_maxFuel}, hasUncookedItem={flag}, " + $"cooking={flag3} (fire={requireFire}, fuel={flag2}), Enable_Auto_Fueling={enableAutoFueling.Value}.")); } if (!flag3) { if (logScanSummary.Value && scanCount % 20 == 0 && station.m_useFuel && num2 <= 0f) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Persisted Stone Oven has no fuel, so cooking cannot progress until fuel is added (manually or via Enable_Auto_Fueling)."); } return; } for (int i = 0; i < station.m_slots.Length; i++) { string itemName = oven.GetString("slot" + i, ""); if (itemName.Length == 0 || oven.GetInt("slotstatus" + i, 0) != 0) { continue; } ItemConversion val = ((IEnumerable<ItemConversion>)station.m_conversion).FirstOrDefault((Func<ItemConversion, bool>)((ItemConversion entry) => (Object)(object)entry.m_from != (Object)null && ((Object)((Component)entry.m_from).gameObject).name == itemName)); if ((Object)(object)val?.m_from == (Object)null) { oven.Set("slot" + i, ""); oven.Set("slot" + i, 0f); oven.Set("slotstatus" + i, 0); continue; } float num3 = oven.GetFloat("slot" + i, 0f) + num; if (station.m_canOvercookItems && (Object)(object)station.m_overCookedItem != (Object)null && num3 > val.m_cookTime * 2f) { oven.Set("slot" + i, ((Object)((Component)station.m_overCookedItem).gameObject).name); oven.Set("slot" + i, num3); oven.Set("slotstatus" + i, 2); if (logScanSummary.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Persisted Stone Oven slot {i} burnt while unattended."); } } else if (num3 > val.m_cookTime && (Object)(object)val.m_to != (Object)null) { oven.Set("slot" + i, ((Object)((Component)val.m_to).gameObject).name); oven.Set("slot" + i, num3); oven.Set("slotstatus" + i, 1); if (logScanSummary.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Persisted Stone Oven slot {i} finished cooking while unattended."); } } else { oven.Set("slot" + i, num3); } } ZDOMan.instance.SetDirtySector(oven); } private static bool HasUncookedPersistedItem(ZDO oven, CookingStation station) { for (int i = 0; i < station.m_slots.Length; i++) { if (oven.GetString("slot" + i, "").Length > 0 && oven.GetInt("slotstatus" + i, 0) == 0) { return true; } } return false; } private void UnloadPersistedCookingStationItems(ZDO oven, CookingStation station, List<PersistedContainer> chests) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0133: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < station.m_slots.Length; i++) { string text = oven.GetString("slot" + i, ""); if (text.Length == 0 || oven.GetInt("slotstatus" + i, 0) == 0) { continue; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { continue; } ItemData item = val.m_itemData.Clone(); item.m_stack = 1; PersistedContainer persistedContainer = chests.FirstOrDefault(delegate(PersistedContainer chest) { Inventory val2 = LoadInventory(chest); return val2.HaveItem(item.m_shared.m_name, true) && val2.CanAddItem(item, -1); }); if (persistedContainer == null) { persistedContainer = chests.FirstOrDefault((PersistedContainer chest) => LoadInventory(chest).CanAddItem(item, -1)); } bool flag = persistedContainer != null && TryAddToPersistedContainer(persistedContainer, item); if (!flag) { ItemDrop.DropItem(item, item.m_stack, oven.GetPosition() + Vector3.up, Quaternion.identity); } if (logScanSummary.Value) { string arg = (flag ? $"chest {persistedContainer.Zdo.m_uid}" : "the ground fallback"); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Removed completed {text} from persisted Stone Oven slot {i} and stored it in {arg}."); } oven.Set("slot" + i, ""); oven.Set("slot" + i, 0f); oven.Set("slotstatus" + i, 0); ZDOMan.instance.SetDirtySector(oven); } } private void FuelPersistedCookingStation(ZDO oven, CookingStation station, List<PersistedContainer> chests) { if ((Object)(object)station.m_fuelItem == (Object)null || station.m_maxFuel <= 0) { return; } string fuelName = station.m_fuelItem.m_itemData.m_shared.m_name; while (oven.GetFloat(ZDOVars.s_fuel, 0f) < (float)station.m_maxFuel) { PersistedContainer persistedContainer = chests.FirstOrDefault((PersistedContainer chest) => ClaimZdoOwnership(chest.Zdo) && LoadInventory(chest).GetItem(fuelName, -1, false) != null); if (persistedContainer == null) { break; } oven.Set(ZDOVars.s_fuel, oven.GetFloat(ZDOVars.s_fuel, 0f) + 1f); if (!TryRemoveFromPersistedContainer(persistedContainer, fuelName)) { break; } ZDOMan.instance.SetDirtySector(oven); } } private void LoadPersistedCookingStationItems(ZDO oven, CookingStation station, List<PersistedContainer> chests) { //IL_01d0: Unknown result type (might be due to invalid IL or missing references) foreach (PersistedContainer chest in chests) { if (!ClaimZdoOwnership(chest.Zdo)) { continue; } Inventory val = LoadInventory(chest); foreach (ItemData item in val.GetAllItems().ToList()) { string itemName = ((Object)item.m_dropPrefab).name; if (!station.m_conversion.Any((ItemConversion conversion) => (Object)(object)conversion.m_from != (Object)null && ((Object)((Component)conversion.m_from).gameObject).name == itemName)) { continue; } int stack = item.m_stack; for (int num = 0; num < stack; num++) { int num2 = FindFreePersistedCookingStationSlot(oven, station); if (num2 < 0) { return; } oven.Set("slot" + num2, itemName); oven.Set("slot" + num2, 0f); oven.Set("slotstatus" + num2, 0); oven.Set(ZDOVars.s_cheatedQueued + num2, item.m_cheated); ZDOMan.instance.SetDirtySector(oven); if (oven.GetString("slot" + num2, "") != itemName) { oven.Set("slot" + num2, ""); oven.Set("slot" + num2, 0f); oven.Set("slotstatus" + num2, 0); continue; } val.RemoveItem(item, 1); SaveInventory(chest, val); if (logScanSummary.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Loaded {itemName} into persisted Stone Oven slot {num2} from chest {chest.Zdo.m_uid}."); } } } } } private void LogPersistedCookingStationState(ZDO oven, CookingStation station) { if (logScanSummary.Value && scanCount % 20 == 0) { string[] value = (from slot in Enumerable.Range(0, station.m_slots.Length) select string.Format("{0}='{1}'/{2:F2}/{3}", slot, oven.GetString("slot" + slot, ""), oven.GetFloat("slot" + slot, 0f), oven.GetInt("slotstatus" + slot, 0))).ToArray(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Persisted Stone Oven slots: " + string.Join(", ", value) + ".")); } } private static int FindFreePersistedCookingStationSlot(ZDO oven, CookingStation station) { for (int i = 0; i < station.m_slots.Length; i++) { if (oven.GetString("slot" + i, "").Length == 0) { return i; } } return -1; } private List<PersistedContainer> FindPersistedContainers() { List<PersistedContainer> list = new List<PersistedContainer>(); foreach (ZDO allPersistedZdo in GetAllPersistedZdos()) { if (allPersistedZdo.GetInt(ZDOVars.s_inUse, 0) == 1) { continue; } GameObject prefab = ZNetScene.instance.GetPrefab(allPersistedZdo.GetPrefab()); if (!((Object)(object)prefab == (Object)null)) { Container componentInChildren = prefab.GetComponentInChildren<Container>(true); if (!((Object)(object)componentInChildren == (Object)null) && IsPlayerChest(componentInChildren)) { list.Add(new PersistedContainer(allPersistedZdo, componentInChildren)); } } } return list; } private static bool IsStoneOven(Smelter smelter) { return smelter.m_name.IndexOf("oven", StringComparison.OrdinalIgnoreCase) >= 0; } private static bool IsPlayerChest(Container container) { return container.m_name.IndexOf("chest", StringComparison.OrdinalIgnoreCase) >= 0; } private static IEnumerable<ZDO> GetAllPersistedZdos() { if (typeof(ZDOMan).GetField("m_objectsByID", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(ZDOMan.instance) is Dictionary<ZDOID, ZDO> dictionary) { return dictionary.Values.ToList(); } return Array.Empty<ZDO>(); } private void UnloadPersistedSmelterItems(ZDO oven, Smelter smelter, List<PersistedContainer> chests) { //IL_00bf: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) int num = oven.GetInt(ZDOVars.s_spawnAmount, 0); string inputName = oven.GetString(ZDOVars.s_spawnOre, ""); ItemConversion val = ((IEnumerable<ItemConversion>)smelter.m_conversion).FirstOrDefault((Func<ItemConversion, bool>)((ItemConversion entry) => (Object)(object)entry.m_from != (Object)null && ((Object)((Component)entry.m_from).gameObject).name == inputName)); if (num > 0 && !((Object)(object)val?.m_to == (Object)null)) { ItemData item = val.m_to.m_itemData.Clone(); item.m_stack = num; PersistedContainer persistedContainer = chests.FirstOrDefault((PersistedContainer chest) => LoadInventory(chest).HaveItem(item.m_shared.m_name, true)); if (persistedContainer == null) { persistedContainer = chests.FirstOrDefault(); } if (persistedContainer == null || !TryAddToPersistedContainer(persistedContainer, item)) { ItemDrop.DropItem(item, item.m_stack, oven.GetPosition() + Vector3.up, Quaternion.identity); } oven.Set(ZDOVars.s_spawnOre, ""); oven.Set(ZDOVars.s_spawnAmount, 0, false); ZDOMan.instance.SetDirtySector(oven); } } private void FuelPersistedSmelter(ZDO oven, Smelter smelter, List<PersistedContainer> chests) { if ((Object)(object)smelter.m_fuelItem == (Object)null || smelter.m_maxFuel <= 0) { return; } string fuelName = smelter.m_fuelItem.m_itemData.m_shared.m_name; while (oven.GetFloat(ZDOVars.s_fuel, 0f) < (float)smelter.m_maxFuel) { PersistedContainer persistedContainer = chests.FirstOrDefault((PersistedContainer chest) => LoadInventory(chest).GetItem(fuelName, -1, false) != null); if (persistedContainer == null || !TryRemoveFromPersistedContainer(persistedContainer, fuelName)) { break; } oven.Set(ZDOVars.s_fuel, oven.GetFloat(ZDOVars.s_fuel, 0f) + 1f); ZDOMan.instance.SetDirtySector(oven); } } private void LoadPersistedSmelterItems(ZDO oven, Smelter smelter, List<PersistedContainer> chests) { foreach (PersistedContainer chest in chests) { Inventory val = LoadInventory(chest); foreach (ItemData item in val.GetAllItems().ToList()) { if (oven.GetInt(ZDOVars.s_queued, 0) >= smelter.m_maxOre) { return; } string itemName = ((Object)item.m_dropPrefab).name; if (smelter.m_conversion.Any((ItemConversion conversion) => (Object)(object)conversion.m_from != (Object)null && ((Object)((Component)conversion.m_from).gameObject).name == itemName)) { val.RemoveItem(item, 1); SaveInventory(chest, val); int num = oven.GetInt(ZDOVars.s_queued, 0); oven.Set("item" + num, itemName); oven.Set(ZDOVars.s_queued, num + 1, false); oven.Set(ZDOVars.s_cheatedQueued, item.m_cheated); ZDOMan.instance.SetDirtySector(oven); } } } } private static Inventory LoadInventory(PersistedContainer container) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown Inventory val = new Inventory(container.Prefab.m_name, container.Prefab.m_bkg, container.Prefab.m_width, container.Prefab.m_height); byte[] byteArray = container.Zdo.GetByteArray(ZDOVars.s_items, (byte[])null); if (byteArray != null) { val.Load(new ZPackage(byteArray)); } return val; } private static void SaveInventory(PersistedContainer container, Inventory inventory) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); inventory.Save(val); container.Zdo.Set(ZDOVars.s_items, val.GetArray()); ZDOMan.instance.SetDirtySector(container.Zdo); } private static bool TryAddToPersistedContainer(PersistedContainer container, ItemData item) { if (!ClaimZdoOwnership(container.Zdo)) { return false; } Inventory val = LoadInventory(container); if (!val.AddItem(item)) { return false; } SaveInventory(container, val); return true; } private static bool TryRemoveFromPersistedContainer(PersistedContainer container, string itemName) { if (!ClaimZdoOwnership(container.Zdo)) { return false; } Inventory val = LoadInventory(container); ItemData item = val.GetItem(itemName, -1, false); if (item == null) { return false; } val.RemoveItem(item, 1); SaveInventory(container, val); return true; } private static bool IsCookingStationLive(ZDO oven) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!ZNetScene.instance.HaveInstance(oven)) { return false; } GameObject val = ZNetScene.instance.FindInstance(oven.m_uid); CookingStation val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren<CookingStation>(true) : null); if ((Object)(object)val2 != (Object)null) { return ((Behaviour)val2).isActiveAndEnabled; } return false; } private static bool ClaimZdoOwnership(ZDO zdo) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { zdo.SetOwner(ZDOMan.GetSessionID()); return zdo.IsOwner(); } long sessionID = ZDOMan.GetSessionID(); long owner = zdo.GetOwner(); if (owner != 0L && owner != sessionID) { return false; } zdo.SetOwner(ZDOMan.GetSessionID()); return zdo.IsOwner(); } private void UnloadFinishedSmelterItems(Smelter oven, List<Container> chests) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)oven).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); int num = zDO.GetInt(ZDOVars.s_spawnAmount, 0); string inputName = zDO.GetString(ZDOVars.s_spawnOre, ""); ItemConversion val = ((IEnumerable<ItemConversion>)oven.m_conversion).FirstOrDefault((Func<ItemConversion, bool>)((ItemConversion entry) => (Object)(object)entry.m_from != (Object)null && ((Object)((Component)entry.m_from).gameObject).name == inputName)); if (num > 0 && !((Object)(object)val?.m_to == (Object)null)) { ItemData item = val.m_to.m_itemData.Clone(); item.m_stack = num; Container val2 = ((IEnumerable<Container>)chests).FirstOrDefault((Func<Container, bool>)((Container chest) => chest.GetInventory().HaveItem(item.m_shared.m_name, true))); if (val2 == null) { val2 = chests.FirstOrDefault(); } if (!((Object)(object)val2 != (Object)null) || !ClaimContainerOwnership(val2) || !val2.GetInventory().AddItem(item)) { ItemDrop.DropItem(item, item.m_stack, ((Component)oven).transform.position + Vector3.up, Quaternion.identity); } component.ClaimOwnership(); zDO.Set(ZDOVars.s_spawnOre, ""); zDO.Set(ZDOVars.s_spawnAmount, 0, false); } } private void FuelSmelter(Smelter oven, List<Container> chests) { if ((Object)(object)oven.m_fuelItem == (Object)null || oven.m_maxFuel <= 0) { return; } ZNetView component = ((Component)oven).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } string fuelName = oven.m_fuelItem.m_itemData.m_shared.m_name; ZDO zDO = component.GetZDO(); while (zDO.GetFloat(ZDOVars.s_fuel, 0f) < (float)oven.m_maxFuel) { Container val = ((IEnumerable<Container>)chests).FirstOrDefault((Func<Container, bool>)((Container chest) => chest.GetInventory().GetItem(fuelName, -1, false) != null)); if ((Object)(object)val == (Object)null || !ClaimContainerOwnership(val)) { break; } ItemData item = val.GetInventory().GetItem(fuelName, -1, false); if (item != null) { component.ClaimOwnership(); val.GetInventory().RemoveItem(item, 1); zDO.Set(ZDOVars.s_fuel, zDO.GetFloat(ZDOVars.s_fuel, 0f) + 1f); } } } private void LoadSmelterItems(Smelter oven, List<Container> chests) { ZNetView component = ((Component)oven).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); foreach (Container chest in chests) { foreach (ItemData item in chest.GetInventory().GetAllItems().ToList()) { if (zDO.GetInt(ZDOVars.s_queued, 0) >= oven.m_maxOre) { return; } string itemName = ((Object)item.m_dropPrefab).name; if (oven.m_conversion.Any((ItemConversion conversion) => (Object)(object)conversion.m_from != (Object)null && ((Object)((Component)conversion.m_from).gameObject).name == itemName) && ClaimContainerOwnership(chest)) { component.ClaimOwnership(); int num = zDO.GetInt(ZDOVars.s_queued, 0); chest.GetInventory().RemoveItem(item, 1); zDO.Set("item" + num, itemName); zDO.Set(ZDOVars.s_queued, num + 1, false); zDO.Set(ZDOVars.s_cheatedQueued, item.m_cheated); } } } } private List<Container> FindNearbyChests(Vector3 position) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return (from container in Object.FindObjectsOfType<Container>() where (Object)(object)container != (Object)null && ((Behaviour)container).isActiveAndEnabled && IsPlayerChest(container) select new { Container = container, Distance = Vector3.Distance(position, ((Component)container).transform.position) } into entry where entry.Distance <= Mathf.Max(0f, scanDistance.Value) orderby entry.Distance select entry.Container).ToList(); } private void LoadBakeableItems(CookingStation oven, List<Container> chests) { bool flag; do { flag = false; foreach (Container chest in chests) { if (!OvenSlots.HasFreeSlot(oven)) { return; } foreach (ItemData item in chest.GetInventory().GetAllItems().ToList()) { if (!OvenSlots.HasFreeSlot(oven)) { return; } if (TryAddToOven(oven, chest, item)) { flag = true; } } } } while (flag); } private void FuelOven(CookingStation oven, List<Container> chests) { ItemDrop fuelItem = oven.m_fuelItem; if ((Object)(object)fuelItem == (Object)null || oven.m_maxFuel <= 0) { return; } MethodInfo method = ((object)oven).GetType().GetMethod("GetFuel", BindingFlags.Instance | BindingFlags.NonPublic); MethodInfo method2 = ((object)oven).GetType().GetMethod("RPC_AddFuel", BindingFlags.Instance | BindingFlags.NonPublic); ZNetView component = ((Component)oven).GetComponent<ZNetView>(); if (method == null || method2 == null || (Object)(object)component == (Object)null || !component.IsValid()) { LogAdapterWarning("CookingStation fuel API or ZNetView was not found."); return; } string name = fuelItem.m_itemData.m_shared.m_name; while (Convert.ToSingle(method.Invoke(oven, null)) < (float)oven.m_maxFuel) { bool flag = false; foreach (Container chest in chests) { Inventory inventory = chest.GetInventory(); ItemData item = inventory.GetItem(name, -1, false); if (item != null && ClaimContainerOwnership(chest)) { component.ClaimOwnership(); float num = Convert.ToSingle(method.Invoke(oven, null)); method2.Invoke(oven, new object[1] { 0L }); if (!(Convert.ToSingle(method.Invoke(oven, null)) <= num)) { inventory.RemoveItem(item, 1); flag = true; break; } } } if (!flag) { break; } } } private void UnloadFinishedItems(CookingStation oven, List<Container> chests) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_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) int slot; do { if (!OvenSlots.TryTakeFinished(oven, out ItemData item, out slot)) { break; } Container val = ((IEnumerable<Container>)chests).FirstOrDefault((Func<Container, bool>)delegate(Container chest) { Inventory inventory = chest.GetInventory(); return inventory.HaveItem(item.m_shared.m_name, true) && inventory.CanAddItem(item, -1); }); if (val == null) { val = ((IEnumerable<Container>)chests).FirstOrDefault((Func<Container, bool>)((Container chest) => chest.GetInventory().CanAddItem(item, -1))); } bool flag = (Object)(object)val != (Object)null && ClaimContainerOwnership(val) && val.GetInventory().AddItem(item); if (!flag) { ItemDrop.DropItem(item, item.m_stack, ((Component)oven).transform.position + Vector3.up, Quaternion.identity); } if (logScanSummary.Value) { string text = (flag ? ("chest '" + ((Object)val).name + "'") : "the ground fallback"); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Removed finished '{item.m_shared.m_name}' from oven '{((Object)oven).name}' slot {slot} and stored it in {text}."); } } while (OvenSlots.RemoveFinished(oven, slot)); } private bool TryAddToOven(CookingStation oven, Container chest, ItemData item) { try { Inventory inventory = chest.GetInventory(); ZNetView component = ((Component)oven).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { LogAdapterWarning("CookingStation has no valid ZNetView."); return false; } string itemName = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null); if (itemName == null) { if (logScanSummary.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Skipped '" + item.m_shared.m_name + "' from chest '" + ((Object)chest).name + "': item has no m_dropPrefab reference.")); } return false; } if (!oven.m_conversion.Any((ItemConversion conversion) => (Object)(object)conversion.m_from != (Object)null && ((Object)((Component)conversion.m_from).gameObject).name == itemName)) { if (logScanSummary.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Skipped '" + itemName + "': not a bakeable item for oven '" + ((Object)oven).name + "' (no matching m_conversion entry).")); } return false; } int num = OvenSlots.FindFreeSlot(oven); if (num < 0) { if (logScanSummary.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Skipped '" + itemName + "': oven '" + ((Object)oven).name + "' has no free slot.")); } return false; } if (!ClaimContainerOwnership(chest)) { if (logScanSummary.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Skipped '" + itemName + "': could not claim ownership of chest '" + ((Object)chest).name + "'.")); } return false; } component.ClaimOwnership(); MethodInfo method = typeof(CookingStation).GetMethod("RPC_AddItem", BindingFlags.Instance | BindingFlags.NonPublic); if (method == null) { LogAdapterWarning("CookingStation.RPC_AddItem was not found."); return false; } method.Invoke(oven, new object[3] { 0L, itemName, item.m_cheated }); if (!OvenSlots.SlotContainsItem(oven, num, itemName)) { if (logScanSummary.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"'{itemName}' was not confirmed in oven '{((Object)oven).name}' slot {num} after RPC_AddItem."); } return false; } component.InvokeRPC(ZNetView.Everybody, "RPC_SetSlotVisual", new object[2] { num, itemName }); inventory.RemoveItem(item, 1); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not load " + item.m_shared.m_name + " into an oven: " + ex.GetBaseException().Message)); return false; } } private static bool ClaimContainerOwnership(Container container) { ZNetView val = ((Component)container).GetComponent<ZNetView>() ?? ((Component)container).GetComponentInParent<ZNetView>(); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } val.ClaimOwnership(); return val.IsOwner(); } private void LogAdapterWarning(string message) { if (!adapterWarningLogged) { adapterWarningLogged = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)(message + " Finished-item automation is disabled for this Valheim build.")); } } } }