Decompiled source of RainDance v0.3.6

Pix.RainDance.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;

[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: AssemblyVersion("0.0.0.0")]
[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;
		}
	}
}
namespace Pix.RainDance
{
	[BepInPlugin("Pix.RainDance", "RainDance", "0.3.6")]
	public sealed class RainDancePlugin : BaseUnityPlugin
	{
		private enum PendingMode
		{
			Weather,
			Sun
		}

		private struct PendingDestruct
		{
			public ZDOID Zdoid;

			public Vector3 Pos;

			public long StrikeAtMs;

			public long DestroyAtMs;

			public bool Struck;
		}

		private sealed class RainDanceTotem : MonoBehaviour, Hoverable, Interactable
		{
			private ZNetView _nview;

			private void Awake()
			{
				_nview = ((Component)this).GetComponent<ZNetView>();
			}

			public string GetHoverName()
			{
				return "Rain Dance Totem";
			}

			public string GetHoverText()
			{
				if (CfgEnabled == null || !CfgEnabled.Value)
				{
					return "Disabled";
				}
				long num = NowMs();
				long num2 = 0L;
				long val = 0L;
				if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO() != null)
				{
					ZDO zDO = _nview.GetZDO();
					num2 = zDO.GetLong("RD_RitualEndMs", 0L);
					val = zDO.GetLong("RD_CooldownEndMs", 0L);
				}
				if (num2 > num)
				{
					return "[E] Tempt the skies\n[F] Tempt the sun\n<color=#cfd7df>(ritual in progress)</color>";
				}
				long num3 = Math.Max(GetGlobalCooldownEndMs(), val);
				string text = ((CfgSelfDestructAfterUse != null && CfgSelfDestructAfterUse.Value) ? "\n<color=#9fdcff>The wood smells of storm.</color>" : "");
				if (num3 > num)
				{
					int num4 = Mathf.CeilToInt((float)(num3 - num) / 1000f);
					return $"[E] Tempt the skies\n[F] Tempt the sun\n<color=#cfd7df>(cooldown {num4}s)</color>{text}";
				}
				return "[E] Tempt the skies\n[F] Tempt the sun" + text;
			}

			private bool ClientCanStartRitual()
			{
				long num = NowMs();
				long num2 = 0L;
				long val = 0L;
				if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO() != null)
				{
					ZDO zDO = _nview.GetZDO();
					num2 = zDO.GetLong("RD_RitualEndMs", 0L);
					val = zDO.GetLong("RD_CooldownEndMs", 0L);
				}
				if (num2 > num)
				{
					return false;
				}
				long num3 = Math.Max(GetGlobalCooldownEndMs(), val);
				if (num3 > num)
				{
					return false;
				}
				return true;
			}

