using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")] [assembly: AssemblyCompany("ValheimRaces")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ValheimRaces")] [assembly: AssemblyTitle("ValheimRaces")] [assembly: AssemblyVersion("1.0.0.0")] [BepInPlugin("valheim.races", "Valheim Races", "2.9.1")] public class ValheimRacesPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class RegisterAltarPrefabInZNetScenePatch { private static void Postfix(ZNetScene __instance) { if (!((Object)(object)Instance == (Object)null) && !((Object)(object)AltarPrefab == (Object)null) && !((Object)(object)__instance == (Object)null) && !__instance.m_prefabs.Contains(AltarPrefab)) { __instance.m_prefabs.Add(AltarPrefab); if (ZNetSceneNamedPrefabsField?.GetValue(__instance) is Dictionary dictionary) { dictionary[StringExtensionMethods.GetStableHashCode(((Object)AltarPrefab).name)] = AltarPrefab; } ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[ValheimRaces] 'altar_racas' registrado no ZNetScene."); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class RegisterAltarPieceInHammerPatch { private static void Postfix(ObjectDB __instance) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown if ((Object)(object)Instance == (Object)null || (Object)(object)AltarPrefab == (Object)null || (Object)(object)__instance == (Object)null) { return; } Piece component = AltarPrefab.GetComponent(); if ((Object)(object)component == (Object)null) { return; } component.m_resources = ParseAltarRecipe(__instance, AltarRecipe?.Value ?? "Wood:10,Stone:5"); GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("piece_workbench") : null); component.m_craftingStation = (((Object)(object)val != (Object)null) ? val.GetComponent() : 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() : 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() : null); PieceTable val4 = ((!((Object)(object)val3 != (Object)null)) ? null : val3.m_itemData?.m_shared?.m_buildPieces); if ((Object)(object)val4 == (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)"[ValheimRaces] Não achei a tabela de peças do Martelo — Altar não vai aparecer no menu de construção."); return; } if (!val4.m_pieces.Contains(AltarPrefab)) { val4.m_pieces.Add(AltarPrefab); } ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[ValheimRaces] Peça 'Altar das Raças' registrada na tabela do Martelo."); } } [HarmonyPatch(typeof(FejdStartup), "SetupCharacterPreview")] private static class FejdCharacterPreviewPatch { private static void Postfix(FejdStartup __instance, PlayerProfile profile) { try { ApplyPreviewRace(__instance, profile); } catch (Exception arg) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)$"Falha ao aplicar raça no preview do menu: {arg}"); } } try { if (string.IsNullOrEmpty((profile != null) ? profile.GetName() : null)) { FejdRaceSelectorUI.EnsureVisible(__instance); } else { FejdRaceSelectorUI.Hide(); } } catch (Exception arg2) { ValheimRacesPlugin instance2 = Instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)$"Falha ao mostrar/esconder o seletor de raça do menu: {arg2}"); } } } } [HarmonyPatch(typeof(VisEquipment), "SetSkinColor")] private static class ForcePreviewSkinColorPatch { private static void Prefix(VisEquipment __instance, ref Vector3 __0) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null) && _previewSkinForced && !string.IsNullOrWhiteSpace(_sessionSelectedPreviewRace)) { Player component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component != (Object)(object)_cachedPreviewPlayerInstance)) { __0 = BlendRaceHueWithBrightness(GetRaceSkinColor(_sessionSelectedPreviewRace), __0); } } } private static void Postfix(VisEquipment __instance) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || string.IsNullOrWhiteSpace(_sessionSelectedPreviewRace)) { return; } Player component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component != (Object)(object)_cachedPreviewPlayerInstance)) { Color c = ToColor(GetRaceEarColorForPreview(component, _sessionSelectedPreviewRace)); Transform val = ((Component)component).transform.Find("Ears"); if ((Object)(object)val != (Object)null) { Instance.FixEarMaterials(val, forceStandardShader: false); Instance.ApplyColor(val, c); } Transform val2 = ((Component)component).transform.Find("OrcEars"); if ((Object)(object)val2 != (Object)null) { Instance.FixEarMaterials(val2, forceStandardShader: false); Instance.ApplyColor(val2, c); } } } } [HarmonyPatch(typeof(Player), "OnSpawned")] private static class PlayerSpawnedPatch { private static void Postfix(Player __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)Instance == (Object)null) { return; } if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { Instance.RestoreLocalSavedRaceIfNeeded(); SendVersionCheckToServer(); } if (IsPlayerLocked(__instance)) { SetZdoLocked(__instance, locked: true); } Instance.ApplyRaceWithDelays(__instance); if (!IsHeadless()) { string race = GetRace(__instance); if (!string.IsNullOrWhiteSpace(race)) { UpdateRaceStatusEffect(__instance, race); } } } } [HarmonyPatch(typeof(Player), "OnDeath")] private static class PlayerDeathPatch { private static void Prefix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Instance == (Object)null) && !IsHeadless()) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)$"[ValheimRaces/Diag] OnDeath disparou pra '{__instance.GetPlayerName()}' (isLocal={(Object)(object)__instance == (Object)(object)Player.m_localPlayer})."); RemovePlayerAttachment(__instance, "JotunFreeze"); } } private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Instance == (Object)null) && !IsHeadless()) { Instance.ApplyRaceWithDelays(__instance); string race = GetRace(__instance); if (!string.IsNullOrWhiteSpace(race)) { UpdateRaceStatusEffect(__instance, race); } } } } [HarmonyPatch(typeof(Player), "CreateDeathEffects")] private static class PlayerRagdollRacePatch { private static void Postfix(Player __instance) { if ((Object)(object)Instance == (Object)null || IsHeadless() || (Object)(object)__instance == (Object)null) { return; } Ragdoll ragdoll = __instance.GetRagdoll(); if ((Object)(object)ragdoll == (Object)null) { return; } string race = GetRace(__instance); if (string.IsNullOrWhiteSpace(race) || !IsRaceEnabled(race)) { return; } try { ZNetView component = ((Component)ragdoll).GetComponent(); 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(); if (!((Object)(object)component == (Object)null) && component.GetZDO() != null) { string text = component.GetZDO().GetString("ValheimRagdollRace", ""); if (!string.IsNullOrWhiteSpace(text) && IsRaceEnabled(text)) { ApplyRaceVisualToRagdoll(__instance, text); } } } catch (Exception ex) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)("[ValheimRaces] Falha ao ler raça do ZDO do ragdoll: " + ex.Message)); } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] private static class ZNetDisconnectPatch { private static void Prefix(ZNetPeer peer) { if (peer == null) { return; } try { OnPeerDisconnected(peer.m_uid); } catch { } } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private static class ZNetShutdownPatch { private static void Prefix() { NetworkRaces.Clear(); LastAppliedRace.Clear(); OriginalSkinColors.Clear(); LastSkinRefreshRequest.Clear(); KnownAdmins.Clear(); HeadCache.Clear(); HeadCacheRace.Clear(); ApplyRaceCoroutineGeneration.Clear(); ZNetViewCache.Clear(); _cachedSavePrefix = null; _cachedZNetInstance = null; _cachedCharacterId = 0L; _cachedServerKey = null; RpcRegistered = false; RegisteredRpcInstance = null; if ((Object)(object)Instance != (Object)null) { Instance.lastBroadcastRace = null; Instance.isRestoringLocalRace = false; } } } [HarmonyPatch(typeof(VisEquipment), "SetHelmetItem")] private static class HelmetScaleOnEquipPatch { private static void Postfix(VisEquipment __instance) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null) && !IsHeadless()) { Player component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { string race = GetRace(component); Vector3 targetScale = ((!string.IsNullOrWhiteSpace(race) && IsRaceEnabled(race)) ? GetRaceScale(race) : HumanScale); ScaleCurrentHelmetForRace(component, targetScale); } } } } [HarmonyPatch(typeof(VisEquipment), "SetHairColor")] private static class ForceRaceHairColorPatch { private static void Prefix(VisEquipment __instance, ref Vector3 __0) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || IsApplyingRace) { return; } Player component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)((Component)component).GetComponent() == (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(); if ((Object)(object)component == (Object)null) { return true; } if ((Object)(object)((Component)component).GetComponent() == (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 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 TargetMethods() { string[] names = new string[2] { "UpdateEquipment", "OnInventoryChanged" }; string[] array = names; foreach (string name in array) { MethodInfo method = AccessTools.Method(typeof(Player), name, (Type[])null, (Type[])null); if (method != null) { yield return method; } } } private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Instance == (Object)null) && !IsApplyingRace && !IsHeadless()) { Instance.RequestOnlineVisualRefresh(__instance); } } } [HarmonyPatch(typeof(Character), "SetVisible")] private static class CharacterSetVisiblePatch { private static void Postfix(Character __instance, bool visible) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) if (!visible || (Object)(object)__instance == (Object)null || (Object)(object)Instance == (Object)null || IsHeadless()) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null)) { string race = GetRace(val); if (!string.IsNullOrWhiteSpace(race) && IsRaceEnabled(race)) { ApplyScale(val, GetRaceScale(race)); } } } } [HarmonyPatch(typeof(Chat), "InputText")] private static class ChatPatch { private static bool Prefix(Chat __instance) { if ((Object)(object)__instance == (Object)null) { return true; } string text = ""; try { FieldInfo field = typeof(Chat).GetField("m_input", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return true; } object value = field.GetValue(__instance); if (value == null) { return true; } text = (value.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value) as string)?.Trim() ?? ""; } catch { return true; } string raceFromSecretCode = GetRaceFromSecretCode(text); if (raceFromSecretCode == null) { return true; } TransformLocalPlayerFromMarketplace(raceFromSecretCode); try { object obj2 = typeof(Chat).GetField("m_input", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(__instance); PropertyInfo propertyInfo = obj2?.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public); if (propertyInfo != null && propertyInfo.CanWrite) { propertyInfo.SetValue(obj2, ""); } } catch { } return false; } } [HarmonyPatch(typeof(Character), "UpdateLayer")] private static class FixNullColliderInUpdateLayerPatch { private static readonly FieldInfo ColliderField = AccessTools.Field(typeof(Character), "m_collider"); private static bool Prefix(Character __instance) { if (ColliderField == null || (Object)(object)__instance == (Object)null) { return true; } object? value = ColliderField.GetValue(__instance); Object val = (Object)((value is Object) ? value : null); if (val != (Object)null) { return true; } Collider component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { ColliderField.SetValue(__instance, component); return true; } return false; } } private sealed class ShaderWarningFilterLogHandler : ILogHandler { private readonly ILogHandler _original; public ShaderWarningFilterLogHandler(ILogHandler original) { _original = original; } public void LogFormat(LogType logType, Object context, string format, params object[] args) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_001c: Unknown result type (might be due to invalid IL or missing references) if ((int)logType != 2 || !ShouldSuppress(format, args)) { _original.LogFormat(logType, context, format, args); } } public void LogException(Exception exception, Object context) { _original.LogException(exception, context); } private static bool ShouldSuppress(string format, object[] args) { try { if (!string.IsNullOrEmpty(format)) { string[] suppressedLogSubstrings = SuppressedLogSubstrings; foreach (string value in suppressedLogSubstrings) { if (format.Contains(value)) { return true; } } } if (args != null) { foreach (object obj in args) { if (!(obj is string text)) { continue; } string[] suppressedLogSubstrings2 = SuppressedLogSubstrings; foreach (string value2 in suppressedLogSubstrings2) { if (text.Contains(value2)) { return true; } } } } } catch { } return false; } } [HarmonyPatch(typeof(BaseAI), "CanSenseTarget", new Type[] { typeof(Character) })] private static class RaceCrouchStealthSensePatch { private static void Postfix(Character target, ref bool __result) { if (__result && IsCrouchStealthed(target)) { __result = false; } } } [HarmonyPatch(typeof(BaseAI), "CanSeeTarget", new Type[] { typeof(Character) })] private static class RaceCrouchStealthSeePatch { private static void Postfix(Character target, ref bool __result) { if (__result && IsCrouchStealthed(target)) { __result = false; } } } [HarmonyPatch(typeof(BaseAI), "CanHearTarget", new Type[] { typeof(Character) })] private static class RaceCrouchStealthHearPatch { private static void Postfix(Character target, ref bool __result) { if (__result && IsCrouchStealthed(target)) { __result = false; } } } [HarmonyPatch(typeof(Character), "UpdateGroundContact")] private static class RaceTremorPatch { private static void Postfix(Character __instance, float dt) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val == (Object)null || !RacialAbilitiesEnabled.Value || !TryGetRaceConfig(val, out var cfg) || !cfg.TremorEnabled.Value) { return; } string visualKey = GetVisualKey(val); if (string.IsNullOrWhiteSpace(visualKey)) { return; } bool flag = ((Character)val).IsOnGround(); TremorWasOnGround.TryGetValue(visualKey, out var value); TremorAirTime.TryGetValue(visualKey, out var value2); if (!flag) { TremorAirTime[visualKey] = value2 + dt; TremorWasOnGround[visualKey] = false; return; } if (!value && value2 >= cfg.TremorMinAirTime.Value) { DoTremor(val, cfg); } TremorAirTime[visualKey] = 0f; TremorWasOnGround[visualKey] = true; } } [HarmonyPatch(typeof(Player), "SetMaxHealth")] private static class RaceMaxHealthPatch { private static Dictionary ParseBiomeShifts(string value) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); if (string.IsNullOrWhiteSpace(value)) { return dictionary; } string[] array = value.Split(new char[1] { ',' }); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length == 2 && Enum.TryParse(array2[0].Trim(), ignoreCase: true, out Biome result) && float.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { dictionary[result] = result2; } } return dictionary; } private static void Prefix(Player __instance, ref float health) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (!TryGetRaceConfig(__instance, out var cfg)) { return; } health += cfg.HealthBonus.Value; if (cfg.DayNightHealthShift.Value != 0f) { health += (IsNightSafe() ? cfg.DayNightHealthShift.Value : (0f - cfg.DayNightHealthShift.Value)); } if (!string.IsNullOrWhiteSpace(cfg.BiomeHealthShifts.Value)) { try { Biome currentBiome = __instance.GetCurrentBiome(); Dictionary dictionary = ParseBiomeShifts(cfg.BiomeHealthShifts.Value); if (dictionary.TryGetValue(currentBiome, out var value)) { health += value; } } catch (Exception ex) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] Falha ao ler bioma atual pra oscilação de vida: " + ex.Message)); } } } if (health < 10f) { health = 10f; } } } [HarmonyPatch(typeof(Player), "SetMaxStamina")] private static class RaceMaxStaminaPatch { private static void Prefix(Player __instance, ref float stamina) { if (TryGetRaceConfig(__instance, out var cfg)) { stamina += cfg.StaminaBonus.Value; } } } [HarmonyPatch(typeof(Player), "SetMaxEitr")] private static class RaceMaxEitrPatch { private static void Prefix(Player __instance, ref float eitr) { if (TryGetRaceConfig(__instance, out var cfg)) { eitr += cfg.EitrBonus.Value; } } } [HarmonyPatch(typeof(Player), "GetMaxCarryWeight")] private static class RaceMaxCarryWeightPatch { private static void Postfix(Player __instance, ref float __result) { if (TryGetRaceConfig(__instance, out var cfg)) { __result += cfg.CarryWeightBonus.Value; } } } [HarmonyPatch(typeof(Character), "Heal")] private static class RaceHealthRegenPatch { private static void Prefix(Character __instance, ref float hp) { if (!(hp <= 0f)) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe())) { hp *= cfg.HealthRegenMultiplier.Value; } } } } [HarmonyPatch(typeof(Character), "AddStamina")] private static class RaceStaminaRegenPatch { private static void Prefix(Character __instance, ref float v) { if (!(v <= 0f)) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe())) { v *= cfg.StaminaRegenMultiplier.Value; } } } } [HarmonyPatch(typeof(Character), "AddEitr")] private static class RaceEitrRegenPatch { private static void Prefix(Character __instance, ref float v) { if (!(v <= 0f)) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe())) { v *= cfg.EitrRegenMultiplier.Value; } } } } [HarmonyPatch(typeof(Player), "UseStamina")] private static class RaceNoStaminaCostPatch { private static void Prefix(Player __instance, ref float v) { if (TryGetRaceConfig(__instance, out var cfg) && cfg.NoResourceCost.Value) { v = 0f; } } } [HarmonyPatch(typeof(Player), "UseEitr")] private static class RaceNoEitrCostPatch { private static void Prefix(Player __instance, ref float v) { if (TryGetRaceConfig(__instance, out var cfg) && cfg.NoResourceCost.Value) { v = 0f; } } } [HarmonyPatch(typeof(Character), "TryUseEitr")] private static class RaceNoEitrCostTryPatch { private static bool Prefix(Character __instance, ref bool __result) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val == (Object)null || !TryGetRaceConfig(val, out var cfg) || !cfg.NoResourceCost.Value) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Character), "GetJogSpeedFactor")] private static class ChilledJogSpeedPatch { private static void Postfix(Character __instance, ref float __result) { if (!((Object)(object)__instance == (Object)null) && ChilledStatus.TryGetValue(((Object)__instance).GetInstanceID(), out (float, float) value) && Time.time < value.Item1) { __result *= value.Item2; } } } [HarmonyPatch(typeof(Character), "GetRunSpeedFactor")] private static class ChilledRunSpeedPatch { private static void Postfix(Character __instance, ref float __result) { if (!((Object)(object)__instance == (Object)null) && ChilledStatus.TryGetValue(((Object)__instance).GetInstanceID(), out (float, float) value) && Time.time < value.Item1) { __result *= value.Item2; } } } [HarmonyPatch(typeof(Character), "Damage")] private static class OnHitElementalDamagePatch { private static void Prefix(HitData hit) { if (hit == null || RacialAbilitiesEnabled == null || !RacialAbilitiesEnabled.Value) { return; } Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if (val == null) { return; } string race = GetRace(val); if (!string.IsNullOrWhiteSpace(race) && Races.TryGetValue(race, out var value) && value.OnHitElementalEnabled.Value && !(value.OnHitElementalDamage.Value <= 0f)) { if (value.BlockAuraIsFrost.Value) { hit.m_damage.m_frost += value.OnHitElementalDamage.Value; } else { hit.m_damage.m_fire += value.OnHitElementalDamage.Value; } } } } [HarmonyPatch(typeof(Character), "GetDamageModifier")] private static class RaceResistancePatch { private static void Postfix(Character __instance, DamageType damageType, ref DamageModifier __result) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected I4, but got Unknown if (__result) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg)) { Dictionary dictionary = ParseResistances(cfg.Resistances.Value); if (dictionary.TryGetValue(damageType, out var value)) { __result = (DamageModifier)(int)value; } } } } [HarmonyPatch(typeof(Character), "Damage")] private static class RaceDamagePatch { private static void Prefix(Character __instance, HitData hit) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) if (hit == null) { return; } _ = hit.m_damage; if (false) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val != (Object)null && TryGetRaceConfig(val, out var cfg)) { if (cfg.DamageTakenMultiplier.Value != 1f) { ScaleDamage(ref hit.m_damage, cfg.DamageTakenMultiplier.Value); } if (RacialAbilitiesEnabled.Value && cfg.IronStanceEnabled.Value && cfg.IronStanceExtraDamageReduction.Value > 0f && ((Character)val).IsBlocking()) { float totalDamage = hit.GetTotalDamage(); ScaleDamage(ref hit.m_damage, 1f - cfg.IronStanceExtraDamageReduction.Value); hit.m_pushForce = 0f; AddEvolutionProgress(val, GetRace(val), totalDamage * cfg.IronStanceExtraDamageReduction.Value); } } Character attacker = hit.GetAttacker(); Player val2 = (Player)(object)((attacker is Player) ? attacker : null); if (!((Object)(object)val2 != (Object)null) || !TryGetRaceConfig(val2, out var cfg2)) { return; } string race = GetRace(val2); float num = cfg2.DamageDoneMultiplier.Value; Dictionary dictionary = ParseSkillMultipliers(cfg2.SkillDamageMultipliers.Value); if (dictionary.TryGetValue(hit.m_skill, out var value)) { num *= value; } if (RacialAbilitiesEnabled.Value && cfg2.LowHealthThreshold.Value > 0f && ((Character)val2).GetMaxHealth() > 0f && ((Character)val2).GetHealth() / ((Character)val2).GetMaxHealth() <= cfg2.LowHealthThreshold.Value) { num *= cfg2.LowHealthDamageBonus.Value; } if (num != 1f) { ScaleDamage(ref hit.m_damage, num); } Dictionary dictionary2 = ParseTypeMultipliers(cfg2.AttackDamageTypeMultipliers.Value); if (dictionary2.Count > 0) { ScaleDamageByType(ref hit.m_damage, dictionary2); } if (cfg2.BackstabMultiplier.Value != 1f) { hit.m_backstabBonus *= cfg2.BackstabMultiplier.Value; } if (hit.m_backstabBonus > 1f) { AddEvolutionProgress(val2, race, 1f); } if (RacialAbilitiesEnabled.Value && cfg2.BackstabStaminaRefundChance.Value > 0f && hit.m_backstabBonus > 1f && Random.value < cfg2.BackstabStaminaRefundChance.Value) { ((Character)val2).AddStamina(cfg2.BackstabStaminaRefundAmount.Value); AddEvolutionProgress(val2, race, 1f); } if (cfg2.KnockbackMultiplier.Value != 1f) { hit.m_pushForce *= cfg2.KnockbackMultiplier.Value; } if (cfg2.XpGainMultiplier.Value != 1f) { hit.m_skillRaiseAmount *= cfg2.XpGainMultiplier.Value; } if (cfg2.LifestealPercent.Value > 0f) { float totalDamage2 = hit.GetTotalDamage(); if (totalDamage2 > 0f) { ((Character)val2).Heal(totalDamage2 * cfg2.LifestealPercent.Value, false); } } } private static void Postfix(Character __instance, HitData hit) { if (hit == null || (Object)(object)__instance == (Object)null || !__instance.IsDead()) { return; } Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg)) { string race = GetRace(val); if (race == "orc") { AddEvolutionProgress(val, race, 1f); } if (race == "vampiro" && IsNightSafe()) { AddEvolutionProgress(val, race, 1f); } if (RacialAbilitiesEnabled.Value && !(cfg.OnKillHealAmount.Value <= 0f) && (!cfg.OnKillHealNightOnly.Value || IsNightSafe())) { ((Character)val).Heal(cfg.OnKillHealAmount.Value, false); } } } private static void ScaleDamageByType(ref DamageTypes dmg, Dictionary mults) { if (mults.TryGetValue((DamageType)1, out var value)) { dmg.m_blunt *= value; } if (mults.TryGetValue((DamageType)2, out var value2)) { dmg.m_slash *= value2; } if (mults.TryGetValue((DamageType)4, out var value3)) { dmg.m_pierce *= value3; } if (mults.TryGetValue((DamageType)8, out var value4)) { dmg.m_chop *= value4; } if (mults.TryGetValue((DamageType)16, out var value5)) { dmg.m_pickaxe *= value5; } if (mults.TryGetValue((DamageType)32, out var value6)) { dmg.m_fire *= value6; } if (mults.TryGetValue((DamageType)64, out var value7)) { dmg.m_frost *= value7; } if (mults.TryGetValue((DamageType)128, out var value8)) { dmg.m_lightning *= value8; } if (mults.TryGetValue((DamageType)256, out var value9)) { dmg.m_poison *= value9; } if (mults.TryGetValue((DamageType)512, out var value10)) { dmg.m_spirit *= value10; } } private static void ScaleDamage(ref DamageTypes dmg, float mult) { dmg.m_blunt *= mult; dmg.m_slash *= mult; dmg.m_pierce *= mult; dmg.m_chop *= mult; dmg.m_pickaxe *= mult; dmg.m_fire *= mult; dmg.m_frost *= mult; dmg.m_lightning *= mult; dmg.m_poison *= mult; dmg.m_spirit *= mult; } } [HarmonyPatch(typeof(Character), "GetStealthFactor")] private static class RaceStealthPatch { private static void Postfix(Character __instance, ref float __result) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg)) { __result *= cfg.StealthMultiplier.Value; } } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(int), typeof(bool), typeof(int), typeof(int) })] private static class RaceBlockFreezingStatusPatch { private static bool Prefix(SEMan __instance, int nameHash, ref StatusEffect __result) { if (nameHash != SEMan.s_statusEffectFreezing && nameHash != SEMan.s_statusEffectCold) { return true; } Character sEManOwner = GetSEManOwner(__instance); Player val = (Player)(object)((sEManOwner is Player) ? sEManOwner : null); if ((Object)(object)val == (Object)null || !TryGetRaceConfig(val, out var cfg) || cfg.HeatResistanceBonus.Value == 0f) { return true; } __result = null; return false; } } [HarmonyPatch(typeof(Character), "GetJogSpeedFactor")] private static class RaceJogSpeedPatch { private static void Postfix(Character __instance, ref float __result) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe())) { __result *= cfg.SpeedMultiplier.Value; } } } [HarmonyPatch(typeof(Character), "GetRunSpeedFactor")] private static class RaceRunSpeedPatch { private static void Postfix(Character __instance, ref float __result) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && (!cfg.NightOnlyBonuses.Value || IsNightSafe())) { __result *= cfg.SpeedMultiplier.Value; } } } [HarmonyPatch(typeof(Player), "GetEquipmentAttackStaminaModifier")] private static class RaceStaminaCostAttackPatch { private static void Postfix(Player __instance, ref float __result) { if (TryGetRaceConfig(__instance, out var cfg)) { __result += GetStaminaCostModifier(cfg, "Attack"); } } } [HarmonyPatch(typeof(Player), "GetEquipmentBlockStaminaModifier")] private static class RaceStaminaCostBlockPatch { private static void Postfix(Player __instance, ref float __result) { if (TryGetRaceConfig(__instance, out var cfg)) { __result += GetStaminaCostModifier(cfg, "Block"); } } } [HarmonyPatch(typeof(Player), "GetEquipmentDodgeStaminaModifier")] private static class RaceStaminaCostDodgePatch { private static void Postfix(Player __instance, ref float __result) { if (TryGetRaceConfig(__instance, out var cfg)) { __result += GetStaminaCostModifier(cfg, "Dodge"); } } } [HarmonyPatch(typeof(Player), "GetEquipmentJumpStaminaModifier")] private static class RaceStaminaCostJumpPatch { private static void Postfix(Player __instance, ref float __result) { if (TryGetRaceConfig(__instance, out var cfg)) { __result += GetStaminaCostModifier(cfg, "Jump"); } } } [HarmonyPatch(typeof(Player), "GetEquipmentRunStaminaModifier")] private static class RaceStaminaCostRunPatch { private static void Postfix(Player __instance, ref float __result) { if (TryGetRaceConfig(__instance, out var cfg)) { __result += GetStaminaCostModifier(cfg, "Run"); } } } [HarmonyPatch(typeof(Player), "GetEquipmentSneakStaminaModifier")] private static class RaceStaminaCostSneakPatch { private static void Postfix(Player __instance, ref float __result) { if (TryGetRaceConfig(__instance, out var cfg)) { __result += GetStaminaCostModifier(cfg, "Sneak"); } } } [HarmonyPatch(typeof(Player), "GetEquipmentSwimStaminaModifier")] private static class RaceStaminaCostSwimPatch { private static void Postfix(Player __instance, ref float __result) { if (TryGetRaceConfig(__instance, out var cfg)) { __result += GetStaminaCostModifier(cfg, "Swim"); } } } [HarmonyPatch(typeof(Player), "UseEitr")] private static class RaceEitrCostPatch { private static void Prefix(Player __instance, ref float v) { if (TryGetRaceConfig(__instance, out var cfg) && !cfg.NoResourceCost.Value && cfg.EitrCostMultiplier.Value != 1f) { v *= cfg.EitrCostMultiplier.Value; } } } [HarmonyPatch(typeof(Character), "TryUseEitr")] private static class RaceEitrCostTryPatch { private static void Prefix(Character __instance, ref float eitrUse) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && TryGetRaceConfig(val, out var cfg) && !cfg.NoResourceCost.Value && cfg.EitrCostMultiplier.Value != 1f) { eitrUse *= cfg.EitrCostMultiplier.Value; } } } public class RaceConfig { public string RaceId; public string DisplayName; public ConfigEntry Enabled; public ConfigEntry Scale; public ConfigEntry SkinColor; public ConfigEntry HairColor; public ConfigEntry EarColor; public ConfigEntry EyeColor; public ConfigEntry SecretCode; public ConfigEntry HealthBonus; public ConfigEntry StaminaBonus; public ConfigEntry EitrBonus; public ConfigEntry CarryWeightBonus; public ConfigEntry HealthRegenMultiplier; public ConfigEntry StaminaRegenMultiplier; public ConfigEntry EitrRegenMultiplier; public ConfigEntry DamageDoneMultiplier; public ConfigEntry SkillDamageMultipliers; public ConfigEntry BackstabMultiplier; public ConfigEntry DamageTakenMultiplier; public ConfigEntry LifestealPercent; public ConfigEntry StealthMultiplier; public ConfigEntry SpeedMultiplier; public ConfigEntry Resistances; public ConfigEntry NoResourceCost; public ConfigEntry XpGainMultiplier; public ConfigEntry KnockbackMultiplier; public ConfigEntry EitrCostMultiplier; public ConfigEntry StaminaCostModifiers; public ConfigEntry AttackDamageTypeMultipliers; public ConfigEntry NightOnlyBonuses; public ConfigEntry DayNightHealthShift; public ConfigEntry BiomeHealthShifts; public ConfigEntry HeatResistanceBonus; public ConfigEntry CrouchInvisible; public ConfigEntry CrouchInvisibleNightOnly; public ConfigEntry LowHealthThreshold; public ConfigEntry LowHealthDamageBonus; public ConfigEntry StillHealAura; public ConfigEntry StillHealAmount; public ConfigEntry StillHealInterval; public ConfigEntry StillHealRequiredStillTime; public ConfigEntry IronStanceEnabled; public ConfigEntry IronStanceExtraDamageReduction; public ConfigEntry BackstabStaminaRefundChance; public ConfigEntry BackstabStaminaRefundAmount; public ConfigEntry TremorEnabled; public ConfigEntry TremorMinAirTime; public ConfigEntry TremorRadius; public ConfigEntry TremorKnockback; public ConfigEntry TremorFireDamage; public ConfigEntry TremorStaggerMultiplier; public ConfigEntry SecondWindEnabled; public ConfigEntry SecondWindThreshold; public ConfigEntry SecondWindHealAmount; public ConfigEntry SecondWindStaminaAmount; public ConfigEntry SecondWindCooldown; public ConfigEntry OnKillHealAmount; public ConfigEntry EvolvesTo; public ConfigEntry EvolutionThreshold; public ConfigEntry OnKillHealNightOnly; public ConfigEntry StillHealDayOnly; public ConfigEntry BlockAuraEnabled; public ConfigEntry BlockAuraDamage; public ConfigEntry BlockAuraRadius; public ConfigEntry BlockAuraIsFrost; public ConfigEntry BlockAuraSlowEnabled; public ConfigEntry BlockAuraSlowPercent; public ConfigEntry BlockAuraSlowDuration; public ConfigEntry OnHitElementalEnabled; public ConfigEntry OnHitElementalDamage; public ConfigEntry FlightEnabled; public ConfigEntry FlightStaminaCostPerTick; public ConfigEntry FlightMinStaminaToStart; } [HarmonyPatch(typeof(Player), "IsDebugFlying")] private static class ForceIsDebugFlyingPatch { private static void Postfix(Player __instance, ref bool __result) { if (!__result && GetDebugFly(__instance)) { __result = true; } } } [HarmonyPatch(typeof(Humanoid), "StartAttack")] private static class BlockAttackWhileFlyingPatch { private static bool Prefix(Humanoid __instance) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val == (Object)null) { return true; } return !GetDebugFly(val) || !(GetRace(val) == "fada"); } } [HarmonyPatch(typeof(Character), "AddStamina")] private static class BlockStaminaRegenWhileFlyingPatch { private static bool Prefix(Character __instance, ref float v) { if (v <= 0f) { return true; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val == (Object)null) { return true; } return !GetDebugFly(val) || !(GetRace(val) == "fada"); } } [HarmonyPatch] private static class BlockStaminaRegenInUpdateStatsPatch { private static IEnumerable TargetMethods() { MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo m in methods) { if (m.Name == "UpdateStats") { yield return m; } } } private static void Prefix(Player __instance, out float __state) { __state = (GetDebugFly(__instance) ? __instance.GetStamina() : (-1f)); } private static void Postfix(Player __instance, float __state) { if (__state < 0f || !GetDebugFly(__instance) || __instance.GetStamina() <= __state || !(StaminaField != null)) { return; } try { StaminaField.SetValue(__instance, __state); } catch { } } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEventFailable <>9__31_0; public static ConsoleEventFailable <>9__32_0; public static ConsoleEventFailable <>9__39_0; internal object b__31_0(ConsoleEventArgs args) { if (!HasDevCommands()) { args.Context.AddString(Text_SemPermissao.Value); return false; } if ((Object)(object)ObjectDB.instance == (Object)null) { args.Context.AddString(Text_DebugObjectDBNaoCarregou.Value); return false; } args.Context.AddString(Text_DebugItensComFireStaff.Value); int num = 0; int num2 = 0; try { if (typeof(ObjectDB).GetField("m_items", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(ObjectDB.instance) is List 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 b__32_0(ConsoleEventArgs args) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { args.Context.AddString(Text_DebugPlayerNaoCarregadoSimples.Value); return false; } try { FieldInfo fieldInfo = AccessTools.Field(typeof(Humanoid), "m_rightItem"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(Humanoid), "m_leftItem"); object? obj = fieldInfo?.GetValue(localPlayer); ItemData val = (ItemData)((obj is ItemData) ? obj : null); object? obj2 = fieldInfo2?.GetValue(localPlayer); ItemData val2 = (ItemData)((obj2 is ItemData) ? obj2 : null); ItemData val3 = val ?? val2; if (val3?.m_shared == null) { args.Context.AddString(Text_DebugNenhumaFerramenta.Value); return false; } string text = (((Object)(object)val3.m_shared.m_buildPieces != (Object)null) ? ((Object)val3.m_shared.m_buildPieces).name : "(nulo)"); args.Context.AddString(Fmt(Text_DebugFerramenta.Value, val3.m_shared.m_name)); args.Context.AddString(Fmt(Text_DebugPieceTableReal.Value, text)); if ((Object)(object)val3.m_shared.m_buildPieces != (Object)null) { List 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 b__39_0(ConsoleEventArgs args) { if (!HasDevCommands()) { args.Context.AddString(Text_SemPermissao.Value); return false; } if (args.Args.Length < 2) { args.Context.AddString(Text_UsoOfflineReset.Value); return false; } if (!long.TryParse(args.Args[1], out var result)) { args.Context.AddString(Text_IdInvalido.Value); return false; } bool flag = ResetOfflinePlayer(result); args.Context.AddString(flag ? Text_OfflineResetado.Value : Text_OfflineNaoEncontrado.Value); return flag; } } private static readonly FieldInfo ZNetSceneNamedPrefabsField = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs"); private static readonly HashSet PendingAltarSwitch = new HashSet(); private static readonly FieldInfo HelmetInstanceField = AccessTools.Field(typeof(VisEquipment), "m_helmetItemInstance"); private static readonly HashSet RegisteredSecretCodes = new HashSet(StringComparer.Ordinal); private static Player _cachedPreviewPlayerInstance; private static Vector3? _originalPreviewSkin; private static Vector3? _originalPreviewHair; private static string _sessionSelectedPreviewRace; private static bool _previewSkinForced; private static bool _previewHairForced; private static string _lastFullyAppliedRace; private static bool _lastAppliedIsFemale; public static bool UserJustClickedRacePending; private const string ZdoRagdollRaceKey = "ValheimRagdollRace"; private const string ModGUID = "valheim.races"; private const string ModName = "Valheim Races"; private const string ModVersion = "2.9.1"; private const string RaceOrc = "orc"; private const string RaceElf = "elfodaluz"; private const string RaceDarkElf = "elfodanoite"; private const string RaceDwarf = "anao"; private const string RaceHalfling = "halfling"; private const string RaceHuman = "humano"; private const string RaceJotun = "jotun"; private const string RaceVampire = "vampiro"; private const string RaceEfrit = "efrit"; private const string RaceFairy = "fada"; private const string ZdoRaceKey = "ValheimRace"; private const string ZdoEvoProgressKey = "ValheimEvoProgress"; private const string ZdoRaceVersionKey = "ValheimRaceVer"; private const int CurrentRaceDataVersion = 1; private const string ZdoLockedKey = "ValheimRaceLocked"; private const string ZdoEarColorKey = "ValheimRaceEarColor"; private const string ZdoSkinColorKey = "ValheimRaceSkinColor"; private const string RpcSetRace = "ValheimRaces_SetRace"; private const string RpcVersionCheck = "ValheimRaces_VersionCheck"; private const string RpcAdminSetRaceRequest = "ValheimRaces_AdminSetRaceRequest"; private static ConfigSync ModConfigSync; private const int FindHeadMaxDepth = 12; private const float RaceApplyMaxDistance = 60f; private static readonly WaitForSeconds Wait01 = new WaitForSeconds(0.1f); private static readonly WaitForSeconds Wait05 = new WaitForSeconds(0.5f); private static readonly WaitForSeconds Wait1 = new WaitForSeconds(1f); private static readonly WaitForSeconds Wait2 = new WaitForSeconds(2f); private static readonly WaitForSeconds WaitSkin005 = new WaitForSeconds(0.05f); private static readonly WaitForSeconds WaitSkin020 = new WaitForSeconds(0.2f); private static readonly WaitForSeconds WaitSkin050 = new WaitForSeconds(0.5f); private static readonly WaitForSeconds WaitSkin100 = new WaitForSeconds(1f); private readonly Harmony harmony = new Harmony("valheim.races"); public static ValheimRacesPlugin Instance; private static GameObject ElfEarsMalePrefab; private static GameObject ElfEarsFemalePrefab; private static GameObject OrcEarsMalePrefab; private static GameObject OrcEarsFemalePrefab; private static GameObject OrcTuskPrefab; private static GameObject HighElfEyesPrefab; private static GameObject HornMalePrefab; private static GameObject HornFemalePrefab; private static GameObject FairyBodyMalePrefab; private static GameObject FairyBodyFemalePrefab; private static bool IsApplyingRace = false; private static bool RpcRegistered = false; private static ZRoutedRpc RegisteredRpcInstance = null; private static readonly Dictionary NetworkRaces = new Dictionary(); private static readonly Dictionary LastAppliedRace = new Dictionary(); private static readonly Dictionary OriginalSkinColors = new Dictionary(); private static readonly Dictionary LastSkinRefreshRequest = new Dictionary(); private static readonly HashSet KnownAdmins = new HashSet(); private static readonly Dictionary HeadCache = new Dictionary(); private static readonly Dictionary HeadCacheRace = new Dictionary(); private static readonly Dictionary ApplyRaceCoroutineGeneration = new Dictionary(); private static readonly Dictionary ZNetViewCache = new Dictionary(); private float timer = 0f; private float syncTimer = 0f; private float localSaveTimer = 0f; private float adminCacheTimer = 0f; private float configWatchTimer = 0f; private DateTime _lastConfigWrite = DateTime.MinValue; private bool isRestoringLocalRace = false; private string lastBroadcastRace = null; private static string _cachedSavePrefix = null; private static long _cachedCharacterId = 0L; private static string _cachedServerKey = null; private static ZNet _cachedZNetInstance = null; private static readonly Vector3 HumanScale = Vector3.one; private static readonly Vector3 InvalidColor = new Vector3(-1f, -1f, -1f); private static readonly Vector3 HighElfEyesPosition = new Vector3(-0.0063f, -0.0194f, -0.00017f); private static readonly Vector3 HighElfEyesRotation = new Vector3(-18.776f, -89.449f, -0.691f); private static readonly Vector3 HighElfEyesScale = new Vector3(0.00993f, 0.011539f, 0.01272f); private static readonly Vector3 OrcTuskPosition = new Vector3(-0.00137f, 0.00114f, -0.00014f); private static readonly Vector3 OrcTuskRotation = new Vector3(-16.932f, -110.817f, 8.571f); private static readonly Vector3 OrcTuskScale = new Vector3(0.00494f, 0.005076f, 0.00559f); private static readonly string[] SuppressedLogSubstrings = new string[5] { "Failed to find expected binary shader data in 'Custom/Player'", "Failed to find expected binary shader data in 'Custom/Creature'", "Failed to find expected binary shader data in 'Custom/Piece'", "Failed to find expected binary shader data in 'Lux Lit Particles/", "Failed to find expected binary shader data in 'Particles/Standard" }; private bool _isReloadingConfig; private static readonly Dictionary StillLastPos = new Dictionary(); private static readonly Dictionary StillTimer = new Dictionary(); private static readonly Dictionary StillHealTimer = new Dictionary(); private static readonly Dictionary SecondWindCooldownTimer = new Dictionary(); private static readonly Dictionary TremorAirTime = new Dictionary(); private static readonly Dictionary TremorWasOnGround = new Dictionary(); private static bool _envNightWarningLogged; private const float BonusRegenSeconds = 30f; private static readonly Dictionary ChilledStatus = new Dictionary(); private static float _lastChilledPurgeTime; private static readonly Dictionary DamageTypeNames = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "Blunt", (DamageType)1 }, { "Slash", (DamageType)2 }, { "Pierce", (DamageType)4 }, { "Chop", (DamageType)8 }, { "Pickaxe", (DamageType)16 }, { "Fire", (DamageType)32 }, { "Frost", (DamageType)64 }, { "Lightning", (DamageType)128 }, { "Poison", (DamageType)256 }, { "Spirit", (DamageType)512 } }; private static readonly Dictionary ModifierNames = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "Normal", (DamageModifier)0 }, { "Resistant", (DamageModifier)1 }, { "Weak", (DamageModifier)2 }, { "Immune", (DamageModifier)3 }, { "Ignore", (DamageModifier)4 }, { "VeryResistant", (DamageModifier)5 }, { "VeryWeak", (DamageModifier)6 }, { "SlightlyResistant", (DamageModifier)7 }, { "SlightlyWeak", (DamageModifier)8 } }; private static FieldInfo _semanCharacterField; public static readonly Dictionary Races = new Dictionary(); private static ConfigFile MainConfigFile; public static ConfigEntry EyeGlowPeak; public static ConfigEntry EmoteOnTransform; public static ConfigEntry VfxOnTransform; public static ConfigEntry FillVitalsOnTransform; public static ConfigEntry RacialAbilitiesEnabled; private static GameObject AltarPrefab; public static ConfigEntry AltarRaces; public static ConfigEntry AltarRecipe; public static ConfigEntry AltarSwitchCostItem; public static ConfigEntry AltarSwitchCostAmount; public static ConfigEntry FlightToggleKey; private static readonly Dictionary FairyEyebrowRenderers = new Dictionary(); private static readonly Dictionary FairyEyebrowShared = new Dictionary(); private static readonly Dictionary FairyBodyAnimators = new Dictionary(); private static readonly FieldInfo DebugFlyField = AccessTools.Field(typeof(Player), "m_debugFly"); private static readonly FieldInfo DebugFlySpeedField = AccessTools.Field(typeof(Character), "m_debugFlySpeed"); private static readonly FieldInfo RunSpeedField = AccessTools.Field(typeof(Character), "m_runSpeed"); private static readonly FieldInfo MoveDirField = AccessTools.Field(typeof(Character), "m_moveDir"); private static readonly FieldInfo MaxAirAltitudeField = AccessTools.Field(typeof(Character), "m_maxAirAltitude"); private static readonly Dictionary OriginalDebugFlySpeed = new Dictionary(); private static KeyCode? _cachedFlightKey; private static string _cachedFlightKeyRaw; private static readonly FieldInfo StaminaField = AccessTools.Field(typeof(Player), "m_stamina"); private static readonly Dictionary RaceStatusEffects = new Dictionary(); private static Sprite _placeholderIcon; private static bool _placeholderIconResolved; private const string RaceIconResourceName = "race_icon.rgba"; private const int RaceIconSize = 128; private static readonly Dictionary RaceSpecificIcons = new Dictionary(); private const string ColorAccent = "#E8A33D"; private const string ColorAbilityBuff = "#8CFF8C"; private const string ColorAbilityDebuff = "#FF8C8C"; private static ConfigFile TextConfigFile; public static ConfigEntry Text_AltarNome; public static ConfigEntry Text_AltarDescricao; public static ConfigEntry Text_AltarHoverEscolher; public static ConfigEntry Text_AltarHoverTrocar; public static ConfigEntry Text_UiEscolhaTitulo; public static ConfigEntry Text_UiFechar; public static ConfigEntry Text_UiTrocarBotao; public static ConfigEntry Text_UiJaEscolheuTitulo; public static ConfigEntry Text_UiMoedaInsuficiente; public static ConfigEntry Text_UiNenhumaRacaDisponivel; public static readonly Dictionary> RaceNameTexts = new Dictionary>(); public static ConfigEntry Text_SemPermissao; public static ConfigEntry Text_UsoRaca; public static ConfigEntry Text_RacaDesativadaAdmin; public static ConfigEntry Text_PlayerNaoEncontrado; public static ConfigEntry Text_PlayerNaoCarregado; public static ConfigEntry Text_AgoraERaca; public static ConfigEntry Text_RacaRemovida; public static ConfigEntry Text_UsoOfflineReset; public static ConfigEntry Text_IdInvalido; public static ConfigEntry Text_OfflineResetado; public static ConfigEntry Text_OfflineNaoEncontrado; public static ConfigEntry Text_EssaRacaDesativada; public static ConfigEntry Text_AgoraEuSou; public static ConfigEntry Text_ConfigRecarregado; public static ConfigEntry Text_CodigosSecretosAtivos; public static ConfigEntry Text_VersaoDiferente; public static ConfigEntry Text_DebugObjectDBNaoCarregou; public static ConfigEntry Text_DebugItensComFireStaff; public static ConfigEntry Text_DebugTotalItens; public static ConfigEntry Text_DebugNenhumEncontrado; public static ConfigEntry Text_DebugPlayerNaoCarregadoSimples; public static ConfigEntry Text_DebugNenhumaFerramenta; public static ConfigEntry Text_DebugFerramenta; public static ConfigEntry Text_DebugPieceTableReal; public static ConfigEntry Text_DebugTotalPecas; public static ConfigEntry Text_DebugEstacaoPerto; public static ConfigEntry Text_DebugNenhumaEstacao; public static ConfigEntry Text_DebugErro; public static ConfigEntry Text_VoceEvoluiu; public static ConfigEntry Text_StatNomeRaca; public static ConfigEntry Text_StatVidaMaxima; public static ConfigEntry Text_StatStaminaMaxima; public static ConfigEntry Text_StatEitrMaximo; public static ConfigEntry Text_StatCapacidadeCarga; public static ConfigEntry Text_StatRegenVida; public static ConfigEntry Text_StatRegenStamina; public static ConfigEntry Text_StatRegenEitr; public static ConfigEntry Text_StatDanoCausado; public static ConfigEntry Text_StatDanoComSkill; public static ConfigEntry Text_StatDanoTipo; public static ConfigEntry Text_StatDanoAtaqueFurtivo; public static ConfigEntry Text_StatForcaEmpurrao; public static ConfigEntry Text_StatDanoRecebido; public static ConfigEntry Text_StatVelocidade; public static ConfigEntry Text_StatFurtividade; public static ConfigEntry Text_StatRouboVida; public static ConfigEntry Text_StatGanhoXP; public static ConfigEntry Text_StatRegenVelocidadeNoite; public static ConfigEntry Text_StatSoANoite; public static ConfigEntry Text_StatVidaNoiteDia; public static ConfigEntry Text_StatVidaBioma; public static ConfigEntry Text_StatFrioAmbiente; public static ConfigEntry Text_StatNaoCongela; public static ConfigEntry Text_StatModificadorDano; public static ConfigEntry Text_StatSemBonus; public static ConfigEntry Text_NivelImune; public static ConfigEntry Text_NivelMuitoResistente; public static ConfigEntry Text_NivelResistente; public static ConfigEntry Text_NivelLevementeResistente; public static ConfigEntry Text_NivelLevementeFraco; public static ConfigEntry Text_NivelFraco; public static ConfigEntry Text_NivelMuitoFraco; public static ConfigEntry Text_NivelIgnora; public static ConfigEntry Text_DanoBlunt; public static ConfigEntry Text_DanoSlash; public static ConfigEntry Text_DanoPierce; public static ConfigEntry Text_DanoChop; public static ConfigEntry Text_DanoPickaxe; public static ConfigEntry Text_DanoFire; public static ConfigEntry Text_DanoFrost; public static ConfigEntry Text_DanoLightning; public static ConfigEntry Text_DanoPoison; public static ConfigEntry Text_DanoSpirit; public static ConfigEntry Text_BiomaMeadows; public static ConfigEntry Text_BiomaBlackForest; public static ConfigEntry Text_BiomaSwamp; public static ConfigEntry Text_BiomaMountain; public static ConfigEntry Text_BiomaPlains; public static ConfigEntry Text_BiomaMistlands; public static ConfigEntry Text_BiomaAshLands; public static ConfigEntry Text_BiomaDeepNorth; public static ConfigEntry Text_BiomaOcean; public static ConfigEntry Text_HabFuriaSangue; public static ConfigEntry Text_HabFuriaSangueDesc; public static ConfigEntry Text_HabAuraCura; public static ConfigEntry Text_HabAuraCuraDesc; public static ConfigEntry Text_HabAuraCuraSoDeDia; public static ConfigEntry Text_HabPosturaFerro; public static ConfigEntry Text_HabPosturaFerroDesc; public static ConfigEntry Text_HabGolpeOportunidade; public static ConfigEntry Text_HabGolpeOportunidadeDesc; public static ConfigEntry Text_HabSegundoFolego; public static ConfigEntry Text_HabSegundoFolegoDesc; public static ConfigEntry Text_HabSedeSangue; public static ConfigEntry Text_HabSedeSangueDesc; public static ConfigEntry Text_HabSedeSangueSoDeNoite; public static ConfigEntry Text_HabMantoSombras; public static ConfigEntry Text_HabMantoSombrasDesc; public static ConfigEntry Text_HabMantoSombrasSoDeNoite; public static ConfigEntry Text_HabTremor; public static ConfigEntry Text_HabTremorDesc; public static ConfigEntry Text_HabAuraChamas; public static ConfigEntry Text_HabAuraChamasDesc; public static ConfigEntry Text_HabSoproGlacial; public static ConfigEntry Text_HabSoproGlacialDesc; public static ConfigEntry Text_HabToqueFlamejante; public static ConfigEntry Text_HabToqueFlamejanteDesc; public static ConfigEntry Text_HabToqueGelado; public static ConfigEntry Text_HabToqueGeladoDesc; public static ConfigEntry Text_HabVoo; public static ConfigEntry Text_HabVooDesc; public static ConfigEntry Text_VooSemStamina; private static readonly FieldInfo ModelIndexField = AccessTools.Field(typeof(VisEquipment), "m_modelIndex"); private static readonly MethodInfo SetSkinColorMethod = AccessTools.Method(typeof(VisEquipment), "SetSkinColor", (Type[])null, (Type[])null); private static readonly MethodInfo SetHairColorMethod = AccessTools.Method(typeof(VisEquipment), "SetHairColor", (Type[])null, (Type[])null); private static readonly FieldInfo SkinColorField = AccessTools.Field(typeof(VisEquipment), "m_skinColor"); private void RegisterAltarPiece() { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)AltarPrefab == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[ValheimRaces] Prefab 'altar_racas' não encontrado — peça do Altar das Raças não registrada."); return; } if ((Object)(object)AltarPrefab.GetComponent() == (Object)null) { AltarPrefab.AddComponent(); } if ((Object)(object)AltarPrefab.GetComponent() == (Object)null) { AltarPrefab.AddComponent(); } if ((Object)(object)AltarPrefab.GetComponent() == (Object)null) { AltarPrefab.AddComponent(); } if ((Object)(object)AltarPrefab.GetComponentInChildren() == (Object)null) { Renderer componentInChildren = AltarPrefab.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { BoxCollider val = AltarPrefab.AddComponent(); 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() ?? AltarPrefab.AddComponent(); 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 list = new List(); 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() : 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() : null); if ((Object)(object)val2 != (Object)null) { list.Add(new Requirement { m_resItem = val2, m_amount = 10, m_recover = true }); } } return list.ToArray(); } public static bool HasChosenRaceViaAltar(Player p) { return IsPlayerLocked(p); } public static bool HasPendingAltarSwitch(Player p) { if ((Object)(object)p == (Object)null) { return false; } long playerIdLong = GetPlayerIdLong(p); return playerIdLong != 0L && PendingAltarSwitch.Contains(playerIdLong); } public static void ChooseRaceFromAltar(string race) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)Instance == (Object)null) { return; } long playerIdLong = GetPlayerIdLong(localPlayer); bool flag = playerIdLong != 0L && PendingAltarSwitch.Contains(playerIdLong); if (!HasChosenRaceViaAltar(localPlayer) || flag) { if (flag) { PendingAltarSwitch.Remove(playerIdLong); } TransformLocalPlayerFromMarketplace(race); } } public static void SwitchRaceFromAltar(Player p) { if (!((Object)(object)Instance == (Object)null) && !((Object)(object)p == (Object)null)) { long playerIdLong = GetPlayerIdLong(p); if (playerIdLong != 0) { PendingAltarSwitch.Add(playerIdLong); } } } private void ApplyRaceWithDelays(Player p) { if (!((Object)(object)p == (Object)null)) { ApplyRace(p); if (!IsHeadless()) { int instanceID = ((Object)p).GetInstanceID(); int value; int num = ((!ApplyRaceCoroutineGeneration.TryGetValue(instanceID, out value)) ? 1 : (value + 1)); ApplyRaceCoroutineGeneration[instanceID] = num; ((MonoBehaviour)this).StartCoroutine(ApplyRaceDelayed(p, Wait01, num)); ((MonoBehaviour)this).StartCoroutine(ApplyRaceDelayed(p, Wait05, num)); ((MonoBehaviour)this).StartCoroutine(ApplyRaceDelayed(p, Wait1, num)); ((MonoBehaviour)this).StartCoroutine(ApplyRaceDelayed(p, Wait2, num)); } } } private IEnumerator ApplyRaceDelayed(Player p, WaitForSeconds wait, int generation) { yield return wait; if (!((Object)(object)p == (Object)null)) { int instanceId = ((Object)p).GetInstanceID(); if (ApplyRaceCoroutineGeneration.TryGetValue(instanceId, out var current) && current == generation) { ApplyRace(p); } } } private void QueueSkinRefresh(Player p, string race) { if (!IsHeadless() && !((Object)(object)p == (Object)null) && !string.IsNullOrWhiteSpace(race)) { string text = GetVisualKey(p); if (string.IsNullOrWhiteSpace(text)) { text = ((Object)p).GetInstanceID().ToString(); } float time = Time.time; if (!LastSkinRefreshRequest.TryGetValue(text, out var value) || !(time - value < 1.25f)) { LastSkinRefreshRequest[text] = time; ((MonoBehaviour)this).StartCoroutine(ForceSkinRefresh(p, race)); } } } private IEnumerator ForceSkinRefresh(Player p, string race) { yield return null; ForceSkinNow(p, race); yield return WaitSkin005; ForceSkinNow(p, race); yield return WaitSkin020; ForceSkinNow(p, race); yield return WaitSkin050; ForceSkinNow(p, race); yield return WaitSkin100; ForceSkinNow(p, race); } private void ForceSkinNow(Player p, string race) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null || string.IsNullOrWhiteSpace(race) || GetRace(p) != race) { return; } bool isApplyingRace = IsApplyingRace; IsApplyingRace = true; try { if (RaceUsesForcedSkin(race)) { ApplySkin(p, GetNetworkSkinColor(p, race)); } Color color = ToColor(GetRaceEarColor(p, race)); if (race == "orc" || race == "jotun") { ApplyOrcEars(p, color); } else if (race == "elfodanoite" || race == "elfodaluz" || race == "halfling") { ApplyEars(p, color); } Transform cachedHead = GetCachedHead(p, race); Transform val = ((cachedHead != null) ? cachedHead.Find("HighElfEyes") : null); if ((Object)(object)val != (Object)null) { ApplyEyeColor(val, GetRaceEyeColor(race)); } } finally { IsApplyingRace = isApplyingRace; } } public void RequestOnlineVisualRefresh(Player p) { if (IsHeadless() || (Object)(object)p == (Object)null) { return; } string race = GetRace(p); if (!string.IsNullOrWhiteSpace(race)) { ApplyRaceWithDelays(p); if (RaceUsesForcedSkin(race) || race == "elfodaluz" || race == "halfling" || race == "vampiro") { QueueSkinRefresh(p, race); } } } public void RequestOnlineVisualRefresh(VisEquipment vis) { if (!IsHeadless() && !((Object)(object)vis == (Object)null)) { Player val = ((Component)vis).GetComponent() ?? ((Component)vis).GetComponentInParent(); 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() ?? ((Component)vis).GetComponentInParent(); if (!((Object)(object)val == (Object)null)) { string race = GetRace(val); if (RaceUsesForcedSkin(race) || race == "elfodaluz" || race == "halfling" || race == "vampiro") { QueueSkinRefresh(val, race); } } } private Transform GetCachedHead(Player p, string race) { if ((Object)(object)p == (Object)null) { return null; } int instanceID = ((Object)p).GetInstanceID(); if (HeadCache.TryGetValue(instanceID, out var value) && HeadCacheRace.TryGetValue(instanceID, out var value2) && value2 == race && (Object)(object)value != (Object)null) { return value; } Transform val = FindHead(((Component)p).transform, 0); HeadCache[instanceID] = val; HeadCacheRace[instanceID] = race; return val; } private static void InvalidateHeadCache(Player p) { if (!((Object)(object)p == (Object)null)) { int instanceID = ((Object)p).GetInstanceID(); HeadCache.Remove(instanceID); HeadCacheRace.Remove(instanceID); } } private static ZNetView GetCachedZNetView(Player player) { if ((Object)(object)player == (Object)null) { return null; } int instanceID = ((Object)player).GetInstanceID(); if (ZNetViewCache.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null) { return value; } ZNetView component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { ZNetViewCache[instanceID] = component; } return component; } public void ApplyRace(Player p) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_056f: Unknown result type (might be due to invalid IL or missing references) //IL_0574: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_04b4: Unknown result type (might be due to invalid IL or missing references) //IL_04e2: Unknown result type (might be due to invalid IL or missing references) //IL_04e7: Unknown result type (might be due to invalid IL or missing references) //IL_0533: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null || IsApplyingRace || GetPlayerIdLong(p) == 0) { return; } bool flag = IsHeadless(); string race = GetRace(p); string visualKey = GetVisualKey(p); string value = ""; if (!string.IsNullOrWhiteSpace(visualKey)) { LastAppliedRace.TryGetValue(visualKey, out value); } bool flag2 = value != race; IsApplyingRace = true; try { if (flag2) { InvalidateHeadCache(p); if (value == "fada") { ForceLandIfFlying(p); } if (!flag) { ResetScaledHelmet(p); } ApplyScale(p, HumanScale); if (!flag) { if (RaceUsesForcedSkin(value)) { ResetSkin(p); } Transform cachedHead = GetCachedHead(p, race); RemoveHeadAttachmentDirect(((Component)p).transform, "Ears"); RemoveHeadAttachmentDirect(((Component)p).transform, "OrcEars"); RemoveHeadAttachmentDirect(cachedHead, "HighElfEyes"); RemoveHeadAttachmentDirect(cachedHead, "OrcTusk"); RemoveHeadAttachmentDirect(((Component)p).transform, "Horn"); RemovePlayerAttachment(p, "JotunFreeze"); if (value == "fada") { RemoveFairyBodyDirect(((Component)p).transform); } } if (!string.IsNullOrWhiteSpace(visualKey)) { LastAppliedRace[visualKey] = race; } UpdateRaceStatusEffect(p, race); } if (string.IsNullOrWhiteSpace(race) || !IsRaceEnabled(race)) { ApplyScale(p, HumanScale); if (!flag && flag2) { string visualKey2 = GetVisualKey(p); if (!string.IsNullOrWhiteSpace(visualKey2) && OriginalSkinColors.TryGetValue(visualKey2, out var value2)) { ApplySkin(p, value2); } else { ApplySkin(p, Vector3.one); } ResetHelmet(p); Transform head = FindHead(((Component)p).transform, 0); RemoveHeadAttachmentDirect(((Component)p).transform, "Ears"); RemoveHeadAttachmentDirect(((Component)p).transform, "OrcEars"); RemoveHeadAttachmentDirect(head, "HighElfEyes"); RemoveHeadAttachmentDirect(head, "OrcTusk"); RemoveHeadAttachmentDirect(((Component)p).transform, "Horn"); RemovePlayerAttachment(p, "JotunFreeze"); RemoveFairyBodyDirect(((Component)p).transform); } return; } ApplyScale(p, GetRaceScale(race)); ScaleCurrentHelmetForRace(p, GetRaceScale(race)); if (!flag) { if (RaceUsesForcedSkin(race)) { CacheOriginalSkinIfNeeded(p); ApplySkin(p, GetNetworkSkinColor(p, race)); QueueSkinRefresh(p, race); } if (RaceUsesForcedHair(race)) { ApplyHair(p, GetRaceHairColor(race)); } Transform cachedHead2 = GetCachedHead(p, race); bool isFemale = IsFemaleModel(p); switch (race) { case "orc": ApplyOrcEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale); ApplyHighElfEyesDirect(p, cachedHead2); ApplyOrcTuskDirect(cachedHead2); break; case "elfodanoite": case "elfodaluz": case "halfling": ApplyEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale); QueueSkinRefresh(p, race); ApplyHighElfEyesDirect(p, cachedHead2); break; case "anao": ApplyHighElfEyesDirect(p, cachedHead2); break; case "humano": ApplyHighElfEyesDirect(p, cachedHead2); break; case "jotun": ApplyOrcEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale); ApplyHighElfEyesDirect(p, cachedHead2); break; case "vampiro": ApplyHighElfEyesDirect(p, cachedHead2); QueueSkinRefresh(p, race); break; case "efrit": ApplyEarsDirect(((Component)p).transform, ToColor(GetRaceEarColor(p, race)), isFemale); ApplyHornDirect(((Component)p).transform, isFemale); ApplyHighElfEyesDirect(p, cachedHead2); QueueSkinRefresh(p, race); break; case "fada": ApplyFairyBodyDirect(((Component)p).transform, isFemale); break; } } } finally { IsApplyingRace = false; } } public void SpawnEffect(Player p) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if (VfxOnTransform != null && VfxOnTransform.Value && !IsHeadless() && !((Object)(object)p == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null)) { Vector3 val = ((Component)p).transform.position + Vector3.up; Quaternion rotation = ((Component)p).transform.rotation; GameObject prefab = ZNetScene.instance.GetPrefab("vfx_spawn_large"); GameObject prefab2 = ZNetScene.instance.GetPrefab("fx_Fader_Roar_Projectile_Hit"); if ((Object)(object)prefab != (Object)null) { Object.Instantiate(prefab, val, rotation); } if ((Object)(object)prefab2 != (Object)null) { Object.Instantiate(prefab2, val, rotation); } } } private static void ScaleCurrentHelmetForRace(Player p, Vector3 targetScale) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null || IsHeadless()) { return; } try { VisEquipment component = ((Component)p).GetComponent(); object? obj = HelmetInstanceField?.GetValue(component); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if (!((Object)(object)val == (Object)null)) { HelmetScaleMarker helmetScaleMarker = val.GetComponent(); if ((Object)(object)helmetScaleMarker == (Object)null) { helmetScaleMarker = val.AddComponent(); helmetScaleMarker.OriginalScale = val.transform.localScale; helmetScaleMarker.OriginalPosition = val.transform.localPosition; helmetScaleMarker.AppliedScale = Vector3.one; } if (!(helmetScaleMarker.AppliedScale == targetScale)) { val.transform.localScale = Vector3.Scale(helmetScaleMarker.OriginalScale, targetScale); val.transform.localPosition = helmetScaleMarker.OriginalPosition; helmetScaleMarker.AppliedScale = targetScale; } } } catch (Exception ex) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] Falha ao escalar capacete: " + ex.Message)); } } } private void ResetHelmet(Player p) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ScaleCurrentHelmetForRace(p, Vector3.one); } private void ResetScaledHelmet(Player p) { ResetHelmet(p); } private static void ApplyScale(Player p, Vector3 scale) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)p == (Object)null)) { ((Component)p).transform.localScale = scale; } } private void RegisterCommands() { RegisterRaceCommand("orc"); RegisterRaceCommand("elfodaluz"); RegisterRaceCommand("elfodanoite"); RegisterRaceCommand("anao"); RegisterRaceCommand("halfling"); RegisterRaceCommand("humano"); RegisterRaceCommand("jotun"); RegisterRaceCommand("vampiro"); RegisterRaceCommand("efrit"); RegisterRaceCommand("fada"); RegisterResetRaceCommand(); RegisterOfflineResetCommand(); ReRegisterSecretCodeCommands(); RegisterReloadCommand(); RegisterListFireItemsCommand(); RegisterWhatPieceTableCommand(); } private void RegisterListFireItemsCommand() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown object obj = <>c.<>9__31_0; if (obj == null) { ConsoleEventFailable val = delegate(ConsoleEventArgs args) { if (!HasDevCommands()) { args.Context.AddString(Text_SemPermissao.Value); return false; } if ((Object)(object)ObjectDB.instance == (Object)null) { args.Context.AddString(Text_DebugObjectDBNaoCarregou.Value); return false; } args.Context.AddString(Text_DebugItensComFireStaff.Value); int num = 0; int num2 = 0; try { if (typeof(ObjectDB).GetField("m_items", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(ObjectDB.instance) is List list) { num2 = list.Count; foreach (GameObject item in list) { if (!((Object)(object)item == (Object)null)) { string name = ((Object)item).name; if (name.ToLowerInvariant().Contains("fire") || name.ToLowerInvariant().Contains("staff")) { args.Context.AddString(" " + name); num++; } } } } } catch (Exception ex) { args.Context.AddString(Fmt(Text_DebugErro.Value, ex.Message)); } args.Context.AddString(Fmt(Text_DebugTotalItens.Value, num2)); if (num == 0) { args.Context.AddString(Text_DebugNenhumEncontrado.Value); } return true; }; <>c.<>9__31_0 = val; obj = (object)val; } ConsoleEventFailable val2 = (ConsoleEventFailable)obj; new ConsoleCommand("listfireitems", "Lista itens com fire/staff no nome (debug)", val2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private void RegisterWhatPieceTableCommand() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown object obj = <>c.<>9__32_0; if (obj == null) { ConsoleEventFailable val = delegate(ConsoleEventArgs args) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { args.Context.AddString(Text_DebugPlayerNaoCarregadoSimples.Value); return false; } try { FieldInfo fieldInfo = AccessTools.Field(typeof(Humanoid), "m_rightItem"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(Humanoid), "m_leftItem"); object? obj2 = fieldInfo?.GetValue(localPlayer); ItemData val3 = (ItemData)((obj2 is ItemData) ? obj2 : null); object? obj3 = fieldInfo2?.GetValue(localPlayer); ItemData val4 = (ItemData)((obj3 is ItemData) ? obj3 : null); ItemData val5 = val3 ?? val4; if (val5?.m_shared == null) { args.Context.AddString(Text_DebugNenhumaFerramenta.Value); return false; } string text = (((Object)(object)val5.m_shared.m_buildPieces != (Object)null) ? ((Object)val5.m_shared.m_buildPieces).name : "(nulo)"); args.Context.AddString(Fmt(Text_DebugFerramenta.Value, val5.m_shared.m_name)); args.Context.AddString(Fmt(Text_DebugPieceTableReal.Value, text)); if ((Object)(object)val5.m_shared.m_buildPieces != (Object)null) { List pieces = val5.m_shared.m_buildPieces.m_pieces; args.Context.AddString(Fmt(Text_DebugTotalPecas.Value, pieces.Count)); } CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); args.Context.AddString(((Object)(object)currentCraftingStation != (Object)null) ? Fmt(Text_DebugEstacaoPerto.Value, ((Object)currentCraftingStation).name) : Text_DebugNenhumaEstacao.Value); } catch (Exception ex) { args.Context.AddString(Fmt(Text_DebugErro.Value, ex.Message)); } return true; }; <>c.<>9__32_0 = val; obj = (object)val; } ConsoleEventFailable val2 = (ConsoleEventFailable)obj; new ConsoleCommand("whatpiecetable", "Mostra o nome real da PieceTable do item equipado (debug)", val2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private void RegisterReloadCommand() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("reloadracas", "Recarrega os codigos secretos do config", (ConsoleEventFailable)delegate(ConsoleEventArgs args) { if (!HasDevCommands()) { args.Context.AddString(Text_SemPermissao.Value); return false; } MainConfigFile.Reload(); NetworkRaces.Clear(); ZNetViewCache.Clear(); foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null)) { string visualKey = GetVisualKey(allPlayer); if (!string.IsNullOrWhiteSpace(visualKey)) { LastAppliedRace[visualKey] = ""; } InvalidateHeadCache(allPlayer); Instance.ApplyRaceWithDelays(allPlayer); } } ReRegisterSecretCodeCommands(); args.Context.AddString(Text_ConfigRecarregado.Value); args.Context.AddString(Text_CodigosSecretosAtivos.Value); foreach (KeyValuePair race in Races) { string value = race.Value.SecretCode.Value; if (!string.IsNullOrWhiteSpace(value)) { args.Context.AddString(" " + GetRaceName(race.Value.RaceId) + " → " + value); } } return true; }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private void ReRegisterSecretCodeCommands() { foreach (KeyValuePair race in Races) { string value = race.Value.SecretCode.Value; string key = race.Key; if (!string.IsNullOrWhiteSpace(value) && !RegisteredSecretCodes.Contains(value)) { RegisterSecretCodeCommand(value, key); RegisteredSecretCodes.Add(value); } } } private void RegisterSecretCodeCommand(string code, string race) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand(code, "", (ConsoleEventFailable)delegate { TransformLocalPlayerFromMarketplace(race); return true; }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private void RegisterRaceCommand(string race) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand(race, race + " me ou " + race + " NomeDoPlayer", (ConsoleEventFailable)delegate(ConsoleEventArgs args) { if (!HasDevCommands()) { args.Context.AddString(Text_SemPermissao.Value); return false; } if (!IsRaceEnabled(race)) { args.Context.AddString(Fmt(Text_RacaDesativadaAdmin.Value, GetRaceName(race))); return false; } if (args.Args.Length < 2) { args.Context.AddString(Fmt(Text_UsoRaca.Value, race)); return false; } Player targetPlayer = GetTargetPlayer(args); if ((Object)(object)targetPlayer == (Object)null) { args.Context.AddString(Text_PlayerNaoEncontrado.Value); return false; } AdminSetRace(targetPlayer, race); args.Context.AddString(Fmt(Text_AgoraERaca.Value, targetPlayer.GetPlayerName(), GetRaceName(race))); return true; }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private void RegisterResetRaceCommand() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) ConsoleEventFailable val = (ConsoleEventFailable)delegate(ConsoleEventArgs args) { if (!HasDevCommands()) { args.Context.AddString(Text_SemPermissao.Value); return false; } if (args.Args.Length < 2) { args.Context.AddString(Fmt(Text_UsoRaca.Value, args.Args[0])); return false; } Player targetPlayer = GetTargetPlayer(args); if ((Object)(object)targetPlayer == (Object)null) { args.Context.AddString(Text_PlayerNaoEncontrado.Value); return false; } long playerIdLong = GetPlayerIdLong(targetPlayer); if (playerIdLong == 0) { args.Context.AddString(Fmt(Text_PlayerNaoCarregado.Value, targetPlayer.GetPlayerName())); return false; } ResetRace(targetPlayer, broadcast: true); args.Context.AddString(Fmt(Text_RacaRemovida.Value, targetPlayer.GetPlayerName())); return true; }; new ConsoleCommand("racareset", "racareset me ou racareset NomeDoPlayer", val, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private Player GetTargetPlayer(ConsoleEventArgs args) { string typedName = string.Join(" ", args.Args.Skip(1)).Trim(); if (typedName.Equals("me", StringComparison.OrdinalIgnoreCase)) { return Player.m_localPlayer; } return ((IEnumerable)Player.GetAllPlayers()).FirstOrDefault((Func)((Player p) => (Object)(object)p != (Object)null && p.GetPlayerName().Equals(typedName, StringComparison.OrdinalIgnoreCase))); } private void RegisterOfflineResetCommand() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown object obj = <>c.<>9__39_0; if (obj == null) { ConsoleEventFailable val = delegate(ConsoleEventArgs args) { if (!HasDevCommands()) { args.Context.AddString(Text_SemPermissao.Value); return false; } if (args.Args.Length < 2) { args.Context.AddString(Text_UsoOfflineReset.Value); return false; } if (!long.TryParse(args.Args[1], out var result)) { args.Context.AddString(Text_IdInvalido.Value); return false; } bool flag = ResetOfflinePlayer(result); args.Context.AddString(flag ? Text_OfflineResetado.Value : Text_OfflineNaoEncontrado.Value); return flag; }; <>c.<>9__39_0 = val; obj = (object)val; } new ConsoleCommand("valheim_reset_offline", "valheim_reset_offline ", (ConsoleEventFailable)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static bool ResetOfflinePlayer(long playerID) { if (ZDOMan.instance == null) { return false; } List list = new List(); int num = 0; while (ZDOMan.instance.GetAllZDOsWithPrefabIterative("Player", list, ref num)) { } foreach (ZDO item in list) { if (item != null) { long num2 = item.GetLong(ZDOVars.s_playerID, 0L); if (num2 == playerID) { item.Set("ValheimRace", ""); item.Set("ValheimRaceLocked", false); item.Set("ValheimRaceEarColor_x", -1f); item.Set("ValheimRaceEarColor_y", -1f); item.Set("ValheimRaceEarColor_z", -1f); item.Set("ValheimRaceSkinColor_x", -1f); item.Set("ValheimRaceSkinColor_y", -1f); item.Set("ValheimRaceSkinColor_z", -1f); NetworkRaces.Remove(playerID); return true; } } } return false; } private static void TransformLocalPlayerFromMarketplace(string race) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)Instance == (Object)null) { return; } if (!IsRaceEnabled(race)) { ((Character)localPlayer).Message((MessageType)2, Text_EssaRacaDesativada.Value, 0, (Sprite)null); return; } if (RaceUsesForcedSkin(race)) { Instance.CacheOriginalSkinIfNeeded(localPlayer); } Instance.SetRace(localPlayer, race, lockPlayer: true, broadcast: true); Instance.ApplyRaceWithDelays(localPlayer); TopOffVitals(localPlayer); if (!IsHeadless()) { Instance.SpawnEffect(localPlayer); } PlayTransformEmote(); ((Character)localPlayer).Message((MessageType)2, Fmt(Text_AgoraEuSou.Value, Instance.GetRaceName(race)), 0, (Sprite)null); } private static void PlayTransformEmote() { if (!EmoteOnTransform.Value) { return; } try { Emote.DoEmote((Emotes)11); } catch (Exception ex) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Falha ao tocar emote de transformação: " + ex.Message)); } } } private static string GetVisualKey(Player player) { if ((Object)(object)player == (Object)null) { return ""; } long playerIdLong = GetPlayerIdLong(player); return (playerIdLong != 0L) ? playerIdLong.ToString() : ""; } private static long GetPlayerIdLong(Player player) { if ((Object)(object)player == (Object)null) { return 0L; } try { long playerID = player.GetPlayerID(); if (playerID != 0) { return playerID; } } catch { } return 0L; } private void RestoreLocalSavedRaceIfNeeded() { if (isRestoringLocalRace) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } string text = GetSavedLocalRace(); string race = GetRace(localPlayer); if ((string.IsNullOrWhiteSpace(text) || !IsRaceEnabled(text)) && string.IsNullOrWhiteSpace(race)) { if (!string.IsNullOrWhiteSpace(_sessionSelectedPreviewRace) && IsRaceEnabled(_sessionSelectedPreviewRace)) { text = _sessionSelectedPreviewRace; } else { string playerName = localPlayer.GetPlayerName(); string text2 = ((!string.IsNullOrWhiteSpace(playerName)) ? GetLastRaceGlobal(playerName) : ""); text = ((!string.IsNullOrWhiteSpace(text2) && IsRaceEnabled(text2)) ? text2 : "humano"); } } if (string.IsNullOrWhiteSpace(text) || !IsRaceEnabled(text)) { return; } if (string.IsNullOrWhiteSpace(race)) { ZNetView cachedZNetView = GetCachedZNetView(localPlayer); if ((Object)(object)cachedZNetView == (Object)null || cachedZNetView.GetZDO() == null) { return; } isRestoringLocalRace = true; try { long playerIdLong = GetPlayerIdLong(localPlayer); if (playerIdLong != 0) { NetworkRaces[playerIdLong] = text; } ForceSetZdoRace(localPlayer, text); ForceSetRaceVisualZdo(localPlayer, text); SetZdoLocked(localPlayer, locked: true); BroadcastRace(localPlayer, text); ApplyRaceWithDelays(localPlayer); return; } finally { isRestoringLocalRace = false; } } SetZdoLocked(localPlayer, locked: true); } private static string GetLocalSavePrefix() { long num = 0L; try { if ((Object)(object)Player.m_localPlayer != (Object)null) { num = Player.m_localPlayer.GetPlayerID(); } } catch { } if (_cachedSavePrefix != null && (Object)(object)_cachedZNetInstance == (Object)(object)ZNet.instance && _cachedCharacterId == num) { return _cachedSavePrefix; } string text = ((num != 0L) ? num.ToString() : "unknown"); string text2 = "local"; try { if ((Object)(object)ZNet.instance != (Object)null) { if (!ZNet.instance.IsServer()) { string text3 = ""; int result = 0; FieldInfo fieldInfo = AccessTools.Field(typeof(ZNet), "m_serverHost"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(ZNet), "m_serverPort"); if (fieldInfo != null) { text3 = fieldInfo.GetValue(ZNet.instance)?.ToString() ?? ""; } if (fieldInfo2 != null) { int.TryParse(fieldInfo2.GetValue(ZNet.instance)?.ToString() ?? "", out result); } if (!string.IsNullOrWhiteSpace(text3)) { text2 = text3 + ((result > 0) ? ("_" + result) : ""); } } else { MethodInfo methodInfo = AccessTools.Method(typeof(ZNet), "GetWorldName", (Type[])null, (Type[])null); if (methodInfo != null) { text2 = methodInfo.Invoke(ZNet.instance, null)?.ToString() ?? "local"; } } } } catch { } _cachedSavePrefix = "ValheimRaces_c" + text + "_s" + SanitizeKey(text2) + "_"; _cachedZNetInstance = ZNet.instance; _cachedCharacterId = num; _cachedServerKey = text2; return _cachedSavePrefix; } private static string SanitizeKey(string value) { if (string.IsNullOrWhiteSpace(value)) { return "unknown"; } char[] array = value.ToCharArray(); for (int i = 0; i < array.Length; i++) { if (!char.IsLetterOrDigit(array[i]) && array[i] != '-') { array[i] = '_'; } } return new string(array); } private static string GetSavedLocalRace() { try { return PlayerPrefs.GetString(GetLocalSavePrefix() + "Race", ""); } catch { return ""; } } private static bool HasSavedLocalRaceLocked() { try { return PlayerPrefs.GetInt(GetLocalSavePrefix() + "Locked", 0) == 1; } catch { return false; } } private static void SaveLocalRace(string race, bool locked) { if (string.IsNullOrWhiteSpace(race)) { return; } try { PlayerPrefs.SetString(GetLocalSavePrefix() + "Race", race); if (locked) { PlayerPrefs.SetInt(GetLocalSavePrefix() + "Locked", 1); } PlayerPrefs.Save(); } catch { } string text = null; try { text = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerName() : null); } catch { } if (string.IsNullOrWhiteSpace(text)) { return; } try { PlayerPrefs.SetString(GetGlobalRaceKeyByName(text), race); PlayerPrefs.Save(); } catch { } } private static string GetGlobalRaceKeyByName(string characterName) { return "ValheimRaces_n" + SanitizeKey(characterName) + "_LastRaceGlobal"; } private static string GetLastRaceGlobal(string characterName) { if (string.IsNullOrWhiteSpace(characterName)) { return ""; } try { return PlayerPrefs.GetString(GetGlobalRaceKeyByName(characterName), ""); } catch { return ""; } } public static void SaveGlobalRaceForCharacterCreation(string characterName, string race) { if (string.IsNullOrWhiteSpace(characterName) || string.IsNullOrWhiteSpace(race) || !IsRaceEnabled(race)) { return; } try { PlayerPrefs.SetString(GetGlobalRaceKeyByName(characterName), race); PlayerPrefs.Save(); } catch { } } private static void ClearLocalSavedRace() { try { PlayerPrefs.DeleteKey(GetLocalSavePrefix() + "Race"); PlayerPrefs.DeleteKey(GetLocalSavePrefix() + "Locked"); PlayerPrefs.Save(); } catch { } } private static bool IsClientConnectedToRemoteServer() { try { return (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer(); } catch { return false; } } private static bool IsSinglePlayer() { try { if ((Object)(object)ZNet.instance == (Object)null) { return false; } return ZNet.instance.IsServer() && ZNet.instance.GetNrOfPlayers() <= 1; } catch { return false; } } public static string GetRaceTooltipText(string race) { RaceConfig value; return Races.TryGetValue(race, out value) ? BuildTooltip(value) : ""; } private static void ApplyPreviewRace(FejdStartup fejd, PlayerProfile profile) { if (!((Object)(object)fejd == (Object)null) && profile != null && !((Object)(object)Instance == (Object)null)) { string text = null; try { text = profile.GetName(); } catch { } string text2 = (UserJustClickedRacePending ? _sessionSelectedPreviewRace : null); if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(text2) && IsRaceEnabled(text2)) { SaveGlobalRaceForCharacterCreation(text, text2); _sessionSelectedPreviewRace = null; UserJustClickedRacePending = false; } InvalidateSessionCacheIfNewPreview(fejd); string text3 = ((!string.IsNullOrWhiteSpace(text2) && IsRaceEnabled(text2)) ? text2 : null); if (string.IsNullOrWhiteSpace(text3) && !string.IsNullOrWhiteSpace(text)) { text3 = GetLastRaceGlobal(text); } if (string.IsNullOrWhiteSpace(text3) || !IsRaceEnabled(text3)) { text3 = "humano"; } ApplyPreviewRaceDirect(fejd, text3); } } private static void InvalidateSessionCacheIfNewPreview(FejdStartup fejd) { Player val = (((Object)(object)fejd != (Object)null) ? fejd.GetPreviewPlayer() : null); if (!((Object)(object)val == (Object)(object)_cachedPreviewPlayerInstance)) { _cachedPreviewPlayerInstance = val; _originalPreviewSkin = null; _originalPreviewHair = null; _sessionSelectedPreviewRace = null; _previewSkinForced = false; _previewHairForced = false; _lastFullyAppliedRace = null; _lastAppliedIsFemale = false; UserJustClickedRacePending = false; } } public static void PollPreviewGenderChange(FejdStartup fejd) { if ((Object)(object)fejd == (Object)null) { return; } Player previewPlayer = fejd.GetPreviewPlayer(); if ((Object)(object)previewPlayer == (Object)null) { return; } InvalidateSessionCacheIfNewPreview(fejd); if (string.IsNullOrWhiteSpace(_lastFullyAppliedRace)) { string text = _sessionSelectedPreviewRace; if (string.IsNullOrWhiteSpace(text) || !IsRaceEnabled(text)) { text = "humano"; } ApplyPreviewRaceDirect(fejd, text); } else if (!((Object)(object)previewPlayer != (Object)(object)_cachedPreviewPlayerInstance) && !string.IsNullOrWhiteSpace(_sessionSelectedPreviewRace)) { bool flag = IsFemaleModel(previewPlayer); if (flag != _lastAppliedIsFemale) { ApplyPreviewRaceDirect(fejd, _sessionSelectedPreviewRace); } } } public static void ApplyPreviewRaceDirect(FejdStartup fejd, string race) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: 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_0382: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)fejd == (Object)null || (Object)(object)Instance == (Object)null || string.IsNullOrWhiteSpace(race) || !IsRaceEnabled(race)) { return; } Player previewPlayer = fejd.GetPreviewPlayer(); if ((Object)(object)previewPlayer == (Object)null) { return; } InvalidateSessionCacheIfNewPreview(fejd); _sessionSelectedPreviewRace = race; if (!_previewSkinForced) { _originalPreviewSkin = Instance.GetCurrentSkinVector(previewPlayer); } if (!_previewHairForced) { _originalPreviewHair = Instance.GetCurrentHairVector(previewPlayer); } bool flag = IsFemaleModel(previewPlayer); bool flag2 = race != _lastFullyAppliedRace || flag != _lastAppliedIsFemale; bool previewSkinForced = _previewSkinForced; bool previewHairForced = _previewHairForced; _previewSkinForced = RaceUsesForcedSkin(race); _previewHairForced = RaceUsesForcedHair(race); if (flag2) { ClearPreviewVisuals(previewPlayer, previewSkinForced, previewHairForced); ApplyScale(previewPlayer, GetRaceScale(race)); } Transform val = Instance.FindHead(((Component)previewPlayer).transform, 0); if (!((Object)(object)val == (Object)null)) { if (_previewSkinForced && flag2) { Instance.ApplySkin(previewPlayer, BlendRaceHueWithBrightness(GetRaceSkinColor(race), Instance.GetCurrentSkinVector(previewPlayer))); } Color val2 = ToColor(GetRaceEarColorForPreview(previewPlayer, race)); switch (race) { case "orc": Instance.ApplyOrcEarsDirect(((Component)previewPlayer).transform, val2, flag); Instance.ApplyOrcTuskDirect(val); break; case "jotun": Instance.ApplyOrcEarsDirect(((Component)previewPlayer).transform, val2, flag); break; case "elfodanoite": case "elfodaluz": case "halfling": Instance.ApplyEarsDirect(((Component)previewPlayer).transform, val2, flag); break; case "efrit": Instance.ApplyEarsDirect(((Component)previewPlayer).transform, val2, flag); Instance.ApplyHornDirect(((Component)previewPlayer).transform, flag); break; case "fada": Instance.ApplyFairyBodyDirect(((Component)previewPlayer).transform, flag); break; } Instance.ApplyHighElfEyesPreview(val, race); Transform val3 = ((Component)previewPlayer).transform.Find("Ears"); if ((Object)(object)val3 != (Object)null) { Instance.FixEarMaterials(val3, forceStandardShader: false); Instance.ApplyColor(val3, val2); } Transform val4 = ((Component)previewPlayer).transform.Find("OrcEars"); if ((Object)(object)val4 != (Object)null) { Instance.FixEarMaterials(val4, forceStandardShader: false); Instance.ApplyColor(val4, val2); } Transform val5 = val.Find("HighElfEyes"); if ((Object)(object)val5 != (Object)null) { Instance.ApplyEyeColor(val5, GetRaceEyeColor(race)); } if (_previewHairForced) { Instance.ApplyHair(previewPlayer, GetRaceHairColor(race)); } _lastFullyAppliedRace = race; FejdRaceSelectorUI.UpdateAbilityHud(race); _lastAppliedIsFemale = flag; } } private static void RemoveAttachmentImmediate(Transform root, string objectName) { if (!((Object)(object)root == (Object)null)) { Transform val = root.Find(objectName); if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } } private static void ClearPreviewVisuals(Player preview, bool wasSkinForced, bool wasHairForced) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)preview == (Object)null)) { Transform val = Instance.FindHead(((Component)preview).transform, 0); RemoveAttachmentImmediate(((Component)preview).transform, "Ears"); RemoveAttachmentImmediate(((Component)preview).transform, "OrcEars"); RemoveAttachmentImmediate(((Component)preview).transform, "Horn"); if ((Object)(object)val != (Object)null) { RemoveAttachmentImmediate(val, "OrcTusk"); RemoveAttachmentImmediate(val, "HighElfEyes"); } RemoveAttachmentImmediate(((Component)preview).transform, "FadaCorpo"); SetVanillaBodyRenderersVisible(((Component)preview).transform, visible: true); ApplyScale(preview, HumanScale); if (wasSkinForced && _originalPreviewSkin.HasValue) { Instance.ApplySkin(preview, _originalPreviewSkin.Value); } if (wasHairForced && _originalPreviewHair.HasValue) { Instance.ApplyHair(preview, _originalPreviewHair.Value); } } } private static Vector3 GetRaceEarColorForPreview(Player preview, string race) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (Races.TryGetValue(race, out var value)) { Vector3 val = ParseColorConfig(value.EarColor.Value, InvalidColor); if (val.x >= 0f) { if (RaceUsesForcedSkin(race) && val == GetRaceSkinColor(race)) { return ((Object)(object)Instance != (Object)null) ? Instance.GetCurrentSkinVector(preview) : val; } return val; } } return ((Object)(object)Instance != (Object)null) ? Instance.GetCurrentSkinVector(preview) : Vector3.one; } private void ApplyHighElfEyesPreview(Transform head, string race) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)head == (Object)null) && !((Object)(object)HighElfEyesPrefab == (Object)null)) { Transform val = head.Find("HighElfEyes"); if ((Object)(object)val == (Object)null) { GameObject val2 = Object.Instantiate(HighElfEyesPrefab, head); ((Object)val2).name = "HighElfEyes"; StripItemComponents(val2); val = val2.transform; } val.localPosition = HighElfEyesPosition; val.localRotation = Quaternion.Euler(HighElfEyesRotation); val.localScale = HighElfEyesScale; ApplyEyeColor(val, GetRaceEyeColor(race)); } } private static void ApplyRaceVisualToRagdoll(Ragdoll ragdoll, string race) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ragdoll == (Object)null || string.IsNullOrWhiteSpace(race)) { return; } try { Transform transform = ((Component)ragdoll).transform; Vector3 localScale = (transform.localScale = GetRaceScale(race)); Transform val = transform.Find("Visual") ?? transform.Find("_Visual") ?? transform.Find("visual"); if ((Object)(object)val != (Object)null) { val.localScale = localScale; } Transform val2 = Instance.FindHead(transform, 0); if ((Object)(object)val2 == (Object)null) { return; } bool isFemale = IsFemaleModel(((Component)ragdoll).GetComponentInChildren()); Color color = ToColor(GetRagdollEarColor(race)); switch (race) { case "orc": Instance.ApplyOrcEarsDirect(transform, color, isFemale); Instance.ApplyOrcTuskDirect(val2); break; case "jotun": Instance.ApplyOrcEarsDirect(transform, color, isFemale); break; case "elfodanoite": case "elfodaluz": case "halfling": Instance.ApplyEarsDirect(transform, color, isFemale); break; case "efrit": Instance.ApplyEarsDirect(transform, color, isFemale); Instance.ApplyHornDirect(transform, isFemale); break; case "fada": Instance.RemoveHeadAttachmentDirect(transform, "FadaCorpo"); Instance.ApplyFairyBodyDirect(transform, isFemale); break; } Instance.ApplyHighElfEyesPreview(val2, race); if (RaceUsesForcedSkin(race)) { VisEquipment componentInChildren = ((Component)ragdoll).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { typeof(VisEquipment).GetMethod("SetSkinColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(componentInChildren, new object[1] { GetRaceSkinColor(race) }); } } } catch (Exception arg) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)$"[ValheimRaces] Falha ao aplicar raça no ragdoll: {arg}"); } } } private static Vector3 GetRagdollEarColor(string race) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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) if (!string.IsNullOrWhiteSpace(race) && Races.TryGetValue(race, out var value)) { Vector3 val = ParseColorConfig(value.EarColor.Value, InvalidColor); if (val.x >= 0f) { return val; } } if (RaceUsesForcedSkin(race)) { return GetRaceSkinColor(race); } return Vector3.one; } private static bool IsHeadless() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 return (int)SystemInfo.graphicsDeviceType == 4; } private void Awake() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown Instance = this; ModConfigSync = new ConfigSync("valheim.races") { DisplayName = "Valheim Races", CurrentVersion = "2.9.1" }; string text = Path.Combine(Paths.ConfigPath, "ValheimRaces"); Directory.CreateDirectory(text); MainConfigFile = new ConfigFile(Path.Combine(text, "valheim.races.cfg"), true); ConfigEntry lockingConfig = MainConfigFile.Bind("Geral", "TravarConfiguracoes", true, "Trava as configs sincronizadas pra só admin do servidor poder mudar. Desligar isso não é recomendado."); ModConfigSync.AddLockingConfigEntry(lockingConfig); CreateTextConfigs(); CreateRaceConfigs(); EyeGlowPeak = SyncedConfig("Geral", "BrilhoOlho", 1f, "Intensidade do brilho do olho (emissão), igual pra todas as raças. IMPORTANTE: valores acima de 1.0 estouram em branco em cores com mais de um canal forte (ex: lilás, roxo-avermelhado) quando o Bloom está desligado — só cores 100% puras num canal só (vermelho/verde/azul puro) escapam disso. 1.0 é o teto seguro que nunca estoura, com ou sem Bloom."); EmoteOnTransform = SyncedConfig("Geral", "EmoteAoTransformar", value: false, "Toca o emote 'Despair' automaticamente sempre que o player troca de raça."); VfxOnTransform = SyncedConfig("Geral", "EfeitoVisualAoTransformar", value: false, "Spawna um efeito visual (tipo uma pequena explosão) sempre que o player troca de raça."); FillVitalsOnTransform = SyncedConfig("Geral", "EncherAoTransformar", value: true, "Enche vida/stamina/eitr até o novo limite (com bônus da raça) assim que o player troca de raça."); RacialAbilitiesEnabled = SyncedConfig("Geral", "HabilidadesRaciaisAtivas", value: true, "Interruptor geral: desliga TODAS as habilidades raciais especiais de uma vez (Fúria de Sangue, Aura de Cura, Postura de Ferro, Golpe de Oportunidade, Tremor, Segundo Fôlego, Sede de Sangue, Invisível ao Agachar), sem precisar mexer raça por raça. Os atributos normais (vida, dano, resistência, etc) continuam funcionando normal."); AltarRaces = SyncedConfig("Altar", "RacasDisponiveis", "orc,elfodaluz,elfodanoite,anao,halfling,humano,vampiro,efrit", "Quais raças aparecem no Altar das Raças, separadas por vírgula (use o ID da raça, ex: 'orc,elfodaluz,anao'). Pode ser qualquer raça (base, Ancião ou Campeão de Deus). Padrão: as 8 raças base originais (sem Jotun)."); AltarRecipe = SyncedConfig("Altar", "ReceitaDaPeca", "SwordCheat:1", "Custo pra construir o Altar das Raças, formato 'Item:Quantidade,Item:Quantidade'."); AltarSwitchCostItem = SyncedConfig("Altar", "CustoTrocaItem", "Coins", "Item cobrado pra trocar de raça depois de já ter escolhido uma vez (nome do prefab do item, ex: 'Coins')."); AltarSwitchCostAmount = SyncedConfig("Altar", "CustoTrocaQuantidade", 50, "Quantidade do item acima cobrada pra trocar de raça depois da primeira escolha."); FlightToggleKey = SyncedConfig("Geral", "TeclaVoo", "F", "Tecla pra ligar/desligar o voo da raça Fada (nome de uma KeyCode do Unity, ex: 'F', 'G', 'LeftAlt')."); if (!IsHeadless()) { LoadAssets(); } AltarPrefab = LoadPrefabFromEmbedded("altar_racas"); RegisterAltarPiece(); RegisterCommands(); harmony.PatchAll(); SuppressUnityShaderWarningLogs(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Valheim Races 2.9.1 carregado!"); try { string location = Assembly.GetExecutingAssembly().Location; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[ValheimRaces] DLL compilada em: {File.GetLastWriteTime(location):dd/MM/yyyy HH:mm:ss}"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[ValheimRaces] Não consegui checar data da DLL: " + ex.Message)); } } private void SuppressUnityShaderWarningLogs() { try { ILogHandler logHandler = Debug.unityLogger.logHandler; if (!(logHandler is ShaderWarningFilterLogHandler)) { Debug.unityLogger.logHandler = (ILogHandler)(object)new ShaderWarningFilterLogHandler(logHandler); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[ValheimRaces] Falha ao tentar filtrar avisos de shader (não crítico, log segue normal): " + ex.Message)); } } public static void LogInfoPublic(string message) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)message); } } private void OnDestroy() { harmony.UnpatchSelf(); } private void Update() { //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_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) RegisterRpcIfNeeded(); if (!IsHeadless() && (Object)(object)Player.m_localPlayer != (Object)null) { TickFlightToggle(Player.m_localPlayer); TickFlightMovement(Player.m_localPlayer); } if ((Object)(object)ZNet.instance != (Object)null) { adminCacheTimer += Time.deltaTime; if (adminCacheTimer >= 10f) { adminCacheTimer = 0f; RefreshAdminCache(); SkinnedAccessoryAttacher.PurgeDestroyedEntries(); PurgeExpiredChilledStatus(); } } if (!IsHeadless()) { syncTimer += Time.deltaTime; if (syncTimer >= 2f) { syncTimer = 0f; SyncLocalRace(); } localSaveTimer += Time.deltaTime; if (localSaveTimer >= 3f) { localSaveTimer = 0f; RestoreLocalSavedRaceIfNeeded(); } } if (IsSinglePlayer() && (Object)(object)Player.m_localPlayer != (Object)null) { configWatchTimer += Time.deltaTime; if (configWatchTimer >= 2f) { configWatchTimer = 0f; CheckConfigFileChanged(); } } timer += Time.deltaTime; if (timer < 0.6f) { return; } timer = 0f; if (IsHeadless()) { foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null)) { ApplyRace(allPlayer); RegenerateBonusVitals(allPlayer, 0.6f); TickStillHealAura(allPlayer, 0.6f); TickSecondWind(allPlayer, 0.6f); TickBlockAura(allPlayer, 0.6f); TickFlightDrain(allPlayer, 0.6f); } } return; } if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } Vector3 position = ((Component)Player.m_localPlayer).transform.position; float num = 3600f; foreach (Player allPlayer2 in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer2 == (Object)null) && (!((Object)(object)allPlayer2 != (Object)(object)Player.m_localPlayer) || !(Vector3.SqrMagnitude(((Component)allPlayer2).transform.position - position) > num))) { ApplyRace(allPlayer2); TickFairyEyebrowColor(allPlayer2); TickFairyFlightAnimation(allPlayer2); } } RegenerateBonusVitals(Player.m_localPlayer, 0.6f); TickStillHealAura(Player.m_localPlayer, 0.6f); TickSecondWind(Player.m_localPlayer, 0.6f); TickBlockAura(Player.m_localPlayer, 0.6f); TickFlightDrain(Player.m_localPlayer, 0.6f); if (GetRace(Player.m_localPlayer) == "humano") { AddEvolutionProgress(Player.m_localPlayer, "humano", 0.6f); } } private void CheckConfigFileChanged() { if (_isReloadingConfig) { return; } try { string configFilePath = MainConfigFile.ConfigFilePath; if (string.IsNullOrWhiteSpace(configFilePath) || !File.Exists(configFilePath)) { return; } DateTime lastWriteTime = File.GetLastWriteTime(configFilePath); if (lastWriteTime <= _lastConfigWrite) { return; } _isReloadingConfig = true; MainConfigFile.Reload(); NetworkRaces.Clear(); ZNetViewCache.Clear(); if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null)) { string visualKey = GetVisualKey(allPlayer); if (!string.IsNullOrWhiteSpace(visualKey)) { LastAppliedRace[visualKey] = ""; } InvalidateHeadCache(allPlayer); ApplyRaceWithDelays(allPlayer); } } ReRegisterSecretCodeCommands(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Config recarregado automaticamente."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Erro ao monitorar config: " + ex.Message)); } finally { try { string configFilePath2 = MainConfigFile.ConfigFilePath; if (!string.IsNullOrWhiteSpace(configFilePath2) && File.Exists(configFilePath2)) { _lastConfigWrite = File.GetLastWriteTime(configFilePath2); } } catch { } _isReloadingConfig = false; } } private static void RefreshAdminCache() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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) if ((Object)(object)ZNet.instance == (Object)null) { return; } KnownAdmins.Clear(); try { foreach (PlayerInfo player in ZNet.instance.GetPlayerList()) { ZDOID characterID = player.m_characterID; if (IsAdminById(((ZDOID)(ref characterID)).UserID)) { HashSet knownAdmins = KnownAdmins; characterID = player.m_characterID; knownAdmins.Add(((ZDOID)(ref characterID)).UserID); } } } catch { } } private static bool IsAdminById(long userId) { if ((Object)(object)ZNet.instance == (Object)null) { return false; } try { if (ZNet.instance.IsAdmin(userId.ToString())) { return true; } ulong num = (ulong)userId; return ZNet.instance.IsAdmin(num.ToString()); } catch { return false; } } public static bool HasDevCommands() { if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)ZNet.instance != (Object)null) { try { long playerID = Player.m_localPlayer.GetPlayerID(); if (playerID != 0L && (KnownAdmins.Contains(playerID) || IsAdminById(playerID))) { return true; } } catch { } } return GetStaticBool("Terminal", "m_cheat") || GetStaticBool("Console", "m_cheat") || GetStaticBool("Terminal", "m_devcommands") || GetStaticBool("Console", "m_devcommands"); } private static bool GetStaticBool(string typeName, string fieldName) { try { Type type = AccessTools.TypeByName(typeName); if (type == null) { return false; } FieldInfo fieldInfo = AccessTools.Field(type, fieldName); if (fieldInfo == null) { return false; } object value = fieldInfo.GetValue(null); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return false; } } private static bool IsCrouchStealthed(Character target) { Player val = (Player)(object)((target is Player) ? target : null); if ((Object)(object)val == (Object)null || !((Character)val).IsCrouching()) { return false; } if (!RacialAbilitiesEnabled.Value || !TryGetRaceConfig(val, out var cfg) || !cfg.CrouchInvisible.Value) { return false; } if (cfg.CrouchInvisibleNightOnly.Value && !IsNightSafe()) { return false; } return true; } public static void TickStillHealAura(Player p, float dt) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null || !RacialAbilitiesEnabled.Value || !TryGetRaceConfig(p, out var cfg) || !cfg.StillHealAura.Value || (cfg.StillHealDayOnly.Value && IsNightSafe())) { return; } string visualKey = GetVisualKey(p); if (string.IsNullOrWhiteSpace(visualKey)) { return; } Vector3 position = ((Component)p).transform.position; if (!StillLastPos.TryGetValue(visualKey, out var value) || Vector3.Distance(position, value) > 0.2f) { StillLastPos[visualKey] = position; StillTimer[visualKey] = 0f; StillHealTimer[visualKey] = 0f; return; } StillTimer.TryGetValue(visualKey, out var value2); value2 += dt; StillTimer[visualKey] = value2; if (value2 < cfg.StillHealRequiredStillTime.Value) { return; } StillHealTimer.TryGetValue(visualKey, out var value3); value3 += dt; if (value3 < cfg.StillHealInterval.Value) { StillHealTimer[visualKey] = value3; return; } StillHealTimer[visualKey] = 0f; if (cfg.StillHealAmount.Value > 0f) { ((Character)p).Heal(cfg.StillHealAmount.Value, false); AddEvolutionProgress(p, GetRace(p), cfg.StillHealAmount.Value); } } public static void TickSecondWind(Player p, float dt) { if ((Object)(object)p == (Object)null || !RacialAbilitiesEnabled.Value || !TryGetRaceConfig(p, out var cfg) || !cfg.SecondWindEnabled.Value) { return; } string visualKey = GetVisualKey(p); if (string.IsNullOrWhiteSpace(visualKey)) { return; } SecondWindCooldownTimer.TryGetValue(visualKey, out var value); if (value > 0f) { SecondWindCooldownTimer[visualKey] = Mathf.Max(0f, value - dt); } else if (!(((Character)p).GetMaxHealth() <= 0f) && !(((Character)p).GetHealth() / ((Character)p).GetMaxHealth() > cfg.SecondWindThreshold.Value)) { if (cfg.SecondWindHealAmount.Value > 0f) { ((Character)p).Heal(cfg.SecondWindHealAmount.Value, false); } if (cfg.SecondWindStaminaAmount.Value > 0f) { ((Character)p).AddStamina(cfg.SecondWindStaminaAmount.Value); } SecondWindCooldownTimer[visualKey] = cfg.SecondWindCooldown.Value; } } private static void DoTremor(Player p, RaceConfig cfg) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) try { AddEvolutionProgress(p, GetRace(p), 1f); Vector3 position = ((Component)p).transform.position; float num = cfg.TremorRadius.Value * cfg.TremorRadius.Value; foreach (Character allCharacter in Character.GetAllCharacters()) { if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter == (Object)(object)p) && !allCharacter.IsPlayer() && !(Vector3.SqrMagnitude(((Component)allCharacter).transform.position - position) > num)) { Vector3 dir = ((Component)allCharacter).transform.position - position; dir.y = 0.5f; ((Vector3)(ref dir)).Normalize(); HitData val = new HitData(); val.m_damage.m_damage = 0f; val.m_damage.m_fire = cfg.TremorFireDamage.Value; val.m_pushForce = cfg.TremorKnockback.Value; val.m_staggerMultiplier = cfg.TremorStaggerMultiplier.Value; val.m_dir = dir; val.m_point = ((Component)allCharacter).transform.position; val.m_attacker = ((Character)p).GetZDOID(); allCharacter.Damage(val); } } } catch (Exception ex) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] Falha no Tremor do Jotun: " + ex.Message)); } } } private static bool IsNightSafe() { try { return EnvMan.IsNight(); } catch (Exception ex) { if (!_envNightWarningLogged) { _envNightWarningLogged = true; ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] EnvMan.IsNight() falhou (só avisando uma vez): " + ex.Message)); } } return false; } } private static bool TryGetRaceConfig(Player p, out RaceConfig cfg) { cfg = null; if ((Object)(object)p == (Object)null) { return false; } string race = GetRace(p); if (string.IsNullOrWhiteSpace(race)) { return false; } return Races.TryGetValue(race, out cfg); } public static void RegenerateBonusVitals(Player p, float dt) { if (!((Object)(object)p == (Object)null) && TryGetRaceConfig(p, out var cfg)) { TickBonusRegen(((Character)p).GetHealth(), ((Character)p).GetMaxHealth(), cfg.HealthBonus.Value, dt, delegate(float amount) { ((Character)p).Heal(amount, false); }); TickBonusRegen(p.GetStamina(), ((Character)p).GetMaxStamina(), cfg.StaminaBonus.Value, dt, delegate(float amount) { ((Character)p).AddStamina(amount); }); TickBonusRegen(p.GetEitr(), ((Character)p).GetMaxEitr(), cfg.EitrBonus.Value, dt, delegate(float amount) { ((Character)p).AddEitr(amount); }); } } private static void TickBonusRegen(float current, float max, float bonus, float dt, Action apply) { if (bonus <= 0f) { return; } float num = max - current; if (!(num <= 0f) && !(num > bonus + 0.1f)) { float num2 = Mathf.Min(num, bonus / 30f * dt); if (num2 > 0f) { apply(num2); } } } public static void TopOffVitals(Player p) { if ((Object)(object)p == (Object)null || FillVitalsOnTransform == null || !FillVitalsOnTransform.Value) { return; } try { ((Character)p).SetHealth(((Character)p).GetMaxHealth()); float num = ((Character)p).GetMaxStamina() - p.GetStamina(); if (num > 0f) { ((Character)p).AddStamina(num); } float num2 = ((Character)p).GetMaxEitr() - p.GetEitr(); if (num2 > 0f) { ((Character)p).AddEitr(num2); } } catch (Exception ex) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Falha ao encher vida/stamina/eitr após transformação: " + ex.Message)); } } } public static void PurgeExpiredChilledStatus() { float time = Time.time; if (time - _lastChilledPurgeTime < 30f) { return; } _lastChilledPurgeTime = time; List list = null; foreach (KeyValuePair item in ChilledStatus) { if (time >= item.Value.Item1) { if (list == null) { list = new List(); } list.Add(item.Key); } } if (list == null) { return; } foreach (int item2 in list) { ChilledStatus.Remove(item2); } } public static void TickBlockAura(Player p, float dt) { //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_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null || !RacialAbilitiesEnabled.Value || !TryGetRaceConfig(p, out var cfg) || !cfg.BlockAuraEnabled.Value || !((Character)p).IsBlocking()) { return; } try { Vector3 position = ((Component)p).transform.position; float num = cfg.BlockAuraRadius.Value * cfg.BlockAuraRadius.Value; float time = Time.time; bool value = cfg.BlockAuraIsFrost.Value; float value2 = cfg.BlockAuraDamage.Value; if (value2 <= 0f) { return; } foreach (Character allCharacter in Character.GetAllCharacters()) { if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter == (Object)(object)p) && !allCharacter.IsPlayer() && !(Vector3.SqrMagnitude(((Component)allCharacter).transform.position - position) > num)) { HitData val = new HitData(); val.m_damage.m_damage = 0f; if (value) { val.m_damage.m_frost = value2; } else { val.m_damage.m_fire = value2; } Vector3 val2 = ((Component)allCharacter).transform.position - position; val.m_dir = ((((Vector3)(ref val2)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val2)).normalized : Vector3.forward); val.m_point = ((Component)allCharacter).transform.position; val.m_attacker = ((Character)p).GetZDOID(); allCharacter.Damage(val); if (cfg.BlockAuraSlowEnabled.Value) { float item = Mathf.Clamp01(1f - cfg.BlockAuraSlowPercent.Value); ChilledStatus[((Object)allCharacter).GetInstanceID()] = (time + cfg.BlockAuraSlowDuration.Value, item); } } } } catch (Exception ex) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] Falha na Aura de Bloqueio: " + ex.Message)); } } } private static Dictionary ParseResistances(string value) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); if (string.IsNullOrWhiteSpace(value)) { return dictionary; } string[] array = value.Split(new char[1] { ',' }); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length == 2 && DamageTypeNames.TryGetValue(array2[0].Trim(), out var value2) && ModifierNames.TryGetValue(array2[1].Trim(), out var value3)) { dictionary[value2] = value3; } } return dictionary; } private static Dictionary ParseTypeMultipliers(string value) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); if (string.IsNullOrWhiteSpace(value)) { return dictionary; } string[] array = value.Split(new char[1] { ',' }); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length == 2 && DamageTypeNames.TryGetValue(array2[0].Trim(), out var value2) && float.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { dictionary[value2] = result; } } return dictionary; } private static Dictionary ParseSkillMultipliers(string value) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); if (string.IsNullOrWhiteSpace(value)) { return dictionary; } string[] array = value.Split(new char[1] { ',' }); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length == 2 && Enum.TryParse(array2[0].Trim(), ignoreCase: true, out SkillType result) && float.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { dictionary[result] = result2; } } return dictionary; } private static Character GetSEManOwner(SEMan seman) { if (seman == null) { return null; } if (_semanCharacterField == null) { _semanCharacterField = AccessTools.Field(typeof(SEMan), "m_character"); } object? obj = _semanCharacterField?.GetValue(seman); return (Character)((obj is Character) ? obj : null); } private static float GetStaminaCostModifier(RaceConfig cfg, string actionKey) { if (cfg == null || string.IsNullOrWhiteSpace(cfg.StaminaCostModifiers.Value)) { return 0f; } string[] array = cfg.StaminaCostModifiers.Value.Split(new char[1] { ',' }); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length == 2 && array2[0].Trim().Equals(actionKey, StringComparison.OrdinalIgnoreCase) && float.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } } return 0f; } private void CreateRaceConfigs() { Races.Clear(); CreateRaceConfig("orc", "Orc", enabled: true, "1,1,1", "#3FA86B", "#3FA86B", "#FFFF00", "X9K7Q2M4Z8P1", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1f, 0f, 1f, 0.9f, "Blunt:Resistant,Frost:Weak", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 0f, crouchInvisible: false, crouchInvisibleNightOnly: false, 0.3f, 1.3f); CreateRaceConfig("elfodaluz", "Elfo da Luz", enabled: true, "1,1,1", "-1", "-1", "#00FF00", "R3T8Y1U6I4O9", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1f, 0f, 1f, 1.15f, "Spirit:Resistant,Poison:Weak", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 0f, crouchInvisible: false, crouchInvisibleNightOnly: false, 0f, 1f, stillHealAura: true, 5f, 2f, 2f, ironStanceEnabled: false, 0f, 0f, 0f, tremorEnabled: false, 0.6f, 6f, 40f, 0f, 1f, secondWindEnabled: false, 0.2f, 0f, 0f, 300f, 0f, onKillHealNightOnly: false, stillHealDayOnly: true); CreateRaceConfig("elfodanoite", "Elfo da Noite", enabled: true, "1,1,1", "#0779c5", "#0779c5", "#8B0000", "V7N2M8Q5L1K6", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1f, 0f, 1f, 1.15f, "Poison:Resistant,Blunt:Weak", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 0f, crouchInvisible: true, crouchInvisibleNightOnly: true); CreateRaceConfig("anao", "Anão", enabled: true, "0.8,0.8,0.8", "-1", "-1", "#9B30FF", "Z4P9X2C7B8N1", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1f, 0f, 1f, 0.9f, "Blunt:VeryResistant,Slash:Resistant,Pierce:Resistant,Fire:Weak", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 0f, crouchInvisible: false, crouchInvisibleNightOnly: false, 0f, 1f, stillHealAura: false, 5f, 2f, 2f, ironStanceEnabled: true, 0.3f); CreateRaceConfig("halfling", "Halfling", enabled: true, "0.8,0.8,0.8", "#B08FE0", "#B08FE0", "#CC5500", "K8L3Q7W2E9R4", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1f, 0f, 1f, 1.2f, "Poison:Resistant,Fire:Weak", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 0f, crouchInvisible: false, crouchInvisibleNightOnly: false, 0f, 1f, stillHealAura: false, 5f, 2f, 2f, ironStanceEnabled: false, 0f, 0.5f, 20f); CreateRaceConfig("jotun", "Jotun", enabled: true, "1,1,1", "#4cc0dd", "#4cc0dd", "#6dceee", "M1N6B9V3C8X5", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1f, 0f, 1f, 0.8f, "Frost:VeryResistant,Fire:Weak", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 100f, crouchInvisible: false, crouchInvisibleNightOnly: false, 0f, 1f, stillHealAura: false, 5f, 2f, 2f, ironStanceEnabled: false, 0f, 0f, 0f, tremorEnabled: false, 0.6f, 6f, 40f, 0f, 1f, secondWindEnabled: false, 0.2f, 0f, 0f, 300f, 0f, onKillHealNightOnly: false, stillHealDayOnly: false, blockAuraEnabled: true, 2f, 4f, blockAuraIsFrost: true, blockAuraSlowEnabled: true, 0.35f); CreateRaceConfig("fada", "Fada", enabled: false, "1,1,1", "-1", "-1", "#00FF00", "F1L3Y9W2N5D8", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1.15f, 0f, 1f, 1.1f, "Spirit:Resistant,Blunt:Weak", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 0f, crouchInvisible: false, crouchInvisibleNightOnly: false, 0f, 1f, stillHealAura: false, 5f, 2f, 2f, ironStanceEnabled: false, 0f, 0f, 0f, tremorEnabled: false, 0.6f, 6f, 40f, 0f, 1f, secondWindEnabled: false, 0.2f, 0f, 0f, 300f, 0f, onKillHealNightOnly: false, stillHealDayOnly: false, blockAuraEnabled: false, 0f, 4f, blockAuraIsFrost: false, blockAuraSlowEnabled: false, 0f, 2f, onHitElementalEnabled: false, 0f, flightEnabled: true); CreateRaceConfig("humano", "Humano", enabled: true, "1,1,1", "-1", "-1", "#00F0FF", "T2Y7U4I8O1P6", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1f, 0f, 1f, 1f, "", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 0f, crouchInvisible: false, crouchInvisibleNightOnly: false, 0f, 1f, stillHealAura: false, 5f, 2f, 2f, ironStanceEnabled: false, 0f, 0f, 0f, tremorEnabled: false, 0.6f, 6f, 40f, 0f, 1f, secondWindEnabled: true, 0.2f, 30f, 30f); CreateRaceConfig("vampiro", "Vampiro", enabled: true, "1,1,1", "#E6E0E5", "#E6E0E5", "#6d0606", "Q5W9E2R7T4Y8", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1f, 0f, 1f, 1.15f, "Poison:Resistant,Fire:Weak,Spirit:Weak", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 0f, crouchInvisible: false, crouchInvisibleNightOnly: false, 0f, 1f, stillHealAura: false, 5f, 2f, 2f, ironStanceEnabled: false, 0f, 0f, 0f, tremorEnabled: false, 0.6f, 6f, 40f, 0f, 1f, secondWindEnabled: false, 0.2f, 0f, 0f, 300f, 40f, onKillHealNightOnly: true); CreateRaceConfig("efrit", "Efrit", enabled: true, "1,1,1", "#890101", "#890101", "#FF0000", "", "-1", 0f, 0f, 0f, 0f, 1f, 1f, 1f, 1f, "", 1f, 1f, 0f, 1f, 1f, "Fire:Resistant,Frost:Weak", noResourceCost: false, "", 0f, 1f, 1f, 1f, "", "", nightOnlyBonuses: false, 0f, "", 0f, crouchInvisible: false, crouchInvisibleNightOnly: false, 0f, 1f, stillHealAura: false, 5f, 2f, 2f, ironStanceEnabled: false, 0f, 0f, 0f, tremorEnabled: false, 0.6f, 6f, 40f, 0f, 1f, secondWindEnabled: false, 0.2f, 0f, 0f, 300f, 0f, onKillHealNightOnly: false, stillHealDayOnly: false, blockAuraEnabled: false, 0f, 4f, blockAuraIsFrost: false, blockAuraSlowEnabled: false, 0f, 2f, onHitElementalEnabled: true, 5f); } private void CreateRaceConfig(string raceId, string displayName, bool enabled, string scale, string skinColor, string earColor, string eyeColor, string secretCode, string hairColor = "-1", float healthBonus = 0f, float staminaBonus = 0f, float eitrBonus = 0f, float carryWeightBonus = 0f, float healthRegenMult = 1f, float staminaRegenMult = 1f, float eitrRegenMult = 1f, float damageDoneMult = 1f, string skillDamageMultipliers = "", float backstabMult = 1f, float damageTakenMult = 1f, float lifestealPercent = 0f, float stealthMult = 1f, float speedMult = 1f, string resistances = "", bool noResourceCost = false, string evolvesTo = "", float evolutionThreshold = 0f, float xpGainMult = 1f, float knockbackMult = 1f, float eitrCostMult = 1f, string staminaCostModifiers = "", string attackDamageTypeMultipliers = "", bool nightOnlyBonuses = false, float dayNightHealthShift = 0f, string biomeHealthShifts = "", float heatResistanceBonus = 0f, bool crouchInvisible = false, bool crouchInvisibleNightOnly = false, float lowHealthThreshold = 0f, float lowHealthDamageBonus = 1f, bool stillHealAura = false, float stillHealAmount = 5f, float stillHealInterval = 2f, float stillHealRequiredStillTime = 2f, bool ironStanceEnabled = false, float ironStanceExtraDamageReduction = 0f, float backstabStaminaRefundChance = 0f, float backstabStaminaRefundAmount = 0f, bool tremorEnabled = false, float tremorMinAirTime = 0.6f, float tremorRadius = 6f, float tremorKnockback = 40f, float tremorFireDamage = 0f, float tremorStaggerMultiplier = 1f, bool secondWindEnabled = false, float secondWindThreshold = 0.2f, float secondWindHealAmount = 0f, float secondWindStaminaAmount = 0f, float secondWindCooldown = 300f, float onKillHealAmount = 0f, bool onKillHealNightOnly = false, bool stillHealDayOnly = false, bool blockAuraEnabled = false, float blockAuraDamage = 0f, float blockAuraRadius = 4f, bool blockAuraIsFrost = false, bool blockAuraSlowEnabled = false, float blockAuraSlowPercent = 0f, float blockAuraSlowDuration = 2f, bool onHitElementalEnabled = false, float onHitElementalDamage = 0f, bool flightEnabled = false, float flightStaminaCostPerTick = 5f, float flightMinStaminaToStart = 20f) { string text = "Raca - " + displayName; Races[raceId] = new RaceConfig { RaceId = raceId, DisplayName = displayName, Enabled = SyncedConfig(text, "Usar", enabled, "Ativa ou desativa a raça " + displayName + "."), Scale = SyncedConfig(text, "Tamanho", scale, "Tamanho da raça no formato X,Y,Z."), SkinColor = SyncedConfig(text, "Cor", skinColor, "Cor da pele em HEX. Use -1 para não alterar."), HairColor = SyncedConfig(text, "CorCabeloBarba", hairColor, "Cor do cabelo e barba em HEX (os dois juntos, o jogo usa a mesma cor pros dois). Use -1 para não alterar."), EarColor = SyncedConfig(text, "CorOrelha", earColor, "Cor da orelha em HEX. Use -1 para usar a cor da pele."), EyeColor = SyncedConfig(text, "CorOlho", eyeColor, "Cor dos olhos em HEX."), SecretCode = SyncedConfig(text, "CodigoSecreto", secretCode, "Código secreto digitado no chat para escolher a raça."), HealthBonus = SyncedConfig(text, "BonusVida", healthBonus, "Vida máxima extra, somada em cima do vanilla (nunca abaixo)."), StaminaBonus = SyncedConfig(text, "BonusStamina", staminaBonus, "Stamina máxima extra, somada em cima do vanilla."), EitrBonus = SyncedConfig(text, "BonusEitr", eitrBonus, "Eitr máximo extra, somado em cima do vanilla."), CarryWeightBonus = SyncedConfig(text, "BonusPeso", carryWeightBonus, "Peso máximo extra que pode carregar, somado em cima do vanilla."), HealthRegenMultiplier = SyncedConfig(text, "MultiplicadorRegenVida", healthRegenMult, "Velocidade de regeneração de vida (e cura em geral). 1.0 = vanilla, 1.4 = 40% mais rápido."), StaminaRegenMultiplier = SyncedConfig(text, "MultiplicadorRegenStamina", staminaRegenMult, "Velocidade de regeneração de stamina. 1.0 = vanilla."), EitrRegenMultiplier = SyncedConfig(text, "MultiplicadorRegenEitr", eitrRegenMult, "Velocidade de regeneração de eitr. 1.0 = vanilla."), DamageDoneMultiplier = SyncedConfig(text, "MultiplicadorDanoCausado", damageDoneMult, "Multiplicador de dano causado em geral. 1.0 = vanilla, 1.15 = +15%."), SkillDamageMultipliers = SyncedConfig(text, "MultiplicadorDanoPorSkill", skillDamageMultipliers, "Bônus de dano extra quando o golpe usa um skill específico, formato 'Skill:Mult,Skill:Mult'. Skills comuns: Swords, Knives, Clubs, Polearms, Spears, Axes, Bows, Crossbows, Unarmed, ElementalMagic, BloodMagic. Ex: 'BloodMagic:1.3,Bows:1.15'."), BackstabMultiplier = SyncedConfig(text, "MultiplicadorAtaqueFurtivo", backstabMult, "Multiplicador extra no bônus de dano de ataque furtivo (backstab). 1.0 = vanilla."), DamageTakenMultiplier = SyncedConfig(text, "MultiplicadorDanoRecebido", damageTakenMult, "Multiplicador de dano recebido em geral. 1.0 = vanilla, 0.85 = -15%."), LifestealPercent = SyncedConfig(text, "RouboDeVida", lifestealPercent, "Fração do dano causado que vira cura pro atacante. 0 = desativado, 0.12 = 12%."), StealthMultiplier = SyncedConfig(text, "MultiplicadorFurtividade", stealthMult, "Multiplicador do fator de furtividade. Menor que 1.0 = mais furtivo (precisa confirmar em jogo se a direção bate)."), SpeedMultiplier = SyncedConfig(text, "MultiplicadorVelocidade", speedMult, "Multiplicador de velocidade de movimento (andar/correr). 1.0 = vanilla."), Resistances = SyncedConfig(text, "Resistencias", resistances, "Resistências a dano por tipo, formato 'Tipo:Nivel,Tipo:Nivel'. Tipos: Blunt, Slash, Pierce, Chop, Pickaxe, Fire, Frost, Lightning, Poison, Spirit. Niveis: Normal, Resistant, VeryResistant, SlightlyResistant, Weak, VeryWeak, SlightlyWeak, Immune, Ignore. Ex: 'Frost:Immune,Fire:Weak'."), NoResourceCost = SyncedConfig(text, "SemGastoStaminaEitr", noResourceCost, "Se true, não gasta stamina nem eitr ao usar ataques/habilidades (a barra só existe pra visual)."), XpGainMultiplier = SyncedConfig(text, "MultiplicadorGanhoXP", xpGainMult, "Multiplicador de XP ganho em skills ao acertar golpes. 1.0 = vanilla, 1.1 = +10%."), KnockbackMultiplier = SyncedConfig(text, "MultiplicadorEmpurrao", knockbackMult, "Multiplicador da força de empurrão (knockback) que os golpes causam. 1.0 = vanilla."), EitrCostMultiplier = SyncedConfig(text, "MultiplicadorCustoEitr", eitrCostMult, "Multiplicador do custo de Eitr ao usar magia. 1.0 = vanilla, 0.8 = -20% custo. Ignorado se SemGastoStaminaEitr estiver ligado."), StaminaCostModifiers = SyncedConfig(text, "ModificadoresCustoStamina", staminaCostModifiers, "Reduz (ou aumenta) o custo de stamina por ação específica, formato 'Acao:Valor,Acao:Valor'. Ações: Attack, Block, Dodge, Jump, Run, Sneak, Swim. Valor positivo reduz custo (ex: 0.2 ~ -20%), negativo aumenta (ex: -0.1 ~ +10%). EXPERIMENTAL — a escala exata do valor pode precisar de ajuste testando em jogo."), AttackDamageTypeMultipliers = SyncedConfig(text, "MultiplicadorDanoPorTipo", attackDamageTypeMultipliers, "Bônus de dano causado, só na fatia daquele TIPO de dano específico (diferente do MultiplicadorDanoPorSkill, que é por arma). Formato 'Tipo:Mult,Tipo:Mult'. Tipos: Blunt, Slash, Pierce, Chop, Pickaxe, Fire, Frost, Lightning, Poison, Spirit."), NightOnlyBonuses = SyncedConfig(text, "BonusSoDeNoite", nightOnlyBonuses, "Se true, os multiplicadores de regen (vida/stamina/eitr) e de velocidade dessa raça só valem durante a noite (EnvMan.IsNight()). De dia, esses dois viram vanilla (1.0). Outros bônus (dano, roubo de vida, etc) continuam sempre ativos."), DayNightHealthShift = SyncedConfig(text, "OscilacaoVidaDiaNoite", dayNightHealthShift, "Faz a vida máxima subir de noite e cair de dia, em cima do BonusVida normal. Ex: 50 = +50 vida à noite, -50 vida de dia (uma diferença total de 100 entre dia e noite). 0 = desativado."), BiomeHealthShifts = SyncedConfig(text, "OscilacaoVidaPorBioma", biomeHealthShifts, "Soma/subtrai vida máxima dependendo do bioma atual do player, formato 'Bioma:Valor,Bioma:Valor'. Biomas: Meadows, BlackForest, Swamp, Mountain, Plains, Mistlands, AshLands, DeepNorth, Ocean. Ex: 'Mistlands:50,Meadows:-20'. Biomas não listados não têm efeito."), HeatResistanceBonus = SyncedConfig(text, "BonusResistenciaFrio", heatResistanceBonus, "Se diferente de 0, essa raça é IMUNE ao frio/calor ambiente (o que causa o status 'Congelando' e o dano de exposição a lava), diferente de resistência a dano de Gelo/Fogo em combate. O valor em si não importa (só precisa ser != 0) — é usado como liga/desliga, não como intensidade."), CrouchInvisible = SyncedConfig(text, "InvisivelAoAgachar", crouchInvisible, "Se true, monstros não conseguem sentir/ver/ouvir o player enquanto estiver agachado (o player continua visível normalmente pros outros players — só engana a IA dos bichos, sem invisibilidade de verdade)."), CrouchInvisibleNightOnly = SyncedConfig(text, "InvisivelAoAgacharSoDeNoite", crouchInvisibleNightOnly, "Se true, o InvisivelAoAgachar acima só funciona durante a noite (EnvMan.IsNight()). De dia, agachar não engana os monstros, funciona vanilla mesmo. Não faz nada se InvisivelAoAgachar estiver desligado."), LowHealthThreshold = SyncedConfig(text, "Habilidade_Orc_LimiarVida", lowHealthThreshold, "Fúria de Sangue (Orc): abaixo de que % de vida (0 a 1) o bônus de dano extra ativa. 0 = desativado."), LowHealthDamageBonus = SyncedConfig(text, "Habilidade_Orc_BonusDano", lowHealthDamageBonus, "Fúria de Sangue (Orc): multiplicador de dano causado quando a vida está abaixo do limiar acima."), StillHealAura = SyncedConfig(text, "Habilidade_ElfoLuz_Ativo", stillHealAura, "Se true, ficar parado por um tempo regenera vida extra periodicamente (autocura, não afeta outros players)."), StillHealAmount = SyncedConfig(text, "Habilidade_ElfoLuz_QuantidadeCura", stillHealAmount, "Quantidade de vida curada por tick enquanto parado."), StillHealInterval = SyncedConfig(text, "Habilidade_ElfoLuz_Intervalo", stillHealInterval, "Intervalo em segundos entre cada tick de cura enquanto parado."), StillHealRequiredStillTime = SyncedConfig(text, "Habilidade_ElfoLuz_TempoParado", stillHealRequiredStillTime, "Quantos segundos parado (sem se mover) até a cura começar a ativar."), IronStanceEnabled = SyncedConfig(text, "Habilidade_Anao_Ativo", ironStanceEnabled, "Postura de Ferro (Anão): reduz dano extra e zera empurrão enquanto estiver bloqueando (IsBlocking())."), IronStanceExtraDamageReduction = SyncedConfig(text, "Habilidade_Anao_ReducaoExtra", ironStanceExtraDamageReduction, "Redução de dano EXTRA (fração 0-1) enquanto bloqueando, somada ao bloqueio normal do jogo. Ex: 0.3 = -30% adicional."), BackstabStaminaRefundChance = SyncedConfig(text, "Habilidade_Halfling_ChanceReembolso", backstabStaminaRefundChance, "Golpe de Oportunidade (Halfling): chance (0-1) de reembolsar stamina num ataque furtivo bem-sucedido. 0 = desativado."), BackstabStaminaRefundAmount = SyncedConfig(text, "Habilidade_Halfling_QuantidadeReembolso", backstabStaminaRefundAmount, "Quantidade de stamina reembolsada quando a chance acima é bem-sucedida."), TremorEnabled = SyncedConfig(text, "Habilidade_Jotun_Ativo", tremorEnabled, "Tremor (Jotun): ao aterrissar depois de cair de uma certa altura, empurra inimigos próximos."), TremorMinAirTime = SyncedConfig(text, "Habilidade_Jotun_TempoNoAr", tremorMinAirTime, "Tempo mínimo no ar (segundos) pra considerar que a queda foi grande o suficiente pra ativar o tremor."), TremorRadius = SyncedConfig(text, "Habilidade_Jotun_Raio", tremorRadius, "Raio em metros do tremor ao aterrissar."), TremorKnockback = SyncedConfig(text, "Habilidade_Jotun_Empurrao", tremorKnockback, "Força do empurrão aplicado nos inimigos dentro do raio do tremor."), TremorFireDamage = SyncedConfig(text, "Habilidade_Tremor_DanoFogo", tremorFireDamage, "Dano de fogo extra aplicado junto do empurrão do tremor (além do empurrão puro). 0 = sem dano, só empurra."), TremorStaggerMultiplier = SyncedConfig(text, "Habilidade_Tremor_Atordoamento", tremorStaggerMultiplier, "Multiplicador de atordoamento (stagger) do tremor. 1.0 = vanilla, valores maiores atordoam mais forte."), SecondWindEnabled = SyncedConfig(text, "Habilidade_Humano_Ativo", secondWindEnabled, "Segundo Fôlego (Humano): quando a vida cai abaixo do limiar, recupera vida/stamina uma vez, com cooldown."), SecondWindThreshold = SyncedConfig(text, "Habilidade_Humano_LimiarVida", secondWindThreshold, "Abaixo de que % de vida (0 a 1) o Segundo Fôlego ativa."), SecondWindHealAmount = SyncedConfig(text, "Habilidade_Humano_QuantidadeVida", secondWindHealAmount, "Quantidade de vida recuperada quando o Segundo Fôlego ativa."), SecondWindStaminaAmount = SyncedConfig(text, "Habilidade_Humano_QuantidadeStamina", secondWindStaminaAmount, "Quantidade de stamina recuperada quando o Segundo Fôlego ativa."), SecondWindCooldown = SyncedConfig(text, "Habilidade_Humano_Cooldown", secondWindCooldown, "Cooldown em segundos antes do Segundo Fôlego poder ativar de novo."), OnKillHealAmount = SyncedConfig(text, "Habilidade_Vampiro_CuraAoMatar", onKillHealAmount, "Sede de Sangue (Vampiro): quantidade de vida curada sempre que um golpe do player mata alguém. 0 = desativado."), OnKillHealNightOnly = SyncedConfig(text, "Habilidade_Vampiro_CuraSoDeNoite", onKillHealNightOnly, "Se true, a cura ao matar acima só funciona durante a noite (EnvMan.IsNight())."), StillHealDayOnly = SyncedConfig(text, "Habilidade_ElfoLuz_SoDeDia", stillHealDayOnly, "Se true, a Aura de Cura do Elfo da Luz só funciona durante o DIA (o inverso do Vampiro)."), BlockAuraEnabled = SyncedConfig(text, "Habilidade_AuraBloqueio_Ativo", blockAuraEnabled, "Aura de Bloqueio (Efrit/Jotun): causa dano elemental em quem estiver perto enquanto o player bloqueia."), BlockAuraDamage = SyncedConfig(text, "Habilidade_AuraBloqueio_Dano", blockAuraDamage, "Dano causado a cada tick (~0.6s) pra cada inimigo dentro do raio, enquanto bloqueando."), BlockAuraRadius = SyncedConfig(text, "Habilidade_AuraBloqueio_Raio", blockAuraRadius, "Raio em metros da Aura de Bloqueio."), BlockAuraIsFrost = SyncedConfig(text, "Habilidade_AuraBloqueio_EhGelo", blockAuraIsFrost, "Se true, o dano da Aura de Bloqueio é de Gelo (Jotun). Se false, é de Fogo (Efrit)."), BlockAuraSlowEnabled = SyncedConfig(text, "Habilidade_AuraBloqueio_Lentidao_Ativo", blockAuraSlowEnabled, "Se true, quem for atingido pela Aura de Bloqueio também fica mais lento por um tempo (Jotun)."), BlockAuraSlowPercent = SyncedConfig(text, "Habilidade_AuraBloqueio_Lentidao_Percentual", blockAuraSlowPercent, "Fração (0-1) de redução de velocidade aplicada no alvo. Ex: 0.35 = -35% de velocidade."), BlockAuraSlowDuration = SyncedConfig(text, "Habilidade_AuraBloqueio_Lentidao_Duracao", blockAuraSlowDuration, "Quantos segundos a lentidão dura depois do último tick que atingiu o alvo."), OnHitElementalEnabled = SyncedConfig(text, "Habilidade_DanoElementalPorGolpe_Ativo", onHitElementalEnabled, "Se true, todo golpe de ataque acertado soma dano elemental extra (usa o mesmo elemento da Aura de Bloqueio)."), OnHitElementalDamage = SyncedConfig(text, "Habilidade_DanoElementalPorGolpe_Dano", onHitElementalDamage, "Quanto de dano elemental extra soma em cada golpe de ataque acertado."), FlightEnabled = SyncedConfig(text, "Habilidade_Voo", flightEnabled, "Fada: liga/desliga a habilidade de voo (tecla configurável em Geral/TeclaVoo)."), FlightStaminaCostPerTick = SyncedConfig(text, "Habilidade_Voo_GastoStaminaPorTick", flightStaminaCostPerTick, "Fada: quanta stamina é gasta a cada tick (~0.6s) enquanto voa, valor fixo. Pousa automaticamente ao zerar."), FlightMinStaminaToStart = SyncedConfig(text, "Habilidade_Voo_StaminaMinimaPraDecolar", flightMinStaminaToStart, "Fada: quantidade mínima de stamina necessária pra CONSEGUIR decolar (não deixa decolar de novo com só uma sobrinha de stamina logo depois de pousar sem estamina)."), EvolvesTo = SyncedConfig(text, "Evolucao_RacaEvoluida", evolvesTo, "ID da raça pra qual essa raça evolui automaticamente ao acumular o suficiente (ver EvolucaoLimite). Vazio = não evolui."), EvolutionThreshold = SyncedConfig(text, "Evolucao_Limite", evolutionThreshold, "Quanto precisa acumular (kills, dano bloqueado, vida curada, segundos jogados, etc — depende da raça) pra evoluir.") }; } private ConfigEntry SyncedConfig(string group, string name, T value, string description) { ConfigEntry val = MainConfigFile.Bind(group, name, value, description); SyncedConfigEntry syncedConfigEntry = ModConfigSync.AddConfigEntry(val); syncedConfigEntry.SynchronizedConfig = true; return val; } private void OnConfigurationSynchronized(object sender, EventArgs args) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Configuração sincronizada com o servidor."); if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } NetworkRaces.Clear(); ZNetViewCache.Clear(); foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null)) { string visualKey = GetVisualKey(allPlayer); if (!string.IsNullOrWhiteSpace(visualKey)) { LastAppliedRace[visualKey] = ""; } InvalidateHeadCache(allPlayer); } } ReRegisterSecretCodeCommands(); foreach (Player allPlayer2 in Player.GetAllPlayers()) { ApplyRaceWithDelays(allPlayer2); } } private void LoadAssets() { ElfEarsMalePrefab = LoadPrefabFromEmbedded("ears_elf_m"); ElfEarsFemalePrefab = LoadPrefabFromEmbedded("ears_elf_f"); OrcEarsMalePrefab = LoadPrefabFromEmbedded("orc_ears_m"); OrcEarsFemalePrefab = LoadPrefabFromEmbedded("orc_ears_f"); OrcTuskPrefab = LoadPrefabFromEmbedded("orc_tusk"); HighElfEyesPrefab = LoadPrefabFromEmbedded("high_elf_eyes"); HornMalePrefab = LoadPrefabFromEmbedded("horns_m"); HornFemalePrefab = LoadPrefabFromEmbedded("horns_f"); FairyBodyMalePrefab = LoadPrefabFromEmbedded("fada_corpo_m"); FairyBodyFemalePrefab = LoadPrefabFromEmbedded("fada_corpo_f"); } private GameObject LoadPrefabFromEmbedded(string assetName) { try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string x) => x.EndsWith(assetName)); if (text == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Asset embutido '" + assetName + "' não encontrado na DLL.")); string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text2 in manifestResourceNames) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("RESOURCE: " + text2)); } return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Stream '" + assetName + "' nulo.")); return null; } byte[] array; using (MemoryStream memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } AssetBundle val = AssetBundle.LoadFromMemory(array); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Falha ao carregar AssetBundle '" + assetName + "'.")); return null; } GameObject val2 = val.LoadAsset(assetName) ?? val.LoadAllAssets().FirstOrDefault(); if ((Object)(object)val2 == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Nenhum prefab em '" + assetName + "'.")); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Prefab '" + assetName + "' carregado.")); } return val2; } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Erro ao carregar asset '{assetName}': {arg}"); return null; } } private static bool IsRaceEnabled(string race) { RaceConfig value; return !string.IsNullOrWhiteSpace(race) && Races.TryGetValue(race, out value) && value.Enabled.Value; } private static bool RaceUsesForcedSkin(string race) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0054: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(race) || !Races.TryGetValue(race, out var value)) { return false; } Vector3 val = ParseColorConfig(value.SkinColor.Value, InvalidColor); return val.x >= 0f && val.y >= 0f && val.z >= 0f; } private static bool RaceUsesForcedHair(string race) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0054: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(race) || !Races.TryGetValue(race, out var value)) { return false; } Vector3 val = ParseColorConfig(value.HairColor.Value, InvalidColor); return val.x >= 0f && val.y >= 0f && val.z >= 0f; } private static Vector3 GetRaceHairColor(string race) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) RaceConfig value; return Races.TryGetValue(race, out value) ? ParseColorConfig(value.HairColor.Value, InvalidColor) : InvalidColor; } private static Vector3 GetRaceScale(string race) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) RaceConfig value; return Races.TryGetValue(race, out value) ? ParseVector(value.Scale.Value, HumanScale) : HumanScale; } private static Vector3 GetRaceSkinColor(string race) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) RaceConfig value; return Races.TryGetValue(race, out value) ? ParseColorConfig(value.SkinColor.Value, Vector3.one) : Vector3.one; } private static Vector3 BlendRaceHueWithBrightness(Vector3 raceColorVec, Vector3 brightnessSourceVec) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) Color val = default(Color); ((Color)(ref val))..ctor(Mathf.Clamp01(raceColorVec.x), Mathf.Clamp01(raceColorVec.y), Mathf.Clamp01(raceColorVec.z)); Color val2 = default(Color); ((Color)(ref val2))..ctor(Mathf.Clamp01(brightnessSourceVec.x), Mathf.Clamp01(brightnessSourceVec.y), Mathf.Clamp01(brightnessSourceVec.z)); float num = default(float); float num2 = default(float); float num3 = default(float); Color.RGBToHSV(val, ref num, ref num2, ref num3); float num4 = default(float); float num5 = default(float); Color.RGBToHSV(val2, ref num3, ref num4, ref num5); num5 = Mathf.Max(num5, 0.55f); Color val3 = Color.HSVToRGB(num, num2, num5); return new Vector3(val3.r, val3.g, val3.b); } private static Vector3 ParseVector(string value, Vector3 fallback) { //IL_0073: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) try { if (string.IsNullOrWhiteSpace(value)) { return fallback; } string[] array = value.Split(new char[1] { ',' }); if (array.Length != 3) { return fallback; } return new Vector3(float.Parse(array[0].Trim(), CultureInfo.InvariantCulture), float.Parse(array[1].Trim(), CultureInfo.InvariantCulture), float.Parse(array[2].Trim(), CultureInfo.InvariantCulture)); } catch { return fallback; } } private static Vector3 ParseColorConfig(string value, Vector3 fallback) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) try { if (string.IsNullOrWhiteSpace(value)) { return fallback; } value = value.Trim(); if (value == "-1" || value.Equals("none", StringComparison.OrdinalIgnoreCase) || value.Equals("nao", StringComparison.OrdinalIgnoreCase) || value.Equals("não", StringComparison.OrdinalIgnoreCase) || value == "-1,-1,-1") { return InvalidColor; } if (value.StartsWith("#")) { Color val = default(Color); if (ColorUtility.TryParseHtmlString(value, ref val)) { return new Vector3(val.r, val.g, val.b); } return fallback; } return ParseVector(value, fallback); } catch { return fallback; } } private static string GetRaceFromSecretCode(string text) { if (string.IsNullOrWhiteSpace(text)) { return null; } foreach (KeyValuePair race in Races) { RaceConfig value = race.Value; if (value?.SecretCode == null || !value.Enabled.Value || !text.Equals(value.SecretCode.Value, StringComparison.Ordinal)) { continue; } return race.Key; } return null; } public string GetRaceName(string race) { if (RaceNameTexts.TryGetValue(race, out var value) && value != null) { return value.Value; } RaceConfig value2; return Races.TryGetValue(race, out value2) ? value2.DisplayName : race; } private static float GetEvolutionProgress(Player p) { if ((Object)(object)p == (Object)null) { return 0f; } try { ZNetView cachedZNetView = GetCachedZNetView(p); if ((Object)(object)cachedZNetView == (Object)null || cachedZNetView.GetZDO() == null) { return 0f; } return cachedZNetView.GetZDO().GetFloat("ValheimEvoProgress", 0f); } catch { return 0f; } } private static void SetEvolutionProgress(Player p, float value) { if ((Object)(object)p == (Object)null) { return; } try { ZNetView cachedZNetView = GetCachedZNetView(p); if (!((Object)(object)cachedZNetView == (Object)null) && cachedZNetView.GetZDO() != null) { cachedZNetView.GetZDO().Set("ValheimEvoProgress", value); } } catch { } } private static void AddEvolutionProgress(Player p, string race, float amount) { if ((Object)(object)p == (Object)null || (Object)(object)p != (Object)(object)Player.m_localPlayer || amount == 0f || string.IsNullOrWhiteSpace(race) || !RacialAbilitiesEnabled.Value || !Races.TryGetValue(race, out var value) || string.IsNullOrWhiteSpace(value.EvolvesTo.Value) || value.EvolutionThreshold.Value <= 0f) { return; } float num = GetEvolutionProgress(p) + amount; SetEvolutionProgress(p, num); if (!(num < value.EvolutionThreshold.Value)) { string value2 = value.EvolvesTo.Value; if (IsRaceEnabled(value2)) { SetEvolutionProgress(p, 0f); ((Character)p).Message((MessageType)2, Text_VoceEvoluiu.Value, 0, (Sprite)null); TransformLocalPlayerFromMarketplace(value2); } } } private void ApplyFairyBodyDirect(Transform root, bool isFemale) { GameObject val = (isFemale ? FairyBodyFemalePrefab : FairyBodyMalePrefab); if ((Object)(object)root == (Object)null || (Object)(object)val == (Object)null) { if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Prefab " + (isFemale ? "fada_corpo_f" : "fada_corpo_m") + " não encontrado.")); } return; } Transform val2 = root.Find("FadaCorpo"); if ((Object)(object)val2 == (Object)null) { GameObject val3 = SkinnedAccessoryAttacher.Attach(val, root); if ((Object)(object)val3 == (Object)null) { return; } ((Object)val3).name = "FadaCorpo"; StripItemComponents(val3); val2 = val3.transform; } ReplaceFairyBodyMockMaterials(root, val2); SetVanillaBodyRenderersVisible(root, visible: false); } private void ReplaceFairyBodyMockMaterials(Transform root, Transform fadaCorpo) { if ((Object)(object)root == (Object)null || (Object)(object)fadaCorpo == (Object)null) { return; } Material val = null; SkinnedMeshRenderer[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren) { if ((Object)(object)val2 == (Object)null || ((Object)((Component)val2).gameObject).name != "body") { continue; } Material[] sharedMaterials = ((Renderer)val2).sharedMaterials; foreach (Material val3 in sharedMaterials) { if ((Object)(object)val3 != (Object)null && ((Object)val3).name.StartsWith("PlayerMaterial")) { val = val3; break; } } if ((Object)(object)val != (Object)null) { break; } } if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[ValheimRaces] Não achei o material de pele real (PlayerMaterial) pra substituir o mock do corpo da Fada."); return; } SkinnedMeshRenderer[] componentsInChildren2 = ((Component)fadaCorpo).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val4 in componentsInChildren2) { if ((Object)(object)val4 == (Object)null) { continue; } string text = ((Object)((Component)val4).gameObject).name.ToLowerInvariant(); if (text.Contains("eyebrow") || text.Contains("sobrancelha") || text.Contains("brow")) { continue; } bool flag = false; Material[] sharedMaterials2 = ((Renderer)val4).sharedMaterials; foreach (Material val5 in sharedMaterials2) { if ((Object)(object)val5 != (Object)null && ((Object)val5).name.StartsWith("JVLmock")) { flag = true; break; } } if (flag) { Material[] array = (Material[])(object)new Material[((Renderer)val4).sharedMaterials.Length]; for (int m = 0; m < array.Length; m++) { array[m] = val; } ((Renderer)val4).sharedMaterials = array; } } } private void RemoveFairyBodyDirect(Transform root) { RemoveHeadAttachmentDirect(root, "FadaCorpo"); SetVanillaBodyRenderersVisible(root, visible: true); string visualKey = GetVisualKey(((Component)root).GetComponent()); if (!string.IsNullOrWhiteSpace(visualKey)) { FairyEyebrowRenderers.Remove(visualKey); FairyEyebrowShared.Remove(visualKey); FairyBodyAnimators.Remove(visualKey); } } private static void SetVanillaBodyRenderersVisible(Transform root, bool visible) { if ((Object)(object)root == (Object)null) { return; } SkinnedMeshRenderer[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).transform.parent == (Object)null) && !((Object)(object)((Component)val).transform.root != (Object)(object)root) && !IsDescendantOfOwnAccessory(((Component)val).transform, root)) { string text = ((Object)((Component)val).gameObject).name.ToLowerInvariant(); if (text == "body" || text.Contains("hair") || text.Contains("beard")) { ((Renderer)val).enabled = visible; } } } } private static bool IsDescendantOfOwnAccessory(Transform t, Transform root) { for (Transform val = t; (Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root; val = val.parent) { string text = ((Object)val).name.ToLowerInvariant(); if (!text.Contains("fadacorpo")) { switch (text) { default: if (!text.Contains("higheleyes")) { continue; } break; case "ears": case "orcears": case "horn": case "orctusk": break; } } return true; } return false; } private Vector3 GetCurrentHairVector(Player p) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null) { return Vector3.one; } VisEquipment component = ((Component)p).GetComponent(); if ((Object)(object)component == (Object)null) { return Vector3.one; } try { FieldInfo field = typeof(VisEquipment).GetField("m_hairColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.GetValue(component) is Vector3 result) { return result; } } catch { } return Vector3.one; } private static bool ShareHairMaterial(Player p, Renderer[] eyebrowRenderers) { if ((Object)(object)p == (Object)null || eyebrowRenderers == null || eyebrowRenderers.Length == 0) { return false; } Material val = null; SkinnedMeshRenderer[] componentsInChildren = ((Component)((Component)p).transform).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && ((Object)((Component)val2).gameObject).name.ToLowerInvariant().Contains("hair")) { Material[] sharedMaterials = ((Renderer)val2).sharedMaterials; if (sharedMaterials.Length != 0 && (Object)(object)sharedMaterials[0] != (Object)null) { val = sharedMaterials[0]; break; } } } if ((Object)(object)val == (Object)null) { List list = new List(); SkinnedMeshRenderer[] componentsInChildren2 = ((Component)((Component)p).transform).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val3 in componentsInChildren2) { if ((Object)(object)val3 != (Object)null) { list.Add(((Object)((Component)val3).gameObject).name); } } ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] Não achei renderer de cabelo (procurei 'hair' no nome). Renderers encontrados no personagem: " + string.Join(", ", list))); } return false; } foreach (Renderer val4 in eyebrowRenderers) { if (!((Object)(object)val4 == (Object)null)) { Material[] array = (Material[])(object)new Material[val4.sharedMaterials.Length]; for (int l = 0; l < array.Length; l++) { array[l] = val; } val4.sharedMaterials = array; } } return true; } private void TickFairyEyebrowColor(Player p) { //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: 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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null || GetRace(p) != "fada") { return; } string visualKey = GetVisualKey(p); if (string.IsNullOrWhiteSpace(visualKey)) { return; } if (!FairyEyebrowRenderers.TryGetValue(visualKey, out var value)) { Transform val = ((Component)p).transform.Find("FadaCorpo"); if ((Object)(object)val == (Object)null) { return; } List list = new List(); Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { string text = ((Object)((Component)val2).gameObject).name.ToLowerInvariant(); if (text.Contains("eyebrow") || text.Contains("sobrancelha") || text.Contains("brow")) { list.Add(val2); } } value = list.ToArray(); FairyEyebrowRenderers[visualKey] = value; if (value.Length == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[ValheimRaces] Nenhum renderer de sobrancelha encontrado no corpo da Fada (procurei 'eyebrow'/'sobrancelha'/'brow' no nome)."); } else { FairyEyebrowShared[visualKey] = ShareHairMaterial(p, value); } } if (value.Length == 0 || (FairyEyebrowShared.TryGetValue(visualKey, out var value2) && value2)) { return; } Vector3 currentHairVector = GetCurrentHairVector(p); Color val3 = default(Color); ((Color)(ref val3))..ctor(currentHairVector.x, currentHairVector.y, currentHairVector.z, 1f); Renderer[] array = value; foreach (Renderer val4 in array) { if ((Object)(object)val4 == (Object)null) { continue; } Material[] materials = val4.materials; foreach (Material val5 in materials) { if (!((Object)(object)val5 == (Object)null)) { if (val5.HasProperty("_Color")) { val5.SetColor("_Color", val3); } if (val5.HasProperty("_BaseColor")) { val5.SetColor("_BaseColor", val3); } } } } } private void TickFairyFlightAnimation(Player p) { if ((Object)(object)p == (Object)null || GetRace(p) != "fada") { return; } string visualKey = GetVisualKey(p); if (string.IsNullOrWhiteSpace(visualKey)) { return; } if (!FairyBodyAnimators.TryGetValue(visualKey, out var value)) { Transform val = ((Component)p).transform.Find("FadaCorpo"); if ((Object)(object)val == (Object)null) { return; } value = ((Component)val).GetComponentsInChildren(true); FairyBodyAnimators[visualKey] = value; if (value.Length == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[ValheimRaces] Nenhum Animator encontrado no corpo da Fada — o parâmetro IsFly não vai ser setado."); } } if (value.Length == 0) { return; } bool debugFly = GetDebugFly(p); Animator[] array = value; foreach (Animator val2 in array) { if (!((Object)(object)val2 == (Object)null)) { try { val2.SetBool("IsFly", debugFly); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[ValheimRaces] Falha ao setar IsFly no Animator da Fada: " + ex.Message)); } } } } private static Vector3 GetVectorField(FieldInfo field, object instance, Vector3 fallback) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (field == null || instance == null) { return fallback; } try { return (Vector3)field.GetValue(instance); } catch { return fallback; } } private static bool GetDebugFly(Player p) { if ((Object)(object)p == (Object)null || DebugFlyField == null) { return false; } try { return (bool)DebugFlyField.GetValue(p); } catch { return false; } } private static void SetDebugFly(Player p, bool value) { if ((Object)(object)p == (Object)null || DebugFlyField == null) { return; } try { DebugFlyField.SetValue(p, value); } catch { } } private static float GetFloatField(FieldInfo field, object instance, float fallback) { if (field == null || instance == null) { return fallback; } try { return (float)field.GetValue(instance); } catch { return fallback; } } private static void SetFloatField(FieldInfo field, object instance, float value) { if (field == null || instance == null) { return; } try { field.SetValue(instance, value); } catch { } } private static KeyCode GetFlightToggleKey() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) string text = ((FlightToggleKey != null) ? FlightToggleKey.Value : "F"); if (_cachedFlightKey.HasValue && _cachedFlightKeyRaw == text) { return _cachedFlightKey.Value; } if (!Enum.TryParse(text?.Trim() ?? "F", ignoreCase: true, out KeyCode result)) { result = (KeyCode)102; } _cachedFlightKey = result; _cachedFlightKeyRaw = text; return result; } private static void StartFlying(Player p) { string visualKey = GetVisualKey(p); if (!string.IsNullOrWhiteSpace(visualKey) && !OriginalDebugFlySpeed.ContainsKey(visualKey)) { OriginalDebugFlySpeed[visualKey] = GetFloatField(DebugFlySpeedField, p, 8f); } float floatField = GetFloatField(RunSpeedField, p, 6f); SetFloatField(DebugFlySpeedField, p, floatField); SetDebugFly(p, value: true); } private static void StopFlying(Player p) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) SetDebugFly(p, value: false); string visualKey = GetVisualKey(p); if (!string.IsNullOrWhiteSpace(visualKey) && OriginalDebugFlySpeed.TryGetValue(visualKey, out var value)) { SetFloatField(DebugFlySpeedField, p, value); OriginalDebugFlySpeed.Remove(visualKey); } Rigidbody val = (((Object)(object)p != (Object)null) ? ((Component)p).GetComponent() : null); if ((Object)(object)val != (Object)null) { val.useGravity = true; val.linearVelocity = Vector3.zero; } if ((Object)(object)p != (Object)null && MaxAirAltitudeField != null) { SetFloatField(MaxAirAltitudeField, p, ((Component)p).transform.position.y); } } private void TickFlightToggle(Player p) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null || RacialAbilitiesEnabled == null || !RacialAbilitiesEnabled.Value) { return; } string race = GetRace(p); if (!string.IsNullOrWhiteSpace(race) && Races.TryGetValue(race, out var value) && value.FlightEnabled.Value && Input.GetKeyDown(GetFlightToggleKey())) { if (GetDebugFly(p)) { StopFlying(p); } else if (p.GetStamina() < value.FlightMinStaminaToStart.Value) { ((Character)p).Message((MessageType)2, Text_VooSemStamina.Value, 0, (Sprite)null); } else { StartFlying(p); } } } private void TickFlightMovement(Player p) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_0107: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null || !GetDebugFly(p) || GetRace(p) != "fada") { return; } if (p.GetStamina() <= 0f) { StopFlying(p); ((Character)p).Message((MessageType)2, Text_VooSemStamina.Value, 0, (Sprite)null); return; } Rigidbody component = ((Component)p).GetComponent(); if ((Object)(object)component == (Object)null) { return; } component.useGravity = false; Vector3 vectorField = GetVectorField(MoveDirField, p, Vector3.zero); float floatField = GetFloatField(RunSpeedField, p, 6f); Vector3 val = vectorField * floatField; if (ZInput.instance != null) { if (ZInput.GetButton("Jump")) { val += Vector3.up * floatField; } if (ZInput.GetButton("Crouch")) { val -= Vector3.up * floatField; } } component.linearVelocity = val; } private static void TickFlightDrain(Player p, float dt) { if ((Object)(object)p == (Object)null || !GetDebugFly(p) || GetRace(p) != "fada") { return; } string race = GetRace(p); RaceConfig value = null; if (string.IsNullOrWhiteSpace(race) || !Races.TryGetValue(race, out value) || !value.FlightEnabled.Value || RacialAbilitiesEnabled == null || !RacialAbilitiesEnabled.Value) { StopFlying(p); return; } float value2 = value.FlightStaminaCostPerTick.Value; if (!(value2 <= 0f)) { if (p.GetStamina() <= 0f) { StopFlying(p); ((Character)p).Message((MessageType)2, Text_VooSemStamina.Value, 0, (Sprite)null); } else { ((Character)p).AddStamina(0f - value2); } } } private static void ForceLandIfFlying(Player p) { if ((Object)(object)p != (Object)null && GetDebugFly(p)) { StopFlying(p); } } private static void ForceSetZdoRace(Player player, string race) { if ((Object)(object)player == (Object)null) { return; } try { ZNetView cachedZNetView = GetCachedZNetView(player); if (!((Object)(object)cachedZNetView == (Object)null) && cachedZNetView.GetZDO() != null) { cachedZNetView.GetZDO().Set("ValheimRace", race ?? ""); cachedZNetView.GetZDO().Set("ValheimRaceVer", 1); } } catch { } } private static void ForceSetRaceVisualZdo(Player player, string race) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && !string.IsNullOrWhiteSpace(race)) { ForceSetZdoVector(player, "ValheimRaceEarColor", GetCalculatedRaceEarColor(player, race)); if (RaceUsesForcedSkin(race)) { ForceSetZdoVector(player, "ValheimRaceSkinColor", GetRaceSkinColor(race)); } } } private static void ForceSetZdoVector(Player player, string key, Vector3 value) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || string.IsNullOrWhiteSpace(key)) { return; } try { ZNetView cachedZNetView = GetCachedZNetView(player); if (!((Object)(object)cachedZNetView == (Object)null) && cachedZNetView.GetZDO() != null) { cachedZNetView.GetZDO().Set(key + "_x", value.x); cachedZNetView.GetZDO().Set(key + "_y", value.y); cachedZNetView.GetZDO().Set(key + "_z", value.z); } } catch { } } private static string GetZdoRace(Player player) { if ((Object)(object)player == (Object)null) { return ""; } try { ZNetView cachedZNetView = GetCachedZNetView(player); if ((Object)(object)cachedZNetView == (Object)null || cachedZNetView.GetZDO() == null) { return ""; } ZDO zDO = cachedZNetView.GetZDO(); string text = zDO.GetString("ValheimRace", ""); if (string.IsNullOrWhiteSpace(text)) { return ""; } int num = zDO.GetInt("ValheimRaceVer", 0); if (num != 1) { zDO.Set("ValheimRaceVer", 1); } return text; } catch { return ""; } } private static void SetZdoLocked(Player player, bool locked) { if ((Object)(object)player == (Object)null) { return; } try { ZNetView cachedZNetView = GetCachedZNetView(player); if (!((Object)(object)cachedZNetView == (Object)null) && cachedZNetView.GetZDO() != null) { cachedZNetView.GetZDO().Set("ValheimRaceLocked", locked); } } catch { } } private static bool GetZdoLocked(Player player) { if ((Object)(object)player == (Object)null) { return false; } try { ZNetView cachedZNetView = GetCachedZNetView(player); if ((Object)(object)cachedZNetView == (Object)null || cachedZNetView.GetZDO() == null) { return false; } return cachedZNetView.GetZDO().GetBool("ValheimRaceLocked", false); } catch { return false; } } private static Vector3 GetZdoVector(Player player, string key, Vector3 fallback) { //IL_00ae: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || string.IsNullOrWhiteSpace(key)) { return fallback; } try { ZNetView cachedZNetView = GetCachedZNetView(player); if ((Object)(object)cachedZNetView == (Object)null || cachedZNetView.GetZDO() == null) { return fallback; } float num = cachedZNetView.GetZDO().GetFloat(key + "_x", fallback.x); float num2 = cachedZNetView.GetZDO().GetFloat(key + "_y", fallback.y); float num3 = cachedZNetView.GetZDO().GetFloat(key + "_z", fallback.z); return new Vector3(num, num2, num3); } catch { return fallback; } } private static string GetRace(Player player) { if ((Object)(object)player == (Object)null) { return ""; } long playerIdLong = GetPlayerIdLong(player); if (playerIdLong == 0) { return ""; } if (NetworkRaces.TryGetValue(playerIdLong, out var value) && !string.IsNullOrWhiteSpace(value)) { return value; } string zdoRace = GetZdoRace(player); if (!string.IsNullOrWhiteSpace(zdoRace)) { NetworkRaces[playerIdLong] = zdoRace; } return zdoRace; } private bool SetRace(Player player, string race, bool lockPlayer, bool broadcast) { if ((Object)(object)player == (Object)null || !IsRaceEnabled(race)) { return false; } InvalidateHeadCache(player); long playerIdLong = GetPlayerIdLong(player); string visualKey = GetVisualKey(player); if (!IsHeadless()) { bool isApplyingRace = IsApplyingRace; IsApplyingRace = true; try { ResetHelmet(player); ResetSkin(player); } finally { IsApplyingRace = isApplyingRace; } } CleanPlayerVisualCaches(playerIdLong, visualKey); SetEvolutionProgress(player, 0f); if (playerIdLong != 0) { NetworkRaces[playerIdLong] = race; } if (RaceUsesForcedSkin(race)) { CacheOriginalSkinIfNeeded(player); } ForceSetZdoRace(player, race); ForceSetRaceVisualZdo(player, race); if ((Object)(object)player == (Object)(object)Player.m_localPlayer) { SaveLocalRace(race, lockPlayer || IsPlayerLocked(player)); } if (broadcast) { BroadcastRace(player, race); } if (lockPlayer) { SetZdoLocked(player, locked: true); } return true; } private void AdminSetRace(Player target, string race) { if ((Object)(object)target == (Object)null || !IsRaceEnabled(race)) { return; } long playerIdLong = GetPlayerIdLong(target); string visualKey = GetVisualKey(target); SetEvolutionProgress(target, 0f); InvalidateHeadCache(target); if (playerIdLong != 0) { NetworkRaces.Remove(playerIdLong); } if (!string.IsNullOrWhiteSpace(visualKey)) { LastAppliedRace[visualKey] = ""; } if (!IsHeadless()) { bool isApplyingRace = IsApplyingRace; IsApplyingRace = true; try { ResetHelmet(target); ResetSkin(target); } finally { IsApplyingRace = isApplyingRace; } } CleanPlayerVisualCaches(playerIdLong, visualKey); if (playerIdLong != 0) { NetworkRaces[playerIdLong] = race; } ForceSetZdoRace(target, race); ForceSetRaceVisualZdo(target, race); if ((Object)(object)target == (Object)(object)Player.m_localPlayer) { SaveLocalRace(race, IsPlayerLocked(target)); } BroadcastRace(target, race); ApplyRaceWithDelays(target); TopOffVitals(target); if (!IsHeadless()) { SpawnEffect(target); } if ((Object)(object)target == (Object)(object)Player.m_localPlayer) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)("[ValheimRaces/Diag] Emote disparado via AdminSetRace (self) pra '" + target.GetPlayerName() + "'.")); } PlayTransformEmote(); } } private void AdminResetRace(Player target) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { return; } long playerIdLong = GetPlayerIdLong(target); string visualKey = GetVisualKey(target); try { SetEvolutionProgress(target, 0f); } catch { } if (playerIdLong != 0) { NetworkRaces.Remove(playerIdLong); } if (!string.IsNullOrWhiteSpace(visualKey)) { LastAppliedRace[visualKey] = ""; } try { InvalidateHeadCache(target); } catch { } int instanceID = ((Object)target).GetInstanceID(); if (ApplyRaceCoroutineGeneration.ContainsKey(instanceID)) { ApplyRaceCoroutineGeneration[instanceID]++; } try { ForceSetZdoRace(target, ""); } catch { } try { ForceSetZdoVector(target, "ValheimRaceEarColor", InvalidColor); } catch { } try { ForceSetZdoVector(target, "ValheimRaceSkinColor", InvalidColor); } catch { } if ((Object)(object)target == (Object)(object)Player.m_localPlayer) { lastBroadcastRace = null; } if (!IsHeadless()) { try { ResetHelmet(target); } catch { } try { ResetSkin(target); } catch { } } try { CleanPlayerVisualCaches(playerIdLong, visualKey); } catch { } try { ApplyScale(target, HumanScale); } catch { } if (!IsHeadless()) { try { Transform head = FindHead(((Component)target).transform, 0); RemoveHeadAttachmentDirect(((Component)target).transform, "Ears"); RemoveHeadAttachmentDirect(((Component)target).transform, "OrcEars"); RemoveHeadAttachmentDirect(head, "HighElfEyes"); RemoveHeadAttachmentDirect(head, "OrcTusk"); RemoveHeadAttachmentDirect(((Component)target).transform, "Horn"); } catch { } try { RemovePlayerAttachment(target, "JotunFreeze"); } catch { } } try { ApplyRaceWithDelays(target); } catch { } if (IsHeadless()) { return; } try { UpdateRaceStatusEffect(target, ""); } catch { } } private void ResetRace(Player player, bool broadcast) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null)) { long playerIdLong = GetPlayerIdLong(player); string visualKey = GetVisualKey(player); SetEvolutionProgress(player, 0f); if (playerIdLong != 0) { NetworkRaces.Remove(playerIdLong); } if (!string.IsNullOrWhiteSpace(visualKey)) { LastAppliedRace[visualKey] = ""; } InvalidateHeadCache(player); int instanceID = ((Object)player).GetInstanceID(); if (ApplyRaceCoroutineGeneration.ContainsKey(instanceID)) { ApplyRaceCoroutineGeneration[instanceID]++; } ForceSetZdoRace(player, ""); SetZdoLocked(player, locked: false); ForceSetZdoVector(player, "ValheimRaceEarColor", InvalidColor); ForceSetZdoVector(player, "ValheimRaceSkinColor", InvalidColor); if ((Object)(object)player == (Object)(object)Player.m_localPlayer) { ClearLocalSavedRace(); lastBroadcastRace = null; } if (!IsHeadless()) { ResetHelmet(player); ResetSkin(player); } CleanPlayerVisualCaches(playerIdLong, visualKey); ApplyScale(player, HumanScale); if (!IsHeadless()) { Transform head = FindHead(((Component)player).transform, 0); RemoveHeadAttachmentDirect(((Component)player).transform, "Ears"); RemoveHeadAttachmentDirect(((Component)player).transform, "OrcEars"); RemoveHeadAttachmentDirect(head, "HighElfEyes"); RemoveHeadAttachmentDirect(head, "OrcTusk"); RemoveHeadAttachmentDirect(((Component)player).transform, "Horn"); RemovePlayerAttachment(player, "JotunFreeze"); } ApplyRaceWithDelays(player); if (!IsHeadless()) { UpdateRaceStatusEffect(player, ""); } if (broadcast) { BroadcastRace(player, ""); } } } private static void CleanPlayerVisualCaches(long playerIdL, string visualKey) { if (!string.IsNullOrWhiteSpace(visualKey)) { OriginalSkinColors.Remove(visualKey); LastSkinRefreshRequest.Remove(visualKey); } if (playerIdL != 0) { string key = playerIdL.ToString(); OriginalSkinColors.Remove(key); LastSkinRefreshRequest.Remove(key); } } private static bool IsPlayerLocked(Player player) { if ((Object)(object)player == (Object)null) { return false; } if (GetZdoLocked(player)) { return true; } if ((Object)(object)player == (Object)(object)Player.m_localPlayer && !IsClientConnectedToRemoteServer() && HasSavedLocalRaceLocked()) { return true; } return false; } private static Vector3 GetRaceEarColor(Player p, string race) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrWhiteSpace(race) && Races.TryGetValue(race, out var value)) { Vector3 val = ParseColorConfig(value.EarColor.Value, InvalidColor); if (val.x >= 0f) { if (RaceUsesForcedSkin(race) && val == GetRaceSkinColor(race)) { return GetNetworkSkinColor(p, race); } return val; } } Vector3 zdoVector = GetZdoVector(p, "ValheimRaceEarColor", InvalidColor); if (zdoVector.x >= 0f) { return zdoVector; } if (RaceUsesForcedSkin(race)) { return GetNetworkSkinColor(p, race); } return ((Object)(object)Instance != (Object)null) ? Instance.GetCurrentSkinVector(p) : Vector3.one; } private static Vector3 GetCalculatedRaceEarColor(Player p, string race) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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_0051: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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) if (!string.IsNullOrWhiteSpace(race) && Races.TryGetValue(race, out var value)) { Vector3 val = ParseColorConfig(value.EarColor.Value, InvalidColor); if (val.x >= 0f) { if (RaceUsesForcedSkin(race) && val == GetRaceSkinColor(race)) { return GetNetworkSkinColor(p, race); } return val; } } if (RaceUsesForcedSkin(race)) { return GetNetworkSkinColor(p, race); } return ((Object)(object)Instance != (Object)null) ? Instance.GetCurrentSkinVector(p) : Vector3.one; } private static Vector3 GetNetworkSkinColor(Player p, string race) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (!RaceUsesForcedSkin(race)) { return Vector3.one; } Vector3 raceSkinColor = GetRaceSkinColor(race); string text = (((Object)(object)p != (Object)null) ? GetVisualKey(p) : null); if (!string.IsNullOrWhiteSpace(text) && OriginalSkinColors.TryGetValue(text, out var value)) { return BlendRaceHueWithBrightness(raceSkinColor, value); } Vector3 zdoVector = GetZdoVector(p, "ValheimRaceSkinColor", InvalidColor); if (zdoVector.x >= 0f) { return BlendRaceHueWithBrightness(raceSkinColor, zdoVector); } return raceSkinColor; } private static Color GetRaceEyeColor(string race) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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 (!Races.TryGetValue(race, out var value)) { return Color.red; } Vector3 val = ParseColorConfig(value.EyeColor.Value, new Vector3(1f, 0f, 0f)); return (Color)((val.x < 0f) ? Color.red : new Color(val.x, val.y, val.z, 1f)); } private static Sprite GetRaceIcon(string race) { if (!string.IsNullOrWhiteSpace(race) && RaceSpecificIcons.TryGetValue(race, out var value) && (Object)(object)value != (Object)null) { return value; } Sprite val = ((!string.IsNullOrWhiteSpace(race)) ? LoadIconFromEmbedded("race_icon_" + race + ".rgba") : null); if ((Object)(object)val == (Object)null) { val = GetPlaceholderIcon(); } if (!string.IsNullOrWhiteSpace(race)) { RaceSpecificIcons[race] = val; } return val; } private static Sprite GetPlaceholderIcon() { if (_placeholderIconResolved) { return _placeholderIcon; } _placeholderIconResolved = true; _placeholderIcon = LoadIconFromEmbedded("race_icon.rgba"); if ((Object)(object)_placeholderIcon != (Object)null) { return _placeholderIcon; } string[] array = new string[5] { "TrophyNeck", "TrophyDeer", "TrophyGreyling", "Amber", "Feathers" }; try { string[] array2 = array; foreach (string text in array2) { ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(text) : null); Sprite val2 = ((val != null) ? val.GetComponent() : null)?.m_itemData?.m_shared?.m_icons?.FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { _placeholderIcon = val2; break; } } } catch (Exception ex) { ValheimRacesPlugin instance2 = Instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)("Falha ao buscar ícone de fallback pro status de raça: " + ex.Message)); } } return _placeholderIcon; } private static Sprite LoadIconFromEmbedded(string fileName) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string x) => x.EndsWith(fileName)); if (text == null) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Ícone embutido '" + fileName + "' não encontrado na DLL (verifique se foi adicionado como Embedded Resource).")); } return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { return null; } byte[] array; using (MemoryStream memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } int num = 65536; if (array.Length != num) { ValheimRacesPlugin instance2 = Instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)$"Ícone '{fileName}' tem {array.Length} bytes, esperado {num} (RaceIconSize errado?)."); } return null; } Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false); val.LoadRawTextureData(array); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } catch (Exception arg) { ValheimRacesPlugin instance3 = Instance; if (instance3 != null) { ((BaseUnityPlugin)instance3).Logger.LogError((object)$"Erro ao carregar ícone '{fileName}': {arg}"); } return null; } } private static StatusEffect GetOrCreateRaceStatusEffect(string race) { if (RaceStatusEffects.TryGetValue(race, out var value) && (Object)(object)value != (Object)null) { return value; } if (!Races.TryGetValue(race, out var value2)) { return null; } StatusEffect val = ScriptableObject.CreateInstance(); ((Object)val).name = "ValheimRace_" + race; val.m_name = Fmt(Text_StatNomeRaca.Value, Instance.GetRaceName(race)); val.m_icon = GetRaceIcon(race); val.m_tooltip = BuildTooltip(value2); RaceStatusEffects[race] = val; return val; } private static Dictionary BuildDamageTypeLabelsPt() { return new Dictionary { { (DamageType)1, Text_DanoBlunt.Value }, { (DamageType)2, Text_DanoSlash.Value }, { (DamageType)4, Text_DanoPierce.Value }, { (DamageType)8, Text_DanoChop.Value }, { (DamageType)16, Text_DanoPickaxe.Value }, { (DamageType)32, Text_DanoFire.Value }, { (DamageType)64, Text_DanoFrost.Value }, { (DamageType)128, Text_DanoLightning.Value }, { (DamageType)256, Text_DanoPoison.Value }, { (DamageType)512, Text_DanoSpirit.Value } }; } private static Dictionary BuildBiomeLabelsPt() { return new Dictionary { { (Biome)1, Text_BiomaMeadows.Value }, { (Biome)8, Text_BiomaBlackForest.Value }, { (Biome)2, Text_BiomaSwamp.Value }, { (Biome)4, Text_BiomaMountain.Value }, { (Biome)16, Text_BiomaPlains.Value }, { (Biome)512, Text_BiomaMistlands.Value }, { (Biome)32, Text_BiomaAshLands.Value }, { (Biome)64, Text_BiomaDeepNorth.Value }, { (Biome)256, Text_BiomaOcean.Value } }; } private static Dictionary ParseBiomeShiftsForTooltip(string value) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(); if (string.IsNullOrWhiteSpace(value)) { return dictionary; } string[] array = value.Split(new char[1] { ',' }); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length == 2 && Enum.TryParse(array2[0].Trim(), ignoreCase: true, out Biome result) && float.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { dictionary[result] = result2; } } return dictionary; } private static string BuildTooltip(RaceConfig cfg) { //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0554: Unknown result type (might be due to invalid IL or missing references) //IL_0564: Unknown result type (might be due to invalid IL or missing references) //IL_0569: Unknown result type (might be due to invalid IL or missing references) //IL_0653: Unknown result type (might be due to invalid IL or missing references) //IL_0663: Unknown result type (might be due to invalid IL or missing references) //IL_0668: Unknown result type (might be due to invalid IL or missing references) //IL_067f: Unknown result type (might be due to invalid IL or missing references) //IL_0685: Invalid comparison between Unknown and I4 //IL_06a0: Unknown result type (might be due to invalid IL or missing references) //IL_06a6: Invalid comparison between Unknown and I4 //IL_06c1: Unknown result type (might be due to invalid IL or missing references) //IL_06c7: Invalid comparison between Unknown and I4 //IL_06e2: Unknown result type (might be due to invalid IL or missing references) //IL_06e8: Invalid comparison between Unknown and I4 //IL_0700: Unknown result type (might be due to invalid IL or missing references) //IL_0706: Invalid comparison between Unknown and I4 //IL_071e: Unknown result type (might be due to invalid IL or missing references) //IL_0724: Invalid comparison between Unknown and I4 //IL_073c: Unknown result type (might be due to invalid IL or missing references) //IL_0742: Invalid comparison between Unknown and I4 //IL_075a: Unknown result type (might be due to invalid IL or missing references) //IL_0760: Invalid comparison between Unknown and I4 List parts = new List(); Dictionary dictionary = BuildDamageTypeLabelsPt(); Dictionary dictionary2 = BuildBiomeLabelsPt(); FlatStat(cfg.HealthBonus.Value, Text_StatVidaMaxima.Value); FlatStat(cfg.StaminaBonus.Value, Text_StatStaminaMaxima.Value); FlatStat(cfg.EitrBonus.Value, Text_StatEitrMaximo.Value); FlatStat(cfg.CarryWeightBonus.Value, Text_StatCapacidadeCarga.Value); PctStat(cfg.HealthRegenMultiplier.Value, Text_StatRegenVida.Value); PctStat(cfg.StaminaRegenMultiplier.Value, Text_StatRegenStamina.Value); PctStat(cfg.EitrRegenMultiplier.Value, Text_StatRegenEitr.Value); PctStat(cfg.DamageDoneMultiplier.Value, Text_StatDanoCausado.Value); Dictionary dictionary3 = ParseSkillMultipliers(cfg.SkillDamageMultipliers.Value); foreach (KeyValuePair item in dictionary3) { float num = (item.Value - 1f) * 100f; if (!(Mathf.Abs(num) < 0.1f)) { Stat(Fmt(Text_StatDanoComSkill.Value, item.Key), string.Format("{0}{1:0}%", (num > 0f) ? "+" : "", num)); } } Dictionary dictionary4 = ParseTypeMultipliers(cfg.AttackDamageTypeMultipliers.Value); foreach (KeyValuePair item2 in dictionary4) { float num2 = (item2.Value - 1f) * 100f; if (!(Mathf.Abs(num2) < 0.1f)) { string value; string text = (dictionary.TryGetValue(item2.Key, out value) ? value : ((object)item2.Key/*cast due to .constrained prefix*/).ToString()); Stat(Fmt(Text_StatDanoTipo.Value, text), string.Format("{0}{1:0}%", (num2 > 0f) ? "+" : "", num2)); } } if (cfg.BackstabMultiplier.Value != 1f) { float num3 = (cfg.BackstabMultiplier.Value - 1f) * 100f; Stat(Text_StatDanoAtaqueFurtivo.Value, $"+{num3:0}%"); } PctStat(cfg.KnockbackMultiplier.Value, Text_StatForcaEmpurrao.Value); float num4 = (1f - cfg.DamageTakenMultiplier.Value) * 100f; if (Mathf.Abs(num4) >= 0.1f) { Stat(Text_StatDanoRecebido.Value, string.Format("{0}{1:0}%", (num4 > 0f) ? "-" : "+", Mathf.Abs(num4))); } PctStat(cfg.SpeedMultiplier.Value, Text_StatVelocidade.Value); float num5 = (1f - cfg.StealthMultiplier.Value) * 100f; if (Mathf.Abs(num5) >= 0.1f) { Stat(Text_StatFurtividade.Value, string.Format("{0}{1:0}%", (num5 > 0f) ? "+" : "-", Mathf.Abs(num5))); } if (cfg.LifestealPercent.Value != 0f) { Stat(Text_StatRouboVida.Value, $"{cfg.LifestealPercent.Value * 100f:0}%"); } PctStat(cfg.XpGainMultiplier.Value, Text_StatGanhoXP.Value); if (cfg.NightOnlyBonuses.Value) { Stat(Text_StatRegenVelocidadeNoite.Value, Text_StatSoANoite.Value); } if (cfg.DayNightHealthShift.Value != 0f) { Stat(Text_StatVidaNoiteDia.Value, $"+{cfg.DayNightHealthShift.Value:0} / -{cfg.DayNightHealthShift.Value:0}"); } Dictionary dictionary5 = ParseBiomeShiftsForTooltip(cfg.BiomeHealthShifts.Value); foreach (KeyValuePair item3 in dictionary5) { if (item3.Value != 0f) { string value2; string text2 = (dictionary2.TryGetValue(item3.Key, out value2) ? value2 : ((object)item3.Key/*cast due to .constrained prefix*/).ToString()); Stat(Fmt(Text_StatVidaBioma.Value, text2), string.Format("{0}{1:0}", (item3.Value > 0f) ? "+" : "", item3.Value)); } } if (cfg.HeatResistanceBonus.Value != 0f) { Stat(Text_StatFrioAmbiente.Value, Text_StatNaoCongela.Value); } Dictionary dictionary6 = ParseResistances(cfg.Resistances.Value); foreach (KeyValuePair item4 in dictionary6) { string value3; string text3 = (dictionary.TryGetValue(item4.Key, out value3) ? value3 : ((object)item4.Key/*cast due to .constrained prefix*/).ToString()); string value4; if ((int)item4.Value == 3) { value4 = Text_NivelImune.Value; } else if ((int)item4.Value == 5) { value4 = Text_NivelMuitoResistente.Value; } else if ((int)item4.Value == 1) { value4 = Text_NivelResistente.Value; } else if ((int)item4.Value == 7) { value4 = Text_NivelLevementeResistente.Value; } else if ((int)item4.Value == 8) { value4 = Text_NivelLevementeFraco.Value; } else if ((int)item4.Value == 2) { value4 = Text_NivelFraco.Value; } else if ((int)item4.Value == 6) { value4 = Text_NivelMuitoFraco.Value; } else { if ((int)item4.Value != 4) { continue; } value4 = Text_NivelIgnora.Value; } parts.Add(Text_StatModificadorDano.Value + ": " + value4 + " VS " + text3 + ""); } if (cfg.LowHealthThreshold.Value > 0f) { AbilityStat(Text_HabFuriaSangue.Value, Fmt(Text_HabFuriaSangueDesc.Value, (cfg.LowHealthDamageBonus.Value - 1f) * 100f, cfg.LowHealthThreshold.Value * 100f)); } if (cfg.CrouchInvisible.Value) { AbilityStat(Text_HabMantoSombras.Value, Text_HabMantoSombrasDesc.Value + (cfg.CrouchInvisibleNightOnly.Value ? Text_HabMantoSombrasSoDeNoite.Value : "")); } if (cfg.StillHealAura.Value) { AbilityStat(Text_HabAuraCura.Value, Fmt(Text_HabAuraCuraDesc.Value, cfg.StillHealAmount.Value, cfg.StillHealInterval.Value) + (cfg.StillHealDayOnly.Value ? Text_HabAuraCuraSoDeDia.Value : "")); } if (cfg.IronStanceEnabled.Value) { AbilityStat(Text_HabPosturaFerro.Value, Fmt(Text_HabPosturaFerroDesc.Value, cfg.IronStanceExtraDamageReduction.Value * 100f)); } if (cfg.BackstabStaminaRefundChance.Value > 0f) { AbilityStat(Text_HabGolpeOportunidade.Value, Fmt(Text_HabGolpeOportunidadeDesc.Value, cfg.BackstabStaminaRefundChance.Value * 100f)); } if (cfg.TremorEnabled.Value) { string text4 = ""; if (cfg.TremorFireDamage.Value > 0f) { text4 = $" +{cfg.TremorFireDamage.Value:0} {Text_DanoFire.Value}"; } AbilityStat(Text_HabTremor.Value, Fmt(Text_HabTremorDesc.Value, text4)); } if (cfg.SecondWindEnabled.Value) { AbilityStat(Text_HabSegundoFolego.Value, Fmt(Text_HabSegundoFolegoDesc.Value, cfg.SecondWindCooldown.Value, cfg.SecondWindThreshold.Value * 100f)); } if (cfg.OnKillHealAmount.Value > 0f) { AbilityStat(Text_HabSedeSangue.Value, Fmt(Text_HabSedeSangueDesc.Value, cfg.OnKillHealAmount.Value) + (cfg.OnKillHealNightOnly.Value ? Text_HabSedeSangueSoDeNoite.Value : "")); } if (cfg.BlockAuraEnabled.Value && cfg.BlockAuraDamage.Value > 0f) { if (cfg.BlockAuraIsFrost.Value) { AbilityStat(Text_HabSoproGlacial.Value, Fmt(Text_HabSoproGlacialDesc.Value, cfg.BlockAuraDamage.Value)); } else { AbilityStat(Text_HabAuraChamas.Value, Fmt(Text_HabAuraChamasDesc.Value, cfg.BlockAuraDamage.Value)); } } if (cfg.OnHitElementalEnabled.Value && cfg.OnHitElementalDamage.Value > 0f) { if (cfg.BlockAuraIsFrost.Value) { AbilityStat(Text_HabToqueGelado.Value, Fmt(Text_HabToqueGeladoDesc.Value, cfg.OnHitElementalDamage.Value)); } else { AbilityStat(Text_HabToqueFlamejante.Value, Fmt(Text_HabToqueFlamejanteDesc.Value, cfg.OnHitElementalDamage.Value)); } } if (cfg.FlightEnabled.Value) { AbilityStat(Text_HabVoo.Value, Fmt(Text_HabVooDesc.Value, cfg.FlightStaminaCostPerTick.Value)); } return (parts.Count > 0) ? string.Join("\n", parts) : Text_StatSemBonus.Value; void AbilityStat(string label, string text5, bool isDebuff = false) { parts.Add("" + label + ": " + text5 + ""); } void FlatStat(float num6, string label) { if (num6 != 0f) { Stat(label, string.Format("{0}{1:0}", (num6 > 0f) ? "+" : "", num6)); } } void PctStat(float multiplier, string label) { float num6 = (multiplier - 1f) * 100f; if (!(Mathf.Abs(num6) < 0.1f)) { Stat(label, string.Format("{0}{1:0}%", (num6 > 0f) ? "+" : "", num6)); } } void Stat(string label, string text5) { parts.Add(label + ": " + text5 + ""); } } private static void UpdateRaceStatusEffect(Player p, string newRace) { if ((Object)(object)p == (Object)null) { return; } SEMan sEMan = ((Character)p).GetSEMan(); if (sEMan == null) { return; } try { foreach (StatusEffect value in RaceStatusEffects.Values) { if ((Object)(object)value != (Object)null && sEMan.HaveStatusEffect(value.NameHash())) { sEMan.RemoveStatusEffect(value, true); } } if (!string.IsNullOrWhiteSpace(newRace) && IsRaceEnabled(newRace)) { StatusEffect orCreateRaceStatusEffect = GetOrCreateRaceStatusEffect(newRace); if ((Object)(object)orCreateRaceStatusEffect != (Object)null) { sEMan.AddStatusEffect(orCreateRaceStatusEffect, true, 0, 0f); } } } catch (Exception ex) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Falha ao atualizar status effect de raça: " + ex.Message)); } } } private void RegisterRpcIfNeeded() { if (ZRoutedRpc.instance != null && (!RpcRegistered || RegisteredRpcInstance != ZRoutedRpc.instance)) { RpcRegistered = true; RegisteredRpcInstance = ZRoutedRpc.instance; try { ZRoutedRpc.instance.Register("ValheimRaces_SetRace", (Action)RPC_SetRace); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RPC SetRace registrado."); } catch (ArgumentException) { } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Erro RPC SetRace: {arg}"); } try { ZRoutedRpc.instance.Register("ValheimRaces_VersionCheck", (Action)RPC_VersionCheck); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RPC VersionCheck registrado."); } catch (ArgumentException) { } catch (Exception arg2) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Erro RPC VersionCheck: {arg2}"); } try { ZRoutedRpc.instance.Register("ValheimRaces_AdminSetRaceRequest", (Action)RPC_AdminSetRaceRequest); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RPC AdminSetRaceRequest registrado."); } catch (ArgumentException) { } catch (Exception arg3) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Erro RPC AdminSetRaceRequest: {arg3}"); } RefreshAdminCache(); } } private static void RPC_VersionCheck(long sender, string remoteVersion) { bool flag = (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer(); bool flag2 = remoteVersion != "2.9.1"; if (flag) { try { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(sender, "ValheimRaces_VersionCheck", new object[1] { "2.9.1" }); } } catch (Exception ex) { ValheimRacesPlugin instance2 = Instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)("[ValheimRaces] Falha ao responder VersionCheck: " + ex.Message)); } } if (flag2) { ValheimRacesPlugin instance3 = Instance; if (instance3 != null) { ((BaseUnityPlugin)instance3).Logger.LogWarning((object)string.Format("[ValheimRaces] Peer {0} conectou com versão do mod diferente: {1} (servidor: {2}).", sender, remoteVersion, "2.9.1")); } } } else if (flag2) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, Fmt(Text_VersaoDiferente.Value, "2.9.1", remoteVersion), 0, (Sprite)null); } ValheimRacesPlugin instance4 = Instance; if (instance4 != null) { ((BaseUnityPlugin)instance4).Logger.LogWarning((object)("[ValheimRaces] Versão do mod diferente do servidor! Local=2.9.1, Servidor=" + remoteVersion + ".")); } } } private static void RPC_AdminSetRaceRequest(long sender, long playerId, string race) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || playerId == 0) { return; } if (sender != playerId && !IsAdminById(sender)) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)$"[ValheimRaces] AdminSetRaceRequest rejeitado: sender={sender} não é admin, tentando mudar playerId={playerId}."); } return; } try { ZRoutedRpc instance2 = ZRoutedRpc.instance; if (instance2 != null) { instance2.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ValheimRaces_SetRace", new object[2] { playerId, race ?? "" }); } } catch (Exception ex) { ValheimRacesPlugin instance3 = Instance; if (instance3 != null) { ((BaseUnityPlugin)instance3).Logger.LogWarning((object)("[ValheimRaces] Falha ao repassar AdminSetRaceRequest: " + ex.Message)); } } } private static void RPC_SetRace(long sender, long playerId, string race) { if (playerId == 0) { return; } if (!IsRpcSenderAuthorized(sender, playerId)) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)$"RPC_SetRace rejeitado: sender={sender} → playerId={playerId}"); } return; } Player val = FindPlayerById(playerId); if (string.IsNullOrWhiteSpace(race)) { NetworkRaces.Remove(playerId); if ((Object)(object)val != (Object)null && (Object)(object)Instance != (Object)null) { Instance.AdminResetRace(val); } return; } NetworkRaces[playerId] = race; if (!((Object)(object)val != (Object)null) || !((Object)(object)Instance != (Object)null)) { return; } ForceSetZdoRace(val, race); ForceSetRaceVisualZdo(val, race); if ((Object)(object)val == (Object)(object)Player.m_localPlayer) { SaveLocalRace(race, locked: true); ValheimRacesPlugin instance2 = Instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogInfo((object)("[ValheimRaces/Diag] Emote disparado via RPC_SetRace (target próprio) pra '" + val.GetPlayerName() + "'.")); } PlayTransformEmote(); } Instance.ApplyRaceWithDelays(val); } private static bool IsRpcSenderAuthorized(long sender, long playerId) { if (ZRoutedRpc.instance == null) { return true; } try { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { return true; } } catch { } if (sender == playerId) { return true; } if (sender == GetServerPeerId()) { return true; } return false; } private static void SendVersionCheckToServer() { try { if (ZRoutedRpc.instance != null && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer())) { long serverPeerId = GetServerPeerId(); ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerId, "ValheimRaces_VersionCheck", new object[1] { "2.9.1" }); } } catch (Exception ex) { ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("[ValheimRaces] Falha ao enviar VersionCheck: " + ex.Message)); } } } private static void BroadcastRace(Player player, string race) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || ZRoutedRpc.instance == null) { return; } long playerIdLong = GetPlayerIdLong(player); if (playerIdLong != 0) { if (string.IsNullOrWhiteSpace(race)) { NetworkRaces.Remove(playerIdLong); ForceSetZdoRace(player, ""); SetZdoLocked(player, locked: false); ForceSetZdoVector(player, "ValheimRaceEarColor", InvalidColor); ForceSetZdoVector(player, "ValheimRaceSkinColor", InvalidColor); } else { NetworkRaces[playerIdLong] = race; ForceSetZdoRace(player, race); ForceSetRaceVisualZdo(player, race); } bool flag = (Object)(object)player == (Object)(object)Player.m_localPlayer; bool flag2 = (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer(); if (flag || flag2) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ValheimRaces_SetRace", new object[2] { playerIdLong, race ?? "" }); } else { long serverPeerId = GetServerPeerId(); ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerId, "ValheimRaces_AdminSetRaceRequest", new object[2] { playerIdLong, race ?? "" }); } } } private void SyncLocalRace() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { string race = GetRace(localPlayer); if (!string.IsNullOrWhiteSpace(race) && !(race == lastBroadcastRace)) { lastBroadcastRace = race; BroadcastRace(localPlayer, race); } } } private static Player FindPlayerById(long playerId) { if (playerId == 0) { return null; } return ((IEnumerable)Player.GetAllPlayers()).FirstOrDefault((Func)((Player p) => (Object)(object)p != (Object)null && GetPlayerIdLong(p) == playerId)); } private static long GetServerPeerId() { if (ZRoutedRpc.instance == null) { return ZRoutedRpc.Everybody; } try { MethodInfo method = typeof(ZRoutedRpc).GetMethod("GetServerPeerID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { return (long)method.Invoke(ZRoutedRpc.instance, null); } } catch { } try { FieldInfo field = typeof(ZRoutedRpc).GetField("m_serverPeerID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { long num = (long)field.GetValue(ZRoutedRpc.instance); if (num != 0) { return num; } } } catch { } return ZRoutedRpc.Everybody; } private static void OnPeerDisconnected(long peerId) { if (peerId == 0) { return; } Player val = FindPlayerById(peerId); if ((Object)(object)val == (Object)null) { val = ((IEnumerable)Player.GetAllPlayers()).FirstOrDefault((Func)delegate(Player p) { if (!((Object)(object)p == (Object)null)) { try { ZNetView cachedZNetView = GetCachedZNetView(p); return (Object)(object)cachedZNetView != (Object)null && cachedZNetView.GetZDO() != null && ((ZDOID)(ref cachedZNetView.GetZDO().m_uid)).UserID == peerId; } catch { return false; } } return false; }); } long num = (((Object)(object)val != (Object)null) ? GetPlayerIdLong(val) : peerId); string text = (((Object)(object)val != (Object)null) ? GetVisualKey(val) : peerId.ToString()); NetworkRaces.Remove(num); if (num != peerId) { NetworkRaces.Remove(peerId); } if (!string.IsNullOrWhiteSpace(text)) { LastAppliedRace.Remove(text); OriginalSkinColors.Remove(text); LastSkinRefreshRequest.Remove(text); } KnownAdmins.Remove(peerId); if ((Object)(object)val != (Object)null) { int instanceID = ((Object)val).GetInstanceID(); InvalidateHeadCache(val); ApplyRaceCoroutineGeneration.Remove(instanceID); ZNetViewCache.Remove(instanceID); } ValheimRacesPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)$"Caches limpos para peer {peerId} (playerID={num}) ao desconectar."); } } private void CreateTextConfigs() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown string text = Path.Combine(Paths.ConfigPath, "ValheimRaces"); Directory.CreateDirectory(text); string text2 = Path.Combine(text, "valheim.races.Translation.cfg"); TextConfigFile = new ConfigFile(text2, true); Text_AltarNome = TextConfig("Translation - Altar", "AltarNome", "Altar das Raças"); Text_AltarDescricao = TextConfig("Translation - Altar", "AltarDescricao", "Escolha sua raça. Só pode ser usado uma vez por personagem."); Text_AltarHoverEscolher = TextConfig("Translation - Altar", "AltarHoverEscolher", "[E] Escolher raça"); Text_AltarHoverTrocar = TextConfig("Translation - Altar", "AltarHoverTrocar", "[E] Trocar de raça"); Text_UiEscolhaTitulo = TextConfig("Translation - Altar", "UiEscolhaTitulo", "Escolha sua raça"); Text_UiFechar = TextConfig("Translation - Altar", "UiFechar", "Fechar"); Text_UiTrocarBotao = TextConfig("Translation - Altar", "UiTrocarBotao", "Trocar ({0} {1})"); Text_UiJaEscolheuTitulo = TextConfig("Translation - Altar", "UiJaEscolheuTitulo", "Você já escolheu sua raça"); Text_UiMoedaInsuficiente = TextConfig("Translation - Altar", "UiMoedaInsuficiente", "Você precisa de {0}x {1} pra trocar de raça."); Text_UiNenhumaRacaDisponivel = TextConfig("Translation - Altar", "UiNenhumaRacaDisponivel", "Nenhuma raça disponível.\nConfira 'RacasDisponiveis' no config."); CreateRaceNameTexts(); Text_SemPermissao = TextConfig("Translation - Comandos", "SemPermissao", "Ops! você não pode fazer isso!"); Text_UsoRaca = TextConfig("Translation - Comandos", "UsoRaca", "Uso: {0} me ou {0} NomeDoPlayer"); Text_RacaDesativadaAdmin = TextConfig("Translation - Comandos", "RacaDesativadaAdmin", "A raça {0} está desativada."); Text_PlayerNaoEncontrado = TextConfig("Translation - Comandos", "PlayerNaoEncontrado", "Player não encontrado."); Text_PlayerNaoCarregado = TextConfig("Translation - Comandos", "PlayerNaoCarregado", "Erro: {0} ainda não carregou no mundo. Aguarde e tente novamente."); Text_AgoraERaca = TextConfig("Translation - Comandos", "AgoraERaca", "{0} agora é {1}."); Text_RacaRemovida = TextConfig("Translation - Comandos", "RacaRemovida", "Raça de {0} removida!"); Text_UsoOfflineReset = TextConfig("Translation - Comandos", "UsoOfflineReset", "Uso: valheim_reset_offline "); Text_IdInvalido = TextConfig("Translation - Comandos", "IdInvalido", "ID inválido."); Text_OfflineResetado = TextConfig("Translation - Comandos", "OfflineResetado", "Player offline resetado."); Text_OfflineNaoEncontrado = TextConfig("Translation - Comandos", "OfflineNaoEncontrado", "Player não encontrado no mundo."); Text_EssaRacaDesativada = TextConfig("Translation - Comandos", "EssaRacaDesativada", "Essa raça está desativada."); Text_AgoraEuSou = TextConfig("Translation - Comandos", "AgoraEuSou", "Agora eu sou: {0}!"); Text_ConfigRecarregado = TextConfig("Translation - Comandos", "ConfigRecarregado", "Config e codigos recarregados!"); Text_CodigosSecretosAtivos = TextConfig("Translation - Comandos", "CodigosSecretosAtivos", "Codigos secretos ativos:"); Text_VersaoDiferente = TextConfig("Translation - Comandos", "VersaoDiferente", "Aviso: sua versão do ValheimRaces ({0}) é diferente da do servidor ({1}). Pode causar bugs — atualize o mod."); Text_DebugObjectDBNaoCarregou = TextConfig("Translation - Debug", "DebugObjectDBNaoCarregou", "ObjectDB ainda não carregou."); Text_DebugItensComFireStaff = TextConfig("Translation - Debug", "DebugItensComFireStaff", "Itens com 'fire' ou 'staff' no nome:"); Text_DebugTotalItens = TextConfig("Translation - Debug", "DebugTotalItens", "Total de itens na lista: {0}"); Text_DebugNenhumEncontrado = TextConfig("Translation - Debug", "DebugNenhumEncontrado", " (nenhum encontrado)"); Text_DebugPlayerNaoCarregadoSimples = TextConfig("Translation - Debug", "DebugPlayerNaoCarregadoSimples", "Player não carregado."); Text_DebugNenhumaFerramenta = TextConfig("Translation - Debug", "DebugNenhumaFerramenta", "Nenhuma ferramenta equipada na mão (segura o Martelo primeiro)."); Text_DebugFerramenta = TextConfig("Translation - Debug", "DebugFerramenta", "Ferramenta: {0}"); Text_DebugPieceTableReal = TextConfig("Translation - Debug", "DebugPieceTableReal", "PieceTable real: {0}"); Text_DebugTotalPecas = TextConfig("Translation - Debug", "DebugTotalPecas", "Total de peças na tabela: {0}"); Text_DebugEstacaoPerto = TextConfig("Translation - Debug", "DebugEstacaoPerto", "Estação perto: {0}"); Text_DebugNenhumaEstacao = TextConfig("Translation - Debug", "DebugNenhumaEstacao", "Nenhuma estação de trabalho por perto."); Text_DebugErro = TextConfig("Translation - Debug", "DebugErro", "Erro: {0}"); Text_VoceEvoluiu = TextConfig("Translation - Evolucao", "VoceEvoluiu", "Você evoluiu! Sentindo um poder ancestral tomar conta de você..."); Text_StatNomeRaca = TextConfig("Translation - Tooltip Geral", "StatNomeRaca", "Raça: {0}"); Text_StatVidaMaxima = TextConfig("Translation - Tooltip Geral", "StatVidaMaxima", "Vida Máxima"); Text_StatStaminaMaxima = TextConfig("Translation - Tooltip Geral", "StatStaminaMaxima", "Stamina Máxima"); Text_StatEitrMaximo = TextConfig("Translation - Tooltip Geral", "StatEitrMaximo", "Eitr Máximo"); Text_StatCapacidadeCarga = TextConfig("Translation - Tooltip Geral", "StatCapacidadeCarga", "Capacidade de Carga"); Text_StatRegenVida = TextConfig("Translation - Tooltip Geral", "StatRegenVida", "Regeneração de Vida"); Text_StatRegenStamina = TextConfig("Translation - Tooltip Geral", "StatRegenStamina", "Regeneração de Stamina"); Text_StatRegenEitr = TextConfig("Translation - Tooltip Geral", "StatRegenEitr", "Regeneração de Eitr"); Text_StatDanoCausado = TextConfig("Translation - Tooltip Geral", "StatDanoCausado", "Dano Causado"); Text_StatDanoComSkill = TextConfig("Translation - Tooltip Geral", "StatDanoComSkill", "Dano com {0}"); Text_StatDanoTipo = TextConfig("Translation - Tooltip Geral", "StatDanoTipo", "Dano {0}"); Text_StatDanoAtaqueFurtivo = TextConfig("Translation - Tooltip Geral", "StatDanoAtaqueFurtivo", "Dano de Ataque Furtivo"); Text_StatForcaEmpurrao = TextConfig("Translation - Tooltip Geral", "StatForcaEmpurrao", "Força de Empurrão"); Text_StatDanoRecebido = TextConfig("Translation - Tooltip Geral", "StatDanoRecebido", "Dano Recebido"); Text_StatVelocidade = TextConfig("Translation - Tooltip Geral", "StatVelocidade", "Velocidade de Movimento"); Text_StatFurtividade = TextConfig("Translation - Tooltip Geral", "StatFurtividade", "Furtividade"); Text_StatRouboVida = TextConfig("Translation - Tooltip Geral", "StatRouboVida", "Roubo de Vida"); Text_StatGanhoXP = TextConfig("Translation - Tooltip Geral", "StatGanhoXP", "Ganho de XP em Skills"); Text_StatRegenVelocidadeNoite = TextConfig("Translation - Tooltip Geral", "StatRegenVelocidadeNoite", "Regen. e Velocidade"); Text_StatSoANoite = TextConfig("Translation - Tooltip Geral", "StatSoANoite", "só à noite"); Text_StatVidaNoiteDia = TextConfig("Translation - Tooltip Geral", "StatVidaNoiteDia", "Vida (noite / dia)"); Text_StatVidaBioma = TextConfig("Translation - Tooltip Geral", "StatVidaBioma", "Vida em {0}"); Text_StatFrioAmbiente = TextConfig("Translation - Tooltip Geral", "StatFrioAmbiente", "Frio Ambiente"); Text_StatNaoCongela = TextConfig("Translation - Tooltip Geral", "StatNaoCongela", "Não Congela"); Text_StatModificadorDano = TextConfig("Translation - Tooltip Geral", "StatModificadorDano", "Modificador de Dano"); Text_StatSemBonus = TextConfig("Translation - Tooltip Geral", "StatSemBonus", "Sem bônus de atributos."); Text_NivelImune = TextConfig("Translation - Tooltip Niveis", "NivelImune", "Imune"); Text_NivelMuitoResistente = TextConfig("Translation - Tooltip Niveis", "NivelMuitoResistente", "Muito Resistente"); Text_NivelResistente = TextConfig("Translation - Tooltip Niveis", "NivelResistente", "Resistente"); Text_NivelLevementeResistente = TextConfig("Translation - Tooltip Niveis", "NivelLevementeResistente", "Levemente Resistente"); Text_NivelLevementeFraco = TextConfig("Translation - Tooltip Niveis", "NivelLevementeFraco", "Levemente Fraco"); Text_NivelFraco = TextConfig("Translation - Tooltip Niveis", "NivelFraco", "Fraco"); Text_NivelMuitoFraco = TextConfig("Translation - Tooltip Niveis", "NivelMuitoFraco", "Muito Fraco"); Text_NivelIgnora = TextConfig("Translation - Tooltip Niveis", "NivelIgnora", "Ignora"); Text_DanoBlunt = TextConfig("Translation - Tooltip Tipos de Dano", "DanoBlunt", "Concussão"); Text_DanoSlash = TextConfig("Translation - Tooltip Tipos de Dano", "DanoSlash", "Corte"); Text_DanoPierce = TextConfig("Translation - Tooltip Tipos de Dano", "DanoPierce", "Perfuração"); Text_DanoChop = TextConfig("Translation - Tooltip Tipos de Dano", "DanoChop", "Corte de Machado"); Text_DanoPickaxe = TextConfig("Translation - Tooltip Tipos de Dano", "DanoPickaxe", "Picareta"); Text_DanoFire = TextConfig("Translation - Tooltip Tipos de Dano", "DanoFire", "Fogo"); Text_DanoFrost = TextConfig("Translation - Tooltip Tipos de Dano", "DanoFrost", "Gelo"); Text_DanoLightning = TextConfig("Translation - Tooltip Tipos de Dano", "DanoLightning", "Raio"); Text_DanoPoison = TextConfig("Translation - Tooltip Tipos de Dano", "DanoPoison", "Veneno"); Text_DanoSpirit = TextConfig("Translation - Tooltip Tipos de Dano", "DanoSpirit", "Espírito"); Text_BiomaMeadows = TextConfig("Translation - Tooltip Biomas", "BiomaMeadows", "Prado"); Text_BiomaBlackForest = TextConfig("Translation - Tooltip Biomas", "BiomaBlackForest", "Floresta Negra"); Text_BiomaSwamp = TextConfig("Translation - Tooltip Biomas", "BiomaSwamp", "Pântano"); Text_BiomaMountain = TextConfig("Translation - Tooltip Biomas", "BiomaMountain", "Montanha"); Text_BiomaPlains = TextConfig("Translation - Tooltip Biomas", "BiomaPlains", "Planície"); Text_BiomaMistlands = TextConfig("Translation - Tooltip Biomas", "BiomaMistlands", "Terras Nubladas"); Text_BiomaAshLands = TextConfig("Translation - Tooltip Biomas", "BiomaAshLands", "Terras Cinzentas"); Text_BiomaDeepNorth = TextConfig("Translation - Tooltip Biomas", "BiomaDeepNorth", "Norte Profundo"); Text_BiomaOcean = TextConfig("Translation - Tooltip Biomas", "BiomaOcean", "Oceano"); Text_HabFuriaSangue = TextConfig("Translation - Tooltip Habilidades", "HabFuriaSangue", "Fúria de Sangue"); Text_HabFuriaSangueDesc = TextConfig("Translation - Tooltip Habilidades", "HabFuriaSangueDesc", "+{0}% Dano abaixo de {1}% Vida"); Text_HabAuraCura = TextConfig("Translation - Tooltip Habilidades", "HabAuraCura", "Aura de Cura"); Text_HabAuraCuraDesc = TextConfig("Translation - Tooltip Habilidades", "HabAuraCuraDesc", "+{0} Vida a cada {1}s parado"); Text_HabAuraCuraSoDeDia = TextConfig("Translation - Tooltip Habilidades", "HabAuraCuraSoDeDia", " (só de dia)"); Text_HabPosturaFerro = TextConfig("Translation - Tooltip Habilidades", "HabPosturaFerro", "Postura de Ferro"); Text_HabPosturaFerroDesc = TextConfig("Translation - Tooltip Habilidades", "HabPosturaFerroDesc", "-{0}% Dano e Sem Empurrão ao Bloquear"); Text_HabGolpeOportunidade = TextConfig("Translation - Tooltip Habilidades", "HabGolpeOportunidade", "Golpe de Oportunidade"); Text_HabGolpeOportunidadeDesc = TextConfig("Translation - Tooltip Habilidades", "HabGolpeOportunidadeDesc", "{0}% Chance de Reembolsar Stamina no Backstab"); Text_HabSegundoFolego = TextConfig("Translation - Tooltip Habilidades", "HabSegundoFolego", "Segundo Fôlego"); Text_HabSegundoFolegoDesc = TextConfig("Translation - Tooltip Habilidades", "HabSegundoFolegoDesc", "Recupera Vida/Stamina 1x a cada {0}s abaixo de {1}% Vida"); Text_HabSedeSangue = TextConfig("Translation - Tooltip Habilidades", "HabSedeSangue", "Sede de Sangue"); Text_HabSedeSangueDesc = TextConfig("Translation - Tooltip Habilidades", "HabSedeSangueDesc", "+{0} Vida ao Matar"); Text_HabSedeSangueSoDeNoite = TextConfig("Translation - Tooltip Habilidades", "HabSedeSangueSoDeNoite", " (só à noite)"); Text_HabMantoSombras = TextConfig("Translation - Tooltip Habilidades", "HabMantoSombras", "Manto das Sombras"); Text_HabMantoSombrasDesc = TextConfig("Translation - Tooltip Habilidades", "HabMantoSombrasDesc", "Monstros Não Detectam ao Agachar"); Text_HabMantoSombrasSoDeNoite = TextConfig("Translation - Tooltip Habilidades", "HabMantoSombrasSoDeNoite", " (só à noite)"); Text_HabTremor = TextConfig("Translation - Tooltip Habilidades", "HabTremor", "Tremor"); Text_HabTremorDesc = TextConfig("Translation - Tooltip Habilidades", "HabTremorDesc", "Empurra Inimigos ao Aterrissar{0}"); Text_HabAuraChamas = TextConfig("Translation - Tooltip Habilidades", "HabAuraChamas", "Aura de Chamas"); Text_HabAuraChamasDesc = TextConfig("Translation - Tooltip Habilidades", "HabAuraChamasDesc", "+{0} Dano de Fogo em Quem Estiver Perto ao Bloquear"); Text_HabSoproGlacial = TextConfig("Translation - Tooltip Habilidades", "HabSoproGlacial", "Sopro Glacial"); Text_HabSoproGlacialDesc = TextConfig("Translation - Tooltip Habilidades", "HabSoproGlacialDesc", "+{0} Dano de Gelo e Lentidão em Quem Estiver Perto ao Bloquear"); Text_HabToqueFlamejante = TextConfig("Translation - Tooltip Habilidades", "HabToqueFlamejante", "Toque Flamejante"); Text_HabToqueFlamejanteDesc = TextConfig("Translation - Tooltip Habilidades", "HabToqueFlamejanteDesc", "+{0} Dano de Fogo em Todo Golpe de Ataque Acertado"); Text_HabToqueGelado = TextConfig("Translation - Tooltip Habilidades", "HabToqueGelado", "Toque Gelado"); Text_HabToqueGeladoDesc = TextConfig("Translation - Tooltip Habilidades", "HabToqueGeladoDesc", "+{0} Dano de Gelo em Todo Golpe de Ataque Acertado"); Text_HabVoo = TextConfig("Translation - Tooltip Habilidades", "HabVoo", "Voo"); Text_HabVooDesc = TextConfig("Translation - Tooltip Habilidades", "HabVooDesc", "Liga/desliga com a tecla configurada — gasta {0} de stamina a cada tick voando, sem regenerar e sem combate no ar"); Text_VooSemStamina = TextConfig("Translation - Evolucao", "VooSemStamina", "Sem stamina — você pousa!"); } private void CreateRaceNameTexts() { Name("orc", "Orc"); Name("elfodaluz", "Elfo da Luz"); Name("elfodanoite", "Elfo da Noite"); Name("anao", "Anão"); Name("halfling", "Halfling"); Name("humano", "Humano"); Name("jotun", "Jotun"); Name("vampiro", "Vampiro"); Name("efrit", "Efrit"); Name("fada", "Fada"); void Name(string id, string defaultName) { RaceNameTexts[id] = TextConfig("Translation - Nomes de Raca", "Nome_" + id, defaultName); } } private ConfigEntry TextConfig(string group, string name, string defaultValue) { ConfigEntry val = TextConfigFile.Bind(group, name, defaultValue, "Texto exibido pro jogador. Pode traduzir/editar livremente — vale pra todo mundo no servidor."); SyncedConfigEntry syncedConfigEntry = ModConfigSync.AddConfigEntry(val); syncedConfigEntry.SynchronizedConfig = true; return val; } public static string Fmt(string template, params object[] args) { if (string.IsNullOrEmpty(template)) { return template ?? ""; } try { return string.Format(template, args); } catch { return template; } } private static bool IsFemaleModel(VisEquipment vis) { if ((Object)(object)vis == (Object)null || ModelIndexField == null) { return false; } try { if (ModelIndexField.GetValue(vis) is int num) { return num == 1; } } catch { } return false; } private static bool IsFemaleModel(Player p) { if ((Object)(object)p == (Object)null) { return false; } return IsFemaleModel(((Component)p).GetComponent()); } private void ApplySkin(Player p, Vector3 color) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) VisEquipment component = ((Component)p).GetComponent(); if (!((Object)(object)component == (Object)null) && !(SetSkinColorMethod == null)) { SetSkinColorMethod.Invoke(component, new object[1] { color }); } } private void ApplyHair(Player p, Vector3 color) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) VisEquipment component = ((Component)p).GetComponent(); if (!((Object)(object)component == (Object)null) && !(SetHairColorMethod == null)) { SetHairColorMethod.Invoke(component, new object[1] { color }); } } private void CacheOriginalSkinIfNeeded(Player p) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)p == (Object)null)) { string visualKey = GetVisualKey(p); if (!string.IsNullOrWhiteSpace(visualKey) && !OriginalSkinColors.ContainsKey(visualKey)) { OriginalSkinColors[visualKey] = GetCurrentSkinVector(p); } } } private static void CacheOriginalSkinValue(Player p, Vector3 skin) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)p == (Object)null)) { string visualKey = GetVisualKey(p); if (!string.IsNullOrWhiteSpace(visualKey) && !OriginalSkinColors.ContainsKey(visualKey)) { OriginalSkinColors[visualKey] = skin; } } } private void ResetSkin(Player p) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)p == (Object)null)) { string visualKey = GetVisualKey(p); if (!string.IsNullOrWhiteSpace(visualKey) && OriginalSkinColors.TryGetValue(visualKey, out var value)) { ApplySkin(p, value); } } } private Vector3 GetCurrentSkinVector(Player p) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null) { return Vector3.one; } VisEquipment component = ((Component)p).GetComponent(); if ((Object)(object)component == (Object)null || SkinColorField == null) { return Vector3.one; } try { if (SkinColorField.GetValue(component) is Vector3 result) { return result; } } catch { } return Vector3.one; } private void ApplyEarsDirect(Transform root, Color color, bool isFemale) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) GameObject val = (isFemale ? ElfEarsFemalePrefab : ElfEarsMalePrefab); if ((Object)(object)root == (Object)null || (Object)(object)val == (Object)null) { if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Prefab " + (isFemale ? "ears_elf_f" : "ears_elf_m") + " não encontrado.")); } return; } Transform val2 = root.Find("Ears"); if ((Object)(object)val2 == (Object)null) { GameObject val3 = SkinnedAccessoryAttacher.Attach(val, root); if ((Object)(object)val3 == (Object)null) { return; } ((Object)val3).name = "Ears"; StripItemComponents(val3); val2 = val3.transform; } FixEarMaterials(val2, forceStandardShader: false); ApplyColor(val2, color); if (!ShareBodySkinMaterial(((Component)val2).gameObject, root)) { FixEarMaterials(val2, forceStandardShader: false); ApplyColor(val2, color); } } private void ApplyOrcEarsDirect(Transform root, Color color, bool isFemale) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) GameObject val = (isFemale ? OrcEarsFemalePrefab : OrcEarsMalePrefab); if ((Object)(object)root == (Object)null || (Object)(object)val == (Object)null) { if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Prefab " + (isFemale ? "orc_ears_f" : "orc_ears_m") + " não encontrado.")); } return; } Transform val2 = root.Find("OrcEars"); if ((Object)(object)val2 == (Object)null) { GameObject val3 = SkinnedAccessoryAttacher.Attach(val, root); if ((Object)(object)val3 == (Object)null) { return; } ((Object)val3).name = "OrcEars"; StripItemComponents(val3); val2 = val3.transform; } if (!ShareBodySkinMaterial(((Component)val2).gameObject, root)) { FixEarMaterials(val2, forceStandardShader: false); ApplyColor(val2, color); } } private bool ShareBodySkinMaterial(GameObject accessory, Transform root) { if ((Object)(object)accessory == (Object)null || (Object)(object)root == (Object)null) { return false; } SkinnedMeshRenderer val = null; SkinnedMeshRenderer[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && ((Object)val2).name == "body") { val = val2; break; } } if ((Object)(object)val == (Object)null) { return false; } Material val3 = null; Material[] materials = ((Renderer)val).materials; foreach (Material val4 in materials) { if ((Object)(object)val4 != (Object)null && ((Object)val4).name.StartsWith("PlayerMaterial")) { val3 = val4; break; } } if ((Object)(object)val3 == (Object)null) { return false; } SkinnedMeshRenderer[] componentsInChildren2 = accessory.GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val5 in componentsInChildren2) { Material[] array = (Material[])(object)new Material[((Renderer)val5).materials.Length]; for (int l = 0; l < array.Length; l++) { array[l] = val3; } ((Renderer)val5).materials = array; } return true; } private void ApplyOrcTuskDirect(Transform head) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)head == (Object)null || (Object)(object)OrcTuskPrefab == (Object)null) { if ((Object)(object)OrcTuskPrefab == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Prefab orc_tusk não encontrado."); } return; } Transform val = head.Find("OrcTusk"); if ((Object)(object)val == (Object)null) { GameObject val2 = Object.Instantiate(OrcTuskPrefab, head); ((Object)val2).name = "OrcTusk"; StripItemComponents(val2); FixEarMaterials(val2.transform); val = val2.transform; } val.localPosition = OrcTuskPosition; val.localRotation = Quaternion.Euler(OrcTuskRotation); val.localScale = OrcTuskScale; FixEarMaterials(val); } private void ApplyHornDirect(Transform root, bool isFemale) { GameObject val = (isFemale ? HornFemalePrefab : HornMalePrefab); if ((Object)(object)root == (Object)null || (Object)(object)val == (Object)null) { if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Prefab " + (isFemale ? "horns_f" : "horns_m") + " não encontrado.")); } return; } Transform val2 = root.Find("Horn"); if ((Object)(object)val2 == (Object)null) { GameObject val3 = SkinnedAccessoryAttacher.Attach(val, root); if ((Object)(object)val3 == (Object)null) { return; } ((Object)val3).name = "Horn"; StripItemComponents(val3); val2 = val3.transform; } FixEarMaterials(val2, forceStandardShader: false); } private void ApplyHighElfEyesDirect(Player p, Transform head) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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) if (!((Object)(object)head == (Object)null) && !((Object)(object)HighElfEyesPrefab == (Object)null)) { Transform val = head.Find("HighElfEyes"); if ((Object)(object)val == (Object)null) { GameObject val2 = Object.Instantiate(HighElfEyesPrefab, head); ((Object)val2).name = "HighElfEyes"; StripItemComponents(val2); val = val2.transform; } val.localPosition = HighElfEyesPosition; val.localRotation = Quaternion.Euler(HighElfEyesRotation); val.localScale = HighElfEyesScale; ApplyEyeColor(val, GetRaceEyeColor(GetRace(p))); } } private void ApplyEyeColor(Transform t, Color color) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)t == (Object)null) { return; } float num = ((EyeGlowPeak != null) ? EyeGlowPeak.Value : 1.5f); float num2 = Mathf.Max(new float[3] { color.r, color.g, color.b }); Color val = ((num2 > 0.001f) ? (color * (num / num2)) : color); Renderer[] componentsInChildren = ((Component)t).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { if ((Object)(object)val2 == (Object)null) { continue; } Material[] materials = val2.materials; foreach (Material val3 in materials) { if (!((Object)(object)val3 == (Object)null)) { if (val3.HasProperty("_EmissionColor")) { val3.EnableKeyword("_EMISSION"); val3.SetColor("_EmissionColor", val); } if (val3.HasProperty("_Color")) { val3.SetColor("_Color", color); } if (val3.HasProperty("_BaseColor")) { val3.SetColor("_BaseColor", color); } if (val3.HasProperty("_TintColor")) { val3.SetColor("_TintColor", color); } } } } } private void ApplyEars(Player p, Color color) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)p == (Object)null)) { ApplyEarsDirect(((Component)p).transform, color, IsFemaleModel(p)); } } private void ApplyOrcEars(Player p, Color color) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)p == (Object)null)) { ApplyOrcEarsDirect(((Component)p).transform, color, IsFemaleModel(p)); } } private void RemoveHeadAttachmentDirect(Transform head, string objectName) { if (!((Object)(object)head == (Object)null)) { Transform val = head.Find(objectName); if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } } private void RemoveHeadAttachment(Player p, string objectName) { if (!((Object)(object)p == (Object)null)) { RemoveHeadAttachmentDirect(GetCachedHead(p, GetRace(p)), objectName); } } private static void RemovePlayerAttachment(Player p, string objectName) { if (!((Object)(object)p == (Object)null)) { Transform val = ((Component)p).transform.Find(objectName); if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } } private void FixEarMaterials(Transform t, bool forceStandardShader = true) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)t == (Object)null) { return; } Shader val = (forceStandardShader ? Shader.Find("Standard") : null); Renderer[] componentsInChildren = ((Component)t).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { if ((Object)(object)val2 == (Object)null) { continue; } Material[] materials = val2.materials; foreach (Material val3 in materials) { if (!((Object)(object)val3 == (Object)null)) { if (val3.IsKeywordEnabled("_EMISSION")) { val3.DisableKeyword("_EMISSION"); } if (val3.HasProperty("_EmissionColor")) { val3.SetColor("_EmissionColor", Color.black); } if (forceStandardShader && (Object)(object)val != (Object)null) { val3.shader = val; } } } } } private void ApplyColor(Transform t, Color c) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)t == (Object)null) { return; } Renderer[] componentsInChildren = ((Component)t).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Material[] materials = val.materials; foreach (Material val2 in materials) { if (!((Object)(object)val2 == (Object)null)) { val2.color = c; if (val2.HasProperty("_Color")) { val2.SetColor("_Color", c); } if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", c); } if (val2.HasProperty("_TintColor")) { val2.SetColor("_TintColor", c); } } } MaterialPropertyBlock val3 = new MaterialPropertyBlock(); val.GetPropertyBlock(val3); val3.SetColor("_SkinColor", c); val.SetPropertyBlock(val3); } } private Transform FindHead(Transform t, int depth) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown if ((Object)(object)t == (Object)null || depth > 12) { return null; } string text = ((Object)t).name.ToLowerInvariant(); if (text == "head" || text.Contains("head") || text.Contains("bip001 head") || text.Contains("helmet_attach") || text.Contains("head_attach")) { return t; } foreach (Transform item in t) { Transform t2 = item; Transform val = FindHead(t2, depth + 1); if ((Object)(object)val != (Object)null) { return val; } } return null; } private void StripItemComponents(GameObject obj) { if (!((Object)(object)obj == (Object)null)) { Collider[] componentsInChildren = obj.GetComponentsInChildren(true); foreach (Collider val in componentsInChildren) { Object.DestroyImmediate((Object)(object)val); } Rigidbody[] componentsInChildren2 = obj.GetComponentsInChildren(true); foreach (Rigidbody val2 in componentsInChildren2) { Object.DestroyImmediate((Object)(object)val2); } ItemDrop[] componentsInChildren3 = obj.GetComponentsInChildren(true); foreach (ItemDrop val3 in componentsInChildren3) { Object.DestroyImmediate((Object)(object)val3); } ZNetView[] componentsInChildren4 = obj.GetComponentsInChildren(true); foreach (ZNetView val4 in componentsInChildren4) { Object.DestroyImmediate((Object)(object)val4); } PlayerController[] componentsInChildren5 = obj.GetComponentsInChildren(true); foreach (PlayerController val5 in componentsInChildren5) { Object.DestroyImmediate((Object)(object)val5); } Player[] componentsInChildren6 = obj.GetComponentsInChildren(true); foreach (Player val6 in componentsInChildren6) { Object.DestroyImmediate((Object)(object)val6); } ZSyncTransform[] componentsInChildren7 = obj.GetComponentsInChildren(true); foreach (ZSyncTransform val7 in componentsInChildren7) { Object.DestroyImmediate((Object)(object)val7); } ZSyncAnimation[] componentsInChildren8 = obj.GetComponentsInChildren(true); foreach (ZSyncAnimation val8 in componentsInChildren8) { Object.DestroyImmediate((Object)(object)val8); } Talker[] componentsInChildren9 = obj.GetComponentsInChildren(true); foreach (Talker val9 in componentsInChildren9) { Object.DestroyImmediate((Object)(object)val9); } VisEquipment[] componentsInChildren10 = obj.GetComponentsInChildren(true); foreach (VisEquipment val10 in componentsInChildren10) { Object.DestroyImmediate((Object)(object)val10); } Skills[] componentsInChildren11 = obj.GetComponentsInChildren(true); foreach (Skills val11 in componentsInChildren11) { Object.DestroyImmediate((Object)(object)val11); } FootStep[] componentsInChildren12 = obj.GetComponentsInChildren(true); foreach (FootStep val12 in componentsInChildren12) { Object.DestroyImmediate((Object)(object)val12); } } } private static Color ToColor(Vector3 v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) return new Color(v.x, v.y, v.z, 1f); } private string GetTransformPath(Transform t) { if ((Object)(object)t == (Object)null) { return ""; } List list = new List(); Transform val = t; while ((Object)(object)val != (Object)null) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } } public static class FejdRaceSelectorUI { private class FejdPreviewGenderPoller : MonoBehaviour { private void Update() { if ((Object)(object)_fejd != (Object)null) { ValheimRacesPlugin.PollPreviewGenderChange(_fejd); } } } private const float ButtonHeight = 26f; private const float ButtonSpacing = 2f; private static GameObject _canvasRoot; private static FejdStartup _fejd; private static Text _bottomTitle; private static Text _bottomBody; public static void EnsureVisible(FejdStartup fejd) { _fejd = fejd; if ((Object)(object)_canvasRoot == (Object)null) { EnsureEventSystem(); BuildCanvas(); BuildPanel(); } _canvasRoot.SetActive(true); } public static void Hide() { if ((Object)(object)_canvasRoot != (Object)null) { _canvasRoot.SetActive(false); } } private static void BuildCanvas() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) _canvasRoot = new GameObject("ValheimRacesFejdSelector"); Canvas val = _canvasRoot.AddComponent(); val.renderMode = (RenderMode)0; val.sortingOrder = 5000; CanvasScaler val2 = _canvasRoot.AddComponent(); val2.uiScaleMode = (ScaleMode)1; val2.referenceResolution = new Vector2(1920f, 1080f); val2.screenMatchMode = (ScreenMatchMode)0; val2.matchWidthOrHeight = 0.5f; _canvasRoot.AddComponent(); _canvasRoot.AddComponent(); } private static void BuildPanel() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Expected O, but got Unknown //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) Font builtinResource = Resources.GetBuiltinResource("LegacyRuntime.ttf"); GameObject val = new GameObject("Panel", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(_canvasRoot.transform, false); RectTransform component = val.GetComponent(); component.anchorMin = new Vector2(1f, 0.5f); component.anchorMax = new Vector2(1f, 0.5f); component.pivot = new Vector2(1f, 0.5f); component.anchoredPosition = new Vector2(-30f, 0f); component.sizeDelta = new Vector2(280f, 760f); Image val2 = val.AddComponent(); ((Graphic)val2).color = new Color(0f, 0f, 0f, 0.65f); GameObject val3 = new GameObject("Title", new Type[1] { typeof(RectTransform) }); val3.transform.SetParent(val.transform, false); Text val4 = val3.AddComponent(); val4.text = "ESCOLHA SUA RAÇA"; val4.font = builtinResource; val4.fontSize = 20; val4.fontStyle = (FontStyle)1; val4.alignment = (TextAnchor)4; ((Graphic)val4).color = Color.white; val4.horizontalOverflow = (HorizontalWrapMode)0; RectTransform component2 = val3.GetComponent(); component2.anchorMin = new Vector2(0f, 1f); component2.anchorMax = new Vector2(1f, 1f); component2.pivot = new Vector2(0.5f, 1f); component2.sizeDelta = new Vector2(0f, 44f); component2.anchoredPosition = new Vector2(0f, -8f); GameObject val5 = new GameObject("Content", new Type[1] { typeof(RectTransform) }); val5.transform.SetParent(val.transform, false); RectTransform component3 = val5.GetComponent(); component3.anchorMin = Vector2.zero; component3.anchorMax = Vector2.one; component3.offsetMin = new Vector2(8f, 8f); component3.offsetMax = new Vector2(-8f, -54f); VerticalLayoutGroup val6 = val5.AddComponent(); ((HorizontalOrVerticalLayoutGroup)val6).spacing = 2f; ((HorizontalOrVerticalLayoutGroup)val6).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val6).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)val6).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val6).childControlWidth = true; int num = 0; foreach (KeyValuePair race in ValheimRacesPlugin.Races) { if (race.Value != null && race.Value.Enabled.Value) { string key = race.Key; string label = (((Object)(object)ValheimRacesPlugin.Instance != (Object)null) ? ValheimRacesPlugin.Instance.GetRaceName(key) : key); CreateRaceButton(val5.transform, builtinResource, key, label); num++; } } ValheimRacesPlugin.LogInfoPublic($"[ValheimRaces/FejdSelector] {num} raça(s) listada(s) no seletor."); BuildBottomHud(builtinResource); } private static void CreateRaceButton(Transform parent, Font font, string raceId, string label) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown GameObject val = new GameObject("Race_" + raceId, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); LayoutElement val2 = val.AddComponent(); val2.preferredHeight = 26f; val2.minHeight = 26f; Image val3 = val.AddComponent(); ((Graphic)val3).color = new Color(1f, 1f, 1f, 0.15f); Button val4 = val.AddComponent