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 YourThirsty v2.1.2
YourThirsty.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; using YourThirsty; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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; } } } internal class Barrel : MonoBehaviour, Interactable, Hoverable { [CompilerGenerated] private sealed class <PourBucketRoutine>d__15 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public ItemData bucket; public Barrel <>4__this; private float <timer>5__1; private bool <bucketDirty>5__2; private int <totalWater>5__3; private int <remaining>5__4; private int <added>5__5; private float <fraction>5__6; private int <partialWater>5__7; private int <space>5__8; private int <toAdd>5__9; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PourBucketRoutine>d__15(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; <>1__state = -3; <timer>5__1 = 0f; <bucketDirty>5__2 = BucketItem.IsDirtyWater(bucket); <totalWater>5__3 = BucketItem.GetWater(bucket); SFXManager.PlayRefill(player); break; case 1: <>1__state = -3; break; } if (<timer>5__1 < 5f) { if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsSwimming()) { goto IL_00bc; } Vector3 velocity = ((Character)player).GetVelocity(); if (((Vector3)(ref velocity)).magnitude > 2f) { goto IL_00bc; } <timer>5__1 += Time.deltaTime; UIManager.SetFillProgress(<timer>5__1 / 5f); <>2__current = null; <>1__state = 1; result = true; } else { <remaining>5__4 = <>4__this.MaxWater - <>4__this.GetStoredWater(); <added>5__5 = Mathf.Min(<totalWater>5__3, <remaining>5__4); if (<added>5__5 > 0) { <>4__this.AddWater(<added>5__5, <bucketDirty>5__2); BucketItem.SetWater(bucket, <totalWater>5__3 - <added>5__5); if (<totalWater>5__3 - <added>5__5 <= 0) { BucketItem.SetDirty(bucket, dirty: false); } } UIManager.HideFillBar(); SFXManager.PlayRefill(player); ((Character)player).Message((MessageType)2, $"Poured water into barrel ({<>4__this.GetStoredWater()}/{<>4__this.MaxWater})", 0, (Sprite)null); <>m__Finally1(); result = false; } goto end_IL_0000; IL_00bc: <fraction>5__6 = <timer>5__1 / 5f; if (<fraction>5__6 > 0.05f) { <partialWater>5__7 = Mathf.Max(1, Mathf.FloorToInt((float)<totalWater>5__3 * <fraction>5__6)); <space>5__8 = <>4__this.MaxWater - <>4__this.GetStoredWater(); <toAdd>5__9 = Mathf.Min(<partialWater>5__7, <space>5__8); if (<toAdd>5__9 > 0) { <>4__this.AddWater(<toAdd>5__9, <bucketDirty>5__2); BucketItem.SetWater(bucket, <totalWater>5__3 - <toAdd>5__9); if (<totalWater>5__3 - <toAdd>5__9 <= 0) { BucketItem.SetDirty(bucket, dirty: false); } } } UIManager.HideFillBar(); result = false; <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; <>4__this._fillRoutine = null; } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <PourContainerRoutine>d__18 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public ContainerState state; public Barrel <>4__this; private float <timer>5__1; private bool <containerDirty>5__2; private int <totalWater>5__3; private int <remaining>5__4; private int <added>5__5; private float <fraction>5__6; private int <partialWater>5__7; private int <space>5__8; private int <toAdd>5__9; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PourContainerRoutine>d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; <>1__state = -3; <timer>5__1 = 0f; <containerDirty>5__2 = state.IsDirty; <totalWater>5__3 = state.CurrentAmount; SFXManager.PlayRefill(player); break; case 1: <>1__state = -3; break; } if (<timer>5__1 < 4f) { if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsSwimming()) { goto IL_00bc; } Vector3 velocity = ((Character)player).GetVelocity(); if (((Vector3)(ref velocity)).magnitude > 2f) { goto IL_00bc; } <timer>5__1 += Time.deltaTime; UIManager.SetFillProgress(<timer>5__1 / 4f); <>2__current = null; <>1__state = 1; result = true; } else { <remaining>5__4 = <>4__this.MaxWater - <>4__this.GetStoredWater(); <added>5__5 = Mathf.Min(<totalWater>5__3, <remaining>5__4); if (<added>5__5 > 0) { <>4__this.AddWater(<added>5__5, <containerDirty>5__2); state.CurrentAmount = <totalWater>5__3 - <added>5__5; ItemManager.SaveContainerState(player, state); } UIManager.HideFillBar(); SFXManager.PlayRefill(player); ((Character)player).Message((MessageType)2, $"Poured water into barrel ({<>4__this.GetStoredWater()}/{<>4__this.MaxWater})", 0, (Sprite)null); <>m__Finally1(); result = false; } goto end_IL_0000; IL_00bc: <fraction>5__6 = <timer>5__1 / 4f; if (<fraction>5__6 > 0.05f) { <partialWater>5__7 = Mathf.Max(1, Mathf.FloorToInt((float)<totalWater>5__3 * <fraction>5__6)); <space>5__8 = <>4__this.MaxWater - <>4__this.GetStoredWater(); <toAdd>5__9 = Mathf.Min(<partialWater>5__7, <space>5__8); if (<toAdd>5__9 > 0) { <>4__this.AddWater(<toAdd>5__9, <containerDirty>5__2); state.CurrentAmount = <totalWater>5__3 - <toAdd>5__9; ItemManager.SaveContainerState(player, state); } } UIManager.HideFillBar(); result = false; <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; <>4__this._fillRoutine = null; } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string ZDO_Water = "YT_BarrelWater"; private const string ZDO_Dirty = "YT_BarrelDirty"; private ZNetView m_nview; private Coroutine _fillRoutine; public int MaxWater => ConfigManager.BarrelCapacity.Value; private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); } public int GetStoredWater() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return 0; } return m_nview.GetZDO().GetInt("YT_BarrelWater", 0); } private void SetStoredWater(int amount) { if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { m_nview.GetZDO().Set("YT_BarrelWater", Mathf.Clamp(amount, 0, MaxWater)); } } public bool IsDirty() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return false; } return m_nview.GetZDO().GetBool("YT_BarrelDirty", false); } private void SetDirty(bool dirty) { if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { m_nview.GetZDO().Set("YT_BarrelDirty", dirty); } } public int AddWater(int amount, bool dirty = false) { int storedWater = GetStoredWater(); int num = MaxWater - storedWater; int num2 = Mathf.Min(amount, num); if (num2 > 0) { SetStoredWater(storedWater + num2); if (dirty) { SetDirty(dirty: true); } } return num2; } public int AddWater(float amount) { return AddWater(Mathf.FloorToInt(amount)); } public int TakeWater(int amount) { int storedWater = GetStoredWater(); int num = Mathf.Min(amount, storedWater); if (num > 0) { SetStoredWater(storedWater - num); if (GetStoredWater() <= 0) { SetDirty(dirty: false); } } return num; } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold) { return false; } if (_fillRoutine != null || DrinkSystem.IsBusy) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } ItemData equippedBucket = BucketItem.GetEquippedBucket(val); if (equippedBucket != null && !BucketItem.IsEmpty(equippedBucket) && !BucketItem.IsBoiling(equippedBucket)) { int num = MaxWater - GetStoredWater(); if (num <= 0) { ((Character)val).Message((MessageType)2, "Barrel is full.", 0, (Sprite)null); return false; } _fillRoutine = ((MonoBehaviour)this).StartCoroutine(PourBucketRoutine(val, equippedBucket)); return true; } if (ItemManager.CanFill(val, dirty: false, out var state)) { int storedWater = GetStoredWater(); if (storedWater > 0) { bool dirty = IsDirty(); int amount = state.MaxAmount - state.CurrentAmount; int num2 = TakeWater(amount); if (num2 > 0) { ItemManager.Fill(val, dirty); SFXManager.PlayRefill(val); ((Character)val).Message((MessageType)2, $"Filled from barrel ({GetStoredWater()}/{MaxWater}).", 0, (Sprite)null); return true; } } ((Character)val).Message((MessageType)2, "Barrel is empty.", 0, (Sprite)null); return false; } if (ItemManager.CanFillFromInventory(val, dirty: false, out var state2)) { int storedWater2 = GetStoredWater(); if (storedWater2 > 0) { bool dirty2 = IsDirty(); int amount2 = state2.MaxAmount - state2.CurrentAmount; int num3 = TakeWater(amount2); if (num3 > 0) { ItemManager.FillFromInventory(val, dirty2); SFXManager.PlayRefill(val); ((Character)val).Message((MessageType)2, $"Filled from barrel ({GetStoredWater()}/{MaxWater}).", 0, (Sprite)null); return true; } } ((Character)val).Message((MessageType)2, "Barrel is empty.", 0, (Sprite)null); return false; } ((Character)val).Message((MessageType)2, "You need a Water Bucket to pour, or a Waterskin/Horn to fill.", 0, (Sprite)null); return false; } [IteratorStateMachine(typeof(<PourBucketRoutine>d__15))] private IEnumerator PourBucketRoutine(Player player, ItemData bucket) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PourBucketRoutine>d__15(0) { <>4__this = this, player = player, bucket = bucket }; } public bool StartPourBucket(Player player, ItemData bucket) { if (_fillRoutine != null || DrinkSystem.IsBusy) { ((Character)player).Message((MessageType)2, "Busy — wait for current action to finish.", 0, (Sprite)null); return false; } int num = MaxWater - GetStoredWater(); if (num <= 0) { ((Character)player).Message((MessageType)2, "Barrel is full.", 0, (Sprite)null); return false; } _fillRoutine = ((MonoBehaviour)this).StartCoroutine(PourBucketRoutine(player, bucket)); return true; } public bool StartPourContainer(Player player, ContainerState state) { if (_fillRoutine != null || DrinkSystem.IsBusy) { ((Character)player).Message((MessageType)2, "Busy — wait for current action to finish.", 0, (Sprite)null); return false; } int num = MaxWater - GetStoredWater(); if (num <= 0) { ((Character)player).Message((MessageType)2, "Barrel is full.", 0, (Sprite)null); return false; } if (state == null || state.CurrentAmount <= 0) { return false; } _fillRoutine = ((MonoBehaviour)this).StartCoroutine(PourContainerRoutine(player, state)); return true; } [IteratorStateMachine(typeof(<PourContainerRoutine>d__18))] private IEnumerator PourContainerRoutine(Player player, ContainerState state) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PourContainerRoutine>d__18(0) { <>4__this = this, player = player, state = state }; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetHoverText() { int storedWater = GetStoredWater(); string text = $"Rain Barrel ({storedWater}/{MaxWater})"; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return text; } ItemData equippedBucket = BucketItem.GetEquippedBucket(localPlayer); if (equippedBucket != null && !BucketItem.IsEmpty(equippedBucket) && !BucketItem.IsBoiling(equippedBucket)) { return text + "\n<color=yellow>[G]</color> Fill Barrel"; } bool flag = false; bool flag2 = false; bool flag3 = false; if (ItemManager.CanFill(localPlayer, dirty: false, out var _)) { flag = true; flag3 = true; } if (ItemManager.CanDrinkFromContainer(localPlayer, out var _)) { flag = true; flag2 = true; } if (flag) { if (storedWater > 0 && flag3) { text += "\n<color=yellow>[E]</color> Fill Container"; } if (flag2) { text += "\n<color=yellow>[G]</color> Fill Barrel"; } } return text; } public string GetHoverName() { return "Rain Barrel"; } } internal static class Horn { internal static bool Use(Player player, ItemData item) { if (ItemManager.CanDrinkFromContainer(player, out var _)) { DrinkSystem.TryDrink(); return true; } SFXManager.PlayEmpty(player); return true; } } [HarmonyPatch(typeof(Player), "Update")] internal static class PlayerPatch { private static SE_Stats _seBucketSlow; private static bool _penaltyActive; private static float _checkTimer; private const float CheckInterval = 0.5f; [HarmonyPostfix] private static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } _checkTimer -= Time.deltaTime; if (!(_checkTimer > 0f)) { _checkTimer = 0.5f; ItemData nonEmptyBucketInInventory = BucketItem.GetNonEmptyBucketInInventory(__instance); bool flag = nonEmptyBucketInInventory != null && BucketItem.IsFull(nonEmptyBucketInInventory); if (flag && !_penaltyActive) { EnsureStatusEffect(); ((Character)__instance).GetSEMan().AddStatusEffect((StatusEffect)(object)_seBucketSlow, false, 0, 0f); _penaltyActive = true; } else if (!flag && _penaltyActive) { ((Character)__instance).GetSEMan().RemoveStatusEffect((StatusEffect)(object)_seBucketSlow, false); _penaltyActive = false; } } } private static void EnsureStatusEffect() { if (!((Object)(object)_seBucketSlow != (Object)null)) { _seBucketSlow = ScriptableObject.CreateInstance<SE_Stats>(); ((Object)_seBucketSlow).name = "SE_YT_BucketSlow"; ((StatusEffect)_seBucketSlow).m_name = "Carrying Water"; ((StatusEffect)_seBucketSlow).m_tooltip = "Heavy Water Bucket slows you down"; ((StatusEffect)_seBucketSlow).m_ttl = 0f; _seBucketSlow.m_speedModifier = (0f - ConfigManager.BucketSpeedPenalty.Value) / 10f; } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class PlayerSpawnedPatch { [HarmonyPostfix] private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { YourThirstyPlugin.Log.LogInfo((object)"PlayerSpawnedPatch: Player spawned — refreshing piece requirements."); ItemRegistration.RefreshPieceRequirements(); } } } internal static class Waterskin { internal static bool Use(Player player, ItemData item) { if (ItemManager.CanDrinkFromContainer(player, out var _)) { DrinkSystem.TryDrink(); return true; } SFXManager.PlayEmpty(player); return true; } } internal class Well : MonoBehaviour, Interactable, Hoverable { private const string ZDO_Water = "YT_WellWater"; private ZNetView m_nview; public int MaxWater => 999; private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); } private void Start() { if ((Object)(object)m_nview != (Object)null && m_nview.IsValid() && m_nview.IsOwner() && m_nview.GetZDO().GetInt("YT_WellWater", -1) < 0) { m_nview.GetZDO().Set("YT_WellWater", MaxWater); } } public int GetStoredWater() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return 0; } int @int = m_nview.GetZDO().GetInt("YT_WellWater", MaxWater); return Mathf.Clamp(@int, 0, MaxWater); } private void SetStoredWater(int amount) { if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { m_nview.GetZDO().Set("YT_WellWater", Mathf.Clamp(amount, 0, MaxWater)); } } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } ItemData equippedBucket = BucketItem.GetEquippedBucket(val); if (equippedBucket != null && !BucketItem.IsFull(equippedBucket)) { int num = BucketItem.Capacity - BucketItem.CurrentWater(equippedBucket); BucketItem.SetWater(equippedBucket, BucketItem.CurrentWater(equippedBucket) + num); SFXManager.PlayRefill(val); ((Character)val).Message((MessageType)2, "Water Bucket filled with clean water.", 0, (Sprite)null); return true; } if (ItemManager.CanFill(val, dirty: false, out var _)) { ItemManager.Fill(val, dirty: false); SFXManager.PlayRefill(val); ((Character)val).Message((MessageType)2, "Filled with clean water from the well.", 0, (Sprite)null); return true; } ((Character)val).Message((MessageType)2, "Equip a Water Bucket or container to fill from the well.", 0, (Sprite)null); return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetHoverText() { return "<color=yellow>[E]</color> Well (Always Full)"; } public string GetHoverName() { return "Well"; } } internal class BoilingBucketPiece : MonoBehaviour, Interactable, Hoverable { private const string ZDO_CoolStart = "YT_CoolStart"; private const string ZDO_CoolActive = "YT_CoolActive"; private ZNetView m_nview; private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)m_nview != (Object)null && m_nview.IsValid() && !m_nview.GetZDO().GetBool("YT_CoolActive", false)) { StartCooling(); } } public float GetTimeRemaining() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return 0f; } long @long = m_nview.GetZDO().GetLong("YT_CoolStart", 0L); if (@long <= 0) { return 0f; } long ticks = ZNet.instance.GetTime().Ticks; float num = (float)((double)(ticks - @long) / 10000000.0); float value = ConfigManager.CoolDurationSeconds.Value; return Mathf.Max(0f, value - num); } public bool IsCooled() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return false; } if (!m_nview.GetZDO().GetBool("YT_CoolActive", false)) { return false; } return GetTimeRemaining() <= 0f; } private void StartCooling() { if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { long ticks = ZNet.instance.GetTime().Ticks; m_nview.GetZDO().Set("YT_CoolStart", ticks); m_nview.GetZDO().Set("YT_CoolActive", true); } } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } if (!IsCooled()) { float timeRemaining = GetTimeRemaining(); int num = Mathf.CeilToInt(timeRemaining); ((Character)val).Message((MessageType)2, $"Water is still cooling... {num}s", 0, (Sprite)null); return false; } GameObject bucket = PrefabLoader.Bucket; if ((Object)(object)bucket == (Object)null) { ((Character)val).Message((MessageType)2, "Error: bucket prefab missing.", 0, (Sprite)null); return false; } ItemDrop component = bucket.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null) { return false; } ItemData val2 = ((Humanoid)val).GetInventory().AddItem(((Object)bucket).name, 1, component.m_itemData.m_quality, component.m_itemData.m_variant, 0L, "", false); if (val2 == null) { ((Character)val).Message((MessageType)2, "Inventory full!", 0, (Sprite)null); return false; } BucketItem.SetWater(val2, BucketItem.Capacity); BucketItem.SetDirty(val2, dirty: false); BucketItem.SetBoiling(val2, boiling: false); SFXManager.PlayRefill(val); ((Character)val).Message((MessageType)2, "Collected purified clean water!", 0, (Sprite)null); if ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) { WearNTear component2 = ((Component)this).GetComponent<WearNTear>(); if ((Object)(object)component2 != (Object)null) { component2.Remove(false); } else { ZNetScene.instance.Destroy(((Component)this).gameObject); } } return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetHoverText() { if (IsCooled()) { return "<color=yellow>[E]</color> Collect Purified Water"; } float timeRemaining = GetTimeRemaining(); int num = Mathf.FloorToInt(timeRemaining / 60f); int num2 = Mathf.FloorToInt(timeRemaining % 60f); string text = ((num > 0) ? $"{num}:{num2:D2}" : $"{num2}s"); return "<color=#AAAAAA>Cooling... " + text + "</color>"; } public string GetHoverName() { return "Boiling Water Bucket"; } } internal class CauldronBoiling : MonoBehaviour { private const string ZDO_BoilStart = "YT_BoilStart"; private const string ZDO_BoilActive = "YT_BoilActive"; private ZNetView m_nview; private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); } private bool EnsureNView() { if ((Object)(object)m_nview == (Object)null) { m_nview = ((Component)this).GetComponent<ZNetView>(); } return (Object)(object)m_nview != (Object)null && m_nview.IsValid(); } public bool IsBoilActive() { if (!EnsureNView()) { return false; } ZDO zDO = m_nview.GetZDO(); if (zDO == null) { return false; } return zDO.GetBool("YT_BoilActive", false); } public bool IsReady() { if (!IsBoilActive()) { return false; } return GetTimeRemaining() <= 0f; } public float GetTimeRemaining() { if (!EnsureNView()) { return 0f; } ZDO zDO = m_nview.GetZDO(); if (zDO == null) { return 0f; } long @long = zDO.GetLong("YT_BoilStart", 0L); if (@long <= 0) { return 0f; } if ((Object)(object)ZNet.instance == (Object)null) { return 0f; } long ticks = ZNet.instance.GetTime().Ticks; float num = (float)((double)(ticks - @long) / 10000000.0); float value = ConfigManager.BoilDurationSeconds.Value; return Mathf.Max(0f, value - num); } public bool StartBoil() { if (!EnsureNView()) { YourThirstyPlugin.Log.LogWarning((object)"CauldronBoiling.StartBoil: m_nview null/invalid — boil NOT started."); return false; } ZDO zDO = m_nview.GetZDO(); if (zDO == null) { YourThirstyPlugin.Log.LogWarning((object)"CauldronBoiling.StartBoil: ZDO is null — boil NOT started."); return false; } if ((Object)(object)ZNet.instance == (Object)null) { YourThirstyPlugin.Log.LogWarning((object)"CauldronBoiling.StartBoil: ZNet.instance is null — boil NOT started."); return false; } long ticks = ZNet.instance.GetTime().Ticks; zDO.Set("YT_BoilStart", ticks); zDO.Set("YT_BoilActive", true); YourThirstyPlugin.Log.LogInfo((object)string.Format("CauldronBoiling.StartBoil: Boil started at ticks={0}, BoilActive={1}", ticks, zDO.GetBool("YT_BoilActive", false))); return true; } public void ResetBoil() { if (EnsureNView()) { ZDO zDO = m_nview.GetZDO(); if (zDO != null) { zDO.Set("YT_BoilActive", false); zDO.Set("YT_BoilStart", 0L); } } } } namespace YourThirsty { internal static class PlayerAnimationInjector { public enum DrinkAnimMode { NaturalWater, ContainerDrink, ContainerRefill } [CompilerGenerated] private sealed class <DrinkTimerRoutine>d__13 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public float duration; public DrinkAnimMode mode; private float <elapsed>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DrinkTimerRoutine>d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //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) switch (<>1__state) { default: return false; case 0: <>1__state = -1; _playing = true; YourThirstyPlugin.Log.LogInfo((object)$"AnimationInjector: Drink animation started ({duration}s, {mode})"); <elapsed>5__1 = 0f; break; case 1: <>1__state = -1; break; } if (<elapsed>5__1 < duration) { if (!((Object)(object)player == (Object)null) && !((Character)player).IsDead() && !((Character)player).IsSwimming()) { Vector3 velocity = ((Character)player).GetVelocity(); if (!(((Vector3)(ref velocity)).magnitude > 2f)) { <elapsed>5__1 += Time.deltaTime; <>2__current = null; <>1__state = 1; return true; } } Stop(); return false; } RestoreAnimatorSpeed(); try { if ((Object)(object)player != (Object)null) { InvokeStopEmote(player); } } catch { } _playing = false; _activeRoutine = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static bool _playing; private static Coroutine _activeRoutine; private static MethodInfo _stopEmote; private static float _savedAnimSpeed = 1f; private static bool _speedOverridden; public static bool IsPlaying => _playing; public static void Init() { _playing = false; _activeRoutine = null; _speedOverridden = false; YourThirstyPlugin.Log.LogInfo((object)"AnimationInjector: initialized."); } public static void Inject(Player player) { } public static void PlayDrinkAnimation(Player player, DrinkAnimMode mode) { if ((Object)(object)player == (Object)null) { return; } Stop(); switch (mode) { case DrinkAnimMode.NaturalWater: { Animator componentInChildren = ((Component)player).GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren != (Object)null) { _savedAnimSpeed = componentInChildren.speed; componentInChildren.speed = 0.4f; _speedOverridden = true; } try { ZSyncAnimation component2 = ((Component)player).GetComponent<ZSyncAnimation>(); if ((Object)(object)component2 != (Object)null) { component2.SetTrigger("interact"); component2.SetTrigger("eat"); } } catch { } break; } case DrinkAnimMode.ContainerDrink: try { player.StartEmote("drink", true); } catch { } break; case DrinkAnimMode.ContainerRefill: try { ZSyncAnimation component = ((Component)player).GetComponent<ZSyncAnimation>(); if ((Object)(object)component != (Object)null) { component.SetTrigger("interact"); } } catch { } break; } _activeRoutine = ((MonoBehaviour)CoroutineHost.Instance).StartCoroutine(DrinkTimerRoutine(player, ConfigManager.DrinkDurationSeconds.Value, mode)); } public static void Stop() { if (_activeRoutine != null) { try { ((MonoBehaviour)CoroutineHost.Instance).StopCoroutine(_activeRoutine); } catch { } _activeRoutine = null; } _playing = false; RestoreAnimatorSpeed(); try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { InvokeStopEmote(localPlayer); } } catch { } } private static void RestoreAnimatorSpeed() { if (!_speedOverridden) { return; } try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { Animator componentInChildren = ((Component)localPlayer).GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.speed = _savedAnimSpeed; } } } catch { } _savedAnimSpeed = 1f; _speedOverridden = false; } [IteratorStateMachine(typeof(<DrinkTimerRoutine>d__13))] private static IEnumerator DrinkTimerRoutine(Player player, float duration, DrinkAnimMode mode) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DrinkTimerRoutine>d__13(0) { player = player, duration = duration, mode = mode }; } private static void InvokeStopEmote(Player player) { if (_stopEmote == null) { _stopEmote = AccessTools.Method(typeof(Player), "StopEmote", (Type[])null, (Type[])null); } _stopEmote?.Invoke(player, null); } } internal static class BiomeWaterQuality { private class BiomeState { public bool IsGood; public float Timer; public (float, float)[] Brackets; public BiomeState((float, float)[] brackets) { Brackets = brackets; IsGood = true; Timer = PickDuration(brackets); } } private static readonly (float min, float max)[] BlackForestBrackets = new(float, float)[4] { (180f, 300f), (360f, 480f), (600f, 720f), (900f, 900f) }; private static readonly (float min, float max)[] PlainsBrackets = new(float, float)[4] { (120f, 240f), (300f, 420f), (480f, 600f), (720f, 900f) }; private static readonly (float min, float max)[] MistlandsBrackets = new(float, float)[4] { (300f, 480f), (600f, 840f), (900f, 1200f), (1500f, 1800f) }; private static readonly Dictionary<Biome, BiomeState> _states = new Dictionary<Biome, BiomeState>(); private static bool _initialized; public static void Init() { _states.Clear(); _states[(Biome)8] = new BiomeState(BlackForestBrackets); _states[(Biome)16] = new BiomeState(PlainsBrackets); _states[(Biome)512] = new BiomeState(MistlandsBrackets); _initialized = true; YourThirstyPlugin.Log.LogInfo((object)"BiomeWaterQuality: initialized (BlackForest, Plains, Mistlands cycling)."); } public static void Update() { //IL_0092: Unknown result type (might be due to invalid IL or missing references) if (!_initialized) { return; } float deltaTime = Time.deltaTime; foreach (KeyValuePair<Biome, BiomeState> state in _states) { BiomeState value = state.Value; value.Timer -= deltaTime; if (value.Timer <= 0f) { value.IsGood = !value.IsGood; value.Timer = PickDuration(value.Brackets); YourThirstyPlugin.Log.LogInfo((object)($"BiomeWaterQuality: {state.Key} water is now " + string.Format("{0} for {1:F0}s", value.IsGood ? "GOOD" : "BAD", value.Timer))); } } } public static bool IsBadWater(Biome biome) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (_states.TryGetValue(biome, out var value)) { return !value.IsGood; } return false; } public static bool HasCycling(Biome biome) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return _states.ContainsKey(biome); } private static float PickDuration((float min, float max)[] brackets) { int num = Random.Range(0, brackets.Length); return Random.Range(brackets[num].min, brackets[num].max); } } internal enum DifficultyLevel { Easy, Casual, Hard, Custom } internal static class ConfigManager { public static ConfigEntry<DifficultyLevel> Difficulty; public static ConfigEntry<float> ThirstDurationMinutes; public static ConfigEntry<float> CleanHydrationAmount; public static ConfigEntry<float> DirtyHydrationAmount; public static ConfigEntry<float> DrinkDurationSeconds; public static ConfigEntry<float> HydratedDuration; public static ConfigEntry<float> SicknessDuration; public static ConfigEntry<float> DirtyWaterSpeedPenalty; public static ConfigEntry<int> WaterskinCapacity; public static ConfigEntry<int> HornCapacity; public static ConfigEntry<int> BucketCapacity; public static ConfigEntry<int> BarrelCapacity; public static ConfigEntry<float> BucketSpeedPenalty; public static ConfigEntry<float> BoilDurationSeconds; public static ConfigEntry<float> CoolDurationSeconds; public static void Init(ConfigFile config) { Difficulty = config.Bind<DifficultyLevel>("Difficulty", "DifficultyLevel", DifficultyLevel.Casual, "Easy = forgiving (slow thirst, big drinks, fast boil).\nCasual = balanced (normal thirst, moderate drinks).\nHard = punishing (fast thirst, small drinks, slow boil, harsh debuffs).\nCustom = use the manual values below without overwriting them."); ThirstDurationMinutes = config.Bind<float>("Thirst", "ThirstDurationMinutes", 35f, "Time in minutes to go from 0 to max thirst."); CleanHydrationAmount = config.Bind<float>("Thirst", "CleanHydrationAmount", 20f, "Thirst reduced per drink (20 = 20% hydration restored)."); DirtyHydrationAmount = config.Bind<float>("Thirst", "DirtyHydrationAmount", 20f, "Thirst reduced per dirty water drink (20 = 20% hydration restored, before dirty penalty)."); DrinkDurationSeconds = config.Bind<float>("Thirst", "DrinkDurationSeconds", 4f, "Duration of drink animation."); HydratedDuration = config.Bind<float>("Buffs", "HydratedDuration", 160f, "Duration in seconds of the Hydrated buff after drinking clean water (160 = 2m 40s)."); SicknessDuration = config.Bind<float>("Buffs", "SicknessDuration", 160f, "Duration in seconds of the Dirty Water debuff from dirty water (160 = 2m 40s)."); DirtyWaterSpeedPenalty = config.Bind<float>("Buffs", "DirtyWaterSpeedPenalty", 0.2f, "Movement speed reduction fraction when sick from dirty water (0.20 = 20%)."); WaterskinCapacity = config.Bind<int>("Containers", "WaterskinCapacity", 5, "Units of water a waterskin holds."); HornCapacity = config.Bind<int>("Containers", "HornCapacity", 3, "Units of water a horn holds."); BucketCapacity = config.Bind<int>("Containers", "BucketCapacity", 6, "Units of water a bucket carries."); BarrelCapacity = config.Bind<int>("Containers", "BarrelCapacity", 12, "Units of water a barrel stores (12 = 2 full bucket pours)."); BucketSpeedPenalty = config.Bind<float>("Containers", "BucketSpeedPenalty", 3f, "Movement speed reduction when carrying a full bucket."); BoilDurationSeconds = config.Bind<float>("Boiling", "BoilDurationSeconds", 150f, "Time in seconds for water to boil in the cauldron (150 = 2 min 30 sec)."); CoolDurationSeconds = config.Bind<float>("Boiling", "CoolDurationSeconds", 60f, "Time in seconds for boiling water to cool after being placed (60 = 1 min)."); ApplyDifficultyPreset(); } public static void ApplyDifficultyPreset() { DifficultyLevel value = Difficulty.Value; switch (value) { case DifficultyLevel.Custom: return; case DifficultyLevel.Easy: ThirstDurationMinutes.Value = 45f; CleanHydrationAmount.Value = 25f; DirtyHydrationAmount.Value = 20f; DrinkDurationSeconds.Value = 3f; HydratedDuration.Value = 200f; SicknessDuration.Value = 90f; DirtyWaterSpeedPenalty.Value = 0.1f; WaterskinCapacity.Value = 6; HornCapacity.Value = 4; BucketCapacity.Value = 8; BarrelCapacity.Value = 16; BucketSpeedPenalty.Value = 2f; BoilDurationSeconds.Value = 90f; CoolDurationSeconds.Value = 30f; break; case DifficultyLevel.Casual: ThirstDurationMinutes.Value = 35f; CleanHydrationAmount.Value = 20f; DirtyHydrationAmount.Value = 20f; DrinkDurationSeconds.Value = 4f; HydratedDuration.Value = 160f; SicknessDuration.Value = 160f; DirtyWaterSpeedPenalty.Value = 0.2f; WaterskinCapacity.Value = 5; HornCapacity.Value = 3; BucketCapacity.Value = 6; BarrelCapacity.Value = 12; BucketSpeedPenalty.Value = 3f; BoilDurationSeconds.Value = 150f; CoolDurationSeconds.Value = 60f; break; case DifficultyLevel.Hard: ThirstDurationMinutes.Value = 22f; CleanHydrationAmount.Value = 15f; DirtyHydrationAmount.Value = 12f; DrinkDurationSeconds.Value = 5f; HydratedDuration.Value = 100f; SicknessDuration.Value = 240f; DirtyWaterSpeedPenalty.Value = 0.3f; WaterskinCapacity.Value = 3; HornCapacity.Value = 2; BucketCapacity.Value = 5; BarrelCapacity.Value = 10; BucketSpeedPenalty.Value = 4f; BoilDurationSeconds.Value = 210f; CoolDurationSeconds.Value = 90f; break; } YourThirstyPlugin.Log.LogInfo((object)$"ConfigManager: Applied '{value}' difficulty preset."); } } internal class CoroutineHost : MonoBehaviour { private static CoroutineHost _instance; public static CoroutineHost Instance => EnsureExists(); public static CoroutineHost EnsureExists() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return _instance; } GameObject val = new GameObject("YourThirsty_CoroutineHost"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent<CoroutineHost>(); return _instance; } } internal static class DrinkSystem { [CompilerGenerated] private sealed class <ContainerDrinkRoutine>d__7 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public bool isDirty; private float <timer>5__1; private float <duration>5__2; private float <amount>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ContainerDrinkRoutine>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; <>1__state = -3; <timer>5__1 = 0f; <duration>5__2 = ConfigManager.DrinkDurationSeconds.Value; if (isDirty) { SFXManager.PlayDirty(player); } else { SFXManager.PlayDrink(player); } break; case 1: <>1__state = -3; break; } if (<timer>5__1 < <duration>5__2) { if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsSwimming()) { goto IL_00c0; } Vector3 velocity = ((Character)player).GetVelocity(); if (((Vector3)(ref velocity)).magnitude > 2f) { goto IL_00c0; } <timer>5__1 += Time.deltaTime; UIManager.SetFillProgress(<timer>5__1 / <duration>5__2); <>2__current = null; <>1__state = 1; result = true; } else { UIManager.HideFillBar(); ItemManager.Drink(player); <amount>5__3 = (isDirty ? ConfigManager.DirtyHydrationAmount.Value : ConfigManager.CleanHydrationAmount.Value); ThirstSystem.ApplyDrink(<amount>5__3, isDirty); BuffManager.ApplyDrinkEffects(player, isDirty); if (isDirty) { UIManager.FlashDirtyWater(); } <>m__Finally1(); result = false; } goto end_IL_0000; IL_00c0: PlayerAnimationInjector.Stop(); UIManager.HideFillBar(); result = false; <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; _drinkRoutine = null; } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <FillBucketRoutine>d__10 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public ItemData bucket; public bool isDirty; private float <timer>5__1; private float <fraction>5__2; private int <partialWater>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FillBucketRoutine>d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; <>1__state = -3; <timer>5__1 = 0f; SFXManager.PlayRefill(player); break; case 1: <>1__state = -3; break; } if (<timer>5__1 < 5f) { if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsSwimming()) { goto IL_0097; } Vector3 velocity = ((Character)player).GetVelocity(); if (((Vector3)(ref velocity)).magnitude > 2f) { goto IL_0097; } <timer>5__1 += Time.deltaTime; UIManager.SetFillProgress(<timer>5__1 / 5f); <>2__current = null; <>1__state = 1; result = true; } else { BucketItem.Fill(bucket, isDirty); UIManager.HideFillBar(); <>m__Finally1(); result = false; } goto end_IL_0000; IL_0097: <fraction>5__2 = <timer>5__1 / 5f; if (<fraction>5__2 > 0.05f) { <partialWater>5__3 = Mathf.Max(1, Mathf.FloorToInt((float)BucketItem.Capacity * <fraction>5__2)); BucketItem.SetWater(bucket, <partialWater>5__3); BucketItem.SetDirty(bucket, isDirty); } PlayerAnimationInjector.Stop(); UIManager.HideFillBar(); result = false; <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; _drinkRoutine = null; } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <FillEquippedRoutine>d__8 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public bool isDirty; private float <timer>5__1; private float <fraction>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FillEquippedRoutine>d__8(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; <>1__state = -3; <timer>5__1 = 0f; SFXManager.PlayRefill(player); break; case 1: <>1__state = -3; break; } if (<timer>5__1 < 4f) { if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsSwimming()) { goto IL_0097; } Vector3 velocity = ((Character)player).GetVelocity(); if (((Vector3)(ref velocity)).magnitude > 2f) { goto IL_0097; } <timer>5__1 += Time.deltaTime; UIManager.SetFillProgress(<timer>5__1 / 4f); <>2__current = null; <>1__state = 1; result = true; } else { ItemManager.Fill(player, isDirty); UIManager.HideFillBar(); <>m__Finally1(); result = false; } goto end_IL_0000; IL_0097: <fraction>5__2 = <timer>5__1 / 4f; if (<fraction>5__2 > 0.05f) { ItemManager.PartialFill(player, isDirty, <fraction>5__2); } PlayerAnimationInjector.Stop(); UIManager.HideFillBar(); result = false; <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; _drinkRoutine = null; } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <NaturalDrinkRoutine>d__6 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public bool isDirty; private float <timer>5__1; private float <duration>5__2; private float <amount>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <NaturalDrinkRoutine>d__6(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; <>1__state = -3; <timer>5__1 = 0f; <duration>5__2 = ConfigManager.DrinkDurationSeconds.Value; if (isDirty) { SFXManager.PlayDirty(player); } else { SFXManager.PlayDrink(player); } break; case 1: <>1__state = -3; break; } if (<timer>5__1 < <duration>5__2) { if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsSwimming()) { goto IL_00ce; } Vector3 velocity = ((Character)player).GetVelocity(); if (((Vector3)(ref velocity)).magnitude > 2f || !WaterSourceDetector.IsNearWater(player)) { goto IL_00ce; } <timer>5__1 += Time.deltaTime; UIManager.SetFillProgress(<timer>5__1 / <duration>5__2); <>2__current = null; <>1__state = 1; result = true; } else { UIManager.HideFillBar(); <amount>5__3 = (isDirty ? ConfigManager.DirtyHydrationAmount.Value : ConfigManager.CleanHydrationAmount.Value); ThirstSystem.ApplyDrink(<amount>5__3, isDirty); BuffManager.ApplyDrinkEffects(player, isDirty); if (isDirty) { UIManager.FlashDirtyWater(); } <>m__Finally1(); result = false; } goto end_IL_0000; IL_00ce: PlayerAnimationInjector.Stop(); UIManager.HideFillBar(); result = false; <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; _drinkRoutine = null; } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static Coroutine _drinkRoutine; public static bool IsBusy => _drinkRoutine != null; public static void TryDrink() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsSwimming() && _drinkRoutine == null) { if (!ItemManager.CanDrinkFromContainer(localPlayer, out var state)) { SFXManager.PlayEmpty(localPlayer); return; } bool isDirty = state.IsDirty; AnimationManager.PrepareDrink(localPlayer, PlayerAnimationInjector.DrinkAnimMode.ContainerDrink); _drinkRoutine = ((MonoBehaviour)CoroutineHost.Instance).StartCoroutine(ContainerDrinkRoutine(localPlayer, isDirty)); } } public static void TryDrinkNatural() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsSwimming() && _drinkRoutine == null && WaterSourceDetector.CanInteractWithWater(localPlayer)) { bool isDirty = WaterSourceDetector.IsDirtyWater(localPlayer); AnimationManager.PrepareDrink(localPlayer, PlayerAnimationInjector.DrinkAnimMode.NaturalWater); _drinkRoutine = ((MonoBehaviour)CoroutineHost.Instance).StartCoroutine(NaturalDrinkRoutine(localPlayer, isDirty)); } } public static void TryFillEquipped(bool isDirty) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && _drinkRoutine == null && ItemManager.CanFill(localPlayer, isDirty, out var _)) { AnimationManager.PrepareDrink(localPlayer, PlayerAnimationInjector.DrinkAnimMode.ContainerRefill); _drinkRoutine = ((MonoBehaviour)CoroutineHost.Instance).StartCoroutine(FillEquippedRoutine(localPlayer, isDirty)); } } [IteratorStateMachine(typeof(<NaturalDrinkRoutine>d__6))] private static IEnumerator NaturalDrinkRoutine(Player player, bool isDirty) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <NaturalDrinkRoutine>d__6(0) { player = player, isDirty = isDirty }; } [IteratorStateMachine(typeof(<ContainerDrinkRoutine>d__7))] private static IEnumerator ContainerDrinkRoutine(Player player, bool isDirty) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ContainerDrinkRoutine>d__7(0) { player = player, isDirty = isDirty }; } [IteratorStateMachine(typeof(<FillEquippedRoutine>d__8))] private static IEnumerator FillEquippedRoutine(Player player, bool isDirty) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FillEquippedRoutine>d__8(0) { player = player, isDirty = isDirty }; } public static void TryFillBucket(bool isDirty) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && _drinkRoutine == null) { ItemData firstBucketInInventory = BucketItem.GetFirstBucketInInventory(localPlayer); if (firstBucketInInventory != null && !BucketItem.IsFull(firstBucketInInventory)) { AnimationManager.PrepareDrink(localPlayer, PlayerAnimationInjector.DrinkAnimMode.ContainerRefill); _drinkRoutine = ((MonoBehaviour)CoroutineHost.Instance).StartCoroutine(FillBucketRoutine(localPlayer, firstBucketInInventory, isDirty)); } } } [IteratorStateMachine(typeof(<FillBucketRoutine>d__10))] private static IEnumerator FillBucketRoutine(Player player, ItemData bucket, bool isDirty) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FillBucketRoutine>d__10(0) { player = player, bucket = bucket, isDirty = isDirty }; } public static void TryDrinkFromWell() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && _drinkRoutine == null) { float value = ConfigManager.CleanHydrationAmount.Value; ThirstSystem.ApplyDrink(value, dirty: false); SFXManager.PlayDrink(localPlayer); } } } internal class GroundLock : MonoBehaviour { private float _groundY; private Rigidbody _rb; public void Lock() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) _groundY = ((Component)this).transform.position.y; _rb = ((Component)this).GetComponent<Rigidbody>(); } private void LateUpdate() { //IL_0007: 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_002c: 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_003e: 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_0067: 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_008b: 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) Vector3 position = ((Component)this).transform.position; if (position.y > _groundY + 0.01f) { ((Component)this).transform.position = new Vector3(position.x, _groundY, position.z); } if ((Object)(object)_rb != (Object)null) { Vector3 linearVelocity = _rb.linearVelocity; if (linearVelocity.y > 0.01f) { _rb.linearVelocity = new Vector3(linearVelocity.x, 0f, linearVelocity.z); } } } public void Unlock() { //IL_0007: 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_0030: 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_0042: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)this).transform.position; if (Mathf.Abs(position.y - _groundY) > 0.01f) { ((Component)this).transform.position = new Vector3(position.x, _groundY, position.z); } Object.Destroy((Object)(object)this); } } [HarmonyPatch(typeof(Hud), "Update")] internal static class HudPatches { private static GameObject _thirstRoot; private static Text _thirstText; private static Image _thirstIcon; private static Sprite _spriteHydrated; private static Sprite _spriteThirsty; private static GameObject _hoverRoot; private static Text _hoverText; private static void Postfix(Hud __instance) { try { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { UpdateThirstHud(__instance); UpdateWaterHoverHud(__instance); UIManager.DrawFillBar(); } } catch (Exception ex) { YourThirstyPlugin.Log.LogError((object)("HudPatches error: " + ex.Message)); } } private static void UpdateThirstHud(Hud hud) { //IL_0084: 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_00a7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_thirstRoot == (Object)null) { CreateThirstHud(hud); } if ((Object)(object)_thirstRoot == (Object)null) { return; } float currentThirst = ThirstSystem.CurrentThirst; if ((Object)(object)_thirstText != (Object)null) { int num = Mathf.RoundToInt(100f - currentThirst); _thirstText.text = $"{num}%"; if (currentThirst >= 80f) { ((Graphic)_thirstText).color = Color.red; } else if (currentThirst >= 60f) { ((Graphic)_thirstText).color = Color.yellow; } else { ((Graphic)_thirstText).color = new Color(0.5f, 0.85f, 1f); } } if ((Object)(object)_thirstIcon != (Object)null) { _thirstIcon.sprite = ((currentThirst >= 60f) ? _spriteThirsty : _spriteHydrated); } } private static string GetContainerDrinkName(Player player) { if (ItemManager.CanDrinkFromContainer(player, out var state) && state != null && state.Item != null) { string text = state.Item.m_shared?.m_name; if (text == "YourThirsty_Waterskin") { return "Drink from Waterskin"; } if (text == "YourThirsty_Horn") { return "Drink from Horn"; } } return "Drink from Container"; } private static void UpdateWaterHoverHud(Hud hud) { if ((Object)(object)_hoverRoot == (Object)null) { CreateHoverHud(hud); } if ((Object)(object)_hoverRoot == (Object)null) { return; } bool flag = UIManager.IsShowingDrinkWater(); bool flag2 = UIManager.IsShowingRefillPrompt(); bool flag3 = UIManager.IsShowingDrinkContainer(); bool flag4 = UIManager.IsShowingEmptyContainer(); bool flag5 = UIManager.IsShowingFillBucket(); Player localPlayer = Player.m_localPlayer; if (flag || flag2 || flag3 || flag4 || flag5) { _hoverRoot.SetActive(true); if (!((Object)(object)_hoverText != (Object)null)) { return; } string drinkKeyName = YourThirstyPlugin.DrinkKeyName; string refillKeyName = YourThirstyPlugin.RefillKeyName; string text = ""; if (flag5) { text = text + "<color=yellow>[" + drinkKeyName + "]</color> Fill Bucket"; } if (flag) { text = text + "<color=yellow>[" + drinkKeyName + "]</color> Drink"; } if (flag2) { text = text + "<color=yellow>[" + drinkKeyName + "]</color> Refill"; } if (flag4 && !flag && !flag2) { text = text + "<color=yellow>[" + drinkKeyName + "]</color> Empty Container"; } if (flag3) { if (text.Length > 0) { text += "\n"; } text = text + "<color=yellow>[" + refillKeyName + "]</color> " + GetContainerDrinkName(localPlayer); } _hoverText.text = text; } else { _hoverRoot.SetActive(false); } } private static void CreateThirstHud(Hud hud) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Expected O, but got Unknown //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: 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_00d2: Unknown result type (might be due to invalid IL or missing references) GameObject rootObject = hud.m_rootObject; if ((Object)(object)rootObject == (Object)null) { return; } if ((Object)(object)YourThirstyPlugin.AssetBundle != (Object)null) { Texture2D val = YourThirstyPlugin.AssetBundle.LoadAsset<Texture2D>("Hydrated"); if ((Object)(object)val != (Object)null) { _spriteHydrated = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), Vector2.one * 0.5f); } Texture2D val2 = YourThirstyPlugin.AssetBundle.LoadAsset<Texture2D>("Thirsty"); if ((Object)(object)val2 != (Object)null) { _spriteThirsty = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), Vector2.one * 0.5f); } } _thirstRoot = new GameObject("YT_ThirstHud"); _thirstRoot.transform.SetParent(rootObject.transform, false); RectTransform val3 = _thirstRoot.AddComponent<RectTransform>(); val3.anchorMin = new Vector2(0.85f, 0.02f); val3.anchorMax = new Vector2(0.95f, 0.07f); val3.offsetMin = Vector2.zero; val3.offsetMax = Vector2.zero; if ((Object)(object)_spriteHydrated != (Object)null) { GameObject val4 = new GameObject("Icon"); val4.transform.SetParent(_thirstRoot.transform, false); RectTransform val5 = val4.AddComponent<RectTransform>(); val5.anchorMin = new Vector2(0f, 0f); val5.anchorMax = new Vector2(0.3f, 1f); val5.offsetMin = Vector2.zero; val5.offsetMax = Vector2.zero; _thirstIcon = val4.AddComponent<Image>(); _thirstIcon.sprite = _spriteHydrated; _thirstIcon.preserveAspect = true; } GameObject val6 = new GameObject("Text"); val6.transform.SetParent(_thirstRoot.transform, false); RectTransform val7 = val6.AddComponent<RectTransform>(); val7.anchorMin = new Vector2(0.35f, 0f); val7.anchorMax = new Vector2(1f, 1f); val7.offsetMin = Vector2.zero; val7.offsetMax = Vector2.zero; _thirstText = val6.AddComponent<Text>(); _thirstText.font = GetDefaultFont(hud); _thirstText.fontSize = 16; ((Graphic)_thirstText).color = new Color(0.5f, 0.85f, 1f); _thirstText.text = "100%"; YourThirstyPlugin.Log.LogInfo((object)"HudPatches: Thirst HUD created."); } private static Font GetDefaultFont(Hud hud) { Text componentInChildren = hud.m_rootObject.GetComponentInChildren<Text>(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.font != (Object)null) { return componentInChildren.font; } return Resources.GetBuiltinResource<Font>("Arial.ttf"); } private static void CreateHoverHud(Hud hud) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) GameObject rootObject = hud.m_rootObject; if (!((Object)(object)rootObject == (Object)null)) { _hoverRoot = new GameObject("YT_WaterHover"); _hoverRoot.transform.SetParent(rootObject.transform, false); _hoverRoot.SetActive(false); RectTransform val = _hoverRoot.AddComponent<RectTransform>(); val.anchorMin = new Vector2(0.35f, 0.38f); val.anchorMax = new Vector2(0.65f, 0.45f); val.offsetMin = Vector2.zero; val.offsetMax = Vector2.zero; _hoverText = _hoverRoot.AddComponent<Text>(); _hoverText.font = GetDefaultFont(hud); _hoverText.fontSize = 16; _hoverText.alignment = (TextAnchor)4; _hoverText.supportRichText = true; ((Graphic)_hoverText).color = Color.white; _hoverText.text = ""; Outline val2 = _hoverRoot.AddComponent<Outline>(); ((Shadow)val2).effectColor = Color.black; ((Shadow)val2).effectDistance = new Vector2(1f, -1f); YourThirstyPlugin.Log.LogInfo((object)"HudPatches: Water hover HUD created."); } } } internal static class InteractionManager { public static void Init() { } public static void Update() { } } internal class ItemGroundGuard : MonoBehaviour { private Rigidbody _rb; private bool _physicsStarted; private float _settledTimer; private const float SettleTime = 6f; private const float MinHeightAboveTerrain = 0.1f; private void Awake() { _rb = ((Component)this).GetComponent<Rigidbody>(); } private void FixedUpdate() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_rb == (Object)null) { Object.Destroy((Object)(object)this); } else if (!_rb.isKinematic) { if (!_physicsStarted) { _physicsStarted = true; _rb.collisionDetectionMode = (CollisionDetectionMode)2; } Vector3 position = ((Component)this).transform.position; float num = 0f; if ((Object)(object)ZoneSystem.instance != (Object)null) { ZoneSystem.instance.GetGroundHeight(position, ref num); } float num2 = num + 0.1f; if (position.y < num2) { position.y = num2; ((Component)this).transform.position = position; _rb.linearVelocity = Vector3.zero; _rb.angularVelocity = Vector3.zero; } Vector3 linearVelocity = _rb.linearVelocity; if (((Vector3)(ref linearVelocity)).sqrMagnitude < 0.01f) { _settledTimer += Time.fixedDeltaTime; } else { _settledTimer = 0f; } if (_settledTimer > 6f) { Object.Destroy((Object)(object)this); } } } } internal static class ItemManager { private const string Key_Amount = "YT_Amount"; private const string Key_Dirty = "YT_Dirty"; private static readonly FieldRef<Humanoid, ItemData> _rightItemRef = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_rightItem"); public static void Init() { YourThirstyPlugin.Log.LogInfo((object)"ItemManager initialized."); } public static bool HasContainer(Player player) { return GetContainer(player) != null; } public static bool CanFill(Player player, bool dirty, out ContainerState state) { state = GetEquippedContainer(player); return state != null && state.CurrentAmount < state.MaxAmount; } public static bool CanDrinkFromContainer(Player player, out ContainerState state) { state = GetEquippedContainer(player); return state != null && state.CurrentAmount > 0; } public static bool CanDrinkFromInventory(Player player, out ContainerState state) { state = GetInventoryContainer(player); return state != null && state.CurrentAmount > 0; } public static bool CanFillFromInventory(Player player, bool dirty, out ContainerState state) { state = GetInventoryContainer(player); return state != null && state.CurrentAmount < state.MaxAmount; } public static void DrinkFromInventory(Player player) { ContainerState inventoryContainer = GetInventoryContainer(player); if (inventoryContainer == null || inventoryContainer.CurrentAmount <= 0) { SFXManager.PlayEmpty(player); return; } inventoryContainer.CurrentAmount--; SaveState(player, inventoryContainer); SyncManager.SyncContainer(player, inventoryContainer.CurrentAmount, inventoryContainer.IsDirty); } public static void FillFromInventory(Player player, bool dirty) { ContainerState inventoryContainer = GetInventoryContainer(player); if (inventoryContainer != null) { inventoryContainer.CurrentAmount = inventoryContainer.MaxAmount; inventoryContainer.IsDirty = dirty; SaveState(player, inventoryContainer); SyncManager.SyncContainer(player, inventoryContainer.CurrentAmount, inventoryContainer.IsDirty); } } private static ContainerState GetEquippedContainer(Player player) { return FindContainer(player, equippedOnly: true); } private static ContainerState GetInventoryContainer(Player player) { return FindContainer(player, equippedOnly: false); } private static ContainerState FindContainer(Player player, bool equippedOnly) { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return null; } ItemData val = (equippedOnly ? _rightItemRef.Invoke((Humanoid)(object)player) : null); foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem == null || allItem.m_shared == null || (equippedOnly && (!allItem.m_equipped || allItem != val))) { continue; } int value; if (allItem.m_shared.m_name == "YourThirsty_Waterskin") { value = ConfigManager.WaterskinCapacity.Value; } else { if (!(allItem.m_shared.m_name == "YourThirsty_Horn")) { continue; } value = ConfigManager.HornCapacity.Value; } Dictionary<string, string> customData = allItem.m_customData; int result = 0; bool isDirty = false; if (customData != null) { if (customData.TryGetValue("YT_Amount", out var value2)) { int.TryParse(value2, out result); } if (customData.TryGetValue("YT_Dirty", out var value3)) { isDirty = value3 == "1"; } } return new ContainerState(allItem, value) { CurrentAmount = result, IsDirty = isDirty }; } return null; } public static void Fill(Player player, bool dirty) { ContainerState equippedContainer = GetEquippedContainer(player); if (equippedContainer != null) { equippedContainer.CurrentAmount = equippedContainer.MaxAmount; equippedContainer.IsDirty = dirty; SaveState(player, equippedContainer); SyncManager.SyncContainer(player, equippedContainer.CurrentAmount, equippedContainer.IsDirty); } } public static void PartialFill(Player player, bool dirty, float fraction) { ContainerState equippedContainer = GetEquippedContainer(player); if (equippedContainer != null) { int num = equippedContainer.MaxAmount - equippedContainer.CurrentAmount; int num2 = Mathf.Max(1, Mathf.FloorToInt((float)num * fraction)); equippedContainer.CurrentAmount = Mathf.Min(equippedContainer.CurrentAmount + num2, equippedContainer.MaxAmount); equippedContainer.IsDirty = dirty; SaveState(player, equippedContainer); SyncManager.SyncContainer(player, equippedContainer.CurrentAmount, equippedContainer.IsDirty); } } public static void Drink(Player player) { ContainerState equippedContainer = GetEquippedContainer(player); if (equippedContainer == null || equippedContainer.CurrentAmount <= 0) { SFXManager.PlayEmpty(player); return; } equippedContainer.CurrentAmount--; SaveState(player, equippedContainer); SyncManager.SyncContainer(player, equippedContainer.CurrentAmount, equippedContainer.IsDirty); } public static bool CanEmptyContainer(Player player, out ContainerState state) { state = GetEquippedContainer(player); return state != null && state.CurrentAmount > 0; } public static void EmptyContainer(Player player) { ContainerState equippedContainer = GetEquippedContainer(player); if (equippedContainer != null && equippedContainer.CurrentAmount > 0) { equippedContainer.CurrentAmount = 0; equippedContainer.IsDirty = false; SaveState(player, equippedContainer); SyncManager.SyncContainer(player, 0, dirty: false); } } private static ContainerState GetContainer(Player player) { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return null; } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem == null || allItem.m_shared == null) { continue; } int value; if (allItem.m_shared.m_name == "YourThirsty_Waterskin") { value = ConfigManager.WaterskinCapacity.Value; } else { if (!(allItem.m_shared.m_name == "YourThirsty_Horn")) { continue; } value = ConfigManager.HornCapacity.Value; } Dictionary<string, string> customData = allItem.m_customData; int result = 0; bool isDirty = false; if (customData != null) { if (customData.TryGetValue("YT_Amount", out var value2)) { int.TryParse(value2, out result); } if (customData.TryGetValue("YT_Dirty", out var value3)) { isDirty = value3 == "1"; } } return new ContainerState(allItem, value) { CurrentAmount = result, IsDirty = isDirty }; } return null; } private static void SaveState(Player player, ContainerState state) { if (state != null && state.Item != null) { if (state.Item.m_customData == null) { state.Item.m_customData = new Dictionary<string, string>(); } state.Item.m_customData["YT_Amount"] = state.CurrentAmount.ToString(); state.Item.m_customData["YT_Dirty"] = (state.IsDirty ? "1" : "0"); } } public static void SaveContainerState(Player player, ContainerState state) { SaveState(player, state); SyncManager.SyncContainer(player, state.CurrentAmount, state.IsDirty); } public static string GetContainerDisplayName(Player player) { ContainerState equippedContainer = GetEquippedContainer(player); if (equippedContainer?.Item?.m_shared != null) { if (equippedContainer.Item.m_shared.m_name == "YourThirsty_Waterskin") { return "Waterskin"; } if (equippedContainer.Item.m_shared.m_name == "YourThirsty_Horn") { return "Horn"; } } return "Container"; } } internal class ContainerState { public ItemData Item; public int CurrentAmount; public int MaxAmount; public bool IsDirty; public ContainerState(ItemData item, int max) { Item = item; MaxAmount = max; CurrentAmount = 0; IsDirty = false; } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDB_Patch { [HarmonyPostfix] private static void Postfix() { if (!((Object)(object)ObjectDB.instance == (Object)null) && ObjectDB.instance.m_items.Count != 0 && !((Object)(object)ZNetScene.instance == (Object)null)) { PrefabLoader.FixAllShaders(); ItemRegistration.Init(); } } } internal static class ItemRegistration { private struct PieceReqSpec { public GameObject Prefab; public (string, int)[] Requirements; } private const string WorkbenchPiecePrefabName = "piece_workbench"; private const string HammerItemPrefabName = "Hammer"; private static ObjectDB _lastRegisteredDB; private static bool _piecesValid; private static Dictionary<int, GameObject> _namedPrefabs; private static Dictionary<int, GameObject> _itemByHash; private static readonly List<PieceReqSpec> _pieceReqSpecs = new List<PieceReqSpec>(); private const string CauldronPiecePrefabName = "piece_cauldron"; public static void Init() { if ((Object)(object)ObjectDB.instance == (Object)null) { YourThirstyPlugin.Log.LogError((object)"ItemRegistration: ObjectDB not ready."); return; } if ((Object)(object)_lastRegisteredDB == (Object)(object)ObjectDB.instance && _piecesValid) { YourThirstyPlugin.Log.LogInfo((object)"ItemRegistration: Already registered for this ObjectDB instance."); return; } _lastRegisteredDB = ObjectDB.instance; _namedPrefabs = null; _itemByHash = null; RegisterToZNetScene(PrefabLoader.Waterskin); RegisterToZNetScene(PrefabLoader.Horn); RegisterToZNetScene(PrefabLoader.Bucket); RegisterToZNetScene(PrefabLoader.Barrel); RegisterToZNetScene(PrefabLoader.Well); RegisterToZNetScene(PrefabLoader.BoilingBucket); RegisterItem(PrefabLoader.Waterskin); RegisterItem(PrefabLoader.Horn); RegisterItem(PrefabLoader.Bucket); RegisterItem(PrefabLoader.BoilWaterItem); RegisterItem(PrefabLoader.CollectBoiledWaterItem); RegisterRecipes(); RegisterCauldronRecipes(); RegisterBuildPieces(); _piecesValid = ValidatePieceRequirements(); YourThirstyPlugin.Log.LogInfo((object)$"ItemRegistration: Complete. PiecesValid={_piecesValid}"); } private static void RegisterToZNetScene(GameObject prefab) { if ((Object)(object)prefab == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return; } if ((Object)(object)prefab.GetComponent<ZNetView>() == (Object)null) { YourThirstyPlugin.Log.LogWarning((object)("Skipping ZNetScene for '" + ((Object)prefab).name + "' — no ZNetView")); return; } if (!ZNetScene.instance.m_prefabs.Contains(prefab)) { ZNetScene.instance.m_prefabs.Add(prefab); } if (_namedPrefabs == null) { _namedPrefabs = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs")?.GetValue(ZNetScene.instance) as Dictionary<int, GameObject>; } if (_namedPrefabs == null) { YourThirstyPlugin.Log.LogWarning((object)("Cannot access m_namedPrefabs — spawn/placement may not work for '" + ((Object)prefab).name + "'")); return; } int stableHashCode = GetStableHashCode(((Object)prefab).name); if (!_namedPrefabs.ContainsKey(stableHashCode)) { _namedPrefabs[stableHashCode] = prefab; YourThirstyPlugin.Log.LogInfo((object)$"Registered ZNetScene prefab: {((Object)prefab).name} (hash {stableHashCode})"); } } private static int GetStableHashCode(string s) { int num = 5381; int num2 = num; for (int i = 0; i < s.Length; i += 2) { num = ((num << 5) + num) ^ s[i]; if (i + 1 < s.Length) { num2 = ((num2 << 5) + num2) ^ s[i + 1]; } } return num + num2 * 1566083941; } private static void RegisterItem(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return; } ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { YourThirstyPlugin.Log.LogWarning((object)("Skipping item '" + ((Object)prefab).name + "' — missing ItemDrop or SharedData")); return; } if (!ObjectDB.instance.m_items.Contains(prefab)) { ObjectDB.instance.m_items.Add(prefab); YourThirstyPlugin.Log.LogInfo((object)("Registered item: " + ((Object)prefab).name)); } try { GameObject dropPrefab = component.m_itemData.m_dropPrefab; YourThirstyPlugin.Log.LogInfo((object)("ItemRegistration: '" + ((Object)prefab).name + "' dropPrefab = " + (((Object)(object)dropPrefab != (Object)null) ? ((Object)dropPrefab).name : "null"))); if ((Object)(object)dropPrefab != (Object)null) { Rigidbody component2 = dropPrefab.GetComponent<Rigidbody>(); Collider component3 = dropPrefab.GetComponent<Collider>(); YourThirstyPlugin.Log.LogInfo((object)("ItemRegistration: dropPrefab Rigidbody isKinematic=" + (((component2 != null) ? component2.isKinematic.ToString() : null) ?? "null") + ", useGravity=" + (((component2 != null) ? component2.useGravity.ToString() : null) ?? "null"))); YourThirstyPlugin.Log.LogInfo((object)("ItemRegistration: dropPrefab Collider present=" + ((Object)(object)component3 != (Object)null))); } } catch (Exception ex) { YourThirstyPlugin.Log.LogWarning((object)("ItemRegistration: Failed to inspect drop prefab for '" + ((Object)prefab).name + "': " + ex.Message)); } if (_itemByHash == null) { _itemByHash = AccessTools.Field(typeof(ObjectDB), "m_itemByHash")?.GetValue(ObjectDB.instance) as Dictionary<int, GameObject>; } if (_itemByHash != null) { int stableHashCode = GetStableHashCode(((Object)prefab).name); _itemByHash[stableHashCode] = prefab; YourThirstyPlugin.Log.LogInfo((object)$"Registered item hash: {((Object)prefab).name} (hash {stableHashCode})"); } else { YourThirstyPlugin.Log.LogWarning((object)("Cannot access m_itemByHash — dropping may not work for '" + ((Object)prefab).name + "'")); } } private static void RegisterRecipes() { AddRecipe("Waterskin", new(string, int)[2] { ("DeerHide", 4), ("LeatherScraps", 3) }); AddRecipe("Horn", new(string, int)[1] { ("TrophyBoar", 3) }); AddRecipe("WaterBucket", new(string, int)[1] { ("Wood", 5) }); } private static void RegisterCauldronRecipes() { CraftingStation val = FindCraftingStation("piece_cauldron"); if ((Object)(object)val == (Object)null) { YourThirstyPlugin.Log.LogWarning((object)"RegisterCauldronRecipes: Cauldron CraftingStation not found. Boil recipes will NOT be available."); return; } AddCauldronRecipe(PrefabLoader.BoilWaterItem, "Recipe_BoilWater", val); AddCauldronRecipe(PrefabLoader.CollectBoiledWaterItem, "Recipe_CollectBoiledWater", val); } private static void AddCauldronRecipe(GameObject dummyItem, string recipeName, CraftingStation station) { if ((Object)(object)dummyItem == (Object)null) { return; } foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if ((Object)(object)recipe != (Object)null && ((Object)recipe).name == recipeName) { YourThirstyPlugin.Log.LogInfo((object)("Cauldron recipe already registered: " + recipeName)); return; } } ItemDrop component = dummyItem.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null)) { Recipe val = ScriptableObject.CreateInstance<Recipe>(); ((Object)val).name = recipeName; val.m_item = component; val.m_craftingStation = station; val.m_amount = 1; val.m_enabled = true; val.m_resources = (Requirement[])(object)new Requirement[0]; ObjectDB.instance.m_recipes.Add(val); YourThirstyPlugin.Log.LogInfo((object)("Registered cauldron recipe: " + recipeName)); } } private static void RegisterBuildPieces() { CraftingStation val = FindCraftingStation("piece_workbench"); if ((Object)(object)val == (Object)null) { YourThirstyPlugin.Log.LogWarning((object)"RegisterBuildPieces: Workbench not found — pieces will be buildable anywhere!"); } AddPiece(PrefabLoader.Barrel, (PieceCategory)0, "BarreICON", new(string, int)[1] { ("Wood", 10) }, val); AddPiece(PrefabLoader.Well, (PieceCategory)0, "WellICON", new(string, int)[2] { ("Stone", 20), ("Wood", 10) }, val); AddPieceToHammer(PrefabLoader.BoilingBucket); if ((Object)(object)PrefabLoader.BoilingBucket != (Object)null && (Object)(object)val != (Object)null) { Piece component = PrefabLoader.BoilingBucket.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { component.m_craftingStation = val; } } } private static void AddRecipe(string itemName, (string, int)[] reqs) { foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if ((Object)(object)recipe != (Object)null && ((Object)recipe).name == "Recipe_" + itemName) { YourThirstyPlugin.Log.LogInfo((object)("Recipe already registered: " + itemName)); return; } } GameObject val = FindItemPrefab(itemName); if ((Object)(object)val == (Object)null) { YourThirstyPlugin.Log.LogError((object)("AddRecipe: Item '" + itemName + "' not found in ObjectDB.m_items.")); return; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { YourThirstyPlugin.Log.LogError((object)("AddRecipe: '" + itemName + "' has no ItemDrop.")); return; } CraftingStation val2 = FindCraftingStation("piece_workbench"); if ((Object)(object)val2 == (Object)null) { YourThirstyPlugin.Log.LogError((object)"AddRecipe: CraftingStation 'piece_workbench' not found."); return; } Recipe val3 = ScriptableObject.CreateInstance<Recipe>(); ((Object)val3).name = "Recipe_" + itemName; val3.m_item = component; val3.m_craftingStation = val2; val3.m_amount = 1; val3.m_enabled = true; val3.m_resources = BuildReqs(reqs); ObjectDB.instance.m_recipes.Add(val3); YourThirstyPlugin.Log.LogInfo((object)("Registered recipe: " + itemName)); } private static CraftingStation FindCraftingStation(string piecePrefabName) { if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(piecePrefabName); if ((Object)(object)prefab != (Object)null) { CraftingStation component = prefab.GetComponent<CraftingStation>(); if ((Object)(object)component != (Object)null) { return component; } } foreach (GameObject prefab2 in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab2 != (Object)null && ((Object)prefab2).name == piecePrefabName) { CraftingStation component2 = prefab2.GetComponent<CraftingStation>(); if ((Object)(object)component2 != (Object)null) { YourThirstyPlugin.Log.LogInfo((object)("FindCraftingStation: Found '" + piecePrefabName + "' via prefab list fallback.")); return component2; } } } } GameObject val = FindItemPrefab(piecePrefabName); return ((Object)(object)val != (Object)null) ? val.GetComponent<CraftingStation>() : null; } private static void AddPiece(GameObject prefab, PieceCategory category, string iconName, (string, int)[] reqs, CraftingStation station = null) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null) { YourThirstyPlugin.Log.LogError((object)"AddPiece: Prefab is null."); return; } bool flag = false; for (int i = 0; i < _pieceReqSpecs.Count; i++) { if ((Object)(object)_pieceReqSpecs[i].Prefab == (Object)(object)prefab) { _pieceReqSpecs[i] = new PieceReqSpec { Prefab = prefab, Requirements = reqs }; flag = true; break; } } if (!flag) { _pieceReqSpecs.Add(new PieceReqSpec { Prefab = prefab, Requirements = reqs }); } Piece val = prefab.GetComponent<Piece>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<Piece>(); val.m_name = ((Object)prefab).name; val.m_description = ""; YourThirstyPlugin.Log.LogInfo((object)("AddPiece: Added Piece component to '" + ((Object)prefab).name + "'.")); } val.m_category = category; val.m_craftingStation = station; val.m_groundPiece = false; val.m_groundOnly = false; Requirement[] array = (val.m_resources = BuildReqs(reqs)); if (array.Length == 0 && reqs.Length != 0) { YourThirstyPlugin.Log.LogError((object)($"AddPiece: '{((Object)prefab).name}' has 0 requirements (expected {reqs.Length}) — " + "vanilla items not found! Piece will be FREE to build.")); } else { YourThirstyPlugin.Log.LogInfo((object)($"AddPiece: '{((Object)prefab).name}' — {array.Length} requirements, " + "station=" + (((station != null) ? ((Object)station).name : null) ?? "NONE"))); } if ((Object)(object)YourThirstyPlugin.AssetBundle != (Object)null && !string.IsNullOrEmpty(iconName)) { Texture2D val2 = YourThirstyPlugin.AssetBundle.LoadAsset<Texture2D>(iconName); if ((Object)(object)val2 != (Object)null) { val.m_icon = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), Vector2.one * 0.5f); } else { YourThirstyPlugin.Log.LogWarning((object)("AddPiece: Icon '" + iconName + "' not found for '" + ((Object)prefab).name + "'")); } } GameObject val3 = FindItemPrefab("Hammer"); if ((Object)(object)val3 == (Object)null) { YourThirstyPlugin.Log.LogError((object)"AddPiece: Hammer prefab not found."); return; } ItemDrop component = val3.GetComponent<ItemDrop>(); PieceTable val4 = (((Object)(object)component != (Object)null) ? component.m_itemData.m_shared.m_buildPieces : null); if ((Object)(object)val4 == (Object)null) { YourThirstyPlugin.Log.LogError((object)"AddPiece: Hammer has no build piece table."); } else if (!val4.m_pieces.Contains(prefab)) { val4.m_pieces.Add(prefab); YourThirstyPlugin.Log.LogInfo((object)("Registered build piece: " + ((Object)prefab).name)); } } private static GameObject FindItemPrefab(string name) { if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(name); if ((Object)(object)prefab != (Object)null) { return prefab; } } if ((Object)(object)ObjectDB.instance != (Object)null) { List<GameObject> items = ObjectDB.instance.m_items; for (int i = 0; i < items.Count; i++) { GameObject val = items[i]; if ((Object)(object)val != (Object)null && ((Object)val).name == name) { return val; } } } if ((Object)(object)ObjectDB.instance != (Object)null) { try { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name); if ((Object)(object)itemPrefab != (Object)null) { YourThirstyPlugin.Log.LogInfo((object)("FindItemPrefab: Found '" + name + "' via ObjectDB.GetItemPrefab.")); return itemPrefab; } } catch { } } if ((Object)(object)ZNetScene.instance != (Object)null) { string text = name.ToLowerInvariant(); foreach (GameObject prefab2 in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab2 != (Object)null && ((Object)prefab2).name.ToLowerInvariant() == text) { YourThirstyPlugin.Log.LogInfo((object)("FindItemPrefab: Found '" + name + "' via case-insensitive match '" + ((Object)prefab2).name + "'.")); return prefab2; } } } if ((Object)(object)ZNetScene.instance != (Object)null) { foreach (GameObject prefab3 in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab3 != (Object)null && ((Object)prefab3).name == name) { YourThirstyPlugin.Log.LogInfo((object)("FindItemPrefab: Found '" + name + "' via brute-force prefab list (hash may be stale).")); return prefab3; } } } YourThirstyPlugin.Log.LogWarning((object)("FindItemPrefab: '" + name + "' not found in ZNetScene or ObjectDB.")); return null; } private static void AddPieceToHammer(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return; } GameObject val = FindItemPrefab("Hammer"); if ((Object)(object)val == (Object)null) { YourThirstyPlugin.Log.LogError((object)"AddPieceToHammer: Hammer prefab not found."); return; } ItemDrop component = val.GetComponent<ItemDrop>(); PieceTable val2 = (((Object)(object)component != (Object)null) ? component.m_itemData.m_shared.m_buildPieces : null); if ((Object)(object)val2 == (Object)null) { YourThirstyPlugin.Log.LogError((object)"AddPieceToHammer: Hammer has no build piece table."); } else if (!val2.m_pieces.Contains(prefab)) { val2.m_pieces.Add(prefab); YourThirstyPlugin.Log.LogInfo((object)("Registered build piece (pre-configured): " + ((Object)prefab).name)); } } private static Requirement[] BuildReqs((string, int)[] reqs) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown List<Requirement> list = new List<Requirement>(); for (int i = 0; i < reqs.Length; i++) { (string, int) tuple = reqs[i]; string item = tuple.Item1; int item2 = tuple.Item2; GameObject val = FindItemPrefab(item); if ((Object)(object)val == (Object)null) { YourThirstyPlugin.Log.LogError((object)("BuildReqs: Missing item '" + item + "' — piece will be free of this resource!")); continue; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { YourThirstyPlugin.Log.LogError((object)("BuildReqs: '" + item + "' (prefab '" + ((Object)val).name + "') has no ItemDrop — skipping.")); } else { list.Add(new Requirement { m_resItem = component, m_amount = item2, m_recover = true }); YourThirstyPlugin.Log.LogInfo((object)$"BuildReqs: Added requirement '{item}' x{item2} (prefab '{((Object)val).name}')"); } } return list.ToArray(); } private static bool ValidatePieceRequirements() { bool allValid = true; Check(PrefabLoader.Barrel, 1); Check(PrefabLoader.Well, 2); if (!allValid) { YourThirstyPlugin.Log.LogWarning((object)"ValidatePieceReqs: Stale/missing requirements detected — refreshing from current ZNetScene."); RefreshPieceRequirements(); } return allValid; void Check(GameObject prefab, int expectedReqs) { if (!((Object)(object)prefab == (Object)null)) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { YourThirstyPlugin.Log.LogError((object)("ValidatePieceReqs: '" + ((Object)prefab).name + "' has no Piece component!")); allValid = false; } else { Requirement[] resources = component.m_resources; int num = ((resources != null) ? resources.Length : 0); if (num < expectedReqs) { YourThirstyPlugin.Log.LogError((object)($"ValidatePieceReqs: '{((Object)prefab).name}' has {num}/{expectedReqs} requirements — " + "materials will be missing! Will retry on next Init.")); allValid = false; } else { for (int i = 0; i < component.m_resources.Length; i++) { Requirement val = component.m_resources[i]; if ((Object)(object)val.m_resItem == (Object)null) { YourThirstyPlugin.Log.LogError((object)$"ValidatePieceReqs: '{((Object)prefab).name}' requirement[{i}] has null/destroyed m_resItem!"); allValid = false; } else { YourThirstyPlugin.Log.LogInfo((object)string.Format("ValidatePieceReqs: '{0}' req[{1}] = '{2}' x{3} ✓", ((Object)prefab).name, i, val.m_resItem.m_itemData?.m_shared?.m_name ?? "?", val.m_amount)); } } } } } } } public static void RefreshPieceRequirements() { if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { YourThirstyPlugin.Log.LogWarning((object)"RefreshPieceRequirements: ZNetScene/ObjectDB not ready."); return; } int num = 0; foreach (PieceReqSpec pieceReqSpec in _pieceReqSpecs) { if ((Object)(object)pieceReqSpec.Prefab == (Object)null) { continue; } Piece component = pieceReqSpec.Prefab.GetComponent<Piece>(); if (!((Object)(object)component == (Object)null)) { Requirement[] array = BuildReqs(pieceReqSpec.Requirements); if (array.Length >= pieceReqSpec.Requirements.Length) {