			public bool Interact(Humanoid user, bool hold, bool alt)
			{
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				if (hold)
				{
					return false;
				}
				if (CfgEnabled == null || !CfgEnabled.Value)
				{
					return true;
				}
				if (!ClientCanStartRitual())
				{
					return true;
				}
				StartLocalRitualVibe(user);
				TryRegisterRpcs(force: false);
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance == null)
				{
					return true;
				}
				if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO() != null)
				{
					instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RD_ServerBeginRitual", new object[1] { _nview.GetZDO().m_uid });
				}
				return true;
			}

			internal void TriggerSunRitual(Humanoid user)
			{
				//IL_009e: Unknown result type (might be due to invalid IL or missing references)
				if (CfgEnabled != null && CfgEnabled.Value && ClientCanStartRitual())
				{
					StartLocalRitualVibe(user);
					TryRegisterRpcs(force: false);
					ZRoutedRpc instance = ZRoutedRpc.instance;
					if (instance != null && (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO() != null)
					{
						instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RD_ServerBeginSunRitual", new object[1] { _nview.GetZDO().m_uid });
					}
				}
			}

			private static void StartLocalRitualVibe(Humanoid user)
			{
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				Player val = (Player)(object)((user is Player) ? user : null);
				if ((Object)(object)val != (Object)null)
				{
					try
					{
						val.StartEmote("dance", true);
					}
					catch
					{
					}
					if (CfgPlayDrumOnInteract != null && CfgPlayDrumOnInteract.Value)
					{
						float volume = ((CfgDrumVolume != null) ? Mathf.Clamp01(CfgDrumVolume.Value) : 0.75f);
						PlayOneShot(_drumClip, ((Component)val).transform.position, volume);
					}
				}
			}

			public bool UseItem(Humanoid user, ItemData item)
			{
				return false;
			}
		}

		private static class Patches
		{
			[HarmonyPatch(typeof(ZNetScene), "Awake")]
			[HarmonyPostfix]
			private static void ZNetScene_Awake_Postfix(ZNetScene __instance)
			{
				EnsurePrefabLoaded();
				RegisterPrefabInZNetScene();
				ApplyPlacementAndBreakEffectsIfPossible();
				TryRegisterRpcs(force: true);
			}

			[HarmonyPatch(typeof(ObjectDB), "Awake")]
			[HarmonyPostfix]
			private static void ObjectDB_Awake_Postfix(ObjectDB __instance)
			{
				EnsurePrefabLoaded();
				TryAddToHammer(__instance);
				ApplyBuildCostIfPossible();
				ApplyPlacementAndBreakEffectsIfPossible();
			}

			[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
			[HarmonyPostfix]
			private static void ObjectDB_CopyOtherDB_Postfix(ObjectDB __instance)
			{
				EnsurePrefabLoaded();
				TryAddToHammer(__instance);
				ApplyBuildCostIfPossible();
				ApplyPlacementAndBreakEffectsIfPossible();
			}

			[HarmonyPatch(typeof(EnvMan), "Update")]
			[HarmonyPostfix]
			private static void EnvMan_Update_Postfix(EnvMan __instance)
			{
				if (CfgEnabled == null || !CfgEnabled.Value)
				{
					return;
				}
				TryRegisterRpcs(force: false);
				LateInitOnce();
				ApplyPlacementAndBreakEffectsIfPossible();
				long num = NowMs();
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
				{
					ServerTick();
				}
				else if (_clientForcedUntilMs > num)
				{
					ApplyEnvLocal(_clientForcedEnv);
					if (_clientForcedTimeEnabled)
					{
						ApplyDebugTimeLocal(enabled: true, _clientForcedTimeOfDay);
					}
				}
				else if (_clientForcedUntilMs != 0)
				{
					_clientForcedUntilMs = 0L;
					_clientForcedEnv = "";
					ApplyEnvLocal("");
					if (_clientForcedTimeEnabled)
					{
						_clientForcedTimeEnabled = false;
						ApplyDebugTimeLocal(enabled: false, 0.5f);
					}
				}
			}

			[HarmonyPatch(typeof(Player), "Update")]
			[HarmonyPostfix]
			private static void Player_Update_Postfix(Player __instance)
			{
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if ((Object)(object)__instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || CfgEnabled == null || !CfgEnabled.Value || CfgSunHotkey == null || IsTextInputOpen())
					{
						return;
					}
					KeyboardShortcut value = CfgSunHotkey.Value;
					if (!((KeyboardShortcut)(ref value)).IsDown())
					{
						return;
					}
					long num = NowMs();
					long globalCooldownEndMs = GetGlobalCooldownEndMs();
					if (globalCooldownEndMs > num)
					{
						return;
					}
					GameObject val = TryGetLocalHoverObject(__instance);
					if (!((Object)(object)val == (Object)null))
					{
						RainDanceTotem rainDanceTotem = val.GetComponent<RainDanceTotem>() ?? val.GetComponentInParent<RainDanceTotem>() ?? val.GetComponentInChildren<RainDanceTotem>(true);
						if (!((Object)(object)rainDanceTotem == (Object)null))
						{
							rainDanceTotem.TriggerSunRitual((Humanoid)(object)__instance);
						}
					}
				}
				catch
				{
				}
			}
		}

		[CompilerGenerated]
		private sealed class <LoadClipCoroutine>d__129 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Func<string> getFileName;

			public Action<AudioClip> assign;

			private string <pluginFolder>5__1;

			private string <fileName>5__2;

			private string <path>5__3;

			private string <url>5__4;

			private UnityWebRequest <req>5__5;

			private AudioClip <clip>5__6;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadClipCoroutine>d__129(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();
					}
				}
				<pluginFolder>5__1 = null;
				<fileName>5__2 = null;
				<path>5__3 = null;
				<url>5__4 = null;
				<req>5__5 = null;
				<clip>5__6 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_013d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0143: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						<pluginFolder>5__1 = Path.GetDirectoryName(typeof(RainDancePlugin).Assembly.Location) ?? Paths.PluginPath;
						<fileName>5__2 = ((getFileName != null) ? getFileName() : null) ?? "";
						<fileName>5__2 = <fileName>5__2.Trim();
						if (<fileName>5__2.Length == 0)
						{
							result = false;
							break;
						}
						<path>5__3 = Path.Combine(<pluginFolder>5__1, <fileName>5__2);
						if (!File.Exists(<path>5__3))
						{
							result = false;
							break;
						}
						<url>5__4 = "file://" + <path>5__3.Replace("\\", "/");
						<req>5__5 = UnityWebRequestMultimedia.GetAudioClip(<url>5__4, (AudioType)14);
						<>1__state = -3;
						<>2__current = <req>5__5.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					case 1:
						<>1__state = -3;
						if ((int)<req>5__5.result != 1)
						{
							result = false;
							<>m__Finally1();
							break;
						}
						<clip>5__6 = null;
						try
						{
							<clip>5__6 = DownloadHandlerAudioClip.GetContent(<req>5__5);
						}
						catch
						{
							<clip>5__6 = null;
						}
						if ((Object)(object)<clip>5__6 != (Object)null)
						{
							assign?.Invoke(<clip>5__6);
						}
						<clip>5__6 = null;
						<>m__Finally1();
						<req>5__5 = null;
						result = false;
						break;
					}
				}
				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;
				if (<req>5__5 != null)
				{
					((IDisposable)<req>5__5).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PluginGuid = "Pix.RainDance";

		public const string PluginName = "RainDance";

		public const string PluginVersion = "0.3.6";

		internal static ManualLogSource Log;

		private static RainDancePlugin _instance;

		private static AssetBundle _bundle;

		private static GameObject _totemPrefab;

		private const string ZdoTotemCooldownEndMs = "RD_CooldownEndMs";

		private const string ZdoTotemRitualEndMs = "RD_RitualEndMs";

		private const string ZdoTotemRitualMode = "RD_RitualMode";

		private const string ZdoTotemRitualNonce = "RD_RitualNonce";

		private const string RpcServerBeginRitual = "RD_ServerBeginRitual";

		private const string RpcServerBeginSunRitual = "RD_ServerBeginSunRitual";

		private const string RpcClientSetEnv = "RD_ClientSetEnv";

		private const string RpcClientVerdict = "RD_ClientVerdict";

		private const string RpcClientSetGlobalCooldown = "RD_SetGlobalCooldown";

		private const string RpcClientLightningVfx = "RD_ClientLightningVfx";

		private const string RpcClientMythLine = "RD_ClientMythLine";

		private const string RpcClientSetDebugTime = "RD_ClientSetDebugTime";

		private static ConfigEntry<bool> CfgEnabled;

		private static ConfigEntry<string> CfgPreset;

		private static ConfigEntry<bool> CfgApplyMostlyClearNow;

		private static ConfigEntry<bool> CfgApplyChaosWeatherNow;

		private static ConfigEntry<float> CfgGlobalCooldownSeconds;

		private static ConfigEntry<float> CfgAnticipationSeconds;

		private static ConfigEntry<float> CfgForcedDurationSeconds;

		private static ConfigEntry<float> CfgChanceWeatherChange;

		private static ConfigEntry<float> CfgChanceGoodWhenChanging;

		private static ConfigEntry<string> CfgGoodEnvsCsv;

		private static ConfigEntry<string> CfgBadEnvsCsv;

		private static ConfigEntry<float> CfgClearWeatherBadBias;

		private static ConfigEntry<float> CfgClearWeatherChangeBoost;

		private static ConfigEntry<KeyboardShortcut> CfgSunHotkey;

		private static ConfigEntry<float> CfgSunChanceChange;

		private static ConfigEntry<float> CfgSunChanceGoodWhenChanging;

		private static ConfigEntry<string> CfgSunGoodEnvsCsv;

		private static ConfigEntry<string> CfgSunBadEnvsCsv;

		private static ConfigEntry<string> CfgSunGoodTimesCsv;

		private static ConfigEntry<string> CfgSunBadTimesCsv;

		private static ConfigEntry<bool> CfgPlayDrumOnInteract;

		private static ConfigEntry<float> CfgDrumVolume;

		private static ConfigEntry<string> CfgDrumFileName;

		private static ConfigEntry<bool> CfgPlayVerdictOnVerdict;

		private static ConfigEntry<float> CfgVerdictVolume;

		private static ConfigEntry<string> CfgVerdictFileName;

		private static ConfigEntry<bool> CfgEnableVerdictVfx;

		private static ConfigEntry<bool> CfgSelfDestructAfterUse;

		private static ConfigEntry<float> CfgSelfDestructDelaySeconds;

		private static ConfigEntry<bool> CfgSpawnLightningAoeServer;

		private static ConfigEntry<bool> CfgAlsoPlayClientLightningVfx;

		private static ConfigEntry<bool> CfgEnableMythLines;

		private static ConfigEntry<bool> CfgMythLinesRevealEnvInLogs;

		private static ConfigEntry<bool> CfgLogDebug;

		private static ConfigEntry<bool> CfgDebugForceWeatherChange;

		private static ConfigEntry<string> CfgBuildCostCsv;

		private static bool _rpcsRegistered;

		private static long _nextRpcRetryMs;

		private static bool _registeredInZNetScene;

		private static bool _addedToHammer;

		private static bool _costApplied;

		private static bool _effectsApplied;

		private static bool _iconApplied;

		private static string _serverForcedEnv = "";

		private static long _serverForcedUntilMs = 0L;

		private static string _clientForcedEnv = "";

		private static long _clientForcedUntilMs = 0L;

		private static bool _serverForcedTimeEnabled = false;

		private static float _serverForcedTimeOfDay = 0.5f;

		private static bool _clientForcedTimeEnabled = false;

		private static float _clientForcedTimeOfDay = 0.5f;

		private static long _serverGlobalCooldownEndMs = 0L;

		private static long _clientGlobalCooldownEndMs = 0L;

		private static bool _pending;

		private static PendingMode _pendingMode;

		private static ZDOID _pendingTotemZdoid;

		private static Vector3 _pendingTotemPos;

		private static long _pendingResolveAtMs;

		private static long _pendingNonce;

		private static AudioClip _drumClip;

		private static bool _drumClipRequested;

		private static AudioClip _verdictClip;

		private static bool _verdictClipRequested;

		private static long _nextForcedEnvBroadcastMs = 0L;

		private const string LightningAoePrefabName = "lightningAOE";

		private static readonly List<PendingDestruct> _pendingDestructs = new List<PendingDestruct>(8);

		private static readonly FieldRef<Player, GameObject> PlayerHoveringRef = AccessTools.FieldRefAccess<Player, GameObject>("m_hovering");

		private void Awake()
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			_instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_registeredInZNetScene = false;
			_addedToHammer = false;
			_costApplied = false;
			_effectsApplied = false;
			_iconApplied = false;
			_serverForcedTimeEnabled = false;
			_clientForcedTimeEnabled = false;
			CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable/disable RainDance.");
			CfgPreset = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Preset", "MostlyClear", new ConfigDescription("Preset: Custom, MostlyClear, ChaosWeather", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "MostlyClear", "ChaosWeather" }), Array.Empty<object>()));
			CfgApplyMostlyClearNow = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ApplyMostlyClearNow", false, "Click to apply MostlyClear values now (auto-resets).");
			CfgApplyChaosWeatherNow = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ApplyChaosWeatherNow", false, "Click to apply ChaosWeather values now (auto-resets).");
			CfgGlobalCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GlobalCooldownSeconds", 240f, "GLOBAL cooldown (seconds).");
			CfgAnticipationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "AnticipationSeconds", 7f, "Dance time before verdict (seconds).");
			CfgForcedDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ForcedDurationSeconds", 300f, "How long the chosen env is forced (seconds).");
			CfgChanceWeatherChange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ChanceWeatherChange", 0.75f, "WEATHER: Chance (0-1) the ritual changes weather (vs no change).");
			CfgChanceGoodWhenChanging = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ChanceGoodWhenChanging", 0.65f, "WEATHER: If changing weather, chance (0-1) it is Good vs Bad.");
			CfgGoodEnvsCsv = ((BaseUnityPlugin)this).Config.Bind<string>("General", "GoodEnvsCsv", "Clear", "WEATHER: Good env pool.");
			CfgBadEnvsCsv = ((BaseUnityPlugin)this).Config.Bind<string>("General", "BadEnvsCsv", "Rain,LightRain,ThunderStorm,Misty,Snow,SnowStorm", "WEATHER: Bad env pool.");
			CfgClearWeatherBadBias = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ClearWeatherBadBias", 0.25f, "WEATHER: When weather is clear-ish, reduce Good chance by this amount.");
			CfgClearWeatherChangeBoost = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ClearWeatherChangeBoost", 0.1f, "WEATHER: When weather is clear-ish, boost ChanceWeatherChange by this amount.");
			CfgSunHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SunRitual", "SunHotkey", new KeyboardShortcut((KeyCode)102, Array.Empty<KeyCode>()), "Hotkey to Tempt the sun while hovering the totem.");
			CfgSunChanceChange = ((BaseUnityPlugin)this).Config.Bind<float>("SunRitual", "SunChanceChange", 0.8f, "SUN: Chance (0-1) to change to a sun/night outcome (vs no change). Default 0.80 (20% no change).");
			CfgSunChanceGoodWhenChanging = ((BaseUnityPlugin)this).Config.Bind<float>("SunRitual", "SunChanceGoodWhenChanging", 0.75f, "SUN: If changing, chance (0-1) of 'good' (dawn/day/evening) vs 'bad' (night). Default 0.75.");
			CfgSunGoodEnvsCsv = ((BaseUnityPlugin)this).Config.Bind<string>("SunRitual", "SunGoodEnvsCsv", "Clear,LightClouds,Twilight_Clear", "SUN: Good env pool (sun-ish).");
			CfgSunBadEnvsCsv = ((BaseUnityPlugin)this).Config.Bind<string>("SunRitual", "SunBadEnvsCsv", "Darklands_dark,Misty", "SUN: Bad env pool (night-ish).");
			CfgSunGoodTimesCsv = ((BaseUnityPlugin)this).Config.Bind<string>("SunRitual", "SunGoodTimesCsv", "0.22,0.30,0.38,0.50,0.65,0.72", "SUN: Good time-of-day pool (0..1): dawn/morning/noon/evening.");
			CfgSunBadTimesCsv = ((BaseUnityPlugin)this).Config.Bind<string>("SunRitual", "SunBadTimesCsv", "0.00,0.05,0.90,0.95", "SUN: Bad time-of-day pool (0..1): midnight/late night.");
			CfgPlayDrumOnInteract = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "PlayDrumOnInteract", true, "Play drum on ritual start (client-side).");
			CfgDrumVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "DrumVolume", 0.75f, "Drum volume (0-1).");
			CfgDrumFileName = ((BaseUnityPlugin)this).Config.Bind<string>("Audio", "DrumFileName", "RD_Drums.ogg", "Drum filename.");
			CfgPlayVerdictOnVerdict = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "PlayVerdictOnVerdict", true, "Play verdict sting at verdict (client-side).");
			CfgVerdictVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "VerdictVolume", 1f, "Verdict volume (0-1). Default 1.0 (100%).");
			CfgVerdictFileName = ((BaseUnityPlugin)this).Config.Bind<string>("Audio", "VerdictFileName", "RD_Verdict.ogg", "Verdict filename.");
			CfgEnableVerdictVfx = ((BaseUnityPlugin)this).Config.Bind<bool>("VFX", "EnableVerdictVfx", true, "Spawn verdict VFX at verdict.");
			CfgSelfDestructAfterUse = ((BaseUnityPlugin)this).Config.Bind<bool>("Lore", "SelfDestructAfterUse", true, "After a ritual, the totem destroys itself.");
			CfgSelfDestructDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Lore", "SelfDestructDelaySeconds", 1.05f, "Delay between verdict and destruction (seconds).");
			CfgSpawnLightningAoeServer = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "SpawnLightningAoeServer", true, "Spawn lightningAOE via ZNetScene.SpawnObject on the server (authoritative).");
			CfgAlsoPlayClientLightningVfx = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "AlsoPlayClientLightningVfx", true, "Also tell every client to locally spawn lightningAOE for visuals (reliable).");
			CfgEnableMythLines = ((BaseUnityPlugin)this).Config.Bind<bool>("Lore", "EnableMythLines", true, "Show cryptic myth lines instead of naming the env.");
			CfgMythLinesRevealEnvInLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "RevealEnvInLogs", false, "Debug only: print the chosen env/time to log.");
			CfgLogDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogDebug", false, "Debug logs.");
			CfgDebugForceWeatherChange = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugForceWeatherChange", false, "WEATHER: Always change weather (testing).");
			CfgBuildCostCsv = ((BaseUnityPlugin)this).Config.Bind<string>("BuildCost", "CostCsv", "Wood:10,Thunderstone:1", "Build cost as CSV: ItemName:Amount,ItemName:Amount ... Example: Wood:10,Thunderstone:1");
			CfgBuildCostCsv.SettingChanged += delegate
			{
				_costApplied = false;
			};
			CfgApplyMostlyClearNow.SettingChanged += delegate
			{
				if (CfgApplyMostlyClearNow.Value)
				{
					ApplyPresetValues("MostlyClear");
					CfgPreset.Value = "MostlyClear";
					CfgApplyMostlyClearNow.Value = false;
				}
			};
			CfgApplyChaosWeatherNow.SettingChanged += delegate
			{
				if (CfgApplyChaosWeatherNow.Value)
				{
					ApplyPresetValues("ChaosWeather");
					CfgPreset.Value = "ChaosWeather";
					CfgApplyChaosWeatherNow.Value = false;
				}
			};
			Harmony.CreateAndPatchAll(typeof(Patches), "Pix.RainDance");
			EnsurePrefabLoaded();
			TryRegisterRpcs(force: true);
			TryRequestDrumClipLoad();
			TryRequestVerdictClipLoad();
		}

		private static void ApplyPresetIfNeeded()
		{
			string text = ((CfgPreset != null) ? CfgPreset.Value : "MostlyClear") ?? "MostlyClear";
			text = text.Trim();
			if (!text.Equals("Custom", StringComparison.OrdinalIgnoreCase))
			{
				ApplyPresetValues(text);
			}
		}

		private static void ApplyPresetValues(string preset)
		{
			if (!string.IsNullOrWhiteSpace(preset))
			{
				preset = preset.Trim();
				if (preset.Equals("MostlyClear", StringComparison.OrdinalIgnoreCase))
				{
					CfgGlobalCooldownSeconds.Value = 240f;
					CfgAnticipationSeconds.Value = 7f;
					CfgForcedDurationSeconds.Value = 300f;
					CfgChanceWeatherChange.Value = 0.75f;
					CfgChanceGoodWhenChanging.Value = 0.68f;
					CfgGoodEnvsCsv.Value = "Clear";
					CfgBadEnvsCsv.Value = "Rain,LightRain,ThunderStorm,Misty,Snow,SnowStorm";
					CfgClearWeatherBadBias.Value = 0.25f;
					CfgClearWeatherChangeBoost.Value = 0.1f;
				}
				else if (preset.Equals("ChaosWeather", StringComparison.OrdinalIgnoreCase))
				{
					CfgGlobalCooldownSeconds.Value = 120f;
					CfgAnticipationSeconds.Value = 7f;
					CfgForcedDurationSeconds.Value = 240f;
					CfgChanceWeatherChange.Value = 1f;
					CfgChanceGoodWhenChanging.Value = 0.5f;
					string value = "Clear,Rain,LightRain,ThunderStorm,Misty,Snow,SnowStorm";
					CfgGoodEnvsCsv.Value = value;
					CfgBadEnvsCsv.Value = value;
					CfgClearWeatherBadBias.Value = 0.1f;
					CfgClearWeatherChangeBoost.Value = 0f;
				}
			}
		}

		private static void Dbg(string msg)
		{
			try
			{
				if (CfgLogDebug != null && CfgLogDebug.Value && Log != null)
				{
					Log.LogInfo((object)msg);
				}
			}
			catch
			{
			}
		}

		private static long NowMs()
		{
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return (long)(ZNet.instance.GetTimeSeconds() * 1000.0);
				}
			}
			catch
			{
			}
			return (long)((double)Time.realtimeSinceStartup * 1000.0);
		}

		private static void EnsurePrefabLoaded()
		{
			if ((Object)(object)_totemPrefab != (Object)null)
			{
				return;
			}
			try
			{
				string directoryName = Path.GetDirectoryName(typeof(RainDancePlugin).Assembly.Location);
				string text = Path.Combine(directoryName ?? Paths.PluginPath, "raindance");
				if (!File.Exists(text))
				{
					Log.LogError((object)("AssetBundle not found: " + text));
					return;
				}
				if ((Object)(object)_bundle == (Object)null)
				{
					_bundle = AssetBundle.LoadFromFile(text);
					if ((Object)(object)_bundle == (Object)null)
					{
						Log.LogError((object)("Failed to load AssetBundle (null): " + text));
						return;
					}
				}
				_totemPrefab = _bundle.LoadAsset<GameObject>("RD_Totem_Root");
				if ((Object)(object)_totemPrefab == (Object)null)
				{
					Log.LogError((object)"Failed to load prefab 'RD_Totem_Root' from AssetBundle.");
					return;
				}
				Piece val = _totemPrefab.GetComponent<Piece>() ?? _totemPrefab.GetComponentInChildren<Piece>(true);
				if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)(object)_totemPrefab)
				{
					_totemPrefab = ((Component)val).gameObject;
				}
				if ((Object)(object)_totemPrefab.GetComponent<RainDanceTotem>() == (Object)null)
				{
					_totemPrefab.AddComponent<RainDanceTotem>();
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Exception preparing prefab: {arg}");
			}
		}

		private static void RegisterPrefabInZNetScene()
		{
			if (!_registeredInZNetScene && !((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)_totemPrefab == (Object)null))
			{
				List<GameObject> prefabs = ZNetScene.instance.m_prefabs;
				if (prefabs != null && !prefabs.Contains(_totemPrefab))
				{
					prefabs.Add(_totemPrefab);
				}
				_registeredInZNetScene = true;
			}
		}

		private static void TryAddToHammer(ObjectDB db)
		{
			if (_addedToHammer || (Object)(object)_totemPrefab == (Object)null || (Object)(object)db == (Object)null || db.m_items == null || db.m_items.Count == 0)
			{
				return;
			}
			GameObject itemPrefab = db.GetItemPrefab("Hammer");
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return;
			}
			PieceTable val = itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces;
			if (!((Object)(object)val == (Object)null))
			{
				if (!val.m_pieces.Contains(_totemPrefab))
				{
					val.m_pieces.Add(_totemPrefab);
				}
				_addedToHammer = true;
			}
		}

		private static List<(string item, int amount)> ParseCostCsv(string csv)
		{
			List<(string, int)> list = new List<(string, int)>(4);
			try
			{
				if (string.IsNullOrWhiteSpace(csv))
				{
					return list;
				}
				string[] array = csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
				for (int i = 0; i < array.Length; i++)
				{
					string text = (array[i] ?? "").Trim();
					if (text.Length == 0)
					{
						continue;
					}
					int num = text.IndexOf(':');
					if (num > 0)
					{
						string text2 = text.Substring(0, num).Trim();
						string s = text.Substring(num + 1).Trim();
						if (text2.Length != 0 && int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result > 0)
						{
							list.Add((text2, result));
						}
					}
				}
			}
			catch
			{
			}
			return list;
		}

		private static void ApplyBuildCostIfPossible()
		{
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			if (_costApplied || (Object)(object)ObjectDB.instance == (Object)null || (Object)(object)_totemPrefab == (Object)null)
			{
				return;
			}
			try
			{
				Piece component = _totemPrefab.GetComponent<Piece>();
				if ((Object)(object)component == (Object)null)
				{
					return;
				}
				string csv = ((CfgBuildCostCsv != null) ? CfgBuildCostCsv.Value : "Wood:10,Thunderstone:1") ?? "";
				List<(string, int)> list = ParseCostCsv(csv);
				if (list.Count == 0)
				{
					return;
				}
				List<Requirement> list2 = new List<Requirement>(list.Count);
				for (int i = 0; i < list.Count; i++)
				{
					(string, int) tuple = list[i];
					string item = tuple.Item1;
					int item2 = tuple.Item2;
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item);
					ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
					if ((Object)(object)val == (Object)null)
					{
						Dbg("BuildCost item not found or not an ItemDrop: '" + item + "'");
						continue;
					}
					list2.Add(new Requirement
					{
						m_resItem = val,
						m_amount = item2,
						m_recover = true
					});
				}
				if (list2.Count > 0)
				{
					component.m_resources = list2.ToArray();
					_costApplied = true;
				}
			}
			catch
			{
			}
		}

		private static Piece FindReferenceWoodPiece()
		{
			try
			{
				if ((Object)(object)ZNetScene.instance == (Object)null)
				{
					return null;
				}
				string[] array = new string[7] { "wood_wall_1x1", "wood_wall_2x1", "wood_wall", "wood_floor_1x1", "wood_floor", "wood_pole", "wood_beam_2m" };
				for (int i = 0; i < array.Length; i++)
				{
					GameObject prefab = ZNetScene.instance.GetPrefab(array[i]);
					if (!((Object)(object)prefab == (Object)null))
					{
						Piece component = prefab.GetComponent<Piece>();
						if (!((Object)(object)component == (Object)null) && component.m_placeEffect.m_effectPrefabs != null && component.m_placeEffect.m_effectPrefabs.Length != 0)
						{
							return component;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static void ApplyPlacementAndBreakEffectsIfPossible()
		{
			if (_effectsApplied || (Object)(object)_totemPrefab == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			try
			{
				Piece component = _totemPrefab.GetComponent<Piece>();
				if ((Object)(object)component == (Object)null)
				{
					return;
				}
				Piece val = FindReferenceWoodPiece();
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				if (val.m_placeEffect.m_effectPrefabs != null && val.m_placeEffect.m_effectPrefabs.Length != 0)
				{
					component.m_placeEffect = val.m_placeEffect;
				}
				WearNTear component2 = _totemPrefab.GetComponent<WearNTear>();
				WearNTear component3 = ((Component)val).gameObject.GetComponent<WearNTear>();
				if ((Object)(object)component2 != (Object)null && (Object)(object)component3 != (Object)null)
				{
					if (component3.m_destroyedEffect.m_effectPrefabs != null && component3.m_destroyedEffect.m_effectPrefabs.Length != 0)
					{
						component2.m_destroyedEffect = component3.m_destroyedEffect;
					}
					if (component3.m_hitEffect.m_effectPrefabs != null && component3.m_hitEffect.m_effectPrefabs.Length != 0)
					{
						component2.m_hitEffect = component3.m_hitEffect;
					}
				}
				_effectsApplied = true;
			}
			catch
			{
			}
		}

		private static void TryRegisterRpcs(bool force)
		{
			if (_rpcsRegistered && !force)
			{
				return;
			}
			long num = NowMs();
			if (!force && num < _nextRpcRetryMs)
			{
				return;
			}
			_nextRpcRetryMs = num + 500;
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null || _rpcsRegistered)
			{
				return;
			}
			try
			{
				instance.Register<ZDOID>("RD_ServerBeginRitual", (Action<long, ZDOID>)delegate(long sender, ZDOID totemZdoid)
				{
					//IL_0024: Unknown result type (might be due to invalid IL or missing references)
					if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
					{
						ServerBeginRitual(totemZdoid, PendingMode.Weather);
					}
				});
				instance.Register<ZDOID>("RD_ServerBeginSunRitual", (Action<long, ZDOID>)delegate(long sender, ZDOID totemZdoid)
				{
					//IL_0024: Unknown result type (might be due to invalid IL or missing references)
					if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
					{
						ServerBeginRitual(totemZdoid, PendingMode.Sun);
					}
				});
				instance.Register<string, long>("RD_ClientSetEnv", (Action<long, string, long>)delegate(long sender, string env, long untilMs)
				{
					_clientForcedEnv = (env ?? "").Trim();
					_clientForcedUntilMs = untilMs;
					ApplyEnvLocal(_clientForcedEnv);
				});
				instance.Register<long>("RD_SetGlobalCooldown", (Action<long, long>)delegate(long sender, long untilMs)
				{
					_clientGlobalCooldownEndMs = untilMs;
				});
				instance.Register<Vector3>("RD_ClientVerdict", (Action<long, Vector3>)delegate(long sender, Vector3 pos)
				{
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_005c: Unknown result type (might be due to invalid IL or missing references)
					if (CfgEnableVerdictVfx != null && CfgEnableVerdictVfx.Value)
					{
						SpawnVerdictVfx(pos);
					}
					if (CfgPlayVerdictOnVerdict != null && CfgPlayVerdictOnVerdict.Value)
					{
						float volume = ((CfgVerdictVolume != null) ? Mathf.Clamp01(CfgVerdictVolume.Value) : 1f);
						PlayOneShot(_verdictClip, pos, volume);
					}
				});
				instance.Register<Vector3>("RD_ClientLightningVfx", (Action<long, Vector3>)delegate(long sender, Vector3 pos)
				{
					//IL_001e: Unknown result type (might be due to invalid IL or missing references)
					if (CfgAlsoPlayClientLightningVfx == null || CfgAlsoPlayClientLightningVfx.Value)
					{
						SpawnLightningAoe_LocalVisual(pos);
					}
				});
				instance.Register<string>("RD_ClientMythLine", (Action<long, string>)delegate(long sender, string line)
				{
					if ((CfgEnableMythLines == null || CfgEnableMythLines.Value) && (Object)(object)MessageHud.instance != (Object)null && !string.IsNullOrWhiteSpace(line))
					{
						MessageHud.instance.ShowMessage((MessageType)2, line, 0, (Sprite)null, false);
					}
				});
				instance.Register<bool, float>("RD_ClientSetDebugTime", (Action<long, bool, float>)delegate(long sender, bool enabled, float tod)
				{
					_clientForcedTimeEnabled = enabled;
					_clientForcedTimeOfDay = Mathf.Repeat(tod, 1f);
					ApplyDebugTimeLocal(_clientForcedTimeEnabled, _clientForcedTimeOfDay);
				});
				_rpcsRegistered = true;
			}
			catch (Exception arg)
			{
				_rpcsRegistered = false;
				try
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)$"[RainDance] RPC registration failed; will retry. {arg}");
					}
				}
				catch
				{
				}
			}
		}

		private static long GetGlobalCooldownEndMs()
		{
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				return _serverGlobalCooldownEndMs;
			}
			return _clientGlobalCooldownEndMs;
		}

		private static void SetServerGlobalCooldownEndMs(long untilMs)
		{
			_serverGlobalCooldownEndMs = Math.Max(_serverGlobalCooldownEndMs, untilMs);
			try
			{
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RD_SetGlobalCooldown", new object[1] { _serverGlobalCooldownEndMs });
				}
			}
			catch
			{
			}
		}

		private static void BroadcastEnvToClients(string env, long untilMs)
		{
			try
			{
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RD_ClientSetEnv", new object[2]
					{
						(env ?? "").Trim(),
						untilMs
					});
				}
			}
			catch
			{
			}
		}

		private static void BroadcastDebugTimeToClients(bool enabled, float tod)
		{
			try
			{
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RD_ClientSetDebugTime", new object[2]
					{
						enabled,
						Mathf.Repeat(tod, 1f)
					});
				}
			}
			catch
			{
			}
		}

		private static void BroadcastVerdict(Vector3 pos)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RD_ClientVerdict", new object[1] { pos });
				}
			}
			catch
			{
			}
		}

		private static void BroadcastLightningVfx(Vector3 pos)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RD_ClientLightningVfx", new object[1] { pos });
				}
			}
			catch
			{
			}
		}

		private static void BroadcastMythLine(string line)
		{
			try
			{
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RD_ClientMythLine", new object[1] { line ?? "" });
				}
			}
			catch
			{
			}
		}

		private static void ServerBeginRitual(ZDOID totemZdoid, PendingMode mode)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			long num = NowMs();
			if (_pending)
			{
				return;
			}
			long globalCooldownEndMs = GetGlobalCooldownEndMs();
			if (globalCooldownEndMs > num)
			{
				return;
			}
			ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(totemZdoid) : null);
			if (val == null)
			{
				return;
			}
			long @long = val.GetLong("RD_RitualEndMs", 0L);
			if (@long <= num)
			{
				long long2 = val.GetLong("RD_CooldownEndMs", 0L);
				if (long2 <= num)
				{
					long num2 = (long)(Mathf.Max(1f, CfgAnticipationSeconds.Value) * 1000f);
					long num3 = (long)(Mathf.Max(5f, CfgGlobalCooldownSeconds.Value) * 1000f);
					val.Set("RD_RitualEndMs", num + num2);
					val.Set("RD_RitualMode", (int)mode);
					val.Set("RD_RitualNonce", num);
					SetServerGlobalCooldownEndMs(num + num3);
					val.Set("RD_CooldownEndMs", num + num3);
					Vector3 position = val.GetPosition();
					_pending = true;
					_pendingMode = mode;
					_pendingTotemZdoid = totemZdoid;
					_pendingTotemPos = position;
					_pendingResolveAtMs = num + num2;
					_pendingNonce = num;
				}
			}
		}

		private static void ServerTick()
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			long num = NowMs();
			if (_pending && num >= _pendingResolveAtMs)
			{
				ResolvePending();
			}
			if (_serverForcedUntilMs > num)
			{
				ApplyEnvLocal(_serverForcedEnv);
				if (_serverForcedTimeEnabled)
				{
					ApplyDebugTimeLocal(enabled: true, _serverForcedTimeOfDay);
				}
				if (_nextForcedEnvBroadcastMs <= num)
				{
					_nextForcedEnvBroadcastMs = num + 10000;
					BroadcastEnvToClients(_serverForcedEnv, _serverForcedUntilMs);
					if (_serverForcedTimeEnabled)
					{
						BroadcastDebugTimeToClients(enabled: true, _serverForcedTimeOfDay);
					}
				}
			}
			else if (_serverForcedUntilMs != 0)
			{
				_serverForcedUntilMs = 0L;
				_serverForcedEnv = "";
				ApplyEnvLocal("");
				BroadcastEnvToClients("", 0L);
				if (_serverForcedTimeEnabled)
				{
					_serverForcedTimeEnabled = false;
					ApplyDebugTimeLocal(enabled: false, 0.5f);
					BroadcastDebugTimeToClients(enabled: false, 0.5f);
				}
			}
			TickPendingDestructs(num);
		}

		private static void ResolvePending()
		{
			//IL_001c: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			long now = NowMs();
			_pending = false;
			ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(_pendingTotemZdoid) : null);
			if (val == null)
			{
				BroadcastVerdict(_pendingTotemPos);
				MaybeScheduleSelfDestruct(_pendingTotemZdoid, _pendingTotemPos);
				SendMythLine(_pendingMode, "Interrupted");
				return;
			}
			long @long = val.GetLong("RD_RitualNonce", 0L);
			if (@long == _pendingNonce)
			{
				val.Set("RD_RitualEndMs", 0L);
				if (_pendingMode == PendingMode.Sun)
				{
					ResolvePending_Sun(now);
				}
				else
				{
					ResolvePending_Weather(now);
				}
			}
		}

		private static void ResolvePending_Weather(long now)
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp01(CfgChanceWeatherChange.Value);
			float num2 = Mathf.Clamp01(CfgChanceGoodWhenChanging.Value);
			string env = "";
			try
			{
				if ((Object)(object)EnvMan.instance != (Object)null)
				{
					EnvSetup currentEnvironment = EnvMan.instance.GetCurrentEnvironment();
					if (currentEnvironment != null && !string.IsNullOrWhiteSpace(currentEnvironment.m_name))
					{
						env = currentEnvironment.m_name.Trim();
					}
				}
			}
			catch
			{
				env = "";
			}
			if (IsClearish(env))
			{
				num = Mathf.Clamp01(num + Mathf.Clamp01(CfgClearWeatherChangeBoost.Value));
				num2 = Mathf.Clamp01(num2 - Mathf.Clamp01(CfgClearWeatherBadBias.Value));
			}
			if (CfgDebugForceWeatherChange != null && CfgDebugForceWeatherChange.Value)
			{
				num = 1f;
			}
			if (!(Random.value <= num))
			{
				BroadcastVerdict(_pendingTotemPos);
				MaybeScheduleSelfDestruct(_pendingTotemZdoid, _pendingTotemPos);
				SendMythLine(PendingMode.Weather, "NoChange");
				return;
			}
			bool flag = Random.value <= num2;
			string text = PickEnvFromCsv(flag ? CfgGoodEnvsCsv.Value : CfgBadEnvsCsv.Value);
			if (string.IsNullOrWhiteSpace(text))
			{
				text = (flag ? "Clear" : "Rain");
			}
			long num3 = (long)(Mathf.Max(10f, CfgForcedDurationSeconds.Value) * 1000f);
			_serverForcedEnv = text.Trim();
			_serverForcedUntilMs = Math.Max(_serverForcedUntilMs, now) + num3;
			_serverForcedTimeEnabled = false;
			ApplyEnvLocal(_serverForcedEnv);
			BroadcastEnvToClients(_serverForcedEnv, _serverForcedUntilMs);
			BroadcastVerdict(_pendingTotemPos);
			MaybeScheduleSelfDestruct(_pendingTotemZdoid, _pendingTotemPos);
			SendMythLine(PendingMode.Weather, _serverForcedEnv);
		}

		private static void ResolvePending_Sun(long now)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp01(CfgSunChanceChange.Value);
			float num2 = Mathf.Clamp01(CfgSunChanceGoodWhenChanging.Value);
			if (!(Random.value <= num))
			{
				BroadcastVerdict(_pendingTotemPos);
				MaybeScheduleSelfDestruct(_pendingTotemZdoid, _pendingTotemPos);
				SendMythLine(PendingMode.Sun, "NoChange");
				return;
			}
			bool flag = Random.value <= num2;
			string text = PickEnvFromCsv(flag ? CfgSunGoodEnvsCsv.Value : CfgSunBadEnvsCsv.Value);
			if (string.IsNullOrWhiteSpace(text))
			{
				text = (flag ? "Clear" : "Darklands_dark");
			}
			float num3 = PickTimeFromCsv(flag ? CfgSunGoodTimesCsv.Value : CfgSunBadTimesCsv.Value, flag ? 0.5f : 0f);
			long num4 = (long)(Mathf.Max(10f, CfgForcedDurationSeconds.Value) * 1000f);
			_serverForcedEnv = text.Trim();
			_serverForcedUntilMs = Math.Max(_serverForcedUntilMs, now) + num4;
			_serverForcedTimeEnabled = true;
			_serverForcedTimeOfDay = Mathf.Repeat(num3, 1f);
			ApplyEnvLocal(_serverForcedEnv);
			ApplyDebugTimeLocal(enabled: true, _serverForcedTimeOfDay);
			BroadcastEnvToClients(_serverForcedEnv, _serverForcedUntilMs);
			BroadcastDebugTimeToClients(enabled: true, _serverForcedTimeOfDay);
			BroadcastVerdict(_pendingTotemPos);
			MaybeScheduleSelfDestruct(_pendingTotemZdoid, _pendingTotemPos);
			SendMythLine(PendingMode.Sun, flag ? "SunGood" : "SunBad");
		}

		private static void SendMythLine(PendingMode mode, string key)
		{
			try
			{
				if (CfgEnableMythLines == null || CfgEnableMythLines.Value)
				{
					string mythLine = GetMythLine(mode, key ?? "");
					if (!string.IsNullOrWhiteSpace(mythLine))
					{
						BroadcastMythLine(mythLine);
					}
				}
			}
			catch
			{
			}
		}

		private static string PickRandom(string[] lines)
		{
			try
			{
				if (lines == null || lines.Length == 0)
				{
					return "";
				}
				int num = Random.Range(0, lines.Length);
				if (num < 0 || num >= lines.Length)
				{
					num = 0;
				}
				return lines[num] ?? "";
			}
			catch
			{
				return "";
			}
		}

		private static string GetMythLine(PendingMode mode, string key)
		{
			string text = (key ?? "").Trim();
			if (text.Equals("NoChange", StringComparison.OrdinalIgnoreCase))
			{
				if (mode == PendingMode.Sun)
				{
					string[] lines = new string[3] { "Sól listens... and keeps her pace.", "Máni turns his face away.", "Heimdall hears you—yet the sky holds steady." };
					return PickRandom(lines);
				}
				string[] lines2 = new string[4] { "Odin watches... and offers no omen.", "Heimdall keeps the gate closed.", "Freya turns away without a word.", "Thor does not lift Mjölnir today." };
				return PickRandom(lines2);
			}
			if (text.Equals("Interrupted", StringComparison.OrdinalIgnoreCase))
			{
				if (mode == PendingMode.Sun)
				{
					string[] lines3 = new string[3] { "Heimdall cuts the rite short.", "Odin snaps the thread—day and night refuse you.", "Máni blinks, and the moment is gone." };
					return PickRandom(lines3);
				}
				string[] lines4 = new string[3] { "Odin cuts the thread. The skies refuse the tale.", "Heimdall scatters the rite before it takes root.", "Freya withdraws her hand—the omen breaks." };
				return PickRandom(lines4);
			}
			if (mode == PendingMode.Sun)
			{
				if (text.Equals("SunGood", StringComparison.OrdinalIgnoreCase))
				{
					string[] lines5 = new string[5] { "Sól smiles upon your steps.", "Freyr lifts the veil—warmth returns.", "Heimdall opens the gate of light.", "Odin's ravens circle, and the day stands tall.", "Baldr's calm drifts over the fields." };
					return PickRandom(lines5);
				}
				if (text.Equals("SunBad", StringComparison.OrdinalIgnoreCase))
				{
					string[] lines6 = new string[4] { "Máni draws the world into shadow.", "Skadi walks the long dark road.", "Odin closes one eye—and the night deepens.", "Hel's hush creeps into the grass." };
					return PickRandom(lines6);
				}
				return "Heimdall shifts his gaze across the horizon.";
			}
			if (text.Equals("ThunderStorm", StringComparison.OrdinalIgnoreCase))
			{
				string[] lines7 = new string[2] { "Thor answers your call.", "Thor raises Mjölnir in the clouds." };
				return PickRandom(lines7);
			}
			if (text.Equals("Clear", StringComparison.OrdinalIgnoreCase) || text.Equals("LightClouds", StringComparison.OrdinalIgnoreCase) || text.Equals("Twilight_Clear", StringComparison.OrdinalIgnoreCase))
			{
				string[] lines8 = new string[2] { "Freya swings her blade.", "Freya lays a calm hand on the sky." };
				return PickRandom(lines8);
			}
			if (text.Equals("Rain", StringComparison.OrdinalIgnoreCase) || text.Equals("LightRain", StringComparison.OrdinalIgnoreCase))
			{
				string[] lines9 = new string[2] { "Njord turns his gaze seaward.", "Njord sends his saltwind through the clouds." };
				return PickRandom(lines9);
			}
			if (text.Equals("Misty", StringComparison.OrdinalIgnoreCase))
			{
				string[] lines10 = new string[2] { "Odin veils the world with one eye.", "Odin's ravens vanish into the fog." };
				return PickRandom(lines10);
			}
			if (text.Equals("Snow", StringComparison.OrdinalIgnoreCase) || text.Equals("SnowStorm", StringComparison.OrdinalIgnoreCase))
			{
				string[] lines11 = new string[2] { "Skadi walks the white road.", "Skadi draws her cloak across the land." };
				return PickRandom(lines11);
			}
			return "Odin stirs above.";
		}

		private static void MaybeScheduleSelfDestruct(ZDOID totemZdoid, Vector3 pos)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (CfgSelfDestructAfterUse != null && CfgSelfDestructAfterUse.Value)
				{
					float num = ((CfgSelfDestructDelaySeconds != null) ? Mathf.Max(0.05f, CfgSelfDestructDelaySeconds.Value) : 1.05f);
					long num2 = NowMs();
					long strikeAtMs = num2 + Math.Max(0L, (long)(Mathf.Max(0f, num - 0.12f) * 1000f));
					long destroyAtMs = num2 + (long)(num * 1000f);
					_pendingDestructs.Add(new PendingDestruct
					{
						Zdoid = totemZdoid,
						Pos = pos,
						StrikeAtMs = strikeAtMs,
						DestroyAtMs = destroyAtMs,
						Struck = false
					});
				}
			}
			catch
			{
			}
		}

		private static void TickPendingDestructs(long now)
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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)
			if (_pendingDestructs.Count == 0)
			{
				return;
			}
			for (int num = _pendingDestructs.Count - 1; num >= 0; num--)
			{
				PendingDestruct value = _pendingDestructs[num];
				if (!value.Struck && now >= value.StrikeAtMs)
				{
					value.Struck = true;
					_pendingDestructs[num] = value;
					if (CfgSpawnLightningAoeServer != null && CfgSpawnLightningAoeServer.Value)
					{
						SpawnLightningAoe_ServerAuthoritative(value.Pos);
						if (CfgAlsoPlayClientLightningVfx != null && CfgAlsoPlayClientLightningVfx.Value)
						{
							BroadcastLightningVfx(value.Pos);
						}
					}
					else
					{
						BroadcastLightningVfx(value.Pos);
					}
				}
				if (now >= value.DestroyAtMs)
				{
					_pendingDestructs.RemoveAt(num);
					DestroyTotemByZdoid(value.Zdoid);
				}
			}
		}

		private static void DestroyTotemByZdoid(ZDOID zdoid)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)ZNetScene.instance == (Object)null)
				{
					return;
				}
				GameObject val = null;
				try
				{
					val = ZNetScene.instance.FindInstance(zdoid);
				}
				catch
				{
					val = null;
				}
				if (!((Object)(object)val == (Object)null))
				{
					ZNetView component = val.GetComponent<ZNetView>();
					if ((Object)(object)component != (Object)null && component.IsValid())
					{
						component.Destroy();
					}
					else
					{
						Object.Destroy((Object)(object)val);
					}
				}
			}
			catch
			{
			}
		}

		private static void SpawnLightningAoe_ServerAuthoritative(Vector3 pos)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && !((Object)(object)ZNetScene.instance == (Object)null))
				{
					GameObject prefab = ZNetScene.instance.GetPrefab("lightningAOE");
					if (!((Object)(object)prefab == (Object)null))
					{
						ZNetScene.instance.SpawnObject(pos, Quaternion.identity, prefab);
					}
				}
			}
			catch
			{
			}
		}

		private static void SpawnLightningAoe_LocalVisual(Vector3 pos)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)ZNetScene.instance == (Object)null))
				{
					GameObject prefab = ZNetScene.instance.GetPrefab("lightningAOE");
					if (!((Object)(object)prefab == (Object)null))
					{
						Object.Instantiate<GameObject>(prefab, pos, Quaternion.identity);
					}
				}
			}
			catch
			{
			}
		}

		private static bool IsClearish(string env)
		{
			if (string.IsNullOrWhiteSpace(env))
			{
				return false;
			}
			string text = env.Trim();
			if (text.Equals("Clear", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (text.Equals("LightClouds", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (text.Equals("Twilight_Clear", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (text.IndexOf("clear", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			return false;
		}

		private static string PickEnvFromCsv(string csv)
		{
			try
			{
				if (string.IsNullOrWhiteSpace(csv))
				{
					return "";
				}
				string[] array = (from s in csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
					select (s ?? "").Trim() into s
					where s.Length > 0
					select s).ToArray();
				if (array.Length == 0)
				{
					return "";
				}
				return array[Random.Range(0, array.Length)];
			}
			catch
			{
				return "";
			}
		}

		private static float PickTimeFromCsv(string csv, float fallback)
		{
			try
			{
				if (string.IsNullOrWhiteSpace(csv))
				{
					return Mathf.Repeat(fallback, 1f);
				}
				string[] array = (from s in csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
					select (s ?? "").Trim() into s
					where s.Length > 0
					select s).ToArray();
				if (array.Length == 0)
				{
					return Mathf.Repeat(fallback, 1f);
				}
				List<float> list = new List<float>(array.Length);
				for (int i = 0; i < array.Length; i++)
				{
					if (float.TryParse(array[i], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && !float.IsNaN(result) && !float.IsInfinity(result))
					{
						list.Add(Mathf.Repeat(result, 1f));
					}
				}
				if (list.Count == 0)
				{
					return Mathf.Repeat(fallback, 1f);
				}
				return list[Random.Range(0, list.Count)];
			}
			catch
			{
				return Mathf.Repeat(fallback, 1f);
			}
		}

		private static void ApplyEnvLocal(string env)
		{
			try
			{
				if (!((Object)(object)EnvMan.instance == (Object)null))
				{
					EnvMan.instance.m_debugEnv = (env ?? "").Trim();
				}
			}
			catch
			{
			}
		}

		private static void ApplyDebugTimeLocal(bool enabled, float tod)
		{
			try
			{
				if (!((Object)(object)EnvMan.instance == (Object)null))
				{
					EnvMan.instance.m_debugTimeOfDay = enabled;
					if (enabled)
					{
						EnvMan.instance.m_debugTime = Mathf.Repeat(tod, 1f);
					}
				}
			}
			catch
			{
			}
		}

		private static void SpawnVerdictVfx(Vector3 pos)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)ZNetScene.instance == (Object)null)
				{
					return;
				}
				string[] array = new string[4] { "vfx_Potion_health_medium", "vfx_Potion_health_small", "vfx_Potion_health", "vfx_Healing" };
				GameObject val = null;
				for (int i = 0; i < array.Length; i++)
				{
					val = ZNetScene.instance.GetPrefab(array[i]);
					if ((Object)(object)val != (Object)null)
					{
						break;
					}
				}
				if (!((Object)(object)val == (Object)null))
				{
					Object.Instantiate<GameObject>(val, pos + Vector3.up * 1f, Quaternion.identity);
				}
			}
			catch
			{
			}
		}

		private static void TryRequestDrumClipLoad()
		{
			if (!_drumClipRequested && !((Object)(object)_instance == (Object)null) && CfgPlayDrumOnInteract != null && CfgPlayDrumOnInteract.Value)
			{
				_drumClipRequested = true;
				((MonoBehaviour)_instance).StartCoroutine(LoadClipCoroutine(() => (CfgDrumFileName != null) ? CfgDrumFileName.Value : "RD_Drums.ogg", delegate(AudioClip clip)
				{
					_drumClip = clip;
				}));
			}
		}

		private static void TryRequestVerdictClipLoad()
		{
			if (!_verdictClipRequested && !((Object)(object)_instance == (Object)null) && CfgPlayVerdictOnVerdict != null && CfgPlayVerdictOnVerdict.Value)
			{
				_verdictClipRequested = true;
				((MonoBehaviour)_instance).StartCoroutine(LoadClipCoroutine(() => (CfgVerdictFileName != null) ? CfgVerdictFileName.Value : "RD_Verdict.ogg", delegate(AudioClip clip)
				{
					_verdictClip = clip;
				}));
			}
		}

		[IteratorStateMachine(typeof(<LoadClipCoroutine>d__129))]
		private static IEnumerator LoadClipCoroutine(Func<string> getFileName, Action<AudioClip> assign)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadClipCoroutine>d__129(0)
			{
				getFileName = getFileName,
				assign = assign
			};
		}

		private static void PlayOneShot(AudioClip clip, Vector3 pos, float volume)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)clip == (Object)null))
				{
					float num = Mathf.Clamp01(volume);
					if (!(num <= 0f))
					{
						AudioSource.PlayClipAtPoint(clip, pos, num);
					}
				}
			}
			catch
			{
			}
		}

		private static bool IsTextInputOpen()
		{
			try
			{
				if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
				{
					return true;
				}
			}
			catch
			{
			}
			try
			{
				if (Console.IsVisible())
				{
					return true;
				}
			}
			catch
			{
			}
			try
			{
				if (TextInput.IsVisible())
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static GameObject TryGetLocalHoverObject(Player p)
		{
			try
			{
				return ((Object)(object)p == (Object)null) ? null : PlayerHoveringRef.Invoke(p);
			}
			catch
			{
				return null;
			}
		}

		private static void LateInitOnce()
		{
			try
			{
				if (!_addedToHammer || !_costApplied)
				{
					EnsurePrefabLoaded();
					if ((Object)(object)ZNetScene.instance != (Object)null)
					{
						RegisterPrefabInZNetScene();
					}
					if ((Object)(object)ObjectDB.instance != (Object)null)
					{
						TryAddToHammer(ObjectDB.instance);
						ApplyBuildCostIfPossible();
					}
					ApplyPlacementAndBreakEffectsIfPossible();
				}
			}
			catch
			{
			}
		}
	}
}