Decompiled source of YourThirsty v2.0.0

YourThirsty.dll

Decompiled 12 hours ago
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)
					{