Decompiled source of ValheimRaces v2.9.4

ValheimRaces.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
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_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: 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 || (Object)(object)__instance.GetItemPrefab("Hammer") == (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), "Awake")]
	private static class FejdStartupPrewarmPatch
	{
		private static void Postfix(FejdStartup __instance)
		{
			try
			{
				GetUiClickClip();
			}
			catch
			{
			}
			try
			{
				FejdRaceSelectorUI.Prewarm(__instance);
			}
			catch (Exception arg)
			{
				ValheimRacesPlugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogWarning((object)$"Falha ao pré-aquecer o seletor de raça do menu: {arg}");
				}
			}
		}
	}

	[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(FejdStartup), "OnNewCharacterCancel")]
	private static class FejdCharacterCancelPatch
	{
		private static void Postfix()
		{
			_sessionSelectedPreviewRace = null;
			UserJustClickedRacePending = false;
			_typedNamePreview = null;
			_lastFullyAppliedRace = null;
			_lastAppliedIsFemale = false;
		}
	}

	[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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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, GetRaceMinSkinBrightness(_sessionSelectedPreviewRace), GetRaceMaxSkinBrightness(_sessionSelectedPreviewRace));
				}
			}
		}

		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())
			{
				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_0053: 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_004e: 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)) ? GetFinalScale(component, 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_0062: 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, GetFinalScale(val, race));
					Instance.RequestOnlineVisualRefresh(val);
				}
			}
		}
	}

	[HarmonyPatch(typeof(Chat), "InputText")]
	private static class ChatPatch
	{
		private static readonly FieldInfo InputField = AccessTools.Field(typeof(Chat), "m_input");

		private static PropertyInfo _textProp;

		private static bool Prefix(Chat __instance)
		{
			if ((Object)(object)__instance == (Object)null || InputField == null)
			{
				return true;
			}
			object value = InputField.GetValue(__instance);
			if (value == null)
			{
				return true;
			}
			if (_textProp == null)
			{
				_textProp = value.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public);
			}
			if (_textProp == null)
			{
				return true;
			}
			string text;
			try
			{
				text = (_textProp.GetValue(value) as string)?.Trim() ?? "";
			}
			catch
			{
				return true;
			}
			string raceFromSecretCode = GetRaceFromSecretCode(text);
			if (raceFromSecretCode == null)
			{
				return true;
			}
			TransformLocalPlayerFromMarketplace(raceFromSecretCode);
			try
			{
				if (_textProp.CanWrite)
				{
					_textProp.SetValue(value, "");
				}
			}
			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;
		}
	}

	[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(Humanoid), "BlockAttack", new Type[]
	{
		typeof(HitData),
		typeof(Character)
	})]
	private static class RaceIronStanceOnBlockPatch
	{
		private static void Postfix(Humanoid __instance, HitData hit, bool __result)
		{
			if (!__result)
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (!((Object)(object)val == (Object)null) && RacialAbilitiesEnabled.Value && TryGetRaceConfig(val, out var cfg) && cfg.UseRacialAbility.Value && cfg.IronStanceEnabled)
			{
				float num = Mathf.Clamp01(cfg.IronStanceExtraDamageReduction);
				if (num > 0f)
				{
					ScaleAllDamageTypes(ref hit.m_damage, 1f - num);
				}
				hit.m_pushForce = 0f;
			}
		}
	}

	[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.UseRacialAbility.Value || !cfg.TremorEnabled)
			{
				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)
			{
				DoTremor(val, cfg);
			}
			TremorAirTime[visualKey] = 0f;
			TremorWasOnGround[visualKey] = true;
		}
	}

	[HarmonyPatch(typeof(Player), "SetMaxHealth")]
	private static class RaceMaxHealthPatch
	{
		private static void Prefix(Player __instance, ref float health)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			if (TryGetDevotionConfig(__instance, out var cfg))
			{
				health += cfg.HealthBonus;
			}
			if (!TryGetRaceConfig(__instance, out var cfg2) || !cfg2.UseModAttributes.Value)
			{
				return;
			}
			health += cfg2.HealthBonus;
			if (cfg2.DayNightHealthShift != 0f)
			{
				health += (IsNightSafe() ? cfg2.DayNightHealthShift : (0f - cfg2.DayNightHealthShift));
			}
			if (!string.IsNullOrWhiteSpace(cfg2.BiomeHealthShifts))
			{
				try
				{
					Biome currentBiome = __instance.GetCurrentBiome();
					Dictionary<Biome, float> dictionary = ParseBiomeShifts(cfg2.BiomeHealthShifts);
					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 (TryGetDevotionConfig(__instance, out var cfg))
			{
				stamina += cfg.StaminaBonus;
			}
			if (TryGetRaceConfig(__instance, out var cfg2) && cfg2.UseModAttributes.Value)
			{
				stamina += cfg2.StaminaBonus;
			}
		}
	}

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

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

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

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

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

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

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

	[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.UseModAttributes.Value || !cfg.NoResourceCost)
			{
				return true;
			}
			__result = true;
			return false;
		}
	}

	[HarmonyPatch(typeof(Player), "GetEquipmentHeatResistanceModifier")]
	private static class RaceHeatImmunityPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (!((Object)(object)__instance == (Object)null) && TryGetRaceConfig(__instance, out var cfg) && cfg.UseModAttributes.Value && cfg.HeatResistanceBonus != 0f)
			{
				__result = Mathf.Max(__result, 1f);
			}
		}
	}

	private class RaceAuraTag : MonoBehaviour
	{
		public string SourcePrefabName;
	}

	[HarmonyPatch(typeof(Humanoid), "BlockAttack", new Type[]
	{
		typeof(HitData),
		typeof(Character)
	})]
	private static class RaceBlockAuraOnBlockPatch
	{
		private static void Postfix(Humanoid __instance, HitData hit, Character attacker, bool __result)
		{
			if (__result)
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (!((Object)(object)val == (Object)null) && RacialAbilitiesEnabled.Value && TryGetRaceConfig(val, out var cfg) && cfg.UseRacialAbility.Value && cfg.BlockAuraEnabled)
				{
					DoBlockAuraHit(val, attacker, cfg);
				}
			}
		}
	}

	[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.UseRacialAbility.Value)
			{
				return;
			}
			if (value.OnHitElementalEnabled && value.OnHitElementalDamage > 0f)
			{
				if (value.BlockAuraIsFrost)
				{
					hit.m_damage.m_frost += value.OnHitElementalDamage;
				}
				else
				{
					hit.m_damage.m_fire += value.OnHitElementalDamage;
				}
			}
			if (value.OnHitSpiritEnabled && value.OnHitSpiritDamage > 0f)
			{
				hit.m_damage.m_spirit += value.OnHitSpiritDamage;
			}
		}
	}

	[HarmonyPatch(typeof(Character), "Damage")]
	private static class RaceCombatDamagePatch
	{
		private static void Prefix(Character __instance, HitData hit, out float __state)
		{
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			__state = (((Object)(object)__instance != (Object)null) ? __instance.GetHealth() : 0f);
			if ((Object)(object)__instance == (Object)null || hit == null)
			{
				return;
			}
			try
			{
				Character attacker = hit.GetAttacker();
				Player val = (Player)(object)((attacker is Player) ? attacker : null);
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)__instance && TryGetDevotionConfig(val, out var cfg))
				{
					if (cfg.DamageDoneMultiplier != 1f)
					{
						ScaleAllDamageTypes(ref hit.m_damage, cfg.DamageDoneMultiplier);
					}
					if (!string.IsNullOrWhiteSpace(cfg.AttackDamageTypeMultipliers))
					{
						Dictionary<DamageType, float> dictionary = ParseTypeMultipliers(cfg.AttackDamageTypeMultipliers);
						foreach (KeyValuePair<DamageType, float> item in dictionary)
						{
							ScaleDamageType(ref hit.m_damage, item.Key, item.Value);
						}
					}
					if (cfg.BackstabMultiplier != 1f && hit.m_backstabBonus > 1f)
					{
						ScaleAllDamageTypes(ref hit.m_damage, cfg.BackstabMultiplier);
					}
					if (cfg.KnockbackMultiplier != 1f)
					{
						hit.m_pushForce *= cfg.KnockbackMultiplier;
					}
				}
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)__instance && TryGetRaceConfig(val, out var cfg2) && cfg2.UseModAttributes.Value)
				{
					if (cfg2.DamageDoneMultiplier != 1f)
					{
						ScaleAllDamageTypes(ref hit.m_damage, cfg2.DamageDoneMultiplier);
					}
					if (!string.IsNullOrWhiteSpace(cfg2.SkillDamageMultipliers))
					{
						Dictionary<string, float> dictionary2 = ParseSkillMultipliers(cfg2.SkillDamageMultipliers);
						if (dictionary2.TryGetValue(((object)Unsafe.As<SkillType, SkillType>(ref hit.m_skill)/*cast due to .constrained prefix*/).ToString(), out var value))
						{
							ScaleAllDamageTypes(ref hit.m_damage, value);
						}
					}
					if (!string.IsNullOrWhiteSpace(cfg2.AttackDamageTypeMultipliers))
					{
						Dictionary<DamageType, float> dictionary3 = ParseTypeMultipliers(cfg2.AttackDamageTypeMultipliers);
						foreach (KeyValuePair<DamageType, float> item2 in dictionary3)
						{
							ScaleDamageType(ref hit.m_damage, item2.Key, item2.Value);
						}
					}
					if (cfg2.BackstabMultiplier != 1f && hit.m_backstabBonus > 1f)
					{
						ScaleAllDamageTypes(ref hit.m_damage, cfg2.BackstabMultiplier);
					}
					if (cfg2.KnockbackMultiplier != 1f)
					{
						hit.m_pushForce *= cfg2.KnockbackMultiplier;
					}
				}
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)__instance && TryGetRaceConfig(val, out var cfg3) && cfg3.UseRacialAbility.Value && cfg3.LowHealthThreshold > 0f && cfg3.LowHealthDamageBonus != 1f)
				{
					float maxHealth = ((Character)val).GetMaxHealth();
					if (maxHealth > 0f && ((Character)val).GetHealth() / maxHealth <= cfg3.LowHealthThreshold)
					{
						ScaleAllDamageTypes(ref hit.m_damage, cfg3.LowHealthDamageBonus);
					}
				}
				Player val2 = (Player)(object)((__instance is Player) ? __instance : null);
				if ((Object)(object)val2 != (Object)null && TryGetDevotionConfig(val2, out var cfg4) && cfg4.DamageTakenMultiplier != 1f)
				{
					ScaleAllDamageTypes(ref hit.m_damage, cfg4.DamageTakenMultiplier);
				}
				if ((Object)(object)val2 != (Object)null && TryGetRaceConfig(val2, out var cfg5) && cfg5.UseModAttributes.Value && cfg5.DamageTakenMultiplier != 1f)
				{
					ScaleAllDamageTypes(ref hit.m_damage, cfg5.DamageTakenMultiplier);
				}
			}
			catch (Exception arg)
			{
				ValheimRacesPlugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogWarning((object)$"[ValheimRaces] RaceCombatDamagePatch.Prefix deu exception (ignorando, dano segue sem bônus racial): {arg}");
				}
			}
		}

		private static void Postfix(Character __instance, HitData hit, float __state)
		{
			if ((Object)(object)__instance == (Object)null || hit == null)
			{
				return;
			}
			try
			{
				Character attacker = hit.GetAttacker();
				Player val = (Player)(object)((attacker is Player) ? attacker : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)__instance)
				{
					return;
				}
				if (__state > 0f && __instance.GetHealth() <= 0f)
				{
					if (TryGetDevotionConfig(val, out var cfg) && cfg.OnKillHealAmount > 0f && (!cfg.OnKillHealNightOnly || IsNightSafe()))
					{
						((Character)val).Heal(cfg.OnKillHealAmount, false);
					}
					if (TryGetRaceConfig(val, out var cfg2) && cfg2.UseRacialAbility.Value && cfg2.OnKillHealAmount > 0f && (!cfg2.OnKillHealNightOnly || IsNightSafe()))
					{
						((Character)val).Heal(cfg2.OnKillHealAmount, false);
					}
				}
				if (TryGetRaceConfig(val, out var cfg3) && cfg3.UseRacialAbility.Value && !(cfg3.LifestealPercent <= 0f))
				{
					float num = __state - __instance.GetHealth();
					if (num > 0f)
					{
						((Character)val).Heal(num * cfg3.LifestealPercent, false);
					}
				}
			}
			catch (Exception arg)
			{
				ValheimRacesPlugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogWarning((object)$"[ValheimRaces] RaceCombatDamagePatch.Postfix deu exception (ignorando): {arg}");
				}
			}
		}
	}

	[HarmonyPatch(typeof(Character), "GetDamageModifier")]
	private static class RaceResistancePatch
	{
		private static void Postfix(Character __instance, DamageType damageType, ref DamageModifier __result)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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)
			//IL_0065: Expected I4, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected I4, but got Unknown
			try
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				if (TryGetDevotionConfig(val, out var cfg) && !string.IsNullOrWhiteSpace(cfg.Resistances))
				{
					Dictionary<DamageType, DamageModifier> dictionary = ParseResistances(cfg.Resistances);
					if (dictionary.TryGetValue(damageType, out var value))
					{
						__result = (DamageModifier)(int)StrongerDamageModifier(__result, value);
					}
				}
				if (TryGetRaceConfig(val, out var cfg2) && cfg2.UseModAttributes.Value && !string.IsNullOrWhiteSpace(cfg2.Resistances))
				{
					Dictionary<DamageType, DamageModifier> dictionary2 = ParseResistances(cfg2.Resistances);
					if (dictionary2.TryGetValue(damageType, out var value2))
					{
						__result = (DamageModifier)(int)StrongerDamageModifier(__result, value2);
					}
				}
			}
			catch (Exception arg)
			{
				ValheimRacesPlugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogWarning((object)$"[ValheimRaces] RaceResistancePatch.Postfix deu exception (ignorando): {arg}");
				}
			}
		}
	}

	[HarmonyPatch(typeof(Skills), "RaiseSkill")]
	private static class RaceXpGainPatch
	{
		private static void Prefix(Skills __instance, ref float factor)
		{
			try
			{
				if (!(SkillsOwnerPlayerField == null) && !(factor <= 0f))
				{
					object? value = SkillsOwnerPlayerField.GetValue(__instance);
					Player val = (Player)((value is Player) ? value : null);
					if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && cfg.UseModAttributes.Value && cfg.XpGainMultiplier != 1f)
					{
						factor *= cfg.XpGainMultiplier;
					}
				}
			}
			catch (Exception arg)
			{
				ValheimRacesPlugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Logger.LogWarning((object)$"[ValheimRaces] RaceXpGainPatch.Prefix deu exception (ignorando): {arg}");
				}
			}
		}
	}

	public class RaceConfig
	{
		public string RaceId;

		public string DisplayName;

		public ConfigEntry<bool> Enabled;

		public ConfigEntry<bool> UseModAttributes;

		public ConfigEntry<bool> UseRacialAbility;

		public ConfigEntry<bool> UseEpicMmoAbilities;

		public string Scale;

		public string SkinColor;

		public string HairColor;

		public string EarColor;

		public string EyeColor;

		public string SecretCode;

		public bool HiddenFromSelector;

		public float HealthBonus;

		public float StaminaBonus;

		public float EitrBonus;

		public float CarryWeightBonus;

		public float HealthRegenMultiplier;

		public float StaminaRegenMultiplier;

		public float EitrRegenMultiplier;

		public float DamageDoneMultiplier;

		public string SkillDamageMultipliers;

		public float BackstabMultiplier;

		public float DamageTakenMultiplier;

		public float LifestealPercent;

		public float StealthMultiplier;

		public float SpeedMultiplier;

		public string Resistances;

		public bool NoResourceCost;

		public float XpGainMultiplier;

		public float KnockbackMultiplier;

		public float EitrCostMultiplier;

		public string StaminaCostModifiers;

		public string AttackDamageTypeMultipliers;

		public bool NightOnlyBonuses;

		public float DayNightHealthShift;

		public string BiomeHealthShifts;

		public float HeatResistanceBonus;

		public bool CrouchInvisible;

		public bool CrouchInvisibleNightOnly;

		public float LowHealthThreshold;

		public float LowHealthDamageBonus;

		public bool StillHealAura;

		public float StillHealAmount;

		public float StillHealInterval;

		public float StillHealRequiredStillTime;

		public bool IronStanceEnabled;

		public float IronStanceExtraDamageReduction;

		public float BackstabStaminaRefundChance;

		public float BackstabStaminaRefundAmount;

		public bool TremorEnabled;

		public float TremorMinAirTime;

		public float TremorRadius;

		public float TremorKnockback;

		public float TremorFireDamage;

		public float TremorStaggerMultiplier;

		public bool SecondWindEnabled;

		public float SecondWindThreshold;

		public float SecondWindHealAmount;

		public float SecondWindStaminaAmount;

		public float SecondWindCooldown;

		public float OnKillHealAmount;

		public string EvolvesTo;

		public float EvolutionThreshold;

		public bool OnKillHealNightOnly;

		public bool StillHealDayOnly;

		public bool BlockAuraEnabled;

		public float BlockAuraDamage;

		public float BlockAuraRadius;

		public bool BlockAuraIsFrost;

		public bool BlockAuraSlowEnabled;

		public float BlockAuraSlowPercent;

		public float BlockAuraSlowDuration;

		public bool OnHitElementalEnabled;

		public float OnHitElementalDamage;

		public bool OnHitSpiritEnabled;

		public float OnHitSpiritDamage;
	}

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

		public static Converter<ParameterInfo, string> <>9__30_2;

		public static ConsoleEventFailable <>9__38_0;

		public static ConsoleEventFailable <>9__39_0;

		public static ConsoleEventFailable <>9__46_0;

		public static ConsoleEvent <>9__84_0;

		public static Func<AudioClip, bool> <>9__384_0;

		public static Func<AudioClip, string> <>9__384_1;

		public static Func<AudioClip, string> <>9__387_1;

		internal string <RegisterInspectHeatCommand>b__30_2(ParameterInfo pi)
		{
			return pi.ParameterType.Name;
		}

		internal object <RegisterListFireItemsCommand>b__38_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__39_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__46_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;
		}

		internal void <RegisterListDollsCommand>b__84_0(ConsoleEventArgs args)
		{
			VisEquipment[] array = Object.FindObjectsByType<VisEquipment>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			args.Context.AddString($"[ValheimRaces] {array.Length} VisEquipment encontrado(s):");
			VisEquipment[] array2 = array;
			foreach (VisEquipment val in array2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					bool flag = (Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)((Component)val).gameObject == (Object)(object)((Component)Player.m_localPlayer).gameObject;
					bool flag2 = (Object)(object)((Component)val).GetComponent<ZNetView>() != (Object)null;
					bool activeInHierarchy = ((Component)val).gameObject.activeInHierarchy;
					string hierarchyPath = GetHierarchyPath(((Component)val).transform);
					string text = $" - '{((Object)((Component)val).gameObject).name}' | ativo={activeInHierarchy} | ZNetView={flag2} | local={flag} | caminho={hierarchyPath}";
					args.Context.AddString(text);
					ValheimRacesPlugin instance = Instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogInfo((object)("[ValheimRaces/Diag] listdolls: " + text));
					}
				}
			}
		}

		internal bool <GetUiClickClip>b__384_0(AudioClip c)
		{
			return (Object)(object)c != (Object)null;
		}

		internal string <GetUiClickClip>b__384_1(AudioClip c)
		{
			return ((Object)c).name;
		}

		internal string <ListAudioClipsContaining>b__387_1(AudioClip c)
		{
			return ((Object)c).name;
		}
	}

	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 const float HumanXpMultiplier = 1.1f;

	private static readonly string[] MmoParamNames = new string[6] { "Strength", "Agility", "Intellect", "Body", "Vigour", "Special" };

	private static readonly Dictionary<string, int[]> RaceMmoAttributeBonus = new Dictionary<string, int[]>
	{
		{
			"humano",
			new int[6] { 2, 2, 2, 2, 2, 2 }
		},
		{
			"elfodaluz",
			new int[6] { 0, 5, 5, 0, 1, 3 }
		},
		{
			"elfodanoite",
			new int[6] { 0, 6, 2, 0, 1, 4 }
		},
		{
			"anao",
			new int[6] { 5, 0, 0, 6, 3, 1 }
		},
		{
			"jotun",
			new int[6] { 5, 0, 0, 7, 3, 1 }
		},
		{
			"efrit",
			new int[6] { 3, 0, 7, 0, 1, 3 }
		},
		{
			"orc",
			new int[6] { 6, 0, 0, 7, 2, 1 }
		},
		{
			"aesir",
			new int[6] { 7, 3, 2, 7, 3, 3 }
		},
		{
			"vanir",
			new int[6] { 2, 4, 4, 3, 7, 5 }
		},
		{
			"cavaleirovalhalla",
			new int[6] { 6, 4, 3, 6, 2, 3 }
		}
	};

	private static bool _mmoChecked;

	private static bool _mmoAvailable;

	private static Type _mmoLevelSystemType;

	private static Type _mmoParameterType;

	private static MethodInfo _mmoGetInstance;

	private static MethodInfo _mmoGetParameter;

	private static MethodInfo _mmoSetParameter;

	private static bool _mmoXpPatched;

	private const string MmoKeyPrefix = "EpicMMOSystem_LevelSystem_";

	private static readonly FieldInfo KnownTextsField = AccessTools.Field(typeof(Player), "m_knownTexts");

	private static bool _mmoAddHpChecked;

	private static float _mmoAddHpConfigValue = 1f;

	private static readonly string[] MmoParamNamesPt = new string[6] { "Força", "Destreza", "Inteligência", "Resistência", "Vigor", "Especialização" };

	private const string MmoBrandColor = "#8fd3f4";

	private const string MmoPositiveColor = "#7fe08a";

	private const string MmoNegativeColor = "#e07a6a";

	private const string MmoNeutralColor = "#d8d0c0";

	private const string MmoDividerColor = "#6b5a3f";

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

	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;

	private static string _typedNamePreview;

	private static readonly FieldInfo NewCharacterNameField = AccessTools.Field(typeof(FejdStartup), "m_csNewCharacterName");

	public static bool UserJustClickedRacePending;

	private static bool _previewShareRetryQueued;

	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 RaceElf = "elfodaluz";

	private const string RaceDarkElf = "elfodanoite";

	private const string RaceDwarf = "anao";

	private const string RaceHuman = "humano";

	private const string RaceJotun = "jotun";

	private const string RaceEfrit = "efrit";

	private const string RaceOrc = "orc";

	private const string RaceValhallaKnight = "cavaleirovalhalla";

	private const string RaceAesir = "aesir";

	private const string RaceVanir = "vanir";

	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 ZdoDevotionKey = "ValheimRaceDevotion";

	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 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 Dictionary<string, string> LastSkinRefreshRace = new Dictionary<string, string>();

	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 raceReconcileTimer = 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 OrcTuskUpperPosition = new Vector3(-0.00137f, 0.00114f, -0.00014f);

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

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

	private static readonly Vector3 OrcTuskLowerPosition = new Vector3(-0.00137f, -0.006f, -0.00014f);

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

	private static readonly Vector3 OrcTuskLowerScale = 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, Vector3> DevotionStillLastPos = new Dictionary<string, Vector3>();

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

	private static readonly Dictionary<string, float> DevotionStillHealTimer = 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;

	public static ConfigEntry<string> AesirAuraPrefab;

	public static ConfigEntry<string> VanirAuraPrefab;

	private static readonly HashSet<string> AuraPrefabWarned = new HashSet<string>();

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

	private static float _lastChilledPurgeTime;

	private static readonly DamageModifier[] DamageModifierProtectionRank;

	private static readonly FieldInfo SkillsOwnerPlayerField;

	public static readonly Dictionary<string, RaceConfig> Races;

	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> DevotionCostItem;

	public static ConfigEntry<int> DevotionCostAmount;

	public static ConfigEntry<float> DevotionScaleBonus;

	private static readonly Dictionary<string, Texture2D> EmbeddedTextureCache;

	private static readonly Dictionary<string, Font> ValheimFontCache;

	private static readonly string[] UiClickClipCandidates;

	private static readonly string[] ExcludedClipSubstrings;

	private static AudioClip _uiClickClip;

	private static bool _uiClickClipResolved;

	private static AudioSource _uiClickSource;

	private static readonly Dictionary<string, StatusEffect> RaceStatusEffects;

	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;

	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 ConfigEntry<string> Text_UiConfirmar;

	public static ConfigEntry<string> Text_UiCancelar;

	public static ConfigEntry<string> Text_UiConfirmarRaca;

	public static ConfigEntry<string> Text_UiConfirmarDeus;

	public static ConfigEntry<string> Text_ChampionBotao;

	public static ConfigEntry<string> Text_ChampionTitulo;

	public static ConfigEntry<string> Text_ChampionDescricao;

	public static ConfigEntry<string> Text_ChampionEscolherAesir;

	public static ConfigEntry<string> Text_ChampionEscolherVanir;

	public static ConfigEntry<string> Text_ChampionCustoInsuficiente;

	public static ConfigEntry<string> Text_ChampionSucesso;

	public static ConfigEntry<string> Text_ChampionNomeStatus;

	public static ConfigEntry<string> Text_ChampionSecaoStatus;

	public static readonly Dictionary<string, ConfigEntry<string>> RaceNameTexts;

	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_HabToqueEspiritual;

	public static ConfigEntry<string> Text_HabToqueEspiritualDesc;

	private static readonly FieldInfo ModelIndexField;

	private static readonly MethodInfo SetSkinColorMethod;

	private static readonly MethodInfo SetHairColorMethod;

	private static readonly FieldInfo SkinColorField;

	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 (!LastSkinRefreshRace.TryGetValue(text, out var value) || !(value == race) || !LastSkinRefreshRequest.TryGetValue(text, out var value2) || !(time - value2 < 1.25f))
			{
				LastSkinRefreshRequest[text] = time;
				LastSkinRefreshRace[text] = race;
				((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_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		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 == "jotun" || race == "anao")
			{
				ApplyOrcEars(p, color);
			}
			else if (race == "elfodanoite" || race == "elfodaluz")
			{
				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 == "anao" || race == "cavaleirovalhalla")
			{
				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 == "anao" || race == "cavaleirovalhalla")
			{
				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_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_027e: Unknown result type (might be due to invalid IL or missing references)
		//IL_028c: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_049b: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0549: Unknown result type (might be due to invalid IL or missing references)
		//IL_054e: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_058b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0590: Unknown result type (might be due to invalid IL or missing references)
		//IL_0510: Unknown result type (might be due to invalid IL or missing references)
		//IL_0515: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d3: 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 (!flag)
				{
					ResetHelmet(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, "OrcTuskUpper");
					RemoveHeadAttachmentDirect(cachedHead, "OrcTuskLower");
					RemoveHeadAttachmentDirect(((Component)p).transform, "Horn");
					RemovePlayerAttachment(p, "JotunFreeze");
					RemoveConstantAura(p);
				}
				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, "OrcTuskUpper");
					RemoveHeadAttachmentDirect(head, "OrcTuskLower");
					RemoveHeadAttachmentDirect(((Component)p).transform, "Horn");
					RemovePlayerAttachment(p, "JotunFreeze");
					RemoveConstantAura(p);
				}
				return;
			}
			ApplyScale(p, GetFinalScale(p, race));
			ScaleCurrentHelmetForRace(p, GetFinalScale(p, 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 "elfodanoite":
				case "elfodaluz":
					ApplyEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale);
					QueueSkinRefresh(p, race);
					ApplyHighElfEyesDirect(p, cachedHead2);
					break;
				case "anao":
					ApplyOrcEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale);
					QueueSkinRefresh(p, race);
					ApplyHighElfEyesDirect(p, cachedHead2);
					break;
				case "humano":
					ApplyHighElfEyesDirect(p, cachedHead2);
					break;
				case "jotun":
					ApplyOrcEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale);
					ApplyHornDirect(((Component)p).transform, isFemale);
					ApplyHighElfEyesDirect(p, cachedHead2);
					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 "orc":
					ApplyOrcEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale);
					ApplyOrcTuskDirect(cachedHead2);
					ApplyHighElfEyesDirect(p, cachedHead2);
					QueueSkinRefresh(p, race);
					break;
				case "aesir":
					ApplyHighElfEyesDirect(p, cachedHead2);
					ApplyConstantAura(p, race);
					QueueSkinRefresh(p, race);
					break;
				case "vanir":
					ApplyEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale);
					ApplyHornDirect(((Component)p).transform, isFemale: true);
					ApplyHighElfEyesDirect(p, cachedHead2);
					ApplyConstantAura(p, race);
					QueueSkinRefresh(p, race);
					break;
				case "cavaleirovalhalla":
					ApplyHighElfEyesDirect(p, cachedHead2);
					QueueSkinRefresh(p, race);
					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_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: 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) && !((Object)(object)val.transform.parent == (Object)null))
			{
				Vector3 lossyScale = val.transform.parent.lossyScale;
				Vector3 localScale = default(Vector3);
				((Vector3)(ref localScale))..ctor(Mathf.Approximately(lossyScale.x, 0f) ? targetScale.x : (targetScale.x / lossyScale.x), Mathf.Approximately(lossyScale.y, 0f) ? targetScale.y : (targetScale.y / lossyScale.y), Mathf.Approximately(lossyScale.z, 0f) ? targetScale.z : (targetScale.z / lossyScale.z));
				val.transform.localScale = localScale;
			}
		}
		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 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("elfodaluz");
		RegisterRaceCommand("elfodanoite");
		RegisterRaceCommand("anao");
		RegisterRaceCommand("humano");
		RegisterRaceCommand("jotun");
		RegisterRaceCommand("efrit");
		RegisterRaceCommand("orc");
		RegisterRaceCommand("cavaleirovalhalla");
		RegisterRaceCommand("aesir");
		RegisterRaceCommand("vanir");
		RegisterResetRaceCommand();
		RegisterOfflineResetCommand();
		ReRegisterSecretCodeCommands();
		RegisterReloadCommand();
		RegisterListFireItemsCommand();
		RegisterWhatPieceTableCommand();
		RegisterInspectPrefabCommand();
		RegisterCheckBodyCommand();
		RegisterListPrefabsCommand();
		RegisterListSoundsCommand();
		RegisterTestSoundCommand();
		RegisterInspectHeatCommand();
	}

	private void RegisterInspectHeatCommand()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_0023: 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;
			}
			Both("[vr_inspecionar_frio] Membros de Player/Character com 'Heat'/'Cold'/'Freez'/'Comfort'/'Wet' no nome:");
			string[] array = new string[5] { "heat", "cold", "freez", "comfort", "wet" };
			int num = 0;
			Type[] array2 = new Type[3]
			{
				typeof(Player),
				typeof(Character),
				typeof(Humanoid)
			};
			foreach (Type type in array2)
			{
				MemberInfo[] members = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				MemberInfo[] array3 = members;
				foreach (MemberInfo memberInfo in array3)
				{
					if (memberInfo is MethodInfo || memberInfo is FieldInfo || memberInfo is PropertyInfo)
					{
						string text = memberInfo.Name.ToLowerInvariant();
						bool flag = false;
						string[] array4 = array;
						foreach (string value in array4)
						{
							if (text.Contains(value))
							{
								flag = true;
								break;
							}
						}
						if (flag && !text.StartsWith("get_") && !text.StartsWith("set_"))
						{
							string text2 = ((!(memberInfo is MethodInfo methodInfo)) ? ((!(memberInfo is FieldInfo fieldInfo)) ? ("[prop]   " + ((PropertyInfo)memberInfo).PropertyType.Name + " " + type.Name + "." + memberInfo.Name) : ("[campo]  " + fieldInfo.FieldType.Name + " " + type.Name + "." + fieldInfo.Name)) : ("[método] " + methodInfo.ReturnType.Name + " " + type.Name + "." + methodInfo.Name + "(" + string.Join(", ", Array.ConvertAll(methodInfo.GetParameters(), (ParameterInfo pi) => pi.ParameterType.Name)) + ")"));
							Both("[vr_inspecionar_frio]   " + text2);
							num++;
						}
					}
				}
			}
			Both($"[vr_inspecionar_frio] {num} membro(s) encontrado(s).");
			return true;
			void Both(string line)
			{
				args.Context.AddString(line);
				((BaseUnityPlugin)this).Logger.LogInfo((object)line);
			}
		};
		new ConsoleCommand("vr_inspecionar_frio", "vr_inspecionar_frio — lista métodos/campos de Player/Character/Humanoid relacionados a frio/calor (debug)", val, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private void RegisterListSoundsCommand()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_0023: 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("Uso: vr_listar_sons TrechoDoNome");
				return false;
			}
			ListAudioClipsContaining(Both, args.Args[1]);
			return true;
			void Both(string line)
			{
				args.Context.AddString(line);
				((BaseUnityPlugin)this).Logger.LogInfo((object)line);
			}
		};
		new ConsoleCommand("vr_listar_sons", "vr_listar_sons TrechoDoNome — lista clipes de áudio carregados com esse nome (debug)", val, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private void RegisterTestSoundCommand()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_0023: 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("Uso: vr_testarsom TrechoDoNome");
				return false;
			}
			return PlayAudioClipContaining(Both, args.Args[1]);
			void Both(string line)
			{
				args.Context.AddString(line);
				((BaseUnityPlugin)this).Logger.LogInfo((object)line);
			}
		};
		new ConsoleCommand("vr_testarsom", "vr_testarsom TrechoDoNome — toca o primeiro clipe carregado com esse nome (debug)", val, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private void RegisterListPrefabsCommand()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_0023: 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("Uso: vr_listar_prefabs TrechoDoNome");
				return false;
			}
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				args.Context.AddString("[vr_listar_prefabs] ZNetScene ainda não carregado (entre no mundo primeiro).");
				return false;
			}
			string text = args.Args[1].ToLowerInvariant();
			int num = 0;
			try
			{
				if (typeof(ZNetScene).GetField("m_namedPrefabs", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(ZNetScene.instance) is IDictionary dictionary)
				{
					foreach (object value in dictionary.Values)
					{
						GameObject val2 = (GameObject)((value is GameObject) ? value : null);
						if (!((Object)(object)val2 == (Object)null) && ((Object)val2).name.ToLowerInvariant().Contains(text))
						{
							Both("[vr_listar_prefabs]   " + ((Object)val2).name);
							num++;
						}
					}
				}
				else
				{
					Both("[vr_listar_prefabs] Não achei o campo 'm_namedPrefabs' no ZNetScene (versão do jogo mudou?).");
				}
			}
			catch (Exception ex)
			{
				Both("[vr_listar_prefabs] Erro ao procurar: " + ex.Message);
			}
			Both($"[vr_listar_prefabs] {num} prefab(s) encontrados contendo '{text}'.");
			return true;
			void Both(string line)
			{
				args.Context.AddString(line);
				((BaseUnityPlugin)this).Logger.LogInfo((object)line);
			}
		};
		new ConsoleCommand("vr_listar_prefabs", "vr_listar_prefabs TrechoDoNome — lista prefabs do ZNetScene com esse nome (debug)", val, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private static SkinnedMeshRenderer FindBodyRenderer(Transform root)
	{
		if ((Object)(object)root == (Object)null)
		{
			return null;
		}
		SkinnedMeshRenderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name.ToLowerInvariant() == "body")
			{
				return val;
			}
		}
		return null;
	}

	private static void DumpMeshInfo(Action<string> log, string label, SkinnedMeshRenderer smr)
	{
		Mesh val = (((Object)(object)smr != (Object)null) ? smr.sharedMesh : null);
		if ((Object)(object)val == (Object)null)
		{
			log("[vr_verificar_corpo] " + label + ": mesh=null");
			return;
		}
		log($"[vr_verificar_corpo] {label}: mesh='{((Object)val).name}' subMeshCount={val.subMeshCount}");
		Material[] sharedMaterials = ((Renderer)smr).sharedMaterials;
		for (int i = 0; i < val.subMeshCount; i++)
		{
			int num = 0;
			try
			{
				num = val.GetTriangles(i).Length / 3;
			}
			catch
			{
			}
			string text = ((i < sharedMaterials.Length && (Object)(object)sharedMaterials[i] != (Object)null) ? ((Object)sharedMaterials[i]).name : "(sem material)");
			log($"[vr_verificar_corpo] {label}:   submesh[{i}] tris={num} material='{text}'");
		}
	}

	private void RegisterCheckBodyCommand()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		ConsoleEventFailable val = (ConsoleEventFailable)delegate(ConsoleEventArgs args)
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0437: Unknown result type (might be due to invalid IL or missing references)
			//IL_043c: Unknown result type (might be due to invalid IL or missing references)
			//IL_044b: Unknown result type (might be due to invalid IL or missing references)
			//IL_045a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0469: Unknown result type (might be due to invalid IL or missing references)
			//IL_0478: Unknown result type (might be due to invalid IL or missing references)
			if (!HasDevCommands())
			{
				args.Context.AddString(Text_SemPermissao.Value);
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Both("[vr_verificar_corpo] Sem player local (entre no mundo primeiro).");
				return false;
			}
			SkinnedMeshRenderer val2 = FindBodyRenderer(((Component)localPlayer).transform);
			if ((Object)(object)val2 == (Object)null)
			{
				Both("[vr_verificar_corpo] Não achei o renderer 'body' do player.");
				return false;
			}
			Both("[vr_verificar_corpo] Raça atual: '" + GetRace(localPlayer) + "'");
			DumpMeshInfo(Both, "body", val2);
			Both($"[vr_verificar_corpo] HasPropertyBlock = {((Renderer)val2)