Decompiled source of ValheimRaces v2.9.1

ValheimRaces.dll

Decompiled 13 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("ValheimRaces")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ValheimRaces")]
[assembly: AssemblyTitle("ValheimRaces")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("valheim.races", "Valheim Races", "2.9.1")]
public class ValheimRacesPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	private static class RegisterAltarPrefabInZNetScenePatch
	{
		private static void Postfix(ZNetScene __instance)
		{
			if (!((Object)(object)Instance == (Object)null) && !((Object)(object)AltarPrefab == (Object)null) && !((Object)(object)__instance == (Object)null) && !__instance.m_prefabs.Contains(AltarPrefab))
			{
				__instance.m_prefabs.Add(AltarPrefab);
				if (ZNetSceneNamedPrefabsField?.GetValue(__instance) is Dictionary<int, GameObject> dictionary)
				{
					dictionary[StringExtensionMethods.GetStableHashCode(((Object)AltarPrefab).name)] = AltarPrefab;
				}
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[ValheimRaces] 'altar_racas' registrado no ZNetScene.");
			}
		}
	}

	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	private static class RegisterAltarPieceInHammerPatch
	{
		private static void Postfix(ObjectDB __instance)
		{
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			if ((Object)(object)Instance == (Object)null || (Object)(object)AltarPrefab == (Object)null || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			Piece component = AltarPrefab.GetComponent<Piece>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			component.m_resources = ParseAltarRecipe(__instance, AltarRecipe?.Value ?? "Wood:10,Stone:5");
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("piece_workbench") : null);
			component.m_craftingStation = (((Object)(object)val != (Object)null) ? val.GetComponent<CraftingStation>() : null);
			if ((Object)(object)component.m_craftingStation == (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)"[ValheimRaces] Não achei a Bancada de Trabalho ('piece_workbench') — Altar ficará sem estação exigida.");
			}
			Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_placeEffect.m_effectPrefabs != null)
			{
				component.m_placeEffect = val2.m_placeEffect;
			}
			else
			{
				component.m_placeEffect = new EffectList();
			}
			GameObject itemPrefab = __instance.GetItemPrefab("Hammer");
			ItemDrop val3 = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			PieceTable val4 = ((!((Object)(object)val3 != (Object)null)) ? null : val3.m_itemData?.m_shared?.m_buildPieces);
			if ((Object)(object)val4 == (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)"[ValheimRaces] Não achei a tabela de peças do Martelo — Altar não vai aparecer no menu de construção.");
				return;
			}
			if (!val4.m_pieces.Contains(AltarPrefab))
			{
				val4.m_pieces.Add(AltarPrefab);
			}
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[ValheimRaces] Peça 'Altar das Raças' registrada na tabela do Martelo.");
		}
	}

	[HarmonyPatch(typeof(FejdStartup), "SetupCharacterPreview")]
	private static class FejdCharacterPreviewPatch
	{
		private static void Postfix(FejdStartup __instance, PlayerProfile profile)
		{
			try
			{
				ApplyPreviewRace(__instance, profile);
			}
			catch (Exception arg)
			{
				ValheimRacesPlugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogWarning((object)$"Falha ao aplicar raça no preview do menu: {arg}");
				}
			}
			try
			{
				if (string.IsNullOrEmpty((profile != null) ? profile.GetName() : null))
				{
					FejdRaceSelectorUI.EnsureVisible(__instance);
				}
				else
				{
					FejdRaceSelectorUI.Hide();
				}
			}
			catch (Exception arg2)
			{
				ValheimRacesPlugin instance2 = Instance;
				if (instance2 != null)
				{
					((BaseUnityPlugin)instance2).Logger.LogWarning((object)$"Falha ao mostrar/esconder o seletor de raça do menu: {arg2}");
				}
			}
		}
	}

	[HarmonyPatch(typeof(VisEquipment), "SetSkinColor")]
	private static class ForcePreviewSkinColorPatch
	{
		private static void Prefix(VisEquipment __instance, ref Vector3 __0)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && _previewSkinForced && !string.IsNullOrWhiteSpace(_sessionSelectedPreviewRace))
			{
				Player component = ((Component)__instance).GetComponent<Player>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component != (Object)(object)_cachedPreviewPlayerInstance))
				{
					__0 = BlendRaceHueWithBrightness(GetRaceSkinColor(_sessionSelectedPreviewRace), __0);
				}
			}
		}

		private static void Postfix(VisEquipment __instance)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || string.IsNullOrWhiteSpace(_sessionSelectedPreviewRace))
			{
				return;
			}
			Player component = ((Component)__instance).GetComponent<Player>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component != (Object)(object)_cachedPreviewPlayerInstance))
			{
				Color c = ToColor(GetRaceEarColorForPreview(component, _sessionSelectedPreviewRace));
				Transform val = ((Component)component).transform.Find("Ears");
				if ((Object)(object)val != (Object)null)
				{
					Instance.FixEarMaterials(val, forceStandardShader: false);
					Instance.ApplyColor(val, c);
				}
				Transform val2 = ((Component)component).transform.Find("OrcEars");
				if ((Object)(object)val2 != (Object)null)
				{
					Instance.FixEarMaterials(val2, forceStandardShader: false);
					Instance.ApplyColor(val2, c);
				}
			}
		}
	}

	[HarmonyPatch(typeof(Player), "OnSpawned")]
	private static class PlayerSpawnedPatch
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)Instance == (Object)null)
			{
				return;
			}
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Instance.RestoreLocalSavedRaceIfNeeded();
				SendVersionCheckToServer();
			}
			if (IsPlayerLocked(__instance))
			{
				SetZdoLocked(__instance, locked: true);
			}
			Instance.ApplyRaceWithDelays(__instance);
			if (!IsHeadless())
			{
				string race = GetRace(__instance);
				if (!string.IsNullOrWhiteSpace(race))
				{
					UpdateRaceStatusEffect(__instance, race);
				}
			}
		}
	}

	[HarmonyPatch(typeof(Player), "OnDeath")]
	private static class PlayerDeathPatch
	{
		private static void Prefix(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Instance == (Object)null) && !IsHeadless())
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)$"[ValheimRaces/Diag] OnDeath disparou pra '{__instance.GetPlayerName()}' (isLocal={(Object)(object)__instance == (Object)(object)Player.m_localPlayer}).");
				RemovePlayerAttachment(__instance, "JotunFreeze");
			}
		}

		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Instance == (Object)null) && !IsHeadless())
			{
				Instance.ApplyRaceWithDelays(__instance);
				string race = GetRace(__instance);
				if (!string.IsNullOrWhiteSpace(race))
				{
					UpdateRaceStatusEffect(__instance, race);
				}
			}
		}
	}

	[HarmonyPatch(typeof(Player), "CreateDeathEffects")]
	private static class PlayerRagdollRacePatch
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)Instance == (Object)null || IsHeadless() || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			Ragdoll ragdoll = __instance.GetRagdoll();
			if ((Object)(object)ragdoll == (Object)null)
			{
				return;
			}
			string race = GetRace(__instance);
			if (string.IsNullOrWhiteSpace(race) || !IsRaceEnabled(race))
			{
				return;
			}
			try
			{
				ZNetView component = ((Component)ragdoll).GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.GetZDO() != null)
				{
					component.GetZDO().Set("ValheimRagdollRace", race);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("[ValheimRaces] Falha ao gravar raça no ZDO do ragdoll: " + ex.Message));
			}
			ApplyRaceVisualToRagdoll(ragdoll, race);
		}
	}

	[HarmonyPatch(typeof(Ragdoll), "Awake")]
	private static class RagdollAwakePatch
	{
		private static void Postfix(Ragdoll __instance)
		{
			if ((Object)(object)Instance == (Object)null || IsHeadless() || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.GetZDO() != null)
				{
					string text = component.GetZDO().GetString("ValheimRagdollRace", "");
					if (!string.IsNullOrWhiteSpace(text) && IsRaceEnabled(text))
					{
						ApplyRaceVisualToRagdoll(__instance, text);
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("[ValheimRaces] Falha ao ler raça do ZDO do ragdoll: " + ex.Message));
			}
		}
	}

	[HarmonyPatch(typeof(ZNet), "Disconnect")]
	private static class ZNetDisconnectPatch
	{
		private static void Prefix(ZNetPeer peer)
		{
			if (peer == null)
			{
				return;
			}
			try
			{
				OnPeerDisconnected(peer.m_uid);
			}
			catch
			{
			}
		}
	}

	[HarmonyPatch(typeof(ZNet), "Shutdown")]
	private static class ZNetShutdownPatch
	{
		private static void Prefix()
		{
			NetworkRaces.Clear();
			LastAppliedRace.Clear();
			OriginalSkinColors.Clear();
			LastSkinRefreshRequest.Clear();
			KnownAdmins.Clear();
			HeadCache.Clear();
			HeadCacheRace.Clear();
			ApplyRaceCoroutineGeneration.Clear();
			ZNetViewCache.Clear();
			_cachedSavePrefix = null;
			_cachedZNetInstance = null;
			_cachedCharacterId = 0L;
			_cachedServerKey = null;
			RpcRegistered = false;
			RegisteredRpcInstance = null;
			if ((Object)(object)Instance != (Object)null)
			{
				Instance.lastBroadcastRace = null;
				Instance.isRestoringLocalRace = false;
			}
		}
	}

	[HarmonyPatch(typeof(VisEquipment), "SetHelmetItem")]
	private static class HelmetScaleOnEquipPatch
	{
		private static void Postfix(VisEquipment __instance)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && !IsHeadless())
			{
				Player component = ((Component)__instance).GetComponent<Player>();
				if (!((Object)(object)component == (Object)null))
				{
					string race = GetRace(component);
					Vector3 targetScale = ((!string.IsNullOrWhiteSpace(race) && IsRaceEnabled(race)) ? GetRaceScale(race) : HumanScale);
					ScaleCurrentHelmetForRace(component, targetScale);
				}
			}
		}
	}

	[HarmonyPatch(typeof(VisEquipment), "SetHairColor")]
	private static class ForceRaceHairColorPatch
	{
		private static void Prefix(VisEquipment __instance, ref Vector3 __0)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || IsApplyingRace)
			{
				return;
			}
			Player component = ((Component)__instance).GetComponent<Player>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)((Component)component).GetComponent<ZNetView>() == (Object)null))
			{
				string race = GetRace(component);
				if (RaceUsesForcedHair(race))
				{
					__0 = GetRaceHairColor(race);
				}
			}
		}
	}

	[HarmonyPatch(typeof(VisEquipment), "SetSkinColor")]
	private static class PreventForcedRaceSkinOverridePatch
	{
		private static bool Prefix(VisEquipment __instance, Vector3 __0)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || IsApplyingRace)
			{
				return true;
			}
			Player component = ((Component)__instance).GetComponent<Player>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			if ((Object)(object)((Component)component).GetComponent<ZNetView>() == (Object)null)
			{
				return true;
			}
			string race = GetRace(component);
			if (!RaceUsesForcedSkin(race))
			{
				return true;
			}
			CacheOriginalSkinValue(component, __0);
			if ((Object)(object)Instance != (Object)null)
			{
				Instance.ForceSkinAfterVanilla(component, race);
			}
			return false;
		}
	}

	[HarmonyPatch]
	private static class VisEquipmentOnlineRefreshPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			string[] names = new string[9] { "UpdateEquipmentVisuals", "UpdateVisuals", "SetChestItem", "SetLegItem", "SetHelmetItem", "SetShoulderItem", "SetUtilityItem", "SetLeftItem", "SetRightItem" };
			string[] array = names;
			foreach (string name in array)
			{
				MethodInfo method = AccessTools.Method(typeof(VisEquipment), name, (Type[])null, (Type[])null);
				if (method != null)
				{
					yield return method;
				}
			}
		}

		private static void Postfix(VisEquipment __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Instance == (Object)null) && !IsApplyingRace && !IsHeadless())
			{
				Instance.ForceSkinAfterVanilla(__instance);
			}
		}
	}

	[HarmonyPatch]
	private static class PlayerOnlineRefreshPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			string[] names = new string[2] { "UpdateEquipment", "OnInventoryChanged" };
			string[] array = names;
			foreach (string name in array)
			{
				MethodInfo method = AccessTools.Method(typeof(Player), name, (Type[])null, (Type[])null);
				if (method != null)
				{
					yield return method;
				}
			}
		}

		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Instance == (Object)null) && !IsApplyingRace && !IsHeadless())
			{
				Instance.RequestOnlineVisualRefresh(__instance);
			}
		}
	}

	[HarmonyPatch(typeof(Character), "SetVisible")]
	private static class CharacterSetVisiblePatch
	{
		private static void Postfix(Character __instance, bool visible)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if (!visible || (Object)(object)__instance == (Object)null || (Object)(object)Instance == (Object)null || IsHeadless())
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (!((Object)(object)val == (Object)null))
			{
				string race = GetRace(val);
				if (!string.IsNullOrWhiteSpace(race) && IsRaceEnabled(race))
				{
					ApplyScale(val, GetRaceScale(race));
				}
			}
		}
	}

	[HarmonyPatch(typeof(Chat), "InputText")]
	private static class ChatPatch
	{
		private static bool Prefix(Chat __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			string text = "";
			try
			{
				FieldInfo field = typeof(Chat).GetField("m_input", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					return true;
				}
				object value = field.GetValue(__instance);
				if (value == null)
				{
					return true;
				}
				text = (value.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value) as string)?.Trim() ?? "";
			}
			catch
			{
				return true;
			}
			string raceFromSecretCode = GetRaceFromSecretCode(text);
			if (raceFromSecretCode == null)
			{
				return true;
			}
			TransformLocalPlayerFromMarketplace(raceFromSecretCode);
			try
			{
				object obj2 = typeof(Chat).GetField("m_input", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(__instance);
				PropertyInfo propertyInfo = obj2?.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public);
				if (propertyInfo != null && propertyInfo.CanWrite)
				{
					propertyInfo.SetValue(obj2, "");
				}
			}
			catch
			{
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(Character), "UpdateLayer")]
	private static class FixNullColliderInUpdateLayerPatch
	{
		private static readonly FieldInfo ColliderField = AccessTools.Field(typeof(Character), "m_collider");

		private static bool Prefix(Character __instance)
		{
			if (ColliderField == null || (Object)(object)__instance == (Object)null)
			{
				return true;
			}
			object? value = ColliderField.GetValue(__instance);
			Object val = (Object)((value is Object) ? value : null);
			if (val != (Object)null)
			{
				return true;
			}
			Collider component = ((Component)__instance).GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				ColliderField.SetValue(__instance, component);
				return true;
			}
			return false;
		}
	}

	private sealed class ShaderWarningFilterLogHandler : ILogHandler
	{
		private readonly ILogHandler _original;

		public ShaderWarningFilterLogHandler(ILogHandler original)
		{
			_original = original;
		}

		public void LogFormat(LogType logType, Object context, string format, params object[] args)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if ((int)logType != 2 || !ShouldSuppress(format, args))
			{
				_original.LogFormat(logType, context, format, args);
			}
		}

		public void LogException(Exception exception, Object context)
		{
			_original.LogException(exception, context);
		}

		private static bool ShouldSuppress(string format, object[] args)
		{
			try
			{
				if (!string.IsNullOrEmpty(format))
				{
					string[] suppressedLogSubstrings = SuppressedLogSubstrings;
					foreach (string value in suppressedLogSubstrings)
					{
						if (format.Contains(value))
						{
							return true;
						}
					}
				}
				if (args != null)
				{
					foreach (object obj in args)
					{
						if (!(obj is string text))
						{
							continue;
						}
						string[] suppressedLogSubstrings2 = SuppressedLogSubstrings;
						foreach (string value2 in suppressedLogSubstrings2)
						{
							if (text.Contains(value2))
							{
								return true;
							}
						}
					}
				}
			}
			catch
			{
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(BaseAI), "CanSenseTarget", new Type[] { typeof(Character) })]
	private static class RaceCrouchStealthSensePatch
	{
		private static void Postfix(Character target, ref bool __result)
		{
			if (__result && IsCrouchStealthed(target))
			{
				__result = false;
			}
		}
	}

	[HarmonyPatch(typeof(BaseAI), "CanSeeTarget", new Type[] { typeof(Character) })]
	private static class RaceCrouchStealthSeePatch
	{
		private static void Postfix(Character target, ref bool __result)
		{
			if (__result && IsCrouchStealthed(target))
			{
				__result = false;
			}
		}
	}

	[HarmonyPatch(typeof(BaseAI), "CanHearTarget", new Type[] { typeof(Character) })]
	private static class RaceCrouchStealthHearPatch
	{
		private static void Postfix(Character target, ref bool __result)
		{
			if (__result && IsCrouchStealthed(target))
			{
				__result = false;
			}
		}
	}

	[HarmonyPatch(typeof(Character), "UpdateGroundContact")]
	private static class RaceTremorPatch
	{
		private static void Postfix(Character __instance, float dt)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val == (Object)null || !RacialAbilitiesEnabled.Value || !TryGetRaceConfig(val, out var cfg) || !cfg.TremorEnabled.Value)
			{
				return;
			}
			string visualKey = GetVisualKey(val);
			if (string.IsNullOrWhiteSpace(visualKey))
			{
				return;
			}
			bool flag = ((Character)val).IsOnGround();
			TremorWasOnGround.TryGetValue(visualKey, out var value);
			TremorAirTime.TryGetValue(visualKey, out var value2);
			if (!flag)
			{
				TremorAirTime[visualKey] = value2 + dt;
				TremorWasOnGround[visualKey] = false;
				return;
			}
			if (!value && value2 >= cfg.TremorMinAirTime.Value)
			{
				DoTremor(val, cfg);
			}
			TremorAirTime[visualKey] = 0f;
			TremorWasOnGround[visualKey] = true;
		}
	}

	[HarmonyPatch(typeof(Player), "SetMaxHealth")]
	private static class RaceMaxHealthPatch
	{
		private static Dictionary<Biome, float> ParseBiomeShifts(string value)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<Biome, float> dictionary = new Dictionary<Biome, float>();
			if (string.IsNullOrWhiteSpace(value))
			{
				return dictionary;
			}
			string[] array = value.Split(new char[1] { ',' });
			foreach (string text in array)
			{
				string[] array2 = text.Split(new char[1] { ':' });
				if (array2.Length == 2 && Enum.TryParse<Biome>(array2[0].Trim(), ignoreCase: true, out Biome result) && float.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
				{
					dictionary[result] = result2;
				}
			}
			return dictionary;
		}

		private static void Prefix(Player __instance, ref float health)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetRaceConfig(__instance, out var cfg))
			{
				return;
			}
			health += cfg.HealthBonus.Value;
			if (cfg.DayNightHealthShift.Value != 0f)
			{
				health += (IsNightSafe() ? cfg.DayNightHealthShift.Value : (0f - cfg.DayNightHealthShift.Value));
			}
			if (!string.IsNullOrWhiteSpace(cfg.BiomeHealthShifts.Value))
			{
				try
				{
					Biome currentBiome = __instance.GetCurrentBiome();
					Dictionary<Biome, float> dictionary = ParseBiomeShifts(cfg.BiomeHealthShifts.Value);
					if (dictionary.TryGetValue(currentBiome, out var value))
					{
						health += value;
					}
				}
				catch (Exception ex)
				{
					ValheimRacesPlugin instance = Instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] Falha ao ler bioma atual pra oscilação de vida: " + ex.Message));
					}
				}
			}
			if (health < 10f)
			{
				health = 10f;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "SetMaxStamina")]
	private static class RaceMaxStaminaPatch
	{
		private static void Prefix(Player __instance, ref float stamina)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				stamina += cfg.StaminaBonus.Value;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "SetMaxEitr")]
	private static class RaceMaxEitrPatch
	{
		private static void Prefix(Player __instance, ref float eitr)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				eitr += cfg.EitrBonus.Value;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "GetMaxCarryWeight")]
	private static class RaceMaxCarryWeightPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				__result += cfg.CarryWeightBonus.Value;
			}
		}
	}

	[HarmonyPatch(typeof(Character), "Heal")]
	private static class RaceHealthRegenPatch
	{
		private static void Prefix(Character __instance, ref float hp)
		{
			if (!(hp <= 0f))
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe()))
				{
					hp *= cfg.HealthRegenMultiplier.Value;
				}
			}
		}
	}

	[HarmonyPatch(typeof(Character), "AddStamina")]
	private static class RaceStaminaRegenPatch
	{
		private static void Prefix(Character __instance, ref float v)
		{
			if (!(v <= 0f))
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe()))
				{
					v *= cfg.StaminaRegenMultiplier.Value;
				}
			}
		}
	}

	[HarmonyPatch(typeof(Character), "AddEitr")]
	private static class RaceEitrRegenPatch
	{
		private static void Prefix(Character __instance, ref float v)
		{
			if (!(v <= 0f))
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe()))
				{
					v *= cfg.EitrRegenMultiplier.Value;
				}
			}
		}
	}

	[HarmonyPatch(typeof(Player), "UseStamina")]
	private static class RaceNoStaminaCostPatch
	{
		private static void Prefix(Player __instance, ref float v)
		{
			if (TryGetRaceConfig(__instance, out var cfg) && cfg.NoResourceCost.Value)
			{
				v = 0f;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "UseEitr")]
	private static class RaceNoEitrCostPatch
	{
		private static void Prefix(Player __instance, ref float v)
		{
			if (TryGetRaceConfig(__instance, out var cfg) && cfg.NoResourceCost.Value)
			{
				v = 0f;
			}
		}
	}

	[HarmonyPatch(typeof(Character), "TryUseEitr")]
	private static class RaceNoEitrCostTryPatch
	{
		private static bool Prefix(Character __instance, ref bool __result)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val == (Object)null || !TryGetRaceConfig(val, out var cfg) || !cfg.NoResourceCost.Value)
			{
				return true;
			}
			__result = true;
			return false;
		}
	}

	[HarmonyPatch(typeof(Character), "GetJogSpeedFactor")]
	private static class ChilledJogSpeedPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			if (!((Object)(object)__instance == (Object)null) && ChilledStatus.TryGetValue(((Object)__instance).GetInstanceID(), out (float, float) value) && Time.time < value.Item1)
			{
				__result *= value.Item2;
			}
		}
	}

	[HarmonyPatch(typeof(Character), "GetRunSpeedFactor")]
	private static class ChilledRunSpeedPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			if (!((Object)(object)__instance == (Object)null) && ChilledStatus.TryGetValue(((Object)__instance).GetInstanceID(), out (float, float) value) && Time.time < value.Item1)
			{
				__result *= value.Item2;
			}
		}
	}

	[HarmonyPatch(typeof(Character), "Damage")]
	private static class OnHitElementalDamagePatch
	{
		private static void Prefix(HitData hit)
		{
			if (hit == null || RacialAbilitiesEnabled == null || !RacialAbilitiesEnabled.Value)
			{
				return;
			}
			Character attacker = hit.GetAttacker();
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if (val == null)
			{
				return;
			}
			string race = GetRace(val);
			if (!string.IsNullOrWhiteSpace(race) && Races.TryGetValue(race, out var value) && value.OnHitElementalEnabled.Value && !(value.OnHitElementalDamage.Value <= 0f))
			{
				if (value.BlockAuraIsFrost.Value)
				{
					hit.m_damage.m_frost += value.OnHitElementalDamage.Value;
				}
				else
				{
					hit.m_damage.m_fire += value.OnHitElementalDamage.Value;
				}
			}
		}
	}

	[HarmonyPatch(typeof(Character), "GetDamageModifier")]
	private static class RaceResistancePatch
	{
		private static void Postfix(Character __instance, DamageType damageType, ref DamageModifier __result)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected I4, but got Unknown
			if (__result)
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg))
			{
				Dictionary<DamageType, DamageModifier> dictionary = ParseResistances(cfg.Resistances.Value);
				if (dictionary.TryGetValue(damageType, out var value))
				{
					__result = (DamageModifier)(int)value;
				}
			}
		}
	}

	[HarmonyPatch(typeof(Character), "Damage")]
	private static class RaceDamagePatch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			if (hit == null)
			{
				return;
			}
			_ = hit.m_damage;
			if (false)
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val != (Object)null && TryGetRaceConfig(val, out var cfg))
			{
				if (cfg.DamageTakenMultiplier.Value != 1f)
				{
					ScaleDamage(ref hit.m_damage, cfg.DamageTakenMultiplier.Value);
				}
				if (RacialAbilitiesEnabled.Value && cfg.IronStanceEnabled.Value && cfg.IronStanceExtraDamageReduction.Value > 0f && ((Character)val).IsBlocking())
				{
					float totalDamage = hit.GetTotalDamage();
					ScaleDamage(ref hit.m_damage, 1f - cfg.IronStanceExtraDamageReduction.Value);
					hit.m_pushForce = 0f;
					AddEvolutionProgress(val, GetRace(val), totalDamage * cfg.IronStanceExtraDamageReduction.Value);
				}
			}
			Character attacker = hit.GetAttacker();
			Player val2 = (Player)(object)((attacker is Player) ? attacker : null);
			if (!((Object)(object)val2 != (Object)null) || !TryGetRaceConfig(val2, out var cfg2))
			{
				return;
			}
			string race = GetRace(val2);
			float num = cfg2.DamageDoneMultiplier.Value;
			Dictionary<SkillType, float> dictionary = ParseSkillMultipliers(cfg2.SkillDamageMultipliers.Value);
			if (dictionary.TryGetValue(hit.m_skill, out var value))
			{
				num *= value;
			}
			if (RacialAbilitiesEnabled.Value && cfg2.LowHealthThreshold.Value > 0f && ((Character)val2).GetMaxHealth() > 0f && ((Character)val2).GetHealth() / ((Character)val2).GetMaxHealth() <= cfg2.LowHealthThreshold.Value)
			{
				num *= cfg2.LowHealthDamageBonus.Value;
			}
			if (num != 1f)
			{
				ScaleDamage(ref hit.m_damage, num);
			}
			Dictionary<DamageType, float> dictionary2 = ParseTypeMultipliers(cfg2.AttackDamageTypeMultipliers.Value);
			if (dictionary2.Count > 0)
			{
				ScaleDamageByType(ref hit.m_damage, dictionary2);
			}
			if (cfg2.BackstabMultiplier.Value != 1f)
			{
				hit.m_backstabBonus *= cfg2.BackstabMultiplier.Value;
			}
			if (hit.m_backstabBonus > 1f)
			{
				AddEvolutionProgress(val2, race, 1f);
			}
			if (RacialAbilitiesEnabled.Value && cfg2.BackstabStaminaRefundChance.Value > 0f && hit.m_backstabBonus > 1f && Random.value < cfg2.BackstabStaminaRefundChance.Value)
			{
				((Character)val2).AddStamina(cfg2.BackstabStaminaRefundAmount.Value);
				AddEvolutionProgress(val2, race, 1f);
			}
			if (cfg2.KnockbackMultiplier.Value != 1f)
			{
				hit.m_pushForce *= cfg2.KnockbackMultiplier.Value;
			}
			if (cfg2.XpGainMultiplier.Value != 1f)
			{
				hit.m_skillRaiseAmount *= cfg2.XpGainMultiplier.Value;
			}
			if (cfg2.LifestealPercent.Value > 0f)
			{
				float totalDamage2 = hit.GetTotalDamage();
				if (totalDamage2 > 0f)
				{
					((Character)val2).Heal(totalDamage2 * cfg2.LifestealPercent.Value, false);
				}
			}
		}

		private static void Postfix(Character __instance, HitData hit)
		{
			if (hit == null || (Object)(object)__instance == (Object)null || !__instance.IsDead())
			{
				return;
			}
			Character attacker = hit.GetAttacker();
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg))
			{
				string race = GetRace(val);
				if (race == "orc")
				{
					AddEvolutionProgress(val, race, 1f);
				}
				if (race == "vampiro" && IsNightSafe())
				{
					AddEvolutionProgress(val, race, 1f);
				}
				if (RacialAbilitiesEnabled.Value && !(cfg.OnKillHealAmount.Value <= 0f) && (!cfg.OnKillHealNightOnly.Value || IsNightSafe()))
				{
					((Character)val).Heal(cfg.OnKillHealAmount.Value, false);
				}
			}
		}

		private static void ScaleDamageByType(ref DamageTypes dmg, Dictionary<DamageType, float> mults)
		{
			if (mults.TryGetValue((DamageType)1, out var value))
			{
				dmg.m_blunt *= value;
			}
			if (mults.TryGetValue((DamageType)2, out var value2))
			{
				dmg.m_slash *= value2;
			}
			if (mults.TryGetValue((DamageType)4, out var value3))
			{
				dmg.m_pierce *= value3;
			}
			if (mults.TryGetValue((DamageType)8, out var value4))
			{
				dmg.m_chop *= value4;
			}
			if (mults.TryGetValue((DamageType)16, out var value5))
			{
				dmg.m_pickaxe *= value5;
			}
			if (mults.TryGetValue((DamageType)32, out var value6))
			{
				dmg.m_fire *= value6;
			}
			if (mults.TryGetValue((DamageType)64, out var value7))
			{
				dmg.m_frost *= value7;
			}
			if (mults.TryGetValue((DamageType)128, out var value8))
			{
				dmg.m_lightning *= value8;
			}
			if (mults.TryGetValue((DamageType)256, out var value9))
			{
				dmg.m_poison *= value9;
			}
			if (mults.TryGetValue((DamageType)512, out var value10))
			{
				dmg.m_spirit *= value10;
			}
		}

		private static void ScaleDamage(ref DamageTypes dmg, float mult)
		{
			dmg.m_blunt *= mult;
			dmg.m_slash *= mult;
			dmg.m_pierce *= mult;
			dmg.m_chop *= mult;
			dmg.m_pickaxe *= mult;
			dmg.m_fire *= mult;
			dmg.m_frost *= mult;
			dmg.m_lightning *= mult;
			dmg.m_poison *= mult;
			dmg.m_spirit *= mult;
		}
	}

	[HarmonyPatch(typeof(Character), "GetStealthFactor")]
	private static class RaceStealthPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg))
			{
				__result *= cfg.StealthMultiplier.Value;
			}
		}
	}

	[HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[]
	{
		typeof(int),
		typeof(bool),
		typeof(int),
		typeof(int)
	})]
	private static class RaceBlockFreezingStatusPatch
	{
		private static bool Prefix(SEMan __instance, int nameHash, ref StatusEffect __result)
		{
			if (nameHash != SEMan.s_statusEffectFreezing && nameHash != SEMan.s_statusEffectCold)
			{
				return true;
			}
			Character sEManOwner = GetSEManOwner(__instance);
			Player val = (Player)(object)((sEManOwner is Player) ? sEManOwner : null);
			if ((Object)(object)val == (Object)null || !TryGetRaceConfig(val, out var cfg) || cfg.HeatResistanceBonus.Value == 0f)
			{
				return true;
			}
			__result = null;
			return false;
		}
	}

	[HarmonyPatch(typeof(Character), "GetJogSpeedFactor")]
	private static class RaceJogSpeedPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe()))
			{
				__result *= cfg.SpeedMultiplier.Value;
			}
		}
	}

	[HarmonyPatch(typeof(Character), "GetRunSpeedFactor")]
	private static class RaceRunSpeedPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe()))
			{
				__result *= cfg.SpeedMultiplier.Value;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "GetEquipmentAttackStaminaModifier")]
	private static class RaceStaminaCostAttackPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				__result += GetStaminaCostModifier(cfg, "Attack");
			}
		}
	}

	[HarmonyPatch(typeof(Player), "GetEquipmentBlockStaminaModifier")]
	private static class RaceStaminaCostBlockPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				__result += GetStaminaCostModifier(cfg, "Block");
			}
		}
	}

	[HarmonyPatch(typeof(Player), "GetEquipmentDodgeStaminaModifier")]
	private static class RaceStaminaCostDodgePatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				__result += GetStaminaCostModifier(cfg, "Dodge");
			}
		}
	}

	[HarmonyPatch(typeof(Player), "GetEquipmentJumpStaminaModifier")]
	private static class RaceStaminaCostJumpPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				__result += GetStaminaCostModifier(cfg, "Jump");
			}
		}
	}

	[HarmonyPatch(typeof(Player), "GetEquipmentRunStaminaModifier")]
	private static class RaceStaminaCostRunPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				__result += GetStaminaCostModifier(cfg, "Run");
			}
		}
	}

	[HarmonyPatch(typeof(Player), "GetEquipmentSneakStaminaModifier")]
	private static class RaceStaminaCostSneakPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				__result += GetStaminaCostModifier(cfg, "Sneak");
			}
		}
	}

	[HarmonyPatch(typeof(Player), "GetEquipmentSwimStaminaModifier")]
	private static class RaceStaminaCostSwimPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (TryGetRaceConfig(__instance, out var cfg))
			{
				__result += GetStaminaCostModifier(cfg, "Swim");
			}
		}
	}

	[HarmonyPatch(typeof(Player), "UseEitr")]
	private static class RaceEitrCostPatch
	{
		private static void Prefix(Player __instance, ref float v)
		{
			if (TryGetRaceConfig(__instance, out var cfg) && !cfg.NoResourceCost.Value && cfg.EitrCostMultiplier.Value != 1f)
			{
				v *= cfg.EitrCostMultiplier.Value;
			}
		}
	}

	[HarmonyPatch(typeof(Character), "TryUseEitr")]
	private static class RaceEitrCostTryPatch
	{
		private static void Prefix(Character __instance, ref float eitrUse)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && !cfg.NoResourceCost.Value && cfg.EitrCostMultiplier.Value != 1f)
			{
				eitrUse *= cfg.EitrCostMultiplier.Value;
			}
		}
	}

	public class RaceConfig
	{
		public string RaceId;

		public string DisplayName;

		public ConfigEntry<bool> Enabled;

		public ConfigEntry<string> Scale;

		public ConfigEntry<string> SkinColor;

		public ConfigEntry<string> HairColor;

		public ConfigEntry<string> EarColor;

		public ConfigEntry<string> EyeColor;

		public ConfigEntry<string> SecretCode;

		public ConfigEntry<float> HealthBonus;

		public ConfigEntry<float> StaminaBonus;

		public ConfigEntry<float> EitrBonus;

		public ConfigEntry<float> CarryWeightBonus;

		public ConfigEntry<float> HealthRegenMultiplier;

		public ConfigEntry<float> StaminaRegenMultiplier;

		public ConfigEntry<float> EitrRegenMultiplier;

		public ConfigEntry<float> DamageDoneMultiplier;

		public ConfigEntry<string> SkillDamageMultipliers;

		public ConfigEntry<float> BackstabMultiplier;

		public ConfigEntry<float> DamageTakenMultiplier;

		public ConfigEntry<float> LifestealPercent;

		public ConfigEntry<float> StealthMultiplier;

		public ConfigEntry<float> SpeedMultiplier;

		public ConfigEntry<string> Resistances;

		public ConfigEntry<bool> NoResourceCost;

		public ConfigEntry<float> XpGainMultiplier;

		public ConfigEntry<float> KnockbackMultiplier;

		public ConfigEntry<float> EitrCostMultiplier;

		public ConfigEntry<string> StaminaCostModifiers;

		public ConfigEntry<string> AttackDamageTypeMultipliers;

		public ConfigEntry<bool> NightOnlyBonuses;

		public ConfigEntry<float> DayNightHealthShift;

		public ConfigEntry<string> BiomeHealthShifts;

		public ConfigEntry<float> HeatResistanceBonus;

		public ConfigEntry<bool> CrouchInvisible;

		public ConfigEntry<bool> CrouchInvisibleNightOnly;

		public ConfigEntry<float> LowHealthThreshold;

		public ConfigEntry<float> LowHealthDamageBonus;

		public ConfigEntry<bool> StillHealAura;

		public ConfigEntry<float> StillHealAmount;

		public ConfigEntry<float> StillHealInterval;

		public ConfigEntry<float> StillHealRequiredStillTime;

		public ConfigEntry<bool> IronStanceEnabled;

		public ConfigEntry<float> IronStanceExtraDamageReduction;

		public ConfigEntry<float> BackstabStaminaRefundChance;

		public ConfigEntry<float> BackstabStaminaRefundAmount;

		public ConfigEntry<bool> TremorEnabled;

		public ConfigEntry<float> TremorMinAirTime;

		public ConfigEntry<float> TremorRadius;

		public ConfigEntry<float> TremorKnockback;

		public ConfigEntry<float> TremorFireDamage;

		public ConfigEntry<float> TremorStaggerMultiplier;

		public ConfigEntry<bool> SecondWindEnabled;

		public ConfigEntry<float> SecondWindThreshold;

		public ConfigEntry<float> SecondWindHealAmount;

		public ConfigEntry<float> SecondWindStaminaAmount;

		public ConfigEntry<float> SecondWindCooldown;

		public ConfigEntry<float> OnKillHealAmount;

		public ConfigEntry<string> EvolvesTo;

		public ConfigEntry<float> EvolutionThreshold;

		public ConfigEntry<bool> OnKillHealNightOnly;

		public ConfigEntry<bool> StillHealDayOnly;

		public ConfigEntry<bool> BlockAuraEnabled;

		public ConfigEntry<float> BlockAuraDamage;

		public ConfigEntry<float> BlockAuraRadius;

		public ConfigEntry<bool> BlockAuraIsFrost;

		public ConfigEntry<bool> BlockAuraSlowEnabled;

		public ConfigEntry<float> BlockAuraSlowPercent;

		public ConfigEntry<float> BlockAuraSlowDuration;

		public ConfigEntry<bool> OnHitElementalEnabled;

		public ConfigEntry<float> OnHitElementalDamage;

		public ConfigEntry<bool> FlightEnabled;

		public ConfigEntry<float> FlightStaminaCostPerTick;

		public ConfigEntry<float> FlightMinStaminaToStart;
	}

	[HarmonyPatch(typeof(Player), "IsDebugFlying")]
	private static class ForceIsDebugFlyingPatch
	{
		private static void Postfix(Player __instance, ref bool __result)
		{
			if (!__result && GetDebugFly(__instance))
			{
				__result = true;
			}
		}
	}

	[HarmonyPatch(typeof(Humanoid), "StartAttack")]
	private static class BlockAttackWhileFlyingPatch
	{
		private static bool Prefix(Humanoid __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			return !GetDebugFly(val) || !(GetRace(val) == "fada");
		}
	}

	[HarmonyPatch(typeof(Character), "AddStamina")]
	private static class BlockStaminaRegenWhileFlyingPatch
	{
		private static bool Prefix(Character __instance, ref float v)
		{
			if (v <= 0f)
			{
				return true;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			return !GetDebugFly(val) || !(GetRace(val) == "fada");
		}
	}

	[HarmonyPatch]
	private static class BlockStaminaRegenInUpdateStatsPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo m in methods)
			{
				if (m.Name == "UpdateStats")
				{
					yield return m;
				}
			}
		}

		private static void Prefix(Player __instance, out float __state)
		{
			__state = (GetDebugFly(__instance) ? __instance.GetStamina() : (-1f));
		}

		private static void Postfix(Player __instance, float __state)
		{
			if (__state < 0f || !GetDebugFly(__instance) || __instance.GetStamina() <= __state || !(StaminaField != null))
			{
				return;
			}
			try
			{
				StaminaField.SetValue(__instance, __state);
			}
			catch
			{
			}
		}
	}

	[Serializable]
	[CompilerGenerated]
	private sealed class <>c
	{
		public static readonly <>c <>9 = new <>c();

		public static ConsoleEventFailable <>9__31_0;

		public static ConsoleEventFailable <>9__32_0;

		public static ConsoleEventFailable <>9__39_0;

		internal object <RegisterListFireItemsCommand>b__31_0(ConsoleEventArgs args)
		{
			if (!HasDevCommands())
			{
				args.Context.AddString(Text_SemPermissao.Value);
				return false;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				args.Context.AddString(Text_DebugObjectDBNaoCarregou.Value);
				return false;
			}
			args.Context.AddString(Text_DebugItensComFireStaff.Value);
			int num = 0;
			int num2 = 0;
			try
			{
				if (typeof(ObjectDB).GetField("m_items", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(ObjectDB.instance) is List<GameObject> list)
				{
					num2 = list.Count;
					foreach (GameObject item in list)
					{
						if (!((Object)(object)item == (Object)null))
						{
							string name = ((Object)item).name;
							if (name.ToLowerInvariant().Contains("fire") || name.ToLowerInvariant().Contains("staff"))
							{
								args.Context.AddString("  " + name);
								num++;
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				args.Context.AddString(Fmt(Text_DebugErro.Value, ex.Message));
			}
			args.Context.AddString(Fmt(Text_DebugTotalItens.Value, num2));
			if (num == 0)
			{
				args.Context.AddString(Text_DebugNenhumEncontrado.Value);
			}
			return true;
		}

		internal object <RegisterWhatPieceTableCommand>b__32_0(ConsoleEventArgs args)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				args.Context.AddString(Text_DebugPlayerNaoCarregadoSimples.Value);
				return false;
			}
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(Humanoid), "m_rightItem");
				FieldInfo fieldInfo2 = AccessTools.Field(typeof(Humanoid), "m_leftItem");
				object? obj = fieldInfo?.GetValue(localPlayer);
				ItemData val = (ItemData)((obj is ItemData) ? obj : null);
				object? obj2 = fieldInfo2?.GetValue(localPlayer);
				ItemData val2 = (ItemData)((obj2 is ItemData) ? obj2 : null);
				ItemData val3 = val ?? val2;
				if (val3?.m_shared == null)
				{
					args.Context.AddString(Text_DebugNenhumaFerramenta.Value);
					return false;
				}
				string text = (((Object)(object)val3.m_shared.m_buildPieces != (Object)null) ? ((Object)val3.m_shared.m_buildPieces).name : "(nulo)");
				args.Context.AddString(Fmt(Text_DebugFerramenta.Value, val3.m_shared.m_name));
				args.Context.AddString(Fmt(Text_DebugPieceTableReal.Value, text));
				if ((Object)(object)val3.m_shared.m_buildPieces != (Object)null)
				{
					List<GameObject> pieces = val3.m_shared.m_buildPieces.m_pieces;
					args.Context.AddString(Fmt(Text_DebugTotalPecas.Value, pieces.Count));
				}
				CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
				args.Context.AddString(((Object)(object)currentCraftingStation != (Object)null) ? Fmt(Text_DebugEstacaoPerto.Value, ((Object)currentCraftingStation).name) : Text_DebugNenhumaEstacao.Value);
			}
			catch (Exception ex)
			{
				args.Context.AddString(Fmt(Text_DebugErro.Value, ex.Message));
			}
			return true;
		}

		internal object <RegisterOfflineResetCommand>b__39_0(ConsoleEventArgs args)
		{
			if (!HasDevCommands())
			{
				args.Context.AddString(Text_SemPermissao.Value);
				return false;
			}
			if (args.Args.Length < 2)
			{
				args.Context.AddString(Text_UsoOfflineReset.Value);
				return false;
			}
			if (!long.TryParse(args.Args[1], out var result))
			{
				args.Context.AddString(Text_IdInvalido.Value);
				return false;
			}
			bool flag = ResetOfflinePlayer(result);
			args.Context.AddString(flag ? Text_OfflineResetado.Value : Text_OfflineNaoEncontrado.Value);
			return flag;
		}
	}

	private static readonly FieldInfo ZNetSceneNamedPrefabsField = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs");

	private static readonly HashSet<long> PendingAltarSwitch = new HashSet<long>();

	private static readonly FieldInfo HelmetInstanceField = AccessTools.Field(typeof(VisEquipment), "m_helmetItemInstance");

	private static readonly HashSet<string> RegisteredSecretCodes = new HashSet<string>(StringComparer.Ordinal);

	private static Player _cachedPreviewPlayerInstance;

	private static Vector3? _originalPreviewSkin;

	private static Vector3? _originalPreviewHair;

	private static string _sessionSelectedPreviewRace;

	private static bool _previewSkinForced;

	private static bool _previewHairForced;

	private static string _lastFullyAppliedRace;

	private static bool _lastAppliedIsFemale;

	public static bool UserJustClickedRacePending;

	private const string ZdoRagdollRaceKey = "ValheimRagdollRace";

	private const string ModGUID = "valheim.races";

	private const string ModName = "Valheim Races";

	private const string ModVersion = "2.9.1";

	private const string RaceOrc = "orc";

	private const string RaceElf = "elfodaluz";

	private const string RaceDarkElf = "elfodanoite";

	private const string RaceDwarf = "anao";

	private const string RaceHalfling = "halfling";

	private const string RaceHuman = "humano";

	private const string RaceJotun = "jotun";

	private const string RaceVampire = "vampiro";

	private const string RaceEfrit = "efrit";

	private const string RaceFairy = "fada";

	private const string ZdoRaceKey = "ValheimRace";

	private const string ZdoEvoProgressKey = "ValheimEvoProgress";

	private const string ZdoRaceVersionKey = "ValheimRaceVer";

	private const int CurrentRaceDataVersion = 1;

	private const string ZdoLockedKey = "ValheimRaceLocked";

	private const string ZdoEarColorKey = "ValheimRaceEarColor";

	private const string ZdoSkinColorKey = "ValheimRaceSkinColor";

	private const string RpcSetRace = "ValheimRaces_SetRace";

	private const string RpcVersionCheck = "ValheimRaces_VersionCheck";

	private const string RpcAdminSetRaceRequest = "ValheimRaces_AdminSetRaceRequest";

	private static ConfigSync ModConfigSync;

	private const int FindHeadMaxDepth = 12;

	private const float RaceApplyMaxDistance = 60f;

	private static readonly WaitForSeconds Wait01 = new WaitForSeconds(0.1f);

	private static readonly WaitForSeconds Wait05 = new WaitForSeconds(0.5f);

	private static readonly WaitForSeconds Wait1 = new WaitForSeconds(1f);

	private static readonly WaitForSeconds Wait2 = new WaitForSeconds(2f);

	private static readonly WaitForSeconds WaitSkin005 = new WaitForSeconds(0.05f);

	private static readonly WaitForSeconds WaitSkin020 = new WaitForSeconds(0.2f);

	private static readonly WaitForSeconds WaitSkin050 = new WaitForSeconds(0.5f);

	private static readonly WaitForSeconds WaitSkin100 = new WaitForSeconds(1f);

	private readonly Harmony harmony = new Harmony("valheim.races");

	public static ValheimRacesPlugin Instance;

	private static GameObject ElfEarsMalePrefab;

	private static GameObject ElfEarsFemalePrefab;

	private static GameObject OrcEarsMalePrefab;

	private static GameObject OrcEarsFemalePrefab;

	private static GameObject OrcTuskPrefab;

	private static GameObject HighElfEyesPrefab;

	private static GameObject HornMalePrefab;

	private static GameObject HornFemalePrefab;

	private static GameObject FairyBodyMalePrefab;

	private static GameObject FairyBodyFemalePrefab;

	private static bool IsApplyingRace = false;

	private static bool RpcRegistered = false;

	private static ZRoutedRpc RegisteredRpcInstance = null;

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

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

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

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

	private static readonly HashSet<long> KnownAdmins = new HashSet<long>();

	private static readonly Dictionary<int, Transform> HeadCache = new Dictionary<int, Transform>();

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

	private static readonly Dictionary<int, int> ApplyRaceCoroutineGeneration = new Dictionary<int, int>();

	private static readonly Dictionary<int, ZNetView> ZNetViewCache = new Dictionary<int, ZNetView>();

	private float timer = 0f;

	private float syncTimer = 0f;

	private float localSaveTimer = 0f;

	private float adminCacheTimer = 0f;

	private float configWatchTimer = 0f;

	private DateTime _lastConfigWrite = DateTime.MinValue;

	private bool isRestoringLocalRace = false;

	private string lastBroadcastRace = null;

	private static string _cachedSavePrefix = null;

	private static long _cachedCharacterId = 0L;

	private static string _cachedServerKey = null;

	private static ZNet _cachedZNetInstance = null;

	private static readonly Vector3 HumanScale = Vector3.one;

	private static readonly Vector3 InvalidColor = new Vector3(-1f, -1f, -1f);

	private static readonly Vector3 HighElfEyesPosition = new Vector3(-0.0063f, -0.0194f, -0.00017f);

	private static readonly Vector3 HighElfEyesRotation = new Vector3(-18.776f, -89.449f, -0.691f);

	private static readonly Vector3 HighElfEyesScale = new Vector3(0.00993f, 0.011539f, 0.01272f);

	private static readonly Vector3 OrcTuskPosition = new Vector3(-0.00137f, 0.00114f, -0.00014f);

	private static readonly Vector3 OrcTuskRotation = new Vector3(-16.932f, -110.817f, 8.571f);

	private static readonly Vector3 OrcTuskScale = new Vector3(0.00494f, 0.005076f, 0.00559f);

	private static readonly string[] SuppressedLogSubstrings = new string[5] { "Failed to find expected binary shader data in 'Custom/Player'", "Failed to find expected binary shader data in 'Custom/Creature'", "Failed to find expected binary shader data in 'Custom/Piece'", "Failed to find expected binary shader data in 'Lux Lit Particles/", "Failed to find expected binary shader data in 'Particles/Standard" };

	private bool _isReloadingConfig;

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

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

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

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

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

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

	private static bool _envNightWarningLogged;

	private const float BonusRegenSeconds = 30f;

	private static readonly Dictionary<int, (float until, float speedFactor)> ChilledStatus = new Dictionary<int, (float, float)>();

	private static float _lastChilledPurgeTime;

	private static readonly Dictionary<string, DamageType> DamageTypeNames = new Dictionary<string, DamageType>(StringComparer.OrdinalIgnoreCase)
	{
		{
			"Blunt",
			(DamageType)1
		},
		{
			"Slash",
			(DamageType)2
		},
		{
			"Pierce",
			(DamageType)4
		},
		{
			"Chop",
			(DamageType)8
		},
		{
			"Pickaxe",
			(DamageType)16
		},
		{
			"Fire",
			(DamageType)32
		},
		{
			"Frost",
			(DamageType)64
		},
		{
			"Lightning",
			(DamageType)128
		},
		{
			"Poison",
			(DamageType)256
		},
		{
			"Spirit",
			(DamageType)512
		}
	};

	private static readonly Dictionary<string, DamageModifier> ModifierNames = new Dictionary<string, DamageModifier>(StringComparer.OrdinalIgnoreCase)
	{
		{
			"Normal",
			(DamageModifier)0
		},
		{
			"Resistant",
			(DamageModifier)1
		},
		{
			"Weak",
			(DamageModifier)2
		},
		{
			"Immune",
			(DamageModifier)3
		},
		{
			"Ignore",
			(DamageModifier)4
		},
		{
			"VeryResistant",
			(DamageModifier)5
		},
		{
			"VeryWeak",
			(DamageModifier)6
		},
		{
			"SlightlyResistant",
			(DamageModifier)7
		},
		{
			"SlightlyWeak",
			(DamageModifier)8
		}
	};

	private static FieldInfo _semanCharacterField;

	public static readonly Dictionary<string, RaceConfig> Races = new Dictionary<string, RaceConfig>();

	private static ConfigFile MainConfigFile;

	public static ConfigEntry<float> EyeGlowPeak;

	public static ConfigEntry<bool> EmoteOnTransform;

	public static ConfigEntry<bool> VfxOnTransform;

	public static ConfigEntry<bool> FillVitalsOnTransform;

	public static ConfigEntry<bool> RacialAbilitiesEnabled;

	private static GameObject AltarPrefab;

	public static ConfigEntry<string> AltarRaces;

	public static ConfigEntry<string> AltarRecipe;

	public static ConfigEntry<string> AltarSwitchCostItem;

	public static ConfigEntry<int> AltarSwitchCostAmount;

	public static ConfigEntry<string> FlightToggleKey;

	private static readonly Dictionary<string, Renderer[]> FairyEyebrowRenderers = new Dictionary<string, Renderer[]>();

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

	private static readonly Dictionary<string, Animator[]> FairyBodyAnimators = new Dictionary<string, Animator[]>();

	private static readonly FieldInfo DebugFlyField = AccessTools.Field(typeof(Player), "m_debugFly");

	private static readonly FieldInfo DebugFlySpeedField = AccessTools.Field(typeof(Character), "m_debugFlySpeed");

	private static readonly FieldInfo RunSpeedField = AccessTools.Field(typeof(Character), "m_runSpeed");

	private static readonly FieldInfo MoveDirField = AccessTools.Field(typeof(Character), "m_moveDir");

	private static readonly FieldInfo MaxAirAltitudeField = AccessTools.Field(typeof(Character), "m_maxAirAltitude");

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

	private static KeyCode? _cachedFlightKey;

	private static string _cachedFlightKeyRaw;

	private static readonly FieldInfo StaminaField = AccessTools.Field(typeof(Player), "m_stamina");

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

	private static Sprite _placeholderIcon;

	private static bool _placeholderIconResolved;

	private const string RaceIconResourceName = "race_icon.rgba";

	private const int RaceIconSize = 128;

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

	private const string ColorAccent = "#E8A33D";

	private const string ColorAbilityBuff = "#8CFF8C";

	private const string ColorAbilityDebuff = "#FF8C8C";

	private static ConfigFile TextConfigFile;

	public static ConfigEntry<string> Text_AltarNome;

	public static ConfigEntry<string> Text_AltarDescricao;

	public static ConfigEntry<string> Text_AltarHoverEscolher;

	public static ConfigEntry<string> Text_AltarHoverTrocar;

	public static ConfigEntry<string> Text_UiEscolhaTitulo;

	public static ConfigEntry<string> Text_UiFechar;

	public static ConfigEntry<string> Text_UiTrocarBotao;

	public static ConfigEntry<string> Text_UiJaEscolheuTitulo;

	public static ConfigEntry<string> Text_UiMoedaInsuficiente;

	public static ConfigEntry<string> Text_UiNenhumaRacaDisponivel;

	public static readonly Dictionary<string, ConfigEntry<string>> RaceNameTexts = new Dictionary<string, ConfigEntry<string>>();

	public static ConfigEntry<string> Text_SemPermissao;

	public static ConfigEntry<string> Text_UsoRaca;

	public static ConfigEntry<string> Text_RacaDesativadaAdmin;

	public static ConfigEntry<string> Text_PlayerNaoEncontrado;

	public static ConfigEntry<string> Text_PlayerNaoCarregado;

	public static ConfigEntry<string> Text_AgoraERaca;

	public static ConfigEntry<string> Text_RacaRemovida;

	public static ConfigEntry<string> Text_UsoOfflineReset;

	public static ConfigEntry<string> Text_IdInvalido;

	public static ConfigEntry<string> Text_OfflineResetado;

	public static ConfigEntry<string> Text_OfflineNaoEncontrado;

	public static ConfigEntry<string> Text_EssaRacaDesativada;

	public static ConfigEntry<string> Text_AgoraEuSou;

	public static ConfigEntry<string> Text_ConfigRecarregado;

	public static ConfigEntry<string> Text_CodigosSecretosAtivos;

	public static ConfigEntry<string> Text_VersaoDiferente;

	public static ConfigEntry<string> Text_DebugObjectDBNaoCarregou;

	public static ConfigEntry<string> Text_DebugItensComFireStaff;

	public static ConfigEntry<string> Text_DebugTotalItens;

	public static ConfigEntry<string> Text_DebugNenhumEncontrado;

	public static ConfigEntry<string> Text_DebugPlayerNaoCarregadoSimples;

	public static ConfigEntry<string> Text_DebugNenhumaFerramenta;

	public static ConfigEntry<string> Text_DebugFerramenta;

	public static ConfigEntry<string> Text_DebugPieceTableReal;

	public static ConfigEntry<string> Text_DebugTotalPecas;

	public static ConfigEntry<string> Text_DebugEstacaoPerto;

	public static ConfigEntry<string> Text_DebugNenhumaEstacao;

	public static ConfigEntry<string> Text_DebugErro;

	public static ConfigEntry<string> Text_VoceEvoluiu;

	public static ConfigEntry<string> Text_StatNomeRaca;

	public static ConfigEntry<string> Text_StatVidaMaxima;

	public static ConfigEntry<string> Text_StatStaminaMaxima;

	public static ConfigEntry<string> Text_StatEitrMaximo;

	public static ConfigEntry<string> Text_StatCapacidadeCarga;

	public static ConfigEntry<string> Text_StatRegenVida;

	public static ConfigEntry<string> Text_StatRegenStamina;

	public static ConfigEntry<string> Text_StatRegenEitr;

	public static ConfigEntry<string> Text_StatDanoCausado;

	public static ConfigEntry<string> Text_StatDanoComSkill;

	public static ConfigEntry<string> Text_StatDanoTipo;

	public static ConfigEntry<string> Text_StatDanoAtaqueFurtivo;

	public static ConfigEntry<string> Text_StatForcaEmpurrao;

	public static ConfigEntry<string> Text_StatDanoRecebido;

	public static ConfigEntry<string> Text_StatVelocidade;

	public static ConfigEntry<string> Text_StatFurtividade;

	public static ConfigEntry<string> Text_StatRouboVida;

	public static ConfigEntry<string> Text_StatGanhoXP;

	public static ConfigEntry<string> Text_StatRegenVelocidadeNoite;

	public static ConfigEntry<string> Text_StatSoANoite;

	public static ConfigEntry<string> Text_StatVidaNoiteDia;

	public static ConfigEntry<string> Text_StatVidaBioma;

	public static ConfigEntry<string> Text_StatFrioAmbiente;

	public static ConfigEntry<string> Text_StatNaoCongela;

	public static ConfigEntry<string> Text_StatModificadorDano;

	public static ConfigEntry<string> Text_StatSemBonus;

	public static ConfigEntry<string> Text_NivelImune;

	public static ConfigEntry<string> Text_NivelMuitoResistente;

	public static ConfigEntry<string> Text_NivelResistente;

	public static ConfigEntry<string> Text_NivelLevementeResistente;

	public static ConfigEntry<string> Text_NivelLevementeFraco;

	public static ConfigEntry<string> Text_NivelFraco;

	public static ConfigEntry<string> Text_NivelMuitoFraco;

	public static ConfigEntry<string> Text_NivelIgnora;

	public static ConfigEntry<string> Text_DanoBlunt;

	public static ConfigEntry<string> Text_DanoSlash;

	public static ConfigEntry<string> Text_DanoPierce;

	public static ConfigEntry<string> Text_DanoChop;

	public static ConfigEntry<string> Text_DanoPickaxe;

	public static ConfigEntry<string> Text_DanoFire;

	public static ConfigEntry<string> Text_DanoFrost;

	public static ConfigEntry<string> Text_DanoLightning;

	public static ConfigEntry<string> Text_DanoPoison;

	public static ConfigEntry<string> Text_DanoSpirit;

	public static ConfigEntry<string> Text_BiomaMeadows;

	public static ConfigEntry<string> Text_BiomaBlackForest;

	public static ConfigEntry<string> Text_BiomaSwamp;

	public static ConfigEntry<string> Text_BiomaMountain;

	public static ConfigEntry<string> Text_BiomaPlains;

	public static ConfigEntry<string> Text_BiomaMistlands;

	public static ConfigEntry<string> Text_BiomaAshLands;

	public static ConfigEntry<string> Text_BiomaDeepNorth;

	public static ConfigEntry<string> Text_BiomaOcean;

	public static ConfigEntry<string> Text_HabFuriaSangue;

	public static ConfigEntry<string> Text_HabFuriaSangueDesc;

	public static ConfigEntry<string> Text_HabAuraCura;

	public static ConfigEntry<string> Text_HabAuraCuraDesc;

	public static ConfigEntry<string> Text_HabAuraCuraSoDeDia;

	public static ConfigEntry<string> Text_HabPosturaFerro;

	public static ConfigEntry<string> Text_HabPosturaFerroDesc;

	public static ConfigEntry<string> Text_HabGolpeOportunidade;

	public static ConfigEntry<string> Text_HabGolpeOportunidadeDesc;

	public static ConfigEntry<string> Text_HabSegundoFolego;

	public static ConfigEntry<string> Text_HabSegundoFolegoDesc;

	public static ConfigEntry<string> Text_HabSedeSangue;

	public static ConfigEntry<string> Text_HabSedeSangueDesc;

	public static ConfigEntry<string> Text_HabSedeSangueSoDeNoite;

	public static ConfigEntry<string> Text_HabMantoSombras;

	public static ConfigEntry<string> Text_HabMantoSombrasDesc;

	public static ConfigEntry<string> Text_HabMantoSombrasSoDeNoite;

	public static ConfigEntry<string> Text_HabTremor;

	public static ConfigEntry<string> Text_HabTremorDesc;

	public static ConfigEntry<string> Text_HabAuraChamas;

	public static ConfigEntry<string> Text_HabAuraChamasDesc;

	public static ConfigEntry<string> Text_HabSoproGlacial;

	public static ConfigEntry<string> Text_HabSoproGlacialDesc;

	public static ConfigEntry<string> Text_HabToqueFlamejante;

	public static ConfigEntry<string> Text_HabToqueFlamejanteDesc;

	public static ConfigEntry<string> Text_HabToqueGelado;

	public static ConfigEntry<string> Text_HabToqueGeladoDesc;

	public static ConfigEntry<string> Text_HabVoo;

	public static ConfigEntry<string> Text_HabVooDesc;

	public static ConfigEntry<string> Text_VooSemStamina;

	private static readonly FieldInfo ModelIndexField = AccessTools.Field(typeof(VisEquipment), "m_modelIndex");

	private static readonly MethodInfo SetSkinColorMethod = AccessTools.Method(typeof(VisEquipment), "SetSkinColor", (Type[])null, (Type[])null);

	private static readonly MethodInfo SetHairColorMethod = AccessTools.Method(typeof(VisEquipment), "SetHairColor", (Type[])null, (Type[])null);

	private static readonly FieldInfo SkinColorField = AccessTools.Field(typeof(VisEquipment), "m_skinColor");

	private void RegisterAltarPiece()
	{
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)AltarPrefab == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"[ValheimRaces] Prefab 'altar_racas' não encontrado — peça do Altar das Raças não registrada.");
			return;
		}
		if ((Object)(object)AltarPrefab.GetComponent<ZNetView>() == (Object)null)
		{
			AltarPrefab.AddComponent<ZNetView>();
		}
		if ((Object)(object)AltarPrefab.GetComponent<WearNTear>() == (Object)null)
		{
			AltarPrefab.AddComponent<WearNTear>();
		}
		if ((Object)(object)AltarPrefab.GetComponent<RaceAltar>() == (Object)null)
		{
			AltarPrefab.AddComponent<RaceAltar>();
		}
		if ((Object)(object)AltarPrefab.GetComponentInChildren<Collider>() == (Object)null)
		{
			Renderer componentInChildren = AltarPrefab.GetComponentInChildren<Renderer>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				BoxCollider val = AltarPrefab.AddComponent<BoxCollider>();
				Bounds localBounds = componentInChildren.localBounds;
				val.center = ((Bounds)(ref localBounds)).center;
				val.size = ((Bounds)(ref localBounds)).size;
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[ValheimRaces] 'altar_racas' não tinha Collider — criei um BoxCollider automático baseado na malha. Se ficar com hitbox estranha, adiciona um Collider certinho no Unity e ele passa a usar esse em vez do automático.");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[ValheimRaces] 'altar_racas' não tem Collider nem Renderer — o altar provavelmente não vai responder a interação.");
			}
		}
		Piece val2 = AltarPrefab.GetComponent<Piece>() ?? AltarPrefab.AddComponent<Piece>();
		val2.m_name = Text_AltarNome.Value;
		val2.m_description = Text_AltarDescricao.Value;
		val2.m_icon = LoadIconFromEmbedded("altar_icon.rgba") ?? GetPlaceholderIcon();
		val2.m_category = (PieceCategory)0;
		val2.m_enabled = true;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"[ValheimRaces] Peça 'Altar das Raças' preparada — entra na tabela do Martelo quando o mundo carregar.");
	}

	private static Requirement[] ParseAltarRecipe(ObjectDB objectDB, string recipe)
	{
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Expected O, but got Unknown
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: 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_011d: Expected O, but got Unknown
		List<Requirement> list = new List<Requirement>();
		if (!string.IsNullOrWhiteSpace(recipe))
		{
			string[] array = recipe.Split(new char[1] { ',' });
			foreach (string text in array)
			{
				string[] array2 = text.Split(new char[1] { ':' });
				if (array2.Length != 2)
				{
					continue;
				}
				string text2 = array2[0].Trim();
				if (string.IsNullOrWhiteSpace(text2) || !int.TryParse(array2[1].Trim(), out var result) || result <= 0)
				{
					continue;
				}
				GameObject itemPrefab = objectDB.GetItemPrefab(text2);
				ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val == (Object)null)
				{
					ValheimRacesPlugin instance = Instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] Item '" + text2 + "' da receita do altar não encontrado — ignorado."));
					}
				}
				else
				{
					list.Add(new Requirement
					{
						m_resItem = val,
						m_amount = result,
						m_recover = true
					});
				}
			}
		}
		if (list.Count == 0)
		{
			GameObject itemPrefab2 = objectDB.GetItemPrefab("Wood");
			ItemDrop val2 = (((Object)(object)itemPrefab2 != (Object)null) ? itemPrefab2.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				list.Add(new Requirement
				{
					m_resItem = val2,
					m_amount = 10,
					m_recover = true
				});
			}
		}
		return list.ToArray();
	}

	public static bool HasChosenRaceViaAltar(Player p)
	{
		return IsPlayerLocked(p);
	}

	public static bool HasPendingAltarSwitch(Player p)
	{
		if ((Object)(object)p == (Object)null)
		{
			return false;
		}
		long playerIdLong = GetPlayerIdLong(p);
		return playerIdLong != 0L && PendingAltarSwitch.Contains(playerIdLong);
	}

	public static void ChooseRaceFromAltar(string race)
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || (Object)(object)Instance == (Object)null)
		{
			return;
		}
		long playerIdLong = GetPlayerIdLong(localPlayer);
		bool flag = playerIdLong != 0L && PendingAltarSwitch.Contains(playerIdLong);
		if (!HasChosenRaceViaAltar(localPlayer) || flag)
		{
			if (flag)
			{
				PendingAltarSwitch.Remove(playerIdLong);
			}
			TransformLocalPlayerFromMarketplace(race);
		}
	}

	public static void SwitchRaceFromAltar(Player p)
	{
		if (!((Object)(object)Instance == (Object)null) && !((Object)(object)p == (Object)null))
		{
			long playerIdLong = GetPlayerIdLong(p);
			if (playerIdLong != 0)
			{
				PendingAltarSwitch.Add(playerIdLong);
			}
		}
	}

	private void ApplyRaceWithDelays(Player p)
	{
		if (!((Object)(object)p == (Object)null))
		{
			ApplyRace(p);
			if (!IsHeadless())
			{
				int instanceID = ((Object)p).GetInstanceID();
				int value;
				int num = ((!ApplyRaceCoroutineGeneration.TryGetValue(instanceID, out value)) ? 1 : (value + 1));
				ApplyRaceCoroutineGeneration[instanceID] = num;
				((MonoBehaviour)this).StartCoroutine(ApplyRaceDelayed(p, Wait01, num));
				((MonoBehaviour)this).StartCoroutine(ApplyRaceDelayed(p, Wait05, num));
				((MonoBehaviour)this).StartCoroutine(ApplyRaceDelayed(p, Wait1, num));
				((MonoBehaviour)this).StartCoroutine(ApplyRaceDelayed(p, Wait2, num));
			}
		}
	}

	private IEnumerator ApplyRaceDelayed(Player p, WaitForSeconds wait, int generation)
	{
		yield return wait;
		if (!((Object)(object)p == (Object)null))
		{
			int instanceId = ((Object)p).GetInstanceID();
			if (ApplyRaceCoroutineGeneration.TryGetValue(instanceId, out var current) && current == generation)
			{
				ApplyRace(p);
			}
		}
	}

	private void QueueSkinRefresh(Player p, string race)
	{
		if (!IsHeadless() && !((Object)(object)p == (Object)null) && !string.IsNullOrWhiteSpace(race))
		{
			string text = GetVisualKey(p);
			if (string.IsNullOrWhiteSpace(text))
			{
				text = ((Object)p).GetInstanceID().ToString();
			}
			float time = Time.time;
			if (!LastSkinRefreshRequest.TryGetValue(text, out var value) || !(time - value < 1.25f))
			{
				LastSkinRefreshRequest[text] = time;
				((MonoBehaviour)this).StartCoroutine(ForceSkinRefresh(p, race));
			}
		}
	}

	private IEnumerator ForceSkinRefresh(Player p, string race)
	{
		yield return null;
		ForceSkinNow(p, race);
		yield return WaitSkin005;
		ForceSkinNow(p, race);
		yield return WaitSkin020;
		ForceSkinNow(p, race);
		yield return WaitSkin050;
		ForceSkinNow(p, race);
		yield return WaitSkin100;
		ForceSkinNow(p, race);
	}

	private void ForceSkinNow(Player p, string race)
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: 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)
		if ((Object)(object)p == (Object)null || string.IsNullOrWhiteSpace(race) || GetRace(p) != race)
		{
			return;
		}
		bool isApplyingRace = IsApplyingRace;
		IsApplyingRace = true;
		try
		{
			if (RaceUsesForcedSkin(race))
			{
				ApplySkin(p, GetNetworkSkinColor(p, race));
			}
			Color color = ToColor(GetRaceEarColor(p, race));
			if (race == "orc" || race == "jotun")
			{
				ApplyOrcEars(p, color);
			}
			else if (race == "elfodanoite" || race == "elfodaluz" || race == "halfling")
			{
				ApplyEars(p, color);
			}
			Transform cachedHead = GetCachedHead(p, race);
			Transform val = ((cachedHead != null) ? cachedHead.Find("HighElfEyes") : null);
			if ((Object)(object)val != (Object)null)
			{
				ApplyEyeColor(val, GetRaceEyeColor(race));
			}
		}
		finally
		{
			IsApplyingRace = isApplyingRace;
		}
	}

	public void RequestOnlineVisualRefresh(Player p)
	{
		if (IsHeadless() || (Object)(object)p == (Object)null)
		{
			return;
		}
		string race = GetRace(p);
		if (!string.IsNullOrWhiteSpace(race))
		{
			ApplyRaceWithDelays(p);
			if (RaceUsesForcedSkin(race) || race == "elfodaluz" || race == "halfling" || race == "vampiro")
			{
				QueueSkinRefresh(p, race);
			}
		}
	}

	public void RequestOnlineVisualRefresh(VisEquipment vis)
	{
		if (!IsHeadless() && !((Object)(object)vis == (Object)null))
		{
			Player val = ((Component)vis).GetComponent<Player>() ?? ((Component)vis).GetComponentInParent<Player>();
			if ((Object)(object)val != (Object)null)
			{
				RequestOnlineVisualRefresh(val);
			}
		}
	}

	public void ForceSkinAfterVanilla(Player p, string race)
	{
		if (!IsHeadless() && !((Object)(object)p == (Object)null) && !string.IsNullOrWhiteSpace(race))
		{
			QueueSkinRefresh(p, race);
		}
	}

	public void ForceSkinAfterVanilla(VisEquipment vis)
	{
		if (IsHeadless() || (Object)(object)vis == (Object)null)
		{
			return;
		}
		Player val = ((Component)vis).GetComponent<Player>() ?? ((Component)vis).GetComponentInParent<Player>();
		if (!((Object)(object)val == (Object)null))
		{
			string race = GetRace(val);
			if (RaceUsesForcedSkin(race) || race == "elfodaluz" || race == "halfling" || race == "vampiro")
			{
				QueueSkinRefresh(val, race);
			}
		}
	}

	private Transform GetCachedHead(Player p, string race)
	{
		if ((Object)(object)p == (Object)null)
		{
			return null;
		}
		int instanceID = ((Object)p).GetInstanceID();
		if (HeadCache.TryGetValue(instanceID, out var value) && HeadCacheRace.TryGetValue(instanceID, out var value2) && value2 == race && (Object)(object)value != (Object)null)
		{
			return value;
		}
		Transform val = FindHead(((Component)p).transform, 0);
		HeadCache[instanceID] = val;
		HeadCacheRace[instanceID] = race;
		return val;
	}

	private static void InvalidateHeadCache(Player p)
	{
		if (!((Object)(object)p == (Object)null))
		{
			int instanceID = ((Object)p).GetInstanceID();
			HeadCache.Remove(instanceID);
			HeadCacheRace.Remove(instanceID);
		}
	}

	private static ZNetView GetCachedZNetView(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return null;
		}
		int instanceID = ((Object)player).GetInstanceID();
		if (ZNetViewCache.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		ZNetView component = ((Component)player).GetComponent<ZNetView>();
		if ((Object)(object)component != (Object)null)
		{
			ZNetViewCache[instanceID] = component;
		}
		return component;
	}

	public void ApplyRace(Player p)
	{
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_056f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0574: Unknown result type (might be due to invalid IL or missing references)
		//IL_04af: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0533: Unknown result type (might be due to invalid IL or missing references)
		//IL_0538: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)p == (Object)null || IsApplyingRace || GetPlayerIdLong(p) == 0)
		{
			return;
		}
		bool flag = IsHeadless();
		string race = GetRace(p);
		string visualKey = GetVisualKey(p);
		string value = "";
		if (!string.IsNullOrWhiteSpace(visualKey))
		{
			LastAppliedRace.TryGetValue(visualKey, out value);
		}
		bool flag2 = value != race;
		IsApplyingRace = true;
		try
		{
			if (flag2)
			{
				InvalidateHeadCache(p);
				if (value == "fada")
				{
					ForceLandIfFlying(p);
				}
				if (!flag)
				{
					ResetScaledHelmet(p);
				}
				ApplyScale(p, HumanScale);
				if (!flag)
				{
					if (RaceUsesForcedSkin(value))
					{
						ResetSkin(p);
					}
					Transform cachedHead = GetCachedHead(p, race);
					RemoveHeadAttachmentDirect(((Component)p).transform, "Ears");
					RemoveHeadAttachmentDirect(((Component)p).transform, "OrcEars");
					RemoveHeadAttachmentDirect(cachedHead, "HighElfEyes");
					RemoveHeadAttachmentDirect(cachedHead, "OrcTusk");
					RemoveHeadAttachmentDirect(((Component)p).transform, "Horn");
					RemovePlayerAttachment(p, "JotunFreeze");
					if (value == "fada")
					{
						RemoveFairyBodyDirect(((Component)p).transform);
					}
				}
				if (!string.IsNullOrWhiteSpace(visualKey))
				{
					LastAppliedRace[visualKey] = race;
				}
				UpdateRaceStatusEffect(p, race);
			}
			if (string.IsNullOrWhiteSpace(race) || !IsRaceEnabled(race))
			{
				ApplyScale(p, HumanScale);
				if (!flag && flag2)
				{
					string visualKey2 = GetVisualKey(p);
					if (!string.IsNullOrWhiteSpace(visualKey2) && OriginalSkinColors.TryGetValue(visualKey2, out var value2))
					{
						ApplySkin(p, value2);
					}
					else
					{
						ApplySkin(p, Vector3.one);
					}
					ResetHelmet(p);
					Transform head = FindHead(((Component)p).transform, 0);
					RemoveHeadAttachmentDirect(((Component)p).transform, "Ears");
					RemoveHeadAttachmentDirect(((Component)p).transform, "OrcEars");
					RemoveHeadAttachmentDirect(head, "HighElfEyes");
					RemoveHeadAttachmentDirect(head, "OrcTusk");
					RemoveHeadAttachmentDirect(((Component)p).transform, "Horn");
					RemovePlayerAttachment(p, "JotunFreeze");
					RemoveFairyBodyDirect(((Component)p).transform);
				}
				return;
			}
			ApplyScale(p, GetRaceScale(race));
			ScaleCurrentHelmetForRace(p, GetRaceScale(race));
			if (!flag)
			{
				if (RaceUsesForcedSkin(race))
				{
					CacheOriginalSkinIfNeeded(p);
					ApplySkin(p, GetNetworkSkinColor(p, race));
					QueueSkinRefresh(p, race);
				}
				if (RaceUsesForcedHair(race))
				{
					ApplyHair(p, GetRaceHairColor(race));
				}
				Transform cachedHead2 = GetCachedHead(p, race);
				bool isFemale = IsFemaleModel(p);
				switch (race)
				{
				case "orc":
					ApplyOrcEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale);
					ApplyHighElfEyesDirect(p, cachedHead2);
					ApplyOrcTuskDirect(cachedHead2);
					break;
				case "elfodanoite":
				case "elfodaluz":
				case "halfling":
					ApplyEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale);
					QueueSkinRefresh(p, race);
					ApplyHighElfEyesDirect(p, cachedHead2);
					break;
				case "anao":
					ApplyHighElfEyesDirect(p, cachedHead2);
					break;
				case "humano":
					ApplyHighElfEyesDirect(p, cachedHead2);
					break;
				case "jotun":
					ApplyOrcEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale);
					ApplyHighElfEyesDirect(p, cachedHead2);
					break;
				case "vampiro":
					ApplyHighElfEyesDirect(p, cachedHead2);
					QueueSkinRefresh(p, race);
					break;
				case "efrit":
					ApplyEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale);
					ApplyHornDirect(((Component)p).transform, isFemale);
					ApplyHighElfEyesDirect(p, cachedHead2);
					QueueSkinRefresh(p, race);
					break;
				case "fada":
					ApplyFairyBodyDirect(((Component)p).transform, isFemale);
					break;
				}
			}
		}
		finally
		{
			IsApplyingRace = false;
		}
	}

	public void SpawnEffect(Player p)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: 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_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		if (VfxOnTransform != null && VfxOnTransform.Value && !IsHeadless() && !((Object)(object)p == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null))
		{
			Vector3 val = ((Component)p).transform.position + Vector3.up;
			Quaternion rotation = ((Component)p).transform.rotation;
			GameObject prefab = ZNetScene.instance.GetPrefab("vfx_spawn_large");
			GameObject prefab2 = ZNetScene.instance.GetPrefab("fx_Fader_Roar_Projectile_Hit");
			if ((Object)(object)prefab != (Object)null)
			{
				Object.Instantiate<GameObject>(prefab, val, rotation);
			}
			if ((Object)(object)prefab2 != (Object)null)
			{
				Object.Instantiate<GameObject>(prefab2, val, rotation);
			}
		}
	}

	private static void ScaleCurrentHelmetForRace(Player p, Vector3 targetScale)
	{
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: 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_00cb: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)p == (Object)null || IsHeadless())
		{
			return;
		}
		try
		{
			VisEquipment component = ((Component)p).GetComponent<VisEquipment>();
			object? obj = HelmetInstanceField?.GetValue(component);
			GameObject val = (GameObject)((obj is GameObject) ? obj : null);
			if (!((Object)(object)val == (Object)null))
			{
				HelmetScaleMarker helmetScaleMarker = val.GetComponent<HelmetScaleMarker>();
				if ((Object)(object)helmetScaleMarker == (Object)null)
				{
					helmetScaleMarker = val.AddComponent<HelmetScaleMarker>();
					helmetScaleMarker.OriginalScale = val.transform.localScale;
					helmetScaleMarker.OriginalPosition = val.transform.localPosition;
					helmetScaleMarker.AppliedScale = Vector3.one;
				}
				if (!(helmetScaleMarker.AppliedScale == targetScale))
				{
					val.transform.localScale = Vector3.Scale(helmetScaleMarker.OriginalScale, targetScale);
					val.transform.localPosition = helmetScaleMarker.OriginalPosition;
					helmetScaleMarker.AppliedScale = targetScale;
				}
			}
		}
		catch (Exception ex)
		{
			ValheimRacesPlugin instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] Falha ao escalar capacete: " + ex.Message));
			}
		}
	}

	private void ResetHelmet(Player p)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		ScaleCurrentHelmetForRace(p, Vector3.one);
	}

	private void ResetScaledHelmet(Player p)
	{
		ResetHelmet(p);
	}

	private static void ApplyScale(Player p, Vector3 scale)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)p == (Object)null))
		{
			((Component)p).transform.localScale = scale;
		}
	}

	private void RegisterCommands()
	{
		RegisterRaceCommand("orc");
		RegisterRaceCommand("elfodaluz");
		RegisterRaceCommand("elfodanoite");
		RegisterRaceCommand("anao");
		RegisterRaceCommand("halfling");
		RegisterRaceCommand("humano");
		RegisterRaceCommand("jotun");
		RegisterRaceCommand("vampiro");
		RegisterRaceCommand("efrit");
		RegisterRaceCommand("fada");
		RegisterResetRaceCommand();
		RegisterOfflineResetCommand();
		ReRegisterSecretCodeCommands();
		RegisterReloadCommand();
		RegisterListFireItemsCommand();
		RegisterWhatPieceTableCommand();
	}

	private void RegisterListFireItemsCommand()
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		object obj = <>c.<>9__31_0;
		if (obj == null)
		{
			ConsoleEventFailable val = delegate(ConsoleEventArgs args)
			{
				if (!HasDevCommands())
				{
					args.Context.AddString(Text_SemPermissao.Value);
					return false;
				}
				if ((Object)(object)ObjectDB.instance == (Object)null)
				{
					args.Context.AddString(Text_DebugObjectDBNaoCarregou.Value);
					return false;
				}
				args.Context.AddString(Text_DebugItensComFireStaff.Value);
				int num = 0;
				int num2 = 0;
				try
				{
					if (typeof(ObjectDB).GetField("m_items", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(ObjectDB.instance) is List<GameObject> list)
					{
						num2 = list.Count;
						foreach (GameObject item in list)
						{
							if (!((Object)(object)item == (Object)null))
							{
								string name = ((Object)item).name;
								if (name.ToLowerInvariant().Contains("fire") || name.ToLowerInvariant().Contains("staff"))
								{
									args.Context.AddString("  " + name);
									num++;
								}
							}
						}
					}
				}
				catch (Exception ex)
				{
					args.Context.AddString(Fmt(Text_DebugErro.Value, ex.Message));
				}
				args.Context.AddString(Fmt(Text_DebugTotalItens.Value, num2));
				if (num == 0)
				{
					args.Context.AddString(Text_DebugNenhumEncontrado.Value);
				}
				return true;
			};
			<>c.<>9__31_0 = val;
			obj = (object)val;
		}
		ConsoleEventFailable val2 = (ConsoleEventFailable)obj;
		new ConsoleCommand("listfireitems", "Lista itens com fire/staff no nome (debug)", val2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private void RegisterWhatPieceTableCommand()
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		object obj = <>c.<>9__32_0;
		if (obj == null)
		{
			ConsoleEventFailable val = delegate(ConsoleEventArgs args)
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					args.Context.AddString(Text_DebugPlayerNaoCarregadoSimples.Value);
					return false;
				}
				try
				{
					FieldInfo fieldInfo = AccessTools.Field(typeof(Humanoid), "m_rightItem");
					FieldInfo fieldInfo2 = AccessTools.Field(typeof(Humanoid), "m_leftItem");
					object? obj2 = fieldInfo?.GetValue(localPlayer);
					ItemData val3 = (ItemData)((obj2 is ItemData) ? obj2 : null);
					object? obj3 = fieldInfo2?.GetValue(localPlayer);
					ItemData val4 = (ItemData)((obj3 is ItemData) ? obj3 : null);
					ItemData val5 = val3 ?? val4;
					if (val5?.m_shared == null)
					{
						args.Context.AddString(Text_DebugNenhumaFerramenta.Value);
						return false;
					}
					string text = (((Object)(object)val5.m_shared.m_buildPieces != (Object)null) ? ((Object)val5.m_shared.m_buildPieces).name : "(nulo)");
					args.Context.AddString(Fmt(Text_DebugFerramenta.Value, val5.m_shared.m_name));
					args.Context.AddString(Fmt(Text_DebugPieceTableReal.Value, text));
					if ((Object)(object)val5.m_shared.m_buildPieces != (Object)null)
					{
						List<GameObject> pieces = val5.m_shared.m_buildPieces.m_pieces;
						args.Context.AddString(Fmt(Text_DebugTotalPecas.Value, pieces.Count));
					}
					CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
					args.Context.AddString(((Object)(object)currentCraftingStation != (Object)null) ? Fmt(Text_DebugEstacaoPerto.Value, ((Object)currentCraftingStation).name) : Text_DebugNenhumaEstacao.Value);
				}
				catch (Exception ex)
				{
					args.Context.AddString(Fmt(Text_DebugErro.Value, ex.Message));
				}
				return true;
			};
			<>c.<>9__32_0 = val;
			obj = (object)val;
		}
		ConsoleEventFailable val2 = (ConsoleEventFailable)obj;
		new ConsoleCommand("whatpiecetable", "Mostra o nome real da PieceTable do item equipado (debug)", val2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private void RegisterReloadCommand()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		new ConsoleCommand("reloadracas", "Recarrega os codigos secretos do config", (ConsoleEventFailable)delegate(ConsoleEventArgs args)
		{
			if (!HasDevCommands())
			{
				args.Context.AddString(Text_SemPermissao.Value);
				return false;
			}
			MainConfigFile.Reload();
			NetworkRaces.Clear();
			ZNetViewCache.Clear();
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (!((Object)(object)allPlayer == (Object)null))
				{
					string visualKey = GetVisualKey(allPlayer);
					if (!string.IsNullOrWhiteSpace(visualKey))
					{
						LastAppliedRace[visualKey] = "";
					}
					InvalidateHeadCache(allPlayer);
					Instance.ApplyRaceWithDelays(allPlayer);
				}
			}
			ReRegisterSecretCodeCommands();
			args.Context.AddString(Text_ConfigRecarregado.Value);
			args.Context.AddString(Text_CodigosSecretosAtivos.Value);
			foreach (KeyValuePair<string, RaceConfig> race in Races)
			{
				string value = race.Value.SecretCode.Value;
				if (!string.IsNullOrWhiteSpace(value))
				{
					args.Context.AddString("  " + GetRaceName(race.Value.RaceId) + " → " + value);
				}
			}
			return true;
		}, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private void ReRegisterSecretCodeCommands()
	{
		foreach (KeyValuePair<string, RaceConfig> race in Races)
		{
			string value = race.Value.SecretCode.Value;
			string key = race.Key;
			if (!string.IsNullOrWhiteSpace(value) && !RegisteredSecretCodes.Contains(value))
			{
				RegisterSecretCodeCommand(value, key);
				RegisteredSecretCodes.Add(value);
			}
		}
	}

	private void RegisterSecretCodeCommand(string code, string race)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Expected O, but got Unknown
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		new ConsoleCommand(code, "", (ConsoleEventFailable)delegate
		{
			TransformLocalPlayerFromMarketplace(race);
			return true;
		}, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private void RegisterRaceCommand(string race)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		new ConsoleCommand(race, race + " me  ou  " + race + " NomeDoPlayer", (ConsoleEventFailable)delegate(ConsoleEventArgs args)
		{
			if (!HasDevCommands())
			{
				args.Context.AddString(Text_SemPermissao.Value);
				return false;
			}
			if (!IsRaceEnabled(race))
			{
				args.Context.AddString(Fmt(Text_RacaDesativadaAdmin.Value, GetRaceName(race)));
				return false;
			}
			if (args.Args.Length < 2)
			{
				args.Context.AddString(Fmt(Text_UsoRaca.Value, race));
				return false;
			}
			Player targetPlayer = GetTargetPlayer(args);
			if ((Object)(object)targetPlayer == (Object)null)
			{
				args.Context.AddString(Text_PlayerNaoEncontrado.Value);
				return false;
			}
			AdminSetRace(targetPlayer, race);
			args.Context.AddString(Fmt(Text_AgoraERaca.Value, targetPlayer.GetPlayerName(), GetRaceName(race)));
			return true;
		}, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private void RegisterResetRaceCommand()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		ConsoleEventFailable val = (ConsoleEventFailable)delegate(ConsoleEventArgs args)
		{
			if (!HasDevCommands())
			{
				args.Context.AddString(Text_SemPermissao.Value);
				return false;
			}
			if (args.Args.Length < 2)
			{
				args.Context.AddString(Fmt(Text_UsoRaca.Value, args.Args[0]));
				return false;
			}
			Player targetPlayer = GetTargetPlayer(args);
			if ((Object)(object)targetPlayer == (Object)null)
			{
				args.Context.AddString(Text_PlayerNaoEncontrado.Value);
				return false;
			}
			long playerIdLong = GetPlayerIdLong(targetPlayer);
			if (playerIdLong == 0)
			{
				args.Context.AddString(Fmt(Text_PlayerNaoCarregado.Value, targetPlayer.GetPlayerName()));
				return false;
			}
			ResetRace(targetPlayer, broadcast: true);
			args.Context.AddString(Fmt(Text_RacaRemovida.Value, targetPlayer.GetPlayerName()));
			return true;
		};
		new ConsoleCommand("racareset", "racareset me  ou  racareset NomeDoPlayer", val, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private Player GetTargetPlayer(ConsoleEventArgs args)
	{
		string typedName = string.Join(" ", args.Args.Skip(1)).Trim();
		if (typedName.Equals("me", StringComparison.OrdinalIgnoreCase))
		{
			return Player.m_localPlayer;
		}
		return ((IEnumerable<Player>)Player.GetAllPlayers()).FirstOrDefault((Func<Player, bool>)((Player p) => (Object)(object)p != (Object)null && p.GetPlayerName().Equals(typedName, StringComparison.OrdinalIgnoreCase)));
	}

	private void RegisterOfflineResetCommand()
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Expected O, but got Unknown
		object obj = <>c.<>9__39_0;
		if (obj == null)
		{
			ConsoleEventFailable val = delegate(ConsoleEventArgs args)
			{
				if (!HasDevCommands())
				{
					args.Context.AddString(Text_SemPermissao.Value);
					return false;
				}
				if (args.Args.Length < 2)
				{
					args.Context.AddString(Text_UsoOfflineReset.Value);
					return false;
				}
				if (!long.TryParse(args.Args[1], out var result))
				{
					args.Context.AddString(Text_IdInvalido.Value);
					return false;
				}
				bool flag = ResetOfflinePlayer(result);
				args.Context.AddString(flag ? Text_OfflineResetado.Value : Text_OfflineNaoEncontrado.Value);
				return flag;
			};
			<>c.<>9__39_0 = val;
			obj = (object)val;
		}
		new ConsoleCommand("valheim_reset_offline", "valheim_reset_offline <playerID/steamID>", (ConsoleEventFailable)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private static bool ResetOfflinePlayer(long playerID)
	{
		if (ZDOMan.instance == null)
		{
			return false;
		}
		List<ZDO> list = new List<ZDO>();
		int num = 0;
		while (ZDOMan.instance.GetAllZDOsWithPrefabIterative("Player", list, ref num))
		{
		}
		foreach (ZDO item in list)
		{
			if (item != null)
			{
				long num2 = item.GetLong(ZDOVars.s_playerID, 0L);
				if (num2 == playerID)
				{
					item.Set("ValheimRace", "");
					item.Set("ValheimRaceLocked", false);
					item.Set("ValheimRaceEarColor_x", -1f);
					item.Set("ValheimRaceEarColor_y", -1f);
					item.Set("ValheimRaceEarColor_z", -1f);
					item.Set("ValheimRaceSkinCol