using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using HeatCooking.Core; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; using UnityEngine.SceneManagement; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("HeatCooking")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+fbc75cb5c10e1fc8becd1288c3855066536c08fd")] [assembly: AssemblyProduct("HeatCooking")] [assembly: AssemblyTitle("HeatCooking")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace HeatCooking { [BepInPlugin("jill920.heatcooking", "Heat Cooking", "1.0.0")] public class Plugin : BaseUnityPlugin { public static Plugin Instance; public static ManualLogSource Log; public static ConfigEntry DebugLogging; public static ConfigEntry CookSpeedMultiplier; public static ConfigEntry CookHeldItems; public static ConfigEntry CookBackpackItems; public static ConfigEntry MinimumCookSpeed; private Harmony _harmony; private bool _managerCreated = false; private void Awake() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; DebugLogging = ((BaseUnityPlugin)this).Config.Bind("General", "DebugLogging", false, "Enable detailed debug logging"); CookSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind("General", "CookSpeedMultiplier", 10f, new ConfigDescription("Multiplier for cooking speed", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 100f), Array.Empty())); CookHeldItems = ((BaseUnityPlugin)this).Config.Bind("General", "CookHeldItems", false, "Whether held items should also be cooked"); CookBackpackItems = ((BaseUnityPlugin)this).Config.Bind("General", "CookBackpackItems", false, "Whether items inside backpacks should also be cooked"); MinimumCookSpeed = ((BaseUnityPlugin)this).Config.Bind("General", "MinimumCookSpeed", 0.01f, new ConfigDescription("Minimum cooking speed", (AcceptableValueBase)(object)new AcceptableValueRange(0.001f, 1f), Array.Empty())); _harmony = new Harmony("jill920.heatcooking"); _harmony.PatchAll(); Log.LogInfo((object)"========================================"); Log.LogInfo((object)"[HeatCooking] LOADED v1.0.0"); Log.LogInfo((object)$" CookSpeedMultiplier: {CookSpeedMultiplier.Value}"); Log.LogInfo((object)$" CookHeldItems: {CookHeldItems.Value}"); Log.LogInfo((object)$" CookBackpackItems: {CookBackpackItems.Value}"); Log.LogInfo((object)$" MinimumCookSpeed: {MinimumCookSpeed.Value}"); Log.LogInfo((object)"========================================"); } private void Update() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_005e: Expected O, but got Unknown if (_managerCreated || !PhotonNetwork.IsConnected) { return; } Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (name.StartsWith("Level")) { _managerCreated = true; if (PhotonNetwork.IsMasterClient) { GameObject val = new GameObject("HeatCookingManager"); val.AddComponent(); LogDebug("HeatCookingManager created (host)"); } else { LogDebug("HeatCookingManager: Not host"); } } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void LogDebug(string message) { if (DebugLogging.Value && Log != null) { Log.LogInfo((object)("[DEBUG] " + message)); } } internal static void LogInfo(string message) { if (Log != null) { Log.LogInfo((object)("[INFO] " + message)); } } internal static void LogWarning(string message) { if (Log != null) { Log.LogWarning((object)("[WARN] " + message)); } } } } namespace HeatCooking.Patches { [HarmonyPatch] internal static class Campfire_CookPatch { [HarmonyPatch(typeof(ItemCooking), "FinishCooking")] [HarmonyPrefix] private static void Prefix_FinishCooking(ItemCooking __instance) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) Item val = ((ItemComponent)(__instance?)).item; if (!((Object)(object)val == (Object)null)) { Character trueHolderCharacter = val.trueHolderCharacter; string text = (((Object)(object)trueHolderCharacter != (Object)null) ? trueHolderCharacter.characterName : "None"); object[] obj = new object[4] { val.UIData?.itemName ?? "Unknown", text, val.itemState, null }; PhotonView photonView = ((MonoBehaviourPun)val).photonView; obj[3] = ((photonView != null) ? new int?(photonView.ViewID) : ((int?)null)); Plugin.LogDebug(string.Format("\ud83d\udd25\ud83d\udd25\ud83d\udd25 FinishCooking called on {0} (holder: {1}, state: {2}, photonView: {3})", obj)); } } [HarmonyPatch(typeof(ItemCooking), "EnableCookingSmokeRPC")] [HarmonyPrefix] private static void Prefix_EnableCookingSmokeRPC(ItemCooking __instance, bool active) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) Item val = ((ItemComponent)(__instance?)).item; if (!((Object)(object)val == (Object)null)) { Character trueHolderCharacter = val.trueHolderCharacter; string text = (((Object)(object)trueHolderCharacter != (Object)null) ? trueHolderCharacter.characterName : "None"); Plugin.LogDebug(string.Format("\ud83d\udca8\ud83d\udca8\ud83d\udca8 EnableCookingSmokeRPC called: active={0} on {1} (holder: {2}, state: {3})", active, val.UIData?.itemName ?? "Unknown", text, val.itemState)); } } [HarmonyPatch(typeof(ItemCooking), "FinishCookingRPC")] [HarmonyPrefix] private static void Prefix_FinishCookingRPC(ItemCooking __instance) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) Item val = ((ItemComponent)(__instance?)).item; if (!((Object)(object)val == (Object)null)) { Character trueHolderCharacter = val.trueHolderCharacter; string text = (((Object)(object)trueHolderCharacter != (Object)null) ? trueHolderCharacter.characterName : "None"); object[] obj = new object[4] { val.UIData?.itemName ?? "Unknown", text, val.itemState, null }; PhotonView photonView = ((MonoBehaviourPun)val).photonView; obj[3] = ((photonView != null) ? new int?(photonView.ViewID) : ((int?)null)); Plugin.LogDebug(string.Format("\ud83d\udce1\ud83d\udce1\ud83d\udce1 FinishCookingRPC called on {0} (holder: {1}, state: {2}, photonView: {3})", obj)); } } [HarmonyPatch(typeof(Item), "SetCookedAmountRPC")] [HarmonyPrefix] private static void Prefix_SetCookedAmountRPC(Item __instance, int amount) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null)) { Character trueHolderCharacter = __instance.trueHolderCharacter; string text = (((Object)(object)trueHolderCharacter != (Object)null) ? trueHolderCharacter.characterName : "None"); object[] obj = new object[5] { amount, __instance.UIData?.itemName ?? "Unknown", text, __instance.itemState, null }; PhotonView photonView = ((MonoBehaviourPun)__instance).photonView; obj[4] = ((photonView != null) ? new int?(photonView.ViewID) : ((int?)null)); Plugin.LogDebug(string.Format("\ud83c\udf73\ud83c\udf73\ud83c\udf73 SetCookedAmountRPC called: amount={0} on {1} (holder: {2}, state: {3}, photonView: {4})", obj)); } } [HarmonyPatch(typeof(ItemCooking), "UpdateCookedBehavior")] [HarmonyPostfix] private static void Postfix_UpdateCookedBehavior(ItemCooking __instance) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) Item val = ((ItemComponent)(__instance?)).item; if (!((Object)(object)val == (Object)null)) { IntItemData data = val.GetData((DataEntryKey)1); if (data != null && data.Value > 0) { Character trueHolderCharacter = val.trueHolderCharacter; string text = (((Object)(object)trueHolderCharacter != (Object)null) ? trueHolderCharacter.characterName : "None"); Plugin.LogDebug(string.Format("\ud83d\udd04 UpdateCookedBehavior: {0} now cooked to level {1} (holder: {2}, state: {3})", val.UIData?.itemName ?? "Unknown", data.Value, text, val.itemState)); } } } } [HarmonyPatch(typeof(CharacterItems), "EquipSlotRpc")] internal static class EquipSlotRpcPatch { private static FieldInfo _characterField; private static FieldInfo _currentSelectedSlotField; static EquipSlotRpcPatch() { _characterField = typeof(CharacterItems).GetField("character", BindingFlags.Instance | BindingFlags.NonPublic); _currentSelectedSlotField = typeof(CharacterItems).GetField("currentSelectedSlot", BindingFlags.Instance | BindingFlags.NonPublic); } [HarmonyPostfix] private static void Postfix(CharacterItems __instance, int slotID, int objectViewID) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Invalid comparison between Unknown and I4 //IL_0138: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient) { return; } Character val = null; if (_characterField != null) { object? value = _characterField.GetValue(__instance); val = (Character)((value is Character) ? value : null); } if ((Object)(object)val == (Object)null) { return; } Optionable val2 = Optionable.None; if (_currentSelectedSlotField != null) { val2 = (Optionable)_currentSelectedSlotField.GetValue(__instance); } Item val3 = null; foreach (Item aLL_ACTIVE_ITEM in Item.ALL_ACTIVE_ITEMS) { if ((Object)(object)aLL_ACTIVE_ITEM != (Object)null && ClassExtensionsMethods.UnityObjectExists(aLL_ACTIVE_ITEM) && (Object)(object)aLL_ACTIVE_ITEM.trueHolderCharacter == (Object)(object)val && (int)aLL_ACTIVE_ITEM.itemState == 1) { val3 = aLL_ACTIVE_ITEM; break; } } if ((Object)(object)val3 != (Object)null) { HeldItemTracker.SetHeldItem(val, val3); Item heldItem = HeldItemTracker.GetHeldItem(val); if ((Object)(object)heldItem != (Object)(object)val3) { Plugin.LogDebug(string.Format("\ud83d\udce6 Held item: {0} -> {1} (slot: {2})", val.characterName, val3.UIData?.itemName ?? "Unknown", val2)); } } else { HeldItemTracker.SetHeldItem(val, null); Plugin.LogDebug($"\ud83d\udc50 {val.characterName} has empty hands (slot: {val2})"); } } } [HarmonyPatch(typeof(StatusEmitter), "Update")] internal static class StatusEmitter_UpdatePatch { private static HashSet _loggedEmitters = new HashSet(); [HarmonyPostfix] private static void Postfix(StatusEmitter __instance) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_00d6: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.DebugLogging.Value || (int)__instance.statusType != 8) { return; } int instanceID = ((Object)__instance).GetInstanceID(); if (_loggedEmitters.Contains(instanceID)) { return; } bool flag = false; MethodInfo method = typeof(StatusEmitter).GetMethod("InRange", BindingFlags.Instance | BindingFlags.NonPublic); if (method != null) { try { flag = (bool)method.Invoke(__instance, null); } catch { } } if (flag) { _loggedEmitters.Add(instanceID); Plugin.LogDebug($"Hot emitter active: {((Object)__instance).name}, amount: {__instance.amount}, radius: {__instance.radius}, pos: {((Component)__instance).transform.position:F2}"); } } } } namespace HeatCooking.Core { public class CookingTracker { private Dictionary _itemCookTime = new Dictionary(); private List _itemsToRemove = new List(); private HashSet _cookingItems = new HashSet(); private Dictionary _savedProgress = new Dictionary(); public int Count => _itemCookTime.Count; public void Update(float deltaTime) { Cleanup(); } public void Cleanup() { _itemsToRemove.Clear(); foreach (KeyValuePair item in _itemCookTime) { if ((Object)(object)item.Key == (Object)null || !ClassExtensionsMethods.UnityObjectExists(item.Key)) { _itemsToRemove.Add(item.Key); _cookingItems.Remove(item.Key); } } foreach (Item item2 in _itemsToRemove) { _itemCookTime.Remove(item2); } } public bool IsTracking(Item item) { return _itemCookTime.ContainsKey(item); } public float GetProgress(Item item) { float value; return _itemCookTime.TryGetValue(item, out value) ? value : 0f; } public void AddTime(Item item, float time) { if ((Object)(object)item == (Object)null) { return; } float num = 0f; if (_savedProgress.TryGetValue(((Object)item).GetInstanceID(), out var value)) { num = value; if (!_itemCookTime.ContainsKey(item)) { _itemCookTime[item] = value; Plugin.LogDebug(string.Format("\ud83d\udd04 Restored cooking progress for {0}: {1:F2}", item.UIData?.itemName ?? "Unknown", value)); } } if (!_itemCookTime.ContainsKey(item)) { _itemCookTime[item] = 0f; } num = _itemCookTime[item]; _itemCookTime[item] += time; _savedProgress[((Object)item).GetInstanceID()] = _itemCookTime[item]; if (num <= 0f && _itemCookTime[item] > 0f) { _cookingItems.Add(item); StartCookingSmoke(item); } } public bool IsComplete(Item item) { float value; return _itemCookTime.TryGetValue(item, out value) && value >= 1f; } public void Reset(Item item) { if (!((Object)(object)item == (Object)null)) { _itemCookTime.Remove(item); _cookingItems.Remove(item); _savedProgress.Remove(((Object)item).GetInstanceID()); StopCookingSmoke(item); } } public void Remove(Item item) { if (!((Object)(object)item == (Object)null)) { if (_itemCookTime.TryGetValue(item, out var value)) { _savedProgress[((Object)item).GetInstanceID()] = value; Plugin.LogDebug(string.Format("\ud83d\udcbe Saved cooking progress for {0}: {1:F2}", item.UIData?.itemName ?? "Unknown", value)); } _itemCookTime.Remove(item); _cookingItems.Remove(item); StopCookingSmoke(item); } } public bool TryGet(Item item, out float time) { return _itemCookTime.TryGetValue(item, out time); } public bool IsCooking(Item item) { return _cookingItems.Contains(item); } private void StartCookingSmoke(Item item) { if (!((Object)(object)item == (Object)null)) { ItemCooking component = ((Component)item).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)((MonoBehaviourPun)component).photonView != (Object)null) { ((MonoBehaviourPun)component).photonView.RPC("EnableCookingSmokeRPC", (RpcTarget)0, new object[1] { true }); Plugin.LogDebug("\ud83d\udca8 Started cooking smoke for " + (item.UIData?.itemName ?? "Unknown")); } } } private void StopCookingSmoke(Item item) { if (!((Object)(object)item == (Object)null)) { ItemCooking component = ((Component)item).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)((MonoBehaviourPun)component).photonView != (Object)null) { ((MonoBehaviourPun)component).photonView.RPC("EnableCookingSmokeRPC", (RpcTarget)0, new object[1] { false }); Plugin.LogDebug("\ud83d\udca8 Stopped cooking smoke for " + (item.UIData?.itemName ?? "Unknown")); } } } public void StopAllSmoke() { foreach (Item cookingItem in _cookingItems) { if ((Object)(object)cookingItem != (Object)null && ClassExtensionsMethods.UnityObjectExists(cookingItem)) { ItemCooking component = ((Component)cookingItem).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)((MonoBehaviourPun)component).photonView != (Object)null) { ((MonoBehaviourPun)component).photonView.RPC("EnableCookingSmokeRPC", (RpcTarget)0, new object[1] { false }); } } } _cookingItems.Clear(); } public void UpdateSmokeForItem(Item item) { if (!((Object)(object)item == (Object)null)) { bool flag = IsCooking(item); float progress = GetProgress(item); bool flag2 = progress > 0f && progress < 1f; if (flag2 && !flag) { _cookingItems.Add(item); StartCookingSmoke(item); } else if (!flag2 && flag) { _cookingItems.Remove(item); StopCookingSmoke(item); } } } } public class EmitterScanner { private List _cachedEmitters = new List(); private HashSet _loggedEmitterIds = new HashSet(); private bool _initialScanDone = false; private List _allFoundEmitters = new List(); public int TotalCached => _cachedEmitters.Count; public int ActiveCount => GetActiveEmitters().Count; public List GetActiveEmitters() { List list = new List(); foreach (StatusEmitter cachedEmitter in _cachedEmitters) { if ((Object)(object)cachedEmitter != (Object)null && ((Component)cachedEmitter).gameObject.activeInHierarchy) { list.Add(cachedEmitter); } } return list; } public void Scan() { //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Invalid comparison between Unknown and I4 //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0467: Invalid comparison between Unknown and I4 //IL_0494: Unknown result type (might be due to invalid IL or missing references) //IL_0499: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) StatusEmitter[] array = Object.FindObjectsOfType(); StatusEmitter[] array2 = Resources.FindObjectsOfTypeAll(); List list = new List(); HashSet hashSet = new HashSet(); StatusEmitter[] array3 = array; foreach (StatusEmitter val in array3) { if ((Object)(object)val != (Object)null && !hashSet.Contains(((Object)val).GetInstanceID())) { hashSet.Add(((Object)val).GetInstanceID()); list.Add(val); } } StatusEmitter[] array4 = array2; foreach (StatusEmitter val2 in array4) { if ((Object)(object)val2 != (Object)null && !hashSet.Contains(((Object)val2).GetInstanceID())) { hashSet.Add(((Object)val2).GetInstanceID()); list.Add(val2); } } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; bool flag = !_initialScanDone; Scene scene; foreach (StatusEmitter item in list) { if ((Object)(object)item == (Object)null || (int)item.statusType != 8) { continue; } num++; scene = ((Component)item).gameObject.scene; string name = ((Scene)(ref scene)).name; bool activeInHierarchy = ((Component)item).gameObject.activeInHierarchy; float amount = item.amount; Vector3 position = ((Component)item).transform.position; string name2 = ((Object)item).name; bool flag2 = activeInHierarchy || amount > 0.1f || name.StartsWith("Level"); if (flag && flag2) { Plugin.LogDebug($"FOUND: {name2} | pos: {position:F2} | active: {activeInHierarchy} | amount: {amount:F2} | scene: '{name}'"); } if (!name.StartsWith("Level") && !string.IsNullOrEmpty(name)) { num3++; continue; } if (string.IsNullOrEmpty(name) && !activeInHierarchy) { num3++; continue; } if (amount <= 0f) { num4++; continue; } bool flag3 = false; foreach (StatusEmitter cachedEmitter in _cachedEmitters) { if ((Object)(object)cachedEmitter == (Object)(object)item) { flag3 = true; break; } } if (!flag3) { _cachedEmitters.Add(item); num2++; Plugin.LogDebug($"✅ ADDED: {name2} at {position:F2}, active: {activeInHierarchy}, amount: {amount:F2}, scene: '{name}'"); } } if (!_initialScanDone) { _initialScanDone = true; int activeCount = ActiveCount; Plugin.LogInfo($"First scan: found {num} hot emitters, added {num2}, cached: {_cachedEmitters.Count}, active: {activeCount}"); Plugin.LogInfo($" Skipped: scene={num3}, amount={num4}"); } else if (num2 > 0) { Plugin.LogInfo($"Scan: added {num2} new emitters, cached: {_cachedEmitters.Count}, active: {ActiveCount}"); } if (num <= 0 || _cachedEmitters.Count != 0 || Time.frameCount % 120 != 0) { return; } Plugin.LogWarning($"Found {num} emitters but none were cached! Check scene names and amounts."); int num5 = 0; foreach (StatusEmitter item2 in list) { if (!((Object)(object)item2 == (Object)null)) { if (num5 >= 5) { break; } if ((int)item2.statusType == 8) { num5++; object[] obj = new object[4] { ((Object)item2).name, null, null, null }; scene = ((Component)item2).gameObject.scene; obj[1] = ((Scene)(ref scene)).name; obj[2] = ((Component)item2).gameObject.activeInHierarchy; obj[3] = item2.amount; Plugin.LogDebug(string.Format(" Example: {0} | scene: '{1}' | active: {2} | amount: {3}", obj)); } } } } public void LogActiveEmitters() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) List activeEmitters = GetActiveEmitters(); if (activeEmitters.Count <= 0 || Time.frameCount % 60 != 0) { return; } Plugin.LogDebug($"Active emitters ({activeEmitters.Count}):"); foreach (StatusEmitter item in activeEmitters) { Plugin.LogDebug($" - {((Object)item).name} at {((Component)item).transform.position:F2}, radius: {item.radius}, amount: {item.amount}"); } } public void Clear() { _cachedEmitters.Clear(); _loggedEmitterIds.Clear(); _allFoundEmitters.Clear(); _initialScanDone = false; } } public class HeatCookingManager : MonoBehaviour { private EmitterScanner _scanner; private CookingTracker _tracker; private ItemCooker _cooker; private float _cookTimer = 0f; private float _scanTimer = 0f; private const float COOK_INTERVAL = 0.5f; private const float SCAN_INTERVAL = 1f; private int _logCounter = 0; private void Start() { _scanner = new EmitterScanner(); _tracker = new CookingTracker(); _cooker = new ItemCooker(_tracker); _scanner.Scan(); } private void Update() { if (PhotonNetwork.IsMasterClient) { _scanTimer += Time.deltaTime; if (_scanTimer > 1f) { _scanTimer = 0f; _scanner.Scan(); } _cookTimer += Time.deltaTime; if (_cookTimer > 0.5f) { _cookTimer = 0f; CookItems(); } } } private void CookItems() { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Invalid comparison between Unknown and I4 //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Invalid comparison between Unknown and I4 _tracker.Cleanup(); List activeEmitters = _scanner.GetActiveEmitters(); HashSet processedItems = new HashSet(); if (Time.frameCount % 60 == 0) { _scanner.LogActiveEmitters(); } if (Time.frameCount % 30 == 0) { int count = Item.ALL_ACTIVE_ITEMS.Count; Plugin.LogDebug($"=== ALL_ACTIVE_ITEMS ({count} items), Active emitters: {activeEmitters.Count}/{_scanner.TotalCached} ==="); } if (activeEmitters.Count == 0) { return; } int itemsInHeat = 0; int itemsCooking = 0; int itemsCompleted = 0; foreach (Item aLL_ACTIVE_ITEM in Item.ALL_ACTIVE_ITEMS) { if (!((Object)(object)aLL_ACTIVE_ITEM == (Object)null) && ClassExtensionsMethods.UnityObjectExists(aLL_ACTIVE_ITEM) && (int)aLL_ACTIVE_ITEM.itemState == 0 && _cooker.ShouldCookItem(aLL_ACTIVE_ITEM)) { float num = ProcessItemInHeatZone(aLL_ACTIVE_ITEM, activeEmitters, ref itemsInHeat, ref itemsCooking, processedItems); if (num >= 1f) { itemsCompleted++; } } } if (Plugin.CookBackpackItems.Value) { foreach (Item aLL_ACTIVE_ITEM2 in Item.ALL_ACTIVE_ITEMS) { if (!((Object)(object)aLL_ACTIVE_ITEM2 == (Object)null) && ClassExtensionsMethods.UnityObjectExists(aLL_ACTIVE_ITEM2) && (int)aLL_ACTIVE_ITEM2.itemState == 2 && _cooker.ShouldCookItem(aLL_ACTIVE_ITEM2)) { float num2 = ProcessItemInHeatZone(aLL_ACTIVE_ITEM2, activeEmitters, ref itemsInHeat, ref itemsCooking, processedItems); if (num2 >= 1f) { itemsCompleted++; } } } } if (Plugin.CookHeldItems.Value) { CookHeldItems(activeEmitters, processedItems, ref itemsCompleted); } _logCounter++; if (_logCounter % 10 == 0 && (itemsInHeat > 0 || itemsCooking > 0)) { Plugin.LogDebug($"Cooking summary: {itemsCooking} cooking, {itemsInHeat} in heat, {itemsCompleted} completed, {_tracker.Count} tracked"); } } private void CookHeldItems(List activeEmitters, HashSet processedItems, ref int itemsCompleted) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.CookHeldItems.Value || activeEmitters.Count == 0) { return; } HeldItemTracker.Cleanup(); int num = 0; int num2 = 0; foreach (KeyValuePair allHeldItem in HeldItemTracker.GetAllHeldItems()) { Character key = allHeldItem.Key; Item value = allHeldItem.Value; if ((Object)(object)key == (Object)null || (Object)(object)value == (Object)null || !ClassExtensionsMethods.UnityObjectExists(value) || !_cooker.ShouldCookItem(value) || processedItems.Contains(value)) { continue; } Vector3 center = key.Center; bool flag = false; float num3 = float.MaxValue; float num4 = 0f; foreach (StatusEmitter activeEmitter in activeEmitters) { if ((Object)(object)activeEmitter == (Object)null) { continue; } float num5 = Vector3.Distance(center, ((Component)activeEmitter).transform.position); float num6 = activeEmitter.radius + activeEmitter.outerFade; if (num5 <= num6) { flag = true; if (num5 < num3) { num3 = num5; num4 = _cooker.GetCookSpeed(value, activeEmitter); } } } if (flag) { processedItems.Add(value); num++; if (num4 > 0.0001f) { float num7 = _cooker.CookItem(value, num4, 0.5f); if (num7 >= 1f) { itemsCompleted++; Plugin.LogDebug("✅ Client held item completed: " + (value.UIData?.itemName ?? "Unknown") + " held by " + key.characterName); } num2++; } } else if (_tracker.IsTracking(value)) { _tracker.Remove(value); } } if (num > 0 || num2 > 0) { Plugin.LogDebug($"\ud83c\udf73 Client held items: {num2} cooking, {num} in heat"); } } private float ProcessItemInHeatZone(Item item, List activeEmitters, ref int itemsInHeat, ref int itemsCooking, HashSet processedItems) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (processedItems.Contains(item)) { return 0f; } bool flag = false; float num = float.MaxValue; float num2 = 0f; Vector3 itemPosition = _cooker.GetItemPosition(item); foreach (StatusEmitter activeEmitter in activeEmitters) { if (!((Object)(object)activeEmitter == (Object)null) && _cooker.IsItemInHeatZone(item, activeEmitter)) { flag = true; float num3 = Vector3.Distance(itemPosition, ((Component)activeEmitter).transform.position); if (num3 < num) { num = num3; num2 = _cooker.GetCookSpeed(item, activeEmitter); } } } if (flag) { processedItems.Add(item); itemsInHeat++; if (num2 > 0.0001f) { float num4 = _cooker.CookItem(item, num2, 0.5f); if (num4 >= 1f) { itemsCooking++; } return num4; } } else if (_tracker.IsTracking(item)) { _tracker.Remove(item); } return 0f; } private void OnDestroy() { _scanner?.Clear(); _tracker?.StopAllSmoke(); } } public static class HeldItemTracker { private static Dictionary _heldItems = new Dictionary(); private static Dictionary _heldItemViewIDs = new Dictionary(); private static Dictionary _hasEmptyHands = new Dictionary(); public static int Count => _heldItems.Count; public static void SetHeldItem(Character character, Item item) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 if ((Object)(object)character == (Object)null) { return; } int instanceID = ((Object)character).GetInstanceID(); Item value; if ((Object)(object)item == (Object)null || !ClassExtensionsMethods.UnityObjectExists(item)) { bool flag = false; foreach (Item aLL_ACTIVE_ITEM in Item.ALL_ACTIVE_ITEMS) { if ((Object)(object)aLL_ACTIVE_ITEM != (Object)null && ClassExtensionsMethods.UnityObjectExists(aLL_ACTIVE_ITEM) && (Object)(object)aLL_ACTIVE_ITEM.trueHolderCharacter == (Object)(object)character && (int)aLL_ACTIVE_ITEM.itemState == 1) { flag = true; _heldItems[instanceID] = aLL_ACTIVE_ITEM; Dictionary heldItemViewIDs = _heldItemViewIDs; PhotonView photonView = ((MonoBehaviourPun)aLL_ACTIVE_ITEM).photonView; heldItemViewIDs[instanceID] = ((photonView != null) ? photonView.ViewID : (-1)); _hasEmptyHands[instanceID] = false; Plugin.LogDebug("\ud83d\udd0d Corrected held item for " + character.characterName + ": " + (aLL_ACTIVE_ITEM.UIData?.itemName ?? "Unknown")); return; } } if (!flag) { _heldItems.Remove(instanceID); _heldItemViewIDs.Remove(instanceID); _hasEmptyHands[instanceID] = true; } } else if (_heldItems.TryGetValue(instanceID, out value) && (Object)(object)value != (Object)null && ((Object)value).GetInstanceID() == ((Object)item).GetInstanceID()) { if ((Object)(object)((MonoBehaviourPun)item).photonView != (Object)null) { _heldItemViewIDs[instanceID] = ((MonoBehaviourPun)item).photonView.ViewID; } _hasEmptyHands[instanceID] = false; } else { _heldItems[instanceID] = item; Dictionary heldItemViewIDs2 = _heldItemViewIDs; PhotonView photonView2 = ((MonoBehaviourPun)item).photonView; heldItemViewIDs2[instanceID] = ((photonView2 != null) ? photonView2.ViewID : (-1)); _hasEmptyHands[instanceID] = false; Plugin.LogDebug(string.Format("\ud83d\udce6 Held item tracked: {0} -> {1} (ViewID: {2})", character.characterName, item.UIData?.itemName ?? "Unknown", _heldItemViewIDs[instanceID])); } } public static Item GetHeldItem(Character character) { //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Invalid comparison between Unknown and I4 //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Invalid comparison between Unknown and I4 if ((Object)(object)character == (Object)null) { return null; } int instanceID = ((Object)character).GetInstanceID(); if (_hasEmptyHands.TryGetValue(instanceID, out var value) && value) { foreach (Item aLL_ACTIVE_ITEM in Item.ALL_ACTIVE_ITEMS) { if ((Object)(object)aLL_ACTIVE_ITEM != (Object)null && ClassExtensionsMethods.UnityObjectExists(aLL_ACTIVE_ITEM) && (Object)(object)aLL_ACTIVE_ITEM.trueHolderCharacter == (Object)(object)character && (int)aLL_ACTIVE_ITEM.itemState == 1) { _heldItems[instanceID] = aLL_ACTIVE_ITEM; Dictionary heldItemViewIDs = _heldItemViewIDs; PhotonView photonView = ((MonoBehaviourPun)aLL_ACTIVE_ITEM).photonView; heldItemViewIDs[instanceID] = ((photonView != null) ? photonView.ViewID : (-1)); _hasEmptyHands[instanceID] = false; return aLL_ACTIVE_ITEM; } } return null; } if (_heldItems.TryGetValue(instanceID, out var value2)) { if ((Object)(object)value2 == (Object)null || !ClassExtensionsMethods.UnityObjectExists(value2) || (Object)(object)value2.trueHolderCharacter != (Object)(object)character || (int)value2.itemState != 1) { _heldItems.Remove(instanceID); _heldItemViewIDs.Remove(instanceID); _hasEmptyHands[instanceID] = true; return null; } return value2; } return null; } public static bool HasHeldItem(Character character) { if ((Object)(object)character == (Object)null) { return false; } return (Object)(object)GetHeldItem(character) != (Object)null; } public static IEnumerable> GetAllHeldItems() { Cleanup(); foreach (KeyValuePair kvp in _heldItems) { Character character = null; foreach (Character c in Character.AllCharacters) { if ((Object)(object)c != (Object)null && ((Object)c).GetInstanceID() == kvp.Key) { character = c; break; } } if ((Object)(object)character != (Object)null && (Object)(object)kvp.Value != (Object)null && ClassExtensionsMethods.UnityObjectExists(kvp.Value) && (Object)(object)kvp.Value.trueHolderCharacter == (Object)(object)character && (int)kvp.Value.itemState == 1) { yield return new KeyValuePair(character, kvp.Value); } } } public static void Cleanup() { List list = new List(); foreach (KeyValuePair heldItem in _heldItems) { if ((Object)(object)heldItem.Value == (Object)null || !ClassExtensionsMethods.UnityObjectExists(heldItem.Value)) { list.Add(heldItem.Key); continue; } bool flag = false; foreach (Character allCharacter in Character.AllCharacters) { if ((Object)(object)allCharacter != (Object)null && ((Object)allCharacter).GetInstanceID() == heldItem.Key) { flag = true; break; } } if (!flag) { list.Add(heldItem.Key); } } foreach (int item in list) { _heldItems.Remove(item); _heldItemViewIDs.Remove(item); _hasEmptyHands.Remove(item); } } public static void Clear() { _heldItems.Clear(); _heldItemViewIDs.Clear(); _hasEmptyHands.Clear(); Plugin.LogDebug("\ud83e\uddf9 All held items cleared"); } } public class ItemCooker { private CookingTracker _tracker; public ItemCooker(CookingTracker tracker) { _tracker = tracker; } public bool ShouldCookItem(Item item) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Invalid comparison between Unknown and I4 //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Invalid comparison between Unknown and I4 if ((Object)(object)item == (Object)null) { return false; } ItemCooking component = ((Component)item).GetComponent(); if ((Object)(object)component == (Object)null) { return false; } if (!component.canBeCooked) { return false; } IntItemData data = item.GetData((DataEntryKey)1); if (data != null && data.Value >= 12) { return false; } if (!Plugin.CookHeldItems.Value && (int)item.itemState == 1) { return false; } if (!Plugin.CookBackpackItems.Value && (int)item.itemState == 2) { return false; } return true; } public List GetBackpackItems() { //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Invalid comparison between Unknown and I4 List list = new List(); if (!Plugin.CookBackpackItems.Value) { return list; } Backpack[] array = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)1); Backpack[] array2 = array; foreach (Backpack val in array2) { if ((Object)(object)val == (Object)null || !ClassExtensionsMethods.UnityObjectExists(val)) { continue; } BackpackData data = ((Item)val).GetData((DataEntryKey)7); if (data == null) { continue; } for (int j = 0; j < data.itemSlots.Length; j++) { ItemSlot val2 = data.itemSlots[j]; if (val2 == null || val2.IsEmpty()) { continue; } Item prefab = val2.prefab; if ((Object)(object)prefab == (Object)null) { continue; } ItemCooking component = ((Component)prefab).GetComponent(); if ((Object)(object)component == (Object)null || !component.canBeCooked) { continue; } IntItemData data2 = prefab.GetData((DataEntryKey)1); if (data2 != null && data2.Value >= 12) { continue; } Item val3 = null; foreach (Item aLL_ACTIVE_ITEM in Item.ALL_ACTIVE_ITEMS) { if ((Object)(object)aLL_ACTIVE_ITEM == (Object)null || !ClassExtensionsMethods.UnityObjectExists(aLL_ACTIVE_ITEM) || aLL_ACTIVE_ITEM.itemID != prefab.itemID || (int)aLL_ACTIVE_ITEM.itemState != 2) { continue; } FieldInfo field = typeof(Item).GetField("backpackReference", BindingFlags.Instance | BindingFlags.NonPublic); if (!(field != null)) { continue; } object value = field.GetValue(aLL_ACTIVE_ITEM); if (value == null) { continue; } Type type = value.GetType(); FieldInfo field2 = type.GetField("view"); if (field2 != null) { object? value2 = field2.GetValue(value); PhotonView val4 = (PhotonView)((value2 is PhotonView) ? value2 : null); if ((Object)(object)val4 != (Object)null && (Object)(object)((Component)val4).GetComponent() == (Object)(object)val) { val3 = aLL_ACTIVE_ITEM; break; } } } if ((Object)(object)val3 != (Object)null) { list.Add(val3); } } } return list; } public float GetCookSpeed(Item item, StatusEmitter emitter) { //IL_001c: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_002f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)emitter == (Object)null) { return 0f; } Vector3 itemPosition = GetItemPosition(item); Vector3 position = ((Component)emitter).transform.position; float num = Vector3.Distance(itemPosition, position); float num2 = emitter.radius + emitter.outerFade; float num3 = 1f - Mathf.Clamp01(num / num2); if (emitter.innerFade > 0f && num < emitter.radius - emitter.innerFade) { num3 = 1f; } float num4 = Mathf.Abs(emitter.amount) * 2f; float num5 = num4 * num3 * Plugin.CookSpeedMultiplier.Value; if (num5 < Plugin.MinimumCookSpeed.Value) { num5 = Plugin.MinimumCookSpeed.Value; } return num5; } public Vector3 GetItemPosition(Item item) { //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) //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_001d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)item == (Object)null) { return Vector3.zero; } return item.Center(); } public bool IsItemInHeatZone(Item item, StatusEmitter emitter) { //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) //IL_0021: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)emitter == (Object)null) { return false; } Vector3 itemPosition = GetItemPosition(item); Vector3 position = ((Component)emitter).transform.position; float num = Vector3.Distance(itemPosition, position); float num2 = emitter.radius + emitter.outerFade; return num <= num2; } public float CookItem(Item item, float cookSpeed, float deltaTime) { if (!ShouldCookItem(item)) { return 0f; } if (!_tracker.IsTracking(item)) { _tracker.AddTime(item, 0f); Plugin.LogDebug(string.Format("✅ Started cooking {0} (speed: {1:F4})", item.UIData?.itemName ?? "Unknown", cookSpeed)); } _tracker.AddTime(item, cookSpeed * deltaTime); _tracker.UpdateSmokeForItem(item); float progress = _tracker.GetProgress(item); if (progress >= 1f) { ApplyCookedState(item); _tracker.Reset(item); int cookedLevel = GetCookedLevel(item); Plugin.LogInfo(string.Format("\ud83d\udd25 Item cooked: {0} (level: {1}/12)", item.UIData?.itemName ?? "Unknown", cookedLevel)); return 1f; } return progress; } private int GetCookedLevel(Item item) { return item.GetData((DataEntryKey)1)?.Value ?? 0; } private void ApplyCookedState(Item item) { if ((Object)(object)item == (Object)null) { return; } ItemCooking component = ((Component)item).GetComponent(); if ((Object)(object)component == (Object)null) { return; } PhotonView photonView = ((MonoBehaviourPun)item).photonView; if (!((Object)(object)photonView == (Object)null)) { int num = item.GetData((DataEntryKey)1)?.Value ?? 0; if (num >= 12) { Plugin.LogDebug(string.Format("\ud83d\udcdd Item {0} already at max cooked amount ({1})", item.UIData?.itemName ?? "Unknown", num)); return; } photonView.RPC("FinishCookingRPC", (RpcTarget)0, Array.Empty()); Plugin.LogDebug(string.Format("\ud83d\udce1 FinishCookingRPC called for {0} (level {1} -> {2})", item.UIData?.itemName ?? "Unknown", num, num + 1)); component.CancelCookingVisuals(); component.UpdateCookedBehavior(); } } } }