Decompiled source of WorldControl v3.0.0

plugins/WorldControl.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("WorldControl")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("3.0.0.0")]
[assembly: AssemblyInformationalVersion("3.0.0+5006c83861da9b211cb31e8b1d53944e6c845180")]
[assembly: AssemblyProduct("WorldControl")]
[assembly: AssemblyTitle("WorldControl")]
[assembly: AssemblyVersion("3.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace WorldControl
{
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("dezzycode.valheim.windcontrol", "World Control", "3.0.0")]
	[BepInDependency("com.jotunn.jotunn", "2.30.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private struct EitrAttackContextState
		{
			public int Depth;

			public bool Secondary;

			public bool Changed;
		}

		private struct EitrReloadCostState
		{
			public Attack Attack;

			public float Value;

			public bool Changed;
		}

		private struct EitrRepairCostState
		{
			public Attack Attack;

			public float Value;

			public bool Changed;
		}

		[HarmonyPatch(typeof(Humanoid), "StartAttack", new Type[]
		{
			typeof(Character),
			typeof(bool)
		})]
		private static class EitrAttackContextPatch
		{
			private static void Prefix(Humanoid __instance, bool __1, ref EitrAttackContextState __state)
			{
				__state = new EitrAttackContextState
				{
					Depth = eitrAttackContextDepth,
					Secondary = eitrAttackContextSecondary,
					Changed = false
				};
				if (CanScaleLocalEitr((Character)(object)((__instance is Player) ? __instance : null)))
				{
					eitrAttackContextDepth++;
					eitrAttackContextSecondary = __1;
					__state.Changed = true;
				}
			}

			private static Exception Finalizer(Exception __exception, ref EitrAttackContextState __state)
			{
				RestoreEitrAttackContext(ref __state);
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Attack), "GetAttackEitr", new Type[] { })]
		private static class EitrAttackCostPatch
		{
			private static void Postfix(Attack __instance, Humanoid ___m_character, ref float __result)
			{
				if (CanScaleLocalEitr((Character)(object)___m_character) && !(__result <= 0f))
				{
					bool flag;
					if (eitrAttackContextDepth <= 0)
					{
						flag = __instance == eitrActiveAttack && eitrActiveAttackSecondary;
					}
					else
					{
						flag = eitrAttackContextSecondary;
						eitrActiveAttack = __instance;
						eitrActiveAttackSecondary = flag;
					}
					float num = (flag ? instance.playerRules.SecondaryEitr : instance.playerRules.PrimaryEitr);
					if (num != 1f)
					{
						__result *= num;
					}
				}
			}
		}

		[HarmonyPatch(typeof(ItemData), "GetDrawEitrDrain")]
		private static class EitrDrawCostPatch
		{
			private static void Postfix(ItemData __instance, ref float __result)
			{
				Plugin instance = Plugin.instance;
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)instance == (Object)null) && instance.playerRulesSynced && !((Object)(object)localPlayer == (Object)null) && __instance != null && !(__result <= 0f))
				{
					float drawEitr = instance.playerRules.DrawEitr;
					if (drawEitr != 1f && ((Humanoid)localPlayer).GetCurrentWeapon() == __instance)
					{
						__result *= drawEitr;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UpdateWeaponLoading", new Type[]
		{
			typeof(ItemData),
			typeof(float)
		})]
		private static class EitrReloadCostPatch
		{
			private static void Prefix(Player __instance, ItemData __0, ref EitrReloadCostState __state)
			{
				__state = ScaleReloadEitrTemporarily(__instance, __0);
			}

			private static Exception Finalizer(Exception __exception, ref EitrReloadCostState __state)
			{
				RestoreReloadEitr(ref __state);
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Player), "Repair", new Type[]
		{
			typeof(ItemData),
			typeof(Piece)
		})]
		private static class EitrRepairCostPatch
		{
			private static void Prefix(Player __instance, ItemData __0, ref EitrRepairCostState __state)
			{
				__state = ScaleRepairEitrTemporarily(__instance, __0);
			}

			private static Exception Finalizer(Exception __exception, ref EitrRepairCostState __state)
			{
				RestoreRepairEitr(ref __state);
				return __exception;
			}
		}

		private struct RegenTickState
		{
			public float Stamina;

			public float Eitr;

			public bool Changed;
		}

		[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
		private static class PlayerRegenCalculationPatch
		{
			private static void Prefix(Player __instance, ref RegenTickState __state)
			{
				__state = default(RegenTickState);
				Plugin instance = Plugin.instance;
				if ((Object)(object)instance == (Object)null || !instance.playerVitalsSynced || (Object)(object)__instance == (Object)null || __instance != Player.m_localPlayer)
				{
					return;
				}
				float staminaRegen = instance.playerVitals.StaminaRegen;
				float eitrRegen = instance.playerVitals.EitrRegen;
				if (staminaRegen != 1f || eitrRegen != 1f)
				{
					__state.Stamina = __instance.m_staminaRegen;
					__state.Eitr = __instance.m_eiterRegen;
					__state.Changed = true;
					if (staminaRegen != 1f)
					{
						__instance.m_staminaRegen = __state.Stamina * staminaRegen;
					}
					if (eitrRegen != 1f)
					{
						__instance.m_eiterRegen = __state.Eitr * eitrRegen;
					}
				}
			}

			private static Exception Finalizer(Exception __exception, Player __instance, ref RegenTickState __state)
			{
				RestoreRegenTick(__instance, ref __state);
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Plugin), "BuildPlayerVitals")]
		private static class EitrRegenVitalsUiPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(Plugin __instance, Transform parent)
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__instance.AddEitrRegenSlider(parent);
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "DestroyUI")]
		private static class EitrRegenUiDestroyPatch
		{
			[HarmonyPriority(800)]
			private static void Prefix(Plugin __instance)
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__instance.eitrRegenUiAdded = false;
				}
			}
		}

		[HarmonyPatch(typeof(EnvMan), "FixedUpdate")]
		private static class EnvironmentPatch
		{
			private static void Prefix(EnvMan __instance)
			{
				Plugin instance = Plugin.instance;
				if ((Object)(object)instance == (Object)null || instance.session == null || !instance.session.Synced || instance.session.State.Revision == 0L)
				{
					return;
				}
				if ((Object)(object)instance.controlledEnvironment != (Object)(object)__instance)
				{
					instance.RestoreEnvironment();
					instance.controlledEnvironment = __instance;
					instance.savedWeather = __instance.m_debugEnv;
					instance.savedTimeEnabled = __instance.m_debugTimeOfDay;
					instance.savedTime = __instance.m_debugTime;
					instance.savedWindEnabled = __instance.m_debugWind;
					instance.savedWindAngle = __instance.m_debugWindAngle;
					instance.savedWindStrength = __instance.m_debugWindIntensity;
					instance.controlledEnvironmentRevision = -1L;
				}
				long revision = instance.session.State.Revision;
				if (instance.controlledEnvironmentRevision != revision)
				{
					Request settings = instance.session.State.Settings;
					__instance.m_debugEnv = settings.Weather;
					if (settings.WindOn)
					{
						__instance.SetDebugWind(settings.Angle, settings.Strength);
					}
					else
					{
						__instance.ResetDebugWind();
					}
					if (settings.TimeMode == 1)
					{
						instance.ownedTime = true;
						__instance.m_debugTimeOfDay = false;
					}
					else if (instance.ownedTime)
					{
						__instance.m_debugTimeOfDay = false;
						instance.ownedTime = false;
					}
					instance.controlledEnvironmentRevision = revision;
				}
			}
		}

		[HarmonyPatch(typeof(EnvMan), "RescaleDayFraction")]
		private static class HeldDayTargetPatch
		{
			private static void Postfix(EnvMan __instance, ref float __result)
			{
				Plugin instance = Plugin.instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance.controlledEnvironment == (Object)(object)__instance && instance.session != null && instance.session.Synced && instance.session.State.Settings.TimeMode == 1)
				{
					__result = instance.session.State.Settings.Hour / 24f;
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "PlayerRule")]
		private static class PlayerRuleFiveMaxPatch
		{
			private static void Postfix(float value, ref bool __result)
			{
				__result = !float.IsNaN(value) && !float.IsInfinity(value) && value >= 0f && value <= 5f;
			}
		}

		[HarmonyPatch(typeof(Plugin), "ValidPlayerRules")]
		private static class PlayerRulesBuffOnlyValidationPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(PlayerResourceRules r, ref bool __result)
			{
				if (__result)
				{
					__result = BuffOnlyPlayerRules(r);
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "BuildStaminaRules")]
		private static class StaminaBuffOnlyUiPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(Plugin __instance, Transform parent)
			{
				SetAllPlayerSliderRanges(parent, 0f, 1f);
				__instance?.ReplacePlayerRuleFooter(parent, "1.00× = Vanilla · lower = less stamina used · 0.00× = no stamina cost.", "1,00× = Vanilla · niedriger = weniger Ausdauerverbrauch · 0,00× = kein Ausdauerverbrauch.");
			}
		}

		[HarmonyPatch(typeof(Plugin), "BuildEitrRules")]
		private static class EitrBuffOnlyUiPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(Plugin __instance, Transform parent)
			{
				SetAllPlayerSliderRanges(parent, 0f, 1f);
				__instance?.ReplacePlayerRuleFooter(parent, "1.00× = Vanilla · lower = less Eitr used · 0.00× = no Eitr cost.", "1,00× = Vanilla · niedriger = weniger Eitr-Verbrauch · 0,00× = kein Eitr-Verbrauch.");
			}
		}

		[HarmonyPatch(typeof(Plugin), "BuildAdrenalineRules")]
		private static class AdrenalineBuffOnlyUiPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(Plugin __instance, Transform parent)
			{
				SetAdrenalineSliderRanges(parent);
				__instance?.ReplacePlayerRuleFooter(parent, "Gains: 1.00× = Vanilla, higher = more. Penalties: 1.00× = Vanilla, lower = less loss.", "Gewinn: 1,00× = Vanilla, höher = mehr. Verluste: 1,00× = Vanilla, niedriger = weniger Verlust.");
			}
		}

		[HarmonyPatch(typeof(Plugin), "LayoutPlayerTabs")]
		private static class PlayerResetButtonHookPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(Plugin __instance)
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__instance.EnsurePlayerResetConfirmationHook();
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "DestroyUI")]
		private static class PlayerResetConfirmationDestroyPatch
		{
			[HarmonyPriority(800)]
			private static void Prefix(Plugin __instance)
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__instance.ResetPlayerConfirmationReferences();
				}
			}
		}

		private sealed class AttackBaseline
		{
			public float AttackAdrenaline;
		}

		private sealed class ShieldBaseline
		{
			public float Block;

			public float Parry;
		}

		[HarmonyPatch(typeof(Plugin), "OpenWindow")]
		private static class PlayerRulesOpenPatch
		{
			private static void Postfix(Plugin __instance)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					if (!__instance.playerRulesDraftDirty)
					{
						__instance.playerRulesDraft = __instance.playerRules;
					}
					__instance.EnsurePlayerRulesUI();
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "EnsureUI")]
		private static class PlayerRulesUiPatch
		{
			private static void Postfix(Plugin __instance, bool __result)
			{
				if (__result && (Object)(object)__instance != (Object)null)
				{
					__instance.EnsurePlayerRulesUI();
				}
			}
		}

		[HarmonyPatch(typeof(Player), "GetBuildStamina")]
		private static class PlayerRulesHomeStaminaPatch
		{
			private static void Postfix(Player __instance, ref float __result)
			{
				Plugin instance = Plugin.instance;
				if (!((Object)(object)instance == (Object)null) && instance.playerRulesSynced && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					__result *= instance.playerRules.HomeStamina;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
		private static class PlayerVitalMaximumPatch
		{
			private static void Postfix(Player __instance, ref float __0, ref float __1, ref float __2)
			{
				Plugin instance = Plugin.instance;
				if (!((Object)(object)instance == (Object)null) && instance.playerVitalsSynced && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					__0 *= instance.playerVitals.MaxHealth;
					__1 *= instance.playerVitals.MaxStamina;
					__2 *= instance.playerVitals.MaxEitr;
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "EnsureUI")]
		private static class PlayerVitalsUiPatch
		{
			private static void Postfix(Plugin __instance, bool __result)
			{
				if (__result && (Object)(object)__instance != (Object)null)
				{
					__instance.EnsurePlayerVitalsUI();
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "OpenWindow")]
		private static class PlayerVitalsOpenPatch
		{
			private static void Postfix(Plugin __instance)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					if (!__instance.playerVitalsDraftDirty)
					{
						__instance.playerVitalsDraft = __instance.playerVitals;
					}
					__instance.EnsurePlayerVitalsUI();
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "EndSession")]
		private static class PlayerVitalsSessionEndPatch
		{
			private static void Prefix(Plugin __instance)
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__instance.RestorePlayerVitalsLocal();
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "VitalSlider")]
		private static class PlayerVitalsSliderRangePatch
		{
			private static void Prefix(ref float __4, ref float __5)
			{
				__4 = 1f;
				__5 = 5f;
			}
		}

		[HarmonyPatch(typeof(Plugin), "ValidVitalMax")]
		private static class PlayerVitalsMaxValidationPatch
		{
			private static void Postfix(float value, ref bool __result)
			{
				__result = !float.IsNaN(value) && !float.IsInfinity(value) && value >= 1f && value <= 5f;
			}
		}

		[HarmonyPatch(typeof(Plugin), "ValidVitalRegen")]
		private static class PlayerVitalsRegenValidationPatch
		{
			private static void Postfix(float value, ref bool __result)
			{
				__result = !float.IsNaN(value) && !float.IsInfinity(value) && value >= 1f && value <= 5f;
			}
		}

		[HarmonyPatch(typeof(RandEventSystem), "UpdateRandomEvent")]
		private static class EventPausePatch
		{
			private static bool Prefix()
			{
				if (!((Object)(object)instance == (Object)null) && instance.session != null && instance.session.Server)
				{
					return !instance.session.State.Settings.EventsPaused;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnDestroy")]
		private static class SessionEndPatch
		{
			private static void Prefix(ZNet __instance)
			{
				if ((Object)(object)instance != (Object)null && instance.network == __instance)
				{
					instance.EndSession();
				}
			}
		}

		private struct RainWetState
		{
			public bool Original;

			public bool Changed;
		}

		[HarmonyPatch(typeof(Plugin), "BuildWeather")]
		private static class RainDamageWeatherUiPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(Plugin __instance, Transform parent)
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__instance.AddRainDamageToggle(parent);
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "IsWet")]
		private static class RainDamageWearPatch
		{
			private static void Prefix(WearNTear __instance, ref RainWetState __state)
			{
				__state = default(RainWetState);
				Plugin instance = Plugin.instance;
				if ((Object)(object)instance == (Object)null || instance.session == null || !instance.session.Synced || !instance.session.State.Settings.NoRainDamage || (Object)(object)__instance == (Object)null || !TryGetRainWetField())
				{
					return;
				}
				try
				{
					ref bool reference = ref rainWetField.Invoke(__instance);
					__state.Original = reference;
					__state.Changed = true;
					reference = false;
				}
				catch
				{
				}
			}

			private static Exception Finalizer(Exception __exception, WearNTear __instance, ref RainWetState __state)
			{
				RestoreRainWet(__instance, ref __state);
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Plugin), "Remember")]
		private static class RainDamageRememberPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(Plugin __instance)
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__instance.RememberRainDamageSetting();
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "Recall")]
		private static class RainDamageRecallPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(Plugin __instance)
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__instance.RecallRainDamageSetting();
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "Players")]
		private static class PlayerListFrameCache
		{
			private static bool Prefix(ref List<PlayerInfo> __result)
			{
				if (playersCachedFrame != Time.frameCount)
				{
					return true;
				}
				__result = PlayerBuffer;
				return false;
			}

			private static void Postfix(ref List<PlayerInfo> __result)
			{
				playersCachedFrame = Time.frameCount;
				__result = PlayerBuffer;
			}
		}

		private struct StaminaAttackContextState
		{
			public int Depth;

			public bool Secondary;

			public bool Changed;
		}

		private struct StaminaReloadState
		{
			public Attack Attack;

			public float Value;

			public bool Changed;
		}

		private struct BlockStaminaState
		{
			public float Normal;

			public float Perfect;

			public bool Changed;
		}

		[HarmonyPatch(typeof(Humanoid), "StartAttack", new Type[]
		{
			typeof(Character),
			typeof(bool)
		})]
		private static class StaminaAttackContextPatch
		{
			private static void Prefix(Humanoid __instance, bool __1, ref StaminaAttackContextState __state)
			{
				__state = new StaminaAttackContextState
				{
					Depth = staminaAttackContextDepth,
					Secondary = staminaAttackContextSecondary,
					Changed = false
				};
				if (CanScaleLocalStamina((Character)(object)((__instance is Player) ? __instance : null)))
				{
					staminaAttackContextDepth++;
					staminaAttackContextSecondary = __1;
					__state.Changed = true;
				}
			}

			private static Exception Finalizer(Exception __exception, ref StaminaAttackContextState __state)
			{
				RestoreStaminaAttackContext(ref __state);
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Attack), "GetAttackStamina", new Type[] { })]
		private static class StaminaAttackCostPatch
		{
			private static void Postfix(Attack __instance, Humanoid ___m_character, ref float __result)
			{
				Plugin instance = Plugin.instance;
				if (!((Object)(object)instance == (Object)null) && instance.playerRulesSynced && CanScaleLocalStamina((Character)(object)___m_character) && !(__result <= 0f) && (__instance == null || !__instance.m_isHomeItem))
				{
					bool flag;
					if (staminaAttackContextDepth <= 0)
					{
						flag = __instance == staminaActiveAttack && staminaActiveAttackSecondary;
					}
					else
					{
						flag = staminaAttackContextSecondary;
						staminaActiveAttack = __instance;
						staminaActiveAttackSecondary = flag;
					}
					float num = (flag ? instance.playerRules.SecondaryStamina : instance.playerRules.PrimaryStamina);
					if (num != 1f)
					{
						__result *= num;
					}
				}
			}
		}

		[HarmonyPatch(typeof(ItemData), "GetDrawStaminaDrain")]
		private static class StaminaDrawCostPatch
		{
			private static void Postfix(ItemData __instance, ref float __result)
			{
				Plugin instance = Plugin.instance;
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)instance == (Object)null) && instance.playerRulesSynced && !((Object)(object)localPlayer == (Object)null) && __instance != null && !(__result <= 0f))
				{
					float drawStamina = instance.playerRules.DrawStamina;
					if (drawStamina != 1f && ((Humanoid)localPlayer).GetCurrentWeapon() == __instance)
					{
						__result *= drawStamina;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UpdateWeaponLoading", new Type[]
		{
			typeof(ItemData),
			typeof(float)
		})]
		private static class StaminaReloadCostPatch
		{
			private static void Prefix(Player __instance, ItemData __0, ref StaminaReloadState __state)
			{
				__state = default(StaminaReloadState);
				if (CanScaleLocalStamina((Character)(object)__instance) && __0 != null && __0.m_shared != null && __0.m_shared.m_attack != null)
				{
					float reloadStamina = instance.playerRules.ReloadStamina;
					if (reloadStamina != 1f)
					{
						Attack val = (__state.Attack = __0.m_shared.m_attack);
						__state.Value = val.m_reloadStaminaDrain;
						__state.Changed = true;
						val.m_reloadStaminaDrain = __state.Value * reloadStamina;
					}
				}
			}

			private static Exception Finalizer(Exception __exception, ref StaminaReloadState __state)
			{
				RestoreStaminaReload(ref __state);
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Humanoid), "BlockAttack", new Type[]
		{
			typeof(HitData),
			typeof(Character)
		})]
		private static class BlockStaminaCostPatch
		{
			private static void Prefix(Humanoid __instance, ref BlockStaminaState __state)
			{
				__state = default(BlockStaminaState);
				if (CanScaleLocalStamina((Character)(object)((__instance is Player) ? __instance : null)))
				{
					float block = instance.playerRules.Block;
					if (block != 1f)
					{
						__state.Normal = __instance.m_blockStaminaDrain;
						__state.Perfect = __instance.m_perfectBlockStaminaDrain;
						__state.Changed = true;
						__instance.m_blockStaminaDrain = __state.Normal * block;
						__instance.m_perfectBlockStaminaDrain = __state.Perfect * block;
					}
				}
			}

			private static Exception Finalizer(Exception __exception, Humanoid __instance, ref BlockStaminaState __state)
			{
				RestoreBlockStamina(__instance, ref __state);
				return __exception;
			}
		}

		private sealed class TerrainOpSnapshot
		{
			private readonly TerrainOp op;

			private readonly float level;

			private readonly float raise;

			private readonly float smooth;

			private readonly float paint;

			public TerrainOpSnapshot(TerrainOp value)
			{
				op = value;
				Settings settings = value.m_settings;
				level = settings.m_levelRadius;
				raise = settings.m_raiseRadius;
				smooth = settings.m_smoothRadius;
				paint = settings.m_paintRadius;
			}

			public void Restore()
			{
				if (!((Object)(object)op == (Object)null) && op.m_settings != null)
				{
					op.m_settings.m_levelRadius = level;
					op.m_settings.m_raiseRadius = raise;
					op.m_settings.m_smoothRadius = smooth;
					op.m_settings.m_paintRadius = paint;
				}
			}
		}

		private sealed class TerrainModifierSnapshot
		{
			private readonly TerrainModifier modifier;

			private readonly float level;

			private readonly float smooth;

			public TerrainModifierSnapshot(TerrainModifier value)
			{
				modifier = value;
				level = value.m_levelRadius;
				smooth = value.m_smoothRadius;
			}

			public void Restore()
			{
				if (!((Object)(object)modifier == (Object)null))
				{
					modifier.m_levelRadius = level;
					modifier.m_smoothRadius = smooth;
				}
			}
		}

		private sealed class PlacementRadiusScope
		{
			public readonly HashSet<int> Seen = new HashSet<int>();

			public readonly List<TerrainOpSnapshot> Ops = new List<TerrainOpSnapshot>();

			public readonly List<TerrainModifierSnapshot> Modifiers = new List<TerrainModifierSnapshot>();

			public void Restore()
			{
				foreach (TerrainOpSnapshot op in Ops)
				{
					op.Restore();
				}
				foreach (TerrainModifierSnapshot modifier in Modifiers)
				{
					modifier.Restore();
				}
			}
		}

		[HarmonyPatch]
		private static class TerrainPlacementPatch
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (!(methodInfo.Name != "TryPlacePiece") && !(methodInfo.ReturnType != typeof(bool)))
					{
						ParameterInfo[] parameters = methodInfo.GetParameters();
						if (parameters.Length == 1 && parameters[0].ParameterType == typeof(Piece))
						{
							yield return methodInfo;
						}
					}
				}
			}

			[HarmonyPriority(800)]
			private static bool Prefix(Player __instance, Piece piece, ref bool __result)
			{
				RestoreTerrainRadiusScope();
				Plugin instance = Plugin.instance;
				if ((Object)(object)instance == (Object)null || instance.terrainEnabled == null || !instance.terrainEnabled.Value || !instance.CanEdit || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null)
				{
					return true;
				}
				if (instance.IsTerrainRampPiece(piece))
				{
					__result = instance.ApplyRamp(__instance);
					return false;
				}
				if (instance.IsTerrainRevertPiece(piece))
				{
					__result = instance.ApplyRevert(__instance);
					return false;
				}
				if (instance.terrainToolRadiusEnabled == null || !instance.terrainToolRadiusEnabled.Value)
				{
					return true;
				}
				TerrainToolKind terrainToolKind = GetTerrainToolKind(((Humanoid)__instance).GetCurrentWeapon());
				if (terrainToolKind == TerrainToolKind.None)
				{
					return true;
				}
				float configuredTerrainRadius = instance.GetConfiguredTerrainRadius(terrainToolKind);
				PlacementRadiusScope placementRadiusScope = new PlacementRadiusScope();
				try
				{
					ScaleTerrainComponents(((Component)piece).gameObject, configuredTerrainRadius, placementRadiusScope);
					Piece val = null;
					try
					{
						val = __instance.GetSelectedPiece();
					}
					catch
					{
					}
					if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)piece)
					{
						ScaleTerrainComponents(((Component)val).gameObject, configuredTerrainRadius, placementRadiusScope);
					}
					if (placementRadiusScope.Ops.Count == 0 && placementRadiusScope.Modifiers.Count == 0)
					{
						placementRadiusScope.Restore();
						return true;
					}
					terrainActiveRadiusScope = placementRadiusScope;
				}
				catch
				{
					placementRadiusScope.Restore();
					throw;
				}
				return true;
			}

			private static Exception Finalizer(Exception __exception)
			{
				RestoreTerrainRadiusScope();
				return __exception;
			}
		}

		[HarmonyPatch]
		private static class TerrainGridMovementPatch
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name != "SetControls")
					{
						continue;
					}
					ParameterInfo[] parameters = methodInfo.GetParameters();
					foreach (ParameterInfo parameterInfo in parameters)
					{
						if (parameterInfo.Name == "movedir" && parameterInfo.ParameterType == typeof(Vector3))
						{
							yield return methodInfo;
							break;
						}
					}
				}
			}

			private static void Prefix(Player __instance, ref Vector3 movedir)
			{
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0104: Unknown result type (might be due to invalid IL or missing references)
				//IL_0105: 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_0118: Unknown result type (might be due to invalid IL or missing references)
				//IL_011d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0122: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0146: Unknown result type (might be due to invalid IL or missing references)
				//IL_014d: Unknown result type (might be due to invalid IL or missing references)
				//IL_018b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0191: Unknown result type (might be due to invalid IL or missing references)
				//IL_0196: Unknown result type (might be due to invalid IL or missing references)
				//IL_0199: Unknown result type (might be due to invalid IL or missing references)
				//IL_019b: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
				Plugin instance = Plugin.instance;
				if ((Object)(object)instance == (Object)null || instance.terrainEnabled == null || !instance.terrainEnabled.Value || instance.terrainGridMovement == null || !instance.terrainGridMovement.Value || !instance.CanEdit || instance.windowOpen || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !IsTerrainPickaxe(((Humanoid)__instance).GetCurrentWeapon()) || instance.terrainFlattenHold == null || !ShortcutHeld(instance.terrainFlattenHold.Value))
				{
					return;
				}
				Vector2 val = new Vector2(movedir.x, movedir.z);
				float num = Mathf.Clamp01(((Vector2)(ref val)).magnitude);
				if (!(num < 0.001f))
				{
					Vector3 val2 = ((Character)__instance).GetLookDir();
					val2.y = 0f;
					if (((Vector3)(ref val2)).sqrMagnitude < 0.001f)
					{
						val2 = ((Component)__instance).transform.forward;
						val2.y = 0f;
					}
					((Vector3)(ref val2)).Normalize();
					Vector3 val3 = Vector3.Cross(Vector3.up, val2);
					Vector3 normalized = ((Vector3)(ref val3)).normalized;
					Vector3 val4 = val2 * movedir.z + normalized * movedir.x;
					val4.y = 0f;
					if (!(((Vector3)(ref val4)).sqrMagnitude < 0.001f))
					{
						((Vector3)(ref val4)).Normalize();
						float num2 = Mathf.Round(Mathf.Atan2(val4.x, val4.z) * 57.29578f / 45f) * 45f * ((float)Math.PI / 180f);
						Vector3 val5 = new Vector3(Mathf.Sin(num2), 0f, Mathf.Cos(num2)) * num;
						movedir.x = Vector3.Dot(val5, normalized);
						movedir.z = Vector3.Dot(val5, val2);
						movedir.y = 0f;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "CreateTerrainActionPiece")]
		private static class TerrainActionPieceUsagePatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(PieceTable table, GameObject __result)
			{
				//IL_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0085: 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)
				if ((Object)(object)table == (Object)null || (Object)(object)__result == (Object)null)
				{
					return;
				}
				Piece component = __result.GetComponent<Piece>();
				if ((Object)(object)component == (Object)null)
				{
					return;
				}
				int num = FindHoeGroundIndex(table);
				if (num >= 0 && num < table.m_pieces.Count && (Object)(object)table.m_pieces[num] != (Object)null)
				{
					Piece component2 = table.m_pieces[num].GetComponent<Piece>();
					if ((Object)(object)component2 != (Object)null)
					{
						component.m_category = component2.m_category;
						component.m_usage = (UsageTagFlags)(((int)component2.m_usage == 0) ? 1 : ((int)component2.m_usage));
						return;
					}
				}
				if ((int)component.m_usage == 0)
				{
					component.m_usage = (UsageTagFlags)1;
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "DestroyUI")]
		private static class DynamicUiDestroyPatch
		{
			[HarmonyPriority(800)]
			private static void Prefix(Plugin __instance)
			{
				if ((Object)(object)__instance != (Object)null)
				{
					__instance.ResetDynamicUiReferences();
				}
			}
		}

		[HarmonyPatch(typeof(Plugin), "EnsureUI")]
		private static class PlayerLayoutCreationPatch
		{
			[HarmonyPriority(0)]
			private static void Postfix(Plugin __instance, bool __result)
			{
				if (__result && !((Object)(object)__instance == (Object)null))
				{
					__instance.EnsurePlayerPageLayout();
					__instance.PolishMainWindow();
				}
			}
		}

		[HarmonyPatch(typeof(ZCursor), "set_LockState")]
		private static class PointerLockGuard
		{
			[HarmonyPriority(0)]
			private static bool Prefix(ref CursorLockMode value)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Invalid comparison between Unknown and I4
				if (!OwnsPointer)
				{
					return true;
				}
				if (value)
				{
					instance.preventedCursorLocks++;
				}
				value = (CursorLockMode)0;
				return (int)Cursor.lockState > 0;
			}
		}

		[HarmonyPatch(typeof(ZCursor), "Hide")]
		private static class PointerVisibilityGuard
		{
			private static bool Prefix()
			{
				return !OwnsPointer;
			}
		}

		[HarmonyPatch(typeof(Menu), "Update")]
		private static class EscapePatch
		{
			private static bool Prefix()
			{
				return !BlockInput;
			}
		}

		private static int eitrAttackContextDepth;

		private static bool eitrAttackContextSecondary;

		private static Attack eitrActiveAttack;

		private static bool eitrActiveAttackSecondary;

		private bool eitrRegenUiAdded;

		private EnvMan controlledEnvironment;

		private string savedWeather;

		private float savedTime;

		private float savedWindAngle;

		private float savedWindStrength;

		private bool savedTimeEnabled;

		private bool savedWindEnabled;

		private bool ownedTime;

		private long controlledEnvironmentRevision = -1L;

		private const float PlayerReductionMin = 0f;

		private const float PlayerReductionMax = 1f;

		private const float PlayerBoostMin = 1f;

		private const float PlayerBoostMax = 5f;

		private Button playerResetHookedButton;

		private GameObject playerResetConfirmOverlay;

		private const int PlayerRulesWireVersion = 1;

		private const string PlayerRulesRequestRpc = "DezzyCode.WorldControl.PlayerRules.Request.v1";

		private const string PlayerRulesStateRpc = "DezzyCode.WorldControl.PlayerRules.State.v1";

		private const float PlayerRuleMin = 0f;

		private const float PlayerRuleMax = 3f;

		private readonly HashSet<ZRpc> playerRulesRegistered = new HashSet<ZRpc>();

		private readonly Dictionary<ZRpc, float> playerRulesRequests = new Dictionary<ZRpc, float>();

		private readonly Dictionary<ZRpc, float> playerRulesEdits = new Dictionary<ZRpc, float>();

		private readonly List<ZRpc> playerRulesStale = new List<ZRpc>();

		private ConfigEntry<string> playerRulesStored;

		private bool playerRulesConfigReady;

		private bool playerRulesLoadedForServer;

		private bool playerRulesSynced;

		private bool playerRulesDraftDirty;

		private long playerRulesRevision;

		private float nextPlayerRulesQuery;

		private ZNet playerRulesNetwork;

		private PlayerResourceRules playerRules = PlayerResourceRules.Vanilla;

		private PlayerResourceRules playerRulesDraft = PlayerResourceRules.Vanilla;

		private int playerPageMode = 4;

		private GameObject playerStaminaPanel;

		private GameObject playerEitrPanel;

		private GameObject playerAdrenalinePanel;

		private Text playerRulesStatus;

		private Player playerRulesAppliedPlayer;

		private readonly Dictionary<string, float> playerFieldBaselines = new Dictionary<string, float>();

		private ObjectDB playerRulesObjectDb;

		private long playerRulesAppliedRevision = -1L;

		private readonly Dictionary<Attack, AttackBaseline> attackBaselines = new Dictionary<Attack, AttackBaseline>();

		private readonly Dictionary<Projectile, float> projectileBaselines = new Dictionary<Projectile, float>();

		private readonly Dictionary<SharedData, ShieldBaseline> shieldBaselines = new Dictionary<SharedData, ShieldBaseline>();

		private const int PlayerVitalsWireVersion = 2;

		private const string PlayerVitalsRequestRpc = "DezzyCode.WorldControl.PlayerVitals.Request.v1";

		private const string PlayerVitalsStateRpc = "DezzyCode.WorldControl.PlayerVitals.State.v1";

		private const float VitalMaxMin = 0.1f;

		private const float VitalMaxMax = 3f;

		private const float VitalRegenMin = 0f;

		private const float VitalRegenMax = 3f;

		private readonly HashSet<ZRpc> playerVitalsRegistered = new HashSet<ZRpc>();

		private readonly Dictionary<ZRpc, float> playerVitalsRequests = new Dictionary<ZRpc, float>();

		private readonly Dictionary<ZRpc, float> playerVitalsEdits = new Dictionary<ZRpc, float>();

		private readonly List<ZRpc> playerVitalsStale = new List<ZRpc>();

		private ConfigEntry<string> playerVitalsStored;

		private bool playerVitalsConfigReady;

		private bool playerVitalsLoadedForServer;

		private bool playerVitalsSynced;

		private bool playerVitalsDraftDirty;

		private long playerVitalsRevision;

		private long playerVitalsAppliedRevision = -1L;

		private float nextPlayerVitalsQuery;

		private float nextPlayerVitalsMaintenance;

		private ZNet playerVitalsNetwork;

		private PlayerVitalRules playerVitals = PlayerVitalRules.Vanilla;

		private PlayerVitalRules playerVitalsDraft = PlayerVitalRules.Vanilla;

		private Player playerVitalsAppliedPlayer;

		private bool playerVitalsUpdateFoodWarned;

		private GameObject playerVitalsPanel;

		private Button playerVitalsTabButton;

		private Text playerVitalsInfo;

		private static MethodInfo PlayerUpdateFoodMethod;

		private static bool playerUpdateFoodResolved;

		private const float VitalBoostMin = 1f;

		private const float VitalBoostMax = 5f;

		public const string PluginGuid = "dezzycode.valheim.windcontrol";

		private const string RequestRpc = "DezzyCode.WorldControl.Request.v3";

		private const string StateRpc = "DezzyCode.WorldControl.State.v3";

		private const string TeleportRpc = "DezzyCode.WorldControl.Teleport.v1";

		private const string SayRpc = "DezzyCode.WorldControl.Say.v1";

		private static Plugin instance;

		private Harmony harmony;

		private ZNet network;

		private Session session;

		private readonly HashSet<ZRpc> registered = new HashSet<ZRpc>();

		private readonly HashSet<ZRpc> participants = new HashSet<ZRpc>();

		private readonly List<ZRpc> stale = new List<ZRpc>();

		private readonly Dictionary<ZRpc, ZNetPeer> peersByRpc = new Dictionary<ZRpc, ZNetPeer>();

		private readonly Dictionary<ZRpc, float> edits = new Dictionary<ZRpc, float>();

		private readonly Dictionary<ZRpc, float> queries = new Dictionary<ZRpc, float>();

		private InitialSync initialSync = new InitialSync();

		private ZRpc serverConnection;

		private bool openWhenSynced;

		private float nextManualQuery;

		private float nextPeerMaintenance;

		private int knownPeerCount = -1;

		private ConfigEntry<KeyCode> toggleKey;

		private ConfigEntry<UiLanguage> language;

		private readonly ConfigEntry<string>[] presets = new ConfigEntry<string>[3];

		private readonly ConfigEntry<string>[] places = new ConfigEntry<string>[3];

		private ConfigEntry<string> stored;

		private bool recalled;

		private UiLanguage builtFor;

		private bool windowOpen;

		private int blockThroughFrame = -1;

		private string statusKey = "status.checking";

		private Request draft = Protocol.Defaults;

		private static FieldRef<RandEventSystem, RandomEvent> randomEventField;

		private static bool randomEventTried;

		private static FieldRef<WearNTear, bool> rainWetField;

		private static bool rainWetFieldTried;

		private float nextPlayerRulesMaintenance;

		private float nextPlayerVitalsTickOptimized;

		private static int playersCachedFrame = -1;

		private static int staminaAttackContextDepth;

		private static bool staminaAttackContextSecondary;

		private static Attack staminaActiveAttack;

		private static bool staminaActiveAttackSecondary;

		private ConfigEntry<bool> terrainEnabled;

		private ConfigEntry<float> terrainFlattenSize;

		private ConfigEntry<float> terrainFlattenSmoothness;

		private ConfigEntry<TerrainFlattenShape> terrainFlattenShape;

		private ConfigEntry<TerrainGroundTexture> terrainGroundTexture;

		private ConfigEntry<KeyboardShortcut> terrainFlattenHold;

		private ConfigEntry<bool> terrainGridMovement;

		private ConfigEntry<bool> terrainToolRadiusEnabled;

		private ConfigEntry<float> terrainHoeRadius;

		private ConfigEntry<float> terrainCultivatorRadius;

		private ConfigEntry<KeyboardShortcut> terrainRadiusIncrease;

		private ConfigEntry<KeyboardShortcut> terrainRadiusDecrease;

		private ConfigEntry<float> terrainRampThickness;

		private ConfigEntry<float> terrainRevertRadius;

		private bool terrainHolding;

		private Vector3 terrainLastCenter = new Vector3(100000f, 100000f, 100000f);

		private float terrainLastSize = -1f;

		private float terrainLastSmooth = -1f;

		private float terrainLastApply = -10f;

		private TerrainFlattenShape terrainLastShape;

		private TerrainGroundTexture terrainLastTexture;

		private bool terrainBackendWarned;

		private GameObject terrainPreviewRoot;

		private LineRenderer flattenPreview;

		private LineRenderer radiusPreview;

		private LineRenderer rampOutlinePreview;

		private LineRenderer rampCenterPreview;

		private LineRenderer revertPreview;

		private Material flattenPreviewMaterial;

		private Material radiusPreviewMaterial;

		private Material rampPreviewMaterial;

		private Material revertPreviewMaterial;

		private PieceTable terrainHoeTable;

		private GameObject terrainRampPrefab;

		private GameObject terrainRevertPrefab;

		private Texture2D terrainRampIconTexture;

		private Texture2D terrainRevertIconTexture;

		private Sprite terrainRampIcon;

		private Sprite terrainRevertIcon;

		private static MethodInfo terrainUpdatePiecesMethod;

		private static FieldInfo terrainHmapField;

		private static FieldInfo terrainLevelDeltaField;

		private static FieldInfo terrainSmoothDeltaField;

		private static FieldInfo terrainModifiedHeightField;

		private static FieldInfo terrainPaintMaskField;

		private static FieldInfo terrainModifiedPaintField;

		private static FieldInfo terrainNviewField;

		private static MethodInfo terrainSaveMethod;

		private static PlacementRadiusScope terrainActiveRadiusScope;

		private static readonly RaycastHit[] TerrainRaycastBuffer = (RaycastHit[])(object)new RaycastHit[256];

		private static readonly HashSet<TerrainComp> TerrainCompilerBuffer = new HashSet<TerrainComp>();

		private static readonly object[] TerrainSaveArguments = new object[1] { false };

		private static bool terrainFastAccessTried;

		private static FieldRef<TerrainComp, Heightmap> terrainHmapFastRef;

		private static FieldRef<TerrainComp, float[]> terrainLevelDeltaFastRef;

		private static FieldRef<TerrainComp, float[]> terrainSmoothDeltaFastRef;

		private static FieldRef<TerrainComp, bool[]> terrainModifiedHeightFastRef;

		private static FieldRef<TerrainComp, Color[]> terrainPaintMaskFastRef;

		private static FieldRef<TerrainComp, bool[]> terrainModifiedPaintFastRef;

		private static FieldRef<TerrainComp, ZNetView> terrainNviewFastRef;

		private static Action<TerrainComp, bool> terrainSaveFast;

		private float terrainNextPreviewUpdate;

		private float terrainNextPieceCheck;

		private bool terrainPieceTextReady;

		private bool terrainPieceTextGerman;

		private GameObject playerLayoutPanel;

		private GameObject playerLayoutStamina;

		private GameObject playerLayoutEitr;

		private GameObject playerLayoutAdrenaline;

		private GameObject playerLayoutVitals;

		private GameObject polishedMainPanel;

		private Button playerSharedResetButton;

		internal const float UiWindowWidth = 1480f;

		internal const float UiWindowHeight = 760f;

		internal const float UiContentX = 230f;

		internal const float UiContentY = 150f;

		internal const float UiContentWidth = 1220f;

		internal const float UiContentHeight = 420f;

		private const int PageTime = 0;

		private const int PageWeather = 1;

		private const int PageWind = 2;

		private const int PageEvents = 3;

		private const int PagePresets = 4;

		private const int PagePlayers = 5;

		private const int PagePlaces = 6;

		private const int PageSay = 7;

		private const int PagePlayerValues = 8;

		private const int PageTerrain = 9;

		private const int PageCount = 10;

		private static readonly string[] TabKeys = new string[10] { "tab.time", "tab.weather", "tab.wind", "tab.events", "tab.presets", "tab.players", "tab.places", "tab.say", "tab.values", "tab.terrain" };

		private GameObject panel;

		private readonly GameObject[] pages = (GameObject[])(object)new GameObject[10];

		private InputField _message;

		private InputField _placeName;

		private int eventPage;

		private int playerPage;

		private static List<string> eventNames;

		private readonly List<Action> refresh = new List<Action>();

		private Text clockText;

		private Text statusText;

		private Button applyButton;

		private Button resetButton;

		private bool uiInputBlocked;

		private bool controlsDirty;

		private int preventedCursorLocks;

		private int recoveredCursorLocks;

		private static Sprite mark;

		private static bool markMissing;

		private int tab;

		private float nextUiRequest;

		private float nextUiRefresh;

		private const int EventsPerPage = 5;

		private static readonly Dictionary<string, string> EventTitles = new Dictionary<string, string>();

		private static readonly Biome[] SingleBiomes;

		private const int PlayersPerPage = 5;

		private static readonly List<PlayerInfo> PlayerBuffer;

		private static readonly CultureInfo Culture;

		private static readonly float[] Holds;

		private bool HasState
		{
			get
			{
				if (session == null || !session.Synced || (Object)(object)network == (Object)null)
				{
					return false;
				}
				if (session.Server)
				{
					return true;
				}
				ZNetPeer serverPeer = network.GetServerPeer();
				if (serverPeer != null && serverConnection != null && serverPeer.m_rpc == serverConnection)
				{
					return serverConnection.IsConnected();
				}
				return false;
			}
		}

		private bool CanEdit
		{
			get
			{
				if (HasState)
				{
					if (!session.Server)
					{
						return session.State.CanEdit;
					}
					return true;
				}
				return false;
			}
		}

		private static bool BlockInput
		{
			get
			{
				if ((Object)(object)instance != (Object)null)
				{
					if (!instance.windowOpen)
					{
						return Time.frameCount <= instance.blockThroughFrame;
					}
					return true;
				}
				return false;
			}
		}

		private static bool OwnsPointer
		{
			get
			{
				if ((Object)(object)instance != (Object)null && instance.windowOpen)
				{
					return Application.isFocused;
				}
				return false;
			}
		}

		private static bool CanScaleLocalEitr(Character character)
		{
			Plugin plugin = instance;
			if ((Object)(object)plugin != (Object)null && plugin.playerRulesSynced && (Object)(object)character != (Object)null)
			{
				return (object)character == Player.m_localPlayer;
			}
			return false;
		}

		private static EitrReloadCostState ScaleReloadEitrTemporarily(Player player, ItemData weapon)
		{
			EitrReloadCostState result = default(EitrReloadCostState);
			if (!CanScaleLocalEitr((Character)(object)player) || weapon == null || weapon.m_shared == null || weapon.m_shared.m_attack == null)
			{
				return result;
			}
			float reloadEitr = instance.playerRules.ReloadEitr;
			if (reloadEitr == 1f)
			{
				return result;
			}
			Attack val = (result.Attack = weapon.m_shared.m_attack);
			result.Value = val.m_reloadEitrDrain;
			result.Changed = true;
			val.m_reloadEitrDrain = result.Value * reloadEitr;
			return result;
		}

		private static void RestoreReloadEitr(ref EitrReloadCostState state)
		{
			if (state.Changed)
			{
				if (state.Attack != null)
				{
					state.Attack.m_reloadEitrDrain = state.Value;
				}
				state.Changed = false;
			}
		}

		private static EitrRepairCostState ScaleRepairEitrTemporarily(Player player, ItemData tool)
		{
			EitrRepairCostState result = default(EitrRepairCostState);
			if (!CanScaleLocalEitr((Character)(object)player) || tool == null || tool.m_shared == null || tool.m_shared.m_attack == null)
			{
				return result;
			}
			float primaryEitr = instance.playerRules.PrimaryEitr;
			if (primaryEitr == 1f)
			{
				return result;
			}
			Attack val = (result.Attack = tool.m_shared.m_attack);
			result.Value = val.m_attackEitr;
			result.Changed = true;
			val.m_attackEitr = result.Value * primaryEitr;
			return result;
		}

		private static void RestoreRepairEitr(ref EitrRepairCostState state)
		{
			if (state.Changed)
			{
				if (state.Attack != null)
				{
					state.Attack.m_attackEitr = state.Value;
				}
				state.Changed = false;
			}
		}

		private static void RestoreEitrAttackContext(ref EitrAttackContextState state)
		{
			if (state.Changed)
			{
				eitrAttackContextDepth = state.Depth;
				eitrAttackContextSecondary = state.Secondary;
				state.Changed = false;
			}
		}

		private static void RestoreRegenTick(Player player, ref RegenTickState state)
		{
			if (state.Changed)
			{
				if ((Object)(object)player != (Object)null)
				{
					player.m_staminaRegen = state.Stamina;
					player.m_eiterRegen = state.Eitr;
				}
				state.Changed = false;
			}
		}

		private void AddEitrRegenSlider(Transform parent)
		{
			if (!((Object)(object)parent == (Object)null) && !eitrRegenUiAdded)
			{
				eitrRegenUiAdded = true;
				VitalSlider(parent, 0f, 246f, 650f, 0f, 3f, "Eitr regeneration", "Eitr-Regeneration", () => playerVitalsDraft.EitrRegen, delegate(float v)
				{
					playerVitalsDraft.EitrRegen = v;
				});
				if ((Object)(object)playerVitalsInfo != (Object)null)
				{
					Position(((Component)playerVitalsInfo).gameObject, 6f, 322f, 1318f, 54f);
				}
			}
		}

		private void RestoreEnvironment()
		{
			if ((Object)(object)controlledEnvironment != (Object)null)
			{
				controlledEnvironment.m_debugEnv = savedWeather;
				controlledEnvironment.m_debugTimeOfDay = savedTimeEnabled;
				controlledEnvironment.m_debugTime = savedTime;
				if (savedWindEnabled)
				{
					controlledEnvironment.SetDebugWind(savedWindAngle, savedWindStrength);
				}
				else
				{
					controlledEnvironment.ResetDebugWind();
				}
			}
			controlledEnvironment = null;
			ownedTime = false;
			controlledEnvironmentRevision = -1L;
		}

		private static bool InRange(float value, float min, float max)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value) && value >= min)
			{
				return value <= max;
			}
			return false;
		}

		private static bool BuffOnlyPlayerRules(PlayerResourceRules r)
		{
			if (!InRange(r.Run, 0f, 1f) || !InRange(r.Jump, 0f, 1f) || !InRange(r.Dodge, 0f, 1f) || !InRange(r.Swim, 0f, 1f) || !InRange(r.Sneak, 0f, 1f) || !InRange(r.Encumbered, 0f, 1f) || !InRange(r.Block, 0f, 1f) || !InRange(r.Grapple, 0f, 1f) || !InRange(r.PrimaryStamina, 0f, 1f) || !InRange(r.SecondaryStamina, 0f, 1f) || !InRange(r.DrawStamina, 0f, 1f) || !InRange(r.ReloadStamina, 0f, 1f) || !InRange(r.HomeStamina, 0f, 1f) || !InRange(r.PrimaryEitr, 0f, 1f) || !InRange(r.SecondaryEitr, 0f, 1f) || !InRange(r.DrawEitr, 0f, 1f) || !InRange(r.ReloadEitr, 0f, 1f))
			{
				return false;
			}
			if (!InRange(r.PrimaryAdrenaline, 1f, 5f) || !InRange(r.SecondaryAdrenaline, 1f, 5f) || !InRange(r.ProjectileAdrenaline, 1f, 5f) || !InRange(r.BlockAdrenaline, 1f, 5f) || !InRange(r.ParryAdrenaline, 1f, 5f) || !InRange(r.PerfectDodgeAdrenaline, 1f, 5f) || !InRange(r.StaggerAdrenaline, 1f, 5f) || !InRange(r.GuardianAdrenaline, 1f, 5f))
			{
				return false;
			}
			if (InRange(r.MissAdrenaline, 0f, 1f))
			{
				return InRange(r.DamageAdrenaline, 0f, 1f);
			}
			return false;
		}

		private static void SetAllPlayerSliderRanges(Transform parent, float min, float max)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			Slider[] componentsInChildren = ((Component)parent).GetComponentsInChildren<Slider>(true);
			foreach (Slider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.minValue = min;
					val.maxValue = max;
					val.SetValueWithoutNotify(Mathf.Clamp(val.value, min, max));
				}
			}
		}

		private static void SetAdrenalineSliderRanges(Transform parent)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			Slider[] componentsInChildren = ((Component)parent).GetComponentsInChildren<Slider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Slider val = componentsInChildren[i];
				if (!((Object)(object)val == (Object)null))
				{
					bool flag = i == 7 || i == 8;
					val.minValue = (flag ? 0f : 1f);
					val.maxValue = (flag ? 1f : 5f);
					val.SetValueWithoutNotify(Mathf.Clamp(val.value, val.minValue, val.maxValue));
				}
			}
		}

		private void ReplacePlayerRuleFooter(Transform parent, string english, string german)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			string text = PR(english, german);
			Text[] componentsInChildren = ((Component)parent).GetComponentsInChildren<Text>(true);
			foreach (Text val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.text) && (val.text.Contains("1.00×") || val.text.Contains("1,00×")))
				{
					val.text = text;
					break;
				}
			}
		}

		private void EnsurePlayerResetConfirmationHook()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			if (!((Object)(object)playerSharedResetButton == (Object)null) && playerResetHookedButton != playerSharedResetButton)
			{
				playerResetHookedButton = playerSharedResetButton;
				((UnityEventBase)playerSharedResetButton.onClick).RemoveAllListeners();
				((UnityEvent)playerSharedResetButton.onClick).AddListener((UnityAction)delegate
				{
					ShowPlayerResetConfirmation();
					controlsDirty = true;
				});
			}
		}

		private void ShowPlayerResetConfirmation()
		{
			if (!((Object)(object)pages[8] == (Object)null))
			{
				if ((Object)(object)playerResetConfirmOverlay == (Object)null)
				{
					BuildPlayerResetConfirmation();
				}
				if (!((Object)(object)playerResetConfirmOverlay == (Object)null))
				{
					playerResetConfirmOverlay.transform.SetAsLastSibling();
					playerResetConfirmOverlay.SetActive(true);
				}
			}
		}

		private void BuildPlayerResetConfirmation()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = pages[8];
			if (!((Object)(object)val == (Object)null))
			{
				GameObject val2 = new GameObject("PlayerResetConfirmation", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val2.transform.SetParent(val.transform, false);
				Position(val2, 0f, 0f, 1220f, 420f);
				Image component = val2.GetComponent<Image>();
				((Graphic)component).color = new Color(0f, 0f, 0f, 0.58f);
				((Graphic)component).raycastTarget = true;
				GameObject val3 = GUIManager.Instance.CreateWoodpanel(val2.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, 640f, 220f, false);
				((Object)val3).name = "PlayerResetConfirmationBox";
				Position(val3, 290f, 88f, 640f, 220f);
				Label(val3.transform, 28f, 22f, 584f, PR("Reset player values?", "Spielerwerte zurücksetzen?"), 24, 38f);
				Label(val3.transform, 28f, 70f, 584f, PR("Are you sure you want to reset all player values to Vanilla?", "Bist du sicher, dass du alle Spielerwerte auf Vanilla zurücksetzen willst?"), 16, 58f);
				Button(val3.transform, 28f, 154f, 278f, 40f, PR("Yes, reset", "Ja, zurücksetzen"), delegate
				{
					ResetAllPlayerDrafts();
					HidePlayerResetConfirmation();
				});
				Button(val3.transform, 334f, 154f, 278f, 40f, PR("Cancel", "Abbrechen"), HidePlayerResetConfirmation);
				playerResetConfirmOverlay = val2;
				playerResetConfirmOverlay.SetActive(false);
			}
		}

		private void HidePlayerResetConfirmation()
		{
			if ((Object)(object)playerResetConfirmOverlay != (Object)null)
			{
				playerResetConfirmOverlay.SetActive(false);
			}
		}

		private void ResetPlayerConfirmationReferences()
		{
			playerResetHookedButton = null;
			playerResetConfirmOverlay = null;
		}

		private void EnsurePlayerRulesConfig()
		{
			if (!playerRulesConfigReady)
			{
				playerRulesConfigReady = true;
				playerRulesStored = ((BaseUnityPlugin)this).Config.Bind<string>("Server - Player Rules", "State", "", "Written by the World Control server. Server-authoritative stamina, eitr and adrenaline multipliers.");
			}
		}

		private static bool PlayerRule(float value)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value) && value >= 0f)
			{
				return value <= 3f;
			}
			return false;
		}

		private static bool ValidPlayerRules(PlayerResourceRules r)
		{
			if (PlayerRule(r.Run) && PlayerRule(r.Jump) && PlayerRule(r.Dodge) && PlayerRule(r.Swim) && PlayerRule(r.Sneak) && PlayerRule(r.Encumbered) && PlayerRule(r.Block) && PlayerRule(r.Grapple) && PlayerRule(r.PrimaryStamina) && PlayerRule(r.SecondaryStamina) && PlayerRule(r.DrawStamina) && PlayerRule(r.ReloadStamina) && PlayerRule(r.HomeStamina) && PlayerRule(r.PrimaryEitr) && PlayerRule(r.SecondaryEitr) && PlayerRule(r.DrawEitr) && PlayerRule(r.ReloadEitr) && PlayerRule(r.PrimaryAdrenaline) && PlayerRule(r.SecondaryAdrenaline) && PlayerRule(r.ProjectileAdrenaline) && PlayerRule(r.BlockAdrenaline) && PlayerRule(r.ParryAdrenaline) && PlayerRule(r.PerfectDodgeAdrenaline) && PlayerRule(r.StaggerAdrenaline) && PlayerRule(r.MissAdrenaline) && PlayerRule(r.DamageAdrenaline))
			{
				return PlayerRule(r.GuardianAdrenaline);
			}
			return false;
		}

		private static void WritePlayerRules(BinaryWriter w, PlayerResourceRules r)
		{
			w.Write(r.Run);
			w.Write(r.Jump);
			w.Write(r.Dodge);
			w.Write(r.Swim);
			w.Write(r.Sneak);
			w.Write(r.Encumbered);
			w.Write(r.Block);
			w.Write(r.Grapple);
			w.Write(r.PrimaryStamina);
			w.Write(r.SecondaryStamina);
			w.Write(r.DrawStamina);
			w.Write(r.ReloadStamina);
			w.Write(r.HomeStamina);
			w.Write(r.PrimaryEitr);
			w.Write(r.SecondaryEitr);
			w.Write(r.DrawEitr);
			w.Write(r.ReloadEitr);
			w.Write(r.PrimaryAdrenaline);
			w.Write(r.SecondaryAdrenaline);
			w.Write(r.ProjectileAdrenaline);
			w.Write(r.BlockAdrenaline);
			w.Write(r.ParryAdrenaline);
			w.Write(r.PerfectDodgeAdrenaline);
			w.Write(r.StaggerAdrenaline);
			w.Write(r.MissAdrenaline);
			w.Write(r.DamageAdrenaline);
			w.Write(r.GuardianAdrenaline);
		}

		private static PlayerResourceRules ReadPlayerRules(BinaryReader r)
		{
			return new PlayerResourceRules
			{
				Run = r.ReadSingle(),
				Jump = r.ReadSingle(),
				Dodge = r.ReadSingle(),
				Swim = r.ReadSingle(),
				Sneak = r.ReadSingle(),
				Encumbered = r.ReadSingle(),
				Block = r.ReadSingle(),
				Grapple = r.ReadSingle(),
				PrimaryStamina = r.ReadSingle(),
				SecondaryStamina = r.ReadSingle(),
				DrawStamina = r.ReadSingle(),
				ReloadStamina = r.ReadSingle(),
				HomeStamina = r.ReadSingle(),
				PrimaryEitr = r.ReadSingle(),
				SecondaryEitr = r.ReadSingle(),
				DrawEitr = r.ReadSingle(),
				ReloadEitr = r.ReadSingle(),
				PrimaryAdrenaline = r.ReadSingle(),
				SecondaryAdrenaline = r.ReadSingle(),
				ProjectileAdrenaline = r.ReadSingle(),
				BlockAdrenaline = r.ReadSingle(),
				ParryAdrenaline = r.ReadSingle(),
				PerfectDodgeAdrenaline = r.ReadSingle(),
				StaggerAdrenaline = r.ReadSingle(),
				MissAdrenaline = r.ReadSingle(),
				DamageAdrenaline = r.ReadSingle(),
				GuardianAdrenaline = r.ReadSingle()
			};
		}

		private static byte[] EncodePlayerRulesRequest(bool apply, PlayerResourceRules rules)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(1);
			binaryWriter.Write(apply ? ((byte)1) : ((byte)0));
			if (apply)
			{
				WritePlayerRules(binaryWriter, rules);
			}
			return memoryStream.ToArray();
		}

		private static bool DecodePlayerRulesRequest(byte[] bytes, out bool apply, out PlayerResourceRules rules)
		{
			apply = false;
			rules = PlayerResourceRules.Vanilla;
			if (bytes == null || bytes.Length > 256)
			{
				return false;
			}
			try
			{
				using BinaryReader binaryReader = new BinaryReader(new MemoryStream(bytes));
				if (binaryReader.ReadInt32() != 1)
				{
					return false;
				}
				byte b = binaryReader.ReadByte();
				if (b > 1)
				{
					return false;
				}
				apply = b == 1;
				if (apply)
				{
					rules = ReadPlayerRules(binaryReader);
				}
				return binaryReader.BaseStream.Position == binaryReader.BaseStream.Length && (!apply || ValidPlayerRules(rules));
			}
			catch (Exception ex) when (ex is IOException || ex is EndOfStreamException || ex is ArgumentException)
			{
				return false;
			}
		}

		private static byte[] EncodePlayerRulesState(long revision, PlayerResourceRules rules)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(1);
			binaryWriter.Write(revision);
			WritePlayerRules(binaryWriter, rules);
			return memoryStream.ToArray();
		}

		private static bool DecodePlayerRulesState(byte[] bytes, out long revision, out PlayerResourceRules rules)
		{
			revision = 0L;
			rules = PlayerResourceRules.Vanilla;
			if (bytes == null || bytes.Length > 256)
			{
				return false;
			}
			try
			{
				using BinaryReader binaryReader = new BinaryReader(new MemoryStream(bytes));
				if (binaryReader.ReadInt32() != 1)
				{
					return false;
				}
				revision = binaryReader.ReadInt64();
				rules = ReadPlayerRules(binaryReader);
				return binaryReader.BaseStream.Position == binaryReader.BaseStream.Length && revision >= 0 && ValidPlayerRules(rules);
			}
			catch (Exception ex) when (ex is IOException || ex is EndOfStreamException || ex is ArgumentException)
			{
				return false;
			}
		}

		private void LoadPlayerRules()
		{
			EnsurePlayerRulesConfig();
			playerRules = PlayerResourceRules.Vanilla;
			playerRulesRevision = 1L;
			string text = ((playerRulesStored != null) ? playerRulesStored.Value : "");
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			try
			{
				if (DecodePlayerRulesState(Convert.FromBase64String(text), out var revision, out var rules))
				{
					playerRules = rules;
					playerRulesRevision = Math.Max(1L, revision);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not read stored player rules: " + ex.Message));
			}
		}

		private void SavePlayerRules()
		{
			EnsurePlayerRulesConfig();
			if (playerRulesStored != null)
			{
				playerRulesStored.Value = Convert.ToBase64String(EncodePlayerRulesState(playerRulesRevision, playerRules));
			}
		}

		private void ResetPlayerRulesNetwork()
		{
			foreach (ZRpc item in playerRulesRegistered)
			{
				try
				{
					item.Unregister("DezzyCode.WorldControl.PlayerRules.Request.v1");
					item.Unregister("DezzyCode.WorldControl.PlayerRules.State.v1");
				}
				catch
				{
				}
			}
			playerRulesRegistered.Clear();
			playerRulesRequests.Clear();
			playerRulesEdits.Clear();
			playerRulesNetwork = network;
			playerRulesLoadedForServer = false;
			nextPlayerRulesQuery = 0f;
			playerRulesSynced = session != null && session.Server;
			playerRulesRevision = 0L;
			if (session == null || !session.Server)
			{
				playerRules = PlayerResourceRules.Vanilla;
			}
			playerRulesDraft = playerRules;
			playerRulesDraftDirty = false;
			RestorePlayerRuleTuning();
		}

		private void PlayerRulesTick()
		{
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Expected O, but got Unknown
			EnsurePlayerRulesConfig();
			if (playerRulesNetwork != network)
			{
				ResetPlayerRulesNetwork();
			}
			if ((Object)(object)network == (Object)null || session == null)
			{
				return;
			}
			if (session.Server && !playerRulesLoadedForServer)
			{
				playerRulesLoadedForServer = true;
				LoadPlayerRules();
				playerRulesSynced = true;
				playerRulesDraft = playerRules;
			}
			foreach (ZNetPeer peer in network.GetPeers())
			{
				if (peer != null && peer.m_rpc != null && playerRulesRegistered.Add(peer.m_rpc))
				{
					peer.m_rpc.Register<ZPackage>("DezzyCode.WorldControl.PlayerRules.Request.v1", (Action<ZRpc, ZPackage>)OnPlayerRulesRequest);
					peer.m_rpc.Register<ZPackage>("DezzyCode.WorldControl.PlayerRules.State.v1", (Action<ZRpc, ZPackage>)OnPlayerRulesState);
					if (session.Server && peer.IsReady() && peer.m_rpc.IsConnected())
					{
						SendPlayerRulesState(peer.m_rpc);
					}
				}
			}
			playerRulesStale.Clear();
			foreach (ZRpc item in playerRulesRegistered)
			{
				if (item == null || !item.IsConnected())
				{
					playerRulesStale.Add(item);
				}
			}
			foreach (ZRpc item2 in playerRulesStale)
			{
				playerRulesRegistered.Remove(item2);
				playerRulesRequests.Remove(item2);
				playerRulesEdits.Remove(item2);
				try
				{
					item2.Unregister("DezzyCode.WorldControl.PlayerRules.Request.v1");
					item2.Unregister("DezzyCode.WorldControl.PlayerRules.State.v1");
				}
				catch
				{
				}
			}
			if (!session.Server && !playerRulesSynced && Time.unscaledTime >= nextPlayerRulesQuery)
			{
				ZNetPeer serverPeer = network.GetServerPeer();
				if (serverPeer != null && serverPeer.IsReady() && serverPeer.m_rpc != null && serverPeer.m_rpc.IsConnected())
				{
					nextPlayerRulesQuery = Time.unscaledTime + 1f;
					serverPeer.m_rpc.Invoke("DezzyCode.WorldControl.PlayerRules.Request.v1", new object[1] { (object)new ZPackage(EncodePlayerRulesRequest(apply: false, PlayerResourceRules.Vanilla)) });
				}
			}
			if (playerRulesSynced)
			{
				ApplyPlayerRuleTuning();
			}
		}

		private void OnPlayerRulesRequest(ZRpc rpc, ZPackage package)
		{
			ZNetPeer val = ReadyPeer(rpc);
			if (session == null || !session.Server || rpc == null || val == null || package == null || package.Size() > 256 || !DecodePlayerRulesRequest(package.GetArray(), out var apply, out var rules))
			{
				return;
			}
			Dictionary<ZRpc, float> dictionary = (apply ? playerRulesEdits : playerRulesRequests);
			if (!dictionary.TryGetValue(rpc, out var value) || !(Time.unscaledTime < value))
			{
				dictionary[rpc] = Time.unscaledTime + (apply ? 0.35f : 0.75f);
				if (apply && IsAdmin(rpc))
				{
					playerRules = rules;
					playerRulesRevision = Math.Max(1L, playerRulesRevision + 1);
					SavePlayerRules();
					playerRulesDraft = playerRules;
					playerRulesDraftDirty = false;
					BroadcastPlayerRules();
					controlsDirty = true;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Player resource rules changed by admin " + val.m_playerName + "."));
				}
				else
				{
					SendPlayerRulesState(rpc);
				}
			}
		}

		private void OnPlayerRulesState(ZRpc rpc, ZPackage package)
		{
			if (session != null && !session.Server && rpc != null && package != null && package.Size() <= 256 && serverConnection != null && rpc == serverConnection && DecodePlayerRulesState(package.GetArray(), out var revision, out var rules) && (!playerRulesSynced || revision >= playerRulesRevision))
			{
				playerRulesRevision = revision;
				playerRules = rules;
				playerRulesSynced = true;
				if (!playerRulesDraftDirty)
				{
					playerRulesDraft = rules;
				}
				controlsDirty = true;
			}
		}

		private void SendPlayerRulesState(ZRpc rpc)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if (rpc != null && rpc.IsConnected())
			{
				rpc.Invoke("DezzyCode.WorldControl.PlayerRules.State.v1", new object[1] { (object)new ZPackage(EncodePlayerRulesState(playerRulesRevision, playerRules)) });
			}
		}

		private void BroadcastPlayerRules()
		{
			foreach (ZNetPeer peer in network.GetPeers())
			{
				if (peer != null && peer.IsReady() && peer.m_rpc != null && peer.m_rpc.IsConnected() && playerRulesRegistered.Contains(peer.m_rpc))
				{
					SendPlayerRulesState(peer.m_rpc);
				}
			}
			ApplyPlayerRuleTuning();
		}

		private void SubmitPlayerRules()
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			if (!CanEdit || !ValidPlayerRules(playerRulesDraft))
			{
				return;
			}
			if (session != null && session.Server)
			{
				playerRules = playerRulesDraft;
				playerRulesRevision = Math.Max(1L, playerRulesRevision + 1);
				playerRulesSynced = true;
				playerRulesDraftDirty = false;
				SavePlayerRules();
				BroadcastPlayerRules();
				controlsDirty = true;
			}
			else
			{
				ZNetPeer val = (((Object)(object)network != (Object)null) ? network.GetServerPeer() : null);
				if (val != null && val.IsReady() && val.m_rpc != null && val.m_rpc.IsConnected())
				{
					val.m_rpc.Invoke("DezzyCode.WorldControl.PlayerRules.Request.v1", new object[1] { (object)new ZPackage(EncodePlayerRulesRequest(apply: true, playerRulesDraft)) });
				}
			}
		}

		private static FieldInfo PlayerRuleField(string name)
		{
			Type type = typeof(Player);
			while (type != null)
			{
				FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && field.FieldType == typeof(float))
				{
					return field;
				}
				type = type.BaseType;
			}
			return null;
		}

		private void ApplyPlayerFloat(Player player, string fieldName, float multiplier)
		{
			FieldInfo fieldInfo = PlayerRuleField(fieldName);
			if (fieldInfo == null || (Object)(object)player == (Object)null)
			{
				return;
			}
			if (!playerFieldBaselines.TryGetValue(fieldName, out var value))
			{
				try
				{
					value = (float)fieldInfo.GetValue(player);
					playerFieldBaselines[fieldName] = value;
				}
				catch
				{
					return;
				}
			}
			try
			{
				fieldInfo.SetValue(player, value * multiplier);
			}
			catch
			{
			}
		}

		private void ApplyPlayerRuleTuning()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				bool flag = playerRulesAppliedPlayer != localPlayer;
				bool flag2 = playerRulesObjectDb != ObjectDB.instance;
				if (flag)
				{
					RestorePlayerFields();
					playerRulesAppliedPlayer = localPlayer;
					playerFieldBaselines.Clear();
					playerRulesAppliedRevision = -1L;
				}
				if (flag2)
				{
					RestoreItemRules();
					playerRulesObjectDb = ObjectDB.instance;
					attackBaselines.Clear();
					projectileBaselines.Clear();
					shieldBaselines.Clear();
					playerRulesAppliedRevision = -1L;
				}
				if (playerRulesAppliedRevision != playerRulesRevision || flag || flag2)
				{
					ApplyPlayerFloat(localPlayer, "m_runStaminaDrain", playerRules.Run);
					ApplyPlayerFloat(localPlayer, "m_jumpStaminaUsage", playerRules.Jump);
					ApplyPlayerFloat(localPlayer, "m_dodgeStaminaUsage", playerRules.Dodge);
					ApplyPlayerFloat(localPlayer, "m_swimStaminaDrainMinSkill", playerRules.Swim);
					ApplyPlayerFloat(localPlayer, "m_swimStaminaDrainMaxSkill", playerRules.Swim);
					ApplyPlayerFloat(localPlayer, "m_sneakStaminaDrain", playerRules.Sneak);
					ApplyPlayerFloat(localPlayer, "m_encumberedStaminaDrain", playerRules.Encumbered);
					ApplyPlayerFloat(localPlayer, "m_grapplingStaminaDrain", playerRules.Grapple);
					ApplyPlayerFloat(localPlayer, "m_perfectDodgeAdrenaline", playerRules.PerfectDodgeAdrenaline);
					ApplyPlayerFloat(localPlayer, "m_staggerEnemyAdrenaline", playerRules.StaggerAdrenaline);
					ApplyPlayerFloat(localPlayer, "m_attackMissAdrenaline", playerRules.MissAdrenaline);
					ApplyPlayerFloat(localPlayer, "m_nonBlockDamageAdrenaline", playerRules.DamageAdrenaline);
					ApplyPlayerFloat(localPlayer, "m_adrenalineGuardianPower", playerRules.GuardianAdrenaline);
					TuneItemRules();
					playerRulesAppliedRevision = playerRulesRevision;
				}
			}
		}

		private void TuneItemRules()
		{
			ObjectDB val = ObjectDB.instance;
			if ((Object)(object)val == (Object)null || val.m_items == null)
			{
				return;
			}
			foreach (GameObject item in val.m_items)
			{
				if (!((Object)(object)item == (Object)null))
				{
					ItemDrop component = item.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null)
					{
						SharedData shared = component.m_itemData.m_shared;
						TuneAttack(shared.m_attack, primary: true);
						TuneAttack(shared.m_secondaryAttack, primary: false);
						TuneShield(shared);
					}
				}
			}
		}

		private void TuneAttack(Attack attack, bool primary)
		{
			if (attack == null)
			{
				return;
			}
			if (!attackBaselines.TryGetValue(attack, out var value))
			{
				value = new AttackBaseline
				{
					AttackAdrenaline = attack.m_attackAdrenaline
				};
				attackBaselines[attack] = value;
			}
			float num = (primary ? playerRules.PrimaryAdrenaline : playerRules.SecondaryAdrenaline);
			attack.m_attackAdrenaline = value.AttackAdrenaline * num;
			if (!((Object)(object)attack.m_attackProjectile != (Object)null))
			{
				return;
			}
			Projectile component = attack.m_attackProjectile.GetComponent<Projectile>();
			if ((Object)(object)component != (Object)null)
			{
				if (!projectileBaselines.TryGetValue(component, out var value2))
				{
					value2 = component.m_adrenaline;
					projectileBaselines[component] = value2;
				}
				component.m_adrenaline = value2 * playerRules.ProjectileAdrenaline;
			}
		}

		private void TuneShield(SharedData shared)
		{
			if (shared != null)
			{
				if (!shieldBaselines.TryGetValue(shared, out var value))
				{
					value = new ShieldBaseline
					{
						Block = shared.m_blockAdrenaline,
						Parry = shared.m_perfectBlockAdrenaline
					};
					shieldBaselines[shared] = value;
				}
				shared.m_blockAdrenaline = value.Block * playerRules.BlockAdrenaline;
				shared.m_perfectBlockAdrenaline = value.Parry * playerRules.ParryAdrenaline;
			}
		}

		private void RestorePlayerFields()
		{
			Player val = playerRulesAppliedPlayer;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			foreach (KeyValuePair<string, float> playerFieldBaseline in playerFieldBaselines)
			{
				FieldInfo fieldInfo = PlayerRuleField(playerFieldBaseline.Key);
				if (!(fieldInfo == null))
				{
					try
					{
						fieldInfo.SetValue(val, playerFieldBaseline.Value);
					}
					catch
					{
					}
				}
			}
		}

		private void RestoreItemRules()
		{
			foreach (KeyValuePair<Attack, AttackBaseline> attackBaseline in attackBaselines)
			{
				Attack key = attackBaseline.Key;
				AttackBaseline value = attackBaseline.Value;
				if (key != null && value != null)
				{
					key.m_attackAdrenaline = value.AttackAdrenaline;
				}
			}
			foreach (KeyValuePair<Projectile, float> projectileBaseline in projectileBaselines)
			{
				if ((Object)(object)projectileBaseline.Key != (Object)null)
				{
					projectileBaseline.Key.m_adrenaline = projectileBaseline.Value;
				}
			}
			foreach (KeyValuePair<SharedData, ShieldBaseline> shieldBaseline in shieldBaselines)
			{
				if (shieldBaseline.Key != null && shieldBaseline.Value != null)
				{
					shieldBaseline.Key.m_blockAdrenaline = shieldBaseline.Value.Block;
					shieldBaseline.Key.m_perfectBlockAdrenaline = shieldBaseline.Value.Parry;
				}
			}
		}

		private void RestorePlayerRuleTuning()
		{
			RestorePlayerFields();
			RestoreItemRules();
			playerRulesAppliedPlayer = null;
			playerFieldBaselines.Clear();
			playerRulesObjectDb = null;
			attackBaselines.Clear();
			projectileBaselines.Clear();
			shieldBaselines.Clear();
			playerRulesAppliedRevision = -1L;
		}

		private static string PR(string english, string german)
		{
			if (!Words.IsGerman)
			{
				return english;
			}
			return german;
		}

		private void EnsurePlayerRulesUI()
		{
			if ((Object)(object)panel == (Object)null || (Object)(object)pages[8] == (Object)null || (Object)(object)playerStaminaPanel != (Object)null)
			{
				return;
			}
			GameObject val = pages[8];
			Position(val, 210f, 158f, 1350f, 470f);
			playerStaminaPanel = PlayerRulePanel(val.transform, "PlayerStamina", 0f, 52f, 1350f, 410f);
			playerEitrPanel = PlayerRulePanel(val.transform, "PlayerEitr", 0f, 52f, 1350f, 410f);
			playerAdrenalinePanel = PlayerRulePanel(val.transform, "PlayerAdrenaline", 0f, 52f, 1350f, 410f);
			Choice(val.transform, 250f, 0f, 240f, () => PR("Stamina", "Ausdauer"), () => playerPageMode == 1, delegate
			{
				playerPageMode = 1;
			});
			Choice(val.transform, 500f, 0f, 240f, () => PR("Eitr", "Eitr"), () => playerPageMode == 2, delegate
			{
				playerPageMode = 2;
			});
			Choice(val.transform, 750f, 0f, 240f, () => PR("Adrenaline", "Adrenalin"), () => playerPageMode == 3, delegate
			{
				playerPageMode = 3;
			});
			BuildStaminaRules(playerStaminaPanel.transform);
			BuildEitrRules(playerEitrPanel.transform);
			BuildAdrenalineRules(playerAdrenalinePanel.transform);
			playerRulesStatus = Label(val.transform, 1010f, 2f, 330f, "", 13, 36f);
			refresh.Add(delegate
			{
				if ((Object)(object)playerStaminaPanel != (Object)null)
				{
					playerStaminaPanel.SetActive(playerPageMode == 1);
				}
				if ((Object)(object)playerEitrPanel != (Object)null)
				{
					playerEitrPanel.SetActive(playerPageMode == 2);
				}
				if ((Object)(object)playerAdrenalinePanel != (Object)null)
				{
					playerAdrenalinePanel.SetActive(playerPageMode == 3);
				}
				if ((Object)(object)playerRulesStatus != (Object)null)
				{
					playerRulesStatus.text = (playerRulesDraftDirty ? PR("Local changes · not applied", "Lokale Änderungen · nicht übernommen") : (playerRulesSynced ? PR("Server rules synchronized", "Serverregeln synchronisiert") : PR("Waiting for server rules ...", "Warte auf Serverregeln ...")));
				}
			});
		}

		private GameObject PlayerRulePanel(Transform parent, string name, float x, float y, float width, float height)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0034: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			Position(val, x, y, width, height);
			return val;
		}

		private void PlayerRuleSlider(Transform parent, float x, float y, float width, string label, Func<float> read, Action<float> write)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			Text text = Label(parent, x + 6f, y, width - 12f, "", 14, 22f);
			GameObject val = DefaultControls.CreateSlider(GUIManager.Instance.ValheimControlResources);
			val.transform.SetParent(parent, false);
			Position(val, x + 8f, y + 23f, width - 16f, 20f);
			Slider slider = val.GetComponent<Slider>();
			GUIManager.Instance.ApplySliderStyle(slider, new Vector2(18f, 20f));
			slider.minValue = 0f;
			slider.maxValue = 3f;
			slider.wholeNumbers = false;
			slider.SetValueWithoutNotify(read());
			((UnityEvent<float>)(object)slider.onValueChanged).AddListener((UnityAction<float>)delegate(float value)
			{
				float num = Mathf.Round(value * 20f) / 20f;
				write(num);
				slider.SetValueWithoutNotify(num);
				playerRulesDraftDirty = true;
				controlsDirty = true;
			});
			Slider obj = slider;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)obj).navigation = navigation;
			refresh.Add(delegate
			{
				float num = read();
				text.text = label + "   " + num.ToString("0.00", CultureInfo.InvariantCulture) + "×";
				if (!Mathf.Approximately(slider.value, num))
				{
					slider.SetValueWithoutNotify(num);
				}
				((Selectable)slider).interactable = CanEdit && playerRulesSynced;
			});
		}

		private void PlayerRuleFooter(Transform parent, string resetWhat)
		{
			Button apply = Button(parent, 0f, 366f, 280f, 36f, PR("Apply to server", "Auf Server übernehmen"), SubmitPlayerRules);
			Button(parent, 294f, 366f, 280f, 36f, PR("Reset all to Vanilla", "Alles auf Vanilla"), delegate
			{
				playerRulesDraft = PlayerResourceRules.Vanilla;
				playerRulesDraftDirty = true;
				controlsDirty = true;
			});
			Label(parent, 590f, 364f, 740f, PR("1.00× = Vanilla · 0.50× = half · 0.00× = free / no gain · 2.00× = double. ", "1,00× = Vanilla · 0,50× = Hälfte · 0,00× = kostenlos / kein Gewinn · 2,00× = doppelt. ") + resetWhat, 13);
			refresh.Add(delegate
			{
				((Selectable)apply).interactable = CanEdit && playerRulesSynced && playerRulesDraftDirty;
			});
		}

		private void BuildStaminaRules(Transform parent)
		{
			Label(parent, 6f, 0f, 1320f, PR("Stamina consumption", "Ausdauerverbrauch"), 19, 26f);
			float x = 0f;
			float x2 = 675f;
			float width = 650f;
			float num = 34f;
			float num2 = 47f;
			PlayerRuleSlider(parent, x, num, width, PR("Run", "Rennen"), () => playerRulesDraft.Run, delegate(float v)
			{
				playerRulesDraft.Run = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Jump", "Springen"), () => playerRulesDraft.Jump, delegate(float v)
			{
				playerRulesDraft.Jump = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Dodge roll", "Ausweichen / Rollen"), () => playerRulesDraft.Dodge, delegate(float v)
			{
				playerRulesDraft.Dodge = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Swim", "Schwimmen"), () => playerRulesDraft.Swim, delegate(float v)
			{
				playerRulesDraft.Swim = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Sneak", "Schleichen"), () => playerRulesDraft.Sneak, delegate(float v)
			{
				playerRulesDraft.Sneak = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Encumbered", "Überladen"), () => playerRulesDraft.Encumbered, delegate(float v)
			{
				playerRulesDraft.Encumbered = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Block", "Blocken"), () => playerRulesDraft.Block, delegate(float v)
			{
				playerRulesDraft.Block = v;
			});
			num = 34f;
			PlayerRuleSlider(parent, x2, num, width, PR("Primary attack", "Primärangriff"), () => playerRulesDraft.PrimaryStamina, delegate(float v)
			{
				playerRulesDraft.PrimaryStamina = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Secondary attack", "Sekundärangriff"), () => playerRulesDraft.SecondaryStamina, delegate(float v)
			{
				playerRulesDraft.SecondaryStamina = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Draw / charge", "Spannen / Aufladen"), () => playerRulesDraft.DrawStamina, delegate(float v)
			{
				playerRulesDraft.DrawStamina = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Reload", "Nachladen"), () => playerRulesDraft.ReloadStamina, delegate(float v)
			{
				playerRulesDraft.ReloadStamina = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Building / home tools", "Bauen / Heimwerkzeuge"), () => playerRulesDraft.HomeStamina, delegate(float v)
			{
				playerRulesDraft.HomeStamina = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Grappling", "Grappling"), () => playerRulesDraft.Grapple, delegate(float v)
			{
				playerRulesDraft.Grapple = v;
			});
			PlayerRuleFooter(parent, PR("Movement and attack values are independent.", "Bewegungs- und Angriffswerte sind unabhängig."));
		}

		private void BuildEitrRules(Transform parent)
		{
			Label(parent, 6f, 0f, 1320f, PR("Eitr consumption", "Eitr-Verbrauch"), 19, 26f);
			float x = 0f;
			float x2 = 675f;
			float width = 650f;
			float num = 48f;
			float num2 = 68f;
			PlayerRuleSlider(parent, x, num, width, PR("Primary attack / spell", "Primärangriff / Zauber"), () => playerRulesDraft.PrimaryEitr, delegate(float v)
			{
				playerRulesDraft.PrimaryEitr = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Secondary attack / spell", "Sekundärangriff / Zauber"), () => playerRulesDraft.SecondaryEitr, delegate(float v)
			{
				playerRulesDraft.SecondaryEitr = v;
			});
			num = 48f;
			PlayerRuleSlider(parent, x2, num, width, PR("Draw / channel", "Spannen / Kanalisieren"), () => playerRulesDraft.DrawEitr, delegate(float v)
			{
				playerRulesDraft.DrawEitr = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Reload / repeated cast", "Nachladen / Wiederholung"), () => playerRulesDraft.ReloadEitr, delegate(float v)
			{
				playerRulesDraft.ReloadEitr = v;
			});
			Label(parent, 6f, 212f, 1320f, PR("These multiply the Eitr values stored on the actual vanilla attack. Modded attacks using the same Valheim fields are covered too.", "Diese Werte multiplizieren die Eitr-Kosten des tatsächlichen Valheim-Angriffs. Mod-Angriffe mit denselben Vanilla-Feldern werden ebenfalls erfasst."), 14, 60f);
			PlayerRuleFooter(parent, "");
		}

		private void BuildAdrenalineRules(Transform parent)
		{
			Label(parent, 6f, 0f, 1320f, PR("Adrenaline gain / loss", "Adrenalin-Gewinn / Verlust"), 19, 26f);
			float x = 0f;
			float x2 = 675f;
			float width = 650f;
			float num = 34f;
			float num2 = 54f;
			PlayerRuleSlider(parent, x, num, width, PR("Primary attack", "Primärangriff"), () => playerRulesDraft.PrimaryAdrenaline, delegate(float v)
			{
				playerRulesDraft.PrimaryAdrenaline = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Secondary attack", "Sekundärangriff"), () => playerRulesDraft.SecondaryAdrenaline, delegate(float v)
			{
				playerRulesDraft.SecondaryAdrenaline = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Projectile hit", "Projektiltreffer"), () => playerRulesDraft.ProjectileAdrenaline, delegate(float v)
			{
				playerRulesDraft.ProjectileAdrenaline = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Block", "Blocken"), () => playerRulesDraft.BlockAdrenaline, delegate(float v)
			{
				playerRulesDraft.BlockAdrenaline = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x, num, width, PR("Perfect block / parry", "Perfekter Block / Parieren"), () => playerRulesDraft.ParryAdrenaline, delegate(float v)
			{
				playerRulesDraft.ParryAdrenaline = v;
			});
			num = 34f;
			PlayerRuleSlider(parent, x2, num, width, PR("Perfect dodge", "Perfektes Ausweichen"), () => playerRulesDraft.PerfectDodgeAdrenaline, delegate(float v)
			{
				playerRulesDraft.PerfectDodgeAdrenaline = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Stagger enemy", "Gegner taumeln lassen"), () => playerRulesDraft.StaggerAdrenaline, delegate(float v)
			{
				playerRulesDraft.StaggerAdrenaline = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Miss penalty", "Fehlschlag-Verlust"), () => playerRulesDraft.MissAdrenaline, delegate(float v)
			{
				playerRulesDraft.MissAdrenaline = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Unblocked damage penalty", "Ungeblockter Schaden-Verlust"), () => playerRulesDraft.DamageAdrenaline, delegate(float v)
			{
				playerRulesDraft.DamageAdrenaline = v;
			});
			num += num2;
			PlayerRuleSlider(parent, x2, num, width, PR("Guardian power gain", "Bosskraft-Gewinn"), () => playerRulesDraft.GuardianAdrenaline, delegate(float v)
			{
				playerRulesDraft.GuardianAdrenaline = v;
			});
			PlayerRuleFooter(parent, PR("Negative vanilla adrenaline values stay negative; the slider scales their size.", "Negative Vanilla-Adrenalinwerte bleiben negativ; der Regler skaliert ihre Stärke."));
		}

		private void EnsurePlayerVitalsConfig()
		{
			if (!playerVitalsConfigReady)
			{
				playerVitalsConfigReady = true;
				playerVitalsStored = ((BaseUnityPlugin)this).Config.Bind<string>("Server - Player Vitals", "State", "", "Written by the World Control server. Server-authoritative health, stamina, eitr, stamina regeneration and eitr regeneration multipliers.");
			}
		}

		private static bool ValidVitalMax(float value)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value) && value >= 0.1f)
			{
				return value <= 3f;
			}
			return false;
		}

		private static bool ValidVitalRegen(float value)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value) && value >= 0f)
			{
				return value <= 3f;
			}
			return false;
		}

		private static bool ValidPlayerVitals(PlayerVitalRules rules)
		{
			if (ValidVitalMax(rules.MaxHealth) && ValidVitalMax(rules.MaxStamina) && ValidVitalMax(rules.MaxEitr) && ValidVitalRegen(rules.StaminaRegen))
			{
				return ValidVitalRegen(rules.EitrRegen);
			}
			return false;
		}

		private static void WritePlayerVitals(BinaryWriter writer, PlayerVitalRules rules)
		{
			writer.Write(rules.MaxHealth);
			writer.Write(rules.MaxStamina);
			writer.Write(rules.MaxEitr);
			writer.Write(rules.StaminaRegen);
			writer.Write(rules.EitrRegen);
		}

		private static PlayerVitalRules ReadPlayerVitals(BinaryReader reader, int version)
		{
			return new PlayerVitalRules
			{
				MaxHealth = reader.ReadSingle(),
				MaxStamina = reader.ReadSingle(),
				MaxEitr = reader.ReadSingle(),
				StaminaRegen = reader.ReadSingle(),
				EitrRegen = ((version >= 2) ? reader.ReadSingle() : 1f)
			};
		}

		private static byte[] EncodePlayerVitalsRequest(bool apply, PlayerVitalRules rules)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(2);
			binaryWriter.Write(apply ? ((byte)1) : ((byte)0));
			if (apply)
			{
				WritePlayerVitals(binaryWriter, rules);
			}
			return memoryStream.ToArray();
		}

		private static bool DecodePlayerVitalsRequest(byte[] bytes, out bool apply, out PlayerVitalRules rules)
		{
			apply = false;
			rules = PlayerVitalRules.Vanilla;
			if (bytes == null || bytes.Length > 96)
			{
				return false;
			}
			try
			{
				using BinaryReader binaryReader = new BinaryReader(new MemoryStream(bytes));
				int num = binaryReader.ReadInt32();
				if (num < 1 || num > 2)
				{
					return false;
				}
				byte b = binaryReader.ReadByte();
				if (b > 1)
				{
					return false;
				}
				apply = b == 1;
				if (apply)
				{
					rules = ReadPlayerVitals(binaryReader, num);
				}
				return binaryReader.BaseStream.Position == binaryReader.BaseStream.Length && (!apply || ValidPlayerVitals(rules));
			}
			catch (Exception ex) when (ex is IOException || ex is EndOfStreamException || ex is ArgumentException)
			{
				return false;
			}
		}

		private static byte[] EncodePlayerVitalsState(long revision, PlayerVitalRules rules)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(2);
			binaryWriter.Write(revision);
			WritePlayerVitals(binaryWriter, rules);
			return memoryStream.ToArray();
		}

		private static bool DecodePlayerVitalsState(byte[] bytes, out long revision, out PlayerVitalRules rules)
		{
			revision = 0L;
			rules = PlayerVitalRules.Vanilla;
			if (bytes == null || bytes.Length > 96)
			{
				return false;
			}
			try
			{
				using BinaryReader binaryReader = new BinaryReader(new MemoryStream(bytes));
				int num = binaryReader.ReadInt32();
				if (num < 1 || num > 2)
				{
					return false;
				}
				revision = binaryReader.ReadInt64();
				rules = ReadPlayerVitals(binaryReader, num);
				return binaryReader.BaseStream.Position == binaryReader.BaseStream.Length && revision >= 0 && ValidPlayerVitals(rules);
			}
			catch (Exception ex) when (ex is IOException || ex is EndOfStreamException || ex is ArgumentException)
			{
				return false;
			}
		}

		private void LoadPlayerVitals()
		{
			EnsurePlayerVitalsConfig();
			playerVitals = PlayerVitalRules.Vanilla;
			playerVitalsRevision = 1L;
			string text = ((playerVitalsStored != null) ? playerVitalsStored.Value : "");
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			try
			{
				if (DecodePlayerVitalsState(Convert.FromBase64String(text), out var revision, out var rules))
				{
					playerVitals = rules;
					playerVitalsRevision = Math.Max(1L, revision);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not read stored player vitals: " + ex.Message));
			}
		}

		private void SavePlayerVitals()
		{
			EnsurePlayerVitalsConfig();
			if (playerVitalsStored != null)
			{
				playerVitalsStored.Value = Convert.ToBase64String(EncodePlayerVitalsState(playerVitalsRevision, playerVitals));
			}
		}

		private void ResetPlayerVitalsNetwork()
		{
			foreach (ZRpc item in playerVitalsRegistered)
			{
				try
				{
					item.Unregister("DezzyCode.WorldControl.PlayerVitals.Request.v1");
					item.Unregister("DezzyCode.WorldControl.PlayerVitals.State.v1");
				}
				catch
				{
				}
			}
			playerVitalsRegistered.Clear();
			playerVitalsRequests.Clear();
			playerVitalsEdits.Clear();
			playerVitalsNetwork = network;
			playerVitalsLoadedForServer = false;
			nextPlayerVitalsQuery = 0f;
			nextPlayerVitalsMaintenance = 0f;
			playerVitalsSynced = session != null && session.Server;
			playerVitalsRevision = 0L;
			if (session == null || !session.Server)
			{
				playerVitals = PlayerVitalRules.Vanilla;
			}
			playerVitalsDraft = playerVitals;
			playerVitalsDraftDirty = false;
			RestorePlayerVitalsLocal();
		}

		private void PlayerVitalsTick()
		{
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Expected O, but got Unknown
			EnsurePlayerVitalsConfig();
			if (playerVitalsNetwork != network)
			{
				ResetPlayerVitalsNetwork();
			}
			if ((Object)(object)network == (Object)null || session == null)
			{
				return;
			}
			if (session.Server && !playerVitalsLoadedForServer)
			{
				playerVitalsLoadedForServer = true;
				LoadPlayerVitals();
				playerVitalsSynced = true;
				playerVitalsDraft = playerVitals;
				playerVitalsAppliedRevision = -1L;
			}
			if (playerVitalsSynced)
			{
				ApplyPlayerVitalsLocal();
			}
			if (Time.unscaledTime < nextPlayerVitalsMaintenance)
			{
				return;
			}
			nextPlayerVitalsMaintenance = Time.unscaledTime + 0.25f;
			foreach (ZNetPeer peer in network.GetPeers())
			{
				if (peer != null && peer.m_rpc != null && playerVitalsRegistered.Add(peer.m_rpc))
				{
					peer.m_rpc.Register<ZPackage>("DezzyCode.WorldControl.PlayerVitals.Request.v1", (Action<ZRpc, ZPackage>)OnPlayerVitalsRequest);
					peer.m_rpc.Register<ZPackage>("DezzyCode.WorldControl.PlayerVitals.State.v1", (Action<ZRpc, ZPackage>)OnPlayerVitalsState);
					if (session.Server && peer.IsReady() && peer.m_rpc.IsConnected())
					{
						SendPlayerVitalsState(peer.m_rpc);
					}
				}
			}
			playerVitalsStale.Clear();
			foreach (ZRpc item in playerVitalsRegistered)
			{
				if (item == null || !item.IsConnected())
				{
					playerVitalsStale.Add(item);
				}
			}
			foreach (ZRpc item2 in playerVitalsStale)
			{
				playerVitalsRegistered.Remove(item2);
				playerVitalsRequests.Remove(item2);
				playerVitalsEdits.Remove(item2);
				try
				{
					item2.Unregister("DezzyCode.WorldControl.PlayerVitals.Request.v1");
					item2.Unregister("DezzyCode.WorldControl.PlayerVitals.State.v1");
				}
				catch
				{
				}
			}
			if (!session.Server && !playerVitalsSynced && Time.unscaledTime >= nextPlayerVitalsQuery)
			{
				ZNetPeer serverPeer = network.GetServerPeer();
				if (serverPeer != null && serverPeer.IsReady() && serverPeer.m_rpc != null && serverPeer.m_rpc.IsConnected())
				{
					nextPlayerVitalsQuery = Time.unscaledTime + 1f;
					serverPeer.m_rpc.Invoke("DezzyCode.WorldControl.PlayerVitals.Request.v1", new object[1] { (object)new ZPackage(EncodePlayerVitalsRequest(apply: false, PlayerVitalRules.Vanilla)) });
				}
			}
		}

		private void OnPlayerVitalsRequest(ZRpc rpc, ZPackage package)
		{
			ZNetPeer val = ReadyPeer(rpc);
			if (session == null || !session.Server || rpc == null || val == null || package == null || package.Size() > 96 || !DecodePlayerVitalsRequest(package.GetArray(), out var apply, out var rules))
			{
				return;
			}
			Dictionary<ZRpc, float> dictionary = (apply ? playerVitalsEdits : playerVitalsRequests);
			if (!dictionary.TryGetValue(rpc, out var value) || !(Time.unscaledTime < value))
			{
				dictionary[rpc] = Time.unscaledTime + (apply ? 0.35f : 0.75f);
				if (apply && IsAdmin(rpc))
				{
					playerVitals = rules;
					playerVitalsRevision = Math.Max(1L, playerVitalsRevision + 1);
					playerVitalsAppliedRevision = -1L;
					SavePlayerVitals();
					playerVitalsDraft = playerVitals;
					playerVitalsDraftDirty = false;
					BroadcastPlayerVitals();
					controlsDirty = true;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Player vital rules changed by admin " + val.m_playerName + "."));
				}
				else
				{
					SendPlayerVitalsState(rpc);
				}
			}
		}

		private void OnPlayerVitalsState(ZRpc rpc, ZPackage package)
		{
			if (session != null && !session.Server && rpc != null && package != null && package.Size() <= 96 && serverConnection != null && rpc == serverConnection && DecodePlayerVitalsState(package.GetArray(), out var revision, out var rules) && (!playerVitalsSynced || revision >= playerVitalsRevision))
			{
				playerVitalsRevision = revision;
				playerVitals = rules;
				playerVitalsSynced = true;
				playerVitalsAppliedRevision = -1L;
				if (!playerVitalsDraftDirty)
				{
					playerVitalsDraft = rules;
				}
				ApplyPlayerVitalsLocal();
				controlsDirty = true;
			}
		}

		private void SendPlayerVitalsState(ZRpc rpc)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if (rpc != null && rpc.IsConnected())
			{
				rpc.Invoke("DezzyCode.WorldControl.PlayerVitals.State.v1", new object[1] { (object)new ZPackage(EncodePlayerVitalsState(playerVitalsRevision, playerVitals)) });
			}
		}

		private void BroadcastPlayerVitals()
		{
			foreach (ZNetPeer peer in network.GetPeers())
			{
				if (peer != null && peer.IsReady() && peer.m_rpc != null && peer.m_rpc.IsConnected() && playerVitalsRegistered.Contains(peer.m_rpc))
				{
					SendPlayerVitalsState(peer.m_rpc);
				}
			}
			ApplyPlayerVitalsLocal();
		}

		private void SubmitPlayerVitals()
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			if (!playerVitalsDraftDirty || !CanEdit || !playerVitalsSynced || !ValidPlayerVitals(playerVitalsDraft))
			{
				return;
			}
			if (session != null && session.Server)
			{
				playerVitals = playerVitalsDraft;
				playerVitalsRevision = Math.Max(1L, playerVitalsRevision + 1);
				playerVitalsAppliedRevision = -1L;
				playerVitalsDraftDirty = false;
				SavePlayerVitals();
				BroadcastPlayerVitals();
				c