using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EnvironmentalAwareness.Data; using EnvironmentalAwareness.Interface; using HarmonyLib; using JetBrains.Annotations; using LocalizationManager; using Microsoft.CodeAnalysis; using ServerSync; using SkillManager; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: AssemblyProduct("EnvironmentalAwareness")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyCompany("EnvironmentalAwareness")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyTitle("EnvironmentalAwareness")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<6f593530-c7c4-4c23-b63a-dc6d8177fab8>Embedded] internal sealed class <6f593530-c7c4-4c23-b63a-dc6d8177fab8>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] [<6f593530-c7c4-4c23-b63a-dc6d8177fab8>Embedded] [CompilerGenerated] internal sealed class <9d033fe9-c380-47d1-b735-cfa82d3b8a67>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <9d033fe9-c380-47d1-b735-cfa82d3b8a67>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <9d033fe9-c380-47d1-b735-cfa82d3b8a67>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [<6f593530-c7c4-4c23-b63a-dc6d8177fab8>Embedded] [CompilerGenerated] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace EnvironmentalAwareness { [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("maxfoxgaming.environmentalawareness", "EnvironmentalAwareness", "1.2.7")] public class Main : BaseUnityPlugin { public const string PluginGUID = "maxfoxgaming.environmentalawareness"; public const string PluginName = "EnvironmentalAwareness"; public const string PluginVersion = "1.2.7"; public const string PluginSavePath = "EnvironmentalAwareness_"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] private static Main instance; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public AssetBundle Bundle; public static Harmony harmony = new Harmony("maxfoxgaming.environmentalawareness"); public static readonly string ModPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public static ManualLogSource Log; public static readonly string VitalitySEName = "EA_Vitality"; public static readonly string EnergySEName = "EA_Energy"; public static readonly string CapabilitySEName = "EA_Capability"; public static readonly string PlayerStatsSEName = "EA_PlayerStats"; public static readonly string HungrySEName = "EA_Hungry"; public static readonly string HotSEName = "EA_Hot"; public static readonly string ScorchingSEName = "EA_Scorching"; public static readonly string ResistanceSkillName = "Resistance"; public static readonly string FitnessSkillName = "Fitness"; public static readonly string PerseverenceSkillName = "Perseverence"; public static readonly int ResistanceHash = StringExtensionMethods.GetStableHashCode(ResistanceSkillName); public static readonly int FitnessHash = StringExtensionMethods.GetStableHashCode(FitnessSkillName); public static readonly int PerseverenceHash = StringExtensionMethods.GetStableHashCode(PerseverenceSkillName); [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public SE_Hungry Hungry; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public SE_Hot Hot; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public SE_Scorching Scorching; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public SE_Vitality Vitality; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public SE_Energy Energy; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public SE_Capability Capability; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public SE_PlayerStats PlayerStats; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public Skill Resistance; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public Skill Fitness; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public Skill Assurance; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public Skill Perseverence; public TutorialText[] TutorialTexts = (TutorialText[])(object)new TutorialText[8] { new TutorialText { m_name = "EnvironmentalAwarenessVitality", m_label = "$ea_tutorial_vitality_label", m_text = "$ea_tutorial_vitality_text", m_topic = "$ea_tutorial_vitality_topic" }, new TutorialText { m_name = "EnvironmentalAwarenessVitalityLow", m_label = "$ea_tutorial_vitality_low_label", m_text = "$ea_tutorial_vitality_low_text", m_topic = "$ea_tutorial_vitality_low_topic" }, new TutorialText { m_name = "EnvironmentalAwarenessEnergy", m_label = "$ea_tutorial_energy_label", m_text = "$ea_tutorial_energy_text", m_topic = "$ea_tutorial_energy_topic" }, new TutorialText { m_name = "EnvironmentalAwarenessEnergyLow", m_label = "$ea_tutorial_energy_low_label", m_text = "$ea_tutorial_energy_low_text", m_topic = "$ea_tutorial_energy_low_topic" }, new TutorialText { m_name = "EnvironmentalAwarenessPotentiality", m_label = "$ea_tutorial_potentiality_label", m_text = "$ea_tutorial_potentiality_text", m_topic = "$ea_tutorial_potentiality_topic" }, new TutorialText { m_name = "EnvronmentalAwarenessPotentialityLow", m_label = "$ea_tutorial_potentiality_low_label", m_text = "$ea_tutorial_potentiality_low_text", m_topic = "$ea_tutorial_potentiality_low_topic" }, new TutorialText { m_name = "EnvironmentalAwarenessCapability", m_label = "$ea_tutorial_capability_low_label", m_text = "$ea_tutorial_capability_low_text", m_topic = "$ea_tutorial_capability_low_topic" }, new TutorialText { m_name = "EnvironmentalAwarenessHot", m_label = "$ea_tutorial_hot_label", m_text = "$ea_tutorial_hot_text", m_topic = "$ea_tutorial_hot_topic" } }; public static readonly string EAHud = "EAHud"; private readonly string[] credits = new string[8] { "ProbablyKory: Inspiration from the StormExposure mod.", "Azumatt: Help with Valheim asset ripping and referencing.", "OrianaVenture: Encouragement with trying status effect manipulation and the save system.", "GsiX & HugoTheDwarf: Help with sprite sizes.", "Blaxxun: ServerSync, SkillManager and LocalizationManager.", "Blacks7ar: Help with SkillManager to get level of custom skill.", "love5225: Korean translations.", "Blace: Russian translations." }; public void Awake() { Localizer.Load(); Log = ((BaseUnityPlugin)this).Logger; instance = this; ConfigManager.CreateConfigValues((BaseUnityPlugin)(object)this); SetupWatcher(); LoadAssets(); InitializeSEs(); InitializeSkills(); SetupCompatibility(); Harmony val = harmony; if (val != null) { val.PatchAll(); } } private void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, "maxfoxgaming.environmentalawareness.cfg"); fileSystemWatcher.Changed += ConfigManager.OnConfigChangedFromFile; fileSystemWatcher.Created += ConfigManager.OnConfigChangedFromFile; fileSystemWatcher.Renamed += ConfigManager.OnConfigChangedFromFile; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } public void LoadAssets() { LogMessage(() => "Loading bundles."); Bundle = LoadBundle("environmentalsprites"); } public void InitializeSEs() { //IL_0108: 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_0119: 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) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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) //IL_013e: 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) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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) LogMessage(() => "Initializing Status Effects."); Hungry = ScriptableObject.CreateInstance(); ((Object)Hungry).name = HungrySEName; Hot = ScriptableObject.CreateInstance(); ((Object)Hot).name = HotSEName; ((SE_Stats)Hot).m_healthRegenMultiplier = 0.5f; ((SE_Stats)Hot).m_staminaRegenMultiplier = 0.75f; ((SE_Stats)Hot).m_eitrRegenMultiplier = 0.75f; ((SE_Stats)Hot).m_speedModifier = -0.05f; Scorching = ScriptableObject.CreateInstance(); ((Object)Scorching).name = ScorchingSEName; ((SE_Stats)Scorching).m_healthRegenMultiplier = 0.2f; ((SE_Stats)Scorching).m_staminaRegenMultiplier = 0.5f; ((SE_Stats)Scorching).m_eitrRegenMultiplier = 0.5f; ((SE_Stats)Scorching).m_speedModifier = -0.2f; ((SE_Stats)Scorching).m_mods = new List { new DamageModPair { m_type = (DamageType)1, m_modifier = (DamageModifier)8 }, new DamageModPair { m_type = (DamageType)2, m_modifier = (DamageModifier)8 }, new DamageModPair { m_type = (DamageType)4, m_modifier = (DamageModifier)8 } }; Vitality = ScriptableObject.CreateInstance(); ((Object)Vitality).name = VitalitySEName; Energy = ScriptableObject.CreateInstance(); ((Object)Energy).name = EnergySEName; Capability = ScriptableObject.CreateInstance(); ((Object)Capability).name = CapabilitySEName; PlayerStats = ScriptableObject.CreateInstance(); ((Object)PlayerStats).name = PlayerStatsSEName; } public void InitializeSkills() { LogMessage(() => "Adding Skills."); if (Resistance == null) { Resistance = new Skill(ResistanceSkillName, Bundle.LoadAsset("vitalityicon1")); } Resistance.SkillEffectFactor = ConfigManager.ResistanceSkillEffectFactor.Value; Resistance.SkillGainFactor = ConfigManager.ResistanceSkillGainFactor.Value; Resistance.Configurable = false; LogSkill(Resistance, ResistanceSkillName); if (Fitness == null) { Fitness = new Skill(FitnessSkillName, Bundle.LoadAsset("energyicon1")); } Fitness.SkillEffectFactor = ConfigManager.FitnessSkillEffectFactor.Value; Fitness.SkillGainFactor = ConfigManager.FitnessSkillGainFactor.Value; Fitness.Configurable = false; LogSkill(Fitness, FitnessSkillName); if (Perseverence == null) { Perseverence = new Skill(PerseverenceSkillName, Bundle.LoadAsset("capabilityicon1")); } Perseverence.SkillEffectFactor = ConfigManager.PerseverenceSkillMaxTimeGain.Value; Perseverence.SkillGainFactor = ConfigManager.PerseverenceSkillGainFactor.Value; Perseverence.Configurable = false; LogSkill(Perseverence, PerseverenceSkillName); } private void SetupCompatibility() { LogMessage(() => "Checking for compatible mods..."); IEnumerable enumerable = from t in Assembly.GetExecutingAssembly().GetTypes() where t.IsClass && t.Namespace == "EnvironmentalAwareness.Compatibility" && t.IsAbstract && t.IsSealed select t; foreach (Type item in enumerable) { MethodInfo method = item.GetMethod("Setup", BindingFlags.Static | BindingFlags.Public); if (!(method == null)) { method.Invoke(null, null); } } } public void OnDestroy() { Harmony val = harmony; if (val != null) { val.UnpatchSelf(); } instance = null; } [NullableContext(2)] public static Main GetInstance() { return instance; } public static void LogMessage(Func message) { if (ConfigManager.DebugLogging.Value) { Log.LogMessage((object)message()); } } public static void LogSkill(Skill skill, string name) { LogMessage(() => string.Join("\n", new List { $"Skill added with name: {name} (SkillManager Hash: {skill.GetHashCode()}, Stable Hash: {StringExtensionMethods.GetStableHashCode(name)})", $"Effect Factor from Config: {skill.SkillEffectFactor}", $"Gain Factor from Config: {skill.SkillGainFactor}" })); } public static bool IsInMainScene() { //IL_0001: 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) Scene activeScene = SceneManager.GetActiveScene(); return ((Scene)(ref activeScene)).name.Equals("main"); } [return: <9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public static AssetBundle LoadBundle(string name) { LogMessage(() => "Attempting to load bundle with name " + name + " from assembly."); string text = ""; try { text = Assembly.GetExecutingAssembly().GetManifestResourceNames().Single((string str) => str.EndsWith(name)); } catch (Exception) { } if (text == "") { LogMessage(() => $"Could not find path to resource in {Assembly.GetExecutingAssembly().GetName()}."); return null; } AssetBundle result; using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text)) { result = AssetBundle.LoadFromStream(stream); } LogMessage(() => $"Loaded assetbundle {name} from {Assembly.GetExecutingAssembly().GetName()} successfully."); return result; } } [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public class SE_Capability : SE_SurvivalBase { public int m_meadsConsumed = 0; public int m_maxMeadsConsumed = 6; public float m_capabilityPercFromMead = 0f; public float m_capabilityPercFromMeadTick = 0f; public float m_meadDigestionTime = 0f; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_vitalityMaxModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_energyMaxModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_perserverenceSkillModifier; public WarningMessage c_warningTired = new WarningMessage("$ea_capability_warningmessage_tired"); public static readonly int Hash = StringExtensionMethods.GetStableHashCode(Main.CapabilitySEName); protected override string SENameKey => "$ea_se_capability"; protected override string IconName => "capabilityicon"; protected override int IconCount => 10; protected override string DataKey => "EnvironmentalAwareness_" + Main.CapabilitySEName; protected override string TooltipKey => "$ea_player_capability"; protected override bool DisplayPercentageEnabledConfigEntry => ConfigManager.DisplayCapabilityPercentage.Value; protected override bool DisplayWarningTextsConfigEntry => ConfigManager.DisplayCapabilityWarningTexts.Value; protected override string[] Statuses => new string[5] { "$ea_capability_status_0", "$ea_capability_status_1", "$ea_capability_status_2", "$ea_capability_status_3", "$ea_capability_status_4" }; protected override void SetupStatModifiers() { c_vitalityMaxModifier = new StatModifier(this, null, StatModifier.CalculationType.INVERSEPERCENTAGE) { m_enabled = ConfigManager.VitalityEnabled.Value, m_maxMultiplier = ConfigManager.CVitalityMaxCap.Value, m_threshold = ConfigManager.CVitalityMaxCapThreshold.Value, m_defaultValue = 100f }; c_energyMaxModifier = new StatModifier(this, null, StatModifier.CalculationType.INVERSEPERCENTAGE) { m_enabled = ConfigManager.EnergyEnabled.Value, m_maxMultiplier = ConfigManager.CEnergyMaxCap.Value, m_threshold = ConfigManager.CEnergyMaxCapThreshold.Value, m_defaultValue = 100f }; c_perserverenceSkillModifier = new StatModifier(this, c_warningTired, StatModifier.CalculationType.REGULAR) { m_enabled = ConfigManager.CapabilityEnabled.Value, m_maxMultiplier = ConfigManager.PerseverenceSkillGainFactor.Value, m_threshold = ConfigManager.PerseverenceSkillMinThreshold.Value, m_defaultValue = 0f }; } public override void SetupBaseFields() { base.SetupBaseFields(); m_baseMaxStatLoss = ConfigManager.CTimeToDrain.Value; } protected override void SetupExtraFields() { m_maxMeadsConsumed = ConfigManager.CTastyMeadLimit.Value; } protected override void LoadExtraFields(List list) { list[4].AssignAsInt(out m_meadsConsumed); list[5].AssignAsFloat(out m_capabilityPercFromMead); list[6].AssignAsFloat(out m_capabilityPercFromMeadTick); list[7].AssignAsBool(out c_warningTired.m_display); list[8].AssignAsFloat(out m_meadDigestionTime); } protected override void SaveExtraFields(StringBuilder sb) { sb.AppendStat(m_meadsConsumed); sb.AppendStat(m_capabilityPercFromMead); sb.AppendStat(m_capabilityPercFromMeadTick); sb.AppendStat(c_warningTired.m_display); sb.AppendStat(m_meadDigestionTime); } protected override void UpdateRealtimeExternalStatChanges(float dt) { UpdateCapabilityFromMead(dt); RaisePerserverenceSkill(dt); } private void UpdateCapabilityFromMead(float dt) { if ((double)m_capabilityPercFromMead < 0.01) { m_capabilityPercFromMead = 0f; m_capabilityPercFromMeadTick = 0f; } else { base.ChangeStatLossByPercentage(-1f * m_capabilityPercFromMeadTick); m_capabilityPercFromMead -= m_capabilityPercFromMeadTick; } } public void RaisePerserverenceSkill(float dt) { ((Character)(object)player).RaiseSkill("Perseverence", 0.01f * dt * c_perserverenceSkillModifier.CalculateMultiplier()); } protected override void UpdateTutorial() { if (m_statLossPerc > 60f) { player.ShowTutorial("EnvironmentalAwarenessCapability", false); } } protected override void UpdateStatValue() { ProcessDigestion(); if (pes.PlayerLayingInBed && !pes.PlayerSleeping) { ApplyCapabilityGainFromLayingInBed(); } else { m_statLoss = Mathf.Clamp(m_statLoss + m_statChange, 0f, m_maxStatLoss); } } public override void Recalculate() { base.Recalculate(); m_statChange = CalculateTotalMultiplier(); } private void ProcessDigestion() { if (m_meadDigestionTime <= 0f) { m_meadDigestionTime = ConfigManager.CTastyMeadDigestionTime.Value; } if (m_meadsConsumed > 0) { float num = ((pes.PlayerLayingInBed && !pes.PlayerSleeping) ? ConfigManager.CTastyMeadDigestionInBedMultiplier.Value : 1f); m_meadDigestionTime -= num; if (m_meadDigestionTime <= 0f) { DecreaseMeadConsumption(); } } } private float CalculateTotalMultiplier() { return CalculateVitalityMultiplier() * CalculateEnergyMultiplier() * CalculateRestedMultiplier(); } private float CalculateVitalityMultiplier() { if (!ConfigManager.VitalityEnabled.Value) { return 1f; } float vitalityPercentage = pes.VitalityPercentage; if (vitalityPercentage >= ConfigManager.CVitalityResistThreshold.Value) { return ConfigManager.CVitalityResist.Value; } if (vitalityPercentage < ConfigManager.CLowVitalityLossThreshold.Value) { return ConfigManager.CLowVitalityLoss.Value; } return 1f; } private float CalculateEnergyMultiplier() { if (!ConfigManager.EnergyEnabled.Value) { return 1f; } float energyPercentage = pes.EnergyPercentage; if (energyPercentage >= ConfigManager.CEnergyResistThreshold.Value) { return ConfigManager.CEnergyResist.Value; } if (energyPercentage < ConfigManager.CLowEnergyLossThreshold.Value) { return ConfigManager.CLowEnergyLoss.Value; } return 1f; } private float CalculateRestedMultiplier() { return pes.PlayerRested ? ConfigManager.CRestedResist.Value : 1f; } protected override float CalculateAdditionalMaxStat() { float num = pes.PerseverenceSkillLevel / 100f; return num * ConfigManager.PerseverenceSkillMaxTimeGain.Value; } protected override void UpdateEffects() { UpdateStatusEffectModifiers(); } private void UpdateStatusEffectModifiers() { pes.VitalityMaxPercentage = c_vitalityMaxModifier.CalculateMultiplier(); pes.EnergyMaxPercentage = c_energyMaxModifier.CalculateMultiplier(); } public void ApplyCapabilityGainFromMead() { if (IncreaseMeadConsumption()) { m_capabilityPercFromMead += ConfigManager.CTastyMeadLossRemove.Value; m_capabilityPercFromMeadTick = ConfigManager.CTastyMeadLossRemove.Value / 100f; } } public void ApplyCapabilityGainFromLayingInBed() { base.ChangeStatLossByPercentage(-1f * ConfigManager.CInBedLossRemove.Value); } public void ApplyCapabilityGainFromSleep() { base.ChangeStatLossByPercentage(-1f * ConfigManager.CSleepLossRemove.Value); DecreaseMeadConsumption(ConfigManager.CTastyMeadSleepRemove.Value); } private bool IncreaseMeadConsumption() { if (m_meadsConsumed >= m_maxMeadsConsumed) { return false; } m_meadsConsumed++; return true; } private void DecreaseMeadConsumption(int amount = 1) { if (m_meadsConsumed != 0) { m_meadsConsumed = Mathf.Max(m_meadsConsumed - amount, 0); } } protected override void LogStatistics() { Main.LogMessage(() => string.Join("\n", new List { "Capability SE UPDATE", $"Capability: {Mathf.Round(100f - m_statLossPerc)} ({m_maxStatLoss - m_statLoss} / {m_maxStatLoss})", $"Change OT: {m_statChange}" })); } public override void GetAdditionalDebugStrings(StringBuilder sb) { base.GetAdditionalDebugStrings(sb); sb.AppendFormat("m_meadsConsumed: {0}\n", m_meadsConsumed); sb.AppendFormat("m_maxMeadsConsumed: {0}\n", m_maxMeadsConsumed); sb.AppendFormat("m_capabilityPercFromMead: {0}\n", m_capabilityPercFromMead); sb.AppendFormat("m_capabilityPercFromMeadTick: {0}\n", m_capabilityPercFromMeadTick); sb.AppendFormat("m_meadDigestionTime {0}\n", m_meadDigestionTime); } } [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [NullableContext(1)] public class SE_Energy : SE_SurvivalBase { public float m_staminaRegenDelay = 0f; public float m_staminaReductionMultiplier = 1f; public float m_energyFromFood = 0f; public float m_energyFromFoodTick = 0f; public float m_energyRegenSpeed = 0.5f; public float m_timeSinceRested = 0f; public float m_fitnessSkillMultiplier = 1f; public float m_seasonMultiplier = 1f; public float m_lossEnergyRestedMult = 1f; public float m_lossEnergyCarryWeightAdd = 0f; public float m_lossEnergyMovementAdd = 0f; public float m_staminaMeadMult = 1f; public float m_noRestMultiplier = 1f; public float s_totalStaminaUseInCycle = 0f; public float s_totalEnergyUseInCycle = 0f; public float s_lastRawLossInCycle; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_carryWeightModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_restedRemoveModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_damageModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_speedModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_skillGainModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_staminaReductionModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_staminaRegenModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_staminaDelayModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_energyLossResistModifier; public WarningMessage c_warningWeight = new WarningMessage("$ea_energy_warningmessage_weight"); public WarningMessage c_warningDamage = new WarningMessage("$ea_energy_warningmessage_damage"); public WarningMessage c_warningSpeed = new WarningMessage("$ea_energy_warningmessage_movement"); public WarningMessage c_warningSkillGain = new WarningMessage("$ea_energy_warningmessage_skillgain"); public WarningMessage c_warningStaminaReduction = new WarningMessage("$ea_energy_warningmessage_maxstamina"); public WarningMessage c_warningStaminaRegen = new WarningMessage("$ea_energy_warningmessage_staminaregen"); public WarningMessage c_warningStaminaDelay = new WarningMessage("$ea_energy_warningmessage_staminadelay"); public static readonly int Hash = StringExtensionMethods.GetStableHashCode(Main.EnergySEName); protected override string SENameKey => "$ea_se_energy"; protected override string IconName => "energyicon"; protected override int IconCount => 15; protected override string DataKey => "EnvironmentalAwareness_" + Main.EnergySEName; protected override string TooltipKey => "$ea_player_energy"; protected override bool DisplayPercentageEnabledConfigEntry => ConfigManager.DisplayEnergyPercentage.Value; protected override bool DisplayWarningTextsConfigEntry => ConfigManager.DisplayEnergyWarningTexts.Value; protected override string[] Statuses => new string[5] { "$ea_energy_status_0", "$ea_energy_status_1", "$ea_energy_status_2", "$ea_energy_status_3", "$ea_energy_status_4" }; protected override void SetupStatModifiers() { c_carryWeightModifier = new StatModifier(this, c_warningWeight, StatModifier.CalculationType.REGULAR) { m_enabled = true, m_maxMultiplier = ConfigManager.ELossHeavyLoadAdd.Value, m_threshold = ConfigManager.ELossHeavyLoadThreshold.Value, m_defaultValue = 0f }; c_restedRemoveModifier = new StatModifier(this, null, StatModifier.CalculationType.ONEZERO) { m_enabled = ConfigManager.ERestedLossEnabled.Value, m_maxMultiplier = 1f, m_threshold = ConfigManager.ERestedLossThreshold.Value, m_defaultValue = 0f }; c_damageModifier = new StatModifier(this, c_warningDamage, StatModifier.CalculationType.INVERSE) { m_enabled = ConfigManager.EDamageReductionEnabled.Value, m_maxMultiplier = ConfigManager.EDamageMaxReduction.Value, m_threshold = ConfigManager.EDamageReductionThreshold.Value, m_defaultValue = 1f }; c_speedModifier = new StatModifier(this, c_warningSpeed, StatModifier.CalculationType.NEGATIVE) { m_enabled = ConfigManager.EMoveSpeedReductionEnabled.Value, m_maxMultiplier = ConfigManager.EMoveSpeedMaxReduction.Value, m_threshold = ConfigManager.EMoveSpeedReductionMinThreshold.Value, m_defaultValue = 0f }; c_skillGainModifier = new StatModifier(this, c_warningSkillGain, StatModifier.CalculationType.NEGATIVE) { m_enabled = ConfigManager.ESkillGainReductionEnabled.Value, m_maxMultiplier = ConfigManager.EMoveSpeedMaxReduction.Value, m_threshold = ConfigManager.EMoveSpeedReductionMinThreshold.Value, m_defaultValue = 0f }; c_staminaReductionModifier = new StatModifier(this, c_warningStaminaReduction, StatModifier.CalculationType.INVERSE) { m_enabled = ConfigManager.EMaxStaminaReductionEnabled.Value, m_maxMultiplier = ConfigManager.EMaxStaminaReduction.Value, m_threshold = ConfigManager.EMaxStaminaReductionThreshold.Value, m_defaultValue = 1f }; c_staminaRegenModifier = new StatModifier(this, c_warningStaminaRegen, StatModifier.CalculationType.INVERSE) { m_enabled = ConfigManager.EStaminaRegenEnabled.Value, m_maxMultiplier = ConfigManager.EStaminaRegenMaxReduction.Value, m_threshold = ConfigManager.EStaminaRegenMinThreshold.Value, m_defaultValue = 1f }; c_staminaDelayModifier = new StatModifier(this, c_warningStaminaDelay, StatModifier.CalculationType.REGULAR) { m_enabled = ConfigManager.EStaminaRegenDelayEnabled.Value, m_maxMultiplier = ConfigManager.EStaminaRegenDelayMaxMultiplier.Value, m_threshold = ConfigManager.EStaminaRegenDelayMinThreshold.Value, m_defaultValue = 0f }; c_energyLossResistModifier = new StatModifier(this, null, StatModifier.CalculationType.INVERSE) { m_enabled = true, m_maxMultiplier = ConfigManager.ELossLowEnergyResist.Value, m_threshold = ConfigManager.ELossLowEnergyThreshold.Value, m_defaultValue = 1f }; } protected override void SetupExtraFields() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) ((SE_Stats)this).m_modifyAttackSkill = (SkillType)999; ((SE_Stats)this).m_raiseSkill = (SkillType)999; ((SE_Stats)this).m_raiseSkillModifier = 0f; m_staminaRegenDelay = 0f; m_staminaReductionMultiplier = 1f; m_seasonMultiplier = 1f; m_lossEnergyRestedMult = 1f; m_lossEnergyCarryWeightAdd = 0f; m_lossEnergyMovementAdd = 0f; m_staminaMeadMult = 1f; m_noRestMultiplier = 1f; } protected override void LoadExtraFields(List list) { list[4].AssignAsFloat(out m_staminaRegenDelay); list[5].AssignAsFloat(out m_staminaReductionMultiplier); list[6].AssignAsFloat(out m_energyFromFood); list[7].AssignAsFloat(out m_energyFromFoodTick); list[8].AssignAsFloat(out m_energyRegenSpeed); list[9].AssignAsFloat(out m_timeSinceRested); list[10].AssignAsFloat(out m_fitnessSkillMultiplier); list[11].AssignAsFloat(out m_seasonMultiplier); list[12].AssignAsFloat(out m_lossEnergyRestedMult); list[13].AssignAsFloat(out m_lossEnergyCarryWeightAdd); list[14].AssignAsFloat(out m_lossEnergyMovementAdd); list[15].AssignAsFloat(out m_staminaMeadMult); list[16].AssignAsFloat(out m_noRestMultiplier); list[17].AssignAsBool(out c_warningSpeed.m_display); list[18].AssignAsBool(out c_warningStaminaRegen.m_display); list[19].AssignAsBool(out c_warningStaminaDelay.m_display); list[20].AssignAsBool(out c_warningSkillGain.m_display); list[21].AssignAsBool(out c_warningStaminaReduction.m_display); list[22].AssignAsBool(out c_warningDamage.m_display); list[23].AssignAsBool(out c_warningWeight.m_display); } protected override void SaveExtraFields(StringBuilder sb) { sb.AppendStat(m_staminaRegenDelay); sb.AppendStat(m_staminaReductionMultiplier); sb.AppendStat(m_energyFromFood); sb.AppendStat(m_energyFromFoodTick); sb.AppendStat(m_energyRegenSpeed); sb.AppendStat(m_timeSinceRested); sb.AppendStat(m_fitnessSkillMultiplier); sb.AppendStat(m_seasonMultiplier); sb.AppendStat(m_lossEnergyRestedMult); sb.AppendStat(m_lossEnergyCarryWeightAdd); sb.AppendStat(m_lossEnergyMovementAdd); sb.AppendStat(m_staminaMeadMult); sb.AppendStat(m_noRestMultiplier); sb.AppendStat(c_warningSpeed.m_display); sb.AppendStat(c_warningStaminaRegen.m_display); sb.AppendStat(c_warningStaminaDelay.m_display); sb.AppendStat(c_warningSkillGain.m_display); sb.AppendStat(c_warningStaminaReduction.m_display); sb.AppendStat(c_warningDamage.m_display); sb.AppendStat(c_warningWeight.m_display); } protected override void GetPlayerHintStrings(StringBuilder sb) { if (pes.EnergyMaxPercentage <= 99f) { sb.AppendFormat("$ea_player_energy_capped \n", Mathf.RoundToInt(pes.EnergyMaxPercentage)); } if (pes.PlayerStaminaMead) { sb.Append("$ea_player_stamina_mead \n"); } if (m_energyFromFood > 0f) { sb.Append("$ea_player_food_recover_energy \n"); } if (m_timeSinceRested > ConfigManager.ELossNoRestThreshold.Value / 2f) { sb.Append("$ea_player_need_rest_energy \n"); } if (m_statLossPerc > ConfigManager.ERestedLossThreshold.Value) { sb.Append("$ea_player_cannot_stay_rested \n"); } } protected override void GetStatLossHintStrings(StringBuilder sb) { if (!pes.PlayerSheltered) { if (pes.PlayerCold || pes.PlayerFreezing) { sb.Append("$ea_player_coldfreezing_energy \n"); } if (pes.PlayerHot || pes.PlayerScorching) { sb.Append("$ea_player_hotscorching_energy \n"); } } if (pes.PlayerWet) { sb.Append("$ea_player_wet_energy \n"); } if (pes.PlayerHungry) { sb.Append("$ea_player_hungry_energy \n"); } } protected override void GetStatGainHintStrings(StringBuilder sb) { sb.Append("$ea_player_recovering_energy \n"); } protected override void GetStatChangeStrings(StringBuilder sb) { if (m_staminaReductionMultiplier != 1f) { sb.AppendFormat("$ea_se_maxstaminamultiplier: {0}x \n", Mathf.Floor(101f * m_staminaReductionMultiplier) / 100f); } if (m_staminaRegenDelay > 0f) { sb.AppendFormat("$ea_se_staminaregendelay: {0}s \n", (Mathf.Floor(10f * m_staminaRegenDelay) / 10f).ToString("+0;-0")); } if (m_staminaMeadMult != 1f) { sb.AppendFormat("$ea_se_energylossresist: {0}% \n", Mathf.Floor(100f * m_staminaMeadMult)); } } protected override void UpdateRealtimeExternalStatChanges(float dt) { UpdateStaminaRegenDelay(); UpdateEnergyFromFood(dt); } private void UpdateStaminaRegenDelay() { if (!((Object)(object)pes == (Object)null)) { player.m_staminaRegenDelay = pes.PlayerStaminaRegenDelay + m_staminaRegenDelay; } } private void UpdateEnergyFromFood(float dt) { if ((double)m_energyFromFood < 0.01) { m_energyFromFood = 0f; m_energyFromFoodTick = 0f; return; } m_energyFromFoodTick = m_maxStatLoss / m_baseMaxStatLoss * Mathf.Min(m_energyRegenSpeed, m_energyFromFood) * dt; m_statLoss -= m_energyFromFoodTick; float num = (100f - pes.EnergyMaxPercentage) * m_maxStatLoss / 100f; if (m_statLoss < num) { m_statLoss = num; } m_energyFromFood -= m_energyFromFoodTick; } protected override void UpdateTutorial() { if (m_statLossPerc > 10f) { player.ShowTutorial("EnvironmentalAwarenessEnergy", false); } if (m_statLossPerc > 60f) { player.ShowTutorial("EnvironmentalAwarenessEnergyLow", false); } } protected override void UpdatePerSecondStateChanges() { UpdateNonRestedState(); UpdateMovementState(); } private void UpdateNonRestedState() { if (pes.PlayerRested) { m_timeSinceRested = 0f; m_noRestMultiplier = 1f; } else { m_timeSinceRested += 1f; m_noRestMultiplier = 1f + Mathf.Min(m_timeSinceRested / ConfigManager.ELossNoRestThreshold.Value, 1f) * (ConfigManager.ELossNoRestMultiplier.Value - 1f); } } private void UpdateMovementState() { m_lossEnergyMovementAdd = (pes.PlayerMoving ? (m_noRestMultiplier * m_seasonMultiplier * m_fitnessSkillMultiplier * m_lossEnergyRestedMult * ConfigManager.ELossMotionAdd.Value) : 0f); } protected override void UpdateStatValue() { float num = c_energyLossResistModifier.CalculateMultiplier() * (m_statChange + m_lossEnergyMovementAdd); m_statLoss = Mathf.Clamp(m_statLoss + num, 0f, m_maxStatLoss); m_statLoss = Mathf.Max((100f - pes.EnergyMaxPercentage) * m_maxStatLoss / 100f, m_statLoss); } public override void Recalculate() { base.Recalculate(); m_lossEnergyRestedMult = CalculateRestedMultiplier(); m_lossEnergyCarryWeightAdd = CalculateCarryWeightAdd(); m_seasonMultiplier = CalculateSeasonMultiplier(); m_staminaMeadMult = CalculateStaminaMeadMultiplier(); m_fitnessSkillMultiplier = CalculateFitnessSkillMultiplier(); m_statChange = m_staminaMeadMult * m_seasonMultiplier * m_fitnessSkillMultiplier * CalculatePassiveLosses() - (CalculateGainsFromRest() + CalculateGainsFromStaminaMead()); } private float CalculateRestedMultiplier() { return pes.PlayerRested ? ConfigManager.ELossRestedResist.Value : 1f; } private float CalculateCarryWeightAdd() { return c_carryWeightModifier.CalculateMultiplier(pes.PlayerCarryWeightPerc); } private float CalculatePassiveLosses() { float num = 0f; if (pes.PlayerCold) { num += ConfigManager.ELossColdAdd.Value; } if (pes.PlayerFreezing) { num += ConfigManager.ELossFreezingAdd.Value; } if (pes.PlayerHot) { num += ConfigManager.ELossHotAdd.Value; } if (pes.PlayerScorching) { num += ConfigManager.ELossScorchingAdd.Value; } if (pes.PlayerWet) { num += ConfigManager.ELossWetAdd.Value; } if (pes.PlayerHungry) { num += ConfigManager.ELossHungryAdd.Value; } return m_lossEnergyRestedMult * num; } private float CalculateGainsFromRest() { float num = 0f; if (pes.PlayerSitting) { num += ConfigManager.ELossSittingRemove.Value; } if (pes.PlayerResting) { num += ConfigManager.ELossRestingRemove.Value; } if (pes.PlayerRested && !pes.PlayerResting && !pes.PlayerHasBadEnvironmentalStatus) { num += ConfigManager.ELossRestedRemove.Value; } if (pes.PlayerSitting && pes.PlayerResting) { num *= ConfigManager.ELossSittingRestingMultiplier.Value; } if (pes.PlayerSitting && pes.PlayerResting && pes.PlayerSheltered) { num *= ConfigManager.ELossSittingRestingShelterMultiplier.Value; } return m_maxStatLoss / m_baseMaxStatLoss * num; } private float CalculateGainsFromStaminaMead() { return pes.PlayerStaminaMead ? (ConfigManager.ELossStaminaMeadRemove.Value * m_maxStatLoss) : 0f; } protected override float CalculateAdditionalMaxStat() { float num = pes.FitnessSkillLevel / 100f; float num2 = ConfigManager.FitnessSkillMaxEnergyGain.Value - m_baseMaxStatLoss; return num * num2; } private float CalculateSeasonMultiplier() { if (pes.PlayerInSeasonExcludedBiome) { return m_seasonMultiplier = 1f; } return pes.EnvironmentSeasonState switch { EnvManHelper.Season.Spring => m_seasonMultiplier = ConfigManager.ESpringSeasonMultiplier.Value, EnvManHelper.Season.Summer => m_seasonMultiplier = ConfigManager.ESummerSeasonMultiplier.Value, EnvManHelper.Season.Fall => m_seasonMultiplier = ConfigManager.EFallSeasonMultiplier.Value, EnvManHelper.Season.Winter => m_seasonMultiplier = ConfigManager.EWinterSeasonMultiplier.Value, _ => m_seasonMultiplier = 1f, }; } private float CalculateStaminaMeadMultiplier() { return m_staminaMeadMult = (pes.PlayerStaminaMead ? (1f - ConfigManager.ELossStaminaMeadResist.Value) : 1f); } private float CalculateFitnessSkillMultiplier() { return 1f - pes.FitnessSkillFactor; } protected override void UpdateEffects() { UpdateRemoveRested(); UpdateStatusEffectModifiers(); } private void UpdateRemoveRested() { if (c_restedRemoveModifier.CalculateMultiplier() > 0f && pes.PlayerRested && !pes.PlayerResting) { StatusEffect statusEffect = ((Character)player).m_seman.GetStatusEffect(SEMan.s_statusEffectRested); SE_Rested val = (SE_Rested)(object)((statusEffect is SE_Rested) ? statusEffect : null); if (!((Object)(object)val == (Object)null)) { ((Character)player).m_seman.RemoveStatusEffect((StatusEffect)(object)val, false); } } } private void UpdateStatusEffectModifiers() { ((SE_Stats)this).m_damageModifier = c_damageModifier.CalculateMultiplier(); ((SE_Stats)this).m_speedModifier = c_speedModifier.CalculateMultiplier(); ((SE_Stats)this).m_raiseSkillModifier = c_skillGainModifier.CalculateMultiplier(); m_staminaReductionMultiplier = c_staminaReductionModifier.CalculateMultiplier(); ((SE_Stats)this).m_staminaRegenMultiplier = c_staminaRegenModifier.CalculateMultiplier(); m_staminaRegenDelay = c_staminaDelayModifier.CalculateMultiplier(); } public void ApplyEnergyGainFromFood(float stamina) { if (!pes.PlayerNoSkillDrain && !(countdownTimer > 0f)) { float num = stamina * ConfigManager.ELossFoodStaminaRemove.Value; float num2 = m_maxStatLoss / m_baseMaxStatLoss; m_energyFromFood += num * num2; } } public void ApplyEnergyGainFromSleeping() { base.ChangeStatLossByPercentage(-1f * ConfigManager.ELossPercentageSleepRemove.Value); } public void ApplyEnergyLossFromStamina(float stamina) { if (!pes.PlayerNoSkillDrain && !(countdownTimer > 0f)) { float num = stamina * (ConfigManager.ELossStaminaPointUsedAdd.Value + m_lossEnergyCarryWeightAdd); float num2 = m_lossEnergyRestedMult * m_seasonMultiplier * m_fitnessSkillMultiplier * m_noRestMultiplier * (1f - pes.FitnessSkillFactor) * num; m_statLoss += num2; if (m_statLoss > m_maxStatLoss) { num = m_statLoss - m_maxStatLoss; m_statLoss = m_maxStatLoss; } RaiseFitnessSkill(num); s_totalStaminaUseInCycle += stamina; s_totalEnergyUseInCycle += num2; s_lastRawLossInCycle = num; } } public void RaiseFitnessSkill(float amount) { ((StatusEffect)this).m_character.RaiseSkill("Fitness", 0.2f * amount * ConfigManager.FitnessSkillGainFactor.Value); } protected override void LogStatistics() { Main.LogMessage(() => string.Join("\n", new List { "ENERGY SE UPDATE", $"Energy: {Mathf.Round(100f - m_statLossPerc)} ({m_maxStatLoss - m_statLoss} / {m_maxStatLoss})", $"Rested Resist Mult: {m_lossEnergyRestedMult}", $"No Rested Debuffs: +{m_noRestMultiplier}x ({m_timeSinceRested}s since last rested)", $"Stamina Regen Multiplier: {((SE_Stats)this).m_staminaRegenMultiplier}x", $"Stamina Regen Delay: +{m_staminaRegenDelay}s", $"Seasonal Multiplier: {m_seasonMultiplier}x", $"Fitness Skill Multiplier {m_fitnessSkillMultiplier}x", $"Stamina Use in Cycle: {s_totalStaminaUseInCycle}", $"Energy Loss from Stamina in Cycle: {s_totalEnergyUseInCycle}", $"Last Raw Loss in Cycle: {s_lastRawLossInCycle}" })); } protected override void ResetCycleStats() { s_totalStaminaUseInCycle = 0f; s_totalEnergyUseInCycle = 0f; s_lastRawLossInCycle = 0f; } public override void GetAdditionalDebugStrings(StringBuilder sb) { base.GetAdditionalDebugStrings(sb); sb.AppendFormat("m_staminaRegenDelay: {0}\n", m_staminaRegenDelay); sb.AppendFormat("m_staminaReductionMultiplier: {0}\n", m_staminaReductionMultiplier); sb.AppendFormat("m_energyFromFood: {0}\n", m_energyFromFood); sb.AppendFormat("m_energyFromFoodTick: {0}\n", m_energyFromFoodTick); sb.AppendFormat("m_energyRegenSpeed: {0}\n", m_energyRegenSpeed); sb.AppendFormat("m_timeSinceRested: {0}\n", m_timeSinceRested); sb.AppendFormat("m_fitnessSkillMultiplier: {0}\n", m_fitnessSkillMultiplier); sb.AppendFormat("m_seasonMultiplier: {0}\n", m_seasonMultiplier); sb.AppendFormat("m_lossEnergyRestedMult: {0}\n", m_lossEnergyRestedMult); sb.AppendFormat("m_lossEnergyCarryWeightAdd: {0}\n", m_lossEnergyCarryWeightAdd); sb.AppendFormat("m_lossEnergyMovementAdd: {0}\n", m_lossEnergyMovementAdd); sb.AppendFormat("m_staminaMeadMult: {0}\n", m_staminaMeadMult); sb.AppendFormat("m_noRestMultiplier: {0}\n", m_noRestMultiplier); } } [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public class SE_Hot : SE_Stats { public static readonly int Hash = StringExtensionMethods.GetStableHashCode(Main.HotSEName); public float m_iconTimer; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(new byte[] { 2, 1 })] public Sprite[] m_icons; public override void Setup(Character character) { ((StatusEffect)this).m_startMessage = "$ea_player_hot_status"; ((SE_Stats)this).Setup(character); ((StatusEffect)this).m_name = "$ea_se_hot"; LoadIcons(); UpdateIcon(); base.m_healthRegenMultiplier = 0.5f; base.m_staminaRegenMultiplier = 0.75f; base.m_eitrRegenMultiplier = 0.75f; base.m_speedModifier = -0.05f; } public override void UpdateStatusEffect(float dt) { m_iconTimer += dt; if (m_iconTimer > 5f) { UpdateIcon(); m_iconTimer -= 5f; } ((SE_Stats)this).UpdateStatusEffect(dt); } protected virtual void LoadIcons() { m_icons = (Sprite[])(object)new Sprite[2] { Main.GetInstance().Bundle.LoadAsset("hoticon"), Main.GetInstance().Bundle.LoadAsset("hoticon2") }; } protected virtual void UpdateIcon() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 Character character = ((StatusEffect)this).m_character; Player val = (Player)(object)((character is Player) ? character : null); if (!((Object)(object)val == (Object)null)) { ((StatusEffect)this).m_icon = m_icons[((int)val.GetCurrentBiome() == 32 && EnvMan.IsNight()) ? 1 : 0]; } } public override string GetIconText() { return ""; } public override string GetTooltipString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("$ea_player_hot_status \n"); stringBuilder.Append(((SE_Stats)this).GetTooltipString()); return stringBuilder.ToString(); } } [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public class SE_Hungry : SE_Stats { public static readonly int Hash = StringExtensionMethods.GetStableHashCode(Main.HungrySEName); public override void Setup(Character character) { ((StatusEffect)this).m_startMessage = "$ea_player_hungry_status"; ((SE_Stats)this).Setup(character); ((StatusEffect)this).m_name = "$ea_se_hungry"; ((StatusEffect)this).m_icon = Main.GetInstance().Bundle.LoadAsset("hungryicon"); ((StatusEffect)this).m_ttl = 1f; } public override string GetIconText() { return ""; } public override void UpdateStatusEffect(float dt) { if (!(((StatusEffect)this).m_time > ((StatusEffect)this).m_ttl)) { ((SE_Stats)this).UpdateStatusEffect(dt); ((StatusEffect)this).m_time = 0f; } } public override void Stop() { ((StatusEffect)this).Stop(); ((StatusEffect)this).m_ttl = 1f; } public override string GetTooltipString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("$ea_player_hungry_status \n"); stringBuilder.Append(((SE_Stats)this).GetTooltipString()); return stringBuilder.ToString(); } } [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public class SE_PlayerStats : StatusEffect, ILoadSave { [NullableContext(0)] private delegate void HandleSurvivalSEs(); [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public Player player; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] private HandleSurvivalSEs HandleSurvivalSE; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] private SE_Vitality vitality; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] private SE_Energy energy; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] private SE_Capability capability; private List playerState = new List(); private List environmentState = new List(); private float player_base_health; private float player_base_stamina; private float player_base_stamina_regen_delay; private float player_carry_weight_perc; private bool player_no_skill_drain; private float player_health_percentage; private float player_body_armor; private bool player_healing_mead; private bool player_stamina_mead; private bool player_eitr_mead; private float player_time_since_final_food_digested; private float player_time_since_eaten_with_good_hp; private Biome player_in_biome = (Biome)895; private bool player_in_excluded_environment; private bool player_moving; private bool player_poison_resistant; private bool player_poison_very_resistant; private bool player_fire_resistant; private bool player_fire_very_resistant; private bool player_lightning_resistant; private bool player_lightning_very_resistant; private bool player_frost_resistant; private bool player_frost_very_resistant; private bool player_sheltered; private bool player_sitting; private bool player_laying_in_bed; private bool player_sleeping; private bool player_near_fire; private bool player_resting; private bool player_rested; private bool player_wet; private bool player_cold; private bool player_freezing; private bool player_hot; private bool player_scorching; private bool player_hungry; private bool player_poisoned; private bool player_burning; private bool player_shocked; private bool player_frozen; private bool player_blood_protected; private bool environment_wet; private bool environment_cold; private bool environment_freezing; private bool environment_hot; private bool environment_scorching; private float environment_wind_intensity; private EnvManHelper.Season environment_season_state; private float resistance_skill_level; private float resistance_skill_factor; private float fitness_skill_level; private float fitness_skill_factor; private float perseverence_skill_level; private float perseverence_skill_factor; private float resistance_extra_attack_multiplier = 1f; private float resistance_extra_mead_duration_multiplier = 1f; private float fitness_food_burn_multiplier = 1f; private float fitness_speed_penalty_reduction = 0f; private int perseverence_comfort_bonus = 0; private float perseverence_max_adrenaline_multiplier = 1f; private float vitality_max_percentage = 100f; private float energy_max_percentage = 100f; private bool recalculate = false; public float lastUpdateTime = 0f; public float lastLogTime = 0f; public static readonly int Hash = StringExtensionMethods.GetStableHashCode(Main.PlayerStatsSEName); [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] private PlayerFoodCache player_food_cache; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] private SE_Stats_Modifiers se_stats_modifiers; public List PlayerState => playerState; public List EnvironmentState => environmentState; public float PlayerBaseHealth => player_base_health; public float PlayerBaseStamina => player_base_stamina; public float PlayerStaminaRegenDelay => player_base_stamina_regen_delay; public float PlayerCarryWeightPerc { get { return player_carry_weight_perc; } set { if (Helper.Approximately(player_carry_weight_perc, value)) { player_carry_weight_perc = value; return; } Main.LogMessage(() => $"Player carry weight changed to {value}%."); player_carry_weight_perc = value; recalculate = true; } } public bool PlayerNoSkillDrain { get { return player_no_skill_drain; } set { if (player_no_skill_drain != value) { Main.LogMessage(() => "Player no skill drain changed."); player_no_skill_drain = value; recalculate = true; playerState.CheckState(value, "No Skill Drain"); } } } public float PlayerHealthPercentage { get { return player_health_percentage; } set { if (!(Mathf.Abs(player_health_percentage - value) < 0.001f)) { Main.LogMessage(() => $"Player HP percentage changed to {value}%."); player_health_percentage = value; recalculate = true; } } } public float PlayerBodyArmor { get { return player_body_armor; } set { if (Helper.Approximately(player_body_armor, value)) { player_body_armor = value; return; } Main.LogMessage(() => $"Player armor changed to {value}."); player_body_armor = value; recalculate = true; } } public bool PlayerHealingMead { get { return player_healing_mead; } set { if (player_healing_mead != value) { Main.LogMessage(() => "Player healing mead changed."); player_healing_mead = value; recalculate = true; playerState.CheckState(value, "Using Healing Mead"); } } } public bool PlayerStaminaMead { get { return player_stamina_mead; } set { if (player_stamina_mead != value) { Main.LogMessage(() => "Player stamina mead changed."); player_stamina_mead = value; recalculate = true; playerState.CheckState(value, "Using Stamina Mead"); } } } public bool PlayerEitrMead { get { return player_eitr_mead; } set { if (player_eitr_mead != value) { Main.LogMessage(() => "Player eitr mead changed."); player_eitr_mead = value; recalculate = true; playerState.CheckState(value, "Using Eitr Mead"); } } } public float PlayerTimeSinceEatenWithGoodHP { get { return player_time_since_eaten_with_good_hp; } set { if (!Helper.Approximately(player_time_since_eaten_with_good_hp, value)) { Main.LogMessage(() => $"Player time since eaten with good HP set to {value}"); if (value == 0f || (value > 60f && player_time_since_eaten_with_good_hp <= 60f)) { recalculate = true; } player_time_since_eaten_with_good_hp = value; } } } public float PlayerTimeSinceFinalFoodDigested { get { return player_time_since_final_food_digested; } set { if (!Helper.Approximately(player_time_since_final_food_digested, value)) { Main.LogMessage(() => $"Player time since final food digested set to {value}."); player_time_since_final_food_digested = value; } } } public bool PlayerInSeasonExcludedBiome => (int)PlayerInBiome == 64 || (int)PlayerInBiome == 32 || (int)PlayerInBiome == 4; public Biome PlayerInBiome { get { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) return player_in_biome; } set { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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) //IL_0015: 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) if (player_in_biome != value) { Main.LogMessage(() => $"Change to biome. Player now in biome {value}."); player_in_biome = value; recalculate = true; } } } public bool PlayerInHarshBiome => new List { (Biome)32, (Biome)64 }.Contains(PlayerInBiome); public bool PlayerInExcludedEnvironment { get { return player_in_excluded_environment; } set { if (player_in_excluded_environment != value) { Main.LogMessage(() => "Change to excluded enviornment."); player_in_excluded_environment = value; recalculate = true; playerState.CheckState(value, "In Excluded Environment"); } } } public bool PlayerMoving { get { return player_moving; } set { if (player_moving != value) { Main.LogMessage(() => "Change to movement."); player_moving = value; playerState.CheckState(value, "Moving"); } } } public bool PlayerPoisonResistant { get { return player_poison_resistant; } set { if (player_poison_resistant != value) { Main.LogMessage(() => "Change to poison resistant."); player_poison_resistant = value; recalculate = true; playerState.CheckState(value, "Resistant vs Poison"); } } } public bool PlayerPoisonVeryResistant { get { return player_poison_very_resistant; } set { if (player_poison_very_resistant != value) { Main.LogMessage(() => "Change to poison very resistant."); player_poison_very_resistant = value; recalculate = true; playerState.CheckState(value, "Very Resistant vs Poison"); } } } public bool PlayerFireResistant { get { return player_fire_resistant; } set { if (player_fire_resistant != value) { Main.LogMessage(() => "Change to fire resistant."); player_fire_resistant = value; recalculate = true; playerState.CheckState(value, "Resistant vs Fire"); } } } public bool PlayerFireVeryResistant { get { return player_fire_very_resistant; } set { if (player_fire_very_resistant != value) { Main.LogMessage(() => "Change to fire very resistant."); player_fire_very_resistant = value; recalculate = true; playerState.CheckState(value, "Very Resistant vs Fire"); } } } public bool PlayerLightningResistant { get { return player_lightning_resistant; } set { if (player_lightning_resistant != value) { Main.LogMessage(() => "Change to lightning resistant."); player_lightning_resistant = value; recalculate = true; playerState.CheckState(value, "Resistant vs Lightning"); } } } public bool PlayerLightningVeryResistant { get { return player_lightning_very_resistant; } set { if (player_lightning_very_resistant != value) { Main.LogMessage(() => "Change to lightning very resistant."); player_lightning_very_resistant = value; recalculate = true; playerState.CheckState(value, "Very Resistant vs Lightning"); } } } public EnvManHelper.Season EnvironmentSeasonState { get { return environment_season_state; } set { if (environment_season_state != value) { Main.LogMessage(() => $"Change to season. Now in season {value}"); environment_season_state = value; recalculate = true; } } } public bool PlayerFrostResistant { get { return player_frost_resistant; } set { if (player_frost_resistant != value) { Main.LogMessage(() => "Change to frost resistant."); player_frost_resistant = value; recalculate = true; playerState.CheckState(value, "Resistant vs Frost"); } } } public bool PlayerFrostVeryResistant { get { return player_frost_very_resistant; } set { if (player_frost_very_resistant != value) { Main.LogMessage(() => "Change to frost very resistant."); player_frost_very_resistant = value; recalculate = true; playerState.CheckState(value, "Very Resistant vs Frost"); } } } public bool PlayerSitting { get { return player_sitting; } set { if (player_sitting != value) { Main.LogMessage(() => "Change to sitting."); player_sitting = value; recalculate = true; playerState.CheckState(value, "Sitting"); } } } public bool PlayerLayingInBed { get { return player_laying_in_bed; } set { if (player_laying_in_bed != value) { Main.LogMessage(() => "Change to laying in bed."); player_laying_in_bed = value; recalculate = true; playerState.CheckState(value, "Laying in a bed"); } } } public bool PlayerSleeping { get { return player_sleeping; } set { if (player_sleeping != value) { Main.LogMessage(() => "Change to sleeping."); player_sleeping = value; recalculate = true; playerState.CheckState(value, "Sleeping"); } } } public bool PlayerSheltered { get { return player_sheltered; } set { if (player_sheltered != value) { Main.LogMessage(() => "Change to sheltered."); player_sheltered = value; recalculate = true; playerState.CheckState(value, "In Shelter"); } } } public bool PlayerNearFire { get { return player_near_fire; } set { if (player_near_fire != value) { Main.LogMessage(() => "Change to near fire."); player_near_fire = value; recalculate = true; playerState.CheckState(value, "Near Fire"); } } } public bool PlayerResting { get { return player_resting; } set { if (player_resting != value) { Main.LogMessage(() => "Change to resting."); player_resting = value; recalculate = true; playerState.CheckState(value, "Resting"); } } } public bool PlayerRested { get { return player_rested; } set { if (player_rested != value) { Main.LogMessage(() => "Change to rested."); player_rested = value; recalculate = true; playerState.CheckState(value, "Rested"); } } } public bool PlayerWet { get { return player_wet; } set { if (player_wet != value) { Main.LogMessage(() => "Change to player wet."); player_wet = value; recalculate = true; playerState.CheckState(value, "Wet"); } } } public bool PlayerCold { get { return player_cold; } set { if (player_cold != value) { Main.LogMessage(() => "Change to player cold."); player_cold = value; recalculate = true; playerState.CheckState(value, "Cold"); } } } public bool PlayerFreezing { get { return player_freezing; } set { if (player_freezing != value) { Main.LogMessage(() => "Change to player freezing."); player_freezing = value; recalculate = true; playerState.CheckState(value, "Freezing"); } } } public bool PlayerHot { get { return player_hot; } set { if (player_hot != value) { Main.LogMessage(() => "Change to player hot."); player_hot = value; recalculate = true; playerState.CheckState(value, "Hot"); } } } public bool PlayerScorching { get { return player_scorching; } set { if (player_scorching != value) { Main.LogMessage(() => "Change to player scorching."); player_scorching = value; recalculate = true; playerState.CheckState(value, "Scorching"); } } } public bool PlayerHungry { get { return player_hungry; } set { if (player_hungry != value) { Main.LogMessage(() => "Change to player hungry."); player_hungry = value; recalculate = true; playerState.CheckState(value, "Hungry"); } } } public bool PlayerPoisoned { get { return player_poisoned; } set { if (player_poisoned != value) { Main.LogMessage(() => "Change to player poisoned."); player_poisoned = value; recalculate = true; playerState.CheckState(value, "Poisoned"); } } } public bool PlayerBurning { get { return player_burning; } set { if (player_burning != value) { Main.LogMessage(() => "Change to player burning."); player_burning = value; recalculate = true; playerState.CheckState(value, "Burning"); } } } public bool PlayerShocked { get { return player_shocked; } set { if (player_shocked != value) { Main.LogMessage(() => "Change to player shocked."); player_shocked = value; recalculate = true; playerState.CheckState(value, "Shocked"); } } } public bool PlayerFrozen { get { return player_frozen; } set { if (player_frozen != value) { Main.LogMessage(() => "Change to player frozen."); player_frozen = value; recalculate = true; playerState.CheckState(value, "Frozen"); } } } public bool PlayerBloodProtected { get { return player_blood_protected; } set { if (player_blood_protected != value) { Main.LogMessage(() => "Change to player blood protected."); player_blood_protected = value; recalculate = true; playerState.CheckState(value, "Blood Protected"); } } } public bool PlayerHasBadElementalStatus => PlayerPoisoned || PlayerBurning || PlayerShocked || PlayerFrozen; public bool PlayerHasBadEnvironmentalStatus => PlayerWet || PlayerCold || PlayerFreezing || PlayerInHarshBiome; public PlayerFoodCache PlayerFoodCache { get { if (player_food_cache == null) { RefreshFoodCacheRefereces(); } return player_food_cache; } } public SE_Stats_Modifiers StatsModifiers { get { if (se_stats_modifiers == null) { se_stats_modifiers = new SE_Stats_Modifiers(this); } return se_stats_modifiers; } } public bool EnvironmentWet { get { return environment_wet; } set { if (environment_wet != value) { Main.LogMessage(() => "Change to environment wet."); environment_wet = value; recalculate = true; environmentState.CheckState(value, "Wet"); } } } public bool EnvironmentCold { get { return environment_cold; } set { if (environment_cold != value) { Main.LogMessage(() => "Change to environment cold."); environment_cold = value; recalculate = true; environmentState.CheckState(value, "Cold"); } } } public bool EnvironmentFreezing { get { return environment_freezing; } set { if (environment_freezing != value) { Main.LogMessage(() => "Change to enviornment freezing."); environment_freezing = value; recalculate = true; environmentState.CheckState(value, "Freezing"); } } } public bool EnvironmentHot { get { return environment_hot; } set { if (environment_hot != value) { Main.LogMessage(() => "Change to enviornment hot."); environment_hot = value; recalculate = true; environmentState.CheckState(value, "Hot"); } } } public bool EnvironmentScorching { get { return environment_scorching; } set { if (environment_scorching != value) { Main.LogMessage(() => "Change to enviornment scorching."); environment_scorching = value; recalculate = true; environmentState.CheckState(value, "Scorching"); } } } public float EnvironmentWindIntensity { get { return environment_wind_intensity; } set { if (!Helper.Approximately(environment_wind_intensity, value)) { Main.LogMessage(() => "Change to enviornment wind intensity."); environment_wind_intensity = value; recalculate = true; } } } public float ResistanceSkillLevel { get { return resistance_skill_level; } set { if (!Helper.IntEqual(resistance_skill_level, value)) { Main.LogMessage(() => $"Change to resistance skill level: {value}"); resistance_skill_level = value; CalculateResistanceExtraAttackMultiplier(); CalculateResistanceExtraMeadDurationMultiplier(); RecalculateStatusEffectModifiers(); recalculate = true; } } } public float ResistanceSkillFactor { get { return resistance_skill_factor; } set { if (!Helper.Approximately(resistance_skill_factor, value)) { Main.LogMessage(() => $"Change to resistance skill factor: {value}"); resistance_skill_factor = value; } } } public float FitnessSkillLevel { get { return fitness_skill_level; } set { if (!Helper.IntEqual(fitness_skill_level, value)) { Main.LogMessage(() => $"Change to fitness skill level: {value}"); fitness_skill_level = value; CalculateFitnessFoodBurnMultiplier(); CalculateFitnessSpeedPenaltyReduction(); recalculate = true; } } } public float FitnessSkillFactor { get { return fitness_skill_factor; } set { if (!Helper.Approximately(fitness_skill_factor, value)) { Main.LogMessage(() => $"Change to fitness skill factor: {value}"); fitness_skill_factor = value; } } } public float PerseverenceSkillLevel { get { return perseverence_skill_level; } set { if (!Helper.IntEqual(perseverence_skill_level, value)) { Main.LogMessage(() => $"Change to perseverence skill level: {value}"); perseverence_skill_level = value; CalculatePerseverenceComfortBonus(); CalculatePerseverenceMaxAdrenalineMultiplier(); recalculate = true; } } } public float PerseverenceSkillFactor { get { return perseverence_skill_factor; } set { if (!Helper.Approximately(perseverence_skill_factor, value)) { Main.LogMessage(() => $"Change to perseverence skill factor: {value}"); perseverence_skill_factor = value; } } } public float VitalityPercentage { get { if ((Object)(object)vitality == (Object)null) { return 100f; } return 100f - vitality.m_statLossPerc; } } public float EnergyPercentage { get { if ((Object)(object)energy == (Object)null) { return 100f; } return 100f - energy.m_statLossPerc; } } public float VitalityMaxPercentage { get { return vitality_max_percentage; } set { vitality_max_percentage = Mathf.Clamp(value, 0f, 100f); } } public float EnergyMaxPercentage { get { return energy_max_percentage; } set { energy_max_percentage = Mathf.Clamp(value, 0f, 100f); } } public float ResistanceExtraAttackMultiplier => resistance_extra_attack_multiplier; public float ResistanceExtraMeadDurationMultiplier => resistance_extra_mead_duration_multiplier; public float FitnessFoodBurnMultiplier => fitness_food_burn_multiplier; public float FitnessSpeedPenaltyReduction => fitness_speed_penalty_reduction; public int PerseverenceComfortBonus => perseverence_comfort_bonus; public float PerseverenceMaxAdrenalineMultiplier => perseverence_max_adrenaline_multiplier; protected virtual string DataKey => "EnvironmentalAwareness_" + Main.PlayerStatsSEName; public override void Setup(Character character) { ((StatusEffect)this).Setup(character); base.m_ttl = 1f; base.m_name = "$ea_se_playerstats"; if (!base.m_character.IsPlayer()) { base.m_time = base.m_ttl; return; } ref Player reference = ref player; Character character2 = base.m_character; reference = (Player)(object)((character2 is Player) ? character2 : null); if ((Object)(object)player == (Object)null) { base.m_time = base.m_ttl + 1f; Main.LogMessage(() => "Survival stats not applied to player. Removing."); } else { CheckBaseStats(); player_food_cache = new PlayerFoodCache(player); se_stats_modifiers = new SE_Stats_Modifiers(this); LoadData(); HandleStatusEffectSetup(); } } public void HandleStatusEffectSetup() { if (ConfigManager.VitalityEnabled.Value) { HandleSurvivalSE = (HandleSurvivalSEs)Delegate.Combine(HandleSurvivalSE, new HandleSurvivalSEs(HandleVitality)); } else { FlashStatusEffect(SE_Vitality.Hash); } if (ConfigManager.EnergyEnabled.Value) { HandleSurvivalSE = (HandleSurvivalSEs)Delegate.Combine(HandleSurvivalSE, new HandleSurvivalSEs(HandleEnergy)); } else { FlashStatusEffect(SE_Energy.Hash); } if (ConfigManager.CapabilityEnabled.Value) { HandleSurvivalSE = (HandleSurvivalSEs)Delegate.Combine(HandleSurvivalSE, new HandleSurvivalSEs(HandleCapability)); } else { FlashStatusEffect(SE_Capability.Hash); } } public void CleanupAndRemoveSurvivalEffects() { SaveAndRemoveStatusEffect(SE_Vitality.Hash); SaveAndRemoveStatusEffect(SE_Energy.Hash); SaveAndRemoveStatusEffect(SE_Capability.Hash); SaveData(); base.m_time = base.m_ttl + 1f; } public override void UpdateStatusEffect(float dt) { ((StatusEffect)this).UpdateStatusEffect(dt); base.m_time = 0f; lastUpdateTime += dt; lastLogTime += dt; if (lastUpdateTime > 1f) { CheckPlayerAndEnvironmentalState(); UpdateFoodCache(); ApplyStatusModifiers(); HandleSurvivalSE?.Invoke(); AfterRecalculate(); lastUpdateTime -= 1f; } if (lastLogTime > ConfigManager.DebugUpdateTime.Value) { LogStats(); lastLogTime -= ConfigManager.DebugUpdateTime.Value; } } public virtual void LoadData() { Main.LogMessage(() => "Loading data for Player Stats"); PlayerFoodCache.LoadData(); if ((Object)(object)player == (Object)null) { Main.LogMessage(() => "No player found. Cannot load data."); return; } if (!player.m_customData.TryGetValue(DataKey, out var data)) { Main.LogMessage(() => "No save data found for the player profile."); return; } if (string.IsNullOrEmpty(data)) { Main.LogMessage(() => "No save data found in entry " + DataKey); return; } Main.LogMessage(() => "Loaded data: " + data); try { string[] array = data.Split(new char[1] { ',' }); array[0].AssignAsFloat(out player_time_since_eaten_with_good_hp); array[1].AssignAsFloat(out player_time_since_final_food_digested); player.m_customData.Remove(DataKey); } catch (Exception ex) { Exception ex2 = ex; Exception e = ex2; Main.LogMessage(() => "Could not parse data for " + DataKey + ". Cancelling load.\n" + e.Message); } finally { } } public virtual void SaveData() { Main.LogMessage(() => "Saving data for Player Stats."); if ((Object)(object)player == (Object)null) { Main.LogMessage(() => "Player not found. Cancelling save."); return; } PlayerFoodCache.SaveData(); if (player.m_customData.TryGetValue(DataKey, out var _)) { Main.LogMessage(() => "Previous save data found. Replacing..."); player.m_customData.Remove(DataKey); } List list = new List { player_time_since_eaten_with_good_hp.ToString(), player_time_since_final_food_digested.ToString() }; string data = string.Join(",", list.ToArray()); player.m_customData.Add(DataKey, data); Main.LogMessage(() => "Saved data: " + data); } public virtual void UpdateFoodCache() { RefreshFoodCacheRefereces(); PlayerFoodCache.RemoveDigestedFoods(); } public virtual void RefreshFoodCacheRefereces() { if (!((Object)(object)PlayerFoodCache.player != (Object)null) && !((Object)(object)player == (Object)null)) { Main.LogMessage(() => "Player reference not found in food cache. Resetting."); player_food_cache = new PlayerFoodCache(player); PlayerFoodCache.LoadData(); } } [NullableContext(0)] public void SaveAndRemoveStatusEffect(int hash) where T : SE_SurvivalBase { if (!((Character)player).m_seman.HaveStatusEffect(hash)) { Main.LogMessage(() => $"Player does not have {typeof(T)} for save."); return; } T val = ((Character)player).m_seman.GetStatusEffect(hash) as T; if ((Object)(object)val == (Object)null) { Main.LogMessage(() => $"Cannot find status effect of type {typeof(T)}"); } else { val.SaveData(); ((StatusEffect)val).m_time = ((StatusEffect)val).m_ttl + 1f; } } [NullableContext(0)] public void FlashStatusEffect(int hash) where T : SE_SurvivalBase { if (!((Character)player).m_seman.HaveStatusEffect(hash)) { ((Character)player).m_seman.AddStatusEffect(hash, false, 0, 0f); Main.LogMessage(() => $"Added {typeof(T)} for flash"); } T val = ((Character)player).m_seman.GetStatusEffect(hash) as T; if ((Object)(object)val == (Object)null) { Main.LogMessage(() => $"Cannot find status effect of type {typeof(T)}"); return; } val.ClearSaveData(); val.SetupBaseFields(); val.Recalculate(); ((StatusEffect)val).m_time = ((StatusEffect)val).m_ttl + 1f; } public void HandleVitality() { if (!((Character)player).m_seman.HaveStatusEffect(SE_Vitality.Hash)) { ((Character)player).m_seman.AddStatusEffect(SE_Vitality.Hash, false, 0, 0f); Main.LogMessage(() => "Vitality status effect initialized"); } vitality = ((Character)player).m_seman.GetStatusEffect(SE_Vitality.Hash) as SE_Vitality; if (ShouldRecalculate()) { vitality?.Recalculate(); } } public void HandleEnergy() { if (!((Character)player).m_seman.HaveStatusEffect(SE_Energy.Hash)) { ((Character)player).m_seman.AddStatusEffect(SE_Energy.Hash, false, 0, 0f); Main.LogMessage(() => "Energy status effect initialized"); } SEMan seman = ((Character)player).m_seman; energy = ((seman != null) ? seman.GetStatusEffect(SE_Energy.Hash) : null) as SE_Energy; if (ShouldRecalculate()) { energy?.Recalculate(); } } public void HandleCapability() { if (!((Character)player).m_seman.HaveStatusEffect(SE_Capability.Hash)) { ((Character)player).m_seman.AddStatusEffect(SE_Capability.Hash, false, 0, 0f); Main.LogMessage(() => "Capability status effect initialized"); } SEMan seman = ((Character)player).m_seman; capability = ((seman != null) ? seman.GetStatusEffect(SE_Capability.Hash) : null) as SE_Capability; if (ShouldRecalculate()) { capability?.Recalculate(); } } public void CheckBaseStats() { player_base_health = player.m_baseHP; player_base_stamina = player.m_baseStamina; player_base_stamina_regen_delay = player.m_staminaRegenDelay; } public void CheckPlayerAndEnvironmentalState() { //IL_0008: 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_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_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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0140: 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) DamageModifiers damageModifiers = ((Character)player).GetDamageModifiers((WeakSpot)null); DamageModifier modifier = ((DamageModifiers)(ref damageModifiers)).GetModifier((DamageType)256); DamageModifier modifier2 = ((DamageModifiers)(ref damageModifiers)).GetModifier((DamageType)32); DamageModifier modifier3 = ((DamageModifiers)(ref damageModifiers)).GetModifier((DamageType)128); DamageModifier modifier4 = ((DamageModifiers)(ref damageModifiers)).GetModifier((DamageType)64); PlayerInBiome = GetCurrentBiome(); PlayerCarryWeightPerc = GetCarryWeightPerc(); PlayerInExcludedEnvironment = CheckExcludedEnvironment(); PlayerBodyArmor = ((Character)player).GetBodyArmor(); PlayerHealthPercentage = ((Character)player).GetHealthPercentage(); PlayerHealingMead = HasStatusCategory("healthpotion"); PlayerStaminaMead = HasStatusCategory("staminapotion"); PlayerEitrMead = HasStatusCategory("eitrpotion"); PlayerTimeSinceEatenWithGoodHP = TickTimeSinceFoodEaten(); PlayerTimeSinceFinalFoodDigested = TickTimeSinceFinalFoodDigested(); PlayerPoisonResistant = GetResistance(modifier) == 1; PlayerPoisonVeryResistant = GetResistance(modifier) == 2; PlayerFireResistant = GetResistance(modifier2) == 1; PlayerFireVeryResistant = GetResistance(modifier2) == 2; PlayerLightningResistant = GetResistance(modifier3) == 1; PlayerLightningVeryResistant = GetResistance(modifier3) == 2; PlayerFrostResistant = GetResistance(modifier4) == 1; PlayerFrostVeryResistant = GetResistance(modifier4) == 2; PlayerMoving = PlayerIsMoving(); PlayerSitting = PlayerIsSitting(); PlayerLayingInBed = PlayerIsLayingInBed(); PlayerSleeping = PlayerIsSleeping(); PlayerSheltered = PlayerIsSheltered(); PlayerHungry = PlayerIsHungry(); PlayerNoSkillDrain = HasStatusEffect(SEMan.s_statusEffectSoftDeath) && ConfigManager.DeathGrantsImmunity.Value; PlayerNearFire = HasStatusEffect(SEMan.s_statusEffectCampFire); PlayerResting = HasStatusEffect(SEMan.s_statusEffectResting); PlayerRested = HasStatusEffect(SEMan.s_statusEffectRested); PlayerCold = HasStatusEffect(SEMan.s_statusEffectCold); PlayerFreezing = HasStatusEffect(SEMan.s_statusEffectFreezing); PlayerHot = HasStatusEffect(SE_Hot.Hash); PlayerScorching = HasStatusEffect(SE_Scorching.Hash); PlayerWet = HasStatusEffect(SEMan.s_statusEffectWet); PlayerPoisoned = HasStatusEffect(SEMan.s_statusEffectPoison); PlayerBurning = HasStatusEffect(SEMan.s_statusEffectBurning); PlayerShocked = HasStatusEffect(SEMan.s_statusEffectLightning); PlayerFrozen = HasStatusEffect(SEMan.s_statusEffectFrost); PlayerBloodProtected = HasStatusEffect(StringExtensionMethods.GetStableHashCode("MagicBarrier")); EnvironmentWet = GetEnvironmentState("wet"); EnvironmentCold = GetEnvironmentState("cold"); EnvironmentFreezing = GetEnvironmentState("freezing"); EnvironmentHot = GetEnvironmentState("hot"); EnvironmentScorching = GetEnvironmentState("scorching"); EnvironmentWindIntensity = GetEnvironmentWindIntensity(); EnvironmentSeasonState = GetSeason(); ResistanceSkillLevel = GetSkillLevel(Main.ResistanceHash); ResistanceSkillFactor = GetSkillEffectFactor(Main.ResistanceSkillName); FitnessSkillLevel = GetSkillLevel(Main.FitnessHash); FitnessSkillFactor = GetSkillEffectFactor(Main.FitnessSkillName); PerseverenceSkillLevel = GetSkillLevel(Main.PerseverenceHash); PerseverenceSkillFactor = GetSkillEffectFactor(Main.PerseverenceSkillName); } private void RecalculateStatusEffectModifiers() { StatsModifiers?.RecalculateAllModifiers(); } private void ApplyStatusModifiers() { StatsModifiers?.ApplyModifiersToActiveEffects(); } private Biome GetCurrentBiome() { //IL_003e: 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_0052: 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_0063: 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) //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_007f: Unknown result type (might be due to invalid IL or missing references) Player obj = player; Vector3? obj2; if (obj == null) { obj2 = null; } else { GameObject gameObject = ((Component)obj).gameObject; if (gameObject == null) { obj2 = null; } else { Transform transform = gameObject.transform; obj2 = ((transform != null) ? new Vector3?(transform.position) : null); } } Vector3 val = (Vector3)(((??)obj2) ?? Vector3.zero); return (Biome)(((Vector3)(ref val)).Equals(Vector3.zero) ? 895 : ((int)Heightmap.FindBiome(val))); } private float GetCarryWeightPerc() { float valueOrDefault = (((Humanoid)(player?)).m_inventory?.m_totalWeight).GetValueOrDefault(); Player obj = player; float num = ((obj != null) ? obj.GetMaxCarryWeight() : 300f); return Mathf.Floor(100f * Mathf.Clamp(valueOrDefault / num, 0f, 1f)); } private bool CheckExcludedEnvironment() { EnvMan instance = EnvMan.instance; string item = ((instance == null) ? null : instance.GetCurrentEnvironment()?.m_name) ?? ""; return ConfigManager.VIgnoredEnvironments.Contains(item); } private int GetResistance(DamageModifier modifier) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)modifier != 1) { if ((int)modifier == 5) { return 2; } return 0; } return 1; } private bool HasStatusEffect(int status) { Player obj = player; bool? obj2; if (obj == null) { obj2 = null; } else { SEMan seman = ((Character)obj).m_seman; obj2 = ((seman != null) ? new bool?(seman.HaveStatusEffect(status)) : null); } bool? flag = obj2; return flag.GetValueOrDefault(); } private bool HasStatusCategory(string category) { Player obj = player; bool? obj2; if (obj == null) { obj2 = null; } else { SEMan seman = ((Character)obj).m_seman; obj2 = ((seman != null) ? new bool?(seman.HaveStatusEffectCategory(category)) : null); } bool? flag = obj2; return flag.GetValueOrDefault(); } private bool PlayerIsMoving() { //IL_002a: 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) Player obj = player; float? obj2; if (obj == null) { obj2 = null; } else { Rigidbody body = ((Character)obj).m_body; if (body == null) { obj2 = null; } else { Vector3 velocity = body.velocity; obj2 = ((Vector3)(ref velocity)).magnitude; } } float? num = obj2; float valueOrDefault = num.GetValueOrDefault(); return valueOrDefault > 0.01f; } private bool PlayerIsSitting() { Player obj = player; return obj != null && ((Character)obj).IsSitting(); } private bool PlayerIsLayingInBed() { Player obj = player; return obj != null && ((Character)obj).InBed(); } private bool PlayerIsSleeping() { Player obj = player; return obj != null && obj.IsSleeping(); } private bool PlayerIsSheltered() { Player obj = player; return obj != null && obj.InShelter(); } private bool PlayerIsHungry() { if (ConfigManager.HungerEnabled.Value) { return HasStatusEffect(SE_Hungry.Hash); } int valueOrDefault = (player?.m_foods?.Count).GetValueOrDefault(); return valueOrDefault == 0; } private float TickTimeSinceFoodEaten() { float num = player_time_since_eaten_with_good_hp; return num + 1f; } private float TickTimeSinceFinalFoodDigested() { int valueOrDefault = (player?.m_foods?.Count).GetValueOrDefault(); float num = player_time_since_final_food_digested; return num + ((valueOrDefault == 0) ? 1f : 0f); } private bool GetEnvironmentState(string state) { return state switch { "scorching" => EnvManHelper.IsScorching(), "hot" => EnvManHelper.IsHot(), "wet" => EnvMan.IsWet(), "cold" => EnvMan.IsCold(), "freezing" => EnvMan.IsFreezing(), _ => false, }; } private float GetEnvironmentWindIntensity() { EnvMan instance = EnvMan.instance; return (instance != null) ? instance.GetWindIntensity() : 0f; } private EnvManHelper.Season GetSeason() { return EnvManHelper.GetSeason(); } private float GetSkillLevel(int hash) { return ((Character)(object)player)?.GetSkillLevel(hash) ?? 0f; } private float GetSkillEffectFactor(string name) { return ((Character)(object)player)?.GetSkillFactor(name) ?? 0f; } private void CalculateResistanceExtraAttackMultiplier() { Main.LogMessage(() => "Calculating Extra Attack Multiplier from Resistance skill."); if (!ConfigManager.VitalityEnabled.Value) { resistance_extra_attack_multiplier = 1f; return; } float num = CalculateSkillThresholdFactor(ResistanceSkillLevel, ConfigManager.ResistanceSkillMissingHPDamageMultiplierStartLevel.Value); resistance_extra_attack_multiplier = 1f + num * (ConfigManager.ResistanceSkillMissingHPDamageMultiplier.Value - 1f); } private void CalculateResistanceExtraMeadDurationMultiplier() { Main.LogMessage(() => "Calculating Extra Mead Duration Multiplier from Resistance skill."); if (!ConfigManager.VitalityEnabled.Value) { resistance_extra_mead_duration_multiplier = 1f; return; } float num = CalculateSkillThresholdFactor(ResistanceSkillLevel, ConfigManager.ResistanceSkillElementalMeadMultiplierStartLevel.Value); resistance_extra_mead_duration_multiplier = 1f + num * (ConfigManager.ResistanceSkillElementalMeadMultiplier.Value - 1f); } private void CalculateFitnessFoodBurnMultiplier() { Main.LogMessage(() => "Calculating Food Burn Multiplier from Fitness skill."); if (!ConfigManager.EnergyEnabled.Value) { fitness_food_burn_multiplier = 1f; return; } float num = CalculateSkillThresholdFactor(FitnessSkillLevel, ConfigManager.FitnessSkillFoodBurnMultiplierStartLevel.Value); fitness_food_burn_multiplier = 1f + num * (ConfigManager.FitnessSkillFoodBurnMultiplier.Value - 1f); } private void CalculateFitnessSpeedPenaltyReduction() { Main.LogMessage(() => "Calculating Fitness Speed Penalty Reduction from Fitness skill."); if (!ConfigManager.EnergyEnabled.Value) { fitness_speed_penalty_reduction = 0f; return; } float num = CalculateSkillThresholdFactor(FitnessSkillLevel, ConfigManager.FitnessSkillSpeedPenaltyRemoveStartLevel.Value); fitness_speed_penalty_reduction = num * (ConfigManager.FitnessSkillSpeedPenaltyRemove.Value / 100f); } private void CalculatePerseverenceComfortBonus() { Main.LogMessage(() => "Calculating Comfort Bonus from Perseverence skill."); if (!ConfigManager.CapabilityEnabled.Value) { perseverence_comfort_bonus = 0; return; } float num = CalculateSkillThresholdFactor(PerseverenceSkillLevel, ConfigManager.PerseverenceSkillComfortBonusStartLevel.Value); perseverence_comfort_bonus = Mathf.CeilToInt(num * (float)ConfigManager.PerseverenceSkillComfortBonus.Value); } private void CalculatePerseverenceMaxAdrenalineMultiplier() { Main.LogMessage(() => "Calculating Max Adrenaline Multiplier from Perseverence skill."); if (!ConfigManager.CapabilityEnabled.Value) { perseverence_max_adrenaline_multiplier = 1f; return; } float num = CalculateSkillThresholdFactor(PerseverenceSkillLevel, ConfigManager.PerseverenceSkillMaxAdrenalineMultiplierStartLevel.Value); perseverence_max_adrenaline_multiplier = 1f - num * (1f - ConfigManager.PerseverenceSkillMaxAdrenalineMultiplier.Value); } public float CalculateSkillThresholdFactor(float level, int threshold) { return Mathf.Clamp((level - (float)threshold) / (100f - (float)threshold), 0f, 1f); } public bool ShouldRecalculate() { return recalculate; } public void AfterRecalculate() { recalculate = false; } public void LogStats() { Main.LogMessage(() => string.Join("\n", new List { "PLAYER STATUSES", $"Environment Stats for Player {player.GetPlayerID()}", "Player State: " + string.Join(", ", PlayerState), $"Resistance: {resistance_skill_level} : {resistance_skill_factor}", $"Fitness: {fitness_skill_level} : {fitness_skill_factor}", $"Perseverence: {perseverence_skill_level} : {perseverence_skill_factor}", "Environment State: " + string.Join(", ", EnvironmentState), $"Season: {EnvironmentSeasonState}" })); } } [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [NullableContext(1)] public class SE_Scorching : SE_Stats { public static readonly int Hash = StringExtensionMethods.GetStableHashCode(Main.ScorchingSEName); public override void Setup(Character character) { //IL_006e: 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_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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //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) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) ((StatusEffect)this).m_startMessage = "$ea_player_scorching_status"; ((SE_Stats)this).Setup(character); ((StatusEffect)this).m_name = "$ea_se_scorching"; ((StatusEffect)this).m_icon = Main.GetInstance().Bundle.LoadAsset("scorchingicon"); base.m_healthRegenMultiplier = 0.2f; base.m_staminaRegenMultiplier = 0.5f; base.m_eitrRegenMultiplier = 0.5f; base.m_speedModifier = -0.2f; base.m_mods = new List { new DamageModPair { m_type = (DamageType)1, m_modifier = (DamageModifier)8 }, new DamageModPair { m_type = (DamageType)2, m_modifier = (DamageModifier)8 }, new DamageModPair { m_type = (DamageType)4, m_modifier = (DamageModifier)8 } }; } public override string GetIconText() { return ""; } public override string GetTooltipString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("$ea_player_scorching_status \n"); stringBuilder.Append(((SE_Stats)this).GetTooltipString()); return stringBuilder.ToString(); } } public class SE_Stats_Extended : SE_Stats { public float m_attackEitrUseModifier; [NullableContext(1)] public override string GetTooltipString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(((SE_Stats)this).GetTooltipString()); if (m_attackEitrUseModifier != 0f) { stringBuilder.AppendFormat("$ea_se_attackeitr: {0}%\n", (m_attackEitrUseModifier * 100f).ToString("+0;-0")); } return stringBuilder.ToString(); } public virtual void ModifyAttackEitrUsage(float baseEitrUse, ref float eitrUse) { eitrUse += baseEitrUse * m_attackEitrUseModifier; } } [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [NullableContext(1)] public class SE_SurvivalBase : SE_Stats_Extended, ILoadSave { [NullableContext(0)] public class StatModifier { public enum CalculationType { REGULAR, NEGATIVE, INVERSE, PLUSONESHIFT, PERCENTAGE, INVERSEPERCENTAGE, ONEZERO } [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public SE_SurvivalBase m_statusEffect; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public WarningMessage m_warning; public CalculationType m_calculationType; public bool m_enabled = true; public float m_defaultValue = 0f; public float m_threshold = 0f; public float m_maxMultiplier = 1f; [NullableContext(1)] public StatModifier(SE_SurvivalBase m_statusEffect, [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] WarningMessage m_warning, CalculationType m_calculationType) { this.m_statusEffect = m_statusEffect; this.m_warning = m_warning; this.m_calculationType = m_calculationType; } public float CalculateMultiplier() { return CalculateMultiplier(m_statusEffect.m_statLossPerc); } public float CalculateMultiplier(float externalValue) { float defaultValue = m_defaultValue; if (!m_enabled) { return defaultValue; } if (externalValue < m_threshold) { m_statusEffect.SetWarningDisplay(m_warning); return defaultValue; } m_statusEffect.SendWarningMessage(m_warning); float num = m_statusEffect.CalculateThresholdMultiplierForStat(m_threshold); return m_calculationType switch { CalculationType.REGULAR => num * m_maxMultiplier, CalculationType.INVERSE => 1f - num * m_maxMultiplier, CalculationType.NEGATIVE => -1f * num * m_maxMultiplier, CalculationType.PLUSONESHIFT => 1f + num * (m_maxMultiplier - 1f), CalculationType.PERCENTAGE => Mathf.Clamp(num * m_maxMultiplier, 0f, 100f), CalculationType.INVERSEPERCENTAGE => Mathf.Clamp(100f - num * (100f - m_maxMultiplier), 0f, 100f), CalculationType.ONEZERO => Mathf.CeilToInt(num), _ => m_maxMultiplier, }; } } [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public class WarningMessage { public bool m_display = false; public string m_message = ""; public float m_lastMessageTime = 0f; public WarningMessage(string m_message) { this.m_message = m_message; } } public float m_statLoss = 0f; public float m_maxStatLoss = 100f; public float m_baseMaxStatLoss = 100f; public float m_statLossPerc = 0f; public float m_statChange = 0f; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(new byte[] { 2, 1 })] protected Sprite[] m_icons; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] protected Sprite m_iconNoSkillDrain; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] protected Sprite m_iconNewSpawn; protected float updateTimerState = 0f; protected float updateTimerStats = 0f; protected float updateTimerIcon = 0f; protected float updateTimerLogs = 0f; protected float countdownTimer = 300f; public readonly Dictionary m_weaknesses = new Dictionary { { "blunt", new DamageModPair { m_type = (DamageType)1, m_modifier = (DamageModifier)2 } }, { "slash", new DamageModPair { m_type = (DamageType)2, m_modifier = (DamageModifier)2 } }, { "pierce", new DamageModPair { m_type = (DamageType)4, m_modifier = (DamageModifier)2 } }, { "fire", new DamageModPair { m_type = (DamageType)32, m_modifier = (DamageModifier)2 } }, { "frost", new DamageModPair { m_type = (DamageType)64, m_modifier = (DamageModifier)2 } }, { "lightning", new DamageModPair { m_type = (DamageType)128, m_modifier = (DamageModifier)2 } }, { "poison", new DamageModPair { m_type = (DamageType)256, m_modifier = (DamageModifier)2 } } }; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] protected Player player; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] protected SE_PlayerStats pes; protected virtual string SENameKey => "$ea"; protected virtual string IconName => "icon"; protected virtual int IconCount => 0; protected virtual string DataKey => "EnvironmentalAwareness_"; protected virtual string TooltipKey => "$ea"; protected virtual bool DisplayPercentageEnabledConfigEntry => true; protected virtual bool DisplayWarningTextsConfigEntry => true; protected virtual string[] Statuses => new string[0]; public override void Setup(Character character) { ((SE_Stats)this).Setup(character); ((StatusEffect)this).m_name = SENameKey; LoadIcons(); ((StatusEffect)this).m_icon = m_icons[0]; SetupBaseFields(); SetupTimerFields(); SetupExtraFields(); ref Player reference = ref player; Character character2 = ((StatusEffect)this).m_character; reference = (Player)(object)((character2 is Player) ? character2 : null); if ((Object)(object)player == (Object)null) { Main.LogMessage(() => "Status effect was not applied to a player."); ((StatusEffect)this).m_time = ((StatusEffect)this).m_ttl + 1f; return; } if (player.IsMaterialKnown("$item_stone") || player.IsMaterialKnown("$item_wood")) { Main.LogMessage(() => "Player knows a material. Cooldown disabled for survival status."); countdownTimer = 0f; } pes = ((Character)player).m_seman.GetStatusEffect(SE_PlayerStats.Hash) as SE_PlayerStats; if ((Object)(object)pes == (Object)null) { Main.LogMessage(() => "Player Environment Stats was null. Removing status effect."); ((StatusEffect)this).m_time = ((StatusEffect)this).m_ttl + 1f; return; } SetupStatModifiers(); Main.LogMessage(() => "Status effect " + ((Object)this).name + " added to player."); LoadData(); Recalculate(); UpdateIcon(); } public override void Stop() { ((StatusEffect)this).Stop(); SetupBaseFields(); SetupTimerFields(); SetupExtraFields(); Main.LogMessage(() => "Status effect " + ((Object)this).name + " removed."); } protected virtual void LoadIcons() { Sprite[] array = (Sprite[])(object)new Sprite[IconCount]; for (int i = 0; i < IconCount; i++) { string text = IconName + (i + 1); array[i] = Main.GetInstance().Bundle.LoadAsset(text); } m_icons = array; m_iconNoSkillDrain = Main.GetInstance().Bundle.LoadAsset(IconName + "death"); m_iconNewSpawn = Main.GetInstance().Bundle.LoadAsset(IconName + "newplayer"); } public virtual void SetupBaseFields() { m_statLoss = 0f; m_statLossPerc = 0f; m_baseMaxStatLoss = 100f; m_maxStatLoss = 100f; } public virtual void SetupTimerFields() { ((StatusEffect)this).m_ttl = 1f; updateTimerState = 0f; updateTimerStats = 0f; updateTimerIcon = 0f; updateTimerLogs = 0f; countdownTimer = ConfigManager.NewPlayerCooldown.Value; } protected virtual void SetupExtraFields() { } protected virtual void SetupStatModifiers() { } public virtual void LoadData() { Main.LogMessage(() => "Loading data for " + ((Object)this).name); if ((Object)(object)player == (Object)null) { Main.LogMessage(() => "No player found. Cannot load data."); return; } if (!player.m_customData.TryGetValue(DataKey, out var data)) { Main.LogMessage(() => "No save data found for the player profile."); return; } if (string.IsNullOrEmpty(data)) { Main.LogMessage(() => "No save data found in entry " + DataKey); return; } Main.LogMessage(() => "Loaded data: " + data); List list = data.Split(new char[1] { ':' }).ToList(); try { list[0].AssignAsFloat(out countdownTimer); list[1].AssignAsFloat(out m_statLoss); list[2].AssignAsFloat(out m_maxStatLoss); list[3].AssignAsFloat(out m_statLossPerc); LoadExtraFields(list); } catch (Exception ex) { Exception ex2 = ex; Exception e = ex2; Main.LogMessage(() => "Could not parse data for " + DataKey + ". Cancelling load.\n" + e.Message); } finally { player.m_customData.Remove(DataKey); Main.LogMessage(() => "Loaded. Removed data key " + DataKey + " from player data."); } } public virtual void ClearSaveData() { Main.LogMessage(() => "Clearing existing save data for " + ((Object)this).name); if ((Object)(object)player == (Object)null) { Main.LogMessage(() => "No player found. Cannot load data."); return; } if (!player.m_customData.TryGetValue(DataKey, out var _)) { Main.LogMessage(() => "No save data found for the player profile - no need to clear."); return; } player.m_customData.Remove(DataKey); Main.LogMessage(() => "Cleared save data key " + DataKey + " from player data."); } protected virtual void LoadExtraFields(List list) { } public virtual void SaveData() { if (!ConfigManager.SavingEnabled.Value) { Main.LogMessage(() => "Saving is not enabled. Skipping save data."); return; } Main.LogMessage(() => "Saving data for " + ((Object)this).name); if ((Object)(object)player == (Object)null) { Main.LogMessage(() => "No player found. Cannot save data."); return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendStat(countdownTimer); stringBuilder.AppendStat(m_statLoss); stringBuilder.AppendStat(m_maxStatLoss); stringBuilder.AppendStat(m_statLossPerc); SaveExtraFields(stringBuilder); string data = stringBuilder.ToString().TrimEnd(new char[1] { ',' }); if (player.m_customData.TryGetValue(DataKey, out var _)) { Main.LogMessage(() => "Previous save data found. Replacing..."); player.m_customData.Remove(DataKey); } player.m_customData.Insert(DataKey, data); Main.LogMessage(() => "Saved data: " + data); } protected virtual void SaveExtraFields(StringBuilder sb) { } public override string GetTooltipString() { StringBuilder stringBuilder = new StringBuilder(); if (pes.PlayerNoSkillDrain) { stringBuilder.AppendFormat("{0}_immune \n", TooltipKey); return stringBuilder.ToString(); } if (countdownTimer > 0f) { stringBuilder.AppendFormat("{0}_cooldown: {1}s. \n", TooltipKey, Mathf.Ceil(countdownTimer)); return stringBuilder.ToString(); } stringBuilder.Append(GetStatusString()); GetPlayerHintStrings(stringBuilder); if (m_statChange > 0f) { GetStatLossHintStrings(stringBuilder); } else if (m_statChange < 0f && m_statLoss > 0.5f) { GetStatGainHintStrings(stringBuilder); } stringBuilder.Append(base.GetTooltipString()); GetStatChangeStrings(stringBuilder); if (ConfigManager.ShowDebugValueInSE.Value) { stringBuilder.Append("Debug info \n"); stringBuilder.Append(((object)this).ToString()); } return stringBuilder.ToString(); } protected virtual void GetPlayerHintStrings(StringBuilder sb) { } protected virtual void GetStatLossHintStrings(StringBuilder sb) { } protected virtual void GetStatGainHintStrings(StringBuilder sb) { } protected virtual void GetStatChangeStrings(StringBuilder sb) { } protected virtual string GetStatusString() { if (Statuses == null || Statuses.Length == 0) { return ""; } int num = Mathf.Clamp(Mathf.FloorToInt(m_statLoss / m_maxStatLoss * (float)Statuses.Length), 0, Statuses.Length - 1); return Statuses[num] + "\n"; } public override string GetIconText() { if (pes.PlayerNoSkillDrain) { return ""; } if (countdownTimer > 0f) { return StatusEffect.GetTimeString(countdownTimer, false, false); } if (!DisplayPercentageEnabledConfigEntry) { return ""; } int num = 100 - Mathf.FloorToInt(m_statLossPerc); return $"{num}%"; } public override void UpdateStatusEffect(float dt) { if (((StatusEffect)this).m_time > ((StatusEffect)this).m_ttl) { return; } if ((Object)(object)pes == (Object)null) { Main.LogMessage(() => "Could not find player environment stats. Removing status effect."); ((StatusEffect)this).m_time = ((StatusEffect)this).m_ttl + 1f; return; } ((SE_Stats)this).UpdateStatusEffect(dt); ((StatusEffect)this).m_time = 0f; m_statLossPerc = CalculateStatLossPercentage(); if (countdownTimer <= 0f && !pes.PlayerNoSkillDrain) { UpdateRealtimeExternalStatChanges(dt); updateTimerState += dt; updateTimerStats += dt; } updateTimerIcon += dt; updateTimerLogs += dt; if (!((Object)(object)player == (Object)null)) { if (updateTimerState >= 1f && countdownTimer <= 0f && !pes.PlayerNoSkillDrain) { UpdatePerSecondStateChanges(); UpdateStatValue(); updateTimerState -= 1f; } if (updateTimerStats >= 5f && countdownTimer <= 0f && !pes.PlayerNoSkillDrain) { UpdateEffects(); UpdateTutorial(); updateTimerStats -= 5f; } if (updateTimerLogs >= ConfigManager.DebugUpdateTime.Value) { LogStatistics(); ResetCycleStats(); updateTimerLogs -= ConfigManager.DebugUpdateTime.Value; } if (countdownTimer > 0f) { countdownTimer -= dt; } else { countdownTimer = 0f; } if (updateTimerIcon > 1f) { UpdateIcon(); updateTimerIcon -= 1f; } } } protected virtual void UpdatePerSecondStateChanges() { } protected virtual void UpdateRealtimeExternalStatChanges(float dt) { } protected virtual void UpdateStatValue() { } protected virtual void UpdateEffects() { } protected virtual void UpdateTutorial() { } public virtual void Recalculate() { Main.LogMessage(() => "Recalculating stats for " + ((Object)this).name + " SE."); m_maxStatLoss = m_baseMaxStatLoss + CalculateAdditionalMaxStat(); } protected virtual float CalculateAdditionalMaxStat() { return 0f; } protected virtual float CalculateStatLossPercentage() { return 100f * (m_statLoss / m_maxStatLoss); } protected virtual void ChangeStatLossByPercentage(float percentageChange) { float num = Mathf.Clamp(m_statLossPerc + percentageChange, 0f, 100f); m_statLoss = num / 100f * m_maxStatLoss; m_statLossPerc = num; } protected virtual float CalculateThresholdMultiplierForStat(float threshold) { return Mathf.Clamp((m_statLoss - threshold) / (m_maxStatLoss - threshold), 0f, 1f); } protected virtual void LogStatistics() { } protected virtual void ResetCycleStats() { } [NullableContext(2)] public virtual void SendWarningMessage(WarningMessage warning) { if (warning != null && warning.m_display && Time.time - warning.m_lastMessageTime > 5f) { SendPlayerMessage(warning.m_message); warning.m_display = false; warning.m_lastMessageTime = Time.time; } } [NullableContext(2)] public virtual void SetWarningDisplay(WarningMessage warning) { if (warning != null) { warning.m_display = true; } } public void SendPlayerMessage(string text) { if (DisplayWarningTextsConfigEntry) { ((StatusEffect)this).m_character.Message((MessageType)2, Localization.instance.Localize(text), 0, (Sprite)null); } } protected void UpdateIcon() { if (pes.PlayerNoSkillDrain) { ((StatusEffect)this).m_icon = m_iconNoSkillDrain; return; } if (countdownTimer > 0f) { ((StatusEffect)this).m_icon = m_iconNewSpawn; return; } int num = Mathf.RoundToInt((float)m_icons.Length * (m_statLoss / m_maxStatLoss)); if (num > m_icons.Length - 1) { num = m_icons.Length - 1; } ((StatusEffect)this).m_icon = m_icons[num]; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendFormat("SENameKey: {0}\n", SENameKey); stringBuilder.AppendFormat("DataKey: {0}\n", DataKey); stringBuilder.AppendFormat("m_statLoss: {0}\n", m_statLoss); stringBuilder.AppendFormat("m_maxStatLoss: {0}\n", m_maxStatLoss); stringBuilder.AppendFormat("m_baseMaxStatLoss: {0}\n", m_baseMaxStatLoss); stringBuilder.AppendFormat("m_statLossPerc: {0}\n", m_statLossPerc); stringBuilder.AppendFormat("m_statChange: {0}\n", m_statChange); GetAdditionalDebugStrings(stringBuilder); return stringBuilder.ToString(); } public virtual void GetAdditionalDebugStrings(StringBuilder sb) { sb.Append("Extra Parameters\n"); } } [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public class SE_Vitality : SE_SurvivalBase { public float m_foodBurnMult = 1f; public float m_foodStatBurn = 1f; public float m_vulnerabilityFromDamage = 0f; public float m_vulnerabilitySkillResist = 0f; public float m_seasonMultiplier = 1f; public float m_armorReduction = 0f; public bool m_physicalWeaknessActive = false; public bool m_elementalWeaknessActive = false; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_healthPerTickModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_healthRegenModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_staminaMultModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_foodBurnModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_moveSpeedModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_physicalWeaknessModifier; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] public StatModifier c_elementalWeaknessModifier; public WarningMessage c_warningHealth = new WarningMessage("$ea_vitality_warningmessage_health"); public WarningMessage c_warningStamina = new WarningMessage("$ea_vitality_warningmessage_stamina"); public WarningMessage c_warningFood = new WarningMessage("$ea_vitality_warningmessage_foodburn"); public WarningMessage c_warningSpeed = new WarningMessage("$ea_vitality_warningmessage_movement"); public WarningMessage c_warningPhysical = new WarningMessage("$ea_vitality_warningmessage_physical"); public WarningMessage c_warningElemental = new WarningMessage("$ea_vitality_warningmessage_elemental"); public static readonly int Hash = StringExtensionMethods.GetStableHashCode(Main.VitalitySEName); protected override string SENameKey => "$ea_se_vitality"; protected override string IconName => "vitalityicon"; protected override int IconCount => 10; protected override string DataKey => "EnvironmentalAwareness_" + Main.VitalitySEName; protected override string TooltipKey => "$ea_player_vulnerability"; protected override bool DisplayPercentageEnabledConfigEntry => ConfigManager.DisplayVitalityPercentage.Value; protected override bool DisplayWarningTextsConfigEntry => ConfigManager.DisplayVitalityWarningTexts.Value; protected override string[] Statuses => new string[5] { "$ea_vulnerability_status_0", "$ea_vulnerability_status_1", "$ea_vulnerability_status_2", "$ea_vulnerability_status_3", "$ea_vulnerability_status_4" }; protected override void SetupStatModifiers() { c_healthPerTickModifier = new StatModifier(this, c_warningHealth, StatModifier.CalculationType.NEGATIVE) { m_enabled = ConfigManager.VHealthDamageEnabled.Value, m_maxMultiplier = ConfigManager.VHealthMaxDamageOverTime.Value, m_threshold = ConfigManager.VHealthDamageMinStartThreshold.Value, m_defaultValue = 0f }; c_healthRegenModifier = new StatModifier(this, null, StatModifier.CalculationType.INVERSE) { m_enabled = ConfigManager.VHealthDamageEnabled.Value, m_maxMultiplier = ConfigManager.VHealthMaxRegenReduction.Value, m_threshold = ConfigManager.VHealthDamageMinStartThreshold.Value, m_defaultValue = 1f }; c_staminaMultModifier = new StatModifier(this, c_warningStamina, StatModifier.CalculationType.INVERSE) { m_enabled = ConfigManager.VStaminaRegenReductionEnabled.Value, m_maxMultiplier = ConfigManager.VStaminaRegenMaxReduction.Value, m_threshold = ConfigManager.VStaminaRegenReductionThreshold.Value, m_defaultValue = 1f }; c_foodBurnModifier = new StatModifier(this, c_warningFood, StatModifier.CalculationType.PLUSONESHIFT) { m_enabled = ConfigManager.VFoodBurnRateEnabled.Value, m_maxMultiplier = ConfigManager.VFoodBurnMaxOverTime.Value, m_threshold = ConfigManager.VFoodBurnMinStartThreshold.Value, m_defaultValue = 1f }; c_moveSpeedModifier = new StatModifier(this, c_warningSpeed, StatModifier.CalculationType.NEGATIVE) { m_enabled = ConfigManager.VMoveSpeedReductionEnabled.Value, m_maxMultiplier = ConfigManager.VMoveSpeedMaxReduction.Value, m_threshold = ConfigManager.VMoveSpeedMinStartThreshold.Value, m_defaultValue = 0f }; c_physicalWeaknessModifier = new StatModifier(this, c_warningPhysical, StatModifier.CalculationType.ONEZERO) { m_enabled = ConfigManager.VPhysicalWeaknessEnabled.Value, m_maxMultiplier = 1f, m_threshold = ConfigManager.VPhysicalWeaknessThreshold.Value, m_defaultValue = 0f }; c_elementalWeaknessModifier = new StatModifier(this, c_warningElemental, StatModifier.CalculationType.ONEZERO) { m_enabled = ConfigManager.VElementalWeaknessEnabled.Value, m_maxMultiplier = 1f, m_threshold = ConfigManager.VElementalWeaknessThreshold.Value, m_defaultValue = 0f }; } protected override void SetupExtraFields() { ((SE_Stats)this).m_tickInterval = 5f; ((SE_Stats)this).m_healthPerTick = 0f; ((SE_Stats)this).m_healthRegenMultiplier = 1f; ((SE_Stats)this).m_staminaRegenMultiplier = 1f; m_foodBurnMult = 1f; ((SE_Stats)this).m_mods = new List(); m_vulnerabilityFromDamage = 0f; m_vulnerabilitySkillResist = 0f; m_seasonMultiplier = 1f; m_armorReduction = 0f; } protected override void LoadExtraFields(List list) { list[4].AssignAsFloat(out m_foodBurnMult); list[5].AssignAsFloat(out m_foodStatBurn); list[6].AssignAsFloat(out m_vulnerabilityFromDamage); list[7].AssignAsFloat(out m_vulnerabilitySkillResist); list[8].AssignAsFloat(out m_seasonMultiplier); list[9].AssignAsFloat(out m_armorReduction); list[10].AssignAsBool(out c_warningHealth.m_display); list[11].AssignAsBool(out c_warningStamina.m_display); list[12].AssignAsBool(out c_warningFood.m_display); list[13].AssignAsBool(out c_warningSpeed.m_display); list[14].AssignAsBool(out c_warningPhysical.m_display); list[15].AssignAsBool(out c_warningElemental.m_display); } protected override void SaveExtraFields(StringBuilder sb) { sb.AppendStat(m_foodBurnMult); sb.AppendStat(m_foodStatBurn); sb.AppendStat(m_vulnerabilityFromDamage); sb.AppendStat(m_vulnerabilitySkillResist); sb.AppendStat(m_seasonMultiplier); sb.AppendStat(m_armorReduction); sb.AppendStat(c_warningHealth.m_display); sb.AppendStat(c_warningStamina.m_display); sb.AppendStat(c_warningFood.m_display); sb.AppendStat(c_warningSpeed.m_display); sb.AppendStat(c_warningPhysical.m_display); sb.AppendStat(c_warningElemental.m_display); } protected override void GetPlayerHintStrings(StringBuilder sb) { if (pes.PlayerInExcludedEnvironment) { sb.Append("$ea_player_excluded_environment \n"); } if (pes.PlayerBloodProtected) { sb.Append("$ea_player_bloodprotected_vitality \n"); } if (pes.VitalityMaxPercentage <= 99f) { sb.AppendFormat("$ea_player_vitality_capped \n", Mathf.RoundToInt(pes.VitalityMaxPercentage)); } if (pes.PlayerHealingMead) { sb.Append("$ea_player_healing_mead \n"); } } protected override void GetStatLossHintStrings(StringBuilder sb) { if (pes.PlayerHungry) { sb.Append("$ea_player_hungry_vitality \n"); } if (!pes.PlayerBloodProtected && pes.PlayerTimeSinceEatenWithGoodHP > 60f && pes.PlayerHealthPercentage < 0.95f) { sb.Append("$ea_player_damaged_vitality \n"); } if (!pes.PlayerSheltered) { if (pes.EnvironmentCold || pes.EnvironmentFreezing) { sb.Append("$ea_player_coldfreezing_vitality \n"); } if (pes.EnvironmentHot || pes.EnvironmentScorching) { sb.Append("$ea_player_hotscorching_vitality \n"); } if (pes.PlayerInHarshBiome) { sb.Append("$ea_player_harshbiome_vitality \n"); } } if (pes.PlayerSheltered && !pes.PlayerNearFire && pes.EnvironmentFreezing) { sb.Append("$ea_player_too_cold_shelter_vitality \n"); } } protected override void GetStatGainHintStrings(StringBuilder sb) { sb.Append("$ea_player_recovering_vitality \n"); } protected override void GetStatChangeStrings(StringBuilder sb) { if (((SE_Stats)this).m_healthPerTick != 0f) { sb.AppendFormat("$se_health: {0} \n", Mathf.Floor(((SE_Stats)this).m_healthPerTick).ToString("+0;-0")); } if (m_foodBurnMult >= 1.01f) { sb.AppendFormat("$ea_se_foodburn: {0} \n", (Mathf.Round(m_foodBurnMult * 100f) / 100f).ToString()); } } protected override void UpdateTutorial() { if (m_statLossPerc > 10f) { player.ShowTutorial("EnvironmentalAwarenessVitality", false); } if (m_statLossPerc > 60f) { player.ShowTutorial("EnvironmentalAwarenessVitalityLow", false); } } public override void Recalculate() { base.Recalculate(); m_vulnerabilitySkillResist = CalculateResistanceFromSkill(); m_seasonMultiplier = CalculateSeasonMultiplier(); m_statChange = CalculateVulnerabilityChange(); } protected override void UpdateStatValue() { m_statLoss = Mathf.Clamp(m_statLoss + m_statChange + m_vulnerabilityFromDamage, 0f, m_maxStatLoss); m_statLoss = Mathf.Max((100f - pes.VitalityMaxPercentage) * m_maxStatLoss / 100f, m_statLoss); m_vulnerabilityFromDamage = 0f; } private float CalculateVulnerabilityChange() { float num = CalculateArmorReduction() * CalculateResistanceFromStaffProtection() * (CalculateLossFromEnvironment() + CalculateLossFromMissingHP()) + CalculateHungerLoss(); float num2 = CalculateRecoveryFromWarmShelteredRestingPassive() + CalculateRecoveryFromHealthMead(); return m_vulnerabilitySkillResist * num - num2; } private float CalculateLossFromEnvironment() { float result = 0f; if (pes.PlayerInExcludedEnvironment) { return result; } float num = 0f; float num2 = 0f; float num3 = 0f; if (pes.EnvironmentCold && !pes.EnvironmentFreezing && !pes.PlayerNearFire) { num = ConfigManager.VColdAdd.Value; } if (pes.EnvironmentFreezing && (!pes.PlayerNearFire || !pes.PlayerSheltered)) { num2 = ConfigManager.VFreezingAdd.Value; } if (pes.PlayerWet) { num3 = ConfigManager.VWetAdd.Value; } result = num + num2 + num3; if (num > 0f && num3 > 0f) { result *= ConfigManager.VColdWetMultiplier.Value; } if (num2 > 0f && num3 > 0f) { result *= ConfigManager.VFreezingWetMultiplier.Value; } if (pes.PlayerFrostResistant && !pes.PlayerFrostVeryResistant) { result *= ConfigManager.VFrostResistantMultiplier.Value; } if (pes.PlayerFrostVeryResistant) { result *= ConfigManager.VFrostVeryResistantMultiplier.Value; } float num4 = 0f; float num5 = 0f; if (pes.EnvironmentHot && !pes.EnvironmentScorching && !pes.PlayerSheltered) { num4 = ConfigManager.VHotAdd.Value; } if (pes.EnvironmentScorching && !pes.PlayerSheltered) { num5 = ConfigManager.VScorchingAdd.Value; } float num6 = num4 + num5; if (pes.PlayerFireResistant && !pes.PlayerFireVeryResistant) { num6 *= ConfigManager.VFireResistantMultiplier.Value; } if (pes.PlayerFireVeryResistant) { num6 *= ConfigManager.VFireVeryResistantMultiplier.Value; } float num7 = 0f; num7 += CalculateStatusEffectLoss(pes.PlayerPoisoned, pes.PlayerPoisonVeryResistant, ConfigManager.VPoisonVeryResistantMultiplier.Value, pes.PlayerPoisonResistant, ConfigManager.VPoisonResistantMultiplier.Value, ConfigManager.VPoisonDamageAdd.Value); num7 += CalculateStatusEffectLoss(pes.PlayerBurning, pes.PlayerFireVeryResistant, ConfigManager.VFireVeryResistantMultiplier.Value, pes.PlayerFireResistant, ConfigManager.VFireResistantMultiplier.Value, ConfigManager.VBurningDamageAdd.Value); num7 += CalculateStatusEffectLoss(pes.PlayerShocked, pes.PlayerLightningVeryResistant, ConfigManager.VLightningVeryResistantMultiplier.Value, pes.PlayerLightningResistant, ConfigManager.VLightningResistantMultiplier.Value, ConfigManager.VShockDamageAdd.Value); num7 += CalculateStatusEffectLoss(pes.PlayerFrozen, pes.PlayerFrostVeryResistant, ConfigManager.VFrostVeryResistantMultiplier.Value, pes.PlayerFrostResistant, ConfigManager.VFrostResistantMultiplier.Value, ConfigManager.VFrostDamageAdd.Value); return m_seasonMultiplier * (result + num6 + CalculateBiomePassiveLoss()) + num7; } private float CalculateStatusEffectLoss(bool debuffType, bool vresistant, float vresistantmult, bool resistant, float resistantmult, float damage) { float result = 0f; if (debuffType && damage > 0f) { float num = 1f; if (vresistant) { num = vresistantmult; } else if (resistant) { num = resistantmult; } result = num * damage; } return result; } private float CalculateLossFromMissingHP() { if (pes.PlayerBloodProtected) { return 0f; } if (pes.PlayerTimeSinceEatenWithGoodHP < 60f) { return 0f; } float num = 1f - pes.PlayerHealthPercentage; if ((double)num < 0.01) { return 0f; } return num * ConfigManager.VMissingHPAdd.Value; } private float CalculateHungerLoss() { return pes.PlayerHungry ? ConfigManager.VHungerAdd.Value : 0f; } private float CalculateBiomePassiveLoss() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0018: Invalid comparison between Unknown and I4 //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 float num = 1f; Biome playerInBiome = pes.PlayerInBiome; Biome val = playerInBiome; if ((int)val != 32) { if ((int)val == 64) { if (pes.PlayerFrostVeryResistant) { num = ConfigManager.VFrostVeryResistantMultiplier.Value; } else if (pes.PlayerFrostResistant) { num = ConfigManager.VFrostResistantMultiplier.Value; } return num * ConfigManager.VDeepNorthPassiveAdd.Value; } return 0f; } if (pes.PlayerFireVeryResistant) { num = ConfigManager.VFireVeryResistantMultiplier.Value; } else if (pes.PlayerFireResistant) { num = ConfigManager.VFireResistantMultiplier.Value; } return num * ConfigManager.VAshlandsPassiveAdd.Value; } private float CalculateSeasonMultiplier() { if (pes.PlayerInSeasonExcludedBiome) { return m_seasonMultiplier = 1f; } return pes.EnvironmentSeasonState switch { EnvManHelper.Season.Spring => m_seasonMultiplier = ConfigManager.VSpringSeasonalMultiplier.Value, EnvManHelper.Season.Summer => m_seasonMultiplier = ConfigManager.VSummerSeasonalMultiplier.Value, EnvManHelper.Season.Fall => m_seasonMultiplier = ConfigManager.VFallSeasonalMultiplier.Value, EnvManHelper.Season.Winter => m_seasonMultiplier = ConfigManager.VWinterSeasonalMultiplier.Value, _ => m_seasonMultiplier = 1f, }; } private float CalculateResistanceFromStaffProtection() { return pes.PlayerBloodProtected ? ConfigManager.VResistanceStaffOfProtection.Value : 1f; } private float CalculateResistanceFromSkill() { return m_vulnerabilitySkillResist = 1f - pes.ResistanceSkillFactor; } private float CalculateRecoveryFromWarmShelteredRestingPassive() { float num = 0f; float num2 = 0f; if (pes.PlayerSheltered) { num = ConfigManager.VShelteredRemove.Value; if (pes.PlayerWet) { num *= 0.1f; } } if (pes.EnvironmentCold || pes.EnvironmentFreezing) { if (pes.PlayerNearFire && !pes.PlayerWet && !pes.PlayerHasBadElementalStatus && pes.PlayerSheltered) { num2 = ConfigManager.VHeatRemove.Value; } } else if (pes.PlayerNearFire && !pes.PlayerWet && !pes.PlayerHasBadElementalStatus) { num2 = ConfigManager.VHeatRemove.Value; } float num3 = num + num2; if (num2 > 0f && num > 0f) { num3 *= ConfigManager.VHeatShelteredMultiplier.Value; } if (pes.PlayerResting) { num3 += ConfigManager.VRestingRemove.Value; } if (pes.PlayerRested) { num3 += ConfigManager.VRestedRemove.Value; } if (!pes.PlayerHungry && !pes.PlayerHasBadEnvironmentalStatus && !pes.PlayerHasBadElementalStatus) { num3 += ConfigManager.VPassiveRemove.Value; } float num4 = 1f; if (pes.PlayerHungry) { num4 = 0.1f; } return num4 * num3; } private float CalculateRecoveryFromHealthMead() { return pes.PlayerHealingMead ? ConfigManager.VHealthPotionRemove.Value : 0f; } private float CalculateArmorReduction() { float num = Mathf.Max(pes.PlayerBodyArmor - (float)ConfigManager.VResistanceMinArmorThreshold.Value, 0f); return m_armorReduction = Mathf.Pow(ConfigManager.VResistancePerArmorPoint.Value, num); } protected override void UpdateEffects() { UpdateStatusEffectModifiers(); UpdatePhysicalWeakness(); UpdateElementalWeakness(); UpdateFoodStats(); RaiseResistanceSkill(); } private void UpdateStatusEffectModifiers() { ((SE_Stats)this).m_healthPerTick = c_healthPerTickModifier.CalculateMultiplier(); ((SE_Stats)this).m_healthRegenMultiplier = c_healthRegenModifier.CalculateMultiplier(); ((SE_Stats)this).m_staminaRegenMultiplier = c_staminaMultModifier.CalculateMultiplier(); ((SE_Stats)this).m_speedModifier = c_moveSpeedModifier.CalculateMultiplier(); m_foodBurnMult = c_foodBurnModifier.CalculateMultiplier(); m_foodStatBurn = Mathf.Sqrt(m_foodBurnMult); } private void UpdatePhysicalWeakness() { if (c_physicalWeaknessModifier.CalculateMultiplier() == 0f) { SetWarningDisplay(c_physicalWeaknessModifier.m_warning); if (m_physicalWeaknessActive) { RemovePhysicalWeaknesses(); m_physicalWeaknessActive = false; } } else if (!m_physicalWeaknessActive) { AddPhysicalWeaknesses(); m_physicalWeaknessActive = true; } } private void UpdateElementalWeakness() { if (c_elementalWeaknessModifier.CalculateMultiplier() == 0f) { SetWarningDisplay(c_elementalWeaknessModifier.m_warning); if (m_elementalWeaknessActive) { RemoveElementalWeaknesses(); m_elementalWeaknessActive = false; } } else if (!m_elementalWeaknessActive) { AddElementalWeaknesses(); m_elementalWeaknessActive = true; } } private void UpdateFoodStats() { PlayerFoodCache playerFoodCache = pes.PlayerFoodCache; foreach (Food food in player.m_foods) { if (!playerFoodCache.TryGetValue(food, out var foodData)) { continue; } float num = foodData.m_time / m_foodBurnMult; if (food.m_time > num) { food.m_time = num; } if (ConfigManager.VFoodBurnStatReduction.Value) { food.m_health = foodData.m_health / m_foodStatBurn; food.m_stamina = foodData.m_stamina / m_foodStatBurn; food.m_eitr = foodData.m_eitr / m_foodStatBurn; Main.LogMessage(() => string.Join("\n", new List { "FOOD STAT CHANGES", $"HP: {foodData.m_health} -> {Mathf.Round(food.m_health)}", $"Stamina: {foodData.m_stamina} -> {Mathf.Round(food.m_stamina)}", $"Eitr: {foodData.m_eitr} -> {Mathf.Round(food.m_eitr)}" })); } } } private void AddPhysicalWeaknesses() { //IL_0012: 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_004a: Unknown result type (might be due to invalid IL or missing references) ((SE_Stats)this).m_mods.Add(m_weaknesses["blunt"]); ((SE_Stats)this).m_mods.Add(m_weaknesses["slash"]); ((SE_Stats)this).m_mods.Add(m_weaknesses["pierce"]); } private void AddElementalWeaknesses() { //IL_0012: 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_004a: 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) ((SE_Stats)this).m_mods.Add(m_weaknesses["fire"]); ((SE_Stats)this).m_mods.Add(m_weaknesses["frost"]); ((SE_Stats)this).m_mods.Add(m_weaknesses["lightning"]); ((SE_Stats)this).m_mods.Add(m_weaknesses["poison"]); } private void RemovePhysicalWeaknesses() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0027: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 for (int num = ((SE_Stats)this).m_mods.Count - 1; num >= 0; num--) { DamageModPair val = ((SE_Stats)this).m_mods[num]; DamageType type = val.m_type; DamageType val2 = type; if (val2 - 1 <= 1 || (int)val2 == 4) { ((SE_Stats)this).m_mods.RemoveAt(num); } } } private void RemoveElementalWeaknesses() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0027: 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_002b: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Invalid comparison between Unknown and I4 for (int num = ((SE_Stats)this).m_mods.Count - 1; num >= 0; num--) { DamageModPair val = ((SE_Stats)this).m_mods[num]; DamageType type = val.m_type; DamageType val2 = type; if ((int)val2 <= 64) { if ((int)val2 != 32 && (int)val2 != 64) { continue; } } else if ((int)val2 != 128 && (int)val2 != 256) { continue; } ((SE_Stats)this).m_mods.RemoveAt(num); } } public void RaiseResistanceSkill() { float value = ConfigManager.ResistanceSkillGainMinThreshold.Value; if (!(m_statLoss <= value)) { float num = CalculateThresholdMultiplierForStat(value); ((Character)(object)player)?.RaiseSkill("Resistance", 0.1f * num * ConfigManager.ResistanceSkillGainFactor.Value); } } protected override void LogStatistics() { Main.LogMessage(() => string.Join("\n", new List { "VITALITY SE UPDATE", $"Vitality: {Mathf.Round(100f * (100f - m_statLoss)) / 100f}%", $"HP Per Tick: {Mathf.Round(100f * ((SE_Stats)this).m_healthPerTick) / 100f}HP/t", $"Stamina Regen Multiplier: {Mathf.Round(100f * ((SE_Stats)this).m_staminaRegenMultiplier) / 100f}x", $"Move Speed: {Mathf.Round(100f * ((SE_Stats)this).m_speedModifier) / 100f}", $"Food Burn Multiplier: {Mathf.Round(100f * m_foodBurnMult) / 100f}x", $"Food Stat Multiplier: {Mathf.Round(100f * m_foodStatBurn) / 100f}x" })); } public void ApplyVulnerabilityFromDamage(float damage) { if (!pes.PlayerNoSkillDrain && !(countdownTimer > 0f)) { m_vulnerabilityFromDamage += CalculateResistanceFromStaffProtection() * m_vulnerabilitySkillResist * m_armorReduction * ConfigManager.VHPDamageAdd.Value * damage; } } public override void GetAdditionalDebugStrings(StringBuilder sb) { base.GetAdditionalDebugStrings(sb); sb.AppendFormat("m_foodBurnMult: {0}\n", m_foodBurnMult); sb.AppendFormat("m_foodStatBurn: {0}\n", m_foodStatBurn); sb.AppendFormat("m_vulnerabilityFromDamage: {0}\n", m_vulnerabilityFromDamage); sb.AppendFormat("m_vulnerabilitySkillResist: {0}\n", m_vulnerabilitySkillResist); sb.AppendFormat("m_seasonMultiplier: {0}\n", m_seasonMultiplier); sb.AppendFormat("m_armorReduction: {0}\n", m_armorReduction); } } } namespace EnvironmentalAwareness.Patch { internal class Attack_ModifyDamage { [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [HarmonyPatch(typeof(Attack), "ModifyDamage")] [NullableContext(1)] public static class Attack_ModifyDamage_Patches { [HarmonyTranspiler] [HarmonyPriority(700)] public static IEnumerable ScaleAttackDamageFromResistanceSkillAndMissingHP(IEnumerable instructions, ILGenerator il) { //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown Main.LogMessage(() => "Applying Transpiler patch for Attack.ModifyDamage()..."); List list = new List(instructions); MethodInfo method = typeof(Attack_ModifyDamage_Patches).GetMethod("ModifyAttackValue", AccessTools.all); MethodInfo method2 = typeof(DamageTypes).GetMethod("Modify", AccessTools.all, null, new Type[1] { typeof(float) }, null); FieldInfo field = typeof(HitData).GetField("m_damage", AccessTools.all); LocalBuilder localBuilder = il.DeclareLocal(typeof(float)); int num = -1; for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode != OpCodes.Ret)) { num = i; break; } } if (num == -1) { return instructions; } num = 0; List collection = new List { new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Call, (object)method), new CodeInstruction(OpCodes.Stloc_S, (object)localBuilder), new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Ldflda, (object)field), new CodeInstruction(OpCodes.Ldloc_S, (object)localBuilder), new CodeInstruction(OpCodes.Call, (object)method2) }; list.InsertRange(num, collection); Main.LogMessage(() => "Patch done."); return list.AsEnumerable(); } public static float ModifyAttackValue(HitData hit) { Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if ((Object)(object)val == (Object)null) { Main.LogMessage(() => "Attack not done by a player."); return 1f; } SE_PlayerStats sE_PlayerStats = ((Character)val).m_seman.GetStatusEffect(SE_PlayerStats.Hash) as SE_PlayerStats; if ((Object)(object)sE_PlayerStats == (Object)null) { Main.LogMessage(() => "Player stats not found."); return 1f; } float resistanceExtraAttackMultiplier = sE_PlayerStats.ResistanceExtraAttackMultiplier; float num = 1f - ((Character)val).GetHealthPercentage(); float modifier = 1f + num * (resistanceExtraAttackMultiplier - 1f); Main.LogMessage(() => $"Player Damage Modifier for Attack: {modifier}x"); return modifier; } } } internal class Hud_Awake { [HarmonyPatch(typeof(Hud), "Awake")] public static class Hud_Awake_Patches { [HarmonyPriority(700)] [HarmonyPrefix] [NullableContext(1)] public static void CreateNewStatusEffectArea(Hud __instance) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //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) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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) GameObject val = new GameObject(Main.EAHud); val.transform.SetParent(__instance.m_rootObject.transform, false); RectTransform val2 = val.AddComponent(); ((Transform)val2).SetAsFirstSibling(); int value = ConfigManager.DisplayEAEffectHUDX.Value; int value2 = ConfigManager.DisplayEAEffectHUDY.Value; float num = ConfigManager.DisplayEAEffectHUDScale.Value / 100f; switch (ConfigManager.DisplayEAEffectsHUDIconLayout.Value) { case ConfigManager.HUDIconLayout.Horizontal: val2.anchorMin = new Vector2(1f, 0.1f); val2.anchorMax = new Vector2(1f, 0.1f); break; case ConfigManager.HUDIconLayout.Vertical: val2.anchorMin = new Vector2(1f, 0.4f); val2.anchorMax = new Vector2(1f, 0.4f); break; default: val2.anchorMin = new Vector2(1f, 0.1f); val2.anchorMax = new Vector2(1f, 0.1f); break; } val2.pivot = new Vector2(1f, 0f); ((Transform)val2).localScale = Vector2.op_Implicit(new Vector2(num, num)); float num2 = -value; Rect rect = val2.rect; float num3 = num2 - ((Rect)(ref rect)).width; rect = val2.rect; val2.anchoredPosition = new Vector2(num3, ((Rect)(ref rect)).height / 2f + (float)value2); val.SetActive(true); } } } internal class Hud_Update { [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [HarmonyPatch(typeof(Hud), "Update")] public static class Hud_Update_Patches { public static MethodInfo mUpdateEAHud = typeof(Hud_Update_Patches).GetMethod("UpdateEAHud", AccessTools.all); [HarmonyPriority(700)] [HarmonyTranspiler] public static IEnumerable UpdateHUDPositionAndActiveEffects(IEnumerable instructions) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown Main.LogMessage(() => "Applying Transpiler patch for Hud.Update()"); List list = new List(instructions); int num = -1; for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode != OpCodes.Ret)) { num = i; break; } } if (num == -1) { Main.LogMessage(() => "Could not find patch point"); return instructions; } List collection = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)mUpdateEAHud) }; list.InsertRange(num, collection); Main.LogMessage(() => "Patch done."); return list.AsEnumerable(); } public static void UpdateEAHud(Hud hud) { if (!TryGetEAHud(hud, out var eaHudObject)) { Main.LogMessage(() => "Could not find HUD object. Exiting."); return; } RectTransform component = eaHudObject.GetComponent(); if ((Object)(object)component == (Object)null) { Main.LogMessage(() => "Could not find rect transform for EAHud."); } else { UpdateVisibilityAndPosition(eaHudObject, component); UpdateEnvironmentalSEVisual(hud, eaHudObject, component); } } public static bool TryGetEAHud(Hud hud, [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] out GameObject eaHudObject) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown GameObject rootObject = hud.m_rootObject; foreach (Transform item in rootObject.transform) { Transform val = item; if (((Object)val).name != Main.EAHud) { continue; } eaHudObject = ((Component)val).gameObject; return true; } eaHudObject = null; return false; } public static void UpdateVisibilityAndPosition(GameObject eaHudObject, RectTransform transform) { //IL_0050: 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_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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_0094: 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_00c2: Unknown result type (might be due to invalid IL or missing references) if (!ConfigManager.DisplayEAEffectsOnDifferentHUD.Value) { eaHudObject.SetActive(false); return; } eaHudObject.SetActive(true); switch (ConfigManager.DisplayEAEffectsHUDIconLayout.Value) { case ConfigManager.HUDIconLayout.Horizontal: transform.anchorMin = new Vector2(1f, 0.1f); transform.anchorMax = new Vector2(1f, 0.1f); break; case ConfigManager.HUDIconLayout.Vertical: transform.anchorMin = new Vector2(1f, 0.4f); transform.anchorMax = new Vector2(1f, 0.4f); break; default: transform.anchorMin = new Vector2(1f, 0.1f); transform.anchorMax = new Vector2(1f, 0.1f); break; } int value = ConfigManager.DisplayEAEffectHUDX.Value; int value2 = ConfigManager.DisplayEAEffectHUDY.Value; float num = ConfigManager.DisplayEAEffectHUDScale.Value / 100f; ((Transform)transform).localScale = Vector2.op_Implicit(new Vector2(num, num)); float num2 = -value; Rect rect = transform.rect; float num3 = num2 - ((Rect)(ref rect)).width; rect = transform.rect; transform.anchoredPosition = new Vector2(num3, ((Rect)(ref rect)).height / 2f + (float)value2); } public static void UpdateEnvironmentalSEVisual(Hud hud, GameObject eaHudObject, RectTransform transform) { //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_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_024f: 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_015a: Unknown result type (might be due to invalid IL or missing references) //IL_023e: 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) List environmentalSEs = GetEnvironmentalSEs(); RectTransform[] componentsInChildren = ((Component)transform).GetComponentsInChildren(); List list = new List(); bool flag = false; if (componentsInChildren.Length - 1 != environmentalSEs.Count) { RectTransform[] array = componentsInChildren; foreach (RectTransform val in array) { if (!((Object)(object)val == (Object)(object)transform)) { Object.Destroy((Object)(object)((Component)val).gameObject); } } flag = true; } if (flag) { for (int j = 0; j < environmentalSEs.Count; j++) { int num = Mathf.FloorToInt((float)(j / hud.m_effectsPerRow)); int num2 = j - num * hud.m_effectsPerRow; RectTransform val2 = Object.Instantiate(hud.m_statusEffectTemplate, (Transform)(object)transform); ((Component)val2).gameObject.SetActive(true); switch (ConfigManager.DisplayEAEffectsHUDIconLayout.Value) { case ConfigManager.HUDIconLayout.Horizontal: val2.anchoredPosition = Vector2.op_Implicit(new Vector3((0f - (float)num2) * hud.m_statusEffectSpacing, (0f - (float)num) * hud.m_statusEffectSpacing, 0f)); break; case ConfigManager.HUDIconLayout.Vertical: val2.anchoredPosition = Vector2.op_Implicit(new Vector3((0f - (float)num) * hud.m_statusEffectSpacing, (0f - (float)num2) * hud.m_statusEffectSpacing, 0f)); break; default: val2.anchoredPosition = Vector2.op_Implicit(new Vector3((0f - (float)num2) * hud.m_statusEffectSpacing, (float)num * hud.m_statusEffectSpacing, 0f)); break; } list.Add(val2); } } else { RectTransform[] componentsInChildren2 = ((Component)transform).GetComponentsInChildren(); RectTransform[] array2 = componentsInChildren2; foreach (RectTransform val3 in array2) { if (!((Object)(object)val3 == (Object)(object)transform)) { list.Add(val3); } } } for (int l = 0; l < environmentalSEs.Count; l++) { SE_SurvivalBase sE_SurvivalBase = environmentalSEs[l]; RectTransform val4 = list[l]; Image component = ((Component)((Transform)val4).Find("Icon")).GetComponent(); component.sprite = ((StatusEffect)sE_SurvivalBase).m_icon; if (((StatusEffect)sE_SurvivalBase).m_flashIcon) { ((Graphic)component).color = ((Mathf.Sin(Time.time * 10f) > 0f) ? Hud.s_colorRedish : Color.white); } else { ((Graphic)component).color = Color.white; } ((Component)((Transform)val4).Find("Cooldown")).gameObject.SetActive(((StatusEffect)sE_SurvivalBase).m_cooldownIcon); ((Component)val4).GetComponentInChildren().text = Localization.instance.Localize(((StatusEffect)sE_SurvivalBase).m_name); TMP_Text component2 = ((Component)((Transform)val4).Find("TimeText")).GetComponent(); string iconText = ((StatusEffect)sE_SurvivalBase).GetIconText(); if (!string.IsNullOrEmpty(iconText)) { ((Component)component2).gameObject.SetActive(true); component2.text = iconText; } else { ((Component)component2).gameObject.SetActive(false); } } } public static List GetEnvironmentalSEs() { List list = new List(); Player localPlayer = Player.m_localPlayer; List statusEffects = ((Character)localPlayer).m_seman.GetStatusEffects(); for (int i = 0; i < statusEffects.Count; i++) { if (statusEffects[i] is SE_SurvivalBase) { list.Add((SE_SurvivalBase)(object)statusEffects[i]); } } return list; } } } internal class Hud_UpdateStatusEffects { [HarmonyPatch(typeof(Hud), "UpdateStatusEffects")] public static class Hud_UpdateStatusEffects_Patches { [HarmonyPrefix] [HarmonyPriority(700)] [NullableContext(1)] public static void RemoveSurvivalEffectsFromMainEffectHUD(ref List statusEffects) { if (!ConfigManager.DisplayEAEffectsOnDifferentHUD.Value) { return; } for (int num = statusEffects.Count - 1; num >= 0; num--) { if (statusEffects[num] is SE_SurvivalBase) { statusEffects.RemoveAt(num); } } } } } internal class ObjectDB_Awake { [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class ObjectDB_Awake_Patches { [HarmonyPriority(700)] [NullableContext(1)] [HarmonyPostfix] public static void AddStatusEffectsToObjectDB(ObjectDB __instance) { List addedSE = new List { "Added Status Effects to ObjectDB:" }; SE_PlayerStats playerStats = Main.GetInstance().PlayerStats; if (!__instance.m_StatusEffects.Contains((StatusEffect)(object)playerStats)) { addedSE.Add($"SE_PlayerStats ({SE_PlayerStats.Hash})"); __instance.m_StatusEffects.Add((StatusEffect)(object)playerStats); } SE_Hungry hungry = Main.GetInstance().Hungry; if (!__instance.m_StatusEffects.Contains((StatusEffect)(object)hungry)) { addedSE.Add($"SE_Hungry ({SE_Hungry.Hash})"); __instance.m_StatusEffects.Add((StatusEffect)(object)hungry); } SE_Hot hot = Main.GetInstance().Hot; if (!__instance.m_StatusEffects.Contains((StatusEffect)(object)hot)) { addedSE.Add($"SE_Hot ({SE_Hot.Hash})"); __instance.m_StatusEffects.Add((StatusEffect)(object)hot); } SE_Scorching scorching = Main.GetInstance().Scorching; if (!__instance.m_StatusEffects.Contains((StatusEffect)(object)scorching)) { addedSE.Add($"SE_Scorching ({SE_Scorching.Hash})"); __instance.m_StatusEffects.Add((StatusEffect)(object)scorching); } SE_Vitality vitality = Main.GetInstance().Vitality; if (!__instance.m_StatusEffects.Contains((StatusEffect)(object)vitality)) { addedSE.Add($"SE_Vitality ({SE_Vitality.Hash})"); __instance.m_StatusEffects.Add((StatusEffect)(object)vitality); } SE_Energy energy = Main.GetInstance().Energy; if (!__instance.m_StatusEffects.Contains((StatusEffect)(object)energy)) { addedSE.Add($"SE_Energy ({SE_Energy.Hash})"); __instance.m_StatusEffects.Add((StatusEffect)(object)energy); } SE_Capability capability = Main.GetInstance().Capability; if (!__instance.m_StatusEffects.Contains((StatusEffect)(object)capability)) { addedSE.Add($"SE_Capability ({SE_Capability.Hash})"); __instance.m_StatusEffects.Add((StatusEffect)(object)capability); } Main.LogMessage([NullableContext(1)] () => string.Join("\n", addedSE)); } } } internal class Player_ConsumeItem { [HarmonyPatch(typeof(Player), "ConsumeItem")] public static class Player_ConsumeItem_Patches { [HarmonyPriority(0)] [HarmonyPostfix] [NullableContext(1)] public static void ApplyCapabilityFromTastyMead(Player __instance, Inventory inventory, ItemData item, ref bool __result) { if (!__result) { Main.LogMessage([NullableContext(1)] () => "Consume failed. Additional Capability not generated."); return; } if (!ConfigManager.CapabilityEnabled.Value) { Main.LogMessage([NullableContext(1)] () => "Capability status not enabled."); return; } GameObject dropPrefab = item.m_dropPrefab; string consumedItem = ((dropPrefab != null) ? ((Object)dropPrefab).name.Replace("(Clone)", "").Trim() : null) ?? "None"; Main.LogMessage([NullableContext(1)] () => "Item consumed: " + consumedItem); if (!(consumedItem != "MeadTasty")) { SE_Capability sE_Capability = ((Character)__instance).m_seman.GetStatusEffect(SE_Capability.Hash) as SE_Capability; Main.LogMessage([NullableContext(1)] () => "Tasty Mead consumed. Applying Capability gain."); sE_Capability?.ApplyCapabilityGainFromMead(); } } } } internal class Player_EatFood { [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [HarmonyPatch(typeof(Player), "EatFood")] public static class Player_EatFood_Patches { [HarmonyPrefix] [HarmonyPriority(0)] public static void AdjustFoodBurnTimeFromFitnessSkill(Player __instance, ref ItemData item, out float __state) { __state = ((Character)__instance).GetHealthPercentage(); if (ConfigManager.EnergyEnabled.Value) { SharedData shared = item.m_shared; shared.m_foodBurnTime *= GetFitnessSkillMultiplier(__instance); } } [HarmonyPostfix] [HarmonyPriority(700)] public static void AddFoodToCacheResetEatingTimers(Player __instance, ItemData item, bool __result, float __state) { if (__result) { HandleFoodCache(__instance, item); HandleFoodTimers(__instance, __state); } } [HarmonyPriority(700)] [HarmonyPostfix] public static void ApplyFoodEnergyGains(Player __instance, ItemData item, bool __result) { if (__result && ConfigManager.EnergyEnabled.Value) { HandleEnergyGains(__instance, item); } } public static void HandleEnergyGains(Player player, ItemData item) { if (item.m_shared.m_foodStamina != 0f && ((Character)player).m_seman.GetStatusEffect(SE_Energy.Hash) is SE_Energy sE_Energy) { sE_Energy.ApplyEnergyGainFromFood(item.m_shared.m_foodStamina); } } public static void HandleFoodCache(Player player, ItemData item) { if (((Character)player).m_seman.GetStatusEffect(SE_PlayerStats.Hash) is SE_PlayerStats sE_PlayerStats) { sE_PlayerStats.PlayerFoodCache.Add(item); } } public static void HandleFoodTimers(Player player, float playerHealthPercBeforeEating) { SE_PlayerStats sE_PlayerStats = ((Character)player).m_seman.GetStatusEffect(SE_PlayerStats.Hash) as SE_PlayerStats; if (!((Object)(object)sE_PlayerStats == (Object)null)) { sE_PlayerStats.PlayerTimeSinceFinalFoodDigested = 0f; if (playerHealthPercBeforeEating >= 0.9f) { sE_PlayerStats.PlayerTimeSinceEatenWithGoodHP = 0f; } } } public static float GetFitnessSkillMultiplier(Player player) { return (((Character)player).m_seman.GetStatusEffect(SE_PlayerStats.Hash) is SE_PlayerStats sE_PlayerStats) ? sE_PlayerStats.FitnessFoodBurnMultiplier : 1f; } } } internal class Player_GetEquipmentMaxAdrenaline { [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [HarmonyPatch(typeof(Player), "GetEquipmentMaxAdrenaline")] public static class Player_GetEquipmentMaxAdrenaline_Patches { [HarmonyPriority(700)] [HarmonyTranspiler] public static IEnumerable ModifyAdrenalineFromPerseverenceSkill(IEnumerable instructions) { //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Expected O, but got Unknown Main.LogMessage(() => "Applying Transpiler patch for Player.GetEquipmentMaxAdrenaline()"); List list = new List(instructions); MethodInfo method = typeof(Player_GetEquipmentMaxAdrenaline_Patches).GetMethod("ModifyMaxAdrenaline", AccessTools.all); MethodInfo method2 = typeof(Player).GetMethod("GetEquipmentModifier", AccessTools.all); int num = -1; int num2 = -1; for (int i = 0; i < list.Count - 2; i++) { if (!(list[i].opcode != OpCodes.Ldarg_0) && !(list[i + 1].opcode != OpCodes.Ldc_I4_S) && (sbyte)list[i + 1].operand == 10 && !(list[i + 2].opcode != OpCodes.Call) && !((MethodInfo)list[i + 2].operand != method2)) { num = i; num2 = i + 3; break; } } if (num == -1 || num2 == -1) { return instructions; } List collection = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null) }; List collection2 = new List { new CodeInstruction(OpCodes.Call, (object)method) }; list.InsertRange(num2, collection2); list.InsertRange(num, collection); Main.LogMessage(() => "Patch done."); return list.AsEnumerable(); } public static float ModifyMaxAdrenaline(Player player, float originalMaxAdrenaline) { if (originalMaxAdrenaline == 0f) { return originalMaxAdrenaline; } SE_PlayerStats sE_PlayerStats = ((Character)player).m_seman.GetStatusEffect(SE_PlayerStats.Hash) as SE_PlayerStats; float modifiedAdrenaline = (originalMaxAdrenaline * sE_PlayerStats?.PerseverenceMaxAdrenalineMultiplier) ?? originalMaxAdrenaline; Main.LogMessage(() => $"Adrenaline Modifier: {originalMaxAdrenaline} -> {modifiedAdrenaline}"); return modifiedAdrenaline; } } } internal class Player_GetEquipmentMovementModifier { [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [NullableContext(1)] [HarmonyPatch(typeof(Player), "GetEquipmentMovementModifier")] public static class Player_GetEquipmentMovementModifier_Patches { [HarmonyPriority(700)] [HarmonyTranspiler] public static IEnumerable ReduceMovementPenaltiesFromFitnessSkill(IEnumerable instructions) { //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Expected O, but got Unknown Main.LogMessage(() => "Applying Transpiler patch for Player.GetEquipmentMovementModifier()"); List list = new List(instructions); MethodInfo method = typeof(Player_GetEquipmentMovementModifier_Patches).GetMethod("ModifyMovementSpeed", AccessTools.all); MethodInfo method2 = typeof(Player).GetMethod("GetEquipmentModifier", AccessTools.all); int num = -1; int num2 = -1; for (int i = 0; i < list.Count - 2; i++) { if (!(list[i].opcode != OpCodes.Ldarg_0) && !(list[i + 1].opcode != OpCodes.Ldc_I4_0) && !(list[i + 2].opcode != OpCodes.Call) && !((MethodInfo)list[i + 2].operand != method2)) { num = i; num2 = i + 3; break; } } if (num == -1 || num2 == -1) { Main.LogMessage(() => "Could not find patch points."); return instructions; } List collection = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null) }; List collection2 = new List { new CodeInstruction(OpCodes.Call, (object)method) }; list.InsertRange(num2, collection2); list.InsertRange(num, collection); Main.LogMessage(() => "Patch done."); return list.AsEnumerable(); } public static float ModifyMovementSpeed(Player player, float originalSpeedModifier) { if (originalSpeedModifier >= 0f) { return originalSpeedModifier; } float valueOrDefault = (originalSpeedModifier * (((Character)player).m_seman.GetStatusEffect(SE_PlayerStats.Hash) as SE_PlayerStats)?.FitnessSpeedPenaltyReduction).GetValueOrDefault(); return originalSpeedModifier - valueOrDefault; } } } internal class Player_GetTotalFoodValue { [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] public static class Player_GetTotalFoodValue_Patches { [NullableContext(1)] [HarmonyPriority(700)] public static void Postfix(Player __instance, ref float stamina) { if (ConfigManager.EMaxStaminaReductionEnabled.Value && ConfigManager.EnergyEnabled.Value) { stamina *= (((Character)__instance).m_seman.GetStatusEffect(SE_Energy.Hash) as SE_Energy)?.m_staminaReductionMultiplier ?? 1f; } } } } internal class Player_OnDamaged { [HarmonyPatch(typeof(Player), "OnDamaged")] public static class Player_OnDamaged_Patches { [HarmonyPostfix] [NullableContext(1)] [HarmonyPriority(700)] public static void DrainVitalityWhenDamaged(Player __instance, HitData hit) { if (ConfigManager.VitalityEnabled.Value) { float totalDamage = hit.GetTotalDamage(); if (!(totalDamage < 1f) && ((Character)__instance).m_seman.GetStatusEffect(SE_Vitality.Hash) is SE_Vitality sE_Vitality) { sE_Vitality.ApplyVulnerabilityFromDamage(totalDamage); } } } } } internal class Player_RPC_UseStamina { [HarmonyPatch(typeof(Player), "RPC_UseStamina")] public static class Player_RPC_UseStamina_Patches { [HarmonyPostfix] [HarmonyPriority(700)] [NullableContext(1)] public static void DrainEnergyWhenStaminaUsed(Player __instance, float v) { if (ConfigManager.EnergyEnabled.Value && ((Character)__instance).m_seman.GetStatusEffect(SE_Energy.Hash) is SE_Energy sE_Energy) { sE_Energy.ApplyEnergyLossFromStamina(v); } } } } internal class Player_Save { [HarmonyPatch(typeof(Player), "Save")] public static class Player_Save_Patches { [NullableContext(1)] [HarmonyPriority(0)] [HarmonyPrefix] public static void SaveSurvivalSkillsData(Player __instance) { List statusEffects = ((Character)__instance).m_seman.GetStatusEffects(); foreach (StatusEffect item in statusEffects) { if (item is ILoadSave loadSave) { loadSave.SaveData(); } } } } } internal class Player_SetSleeping { [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [HarmonyPatch(typeof(Player), "SetSleeping")] public static class Player_SetSleeping_Patches { [HarmonyPrefix] [HarmonyPriority(700)] public static void StoreSleepingState(Player __instance, bool sleep, out bool __state) { __state = __instance.m_sleeping != sleep; } [HarmonyPostfix] [HarmonyPriority(700)] public static void RecoverCapabilityAndEnergyFromSleep(Player __instance, bool __state) { if (__state) { if (((Character)__instance).m_seman.GetStatusEffect(SE_Capability.Hash) is SE_Capability sE_Capability) { sE_Capability.ApplyCapabilityGainFromSleep(); } if (((Character)__instance).m_seman.GetStatusEffect(SE_Energy.Hash) is SE_Energy sE_Energy) { sE_Energy.ApplyEnergyGainFromSleeping(); } } } } } internal class Player_UpdateEnvStatusEffects { [NullableContext(1)] [HarmonyPatch(typeof(Player), "UpdateEnvStatusEffects")] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public static class Player_UpdateEnvStatusEffects_Patches { [HarmonyTranspiler] [HarmonyPriority(700)] public static IEnumerable AddPlayerStatsAndHotStatusChecks(IEnumerable instructions) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Expected O, but got Unknown //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Expected O, but got Unknown //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Expected O, but got Unknown //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Expected O, but got Unknown Main.LogMessage(() => "Applying Transpiler patch for Player.UpdateEnvStatusEffects()..."); List list = new List(instructions); MethodInfo method = typeof(Player_UpdateEnvStatusEffects_Patches).GetMethod("HandlePlayerStats", AccessTools.all); MethodInfo method2 = typeof(Player_UpdateEnvStatusEffects_Patches).GetMethod("HandleHeatSEs", AccessTools.all); MethodInfo method3 = typeof(Player_UpdateEnvStatusEffects_Patches).GetMethod("PlayerInAshlands", AccessTools.all); List collection = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)method), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)method2) }; list.InsertRange(0, collection); int insertIndex = -1; Label? label = null; for (int i = 0; i < list.Count - 5; i++) { if (!(list[i].opcode != OpCodes.Ldloc_S) && !(list[i + 1].opcode != OpCodes.Ldc_I4_1) && !(list[i + 2].opcode != OpCodes.Beq) && !(list[i + 3].opcode != OpCodes.Ldloc_S) && !(list[i + 4].opcode != OpCodes.Ldc_I4_5) && !(list[i + 5].opcode != OpCodes.Beq)) { label = (Label)list[i + 5].operand; insertIndex = i + 6; break; } } if (insertIndex == -1 || !label.HasValue) { Main.LogMessage(() => $"{insertIndex}"); Main.LogMessage(() => "Could not find patch point or label."); return instructions; } List collection2 = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)method3), new CodeInstruction(OpCodes.Ldc_I4_1, (object)null), new CodeInstruction(OpCodes.Beq, (object)label) }; list.InsertRange(insertIndex, collection2); Main.LogMessage(() => "Patch done."); return list.AsEnumerable(); } public static void HandlePlayerStats(Player player) { if (!((Character)player).m_seman.HaveStatusEffect(SE_PlayerStats.Hash)) { ((Character)player).m_seman.AddStatusEffect(SE_PlayerStats.Hash, false, 0, 0f); Main.LogMessage(() => "Environment Status (invisible SE) applied to player."); } } public static void HandleHeatSEs(Player player) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Invalid comparison between Unknown and I4 //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Invalid comparison between Unknown and I4 if (!ConfigManager.OverheatingEnabled.Value) { return; } DamageModifiers damageModifiers = ((Character)player).GetDamageModifiers((WeakSpot)null); DamageModifier modifier = ((DamageModifiers)(ref damageModifiers)).GetModifier((DamageType)32); bool flag = EnvManHelper.IsHot() && !EnvManHelper.IsScorching(); bool flag2 = EnvManHelper.IsScorching(); bool flag3 = WorldGenerator.GetAshlandsOceanGradient(((Component)player).transform.position) > 0f; bool flag4 = ((Character)player).InWater(); bool flag5 = ((Character)player).m_seman.HaveStatusEffect(SEMan.s_statusEffectWet); bool flag6 = Object.op_Implicit((Object)(object)EffectArea.IsPointInsideArea(((Component)player).transform.position, (Type)64, 1f)); bool flag7 = player.InShelter(); bool flag8 = (int)modifier == 1 || (int)modifier == 5 || (int)modifier == 7; bool flag9 = (flag2 && !flag7 && !flag5 && !flag8) || (flag4 && flag3 && !flag8); bool flag10 = (flag && !flag7 && !flag5 && !flag8) || (flag2 && (flag7 || flag5 || flag8)) || (flag4 && flag3); if (flag9 && !flag6) { if (!((Character)player).m_seman.RemoveStatusEffect(SE_Hot.Hash, true)) { ((Character)player).m_seman.AddStatusEffect(SE_Scorching.Hash, false, 0, 0f); } } else if (flag10 && !flag6) { if (!((Character)player).m_seman.RemoveStatusEffect(SE_Scorching.Hash, true)) { ((Character)player).m_seman.AddStatusEffect(SE_Hot.Hash, false, 0, 0f); player.ShowTutorial("EnvironmentalAwarenessHot", false); } } else { ((Character)player).m_seman.RemoveStatusEffect(SE_Hot.Hash, false); ((Character)player).m_seman.RemoveStatusEffect(SE_Scorching.Hash, false); } } public static bool PlayerInAshlands(Player player) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 return ConfigManager.OverheatingEnabled.Value && (int)player.GetCurrentBiome() == 32; } } } internal class Player_UpdateFood { [HarmonyPatch(typeof(Player), "UpdateFood")] public static class Player_UpdateFood_Patches { [HarmonyPriority(700)] [HarmonyPostfix] [NullableContext(1)] public static void CheckPlayerHungry(Player __instance) { if (!ConfigManager.HungerEnabled.Value) { return; } SE_PlayerStats sE_PlayerStats = ((Character)__instance).m_seman.GetStatusEffect(SE_PlayerStats.Hash) as SE_PlayerStats; if ((Object)(object)sE_PlayerStats == (Object)null) { return; } if (sE_PlayerStats.PlayerTimeSinceFinalFoodDigested > (float)ConfigManager.HungerTime.Value && sE_PlayerStats.PlayerFoodCache.Count == 0) { if (!((Character)__instance).m_seman.HaveStatusEffect(SE_Hungry.Hash)) { Main.LogMessage([NullableContext(1)] () => "Adding Hungry status effect to player."); ((Character)__instance).m_seman.AddStatusEffect(SE_Hungry.Hash, false, 0, 0f); } } else { SE_Hungry sE_Hungry = ((Character)__instance).m_seman.GetStatusEffect(SE_Hungry.Hash) as SE_Hungry; if (!((Object)(object)sE_Hungry == (Object)null)) { ((StatusEffect)sE_Hungry).m_time = ((StatusEffect)sE_Hungry).m_ttl + 1f; } } } } } internal class SE_Rested_CalculateComfortLevel { [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [HarmonyPatch(typeof(SE_Rested), "CalculateComfortLevel", new Type[] { typeof(Player) })] public static class SE_Rested_CalculateComfortLevel_Patches { [HarmonyTranspiler] [HarmonyPriority(700)] public static IEnumerable AddExtraComfortFromPerseverenceSkill(IEnumerable instructions) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown Main.LogMessage(() => "Applying Transpiler patch for SE_Rested.CalculateComfortLevel(Player player)..."); List list = new List(instructions); MethodInfo method = typeof(SE_Rested_CalculateComfortLevel_Patches).GetMethod("GetAdditionalComfortLevel", AccessTools.all); int num = -1; for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode != OpCodes.Ret)) { num = i; break; } } if (num == -1) { Main.LogMessage(() => "Could not find patch point."); return instructions; } List collection = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)method), new CodeInstruction(OpCodes.Add, (object)null) }; list.InsertRange(num, collection); Main.LogMessage(() => "Patch done."); return list.AsEnumerable(); } public static int GetAdditionalComfortLevel(Player player) { return (((Character)player).m_seman.GetStatusEffect(SE_PlayerStats.Hash) is SE_PlayerStats sE_PlayerStats) ? sE_PlayerStats.PerseverenceComfortBonus : 0; } } } internal class SE_Stats_Setup { [HarmonyPatch(typeof(SE_Stats), "Setup")] [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public static class SE_Stats_Setup_Patches { [HarmonyTranspiler] [HarmonyPriority(700)] public static IEnumerable AdjustElementalMeadsDurationFromResistanceSkill(IEnumerable instructions) { //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Expected O, but got Unknown //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Expected O, but got Unknown //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Expected O, but got Unknown //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Expected O, but got Unknown Main.LogMessage(() => "Applying Transpiler patch for SE_Stats.Setup()..."); List list = new List(instructions); MethodInfo method = typeof(SE_Stats_Setup_Patches).GetMethod("GetAdjustedTTL"); MethodInfo method2 = typeof(SE_Stats).GetMethod("StartupEffects", AccessTools.all); FieldInfo field = typeof(SE_Stats).GetField("m_ttl", AccessTools.all); int num = -1; for (int i = 0; i < list.Count - 1; i++) { if (!(list[i].opcode != OpCodes.Ldarg_0) && !(list[i + 1].opcode != OpCodes.Call) && !((MethodInfo)list[i + 1].operand != method2)) { num = i + 2; break; } } if (num == -1) { Main.LogMessage(() => "Could not find patch point."); return instructions; } List collection = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)method), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)field), new CodeInstruction(OpCodes.Mul, (object)null), new CodeInstruction(OpCodes.Stfld, (object)field) }; list.InsertRange(num, collection); Main.LogMessage(() => "Patch done."); return list.AsEnumerable(); } public static float GetAdjustedTTL(SE_Stats status) { if (!((Object)status).name.ToLower().Contains("mead") || !((Object)status).name.ToLower().Contains("potion")) { return 1f; } int resistantElementalModifiers = GetResistantElementalModifiers(status); if (resistantElementalModifiers != 1) { return 1f; } Character character = ((StatusEffect)status).m_character; Player val = (Player)(object)((character is Player) ? character : null); if ((Object)(object)val == (Object)null) { return 1f; } return (((Character)val).m_seman.GetStatusEffect(SE_PlayerStats.Hash) is SE_PlayerStats sE_PlayerStats) ? sE_PlayerStats.ResistanceExtraMeadDurationMultiplier : 1f; } public static int GetResistantElementalModifiers(SE_Stats status) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Invalid comparison between Unknown and I4 //IL_0025: 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_002d: Invalid comparison between Unknown and I4 //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) //IL_003a: Invalid comparison between Unknown and I4 //IL_0055: 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_005c: Invalid comparison between Unknown and I4 //IL_003c: 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) //IL_0047: Invalid comparison between Unknown and I4 //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Invalid comparison between Unknown and I4 int num = 0; foreach (DamageModPair mod in status.m_mods) { if (((int)mod.m_type == 32 || (int)mod.m_type == 64 || (int)mod.m_type == 128 || (int)mod.m_type == 256) && ((int)mod.m_modifier == 1 || (int)mod.m_modifier == 5)) { num++; } } return num; } } } internal class SE_Stats_UpdateStatusEffect { [HarmonyPatch(typeof(SE_Stats), "UpdateStatusEffect")] public static class SE_Stats_UpdateStatusEffect_Patches { [NullableContext(1)] [HarmonyTranspiler] [HarmonyPriority(700)] public static IEnumerable FixZeroHPCausingDamage(IEnumerable instructions) { //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Expected O, but got Unknown //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown Main.LogMessage([NullableContext(1)] () => "Applying Transpiler patch for SE_Stats.UpdateStatusEffect()..."); List list = new List(instructions); FieldInfo field = typeof(SE_Stats).GetField("m_healthPerTick", AccessTools.all); int num = -1; int index = -1; for (int i = 1; i < list.Count - 5; i++) { if (!(list[i - 1].opcode != OpCodes.Blt_Un) && !(list[i].opcode != OpCodes.Ldarg_0) && !(list[i + 1].opcode != OpCodes.Ldfld) && !((FieldInfo)list[i + 1].operand != field) && !(list[i + 2].opcode != OpCodes.Ldc_R4) && !(list[i + 3].opcode != OpCodes.Ble_Un)) { index = i - 1; num = i; break; } } if (num == -1) { Main.LogMessage([NullableContext(1)] () => "Could not find patch point."); return instructions; } Label label = (Label)list[index].operand; List collection = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)field), new CodeInstruction(OpCodes.Ldc_R4, (object)0f), new CodeInstruction(OpCodes.Beq, (object)label) }; list.InsertRange(num, collection); Main.LogMessage([NullableContext(1)] () => "Patch done."); return list.AsEnumerable(); } } } internal class SE_Wet_UpdateStatusEffect { [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [HarmonyPatch(typeof(SE_Wet), "UpdateStatusEffect")] public static class SE_Wet_UpdateStatusEffect_Patches { [HarmonyTranspiler] [HarmonyPriority(700)] public static IEnumerable AddHotChecksToWetSEDuration(IEnumerable instructions) { //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown Main.LogMessage(() => "Applying Transpiler patch for SE_Wet.UpdateStatusEffect()..."); List list = new List(instructions); MethodInfo method = typeof(SE_Wet_UpdateStatusEffect_Patches).GetMethod("UpdateHotScorching", AccessTools.all); MethodInfo method2 = typeof(SE_Stats).GetMethod("UpdateStatusEffect", AccessTools.all); int num = -1; for (int i = 0; i < list.Count - 2; i++) { if (!(list[i].opcode != OpCodes.Ldarg_0) && !(list[i + 1].opcode != OpCodes.Ldarg_1) && !(list[i + 2].opcode != OpCodes.Call) && !((MethodInfo)list[i + 2].operand != method2)) { num = i + 3; break; } } if (num == -1) { Main.LogMessage(() => "Could not find patch point."); return instructions; } List collection = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Call, (object)method) }; list.InsertRange(0, collection); Main.LogMessage(() => "Patch done."); return list.AsEnumerable(); } public static void UpdateHotScorching(SE_Wet wet, float dt) { bool flag = EnvManHelper.IsScorching(); bool flag2 = EnvManHelper.IsHot(); bool flag3 = ((StatusEffect)wet).m_character.IsUnderRoof(); if (flag) { ((StatusEffect)wet).m_time = ((StatusEffect)wet).m_time + (float)(flag3 ? 25 : 100) * dt; } else if (flag2) { ((StatusEffect)wet).m_time = ((StatusEffect)wet).m_time + (float)(flag3 ? 2 : 5) * dt; } } } } internal class Tutorial_Awake { [HarmonyPatch(typeof(Tutorial), "Awake")] public static class Tutorial_Awake_Patches { [HarmonyPriority(700)] [HarmonyPostfix] [NullableContext(1)] public static void AddNewTutorials(Tutorial __instance) { List addedTutorials = new List { "Added tutorials: " }; TutorialText[] tutorialTexts = Main.GetInstance().TutorialTexts; foreach (TutorialText val in tutorialTexts) { if (!__instance.m_texts.Contains(val)) { addedTutorials.Add(val.m_name); __instance.m_texts.Add(val); } } Main.LogMessage([NullableContext(1)] () => string.Join(", ", addedTutorials)); } } } } namespace EnvironmentalAwareness.Interface { internal interface ILoadSave { void LoadData(); void SaveData(); } } namespace EnvironmentalAwareness.Data { [NullableContext(2)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public class ConfigManager { [NullableContext(0)] public enum HUDIconLayout { Horizontal, Vertical } public static ConfigSync configSync; public static ConfigEntry ConfigLocked; public static ConfigEntry DebugLogging; public static ConfigEntry DebugUpdateTime; public static ConfigEntry ShowDebugValueInSE; public static ConfigEntry SavingEnabled; public static ConfigEntry VitalityEnabled; public static ConfigEntry EnergyEnabled; public static ConfigEntry PotentialityEnabled; public static ConfigEntry CapabilityEnabled; public static ConfigEntry HungerEnabled; public static ConfigEntry HungerTime; public static ConfigEntry OverheatingEnabled; public static ConfigEntry NewPlayerCooldown; public static ConfigEntry DeathGrantsImmunity; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(new byte[] { 2, 1 })] public static ConfigEntry GlobalKeySpring; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(new byte[] { 2, 1 })] public static ConfigEntry GlobalKeySummer; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(new byte[] { 2, 1 })] public static ConfigEntry GlobalKeyFall; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(new byte[] { 2, 1 })] public static ConfigEntry GlobalKeyWinter; public static ConfigEntry VColdAdd; public static ConfigEntry VFreezingAdd; public static ConfigEntry VHotAdd; public static ConfigEntry VScorchingAdd; public static ConfigEntry VWetAdd; public static ConfigEntry VColdWetMultiplier; public static ConfigEntry VFreezingWetMultiplier; public static ConfigEntry VHungerAdd; public static ConfigEntry VHPDamageAdd; public static ConfigEntry VMissingHPAdd; public static ConfigEntry VPoisonDamageAdd; public static ConfigEntry VBurningDamageAdd; public static ConfigEntry VShockDamageAdd; public static ConfigEntry VFrostDamageAdd; public static ConfigEntry VAshlandsPassiveAdd; public static ConfigEntry VDeepNorthPassiveAdd; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(new byte[] { 2, 1 })] public static ConfigEntry VEnvironmentsToIgnore; public static ConfigEntry VSpringSeasonalMultiplier; public static ConfigEntry VSummerSeasonalMultiplier; public static ConfigEntry VFallSeasonalMultiplier; public static ConfigEntry VWinterSeasonalMultiplier; public static ConfigEntry VHeatRemove; public static ConfigEntry VShelteredRemove; public static ConfigEntry VHeatShelteredMultiplier; public static ConfigEntry VRestingRemove; public static ConfigEntry VRestedRemove; public static ConfigEntry VPassiveRemove; public static ConfigEntry VHealthPotionRemove; public static ConfigEntry VResistancePerArmorPoint; public static ConfigEntry VResistanceMinArmorThreshold; public static ConfigEntry VResistanceStaffOfProtection; public static ConfigEntry VPoisonResistantMultiplier; public static ConfigEntry VPoisonVeryResistantMultiplier; public static ConfigEntry VFireResistantMultiplier; public static ConfigEntry VFireVeryResistantMultiplier; public static ConfigEntry VLightningResistantMultiplier; public static ConfigEntry VLightningVeryResistantMultiplier; public static ConfigEntry VFrostResistantMultiplier; public static ConfigEntry VFrostVeryResistantMultiplier; public static ConfigEntry VMultiplierPer10FoodValue; public static ConfigEntry VHealthDamageEnabled; public static ConfigEntry VHealthMaxDamageOverTime; public static ConfigEntry VHealthMaxRegenReduction; public static ConfigEntry VHealthDamageMinStartThreshold; public static ConfigEntry VMoveSpeedReductionEnabled; public static ConfigEntry VMoveSpeedMaxReduction; public static ConfigEntry VMoveSpeedMinStartThreshold; public static ConfigEntry VStaminaRegenReductionEnabled; public static ConfigEntry VStaminaRegenMaxReduction; public static ConfigEntry VStaminaRegenReductionThreshold; public static ConfigEntry VFoodBurnRateEnabled; public static ConfigEntry VFoodBurnMaxOverTime; public static ConfigEntry VFoodBurnMinStartThreshold; public static ConfigEntry VFoodBurnStatReduction; public static ConfigEntry VPhysicalWeaknessEnabled; public static ConfigEntry VPhysicalWeaknessThreshold; public static ConfigEntry VElementalWeaknessEnabled; public static ConfigEntry VElementalWeaknessThreshold; public static ConfigEntry ELossStaminaPointUsedAdd; public static ConfigEntry ELossMotionAdd; public static ConfigEntry ELossHungryAdd; public static ConfigEntry ELossColdAdd; public static ConfigEntry ELossFreezingAdd; public static ConfigEntry ELossHotAdd; public static ConfigEntry ELossScorchingAdd; public static ConfigEntry ELossWetAdd; public static ConfigEntry ELossHeavyLoadAdd; public static ConfigEntry ELossHeavyLoadThreshold; public static ConfigEntry ELossNoRestMultiplier; public static ConfigEntry ELossNoRestThreshold; public static ConfigEntry ESpringSeasonMultiplier; public static ConfigEntry ESummerSeasonMultiplier; public static ConfigEntry EFallSeasonMultiplier; public static ConfigEntry EWinterSeasonMultiplier; public static ConfigEntry ELossSittingRemove; public static ConfigEntry ELossRestingRemove; public static ConfigEntry ELossSittingRestingMultiplier; public static ConfigEntry ELossSittingRestingShelterMultiplier; public static ConfigEntry ELossRestedRemove; public static ConfigEntry ELossPercentageSleepRemove; public static ConfigEntry ELossFoodStaminaRemove; public static ConfigEntry ELossStaminaMeadRemove; public static ConfigEntry ELossRestedResist; public static ConfigEntry ELossStaminaMeadResist; public static ConfigEntry ELossLowEnergyResist; public static ConfigEntry ELossLowEnergyThreshold; public static ConfigEntry EDamageReductionEnabled; public static ConfigEntry EDamageMaxReduction; public static ConfigEntry EDamageReductionThreshold; public static ConfigEntry EMaxStaminaReductionEnabled; public static ConfigEntry EMaxStaminaReduction; public static ConfigEntry EMaxStaminaReductionThreshold; public static ConfigEntry ESkillGainReductionEnabled; public static ConfigEntry ESkillGainMaxReduction; public static ConfigEntry ESkillGainReductionThreshold; public static ConfigEntry EStaminaRegenEnabled; public static ConfigEntry EStaminaRegenMaxReduction; public static ConfigEntry EStaminaRegenMinThreshold; public static ConfigEntry EStaminaRegenDelayEnabled; public static ConfigEntry EStaminaRegenDelayMaxMultiplier; public static ConfigEntry EStaminaRegenDelayMinThreshold; public static ConfigEntry EMoveSpeedReductionEnabled; public static ConfigEntry EMoveSpeedMaxReduction; public static ConfigEntry EMoveSpeedReductionMinThreshold; public static ConfigEntry ERestedLossEnabled; public static ConfigEntry ERestedLossThreshold; public static ConfigEntry PLossEitrPointAdd; public static ConfigEntry PLossWhenShieldedAdd; public static ConfigEntry PLossOverspentEitrPointAdd; public static ConfigEntry PLossPassiveRemove; public static ConfigEntry PLossRestedRemove; public static ConfigEntry PLossRestedRemoveMultiplier; public static ConfigEntry PLossFoodEitrRemove; public static ConfigEntry PLossEitrMeadRemove; public static ConfigEntry PLossSleepRemove; public static ConfigEntry PLossRestedResist; public static ConfigEntry PLossEitrMeadResist; public static ConfigEntry PEitrRegenReductionEnabled; public static ConfigEntry PEitrRegenMaxReduction; public static ConfigEntry PEitrRegenReductionThreshold; public static ConfigEntry PEitrCostIncreaseEnabled; public static ConfigEntry PEitrCostMaxIncrease; public static ConfigEntry PEitrCostIncreaseThreshold; public static ConfigEntry CTimeToDrain; public static ConfigEntry CLowVitalityLoss; public static ConfigEntry CLowVitalityLossThreshold; public static ConfigEntry CLowEnergyLoss; public static ConfigEntry CLowEnergyLossThreshold; public static ConfigEntry CSleepLossRemove; public static ConfigEntry CInBedLossRemove; public static ConfigEntry CTastyMeadLossRemove; public static ConfigEntry CTastyMeadLimit; public static ConfigEntry CTastyMeadSleepRemove; public static ConfigEntry CTastyMeadDigestionTime; public static ConfigEntry CTastyMeadDigestionInBedMultiplier; public static ConfigEntry CRestedResist; public static ConfigEntry CVitalityResist; public static ConfigEntry CVitalityResistThreshold; public static ConfigEntry CEnergyResist; public static ConfigEntry CEnergyResistThreshold; public static ConfigEntry CVitalityMaxCap; public static ConfigEntry CVitalityMaxCapThreshold; public static ConfigEntry CEnergyMaxCap; public static ConfigEntry CEnergyMaxCapThreshold; public static ConfigEntry ResistanceSkillEffectFactor; public static ConfigEntry ResistanceSkillGainMinThreshold; public static ConfigEntry ResistanceSkillMissingHPDamageMultiplier; public static ConfigEntry ResistanceSkillMissingHPDamageMultiplierStartLevel; public static ConfigEntry ResistanceSkillElementalMeadMultiplier; public static ConfigEntry ResistanceSkillElementalMeadMultiplierStartLevel; public static ConfigEntry ResistanceSkillColdHotDebuffMitigationPerc; public static ConfigEntry ResistanceSkillColdHotDebuffMitigationPercStartLevel; public static ConfigEntry ResistanceSkillFreezingScorchingDebuffMitigationPerc; public static ConfigEntry ResistanceSkillFreezingScorchingDebuffMitigationPercStartLevel; public static ConfigEntry ResistanceSkillWetDebuffMitigationPerc; public static ConfigEntry ResistanceSkillWetDebuffMitigationPercStartLevel; public static ConfigEntry ResistanceSkillGainFactor; public static ConfigEntry FitnessSkillEffectFactor; public static ConfigEntry FitnessSkillGainFactor; public static ConfigEntry FitnessSkillMaxEnergyGain; public static ConfigEntry FitnessSkillSpeedPenaltyRemove; public static ConfigEntry FitnessSkillSpeedPenaltyRemoveStartLevel; public static ConfigEntry FitnessSkillFoodBurnMultiplier; public static ConfigEntry FitnessSkillFoodBurnMultiplierStartLevel; public static ConfigEntry AssuranceSkillEffectFactor; public static ConfigEntry AssuranceSkillMaxPotentialityGain; public static ConfigEntry AssuranceSkillCriticalHitChance; public static ConfigEntry AssuranceSkillCriticalHitDamage; public static ConfigEntry AssuranceSkillCriticalHitStartLevel; public static ConfigEntry AssuranceSkillGainFactor; public static ConfigEntry PerseverenceSkillMaxTimeGain; public static ConfigEntry PerseverenceSkillMinThreshold; public static ConfigEntry PerseverenceSkillGainFactor; public static ConfigEntry PerseverenceSkillComfortBonus; public static ConfigEntry PerseverenceSkillComfortBonusStartLevel; public static ConfigEntry PerseverenceSkillMaxAdrenalineMultiplier; public static ConfigEntry PerseverenceSkillMaxAdrenalineMultiplierStartLevel; public static ConfigEntry DisplayVitalityPercentage; public static ConfigEntry DisplayVitalityWarningTexts; public static ConfigEntry DisplayEnergyPercentage; public static ConfigEntry DisplayEnergyWarningTexts; public static ConfigEntry DisplayCapabilityPercentage; public static ConfigEntry DisplayCapabilityWarningTexts; public static ConfigEntry DisplayEAEffectsOnDifferentHUD; public static ConfigEntry DisplayEAEffectsHUDIconLayout; public static ConfigEntry DisplayEAEffectHUDX; public static ConfigEntry DisplayEAEffectHUDY; public static ConfigEntry DisplayEAEffectHUDScale; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(new byte[] { 2, 1 })] public static List VIgnoredEnvironments; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string ZerA = "0a. General"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string ZerB = "0b. Season Mod Integration"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string OneA = "1a. Vitality Loss"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string OneB = "1b. Vitality Recovery"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string OneC = "1c. Resistances to Vitality Loss"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string OneD = "1d. Vitality Effects"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string TwoA = "2a. Energy Loss"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string TwoB = "2b. Energy Recovery"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string TwoC = "2c. Resistance to Energy Loss"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string TwoD = "2d. Energy Effects"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string FouA = "3a. Capability Loss"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string FouB = "3b. Capability Recovery"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string FouC = "3c. Resistance to Capability Loss"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string FouD = "3d. Capability Effects"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string FivA = "4a. Skill: Resistance"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string FivB = "4b. Skill: Fitness"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string FivC = "4c. Skill: Assurance"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string FivD = "4d. Skill: Perserverence"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string Six = "5. UI and Display"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string SevA = "7a. Balrond Amazing Nature Compatibility"; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public static readonly string SevB = "7b. You're Thirsty Compatibility"; [NullableContext(1)] public static void CreateConfigValues(BaseUnityPlugin plugin) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Expected O, but got Unknown //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Expected O, but got Unknown //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Expected O, but got Unknown //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Expected O, but got Unknown //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Expected O, but got Unknown //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Expected O, but got Unknown //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Expected O, but got Unknown //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Expected O, but got Unknown //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Expected O, but got Unknown //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Expected O, but got Unknown //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Expected O, but got Unknown //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Expected O, but got Unknown //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Expected O, but got Unknown //IL_0414: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Expected O, but got Unknown //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_045b: Expected O, but got Unknown //IL_048e: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Expected O, but got Unknown //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Expected O, but got Unknown //IL_0508: Unknown result type (might be due to invalid IL or missing references) //IL_0512: Expected O, but got Unknown //IL_0545: Unknown result type (might be due to invalid IL or missing references) //IL_054f: Expected O, but got Unknown //IL_0582: Unknown result type (might be due to invalid IL or missing references) //IL_058c: Expected O, but got Unknown //IL_05bf: Unknown result type (might be due to invalid IL or missing references) //IL_05c9: Expected O, but got Unknown //IL_05fc: Unknown result type (might be due to invalid IL or missing references) //IL_0606: Expected O, but got Unknown //IL_0639: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Expected O, but got Unknown //IL_0676: Unknown result type (might be due to invalid IL or missing references) //IL_0680: Expected O, but got Unknown //IL_06b3: Unknown result type (might be due to invalid IL or missing references) //IL_06bd: Expected O, but got Unknown //IL_06f0: Unknown result type (might be due to invalid IL or missing references) //IL_06fa: Expected O, but got Unknown //IL_072d: Unknown result type (might be due to invalid IL or missing references) //IL_0737: Expected O, but got Unknown //IL_075c: Unknown result type (might be due to invalid IL or missing references) //IL_0766: Expected O, but got Unknown //IL_07bd: Unknown result type (might be due to invalid IL or missing references) //IL_07c7: Expected O, but got Unknown //IL_07fa: Unknown result type (might be due to invalid IL or missing references) //IL_0804: Expected O, but got Unknown //IL_0837: Unknown result type (might be due to invalid IL or missing references) //IL_0841: Expected O, but got Unknown //IL_0874: Unknown result type (might be due to invalid IL or missing references) //IL_087e: Expected O, but got Unknown //IL_08b1: Unknown result type (might be due to invalid IL or missing references) //IL_08bb: Expected O, but got Unknown //IL_08ee: Unknown result type (might be due to invalid IL or missing references) //IL_08f8: Expected O, but got Unknown //IL_092b: Unknown result type (might be due to invalid IL or missing references) //IL_0935: Expected O, but got Unknown //IL_0968: Unknown result type (might be due to invalid IL or missing references) //IL_0972: Expected O, but got Unknown //IL_09a5: Unknown result type (might be due to invalid IL or missing references) //IL_09af: Expected O, but got Unknown //IL_09e2: Unknown result type (might be due to invalid IL or missing references) //IL_09ec: Expected O, but got Unknown //IL_0a1f: Unknown result type (might be due to invalid IL or missing references) //IL_0a29: Expected O, but got Unknown //IL_0a5c: Unknown result type (might be due to invalid IL or missing references) //IL_0a66: Expected O, but got Unknown //IL_0a92: Unknown result type (might be due to invalid IL or missing references) //IL_0a9c: Expected O, but got Unknown //IL_0acf: Unknown result type (might be due to invalid IL or missing references) //IL_0ad9: Expected O, but got Unknown //IL_0b0c: Unknown result type (might be due to invalid IL or missing references) //IL_0b16: Expected O, but got Unknown //IL_0b49: Unknown result type (might be due to invalid IL or missing references) //IL_0b53: Expected O, but got Unknown //IL_0b86: Unknown result type (might be due to invalid IL or missing references) //IL_0b90: Expected O, but got Unknown //IL_0bc3: Unknown result type (might be due to invalid IL or missing references) //IL_0bcd: Expected O, but got Unknown //IL_0c00: Unknown result type (might be due to invalid IL or missing references) //IL_0c0a: Expected O, but got Unknown //IL_0c3d: Unknown result type (might be due to invalid IL or missing references) //IL_0c47: Expected O, but got Unknown //IL_0c7a: Unknown result type (might be due to invalid IL or missing references) //IL_0c84: Expected O, but got Unknown //IL_0cb7: Unknown result type (might be due to invalid IL or missing references) //IL_0cc1: Expected O, but got Unknown //IL_0cf4: Unknown result type (might be due to invalid IL or missing references) //IL_0cfe: Expected O, but got Unknown //IL_0d1f: Unknown result type (might be due to invalid IL or missing references) //IL_0d29: Expected O, but got Unknown //IL_0d5c: Unknown result type (might be due to invalid IL or missing references) //IL_0d66: Expected O, but got Unknown //IL_0d99: Unknown result type (might be due to invalid IL or missing references) //IL_0da3: Expected O, but got Unknown //IL_0dd6: Unknown result type (might be due to invalid IL or missing references) //IL_0de0: Expected O, but got Unknown //IL_0e01: Unknown result type (might be due to invalid IL or missing references) //IL_0e0b: Expected O, but got Unknown //IL_0e3e: Unknown result type (might be due to invalid IL or missing references) //IL_0e48: Expected O, but got Unknown //IL_0e7b: Unknown result type (might be due to invalid IL or missing references) //IL_0e85: Expected O, but got Unknown //IL_0ea6: Unknown result type (might be due to invalid IL or missing references) //IL_0eb0: Expected O, but got Unknown //IL_0ee3: Unknown result type (might be due to invalid IL or missing references) //IL_0eed: Expected O, but got Unknown //IL_0f20: Unknown result type (might be due to invalid IL or missing references) //IL_0f2a: Expected O, but got Unknown //IL_0f4b: Unknown result type (might be due to invalid IL or missing references) //IL_0f55: Expected O, but got Unknown //IL_0f88: Unknown result type (might be due to invalid IL or missing references) //IL_0f92: Expected O, but got Unknown //IL_0fc5: Unknown result type (might be due to invalid IL or missing references) //IL_0fcf: Expected O, but got Unknown //IL_0ff0: Unknown result type (might be due to invalid IL or missing references) //IL_0ffa: Expected O, but got Unknown //IL_101b: Unknown result type (might be due to invalid IL or missing references) //IL_1025: Expected O, but got Unknown //IL_1058: Unknown result type (might be due to invalid IL or missing references) //IL_1062: Expected O, but got Unknown //IL_1083: Unknown result type (might be due to invalid IL or missing references) //IL_108d: Expected O, but got Unknown //IL_10c0: Unknown result type (might be due to invalid IL or missing references) //IL_10ca: Expected O, but got Unknown //IL_10fd: Unknown result type (might be due to invalid IL or missing references) //IL_1107: Expected O, but got Unknown //IL_113a: Unknown result type (might be due to invalid IL or missing references) //IL_1144: Expected O, but got Unknown //IL_1177: Unknown result type (might be due to invalid IL or missing references) //IL_1181: Expected O, but got Unknown //IL_11b4: Unknown result type (might be due to invalid IL or missing references) //IL_11be: Expected O, but got Unknown //IL_11f1: Unknown result type (might be due to invalid IL or missing references) //IL_11fb: Expected O, but got Unknown //IL_122e: Unknown result type (might be due to invalid IL or missing references) //IL_1238: Expected O, but got Unknown //IL_126b: Unknown result type (might be due to invalid IL or missing references) //IL_1275: Expected O, but got Unknown //IL_12a8: Unknown result type (might be due to invalid IL or missing references) //IL_12b2: Expected O, but got Unknown //IL_12e5: Unknown result type (might be due to invalid IL or missing references) //IL_12ef: Expected O, but got Unknown //IL_1322: Unknown result type (might be due to invalid IL or missing references) //IL_132c: Expected O, but got Unknown //IL_135f: Unknown result type (might be due to invalid IL or missing references) //IL_1369: Expected O, but got Unknown //IL_139c: Unknown result type (might be due to invalid IL or missing references) //IL_13a6: Expected O, but got Unknown //IL_13d9: Unknown result type (might be due to invalid IL or missing references) //IL_13e3: Expected O, but got Unknown //IL_1416: Unknown result type (might be due to invalid IL or missing references) //IL_1420: Expected O, but got Unknown //IL_1453: Unknown result type (might be due to invalid IL or missing references) //IL_145d: Expected O, but got Unknown //IL_1490: Unknown result type (might be due to invalid IL or missing references) //IL_149a: Expected O, but got Unknown //IL_14cd: Unknown result type (might be due to invalid IL or missing references) //IL_14d7: Expected O, but got Unknown //IL_150a: Unknown result type (might be due to invalid IL or missing references) //IL_1514: Expected O, but got Unknown //IL_1547: Unknown result type (might be due to invalid IL or missing references) //IL_1551: Expected O, but got Unknown //IL_1584: Unknown result type (might be due to invalid IL or missing references) //IL_158e: Expected O, but got Unknown //IL_15c1: Unknown result type (might be due to invalid IL or missing references) //IL_15cb: Expected O, but got Unknown //IL_15fe: Unknown result type (might be due to invalid IL or missing references) //IL_1608: Expected O, but got Unknown //IL_163b: Unknown result type (might be due to invalid IL or missing references) //IL_1645: Expected O, but got Unknown //IL_1678: Unknown result type (might be due to invalid IL or missing references) //IL_1682: Expected O, but got Unknown //IL_16b5: Unknown result type (might be due to invalid IL or missing references) //IL_16bf: Expected O, but got Unknown //IL_16f2: Unknown result type (might be due to invalid IL or missing references) //IL_16fc: Expected O, but got Unknown //IL_172f: Unknown result type (might be due to invalid IL or missing references) //IL_1739: Expected O, but got Unknown //IL_176c: Unknown result type (might be due to invalid IL or missing references) //IL_1776: Expected O, but got Unknown //IL_1797: Unknown result type (might be due to invalid IL or missing references) //IL_17a1: Expected O, but got Unknown //IL_17d4: Unknown result type (might be due to invalid IL or missing references) //IL_17de: Expected O, but got Unknown //IL_1811: Unknown result type (might be due to invalid IL or missing references) //IL_181b: Expected O, but got Unknown //IL_183c: Unknown result type (might be due to invalid IL or missing references) //IL_1846: Expected O, but got Unknown //IL_1879: Unknown result type (might be due to invalid IL or missing references) //IL_1883: Expected O, but got Unknown //IL_18b6: Unknown result type (might be due to invalid IL or missing references) //IL_18c0: Expected O, but got Unknown //IL_18e1: Unknown result type (might be due to invalid IL or missing references) //IL_18eb: Expected O, but got Unknown //IL_191e: Unknown result type (might be due to invalid IL or missing references) //IL_1928: Expected O, but got Unknown //IL_195b: Unknown result type (might be due to invalid IL or missing references) //IL_1965: Expected O, but got Unknown //IL_1986: Unknown result type (might be due to invalid IL or missing references) //IL_1990: Expected O, but got Unknown //IL_19c3: Unknown result type (might be due to invalid IL or missing references) //IL_19cd: Expected O, but got Unknown //IL_1a00: Unknown result type (might be due to invalid IL or missing references) //IL_1a0a: Expected O, but got Unknown //IL_1a2b: Unknown result type (might be due to invalid IL or missing references) //IL_1a35: Expected O, but got Unknown //IL_1a68: Unknown result type (might be due to invalid IL or missing references) //IL_1a72: Expected O, but got Unknown //IL_1aa5: Unknown result type (might be due to invalid IL or missing references) //IL_1aaf: Expected O, but got Unknown //IL_1ad0: Unknown result type (might be due to invalid IL or missing references) //IL_1ada: Expected O, but got Unknown //IL_1b0d: Unknown result type (might be due to invalid IL or missing references) //IL_1b17: Expected O, but got Unknown //IL_1b4a: Unknown result type (might be due to invalid IL or missing references) //IL_1b54: Expected O, but got Unknown //IL_1b75: Unknown result type (might be due to invalid IL or missing references) //IL_1b7f: Expected O, but got Unknown //IL_1bb2: Unknown result type (might be due to invalid IL or missing references) //IL_1bbc: Expected O, but got Unknown //IL_1bef: Unknown result type (might be due to invalid IL or missing references) //IL_1bf9: Expected O, but got Unknown //IL_1c2c: Unknown result type (might be due to invalid IL or missing references) //IL_1c36: Expected O, but got Unknown //IL_1c69: Unknown result type (might be due to invalid IL or missing references) //IL_1c73: Expected O, but got Unknown //IL_1ca6: Unknown result type (might be due to invalid IL or missing references) //IL_1cb0: Expected O, but got Unknown //IL_1ce3: Unknown result type (might be due to invalid IL or missing references) //IL_1ced: Expected O, but got Unknown //IL_1d20: Unknown result type (might be due to invalid IL or missing references) //IL_1d2a: Expected O, but got Unknown //IL_1d5d: Unknown result type (might be due to invalid IL or missing references) //IL_1d67: Expected O, but got Unknown //IL_1d9a: Unknown result type (might be due to invalid IL or missing references) //IL_1da4: Expected O, but got Unknown //IL_1dcc: Unknown result type (might be due to invalid IL or missing references) //IL_1dd6: Expected O, but got Unknown //IL_1dfe: Unknown result type (might be due to invalid IL or missing references) //IL_1e08: Expected O, but got Unknown //IL_1e3b: Unknown result type (might be due to invalid IL or missing references) //IL_1e45: Expected O, but got Unknown //IL_1e78: Unknown result type (might be due to invalid IL or missing references) //IL_1e82: Expected O, but got Unknown //IL_1eb5: Unknown result type (might be due to invalid IL or missing references) //IL_1ebf: Expected O, but got Unknown //IL_1ef2: Unknown result type (might be due to invalid IL or missing references) //IL_1efc: Expected O, but got Unknown //IL_1f2f: Unknown result type (might be due to invalid IL or missing references) //IL_1f39: Expected O, but got Unknown //IL_1f6c: Unknown result type (might be due to invalid IL or missing references) //IL_1f76: Expected O, but got Unknown //IL_1fa9: Unknown result type (might be due to invalid IL or missing references) //IL_1fb3: Expected O, but got Unknown //IL_1fe6: Unknown result type (might be due to invalid IL or missing references) //IL_1ff0: Expected O, but got Unknown //IL_2023: Unknown result type (might be due to invalid IL or missing references) //IL_202d: Expected O, but got Unknown //IL_2060: Unknown result type (might be due to invalid IL or missing references) //IL_206a: Expected O, but got Unknown //IL_209d: Unknown result type (might be due to invalid IL or missing references) //IL_20a7: Expected O, but got Unknown //IL_20da: Unknown result type (might be due to invalid IL or missing references) //IL_20e4: Expected O, but got Unknown //IL_2117: Unknown result type (might be due to invalid IL or missing references) //IL_2121: Expected O, but got Unknown //IL_2154: Unknown result type (might be due to invalid IL or missing references) //IL_215e: Expected O, but got Unknown //IL_2180: Unknown result type (might be due to invalid IL or missing references) //IL_218a: Expected O, but got Unknown //IL_21bd: Unknown result type (might be due to invalid IL or missing references) //IL_21c7: Expected O, but got Unknown //IL_21f0: Unknown result type (might be due to invalid IL or missing references) //IL_21fa: Expected O, but got Unknown //IL_222d: Unknown result type (might be due to invalid IL or missing references) //IL_2237: Expected O, but got Unknown //IL_2260: Unknown result type (might be due to invalid IL or missing references) //IL_226a: Expected O, but got Unknown //IL_229d: Unknown result type (might be due to invalid IL or missing references) //IL_22a7: Expected O, but got Unknown //IL_22d0: Unknown result type (might be due to invalid IL or missing references) //IL_22da: Expected O, but got Unknown //IL_230d: Unknown result type (might be due to invalid IL or missing references) //IL_2317: Expected O, but got Unknown //IL_2340: Unknown result type (might be due to invalid IL or missing references) //IL_234a: Expected O, but got Unknown //IL_237d: Unknown result type (might be due to invalid IL or missing references) //IL_2387: Expected O, but got Unknown //IL_23ba: Unknown result type (might be due to invalid IL or missing references) //IL_23c4: Expected O, but got Unknown //IL_23f7: Unknown result type (might be due to invalid IL or missing references) //IL_2401: Expected O, but got Unknown //IL_2434: Unknown result type (might be due to invalid IL or missing references) //IL_243e: Expected O, but got Unknown //IL_2467: Unknown result type (might be due to invalid IL or missing references) //IL_2471: Expected O, but got Unknown //IL_24a4: Unknown result type (might be due to invalid IL or missing references) //IL_24ae: Expected O, but got Unknown //IL_24d7: Unknown result type (might be due to invalid IL or missing references) //IL_24e1: Expected O, but got Unknown //IL_2514: Unknown result type (might be due to invalid IL or missing references) //IL_251e: Expected O, but got Unknown //IL_2551: Unknown result type (might be due to invalid IL or missing references) //IL_255b: Expected O, but got Unknown //IL_258e: Unknown result type (might be due to invalid IL or missing references) //IL_2598: Expected O, but got Unknown //IL_25c0: Unknown result type (might be due to invalid IL or missing references) //IL_25ca: Expected O, but got Unknown //IL_25f3: Unknown result type (might be due to invalid IL or missing references) //IL_25fd: Expected O, but got Unknown //IL_2630: Unknown result type (might be due to invalid IL or missing references) //IL_263a: Expected O, but got Unknown //IL_2663: Unknown result type (might be due to invalid IL or missing references) //IL_266d: Expected O, but got Unknown //IL_26a0: Unknown result type (might be due to invalid IL or missing references) //IL_26aa: Expected O, but got Unknown //IL_26cb: Unknown result type (might be due to invalid IL or missing references) //IL_26d6: Expected O, but got Unknown //IL_26f7: Unknown result type (might be due to invalid IL or missing references) //IL_2702: Expected O, but got Unknown //IL_2723: Unknown result type (might be due to invalid IL or missing references) //IL_272e: Expected O, but got Unknown //IL_274f: Unknown result type (might be due to invalid IL or missing references) //IL_275a: Expected O, but got Unknown //IL_277b: Unknown result type (might be due to invalid IL or missing references) //IL_2786: Expected O, but got Unknown //IL_27a7: Unknown result type (might be due to invalid IL or missing references) //IL_27b2: Expected O, but got Unknown //IL_27d3: Unknown result type (might be due to invalid IL or missing references) //IL_27de: Expected O, but got Unknown //IL_27ff: Unknown result type (might be due to invalid IL or missing references) //IL_280a: Expected O, but got Unknown //IL_282b: Unknown result type (might be due to invalid IL or missing references) //IL_2836: Expected O, but got Unknown //IL_2857: Unknown result type (might be due to invalid IL or missing references) //IL_2862: Expected O, but got Unknown //IL_2895: Unknown result type (might be due to invalid IL or missing references) //IL_28a0: Expected O, but got Unknown configSync = new ConfigSync("maxfoxgaming.environmentalawareness") { DisplayName = "EnvironmentalAwareness", CurrentVersion = "1.2.7", MinimumRequiredVersion = "1.2.7" }; plugin.Config.SaveOnConfigSet = true; ConfigLocked = plugin.Config.BindServer(ZerA, "Config Locked", value: true, new ConfigDescription("If enabled, the configuration is locked and can only be changed by server admins.", (AcceptableValueBase)null, Array.Empty())); configSync.AddLockingConfigEntry(ConfigLocked); DebugLogging = plugin.Config.BindServerSubscribe(ZerA, "Logs Enabled", value: false, new ConfigDescription("Whether the mod should print outputs and data to the console. Only needed for debugging.", (AcceptableValueBase)null, Array.Empty())); DebugUpdateTime = plugin.Config.BindServerSubscribe(ZerA, "Time Between Logging Updates", 30f, new ConfigDescription("If logging is enabled, this determines how often full status updates are pushed to the console.", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 300f), Array.Empty())); ShowDebugValueInSE = plugin.Config.BindServerSubscribe(ZerA, "Status Effect Debug", value: false, new ConfigDescription("Whether advanced information about status effects added by this mod are shown in the status effect window. Only needed for debugging.", (AcceptableValueBase)null, Array.Empty())); SavingEnabled = plugin.Config.BindServerSubscribe(ZerA, "Status Saving Enabled", value: true, new ConfigDescription("If enabled, logging out will save stat information to the player character.", (AcceptableValueBase)null, Array.Empty())); VitalityEnabled = plugin.Config.BindServerSubscribe(ZerA, "Vitality & Resistance Enabled", value: true, new ConfigDescription("If enabled, the player will have the Vitality status effect which reacts to their environment, and a Resistance skill that allows them to whithstand drops in vitality as it levels up.", (AcceptableValueBase)null, Array.Empty())); EnergyEnabled = plugin.Config.BindServerSubscribe(ZerA, "Energy & Fitness Enabled", value: true, new ConfigDescription("If enabled, the player will have the Energy status effect which reacts to their physical activities, and a Fitness skill that allows them to whithstand drops in energy as it levels up.", (AcceptableValueBase)null, Array.Empty())); CapabilityEnabled = plugin.Config.BindServerSubscribe(ZerA, "Capability & Perseverence Enabled", value: true, new ConfigDescription("If enabled, the player will have the Capability status effect which slowly deteriorates as the player stays awake longer, and a Perseverence skill that allows them to stay awake longer before negative effects occur.", (AcceptableValueBase)null, Array.Empty())); HungerEnabled = plugin.Config.BindServerSubscribe(ZerA, "Hunger Enabled", value: true, new ConfigDescription("If enabled, the player will get a Hungry status effect when they have no food and have not eaten for a set time. This status effect is purely for display purposes, to help alert the player to eat when needed.", (AcceptableValueBase)null, Array.Empty())); HungerTime = plugin.Config.BindServerSubscribe(ZerA, "Time Since Eating for Hunger", 180, new ConfigDescription("If Hunger is enabled, it will be applied to the player after this length of time since they fully digested their last food item.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 600), Array.Empty())); OverheatingEnabled = plugin.Config.BindServerSubscribe(ZerA, "Overheating Enabled", value: true, new ConfigDescription("If enabled, two new status effects 'Hot' and 'Scorching' will be added. BEWARE this will make the Ashlands BRUTAL. If no season mod is installed, the player will be 'Hot' in the Plains on clear/cloudy afternoons and in the Ashlands at night. The player will be 'Scorching' in the Ashlands during the day. If a seasons mod is installed, the player will be 'Hot' in clear/cloudy weather in the Meadows amd Black Forest in Summer, Ashland nights all year round, Ashland days in Winter, and Plains in Spring and Summer, and 'Scorching' in the Plains in Summer afternoons amd Ashlands during Spring, Summer and Autumn days. These are offset by fire resistance meads and gear.", (AcceptableValueBase)null, Array.Empty())); NewPlayerCooldown = plugin.Config.BindServerSubscribe(ZerA, "New Player Immunity", 300f, new ConfigDescription("New characters who have not picked up items will spawn in with an immunity to energy and vitality loss. The immunity will wear off after this amount of time.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1200f), Array.Empty())); DeathGrantsImmunity = plugin.Config.BindServerSubscribe(ZerA, "Death Grants Immunity", value: true, new ConfigDescription("If the player has died, effects of vitality and energy loss will not start until the player's No Skill Drain buff ends.", (AcceptableValueBase)null, Array.Empty())); GlobalKeySpring = plugin.Config.BindServerSubscribe(ZerB, "Global Key for Spring", "season_spring", new ConfigDescription("If a seasons mod is installed such as Seasonality or Seasons, what global key is used to represent Spring. Note that for Shudnal's Seasons mod, you must turn on seasonal global keys. It is on by default in Seasonality.", (AcceptableValueBase)null, Array.Empty())); GlobalKeySummer = plugin.Config.BindServerSubscribe(ZerB, "Global Key for Summer", "season_summer", new ConfigDescription("If a seasons mod is installed such as Seasonality or Seasons, what global key is used to represent Summer. Note that for Shudnal's Seasons mod, you must turn on seasonal global keys. It is on by default in Seasonality.", (AcceptableValueBase)null, Array.Empty())); GlobalKeyFall = plugin.Config.BindServerSubscribe(ZerB, "Global Key for Fall", "season_fall", new ConfigDescription("If a seasons mod is installed such as Seasonality or Seasons, what global key is used to represent Fall. Note that for Shudnal's Seasons mod, you must turn on seasonal global keys. It is on by default in Seasonality.", (AcceptableValueBase)null, Array.Empty())); GlobalKeyWinter = plugin.Config.BindServerSubscribe(ZerB, "Global Key for Winter", "season_winter", new ConfigDescription("If a seasons mod is installed such as Seasonality or Seasons, what global key is used to represent Winter. Note that for Shudnal's Seasons mod, you must turn on seasonal global keys. It is on by default in Seasonality.", (AcceptableValueBase)null, Array.Empty())); VColdAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss when Cold", 0.045f, new ConfigDescription("How much vitality is lost when the environment is cold.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VFreezingAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss when Freezing", 0.155f, new ConfigDescription("How much vitality is lost when the environment is freezing.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VHotAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss when Hot", 0.02f, new ConfigDescription("How much vitality is lost when the environment is hot. This will only apply if Overheating is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VScorchingAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss when Scorching", 0.095f, new ConfigDescription("How much vitality is lost when the environment is scorching. This will only apply if Overheating is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VWetAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss when Wet", 0.035f, new ConfigDescription("How much vitality is lost when the player is wet.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VColdWetMultiplier = plugin.Config.BindServerSubscribe(OneA, "Wet and Cold Multiplier", 1.25f, new ConfigDescription("If the player is both wet and the environment is cold, vitality loss gets multiplied by this amount after resistances. A value of 1 does nothing.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); VFreezingWetMultiplier = plugin.Config.BindServerSubscribe(OneA, "Wet and Freezing Multiplier", 1.55f, new ConfigDescription("If the player is both wet and the environment is freezing, vitality loss gets multiplied by this amount after resistances. A value of 1 does nothing.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); VHungerAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss when Hungry", 0.25f, new ConfigDescription("If the player has not eaten and has no food slots filled, this value will be added to the vitality loss, bypassing all resistances. A value of 0 disables this feature. If you have enabled the Hunger status effect and associated timer before the player gets hungry, the Vitality loss will only occur once the player has the Hungry status effect.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VHPDamageAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss per HP of Damage", 0.005f, new ConfigDescription("How much vitality is lost per health point of damage sustained by the player. This number is VERY sensitive. A value of 0 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.1f), Array.Empty())); VMissingHPAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss when HP at 0%", 0.08f, new ConfigDescription("When the player's HP bar is not full, this is the rate at which Vitality will drop, reaching this value when HP is at 0%. The vitality loss will not apply for 60s after the player has eaten to allow their HP to recover first. A value of 0 disables this effect.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VPoisonDamageAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss from Poison", 0.24f, new ConfigDescription("How much vitality is lost when the player is poisoned. Affected by poison resistance. A value of 0 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VBurningDamageAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss from Burning", 0.2f, new ConfigDescription("How much vitality is lost when the player is on fire. Affected by fire resistance. A value of 0 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VFrostDamageAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss from Frozen", 0.15f, new ConfigDescription("How much vitality is lost when the player is frozen. Affected by frost resistance. A value of 0 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VShockDamageAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality loss from Shocked", 0.3f, new ConfigDescription("How much vitality is lost when the player is shocked. Affected by lightning resistance. A value of 0 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VAshlandsPassiveAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss from being in Ashlands", 0.2f, new ConfigDescription("How much vitality is lost when the player is in the Ashlands. A value of 0 disables this effect..", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VDeepNorthPassiveAdd = plugin.Config.BindServerSubscribe(OneA, "Vitality Loss from being in Deep North", 0.2f, new ConfigDescription("How much vitality is lost when the player is in the Deep North. A value of 0 disables this effect.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VEnvironmentsToIgnore = plugin.Config.BindServerSubscribe(OneA, "Environments that Bypass Vitality Loss", "Eikthyr,GDKing,Bonemass,Moder,GoblinKing,Queen,Fader", new ConfigDescription("A comma separated list of environments that will not affect the player's vitality negatively.", (AcceptableValueBase)null, Array.Empty())); VIgnoredEnvironments = new List(VEnvironmentsToIgnore.Value.Split(new char[1] { ',' })); VSpringSeasonalMultiplier = plugin.Config.BindServerSubscribe(OneA, "Multiplier to Vitality Loss during Spring", 0.95f, new ConfigDescription("If a seasons mod is installed, this number is multiplied by the final vitality loss during Spring. A value of 0 means no vitality will be lost in spring. A value of 1 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); VSummerSeasonalMultiplier = plugin.Config.BindServerSubscribe(OneA, "Multiplier to Vitality Loss during Summer", 0.75f, new ConfigDescription("If a seasons mod is installed, this number is multiplied by the final vitality loss during Summer. A value of 0 means no vitality will be lost in summer. A value of 1 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); VFallSeasonalMultiplier = plugin.Config.BindServerSubscribe(OneA, "Multiplier to Vitality Loss during Fall", 1.15f, new ConfigDescription("If a seasons mod is installed, this number is multiplied by the final vitality loss during Fall. A value of 0 means no vitality will be lost in fall. A value of 1 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); VWinterSeasonalMultiplier = plugin.Config.BindServerSubscribe(OneA, "Multiplier to Vitality Loss during Winter", 1.45f, new ConfigDescription("If a seasons mod is installed, this number is multiplied by the final vitality loss during Winter. A value of 0 means no vitality will be lost in winter. A value of 1 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); VHeatRemove = plugin.Config.BindServerSubscribe(OneB, "Vitality Recovered when Warm", 0.25f, new ConfigDescription("How much vitality is recovered when the player is by a fire or warm.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VShelteredRemove = plugin.Config.BindServerSubscribe(OneB, "Vitality Recovered when Sheltered", 0.25f, new ConfigDescription("How much vitality is recovered when the player is sheltered.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VHeatShelteredMultiplier = plugin.Config.BindServerSubscribe(OneB, "Warm and Sheltered Multiplier", 1.25f, new ConfigDescription("If the player is both warm and sheltered, multiplies how much vitality is recovered from heat and shelter. A value of 1 does nothing.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); VRestingRemove = plugin.Config.BindServerSubscribe(OneB, "Vitality Recovered when Resting", 0.1f, new ConfigDescription("How much vitality is recovered when the player is resting.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VRestedRemove = plugin.Config.BindServerSubscribe(OneB, "Vitality Recovered when Rested", 0.005f, new ConfigDescription("How much vitality is recovered while the player has Rested.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VPassiveRemove = plugin.Config.BindServerSubscribe(OneB, "Passive Vitality Recovery", 0.005f, new ConfigDescription("How much vitality is recovered passively when the player is not in unfavourable conditions.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VHealthPotionRemove = plugin.Config.BindServerSubscribe(OneB, "Vitality Recovered from Health Meads", 0.1f, new ConfigDescription("How much vitality is recovered per second while a health potion is active. A value of 0 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VResistancePerArmorPoint = plugin.Config.BindServerSubscribe(OneC, "Armor Point Multiplier", 0.994f, new ConfigDescription("Per armor point, a multiplier applied to vitality loss. A value of 1 does nothing. NOTE: This number is VERY sensitive. 0.995 will reduce vitality loss to 60% of its original value", (AcceptableValueBase)(object)new AcceptableValueRange(0.95f, 1f), Array.Empty())); VResistanceMinArmorThreshold = plugin.Config.BindServerSubscribe(OneC, "Armor Point Threshold", 50, new ConfigDescription("How many armor points are needed before the armor point multiplier begins to apply.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 200), Array.Empty())); VResistanceStaffOfProtection = plugin.Config.BindServerSubscribe(OneC, "Staff of Protection Multiplier", 0.65f, new ConfigDescription("If the player has the Staff of Protection effect, vitality loss will be multiplied by this value. A value of 1 does nothing. A value of 0 will make the player completely immune to vitality loss from the environment while the shield is active.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VPoisonResistantMultiplier = plugin.Config.BindServerSubscribe(OneC, "Resistant vs Poison Multiplier", 0.65f, new ConfigDescription("If the player has Resistant vs Poison, multiplies the amount added from poison damage by this number. A value of 1 has no effect. A value of 0 means resistant stops vitality loss from being poisoned.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VPoisonVeryResistantMultiplier = plugin.Config.BindServerSubscribe(OneC, "Very Resistant vs Poison Multiplier", 0.25f, new ConfigDescription("If the player has Very Resistant vs Poison, multiplies the amount added from poison damage by this number. A value of 1 has no effect. A value of 0 means very resistant stops vitality loss from being poisoned.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VFireResistantMultiplier = plugin.Config.BindServerSubscribe(OneC, "Resistant vs Fire Multiplier", 0.65f, new ConfigDescription("If the player has Resistant vs Fire, multiplies the amount added from burning, hot and scorching damage by this number. A value of 1 has no effect. A value of 0 means resistant stops vitality loss from being burned or being in the Ashlands.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VFireVeryResistantMultiplier = plugin.Config.BindServerSubscribe(OneC, "Very Resistant vs Fire Multiplier", 0.25f, new ConfigDescription("If the player has Very Resistant vs Fire, multiplies the amount added from burning, hot and scorching damage by this number. A value of 1 has no effect. A value of 0 means very resistant stops vitality loss from being burned or being in the Ashlands.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VLightningResistantMultiplier = plugin.Config.BindServerSubscribe(OneC, "Resistant vs Lightning Multiplier", 0.85f, new ConfigDescription("If the player has Resistant vs Lightning, multiplies the amount added from shock damage or by this number. A value of 1 has no effect. A value of 0 means resistant stops vitality loss from being shocked.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VLightningVeryResistantMultiplier = plugin.Config.BindServerSubscribe(OneC, "Very Resistant vs Lightning Multiplier", 0.7f, new ConfigDescription("If the player has Very Resistant vs Lightning, multiplies the amount added from shock damage by this number. A value of 1 has no effect. A value of 0 means very resistant stops vitality loss from being shocked.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VFrostResistantMultiplier = plugin.Config.BindServerSubscribe(OneC, "Resistant vs Frost Multiplier", 0.85f, new ConfigDescription("If the player has Resistant vs Frost, multiplies the amount added from cold and freezing by this number. A value of 1 has no effect. A value of 0 means resistant stops vitality loss from cold, freezing, being frozen, or being in the Deep North.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VFrostVeryResistantMultiplier = plugin.Config.BindServerSubscribe(OneC, "Very Resistant vs Frost Multiplier", 0.75f, new ConfigDescription("If the player has Very Resistant vs Frost, multiplies the amount added from cold and freezing by this number. A value of 1 has no effect. A value of 0 means very resistant stops vitality loss from cold, freezing, being frozen, or being in the Deep North.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VMultiplierPer10FoodValue = plugin.Config.BindServerSubscribe(OneC, "Resistance Multiplier per 10HP of Food", 0.984f, new ConfigDescription("For every 10HP granted by food, this value will be multiplied by vitality loss recursively. This number is VERY sensitive. Suggested leaving between 0.983 (40% resistance at +300HP) and 0.993 (20% resistance at +300HP). A value of 1 will disable this effect.", (AcceptableValueBase)(object)new AcceptableValueRange(0.95f, 1f), Array.Empty())); VHealthDamageEnabled = plugin.Config.BindServerSubscribe(OneD, "Health Damage Enabled", value: true, new ConfigDescription("Whether having low vitality will start to damage the player.", (AcceptableValueBase)null, Array.Empty())); VHealthMaxDamageOverTime = plugin.Config.BindServerSubscribe(OneD, "Damage per Tick at 0% Vitality", 10f, new ConfigDescription("How much damage is done to the player every damage tick when vitality is 0%.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); VHealthMaxRegenReduction = plugin.Config.BindServerSubscribe(OneD, "Health Regen Reduction at 0% Vitality", 1f, new ConfigDescription("How much health regen is affected when vitality is 0%.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VHealthDamageMinStartThreshold = plugin.Config.BindServerSubscribe(OneD, "Danage Start Threshold", 60f, new ConfigDescription("At what percentage lost vitality the player must be before they begin taking damage. Damage will scale up.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); VMoveSpeedReductionEnabled = plugin.Config.BindServerSubscribe(OneD, "Move Speed Reduction Enabled", value: true, new ConfigDescription("Whether having low vitality will start to reduce movement speed of the player.", (AcceptableValueBase)null, Array.Empty())); VMoveSpeedMaxReduction = plugin.Config.BindServerSubscribe(OneD, "Move Speed Reduction at 0% Vitality", 0.3f, new ConfigDescription("How much movement speed is taken when vitality is 0%.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.8f), Array.Empty())); VMoveSpeedMinStartThreshold = plugin.Config.BindServerSubscribe(OneD, "Move Speed Reduction Threshold", 50f, new ConfigDescription("At what percentage of lost vitality the player must be before they start to move slower. Speed will scale up.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); VStaminaRegenReductionEnabled = plugin.Config.BindServerSubscribe(OneD, "Stamina Regen Reduction Enabled", value: true, new ConfigDescription("Whether having low vitality will decrease the player's stamina regen speed.", (AcceptableValueBase)null, Array.Empty())); VStaminaRegenMaxReduction = plugin.Config.BindServerSubscribe(OneD, "Stamina Regen Reduction at 0% Vitality", 0.5f, new ConfigDescription("How much stamina regen is reduced when vitality is 0%. A value of 0 disables the effect. ", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.8f), Array.Empty())); VStaminaRegenReductionThreshold = plugin.Config.BindServerSubscribe(OneD, "Stamina Regen Reduction Threshold", 30f, new ConfigDescription("At what percentage of lost vitality the player must be before their stamina regen is affected. Regen will scale up.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); VFoodBurnRateEnabled = plugin.Config.BindServerSubscribe(OneD, "Food Burn Multiplier Enabled", value: true, new ConfigDescription("Whether having low vitality will affect how fast the player burns through their consumed food.", (AcceptableValueBase)null, Array.Empty())); VFoodBurnMaxOverTime = plugin.Config.BindServerSubscribe(OneD, "Food Burn Multiplier at 0% Vitality", 2f, new ConfigDescription("Food will get burned this much faster when vitality is 0%.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 20f), Array.Empty())); VFoodBurnMinStartThreshold = plugin.Config.BindServerSubscribe(OneD, "Food Burn Multiplier Threshold", 45f, new ConfigDescription("At what percentage of lost vitality the player must be before food burn rate increases. Burn rate will scale up.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); VFoodBurnStatReduction = plugin.Config.BindServerSubscribe(OneD, "Food Burn Stat Reduction", value: true, new ConfigDescription("Whether food burn should also lower its stats.", (AcceptableValueBase)null, Array.Empty())); VPhysicalWeaknessEnabled = plugin.Config.BindServerSubscribe(OneD, "Physical Weakness Enabled", value: true, new ConfigDescription("Whether having low vitality will make the player weak to physical damage.", (AcceptableValueBase)null, Array.Empty())); VPhysicalWeaknessThreshold = plugin.Config.BindServerSubscribe(OneD, "Physical Weakness Threshold", 70f, new ConfigDescription("At what percentage of lost vitality the player becomes weak to Blunt, Slash, Pierce damage.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); VElementalWeaknessEnabled = plugin.Config.BindServerSubscribe(OneD, "Elemental Weakness Enabled", value: true, new ConfigDescription("Whether having low vitality will make the player weak to elemental damage.", (AcceptableValueBase)null, Array.Empty())); VElementalWeaknessThreshold = plugin.Config.BindServerSubscribe(OneD, "Elemental Weakness Threshold", 80f, new ConfigDescription("At what percentage of lost vitality the player becomes weak to Fire, Frost, Shock and Poison damage.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ELossStaminaPointUsedAdd = plugin.Config.BindServerSubscribe(TwoA, "Energy Lost per Stamina Point", 0.074f, new ConfigDescription("How much energy is lost when you use one point of stamina. A value of 0 disables this effect.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.01f), Array.Empty())); ELossMotionAdd = plugin.Config.BindServerSubscribe(TwoA, "Energy Loss when Moving", 0.2f, new ConfigDescription("How much energy is lost per second when the player is moving.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossColdAdd = plugin.Config.BindServerSubscribe(TwoA, "Energy Loss when Cold", 0.015f, new ConfigDescription("How much energy is lost per second when the player is cold.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossFreezingAdd = plugin.Config.BindServerSubscribe(TwoA, "Energy Loss when Freezing", 0.03f, new ConfigDescription("How much energy is lost per second when the player is freezing.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossHotAdd = plugin.Config.BindServerSubscribe(TwoA, "Energy Loss when Hot", 0.04f, new ConfigDescription("How much energy is lost per second when the player is hot. This will only apply when Overheating is enabled", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossScorchingAdd = plugin.Config.BindServerSubscribe(TwoA, "Energy Loss when Scorching", 0.07f, new ConfigDescription("How much energy is lost per second when the player is scorching. This will only apply when Overheating is enabled", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossWetAdd = plugin.Config.BindServerSubscribe(TwoA, "Energy Loss when Wet", 0.01f, new ConfigDescription("How much energy is lost per second when the player is wet.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossHungryAdd = plugin.Config.BindServerSubscribe(TwoA, "Energy Loss when Hungry", 0.32f, new ConfigDescription("How much energy is lost per second when the player is hungry.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossHeavyLoadAdd = plugin.Config.BindServerSubscribe(TwoA, "Energy Loss when Carrying Heavy Load", 0.035f, new ConfigDescription("How much additional energy is lost per one point of stamina when the player has a heavy load.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossHeavyLoadThreshold = plugin.Config.BindServerSubscribe(TwoA, "Heavy Load Threshold", 60f, new ConfigDescription("At what percentage of your max carry weight is considered a heavy load.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ELossNoRestMultiplier = plugin.Config.BindServerSubscribe(TwoA, "Energy Loss Multiplier when Not Rested", 1.5f, new ConfigDescription("If the player is not rested, this multiplier will be applied to all sources of loss, scaling up with time.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 5f), Array.Empty())); ELossNoRestThreshold = plugin.Config.BindServerSubscribe(TwoA, "Not Rested Time Threshold", 600f, new ConfigDescription("After the player loases rest status, the amount of energy loss will increase slowly to its maximum in this amount of time, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange(120f, 1200f), Array.Empty())); ESpringSeasonMultiplier = plugin.Config.BindServerSubscribe(TwoA, "Multiplier to Energy Loss during Spring", 0.8f, new ConfigDescription("If a seasons mod is installed, this number is multiplied by the final Energy loss during Spring. A value of 0 means no energy will be lost in spring. A value of 1 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); ESummerSeasonMultiplier = plugin.Config.BindServerSubscribe(TwoA, "Multiplier to Energy Loss during Summer", 0.9f, new ConfigDescription("If a seasons mod is installed, this number is multiplied by the final Energy loss during Summer. A value of 0 means no energy will be lost in summer. A value of 1 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); EFallSeasonMultiplier = plugin.Config.BindServerSubscribe(TwoA, "Multiplier to Energy Loss during Fall", 1.1f, new ConfigDescription("If a seasons mod is installed, this number is multiplied by the final Energy loss during Fall. A value of 0 means no energy will be lost in fall. A value of 1 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); EWinterSeasonMultiplier = plugin.Config.BindServerSubscribe(TwoA, "Multiplier to Energy Loss during Winter", 1.2f, new ConfigDescription("If a seasons mod is installed, this number is multiplied by the final Energy loss during Winter. A value of 0 means no energy will be lost in winter. A value of 1 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); ELossSittingRemove = plugin.Config.BindServerSubscribe(TwoB, "Energy Recovered when Sitting", 0.3f, new ConfigDescription("How much energy is gained when the player is sitting but not resting.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossRestingRemove = plugin.Config.BindServerSubscribe(TwoB, "Energy Recovered when Resting", 0.5f, new ConfigDescription("How much energy is gained when the player is resting.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossSittingRestingMultiplier = plugin.Config.BindServerSubscribe(TwoB, "Multiplier when Sitting and Resting", 1.5f, new ConfigDescription("When the player is both sitting and resting, the recovery will be multiplied by this amount.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); ELossSittingRestingShelterMultiplier = plugin.Config.BindServerSubscribe(TwoB, "Multiplier when Sitting, Resting and Sheltered", 1.5f, new ConfigDescription("When the player is sitting, rested and in a shelter, the recovery will be multiplied by this amount", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); ELossRestedRemove = plugin.Config.BindServerSubscribe(TwoB, "Energy Recovered when Rested", 0.05f, new ConfigDescription("How much energy is gained when the player is rested.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossPercentageSleepRemove = plugin.Config.BindServerSubscribe(TwoB, "Energy Percentage Recovered after Sleep", 70f, new ConfigDescription("How much energy is regained after the player sleeps.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ELossFoodStaminaRemove = plugin.Config.BindServerSubscribe(TwoB, "Energy Recovered per Food Stamina", 0.5f, new ConfigDescription("How much energy is gained per stamina point of consumed food.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossStaminaMeadRemove = plugin.Config.BindServerSubscribe(TwoB, "Energy Recovered from Stamina Meads", 0.02f, new ConfigDescription("Percentage of energy regained per second when the player has a Stamina mead active.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.5f), Array.Empty())); ELossRestedResist = plugin.Config.BindServerSubscribe(TwoC, "Energy Loss Resistance when Rested", 0.2f, new ConfigDescription("When the player is Rested, the energy loss is multiplied by this amount. A value of 0 will remove all energy loss when rested.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossStaminaMeadResist = plugin.Config.BindServerSubscribe(TwoC, "Energy Loss Resistance from Stamina Meads", 0.4f, new ConfigDescription("When the player has used a stamina mead, they will resist this much energy loss during its duration.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ELossLowEnergyResist = plugin.Config.BindServerSubscribe(TwoC, "Energy Loss Resistance when Low", 0.7f, new ConfigDescription("As the player's energy gets lower, they will slowly gain a resistance to further losses to slow down the rate of debuffs. Setting this value to 0 disables this feature.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.8f), Array.Empty())); ELossLowEnergyThreshold = plugin.Config.BindServerSubscribe(TwoC, "Energy Loss Resistance Threshold", 50f, new ConfigDescription("At what percentage of lost energy the player must be before they start building a resistance to energy loss.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); EDamageReductionEnabled = plugin.Config.BindServerSubscribe(TwoD, "Damage Reduction Enabled", value: true, new ConfigDescription("Whether having low energy will start to affect the player's damage output to creatures and objects.", (AcceptableValueBase)null, Array.Empty())); EDamageMaxReduction = plugin.Config.BindServerSubscribe(TwoD, "Damage Reduction at 0%", 0.6f, new ConfigDescription("When Energy is at 0%, attack damage from the player will be reduced by this amount, gradually scaling up.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); EDamageReductionThreshold = plugin.Config.BindServerSubscribe(TwoD, "Damage Reduction Threshold", 50f, new ConfigDescription("At what percentage of lost energy the player must be before their damage is reduced.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ESkillGainReductionEnabled = plugin.Config.BindServerSubscribe(TwoD, "Skill Gain Reduction Enabled", value: true, new ConfigDescription("Whether having low energy will start to slow down skill gains.", (AcceptableValueBase)null, Array.Empty())); ESkillGainMaxReduction = plugin.Config.BindServerSubscribe(TwoD, "Skill Gain Reduction at 0%", 0.5f, new ConfigDescription("When Energy is at 0%, player skills will be slowed down by this amount, gradually scaling up.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ESkillGainReductionThreshold = plugin.Config.BindServerSubscribe(TwoD, "Skill Gain Reduction Threshold", 70f, new ConfigDescription("At what percentage of lost energy the player must be before their skills start to raise slower.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); EMaxStaminaReductionEnabled = plugin.Config.BindServerSubscribe(TwoD, "Max Stamina Reduction Enabled", value: true, new ConfigDescription("Whether having low energy will lower the player's maximum stamina.", (AcceptableValueBase)null, Array.Empty())); EMaxStaminaReduction = plugin.Config.BindServerSubscribe(TwoD, "Max Stamina Reduction at 0%", 0.5f, new ConfigDescription("This multiplier will be applied to the player's maximum stamina when their energy is at 0%.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); EMaxStaminaReductionThreshold = plugin.Config.BindServerSubscribe(TwoD, "Max Stamina Reduction Threshold", 40f, new ConfigDescription("At what percentage of lost energy the player must be before maximum stamina starts to decline.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); EStaminaRegenEnabled = plugin.Config.BindServerSubscribe(TwoD, "Stamina Regen Reduction Enabled", value: true, new ConfigDescription("Whether having low energy will affect the player's stamina regeneration.", (AcceptableValueBase)null, Array.Empty())); EStaminaRegenMaxReduction = plugin.Config.BindServerSubscribe(TwoD, "Stamina Regen Max Reduction", 0.6f, new ConfigDescription("When Energy is 0%, stamina regen is reduced by this amount.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); EStaminaRegenMinThreshold = plugin.Config.BindServerSubscribe(TwoD, "Stamina Regen Reduction Threshold", 60f, new ConfigDescription("At what percentage of lost energy the player must be before their stamina regen starts to be reduced.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); EStaminaRegenDelayEnabled = plugin.Config.BindServerSubscribe(TwoD, "Longer Stamina Delay Enabled", value: true, new ConfigDescription("Whether having low energy will lengthen the time for stamina to regenerate.", (AcceptableValueBase)null, Array.Empty())); EStaminaRegenDelayMaxMultiplier = plugin.Config.BindServerSubscribe(TwoD, "Longer Stamina Delay Time", 0.5f, new ConfigDescription("When Energy is at 0%, stamina regen delay will be increased by this amount of seconds.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); EStaminaRegenDelayMinThreshold = plugin.Config.BindServerSubscribe(TwoD, "Longer Stamina Delay Threshold", 35f, new ConfigDescription("At what percentage of lost energy the player must be before their stamina regen delay starst to increase.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); EMoveSpeedReductionEnabled = plugin.Config.BindServerSubscribe(TwoD, "Move Speed Reduction Enabled", value: true, new ConfigDescription("Whether having low energy will slow down player movement.", (AcceptableValueBase)null, Array.Empty())); EMoveSpeedMaxReduction = plugin.Config.BindServerSubscribe(TwoD, "Move Speed Max Reduction", 0.2f, new ConfigDescription("When Energy is 0%, how much slower the player will move.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.8f), Array.Empty())); EMoveSpeedReductionMinThreshold = plugin.Config.BindServerSubscribe(TwoD, "Move Speed Reduction Threshold", 80f, new ConfigDescription("At what percentage of lost energy the player will start to move slower.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ERestedLossEnabled = plugin.Config.BindServerSubscribe(TwoD, "Remove Rested Enabled", value: true, new ConfigDescription("Whether the Rested buff should be removed if the player's energy level is low.", (AcceptableValueBase)null, Array.Empty())); ERestedLossThreshold = plugin.Config.BindServerSubscribe(TwoD, "Remove Rested Threshold", 65f, new ConfigDescription("At what percentage of energy loss the player must be before the Rested status is removed.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CTimeToDrain = plugin.Config.BindServerSubscribe(FouA, "Base Capability Drain Time", 2700f, new ConfigDescription("Time for the player's Capability to drain completely after waking up.", (AcceptableValueBase)(object)new AcceptableValueRange(1800f, 7200f), Array.Empty())); CLowVitalityLoss = plugin.Config.BindServerSubscribe(FouA, "Capability loss at low Vitality", 1.1f, new ConfigDescription("When the player's Vitality is low, this multiplier will be applied to Capability loss.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 2f), Array.Empty())); CLowVitalityLossThreshold = plugin.Config.BindServerSubscribe(FouA, "Low Vitality Threshold", 50f, new ConfigDescription("When Vitality loss reaches this percentage or more, the multiplier will take effect.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CLowEnergyLoss = plugin.Config.BindServerSubscribe(FouA, "Capability loss at low Energy", 1.1f, new ConfigDescription("When the player's Energy is low, this multiplier will be applied to Capability loss.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 2f), Array.Empty())); CLowEnergyLossThreshold = plugin.Config.BindServerSubscribe(FouA, "Low Energy Threshold", 70f, new ConfigDescription("When Energy loss reaches this percentage or more, the multiplier will take effect.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CSleepLossRemove = plugin.Config.BindServerSubscribe(FouB, "Capability Recovered from Sleeping", 100f, new ConfigDescription("Percentage of the player's Capability recovered when sleeping.", (AcceptableValueBase)(object)new AcceptableValueRange(50f, 100f), Array.Empty())); CInBedLossRemove = plugin.Config.BindServerSubscribe(FouB, "Capability Recovered from Beds", 0.5f, new ConfigDescription("Percentage of the player's Capability recovered when laying in bed but not sleeping. Set to 0 to disable. ", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CTastyMeadLossRemove = plugin.Config.BindServerSubscribe(FouB, "Capability Recovered from Tasty Mead", 25f, new ConfigDescription("Percentage of the player's Capability recovered when drinking a Tasty Mead.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CTastyMeadLimit = plugin.Config.BindServerSubscribe(FouB, "Tasty Mead Allowance", 6, new ConfigDescription("This is the maximum number of Tasty Meads that the player can use to recover Capability before they stop having any effect. After this, the player must sleep.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 10), Array.Empty())); CTastyMeadSleepRemove = plugin.Config.BindServerSubscribe(FouB, "Tasty Mead Count Removal on Sleep", 3, new ConfigDescription("When sleeping, this amount of Tasty Mead is removed from the current allowance.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 10), Array.Empty())); CTastyMeadDigestionTime = plugin.Config.BindServerSubscribe(FouB, "Tasty Mead Digestion Time", 900, new ConfigDescription("How long it takes for the player to digest one Tasty Mead after drinking.", (AcceptableValueBase)(object)new AcceptableValueRange(300, 1800), Array.Empty())); CTastyMeadDigestionInBedMultiplier = plugin.Config.BindServerSubscribe(FouB, "Digestion Multiplier when in Bed", 5f, new ConfigDescription("When the player is laying in bed, but not sleeping, the digestion rate is multiplied by this amount.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); CRestedResist = plugin.Config.BindServerSubscribe(FouC, "Capability loss resistance when Rested", 0.966f, new ConfigDescription("If the player is Rested, this value is multiplied to their Capability loss. A value of 0 will make players immune to any loss when rested.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); CVitalityResist = plugin.Config.BindServerSubscribe(FouC, "Capability loss resistance with high Vitality", 0.966f, new ConfigDescription("If the player has high Vitality, this value is multiplied to their Capability loss. A value of 0 will make players immune to any loss when their vitality is high.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); CVitalityResistThreshold = plugin.Config.BindServerSubscribe(FouC, "High Vitality Threshold", 80f, new ConfigDescription("If the player has this percentage of Vitality or more, the resistance multiplier will apply.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CEnergyResist = plugin.Config.BindServerSubscribe(FouC, "Capability loss resistance with high Energy", 0.966f, new ConfigDescription("If the player has high Energy, this value is multiplied to their Capability loss. A value of 0 will make players immune to any loss when their energy is high.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); CEnergyResistThreshold = plugin.Config.BindServerSubscribe(FouC, "High Energy Threshold", 80f, new ConfigDescription("If the player has this percentage of Energy or more, the resistance multiplier will apply.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CVitalityMaxCap = plugin.Config.BindServerSubscribe(FouD, "Vitality Max Cap", 60f, new ConfigDescription("When the player's Capability is at 0%, their Vitality stat cannot go above this percentage.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CVitalityMaxCapThreshold = plugin.Config.BindServerSubscribe(FouD, "Vitality Cap Threshold", 70f, new ConfigDescription("Vitality cap will start coming into effect when the player has lost this percentage of Capability.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CEnergyMaxCap = plugin.Config.BindServerSubscribe(FouD, "Energy Max Cap", 10f, new ConfigDescription("When the player's Capability is at 0%, their Energy stat cannot go above this percentage.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); CEnergyMaxCapThreshold = plugin.Config.BindServerSubscribe(FouD, "Energy Cap Threshold", 50f, new ConfigDescription("Energy cap will start coming into effect when the player has lost this percentage of Capability.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ResistanceSkillEffectFactor = plugin.Config.BindServerSubscribe(FivA, "Resistance to Vitality Loss at level 100", 0.25f, new ConfigDescription("How much resistance is given to all vitality loss when the Resistance skill is level 100.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ResistanceSkillGainMinThreshold = plugin.Config.BindServerSubscribe(FivA, "Skill Gain Threshold", 40f, new ConfigDescription("Resistance skill will start to level up after this percentage of vitality is lost. A value of 100 will stop skill levelling up", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ResistanceSkillMissingHPDamageMultiplier = plugin.Config.BindServerSubscribe(FivA, "Damage Multiplier at 100% HP Loss at level 100", 1.4f, new ConfigDescription("When Resistance skill is at 100, this multiplier will apply to your damage dealt when HP is at 0%. A value of 1 does nothing.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 2f), Array.Empty())); ResistanceSkillMissingHPDamageMultiplierStartLevel = plugin.Config.BindServerSubscribe(FivA, "Damage Multiplier Min Level", 50, new ConfigDescription("At what Resistance level the player must be before extra damage multiplier is given.", (AcceptableValueBase)null, Array.Empty())); ResistanceSkillElementalMeadMultiplier = plugin.Config.BindServerSubscribe(FivA, "Elemental Mead Multiplier at level 100", 1.5f, new ConfigDescription("When the Resistance skill is at 100, this multiplier will apply to duration of any meads that grant resistance to elemental effects. A value of 1 disables this effect.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 3f), Array.Empty())); ResistanceSkillElementalMeadMultiplierStartLevel = plugin.Config.BindServerSubscribe(FivA, "Elemental Mead Multiplier Min Level", 20, new ConfigDescription("At what Resistance level the player must be before extra mead duration multiplier is given.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ResistanceSkillColdHotDebuffMitigationPerc = plugin.Config.BindServerSubscribe(FivA, "Cold & Hot Debuff Mitigation Percentage", 60f, new ConfigDescription("When the Resistance skill is at 100, this percentage of the negative traits of the Cold and Hot status effects will not apply. For example, setting this to 60% will make the Cold debuff only nerf health regen by 20% at level 100 instead of the usual 50%.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ResistanceSkillColdHotDebuffMitigationPercStartLevel = plugin.Config.BindServerSubscribe(FivA, "Cold & Hot Debuff Mitigation Min Level", 40, new ConfigDescription("At what Resistance level the player must be before the negaive traits of the Cold and Hot status effects will be affected.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ResistanceSkillFreezingScorchingDebuffMitigationPerc = plugin.Config.BindServerSubscribe(FivA, "Freezing & Scorching Debuff Mitigation Percentage", 50f, new ConfigDescription("When the Resistance skill is at 100, this percentage of the negative traits of the Freezing and Scorching status effects will not apply. For example, setting this to 50% will make the Freezing debuff only deal 0.5 damage per tick instead of the usual 1 damage.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ResistanceSkillFreezingScorchingDebuffMitigationPercStartLevel = plugin.Config.BindServerSubscribe(FivA, "Freezing & Scorching Debuff Mitigation Min Level", 70, new ConfigDescription("At what Resistance level the player must be before the negative traits of the Freezing and Scorching status effects will be affected.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ResistanceSkillWetDebuffMitigationPerc = plugin.Config.BindServerSubscribe(FivA, "Wet Debuff Mitigation Percentage", 80f, new ConfigDescription("When the Resistance skill is at 100, this percentage of the negative traits of the Wet status effect will not apply. For example, setting this to 80% will make the Wet debuff only nerf health regeneration by 5% instead of the usual 25%.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); ResistanceSkillWetDebuffMitigationPercStartLevel = plugin.Config.BindServerSubscribe(FivA, "Wet Debuff Mitigation Min Level", 40, new ConfigDescription("At what Resistance level the player must be before the negative traits of the Wet status effect will be affected.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ResistanceSkillGainFactor = plugin.Config.BindServerSubscribe(FivA, "Skill Gain Factor", 1f, new ConfigDescription("How quickly the skill will go up after the threshold is met. A value of 0 will stop all skill gain.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); FitnessSkillEffectFactor = plugin.Config.BindServerSubscribe(FivB, "Resistance to Energy Loss at level 100", 0.35f, new ConfigDescription("How much less energy is lost when using stamina when the Fitness skill is level 100.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); FitnessSkillMaxEnergyGain = plugin.Config.BindServerSubscribe(FivB, "Maximum Energy Capacity at level 100", 1000f, new ConfigDescription("Maximum energy capacity when the Fitness skill is level 100.", (AcceptableValueBase)(object)new AcceptableValueRange(100f, 5000f), Array.Empty())); FitnessSkillSpeedPenaltyRemove = plugin.Config.BindServerSubscribe(FivB, "Speed Penalty Removal Amount at level 100", 50f, new ConfigDescription("This percentage of all speed penalty is removed from the player when the Fitness skill is level 100.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); FitnessSkillSpeedPenaltyRemoveStartLevel = plugin.Config.BindServerSubscribe(FivB, "Speed Penalty Removal Min Level", 30, new ConfigDescription("At what Fitness level the player must be before speed penalties are affected.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); FitnessSkillFoodBurnMultiplier = plugin.Config.BindServerSubscribe(FivB, "Food Time Multiplier at Level 100", 1.3f, new ConfigDescription("This multiplier will apply to all of the player's consumed food when Fitness skill is at level 100.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 3f), Array.Empty())); FitnessSkillFoodBurnMultiplierStartLevel = plugin.Config.BindServerSubscribe(FivB, "Food Time Multiplier Min Level", 25, new ConfigDescription("At what Fitness level the player must be before food burn multipliers are affected.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); FitnessSkillGainFactor = plugin.Config.BindServerSubscribe(FivB, "Skill Gain Factor", 1f, new ConfigDescription("How quickly the skill will level up.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); PerseverenceSkillMaxTimeGain = plugin.Config.BindServerSubscribe(FivD, "Capability Time Gain at level 100", 2700f, new ConfigDescription("Maximum time in seconds before Capability drains when the Perseverence skill is level 100.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10800f), Array.Empty())); PerseverenceSkillMinThreshold = plugin.Config.BindServerSubscribe(FivD, "Skill Gain Threshold", 60f, new ConfigDescription("Perseverence skill will start to level up after this percentage of capability is lost. A value of 100 will stop skill levelling up.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); PerseverenceSkillComfortBonus = plugin.Config.BindServerSubscribe(FivD, "Comfort Bonus Gain at level 100", 3, new ConfigDescription("When Perseverence skill is at level 100, this bonus will be applied to the player's comfort level whenever they are in a place of comfort. A value of 0 disables this effect", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20), Array.Empty())); PerseverenceSkillComfortBonusStartLevel = plugin.Config.BindServerSubscribe(FivD, "Comfort Bonus Min Level", 30, new ConfigDescription("At what Perseverence level the player must be before extra comfort value can be applied.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); PerseverenceSkillMaxAdrenalineMultiplier = plugin.Config.BindServerSubscribe(FivD, "Adrenaline Reduction Multiplier at level 100", 0.3f, new ConfigDescription("When Perseverence skill is at level 100, the player's maximum adrenaline cap is multiplied by this value. The player will need to build up less adrenaline to use trinket effects. A value of 1 disables this effect.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 1f), Array.Empty())); PerseverenceSkillMaxAdrenalineMultiplierStartLevel = plugin.Config.BindServerSubscribe(FivD, "Adrenaline Reduction Multiplier Min Level", 50, new ConfigDescription("At what Perseverence level the player must be before maximum adrenaline multiplier starts to apply.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); PerseverenceSkillGainFactor = plugin.Config.BindServerSubscribe(FivD, "Skill Gain Factor", 1f, new ConfigDescription("How quickly the skill will level up.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); DisplayVitalityPercentage = plugin.Config.BindServer(Six, "Show Vitality Percentage", value: true, new ConfigDescription("Whether the player's vitality should be shown as a percentage below the status effect icon. Can disable for more immersion.", (AcceptableValueBase)null, Array.Empty()), synchronizedSetting: false); DisplayVitalityWarningTexts = plugin.Config.BindServer(Six, "Show Vitality Warning Messages", value: true, new ConfigDescription("When a debuff happens due to lowered vitality, the player can be shown a warning message about what stats are affected.", (AcceptableValueBase)null, Array.Empty()), synchronizedSetting: false); DisplayEnergyPercentage = plugin.Config.BindServer(Six, "Show Energy Percentage", value: true, new ConfigDescription("Whether the player's remaining energy should be shown as a percentage below the status effect icon. Can disable for more immersion.", (AcceptableValueBase)null, Array.Empty()), synchronizedSetting: false); DisplayEnergyWarningTexts = plugin.Config.BindServer(Six, "Show Energy Warning Messages", value: true, new ConfigDescription("When a debuff happens due to low energy, the player can be shown a warning message about what stats are affected.", (AcceptableValueBase)null, Array.Empty()), synchronizedSetting: false); DisplayCapabilityPercentage = plugin.Config.BindServer(Six, "Show Capability Percentage", value: true, new ConfigDescription("Whether the player's capability should be shown as a percentage below the status effect icon. Can disable for more immersion.", (AcceptableValueBase)null, Array.Empty()), synchronizedSetting: false); DisplayCapabilityWarningTexts = plugin.Config.BindServer(Six, "Show Capability Warning Messages", value: true, new ConfigDescription("When a debuff happens due to lowered capability, the player can be shown a warning message about what stats are affected.", (AcceptableValueBase)null, Array.Empty()), synchronizedSetting: false); DisplayEAEffectsOnDifferentHUD = plugin.Config.BindServer(Six, "Use Alternative HUD", value: false, new ConfigDescription("If enabled, all major status effects from this mod will be shown on a different HUD that can be repositioned.", (AcceptableValueBase)null, Array.Empty())); DisplayEAEffectsHUDIconLayout = plugin.Config.BindServer(Six, "HUD Icon Layout", HUDIconLayout.Horizontal, new ConfigDescription("Orient the icons of the HUD horizontally or vertically.", (AcceptableValueBase)null, Array.Empty())); DisplayEAEffectHUDX = plugin.Config.BindServer(Six, "HUD position X", 0, new ConfigDescription("Horizontal alignment for the HUD. Increasing this value will move it to the left.", (AcceptableValueBase)null, Array.Empty())); DisplayEAEffectHUDY = plugin.Config.BindServer(Six, "HUD position Y", 0, new ConfigDescription("Vertical alignment for the HUD. Increasing this value will move it upwards.", (AcceptableValueBase)null, Array.Empty())); DisplayEAEffectHUDScale = plugin.Config.BindServer(Six, "HUD Icon Size", 100f, new ConfigDescription("Scale for the HUD. A value of 100 is normal size.", (AcceptableValueBase)(object)new AcceptableValueRange(50f, 125f), Array.Empty())); } [NullableContext(1)] public static void OnConfigChanged(object sender, EventArgs e) { Main.GetInstance()?.InitializeSkills(); Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && ((Character)localPlayer).m_seman.HaveStatusEffect(SE_PlayerStats.Hash)) { SE_PlayerStats sE_PlayerStats = ((Character)localPlayer).m_seman.GetStatusEffect(SE_PlayerStats.Hash) as SE_PlayerStats; if (!((Object)(object)sE_PlayerStats == (Object)null)) { sE_PlayerStats.CleanupAndRemoveSurvivalEffects(); } } } [NullableContext(1)] public static void OnConfigChangedFromFile(object sender, EventArgs e) { if (!File.Exists(Paths.ConfigPath + "/maxfoxgaming.environmentalawareness.cfg")) { Main.LogMessage([NullableContext(1)] () => "Could not find file in path " + Paths.ConfigPath + "/maxfoxgaming.environmentalawareness.cfg"); return; } try { ((BaseUnityPlugin)Main.GetInstance()).Config.Reload(); } catch { Main.LogMessage([NullableContext(1)] () => "Error reloading " + Paths.ConfigPath + "/maxfoxgaming.environmentalawareness.cfg"); } } } public static class EnvManHelper { public enum Season { Spring, Summer, Fall, Winter, None } [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] private static List scorchingBossEnvironments = new List { "GoblinKing", "Fader" }; public static bool IsScorching() { //IL_0066: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Invalid comparison between Unknown and I4 //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Invalid comparison between Unknown and I4 if (!ConfigManager.OverheatingEnabled.Value) { return false; } EnvMan instance = EnvMan.instance; string item = ((instance == null) ? null : instance.GetCurrentEnvironment()?.m_name) ?? ""; if (scorchingBossEnvironments.Contains(item)) { return true; } EnvMan instance2 = EnvMan.instance; Biome val = (Biome)((instance2 != null) ? ((int)instance2.GetBiome()) : 0); if ((int)val == 32 && !EnvMan.IsNight() && GetSeason() != Season.Winter) { return true; } if (GetSeason() != Season.Summer) { return false; } if ((int)val != 16) { return false; } if (EnvMan.IsCold() || EnvMan.IsFreezing() || EnvMan.IsWet()) { return false; } EnvMan instance3 = EnvMan.instance; float num = ((instance3 != null) ? instance3.GetDayFraction() : 0f); return num >= 0.5f && num <= 0.65f; } public static bool IsHot() { //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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //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_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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Invalid comparison between Unknown and I4 //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Invalid comparison between Unknown and I4 if (!ConfigManager.OverheatingEnabled.Value) { return false; } EnvMan instance = EnvMan.instance; Biome val = (Biome)((instance != null) ? ((int)instance.GetBiome()) : 0); if ((int)val == 32) { return true; } if (EnvMan.IsCold() || EnvMan.IsFreezing() || EnvMan.IsWet()) { return false; } Season season = GetSeason(); EnvMan instance2 = EnvMan.instance; float num = ((instance2 != null) ? instance2.GetDayFraction() : 0f); Biome val2 = val; Biome val3 = val2; if ((int)val3 != 1) { if ((int)val3 != 8) { if ((int)val3 == 16) { if (season == Season.None || season == Season.Summer) { return (double)num >= 0.3 && (double)num <= 0.7; } if (season == Season.Spring) { return (double)num >= 0.5 && (double)num <= 0.65; } return false; } return false; } if (season == Season.Summer) { return (double)num >= 0.45 && (double)num <= 0.65; } return false; } if (season == Season.Summer) { return (double)num >= 0.45 && (double)num <= 0.65; } return false; } public static Season GetSeason() { ZoneSystem instance = ZoneSystem.instance; List list = ((instance != null) ? instance.GetGlobalKeys() : null) ?? new List(); if (list.Contains(ConfigManager.GlobalKeySpring.Value)) { return Season.Spring; } if (list.Contains(ConfigManager.GlobalKeySummer.Value)) { return Season.Summer; } if (list.Contains(ConfigManager.GlobalKeyFall.Value)) { return Season.Fall; } if (list.Contains(ConfigManager.GlobalKeyWinter.Value)) { return Season.Winter; } return Season.None; } } [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public static class Helper { public static List armorTypes = new List { (ItemType)6, (ItemType)17, (ItemType)7, (ItemType)11 }; public static ConfigEntry BindServerSubscribe<[<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] T>(this ConfigFile config, string group, string name, T value, ConfigDescription description) { ConfigEntry val = config.BindServer(group, name, value, description); val.SettingChanged += ConfigManager.OnConfigChanged; return val; } public static ConfigEntry BindServer<[<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] T>(this ConfigFile config, string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { ConfigEntry val = config.Bind(group, name, value, description); SyncedConfigEntry syncedConfigEntry = ConfigManager.configSync.AddConfigEntry(val); syncedConfigEntry.SynchronizedConfig = synchronizedSetting; return val; } public static void Insert<[<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] S, [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] T>(this Dictionary dictionary, S key, T value) { if (dictionary.ContainsKey(key)) { dictionary[key] = value; } else { dictionary.Add(key, value); } } public static void CheckState(this List list, bool state, string message) { if (state && !list.Contains(message)) { list.Add(message); } else { list.Remove(message); } } public static float GetSkillLevel(this Character character, int hash) { float result = 0f; Skills skills = character.GetSkills(); if ((Object)(object)skills == (Object)null) { return result; } if (skills.m_skillData.TryGetValue((SkillType)Mathf.Abs(hash), out var value)) { result = value.m_level; } return result; } public static bool IsEquippedArmor(this ItemDrop itemDrop) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) return armorTypes.Contains(itemDrop.m_itemData.m_shared.m_itemType) && itemDrop.m_itemData.m_equipped; } public static void AssignAsInt(this string str, out int value) { if (!int.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out value)) { throw new Exception("Could not parse " + str + " as int."); } } public static void AssignAsFloat(this string str, out float value) { if (!float.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out value)) { throw new Exception("Could not parse " + str + " as float."); } } public static void AssignAsBool(this string str, out bool value) { if (!bool.TryParse(str, out value)) { throw new Exception("Could not parse " + str + " as bool."); } } public static void AppendStat(this StringBuilder sb, int value) { sb.AppendFormat("{0}:", value.ToString(CultureInfo.InvariantCulture)); } public static void AppendStat(this StringBuilder sb, float value) { sb.AppendFormat("{0}:", value.ToString(CultureInfo.InvariantCulture)); } public static void AppendStat(this StringBuilder sb, bool value) { sb.AppendFormat("{0}:", value.ToString(CultureInfo.InvariantCulture)); } public static void AppendStat(this StringBuilder sb, string value) { sb.AppendFormat("{0}:", value.ToString(CultureInfo.InvariantCulture)); } public static bool Approximately(float a, float b, float e = 0.001f) { return Mathf.Abs(b - a) < e; } public static bool IntEqual(float a, float b) { return (int)a == (int)b; } } [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [NullableContext(1)] public class PlayerFoodCache { public Dictionary cache = new Dictionary(); public Player player; public int Count => cache.Count; protected string DataKey => "EnvironmentalAwareness_FoodCache"; public PlayerFoodCache(Player player) { this.player = player; } public void AddCurrentFoods() { if ((Object)(object)player == (Object)null) { return; } foreach (Food food in player.m_foods) { Add(food); } } public void RemoveDigestedFoods() { if ((Object)(object)player == (Object)null) { return; } List list = new List(); foreach (Food food in player.m_foods) { list.Add(food.m_name); } List list2 = cache.Keys.ToList(); List list3 = list.Intersect(list2).ToList(); List list4 = new List(); foreach (string item in list2) { if (!list3.Contains(item)) { list4.Add(item); } } foreach (string item2 in list4) { cache.Remove(item2); } if (list4.Count > 0) { SaveData(); } } public void Add(Food food) { string name = food.m_item.m_shared.m_name; PlayerFoodData value = new PlayerFoodData(food); if (cache.ContainsKey(name)) { cache.Remove(name); } cache.Add(name, value); } public void Add(ItemData itemData) { string name = itemData.m_shared.m_name; PlayerFoodData value = new PlayerFoodData(itemData); if (cache.ContainsKey(name)) { cache.Remove(name); } cache.Add(name, value); } public void Remove(string foodEntry) { if (Contains(foodEntry)) { cache.Remove(foodEntry); } } public void Remove(Food food) { Remove(food.m_name); } public bool Contains(string foodEntry) { return cache.ContainsKey(foodEntry); } public bool Contains(Food food) { return Contains(food.m_name); } public bool TryGetValue(Food food, [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] out PlayerFoodData data) { string name = food.m_item.m_shared.m_name; return TryGetValue(name, out data); } public bool TryGetValue(string foodName, [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(2)] out PlayerFoodData data) { return cache.TryGetValue(foodName, out data); } public void LoadData() { Main.LogMessage(() => "Loading data for Player Food Cache"); if ((Object)(object)player == (Object)null) { Main.LogMessage(() => "No player found. Cannot load data."); return; } if (!player.m_customData.TryGetValue(DataKey, out var data)) { Main.LogMessage(() => "No save data found for the player profile."); return; } if (string.IsNullOrEmpty(data)) { Main.LogMessage(() => "No save data found in entry " + DataKey); return; } Main.LogMessage(() => "Loaded data: " + data); try { LoadCacheFromDataString(data); } catch (Exception ex) { Exception ex2 = ex; Exception e = ex2; Main.LogMessage(() => "Could not parse data for " + DataKey + ". Cancelling load.\n" + e.Message); AddCurrentFoods(); } finally { SaveData(); } } private void LoadCacheFromDataString(string data) { List list = data.Split(new char[1] { '|' }).ToList(); foreach (string item in list) { List list2 = item.Split(new char[1] { '=' }).ToList(); if (list2.Count != 2) { throw new Exception("Could not parse " + item + "."); } cache.Add(list2[0], new PlayerFoodData(list2[1])); } } public void SaveData() { if ((Object)(object)player == (Object)null) { Main.LogMessage(() => "Could not save food cache data."); return; } string data = GetSaveString(); if (player.m_customData.TryGetValue(DataKey, out var _)) { Main.LogMessage(() => "Previous save data found. Replacing..."); player.m_customData.Remove(DataKey); } if (string.IsNullOrEmpty(data)) { Main.LogMessage(() => "No new data to save."); return; } player.m_customData.Add(DataKey, data); Main.LogMessage(() => "Saved data: " + data); } private string GetSaveString() { List list = new List(); foreach (KeyValuePair item in cache) { list.Add(item.Key + "=" + item.Value.GetSaveString()); } return string.Join("|", list); } } [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [NullableContext(1)] public class PlayerFoodData { public float m_health; public float m_stamina; public float m_eitr; public float m_time; public PlayerFoodData(Food food) { m_health = Mathf.Max(food.m_health, food.m_item.m_shared.m_food); m_stamina = Mathf.Max(food.m_stamina, food.m_item.m_shared.m_foodStamina); m_eitr = Mathf.Max(food.m_eitr, food.m_item.m_shared.m_foodEitr); m_time = Mathf.Max(food.m_time, food.m_item.m_shared.m_foodBurnTime); } public PlayerFoodData(ItemData itemData) { m_health = itemData.m_shared.m_food; m_stamina = itemData.m_shared.m_foodStamina; m_eitr = itemData.m_shared.m_foodEitr; m_time = itemData.m_shared.m_foodBurnTime; } public PlayerFoodData(string data) { List list = data.TrimStart(new char[1] { '(' }).TrimEnd(new char[1] { ')' }).Split(new char[1] { ';' }) .ToList(); if (list.Count != 4) { throw new Exception("Error parsing " + data + " to PlayerFoodData(string data)."); } if (!float.TryParse(list[0], out m_health)) { throw new Exception("Could not parse " + list[0] + " as float."); } if (!float.TryParse(list[1], out m_stamina)) { throw new Exception("Could not parse " + list[1] + " as float."); } if (!float.TryParse(list[2], out m_eitr)) { throw new Exception("Could not parse " + list[2] + " as float."); } if (!float.TryParse(list[3], out m_time)) { throw new Exception("Could not parse " + list[3] + " as float."); } } public string GetSaveString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append($"({m_health};{m_stamina};{m_eitr};{m_time})"); return stringBuilder.ToString(); } } [NullableContext(1)] [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public class SE_Stats_Modifiers { [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] public class SE_Stats_Modifier { public int m_statusHashCode; public SE_PlayerStats m_playerStats; public float m_originalHealthRegenMultiplier; public float m_currentHealthRegenMultiplier; public float m_originalStaminaRegenMultiplier; public float m_currentStaminaRegenMultiplier; public float m_originalEitrRegenMultiplier; public float m_currentEitrRegenMultiplier; public float m_originalSpeedModifier; public float m_currentSpeedModifier; public float m_originalHealthPerTick; public float m_currentHealthPerTick; public SE_Stats_Modifier(int hash, List originalModifiers, SE_PlayerStats playerStats) { ObjectDB instance = ObjectDB.instance; StatusEffect obj = ((instance != null) ? instance.GetStatusEffect(hash) : null); SE_Stats val = (SE_Stats)(object)((obj is SE_Stats) ? obj : null); m_statusHashCode = hash; m_playerStats = playerStats; m_originalHealthRegenMultiplier = val?.m_healthRegenMultiplier ?? originalModifiers[0]; m_originalStaminaRegenMultiplier = val?.m_staminaRegenMultiplier ?? originalModifiers[1]; m_originalEitrRegenMultiplier = val?.m_eitrRegenMultiplier ?? originalModifiers[2]; m_originalSpeedModifier = val?.m_speedModifier ?? originalModifiers[3]; m_originalHealthPerTick = val?.m_healthPerTick ?? originalModifiers[4]; m_currentHealthRegenMultiplier = m_originalHealthRegenMultiplier; m_currentStaminaRegenMultiplier = m_originalStaminaRegenMultiplier; m_currentEitrRegenMultiplier = m_originalEitrRegenMultiplier; m_currentSpeedModifier = m_originalSpeedModifier; m_currentHealthPerTick = m_originalHealthPerTick; } public void ApplyModifiedStatsToSE() { Player player = m_playerStats.player; StatusEffect obj = ((player != null) ? ((Character)player).m_seman.GetStatusEffect(m_statusHashCode) : null); SE_Stats val = (SE_Stats)(object)((obj is SE_Stats) ? obj : null); if (!((Object)(object)val == (Object)null)) { val.m_healthRegenMultiplier = m_currentHealthRegenMultiplier; val.m_staminaRegenMultiplier = m_currentStaminaRegenMultiplier; val.m_eitrRegenMultiplier = m_currentEitrRegenMultiplier; val.m_speedModifier = m_currentSpeedModifier; val.m_healthPerTick = m_currentHealthPerTick; } } public void CalculateModifiedEffects(int skillLevel, int startLevel, float modifier) { float num = Mathf.Clamp((float)(skillLevel - startLevel) / (100f - (float)startLevel), 0f, 1f); float num2 = modifier / 100f; float num3 = num * num2; float num4 = 1f - num3; float num5 = num3 * (1f - m_originalHealthRegenMultiplier); float num6 = num3 * (1f - m_originalStaminaRegenMultiplier); float num7 = num3 * (1f - m_originalEitrRegenMultiplier); float num8 = num3 * (-1f * m_originalHealthPerTick); m_currentHealthRegenMultiplier = m_originalHealthRegenMultiplier + num5; m_currentStaminaRegenMultiplier = m_originalStaminaRegenMultiplier + num6; m_currentEitrRegenMultiplier = m_originalEitrRegenMultiplier + num7; m_currentHealthPerTick = m_originalHealthPerTick + num8; m_currentSpeedModifier = m_originalSpeedModifier * num4; Main.LogMessage(() => "Modified Stats:\n" + $"Health Regen: {m_originalHealthRegenMultiplier} -> {m_currentHealthRegenMultiplier}\n" + $"Stamina Regen: {m_originalStaminaRegenMultiplier} -> {m_currentStaminaRegenMultiplier}\n" + $"Eitr Regen: {m_originalEitrRegenMultiplier} -> {m_currentEitrRegenMultiplier}\n" + $"Speed Modifier: {m_originalSpeedModifier} -> {m_currentSpeedModifier}\n" + $"Health Per Tick: {m_originalHealthPerTick} -> {m_currentHealthPerTick}"); } } private SE_PlayerStats m_playerStats; private List m_modifiers; public SE_Stats_Modifiers(SE_PlayerStats playerStats) { m_playerStats = playerStats; m_modifiers = new List { new SE_Stats_Modifier(SE_Scorching.Hash, new List { 0.2f, 0.5f, 0.5f, -0.2f, 0f }, m_playerStats), new SE_Stats_Modifier(SE_Hot.Hash, new List { 0.5f, 0.75f, 0.75f, -0.05f, 0f }, m_playerStats), new SE_Stats_Modifier(SEMan.s_statusEffectWet, new List { 0.75f, 0.85f, 0.85f, 0f, 0f }, m_playerStats), new SE_Stats_Modifier(SEMan.s_statusEffectCold, new List { 0.5f, 0.75f, 0.75f, 0f, 0f }, m_playerStats), new SE_Stats_Modifier(SEMan.s_statusEffectFreezing, new List { 0f, 0.4f, 0.4f, 0f, -1f }, m_playerStats) }; RecalculateAllModifiers(); } public void RecalculateAllModifiers() { m_modifiers[0]?.CalculateModifiedEffects((int)m_playerStats.ResistanceSkillLevel, ConfigManager.ResistanceSkillFreezingScorchingDebuffMitigationPercStartLevel.Value, ConfigManager.ResistanceSkillFreezingScorchingDebuffMitigationPerc.Value); m_modifiers[1]?.CalculateModifiedEffects((int)m_playerStats.ResistanceSkillLevel, ConfigManager.ResistanceSkillColdHotDebuffMitigationPercStartLevel.Value, ConfigManager.ResistanceSkillColdHotDebuffMitigationPerc.Value); m_modifiers[2]?.CalculateModifiedEffects((int)m_playerStats.ResistanceSkillLevel, ConfigManager.ResistanceSkillWetDebuffMitigationPercStartLevel.Value, ConfigManager.ResistanceSkillWetDebuffMitigationPerc.Value); m_modifiers[3]?.CalculateModifiedEffects((int)m_playerStats.ResistanceSkillLevel, ConfigManager.ResistanceSkillColdHotDebuffMitigationPercStartLevel.Value, ConfigManager.ResistanceSkillColdHotDebuffMitigationPerc.Value); m_modifiers[4]?.CalculateModifiedEffects((int)m_playerStats.ResistanceSkillLevel, ConfigManager.ResistanceSkillFreezingScorchingDebuffMitigationPercStartLevel.Value, ConfigManager.ResistanceSkillFreezingScorchingDebuffMitigationPerc.Value); } public void ApplyModifiersToActiveEffects() { foreach (SE_Stats_Modifier modifier in m_modifiers) { modifier.ApplyModifiedStatsToSE(); } } } } namespace EnvironmentalAwareness.Compatibility { public static class BalrondAmazingNature { private static bool enabled = false; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public const string GUID = "balrond.astafaraios.BalrondAmazingNature"; public static readonly int ScorchedHash = StringExtensionMethods.GetStableHashCode("SE_Scorched_bal"); public static readonly int ChilledHash = StringExtensionMethods.GetStableHashCode("SE_Chilled_bal"); public static readonly int EnfeebledHash = StringExtensionMethods.GetStableHashCode("SE_Enfeebled_bal"); public static readonly int StaticChargedHash = StringExtensionMethods.GetStableHashCode("SE_StaticCharge_bal"); public static readonly int SoulSappedHash = StringExtensionMethods.GetStableHashCode("SE_SoulSapped_bal"); public static readonly int FracturedHash = StringExtensionMethods.GetStableHashCode("SE_Fractured_bal"); public static readonly int LaceratedHash = StringExtensionMethods.GetStableHashCode("SE_Lacerated_bal"); public static readonly int PuncturedHash = StringExtensionMethods.GetStableHashCode("SE_Punctured_bal"); public static readonly int BleedingHash = StringExtensionMethods.GetStableHashCode("SE_Bleeding_bal"); public static readonly int ColdDayHash = StringExtensionMethods.GetStableHashCode("SE_ColdDay_bal"); public static readonly int SoakedHash = StringExtensionMethods.GetStableHashCode("SE_Soaked_bal"); public static bool Enabled => enabled; public static void Setup() { enabled = Chainloader.PluginInfos.ContainsKey("balrond.astafaraios.BalrondAmazingNature"); if (Enabled) { Main.LogMessage([NullableContext(1)] () => "BalrondAmazingNature detected."); } } } [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(0)] [NullableContext(2)] public static class YoureThirsty { private static bool enabled = false; private static bool setupComplete = false; private static Assembly modAssembly; [<9d033fe9-c380-47d1-b735-cfa82d3b8a67>Nullable(1)] public const string GUID = "marc.yourthirsty"; public static PropertyInfo pCurrentThirst; public static readonly int HydratedHash = StringExtensionMethods.GetStableHashCode("SE_YT_Hydrated"); public static readonly int DirtyWaterHash = StringExtensionMethods.GetStableHashCode("SE_YT_DirtyWater"); public static bool Enabled => enabled; public static bool SetupComplete => setupComplete; public static void Setup() { enabled = Chainloader.PluginInfos.ContainsKey("marc.yourthirsty"); if (!Enabled) { return; } Main.LogMessage([NullableContext(1)] () => "YoureThirsty detected. Setting up references."); modAssembly = FindAssembly(); if (modAssembly == null) { Main.LogMessage([NullableContext(1)] () => "Assembly information could not be loaded. Aborting."); return; } pCurrentThirst = modAssembly?.GetType("YourThirsty.ThirstSystem")?.GetProperty("CurrentThirst", AccessTools.all); if (pCurrentThirst == null) { Main.LogMessage([NullableContext(1)] () => "Could not find static property 'CurrentThirst' in 'YourThirsty.ThirstSystem'. Aborting."); return; } Main.LogMessage([NullableContext(1)] () => "References added successfully."); setupComplete = true; } private static Assembly FindAssembly() { Assembly result = null; if (Chainloader.PluginInfos.TryGetValue("marc.yourthirsty", out var value)) { result = ((object)value.Instance).GetType().Assembly; } return result; } } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<5141f2fb-80e6-4dad-bc48-d638918d7d67>Embedded] internal sealed class <5141f2fb-80e6-4dad-bc48-d638918d7d67>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] [CompilerGenerated] [<5141f2fb-80e6-4dad-bc48-d638918d7d67>Embedded] internal sealed class <6c733c34-deed-4359-b6c3-d2f8a23e5d1b>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <6c733c34-deed-4359-b6c3-d2f8a23e5d1b>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <6c733c34-deed-4359-b6c3-d2f8a23e5d1b>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] [<5141f2fb-80e6-4dad-bc48-d638918d7d67>Embedded] [CompilerGenerated] internal sealed class <2d448f51-151b-4c19-8bdf-da60c823d234>NullableContextAttribute : Attribute { public readonly byte Flag; public <2d448f51-151b-4c19-8bdf-da60c823d234>NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [<5141f2fb-80e6-4dad-bc48-d638918d7d67>Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ServerSync { [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] [PublicAPI] internal abstract class OwnConfigEntryBase { [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] public object LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] [PublicAPI] [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] internal class SyncedConfigEntry<[<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] T> : OwnConfigEntryBase { public readonly ConfigEntry SourceConfig; public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig; public T Value { get { return SourceConfig.Value; } set { SourceConfig.Value = value; } } public SyncedConfigEntry(ConfigEntry sourceConfig) { SourceConfig = sourceConfig; base..ctor(); } public void AssignLocalValue(T value) { if (LocalBaseValue == null) { Value = value; } else { LocalBaseValue = value; } } } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(2)] [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] internal abstract class CustomSyncedValueBase { public object LocalBaseValue; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(1)] public readonly string Identifier; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(1)] public readonly Type Type; private object boxedValue; protected bool localIsOwner; public readonly int Priority; public object BoxedValue { get { return boxedValue; } set { boxedValue = value; this.ValueChanged?.Invoke(); } } public event Action ValueChanged; [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority) { Priority = priority; Identifier = identifier; Type = type; configSync.AddCustomValue(this); localIsOwner = configSync.IsSourceOfTruth; configSync.SourceOfTruthChanged += delegate(bool truth) { localIsOwner = truth; }; } } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] [PublicAPI] internal sealed class CustomSyncedValue<[<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] T> : CustomSyncedValueBase { public T Value { get { return (T)base.BoxedValue; } set { base.BoxedValue = value; } } public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0) : base(configSync, identifier, typeof(T), priority) { Value = value; } public void AssignLocalValue(T value) { if (localIsOwner) { Value = value; } else { LocalBaseValue = value; } } } internal class ConfigurationManagerAttributes { [UsedImplicitly] public bool? ReadOnly = false; } [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] [PublicAPI] internal class ConfigSync { [HarmonyPatch(typeof(ZRpc), "HandlePackage")] [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] private static class SnatchCurrentlyHandlingRPC { [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] public static ZRpc currentRpc; [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] [HarmonyPrefix] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [HarmonyPatch(typeof(ZNet), "Awake")] [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] internal static class RegisterRPCPatch { [HarmonyPostfix] [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] private static void Postfix(ZNet __instance) { isServer = __instance.IsServer(); foreach (ConfigSync configSync2 in configSyncs) { ZRoutedRpc.instance.Register(configSync2.Name + " ConfigSync", (Action)configSync2.RPC_FromOtherClientConfigSync); if (isServer) { configSync2.InitialSyncDone = true; Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections")); } } if (isServer) { ((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges()); } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] static void SendAdmin(List peers, bool isAdmin) { ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1] { new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = isAdmin } }); ConfigSync configSync = configSyncs.First(); if (configSync != null) { ((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package)); } } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] static IEnumerator WatchAdminListChanges() { MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); List CurrentList = new List(adminList.GetList()); while (true) { yield return (object)new WaitForSeconds(30f); if (!adminList.GetList().SequenceEqual(CurrentList)) { CurrentList = new List(adminList.GetList()); List adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p) { string hostName = p.m_rpc.GetSocket().GetHostName(); return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName })); }).ToList(); List nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList(); SendAdmin(nonAdminPeer, isAdmin: false); SendAdmin(adminPeer, isAdmin: true); } } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] private static class RegisterClientRPCPatch { [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { return; } foreach (ConfigSync configSync in configSyncs) { peer.m_rpc.Register(configSync.Name + " ConfigSync", (Action)configSync.RPC_FromServerConfigSync); } } } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] private class ParsedConfigs { [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 1, 1, 2 })] public readonly Dictionary configValues = new Dictionary(); [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 1, 1, 2 })] public readonly Dictionary customValues = new Dictionary(); } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ResetConfigsOnShutdown { [HarmonyPostfix] private static void Postfix() { ProcessingServerUpdate = true; foreach (ConfigSync configSync in configSyncs) { configSync.resetConfigsFromServer(); configSync.IsSourceOfTruth = true; configSync.InitialSyncDone = false; } ProcessingServerUpdate = false; } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] private class SendConfigsAfterLogin { [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] private class BufferingSocket : ZPlayFabSocket, ISocket { public volatile bool finished = false; public volatile int versionMatchQueued = -1; public readonly List Package = new List(); public readonly ISocket Original; public BufferingSocket(ISocket original) { Original = original; ((ZPlayFabSocket)this)..ctor(); } public bool IsConnected() { return Original.IsConnected(); } public ZPackage Recv() { return Original.Recv(); } public int GetSendQueueSize() { return Original.GetSendQueueSize(); } public int GetCurrentSendRate() { return Original.GetCurrentSendRate(); } public bool IsHost() { return Original.IsHost(); } public void Dispose() { Original.Dispose(); } public bool GotNewData() { return Original.GotNewData(); } public void Close() { Original.Close(); } public string GetEndPointString() { return Original.GetEndPointString(); } public void GetAndResetStats(out int totalSent, out int totalRecv) { Original.GetAndResetStats(ref totalSent, ref totalRecv); } public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec) { Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec); } public ISocket Accept() { return Original.Accept(); } public int GetHostPort() { return Original.GetHostPort(); } public bool Flush() { return Original.Flush(); } public string GetHostName() { return Original.GetHostName(); } public void VersionMatch() { if (finished) { Original.VersionMatch(); } else { versionMatchQueued = Package.Count; } } public void Send(ZPackage pkg) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown int pos = pkg.GetPos(); pkg.SetPos(0); int num = pkg.ReadInt(); if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished) { ZPackage val = new ZPackage(pkg.GetArray()); val.SetPos(pos); Package.Add(val); } else { pkg.SetPos(pos); Original.Send(pkg); } } } [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix([<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 2, 1, 1 })] ref Dictionary __state, ZNet __instance, ZRpc rpc) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 if (!__instance.IsServer()) { return; } BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket()); AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket); object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (val != null && (int)ZNet.m_onlineBackend > 0) { FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket"); object? value = fieldInfo.GetValue(val); ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null); if (val2 != null) { typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId); } fieldInfo.SetValue(val, bufferingSocket); } if (__state == null) { __state = new Dictionary(); } __state[Assembly.GetExecutingAssembly()] = bufferingSocket; } [HarmonyPostfix] private static void Postfix(Dictionary __state, ZNet __instance, ZRpc rpc) { ZNetPeer peer; if (__instance.IsServer()) { object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (peer == null) { SendBufferedData(); } else { ((MonoBehaviour)__instance).StartCoroutine(sendAsync()); } } void SendBufferedData() { if (rpc.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket.Original); object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null); if (val != null) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = __state[Assembly.GetExecutingAssembly()]; bufferingSocket2.finished = true; for (int i = 0; i < bufferingSocket2.Package.Count; i++) { if (i == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } bufferingSocket2.Original.Send(bufferingSocket2.Package[i]); } if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } } IEnumerator sendAsync() { foreach (ConfigSync configSync in configSyncs) { List entries = new List(); if (configSync.CurrentVersion != null) { entries.Add(new PackageEntry { section = "Internal", key = "serverversion", type = typeof(string), value = configSync.CurrentVersion }); } MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); entries.Add(new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2] { adminList, rpc.GetSocket().GetHostName() })) }); ZPackage package = ConfigsToPackage(configSync.allConfigs.Select([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false); yield return ((MonoBehaviour)__instance).StartCoroutine(configSync.sendZPackage(new List { peer }, package)); } SendBufferedData(); } } } [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] private class PackageEntry { public string section = null; public string key = null; public Type type = null; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] public object value; } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] [HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")] private static class PreventSavingServerInfo { [HarmonyPrefix] [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] private static bool Prefix(ConfigEntryBase __instance, ref string __result) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase)) { return true; } __result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType); return false; } } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] [HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")] private static class PreventConfigRereadChangingValues { [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, string value) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null) { return true; } try { ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType); } catch (Exception ex) { Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}"); } return false; } } [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] private class InvalidDeserializationTypeException : Exception { public string expected = null; public string received = null; public string field = ""; } public static bool ProcessingServerUpdate; public readonly string Name; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] public string DisplayName; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] public string CurrentVersion; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] public string MinimumRequiredVersion; public bool ModRequired = false; private bool? forceConfigLocking; private bool isSourceOfTruth = true; private static readonly HashSet configSyncs; private readonly HashSet allConfigs = new HashSet(); private HashSet allCustomValues = new HashSet(); private static bool isServer; private static bool lockExempt; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] private OwnConfigEntryBase lockedConfig = null; private const byte PARTIAL_CONFIGS = 1; private const byte FRAGMENTED_CONFIG = 2; private const byte COMPRESSED_CONFIG = 4; private readonly Dictionary> configValueCache = new Dictionary>(); [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 1, 0, 1 })] private readonly List> cacheExpirations = new List>(); private static long packageCounter; public bool IsLocked { get { bool? flag = forceConfigLocking; bool num; if (!flag.HasValue) { if (lockedConfig == null) { goto IL_0052; } num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0; } else { num = flag.GetValueOrDefault(); } if (!num) { goto IL_0052; } int result = ((!lockExempt) ? 1 : 0); goto IL_0053; IL_0053: return (byte)result != 0; IL_0052: result = 0; goto IL_0053; } set { forceConfigLocking = value; } } public bool IsAdmin => lockExempt || isSourceOfTruth; public bool IsSourceOfTruth { get { return isSourceOfTruth; } private set { if (value != isSourceOfTruth) { isSourceOfTruth = value; this.SourceOfTruthChanged?.Invoke(value); } } } public bool InitialSyncDone { get; private set; } = false; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] [method: <2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(2)] [field: <6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] public event Action SourceOfTruthChanged; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] [method: <2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(2)] [field: <6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] private event Action lockedConfigChanged; static ConfigSync() { ProcessingServerUpdate = false; configSyncs = new HashSet(); lockExempt = false; packageCounter = 0L; RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle); } public ConfigSync(string name) { Name = name; configSyncs.Add(this); new VersionCheck(this); } public SyncedConfigEntry AddConfigEntry<[<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] T>(ConfigEntry configEntry) { OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry); SyncedConfigEntry syncedEntry = ownConfigEntryBase as SyncedConfigEntry; if (syncedEntry == null) { syncedEntry = new SyncedConfigEntry(configEntry); AccessTools.DeclaredField(typeof(ConfigDescription), "k__BackingField").SetValue(((ConfigEntryBase)configEntry).Description, new object[1] { new ConfigurationManagerAttributes() }.Concat(((ConfigEntryBase)configEntry).Description.Tags ?? Array.Empty()).Concat(new SyncedConfigEntry[1] { syncedEntry }).ToArray()); configEntry.SettingChanged += [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (object _, EventArgs _) => { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry); } }; allConfigs.Add(syncedEntry); } return syncedEntry; } public SyncedConfigEntry AddLockingConfigEntry<[<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] T>(ConfigEntry lockingConfig) where T : IConvertible { if (lockedConfig != null) { throw new Exception("Cannot initialize locking ConfigEntry twice"); } lockedConfig = AddConfigEntry(lockingConfig); lockingConfig.SettingChanged += [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (object _, EventArgs _) => { this.lockedConfigChanged?.Invoke(); }; return (SyncedConfigEntry)lockedConfig; } internal void AddCustomValue(CustomSyncedValueBase customValue) { if (allCustomValues.Select([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue.Identifier)) { throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)"); } allCustomValues.Add(customValue); allCustomValues = new HashSet(allCustomValues.OrderByDescending([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (CustomSyncedValueBase v) => v.Priority)); customValue.ValueChanged += delegate { if (!ProcessingServerUpdate) { Broadcast(ZRoutedRpc.Everybody, customValue); } }; } private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package) { lockedConfigChanged += serverLockedSettingChanged; IsSourceOfTruth = false; if (HandleConfigSyncRPC(0L, package, clientUpdate: false)) { InitialSyncDone = true; } } private void RPC_FromOtherClientConfigSync(long sender, ZPackage package) { HandleConfigSyncRPC(sender, package, clientUpdate: true); } private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Expected O, but got Unknown try { if (isServer && IsLocked) { ZRpc currentRpc = SnatchCurrentlyHandlingRPC.currentRpc; object obj; if (currentRpc == null) { obj = null; } else { ISocket socket = currentRpc.GetSocket(); obj = ((socket != null) ? socket.GetHostName() : null); } string text = (string)obj; if (text != null) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text })))) { return false; } } } cacheExpirations.RemoveAll(([<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 0, 1 })] KeyValuePair kv) => { if (kv.Key < DateTimeOffset.Now.Ticks) { configValueCache.Remove(kv.Value); return true; } return false; }); byte b = package.ReadByte(); if ((b & 2u) != 0) { long num = package.ReadLong(); string text2 = sender.ToString() + num; if (!configValueCache.TryGetValue(text2, out var value)) { value = new SortedDictionary(); configValueCache[text2] = value; cacheExpirations.Add(new KeyValuePair(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2)); } int key = package.ReadInt(); int num2 = package.ReadInt(); value.Add(key, package.ReadByteArray()); if (value.Count < num2) { return false; } configValueCache.Remove(text2); package = new ZPackage(value.Values.SelectMany([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (byte[] a) => a).ToArray()); b = package.ReadByte(); } ProcessingServerUpdate = true; if ((b & 4u) != 0) { byte[] buffer = package.ReadByteArray(); MemoryStream stream = new MemoryStream(buffer); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress)) { deflateStream.CopyTo(memoryStream); } package = new ZPackage(memoryStream.ToArray()); b = package.ReadByte(); } if ((b & 1) == 0) { resetConfigsFromServer(); } ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package); ConfigFile val2 = null; bool saveOnConfigSet = false; foreach (KeyValuePair configValue in parsedConfigs.configValues) { if (!isServer && configValue.Key.LocalBaseValue == null) { configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue; } if (val2 == null) { val2 = configValue.Key.BaseConfig.ConfigFile; saveOnConfigSet = val2.SaveOnConfigSet; val2.SaveOnConfigSet = false; } configValue.Key.BaseConfig.BoxedValue = configValue.Value; } if (val2 != null) { val2.SaveOnConfigSet = saveOnConfigSet; } foreach (KeyValuePair customValue in parsedConfigs.customValues) { if (!isServer) { CustomSyncedValueBase key2 = customValue.Key; if (key2.LocalBaseValue == null) { key2.LocalBaseValue = customValue.Key.BoxedValue; } } customValue.Key.BoxedValue = customValue.Value; } Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name)); if (!isServer) { serverLockedSettingChanged(); } return true; } finally { ProcessingServerUpdate = false; } } private ParsedConfigs ReadConfigsFromPackage(ZPackage package) { ParsedConfigs parsedConfigs = new ParsedConfigs(); Dictionary dictionary = allConfigs.Where([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (OwnConfigEntryBase c) => c); Dictionary dictionary2 = allCustomValues.ToDictionary([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (CustomSyncedValueBase c) => c.Identifier, [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (CustomSyncedValueBase c) => c); int num = package.ReadInt(); for (int i = 0; i < num; i++) { string text = package.ReadString(); string text2 = package.ReadString(); string text3 = package.ReadString(); Type type = Type.GetType(text3); if (text3 == "" || type != null) { object obj; try { obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type)); } catch (InvalidDeserializationTypeException ex) { Debug.LogWarning((object)("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected)); continue; } OwnConfigEntryBase value2; if (text == "Internal") { CustomSyncedValueBase value; if (text2 == "serverversion") { if (obj?.ToString() != CurrentVersion) { Debug.LogWarning((object)("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown"))); } } else if (text2 == "lockexempt") { if (obj is bool flag) { lockExempt = flag; } } else if (dictionary2.TryGetValue(text2, out value)) { if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3) { parsedConfigs.customValues[value] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName)); } } else if (dictionary.TryGetValue(text + "_" + text2, out value2)) { Type type2 = configType(value2.BaseConfig); if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3) { parsedConfigs.configValues[value2] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName)); } else { Debug.LogWarning((object)("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match.")); } continue; } Debug.LogWarning((object)("Got invalid type " + text3 + ", abort reading of received configs")); return new ParsedConfigs(); } return parsedConfigs; } private static bool isWritableConfig(OwnConfigEntryBase config) { ConfigSync configSync = configSyncs.FirstOrDefault([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (ConfigSync cs) => cs.allConfigs.Contains(config)); if (configSync == null) { return true; } return configSync.IsSourceOfTruth || !config.SynchronizedConfig || config.LocalBaseValue == null || (!configSync.IsLocked && (config != configSync.lockedConfig || lockExempt)); } private void serverLockedSettingChanged() { foreach (OwnConfigEntryBase allConfig in allConfigs) { configAttribute(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig); } } private void resetConfigsFromServer() { ConfigFile val = null; bool saveOnConfigSet = false; foreach (OwnConfigEntryBase item in allConfigs.Where([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (OwnConfigEntryBase config) => config.LocalBaseValue != null)) { if (val == null) { val = item.BaseConfig.ConfigFile; saveOnConfigSet = val.SaveOnConfigSet; val.SaveOnConfigSet = false; } item.BaseConfig.BoxedValue = item.LocalBaseValue; item.LocalBaseValue = null; } if (val != null) { val.SaveOnConfigSet = saveOnConfigSet; } foreach (CustomSyncedValueBase item2 in allCustomValues.Where([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (CustomSyncedValueBase config) => config.LocalBaseValue != null)) { item2.BoxedValue = item2.LocalBaseValue; item2.LocalBaseValue = null; } lockedConfigChanged -= serverLockedSettingChanged; serverLockedSettingChanged(); } private IEnumerator distributeConfigToPeers(ZNetPeer peer, ZPackage package) { ZRoutedRpc rpc = ZRoutedRpc.instance; if (rpc == null) { yield break; } byte[] data = package.GetArray(); if (data != null && data.LongLength > 250000) { int fragments = (int)(1 + (data.LongLength - 1) / 250000); long packageIdentifier = ++packageCounter; int fragment = 0; while (fragment < fragments) { foreach (bool item in waitForQueue()) { yield return item; } if (peer.m_socket.IsConnected()) { ZPackage fragmentedPackage = new ZPackage(); fragmentedPackage.Write((byte)2); fragmentedPackage.Write(packageIdentifier); fragmentedPackage.Write(fragment); fragmentedPackage.Write(fragments); fragmentedPackage.Write(data.Skip(250000 * fragment).Take(250000).ToArray()); SendPackage(fragmentedPackage); if (fragment != fragments - 1) { yield return true; } int num = fragment + 1; fragment = num; continue; } break; } yield break; } foreach (bool item2 in waitForQueue()) { yield return item2; } SendPackage(package); void SendPackage(ZPackage pkg) { string text = Name + " ConfigSync"; if (isServer) { peer.m_rpc.Invoke(text, new object[1] { pkg }); } else { rpc.InvokeRoutedRPC(peer.m_server ? 0 : peer.m_uid, text, new object[1] { pkg }); } } IEnumerable waitForQueue() { float timeout = Time.time + 30f; while (peer.m_socket.GetSendQueueSize() > 20000) { if (Time.time > timeout) { Debug.Log((object)$"Disconnecting {peer.m_uid} after 30 seconds config sending timeout"); peer.m_rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)5 }); ZNet.instance.Disconnect(peer); break; } yield return false; } } } private IEnumerator sendZPackage(long target, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return Enumerable.Empty().GetEnumerator(); } List list = (List)AccessTools.DeclaredField(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance); if (target != ZRoutedRpc.Everybody) { list = list.Where([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (ZNetPeer p) => p.m_uid == target).ToList(); } return sendZPackage(list, package); } private IEnumerator sendZPackage(List peers, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { yield break; } byte[] rawData = package.GetArray(); if (rawData != null && rawData.LongLength > 10000) { ZPackage compressedPackage = new ZPackage(); compressedPackage.Write((byte)4); MemoryStream output = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(output, CompressionLevel.Optimal)) { deflateStream.Write(rawData, 0, rawData.Length); } compressedPackage.Write(output.ToArray()); package = compressedPackage; } List> writers = (from peer in peers where peer.IsReady() select peer into p select distributeConfigToPeers(p, package)).ToList(); writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); while (writers.Count > 0) { yield return null; writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); } } private void Broadcast(long target, params ConfigEntryBase[] configs) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(configs); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private void Broadcast(long target, params CustomSyncedValueBase[] customValues) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(null, customValues); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } [return: <6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] private static OwnConfigEntryBase configData(ConfigEntryBase config) { return config.Description.Tags?.OfType().SingleOrDefault(); } [return: <6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 2, 1 })] public static SyncedConfigEntry ConfigData<[<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] T>(ConfigEntry config) { return ((ConfigEntryBase)config).Description.Tags?.OfType>().SingleOrDefault(); } private static T configAttribute<[<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] T>(ConfigEntryBase config) { return config.Description.Tags.OfType().First(); } private static Type configType(ConfigEntryBase config) { return configType(config.SettingType); } private static Type configType(Type type) { return type.IsEnum ? Enum.GetUnderlyingType(type) : type; } private static ZPackage ConfigsToPackage([<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 2, 1 })] IEnumerable configs = null, [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 2, 1 })] IEnumerable customValues = null, [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 2, 1 })] IEnumerable packageEntries = null, bool partial = true) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown List list = configs?.Where([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List(); List list2 = customValues?.ToList() ?? new List(); ZPackage val = new ZPackage(); val.Write((byte)(partial ? 1 : 0)); val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0)); foreach (PackageEntry item in packageEntries ?? Array.Empty()) { AddEntryToPackage(val, item); } foreach (CustomSyncedValueBase item2 in list2) { AddEntryToPackage(val, new PackageEntry { section = "Internal", key = item2.Identifier, type = item2.Type, value = item2.BoxedValue }); } foreach (ConfigEntryBase item3 in list) { AddEntryToPackage(val, new PackageEntry { section = item3.Definition.Section, key = item3.Definition.Key, type = configType(item3), value = item3.BoxedValue }); } return val; } private static void AddEntryToPackage(ZPackage package, PackageEntry entry) { package.Write(entry.section); package.Write(entry.key); package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type)); AddValueToZPackage(package, entry.value); } private static string GetZPackageTypeString(Type type) { return type.AssemblyQualifiedName; } private static void AddValueToZPackage(ZPackage package, [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] object value) { Type type = value?.GetType(); if (value is Enum) { value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture); } else { if (value is ICollection collection) { package.Write(collection.Count); { foreach (object item in collection) { AddValueToZPackage(package, item); } return; } } if ((object)type != null && type.IsValueType && !type.IsPrimitive) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); package.Write(fields.Length); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { package.Write(GetZPackageTypeString(fieldInfo.FieldType)); AddValueToZPackage(package, fieldInfo.GetValue(value)); } return; } } ZRpc.Serialize(new object[1] { value }, ref package); } private static object ReadValueWithTypeFromZPackage(ZPackage package, Type type) { if ((object)type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int num = package.ReadInt(); if (num != fields.Length) { throw new InvalidDeserializationTypeException { received = $"(field count: {num})", expected = $"(field count: {fields.Length})" }; } object uninitializedObject = FormatterServices.GetUninitializedObject(type); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { string text = package.ReadString(); if (text != GetZPackageTypeString(fieldInfo.FieldType)) { throw new InvalidDeserializationTypeException { received = text, expected = GetZPackageTypeString(fieldInfo.FieldType), field = fieldInfo.Name }; } fieldInfo.SetValue(uninitializedObject, ReadValueWithTypeFromZPackage(package, fieldInfo.FieldType)); } return uninitializedObject; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { int num2 = package.ReadInt(); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments); FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic); for (int j = 0; j < num2; j++) { object obj = ReadValueWithTypeFromZPackage(package, type2); dictionary.Add(field.GetValue(obj), field2.GetValue(obj)); } return dictionary; } if (type != typeof(List) && type.IsGenericType) { Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]); if ((object)type3 != null && type3.IsAssignableFrom(type)) { int num3 = package.ReadInt(); object obj2 = Activator.CreateInstance(type); MethodInfo method = type3.GetMethod("Add"); for (int k = 0; k < num3; k++) { method.Invoke(obj2, new object[1] { ReadValueWithTypeFromZPackage(package, type.GenericTypeArguments[0]) }); } return obj2; } } ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo)); AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type); List source = new List(); ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source); return source.First(); } } [<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(1)] [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(0)] [HarmonyPatch] [PublicAPI] internal class VersionCheck { private static readonly HashSet versionChecks; private static readonly Dictionary notProcessedNames; public string Name; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] private string displayName; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] private string currentVersion; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] private string minimumRequiredVersion; public bool ModRequired = true; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] private string ReceivedCurrentVersion; [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] private string ReceivedMinimumRequiredVersion; private readonly List ValidatedClients = new List(); [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] private ConfigSync ConfigSync; public string DisplayName { get { return displayName ?? Name; } set { displayName = value; } } public string CurrentVersion { get { return currentVersion ?? "0.0.0"; } set { currentVersion = value; } } public string MinimumRequiredVersion { get { return minimumRequiredVersion ?? (ModRequired ? CurrentVersion : "0.0.0"); } set { minimumRequiredVersion = value; } } private static void PatchServerSync() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown Patches patchInfo = PatchProcessor.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null)); if (patchInfo != null && patchInfo.Postfixes.Count([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (Patch p) => p.PatchMethod.DeclaringType == typeof(ConfigSync.RegisterRPCPatch)) > 0) { return; } Harmony val = new Harmony("org.bepinex.helpers.ServerSync"); foreach (Type item in from t in typeof(ConfigSync).GetNestedTypes(BindingFlags.NonPublic).Concat(new Type[1] { typeof(VersionCheck) }) where t.IsClass select t) { val.PatchAll(item); } } static VersionCheck() { versionChecks = new HashSet(); notProcessedNames = new Dictionary(); typeof(ThreadingHelper).GetMethod("StartSyncInvoke").Invoke(ThreadingHelper.Instance, new object[1] { new Action(PatchServerSync) }); } public VersionCheck(string name) { Name = name; ModRequired = true; versionChecks.Add(this); } public VersionCheck(ConfigSync configSync) { ConfigSync = configSync; Name = ConfigSync.Name; versionChecks.Add(this); } public void Initialize() { ReceivedCurrentVersion = null; ReceivedMinimumRequiredVersion = null; if (ConfigSync != null) { Name = ConfigSync.Name; DisplayName = ConfigSync.DisplayName; CurrentVersion = ConfigSync.CurrentVersion; MinimumRequiredVersion = ConfigSync.MinimumRequiredVersion; ModRequired = ConfigSync.ModRequired; } } private bool IsVersionOk() { if (ReceivedMinimumRequiredVersion == null || ReceivedCurrentVersion == null) { return !ModRequired; } bool flag = new System.Version(CurrentVersion) >= new System.Version(ReceivedMinimumRequiredVersion); bool flag2 = new System.Version(ReceivedCurrentVersion) >= new System.Version(MinimumRequiredVersion); return flag && flag2; } private string ErrorClient() { if (ReceivedMinimumRequiredVersion == null) { return DisplayName + " is not installed on the server."; } return (new System.Version(CurrentVersion) >= new System.Version(ReceivedMinimumRequiredVersion)) ? (DisplayName + " may not be higher than version " + ReceivedCurrentVersion + ". You have version " + CurrentVersion + ".") : (DisplayName + " needs to be at least version " + ReceivedMinimumRequiredVersion + ". You have version " + CurrentVersion + "."); } private string ErrorServer(ZRpc rpc) { return "Disconnect: The client (" + rpc.GetSocket().GetHostName() + ") doesn't have the correct " + DisplayName + " version " + MinimumRequiredVersion; } private string Error([<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(2)] ZRpc rpc = null) { return (rpc == null) ? ErrorClient() : ErrorServer(rpc); } private static VersionCheck[] GetFailedClient() { return versionChecks.Where([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (VersionCheck check) => !check.IsVersionOk()).ToArray(); } private static VersionCheck[] GetFailedServer(ZRpc rpc) { return versionChecks.Where([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (VersionCheck check) => check.ModRequired && !check.ValidatedClients.Contains(rpc)).ToArray(); } private static void Logout() { Game.instance.Logout(true, true); AccessTools.DeclaredField(typeof(ZNet), "m_connectionStatus").SetValue(null, (object)(ConnectionStatus)3); } private static void DisconnectClient(ZRpc rpc) { rpc.Invoke("Error", new object[1] { 3 }); } private static void CheckVersion(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, null); } private static void CheckVersion(ZRpc rpc, ZPackage pkg, [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(new byte[] { 2, 1, 1 })] Action original) { string text = pkg.ReadString(); string text2 = pkg.ReadString(); string text3 = pkg.ReadString(); bool flag = false; foreach (VersionCheck versionCheck in versionChecks) { if (!(text != versionCheck.Name)) { Debug.Log((object)("Received " + versionCheck.DisplayName + " version " + text3 + " and minimum version " + text2 + " from the " + (ZNet.instance.IsServer() ? "client" : "server") + ".")); versionCheck.ReceivedMinimumRequiredVersion = text2; versionCheck.ReceivedCurrentVersion = text3; if (ZNet.instance.IsServer() && versionCheck.IsVersionOk()) { versionCheck.ValidatedClients.Add(rpc); } flag = true; } } if (flag) { return; } pkg.SetPos(0); if (original != null) { original(rpc, pkg); if (pkg.GetPos() == 0) { notProcessedNames.Add(text, text3); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [HarmonyPrefix] private static bool RPC_PeerInfo(ZRpc rpc, ZNet __instance) { VersionCheck[] array = (__instance.IsServer() ? GetFailedServer(rpc) : GetFailedClient()); if (array.Length == 0) { return true; } VersionCheck[] array2 = array; foreach (VersionCheck versionCheck in array2) { Debug.LogWarning((object)versionCheck.Error(rpc)); } if (__instance.IsServer()) { DisconnectClient(rpc); } else { Logout(); } return false; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPrefix] private static void RegisterAndCheckVersion(ZNetPeer peer, ZNet __instance) { //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Expected O, but got Unknown notProcessedNames.Clear(); IDictionary dictionary = (IDictionary)typeof(ZRpc).GetField("m_functions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(peer.m_rpc); if (dictionary.Contains(StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck"))) { object obj = dictionary[StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck")]; Action action = (Action)obj.GetType().GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj); peer.m_rpc.Register("ServerSync VersionCheck", (Action)([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (ZRpc rpc, [<6c733c34-deed-4359-b6c3-d2f8a23e5d1b>Nullable(1)] ZPackage pkg) => { CheckVersion(rpc, pkg, action); })); } else { peer.m_rpc.Register("ServerSync VersionCheck", (Action)CheckVersion); } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.Initialize(); if (versionCheck.ModRequired || __instance.IsServer()) { Debug.Log((object)("Sending " + versionCheck.DisplayName + " version " + versionCheck.CurrentVersion + " and minimum version " + versionCheck.MinimumRequiredVersion + " to the " + (__instance.IsServer() ? "client" : "server") + ".")); ZPackage val = new ZPackage(); val.Write(versionCheck.Name); val.Write(versionCheck.MinimumRequiredVersion); val.Write(versionCheck.CurrentVersion); peer.m_rpc.Invoke("ServerSync VersionCheck", new object[1] { val }); } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] [HarmonyPrefix] private static void RemoveDisconnected(ZNetPeer peer, ZNet __instance) { if (!__instance.IsServer()) { return; } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.ValidatedClients.Remove(peer.m_rpc); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] [HarmonyPostfix] private static void ShowConnectionError(FejdStartup __instance) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) if (!__instance.m_connectionFailedPanel.activeSelf || (int)ZNet.GetConnectionStatus() != 3) { return; } bool flag = false; VersionCheck[] failedClient = GetFailedClient(); if (failedClient.Length != 0) { string text = string.Join("\n", failedClient.Select([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (VersionCheck check) => check.Error())); TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + text; flag = true; } foreach (KeyValuePair item in notProcessedNames.OrderBy([<2d448f51-151b-4c19-8bdf-da60c823d234>NullableContext(0)] (KeyValuePair kv) => kv.Key)) { if (!__instance.m_connectionFailedError.text.Contains(item.Key)) { TMP_Text connectionFailedError2 = __instance.m_connectionFailedError; connectionFailedError2.text = connectionFailedError2.text + "\nServer expects you to have " + item.Key + " (Version: " + item.Value + ") installed."; flag = true; } } if (flag) { RectTransform component = ((Component)__instance.m_connectionFailedPanel.transform.Find("Image")).GetComponent(); Vector2 sizeDelta = component.sizeDelta; sizeDelta.x = 675f; component.sizeDelta = sizeDelta; __instance.m_connectionFailedError.ForceMeshUpdate(false, false); float num = __instance.m_connectionFailedError.renderedHeight + 105f; RectTransform component2 = ((Component)((Component)component).transform.Find("ButtonOk")).GetComponent(); component2.anchoredPosition = new Vector2(component2.anchoredPosition.x, component2.anchoredPosition.y - (num - component.sizeDelta.y) / 2f); sizeDelta = component.sizeDelta; sizeDelta.y = num; component.sizeDelta = sizeDelta; } } } } namespace Microsoft.CodeAnalysis { [Embedded] [CompilerGenerated] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class <2b709a9d-5630-45b7-9fe6-df71a8918c0c>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <2b709a9d-5630-45b7-9fe6-df71a8918c0c>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <2b709a9d-5630-45b7-9fe6-df71a8918c0c>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class <0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContextAttribute : Attribute { public readonly byte Flag; public <0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SkillManager { [PublicAPI] [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(0)] [<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(1)] internal class Skill { [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(0)] public static class LocalizationCache { private static readonly Dictionary localizations = new Dictionary(); internal static void LocalizationPostfix(Localization __instance, string language) { string key = localizations.FirstOrDefault([<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(0)] (KeyValuePair l) => l.Value == __instance).Key; if (key != null) { localizations.Remove(key); } if (!localizations.ContainsKey(language)) { localizations.Add(language, __instance); } } public static Localization ForLanguage([<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] string language = null) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if (localizations.TryGetValue(language ?? PlayerPrefs.GetString("language", "English"), out var value)) { return value; } value = new Localization(); if (language != null) { value.SetupLanguage(language); } return value; } } [PublicAPI] [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(0)] public class LocalizeKey { private static readonly List keys = new List(); public readonly string Key; public readonly Dictionary Localizations = new Dictionary(); public LocalizeKey(string key) { Key = key.Replace("$", ""); keys.Add(this); } public void Alias(string alias) { Localizations.Clear(); if (!alias.Contains("$")) { alias = "$" + alias; } Localizations["alias"] = alias; Localization.instance.AddWord(Key, Localization.instance.Localize(alias)); } public LocalizeKey English(string key) { return addForLang("English", key); } public LocalizeKey Swedish(string key) { return addForLang("Swedish", key); } public LocalizeKey French(string key) { return addForLang("French", key); } public LocalizeKey Italian(string key) { return addForLang("Italian", key); } public LocalizeKey German(string key) { return addForLang("German", key); } public LocalizeKey Spanish(string key) { return addForLang("Spanish", key); } public LocalizeKey Russian(string key) { return addForLang("Russian", key); } public LocalizeKey Romanian(string key) { return addForLang("Romanian", key); } public LocalizeKey Bulgarian(string key) { return addForLang("Bulgarian", key); } public LocalizeKey Macedonian(string key) { return addForLang("Macedonian", key); } public LocalizeKey Finnish(string key) { return addForLang("Finnish", key); } public LocalizeKey Danish(string key) { return addForLang("Danish", key); } public LocalizeKey Norwegian(string key) { return addForLang("Norwegian", key); } public LocalizeKey Icelandic(string key) { return addForLang("Icelandic", key); } public LocalizeKey Turkish(string key) { return addForLang("Turkish", key); } public LocalizeKey Lithuanian(string key) { return addForLang("Lithuanian", key); } public LocalizeKey Czech(string key) { return addForLang("Czech", key); } public LocalizeKey Hungarian(string key) { return addForLang("Hungarian", key); } public LocalizeKey Slovak(string key) { return addForLang("Slovak", key); } public LocalizeKey Polish(string key) { return addForLang("Polish", key); } public LocalizeKey Dutch(string key) { return addForLang("Dutch", key); } public LocalizeKey Portuguese_European(string key) { return addForLang("Portuguese_European", key); } public LocalizeKey Portuguese_Brazilian(string key) { return addForLang("Portuguese_Brazilian", key); } public LocalizeKey Chinese(string key) { return addForLang("Chinese", key); } public LocalizeKey Japanese(string key) { return addForLang("Japanese", key); } public LocalizeKey Korean(string key) { return addForLang("Korean", key); } public LocalizeKey Hindi(string key) { return addForLang("Hindi", key); } public LocalizeKey Thai(string key) { return addForLang("Thai", key); } public LocalizeKey Abenaki(string key) { return addForLang("Abenaki", key); } public LocalizeKey Croatian(string key) { return addForLang("Croatian", key); } public LocalizeKey Georgian(string key) { return addForLang("Georgian", key); } public LocalizeKey Greek(string key) { return addForLang("Greek", key); } public LocalizeKey Serbian(string key) { return addForLang("Serbian", key); } public LocalizeKey Ukrainian(string key) { return addForLang("Ukrainian", key); } private LocalizeKey addForLang(string lang, string value) { Localizations[lang] = value; if (Localization.instance.GetSelectedLanguage() == lang) { Localization.instance.AddWord(Key, value); } else if (lang == "English" && !Localization.instance.m_translations.ContainsKey(Key)) { Localization.instance.AddWord(Key, value); } return this; } [HarmonyPriority(300)] internal static void AddLocalizedKeys(Localization __instance, string language) { foreach (LocalizeKey key in keys) { string value2; if (key.Localizations.TryGetValue(language, out var value) || key.Localizations.TryGetValue("English", out value)) { __instance.AddWord(key.Key, value); } else if (key.Localizations.TryGetValue("alias", out value2)) { __instance.AddWord(key.Key, Localization.instance.Localize(value2)); } } } } [<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(0)] private class ConfigurationManagerAttributes { [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] [UsedImplicitly] public string Category; } [<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(0)] [HarmonyPatch(typeof(Skills), "IsSkillValid")] private static class Patch_Skills_IsSkillValid { private static void Postfix(SkillType type, ref bool __result) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (!__result && skills.ContainsKey(type)) { __result = true; } } } private static readonly Dictionary skills; internal static readonly Dictionary skillByName; private readonly string skillName; private readonly string internalSkillName; private readonly SkillDef skillDef; public readonly LocalizeKey Name; public readonly LocalizeKey Description; private float skillEffectFactor = 1f; private int skillLoss = 5; public bool Configurable; private static bool InitializedTerminal; [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] private static Localization _english; [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] private static BaseUnityPlugin _plugin; private static bool hasConfigSync; [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] private static object _configSync; public float SkillGainFactor { get { return skillDef.m_increseStep; } set { skillDef.m_increseStep = value; this.SkillGainFactorChanged?.Invoke(value); } } public float SkillEffectFactor { get { return skillEffectFactor; } set { skillEffectFactor = value; this.SkillEffectFactorChanged?.Invoke(value); } } public int SkillLoss { get { return skillLoss; } set { skillLoss = value; this.SkillLossChanged?.Invoke(value); } } private static Localization english => _english ?? (_english = LocalizationCache.ForLanguage("English")); private static BaseUnityPlugin plugin { get { //IL_0041: 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_004c: Expected O, but got Unknown object obj = _plugin; if (obj == null) { BaseUnityPlugin val = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)Assembly.GetExecutingAssembly().DefinedTypes.First([<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); _plugin = val; obj = (object)val; } return (BaseUnityPlugin)obj; } } [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] private static object configSync { [<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(2)] get { if (_configSync == null && hasConfigSync) { Type type = Assembly.GetExecutingAssembly().GetType("ServerSync.ConfigSync"); if ((object)type != null) { _configSync = Activator.CreateInstance(type, plugin.Info.Metadata.GUID + " SkillManager"); type.GetField("CurrentVersion").SetValue(_configSync, plugin.Info.Metadata.Version.ToString()); type.GetProperty("IsLocked").SetValue(_configSync, true); } else { hasConfigSync = false; } } return _configSync; } } [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] [method: <0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(2)] [field: <2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] public event Action SkillGainFactorChanged; [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] [method: <0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(2)] [field: <2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] public event Action SkillEffectFactorChanged; [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] [method: <0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(2)] [field: <2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] public event Action SkillLossChanged; public Skill(string englishName, string icon) : this(englishName, loadSprite(icon, 64, 64)) { } public Skill(string englishName, Sprite icon) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_004e: 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_0064: 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_0076: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown SkillType val = fromName(englishName); string text = new Regex("[^a-zA-Z]").Replace(englishName, "_"); skills[val] = this; skillByName[englishName] = this; skillDef = new SkillDef { m_description = "$skilldesc_" + text, m_icon = icon, m_increseStep = 1f, m_skill = val }; internalSkillName = text; skillName = englishName; Name = new LocalizeKey("skill_" + ((object)(SkillType)(ref val)).ToString()).English(englishName); Description = new LocalizeKey("skilldesc_" + text); } public static SkillType fromName(string englishName) { return (SkillType)Math.Abs(StringExtensionMethods.GetStableHashCode(englishName)); } static Skill() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0065: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_011a: 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) //IL_0155: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Expected O, but got Unknown //IL_01ab: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Expected O, but got Unknown //IL_023c: Expected O, but got Unknown skills = new Dictionary(); skillByName = new Dictionary(); InitializedTerminal = false; hasConfigSync = true; Harmony val = new Harmony("org.bepinex.helpers.skillmanager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_FejdStartup", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "GetSkillDef", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_GetSkillDef", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatRaiseSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatRaiseskill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatResetSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatResetSkill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(LocalizeKey), "AddLocalizedKeys", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Terminal), "InitTerminal", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal_Prefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(LocalizationCache), "LocalizationPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "OnDeath", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Finalizer", (Type[])null, (Type[])null)), (HarmonyMethod)null); } private static void Patch_FejdStartup() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Expected O, but got Unknown foreach (Skill skill in skills.Values) { if (skill.Configurable) { string key = skill.Name.Key; string group = new Regex("['[\"\\]]").Replace(english.Localize(key), "").Trim(); string category = Localization.instance.Localize(key).Trim(); ConfigEntry skillGain = config(group, "Skill gain factor", skill.SkillGainFactor, new ConfigDescription("The rate at which you gain experience for the skill.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 5f), new object[1] { new ConfigurationManagerAttributes { Category = category } })); skill.SkillGainFactor = skillGain.Value; skillGain.SettingChanged += [<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(0)] (object _, EventArgs _) => { skill.SkillGainFactor = skillGain.Value; }; ConfigEntry skillEffect = config(group, "Skill effect factor", skill.SkillEffectFactor, new ConfigDescription("The power of the skill, based on the default power.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 5f), new object[1] { new ConfigurationManagerAttributes { Category = category } })); skill.SkillEffectFactor = skillEffect.Value; skillEffect.SettingChanged += [<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(0)] (object _, EventArgs _) => { skill.SkillEffectFactor = skillEffect.Value; }; ConfigEntry skillLoss = config(group, "Skill loss", skill.skillLoss, new ConfigDescription("How much experience to lose on death.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), new object[1] { new ConfigurationManagerAttributes { Category = category } })); skill.skillLoss = skillLoss.Value; skillLoss.SettingChanged += [<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(0)] (object _, EventArgs _) => { skill.skillLoss = skillLoss.Value; }; } } } private static void Patch_Skills_GetSkillDef([<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] ref SkillDef __result, List ___m_skills, SkillType type) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (__result == null) { SkillDef val = GetSkillDef(type); if (val != null) { ___m_skills.Add(val); __result = val; } } } private static bool Patch_Skills_CheatRaiseskill(Skills __instance, string name, float value, Player ___m_player) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_003c: Unknown result type (might be due to invalid IL or missing references) foreach (SkillType key in skills.Keys) { SkillType current = key; Skill skill = skills[current]; if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase)) { Skill skill2 = __instance.GetSkill(current); skill2.m_level += value; skill2.m_level = Mathf.Clamp(skill2.m_level, 0f, 100f); ((Character)___m_player).Message((MessageType)1, "Skill increased " + Localization.instance.Localize("$skill_" + ((object)(SkillType)(ref current)).ToString()) + ": " + (int)skill2.m_level, 0, skill2.m_info.m_icon); Console.instance.Print("Skill " + skill.internalSkillName + " = " + skill2.m_level); return false; } } return true; } private static bool Patch_Skills_CheatResetSkill(Skills __instance, string name) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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) foreach (SkillType key in skills.Keys) { Skill skill = skills[key]; if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase)) { __instance.ResetSkill(key); Console.instance.Print("Skill " + skill.internalSkillName + " reset"); return false; } } return true; } private static void Patch_Skills_OnDeath_Prefix(Skills __instance, [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(new byte[] { 2, 1 })] ref Dictionary __state) { //IL_002b: 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) //IL_0091: Unknown result type (might be due to invalid IL or missing references) if (__state == null) { __state = new Dictionary(); } foreach (KeyValuePair skill in skills) { if (__instance.m_skillData.TryGetValue(skill.Key, out var value)) { __state[skill.Key] = value; if (skill.Value.skillLoss > 0) { Skill obj = value; obj.m_level -= value.m_level * (float)skill.Value.SkillLoss / 100f; value.m_accumulator = 0f; } __instance.m_skillData.Remove(skill.Key); } } } private static void Patch_Skills_OnDeath_Finalizer(Skills __instance, [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(new byte[] { 2, 1 })] ref Dictionary __state) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (__state == null) { return; } foreach (KeyValuePair item in __state) { __instance.m_skillData[item.Key] = item.Value; } __state = null; } private static void Patch_Terminal_InitTerminal_Prefix() { InitializedTerminal = Terminal.m_terminalInitialized; } private static void Patch_Terminal_InitTerminal() { if (!InitializedTerminal) { AddSkill(Terminal.commands["raiseskill"]); AddSkill(Terminal.commands["resetskill"]); } static void AddSkill(ConsoleCommand command) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown ConsoleOptionsFetcher fetcher = command.m_tabOptionsFetcher; command.m_tabOptionsFetcher = (ConsoleOptionsFetcher)([<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(0)] () => { List list = fetcher.Invoke(); list.AddRange(skills.Values.Select([<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(0)] (Skill skill) => skill.internalSkillName)); return list; }); } } [<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(2)] private static SkillDef GetSkillDef(SkillType skillType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!skills.ContainsKey(skillType)) { return null; } return skills[skillType].skillDef; } private static byte[] ReadEmbeddedFileBytes(string name) { using MemoryStream memoryStream = new MemoryStream(); Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName().Name + "." + name).CopyTo(memoryStream); return memoryStream.ToArray(); } private static Texture2D loadTexture(string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_001f: Expected O, but got Unknown Texture2D val = new Texture2D(0, 0); ImageConversion.LoadImage(val, ReadEmbeddedFileBytes("icons." + name)); return val; } private static Sprite loadSprite(string name, int width, int height) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) return Sprite.Create(loadTexture(name), new Rect(0f, 0f, (float)width, (float)height), Vector2.zero); } private static ConfigEntry config<[<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] T>(string group, string name, T value, ConfigDescription description) { ConfigEntry val = plugin.Config.Bind(group, name, value, description); configSync?.GetType().GetMethod("AddConfigEntry").MakeGenericMethod(typeof(T)) .Invoke(configSync, new object[1] { val }); return val; } private static ConfigEntry config<[<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(2)] T>(string group, string name, T value, string description) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty())); } } [<0c9e426e-5bcc-47b2-9d6d-7f4911c07150>NullableContext(1)] [<2b709a9d-5630-45b7-9fe6-df71a8918c0c>Nullable(0)] [PublicAPI] internal static class SkillExtensions { public static float GetSkillFactor(this Character character, string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return character.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor; } public static float GetSkillFactor(this Skills skills, string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return skills.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor; } public static void RaiseSkill(this Character character, string name, float value = 1f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) character.RaiseSkill(Skill.fromName(name), value); } public static void RaiseSkill(this Skills skill, string name, float value = 1f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) skill.RaiseSkill(Skill.fromName(name), value); } public static void LowerSkill(this Character character, string name, float factor = 1f) { character.GetSkills().LowerSkill(name, factor); } public static void LowerSkill(this Skills skills, string name, float factor) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (factor > 0f && skills.m_skillData.TryGetValue(Skill.fromName(name), out var value)) { Skill obj = value; obj.m_level -= value.m_level * factor; value.m_accumulator = 0f; } } } } namespace Microsoft.CodeAnalysis { [Embedded] [CompilerGenerated] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] [CompilerGenerated] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace LocalizationManager { [PublicAPI] [NullableContext(1)] [Nullable(0)] internal class Localizer { private static readonly Dictionary>> PlaceholderProcessors; private static readonly Dictionary> loadedTexts; private static readonly ConditionalWeakTable localizationLanguage; private static readonly List> localizationObjects; [Nullable(2)] private static BaseUnityPlugin _plugin; private static readonly List fileExtensions; private static BaseUnityPlugin plugin { get { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown if (_plugin == null) { IEnumerable source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from t in ex.Types where t != null select t.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); } return _plugin; } } private static void UpdatePlaceholderText(Localization localization, string key) { localizationLanguage.TryGetValue(localization, out var value); string text = loadedTexts[value][key]; if (PlaceholderProcessors.TryGetValue(key, out var value2)) { text = value2.Aggregate(text, [NullableContext(0)] (string current, KeyValuePair> kv) => current.Replace("{" + kv.Key + "}", kv.Value())); } localization.AddWord(key, text); } public static void AddPlaceholder(string key, string placeholder, ConfigEntry config, [Nullable(new byte[] { 2, 1, 1 })] Func convertConfigValue = null) { if (convertConfigValue == null) { convertConfigValue = [NullableContext(0)] [return: Nullable(1)] (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key)) { PlaceholderProcessors[key] = new Dictionary>(); } config.SettingChanged += [NullableContext(0)] (object _, EventArgs _) => { UpdatePlaceholder(); }; if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage())) { UpdatePlaceholder(); } void UpdatePlaceholder() { PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value); UpdatePlaceholderText(Localization.instance, key); } } public static void AddText(string key, string text) { List> list = new List>(); foreach (WeakReference localizationObject in localizationObjects) { if (localizationObject.TryGetTarget(out var target)) { Dictionary dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)]; if (!target.m_translations.ContainsKey(key)) { dictionary[key] = text; target.AddWord(key, text); } } else { list.Add(localizationObject); } } foreach (WeakReference item in list) { localizationObjects.Remove(item); } } public static void Load() { LoadLocalization(Localization.instance, Localization.instance.GetSelectedLanguage()); } private static void LoadLocalization(Localization __instance, string language) { if (!localizationLanguage.Remove(__instance)) { localizationObjects.Add(new WeakReference(__instance)); } localizationLanguage.Add(__instance, language); Dictionary dictionary = new Dictionary(); foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories) where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0 select f) { string text = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' })[1]; if (dictionary.ContainsKey(text)) { Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped.")); } else { dictionary[text] = item; } } byte[] array = LoadTranslationFromAssembly("English"); if (array == null) { throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml."); } Dictionary dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize>(Encoding.UTF8.GetString(array)); if (dictionary2 == null) { throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty."); } string text2 = null; if (language != "English") { if (dictionary.ContainsKey(language)) { text2 = File.ReadAllText(dictionary[language]); } else { byte[] array2 = LoadTranslationFromAssembly(language); if (array2 != null) { text2 = Encoding.UTF8.GetString(array2); } } } if (text2 == null && dictionary.ContainsKey("English")) { text2 = File.ReadAllText(dictionary["English"]); } if (text2 != null) { foreach (KeyValuePair item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize>(text2) ?? new Dictionary()) { dictionary2[item2.Key] = item2.Value; } } loadedTexts[language] = dictionary2; foreach (KeyValuePair item3 in dictionary2) { UpdatePlaceholderText(__instance, item3.Key); } } static Localizer() { //IL_004d: 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_008c: Expected O, but got Unknown PlaceholderProcessors = new Dictionary>>(); loadedTexts = new Dictionary>(); localizationLanguage = new ConditionalWeakTable(); localizationObjects = new List>(); fileExtensions = new List { ".json", ".yml" }; new Harmony("org.bepinex.helpers.LocalizationManager").Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } [return: Nullable(2)] private static byte[] LoadTranslationFromAssembly(string language) { foreach (string fileExtension in fileExtensions) { byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension); if (array != null) { return array; } } return null; } [NullableContext(2)] public static byte[] ReadEmbeddedFileBytes([Nullable(1)] string resourceFileName, Assembly containingAssembly = null) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal)); if (text != null) { containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); } return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] [CompilerGenerated] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] internal sealed class AllowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] internal sealed class DisallowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] internal sealed class DoesNotReturnAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class DoesNotReturnIfAttribute : Attribute { public bool ParameterValue { get; } public DoesNotReturnIfAttribute(bool parameterValue) { ParameterValue = parameterValue; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] internal sealed class MaybeNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class MaybeNullWhenAttribute : Attribute { public bool ReturnValue { get; } public MaybeNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] internal sealed class NotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] internal sealed class NotNullIfNotNullAttribute : Attribute { public string ParameterName { get; } public NotNullIfNotNullAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class NotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public NotNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } } namespace System.Collections.Generic { internal static class DeconstructionExtensions { public static void Deconstruct(this KeyValuePair pair, out TKey key, out TValue value) { key = pair.Key; value = pair.Value; } } } namespace YamlDotNet { internal sealed class CultureInfoAdapter : CultureInfo { private readonly IFormatProvider provider; public CultureInfoAdapter(CultureInfo baseCulture, IFormatProvider provider) : base(baseCulture.LCID) { this.provider = provider; } public override object? GetFormat(Type? formatType) { return provider.GetFormat(formatType); } } internal static class ReflectionExtensions { private static readonly FieldInfo? RemoteStackTraceField = typeof(Exception).GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic); public static Type? BaseType(this Type type) { return type.BaseType; } public static bool IsValueType(this Type type) { return type.IsValueType; } public static bool IsGenericType(this Type type) { return type.IsGenericType; } public static bool IsGenericTypeDefinition(this Type type) { return type.IsGenericTypeDefinition; } public static bool IsInterface(this Type type) { return type.IsInterface; } public static bool IsEnum(this Type type) { return type.IsEnum; } public static bool IsDbNull(this object value) { return value is DBNull; } public static bool HasDefaultConstructor(this Type type) { if (!type.IsValueType) { return type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null) != null; } return true; } public static TypeCode GetTypeCode(this Type type) { return Type.GetTypeCode(type); } public static PropertyInfo? GetPublicProperty(this Type type, string name) { return type.GetProperty(name); } public static FieldInfo? GetPublicStaticField(this Type type, string name) { return type.GetField(name, BindingFlags.Static | BindingFlags.Public); } public static IEnumerable GetProperties(this Type type, bool includeNonPublic) { BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; if (includeNonPublic) { bindingFlags |= BindingFlags.NonPublic; } if (!type.IsInterface) { return type.GetProperties(bindingFlags); } return new Type[1] { type }.Concat(type.GetInterfaces()).SelectMany((Type i) => i.GetProperties(bindingFlags)); } public static IEnumerable GetPublicProperties(this Type type) { return type.GetProperties(includeNonPublic: false); } public static IEnumerable GetPublicFields(this Type type) { return type.GetFields(BindingFlags.Instance | BindingFlags.Public); } public static IEnumerable GetPublicStaticMethods(this Type type) { return type.GetMethods(BindingFlags.Static | BindingFlags.Public); } public static MethodInfo GetPrivateStaticMethod(this Type type, string name) { return type.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic) ?? throw new MissingMethodException("Expected to find a method named '" + name + "' in '" + type.FullName + "'."); } public static MethodInfo? GetPublicStaticMethod(this Type type, string name, params Type[] parameterTypes) { return type.GetMethod(name, BindingFlags.Static | BindingFlags.Public, null, parameterTypes, null); } public static MethodInfo? GetPublicInstanceMethod(this Type type, string name) { return type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public); } public static Exception Unwrap(this TargetInvocationException ex) { Exception innerException = ex.InnerException; if (innerException == null) { return ex; } if (RemoteStackTraceField != null) { RemoteStackTraceField.SetValue(innerException, innerException.StackTrace + "\r\n"); } return innerException; } public static bool IsInstanceOf(this Type type, object o) { return type.IsInstanceOfType(o); } public static Attribute[] GetAllCustomAttributes(this PropertyInfo property) { return Attribute.GetCustomAttributes(property, typeof(TAttribute)); } } internal static class PropertyInfoExtensions { public static object? ReadValue(this PropertyInfo property, object target) { return property.GetValue(target, null); } } internal static class StandardRegexOptions { public const RegexOptions Compiled = RegexOptions.Compiled; } } namespace YamlDotNet.Serialization { internal abstract class BuilderSkeleton where TBuilder : BuilderSkeleton { internal INamingConvention namingConvention = NullNamingConvention.Instance; internal ITypeResolver typeResolver; internal readonly YamlAttributeOverrides overrides; internal readonly LazyComponentRegistrationList typeConverterFactories; internal readonly LazyComponentRegistrationList typeInspectorFactories; private bool ignoreFields; private bool includeNonPublicProperties; protected abstract TBuilder Self { get; } internal BuilderSkeleton(ITypeResolver typeResolver) { overrides = new YamlAttributeOverrides(); typeConverterFactories = new LazyComponentRegistrationList { { typeof(YamlDotNet.Serialization.Converters.GuidConverter), (Nothing _) => new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: false) }, { typeof(SystemTypeConverter), (Nothing _) => new SystemTypeConverter() } }; typeInspectorFactories = new LazyComponentRegistrationList(); this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); } internal ITypeInspector BuildTypeInspector() { ITypeInspector typeInspector = new ReadablePropertiesTypeInspector(typeResolver, includeNonPublicProperties); if (!ignoreFields) { typeInspector = new CompositeTypeInspector(new ReadableFieldsTypeInspector(typeResolver), typeInspector); } return typeInspectorFactories.BuildComponentChain(typeInspector); } public TBuilder IgnoreFields() { ignoreFields = true; return Self; } public TBuilder IncludeNonPublicProperties() { includeNonPublicProperties = true; return Self; } public TBuilder WithNamingConvention(INamingConvention namingConvention) { this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention"); return Self; } public TBuilder WithTypeResolver(ITypeResolver typeResolver) { this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); return Self; } public abstract TBuilder WithTagMapping(TagName tag, Type type); public TBuilder WithAttributeOverride(Expression> propertyAccessor, Attribute attribute) { overrides.Add(propertyAccessor, attribute); return Self; } public TBuilder WithAttributeOverride(Type type, string member, Attribute attribute) { overrides.Add(type, member, attribute); return Self; } public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter) { return WithTypeConverter(typeConverter, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter, Action> where) { IYamlTypeConverter typeConverter2 = typeConverter; if (typeConverter2 == null) { throw new ArgumentNullException("typeConverter"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeConverterFactories.CreateRegistrationLocationSelector(typeConverter2.GetType(), (Nothing _) => typeConverter2)); return Self; } public TBuilder WithTypeConverter(WrapperFactory typeConverterFactory, Action> where) where TYamlTypeConverter : IYamlTypeConverter { WrapperFactory typeConverterFactory2 = typeConverterFactory; if (typeConverterFactory2 == null) { throw new ArgumentNullException("typeConverterFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeConverterFactories.CreateTrackingRegistrationLocationSelector(typeof(TYamlTypeConverter), (IYamlTypeConverter wrapped, Nothing _) => typeConverterFactory2(wrapped))); return Self; } public TBuilder WithoutTypeConverter() where TYamlTypeConverter : IYamlTypeConverter { return WithoutTypeConverter(typeof(TYamlTypeConverter)); } public TBuilder WithoutTypeConverter(Type converterType) { if (converterType == null) { throw new ArgumentNullException("converterType"); } typeConverterFactories.Remove(converterType); return Self; } public TBuilder WithTypeInspector(Func typeInspectorFactory) where TTypeInspector : ITypeInspector { return WithTypeInspector(typeInspectorFactory, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public TBuilder WithTypeInspector(Func typeInspectorFactory, Action> where) where TTypeInspector : ITypeInspector { Func typeInspectorFactory2 = typeInspectorFactory; if (typeInspectorFactory2 == null) { throw new ArgumentNullException("typeInspectorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeInspectorFactories.CreateRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector inner) => typeInspectorFactory2(inner))); return Self; } public TBuilder WithTypeInspector(WrapperFactory typeInspectorFactory, Action> where) where TTypeInspector : ITypeInspector { WrapperFactory typeInspectorFactory2 = typeInspectorFactory; if (typeInspectorFactory2 == null) { throw new ArgumentNullException("typeInspectorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(typeInspectorFactories.CreateTrackingRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector wrapped, ITypeInspector inner) => typeInspectorFactory2(wrapped, inner))); return Self; } public TBuilder WithoutTypeInspector() where TTypeInspector : ITypeInspector { return WithoutTypeInspector(typeof(TTypeInspector)); } public TBuilder WithoutTypeInspector(Type inspectorType) { if (inspectorType == null) { throw new ArgumentNullException("inspectorType"); } typeInspectorFactories.Remove(inspectorType); return Self; } protected IEnumerable BuildTypeConverters() { return typeConverterFactories.BuildComponentList(); } } internal delegate TComponent WrapperFactory(TComponentBase wrapped) where TComponent : TComponentBase; internal delegate TComponent WrapperFactory(TComponentBase wrapped, TArgument argument) where TComponent : TComponentBase; [Flags] internal enum DefaultValuesHandling { Preserve = 0, OmitNull = 1, OmitDefaults = 2, OmitEmptyCollections = 4 } internal sealed class Deserializer : IDeserializer { private readonly IValueDeserializer valueDeserializer; public Deserializer() : this(new DeserializerBuilder().BuildValueDeserializer()) { } private Deserializer(IValueDeserializer valueDeserializer) { this.valueDeserializer = valueDeserializer ?? throw new ArgumentNullException("valueDeserializer"); } public static Deserializer FromValueDeserializer(IValueDeserializer valueDeserializer) { return new Deserializer(valueDeserializer); } public T Deserialize(string input) { using StringReader input2 = new StringReader(input); return Deserialize(input2); } public T Deserialize(TextReader input) { return Deserialize(new Parser(input)); } public object? Deserialize(TextReader input) { return Deserialize(input, typeof(object)); } public object? Deserialize(string input, Type type) { using StringReader input2 = new StringReader(input); return Deserialize(input2, type); } public object? Deserialize(TextReader input, Type type) { return Deserialize(new Parser(input), type); } public T Deserialize(IParser parser) { return (T)Deserialize(parser, typeof(T)); } public object? Deserialize(IParser parser) { return Deserialize(parser, typeof(object)); } public object? Deserialize(IParser parser, Type type) { if (parser == null) { throw new ArgumentNullException("parser"); } if (type == null) { throw new ArgumentNullException("type"); } YamlDotNet.Core.Events.StreamStart @event; bool flag = parser.TryConsume(out @event); YamlDotNet.Core.Events.DocumentStart event2; bool flag2 = parser.TryConsume(out event2); object result = null; if (!parser.Accept(out var _) && !parser.Accept(out var _)) { using SerializerState serializerState = new SerializerState(); result = valueDeserializer.DeserializeValue(parser, type, serializerState, valueDeserializer); serializerState.OnDeserialization(); } if (flag2) { parser.Consume(); } if (flag) { parser.Consume(); } return result; } } internal sealed class DeserializerBuilder : BuilderSkeleton { private Lazy objectFactory; private readonly LazyComponentRegistrationList nodeDeserializerFactories; private readonly LazyComponentRegistrationList nodeTypeResolverFactories; private readonly Dictionary tagMappings; private readonly Dictionary typeMappings; private bool ignoreUnmatched; protected override DeserializerBuilder Self => this; public DeserializerBuilder() : base((ITypeResolver)new StaticTypeResolver()) { typeMappings = new Dictionary(); objectFactory = new Lazy(() => new DefaultObjectFactory(typeMappings), isThreadSafe: true); tagMappings = new Dictionary { { FailsafeSchema.Tags.Map, typeof(Dictionary) }, { FailsafeSchema.Tags.Str, typeof(string) }, { JsonSchema.Tags.Bool, typeof(bool) }, { JsonSchema.Tags.Float, typeof(double) }, { JsonSchema.Tags.Int, typeof(int) }, { DefaultSchema.Tags.Timestamp, typeof(DateTime) } }; typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner)); typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner); typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner)); typeInspectorFactories.Add(typeof(YamlAttributeOverridesInspector), (ITypeInspector inner) => (overrides == null) ? inner : new YamlAttributeOverridesInspector(inner, overrides.Clone())); typeInspectorFactories.Add(typeof(ReadableAndWritablePropertiesTypeInspector), (ITypeInspector inner) => new ReadableAndWritablePropertiesTypeInspector(inner)); nodeDeserializerFactories = new LazyComponentRegistrationList { { typeof(YamlConvertibleNodeDeserializer), (Nothing _) => new YamlConvertibleNodeDeserializer(objectFactory.Value) }, { typeof(YamlSerializableNodeDeserializer), (Nothing _) => new YamlSerializableNodeDeserializer(objectFactory.Value) }, { typeof(TypeConverterNodeDeserializer), (Nothing _) => new TypeConverterNodeDeserializer(BuildTypeConverters()) }, { typeof(NullNodeDeserializer), (Nothing _) => new NullNodeDeserializer() }, { typeof(ScalarNodeDeserializer), (Nothing _) => new ScalarNodeDeserializer() }, { typeof(ArrayNodeDeserializer), (Nothing _) => new ArrayNodeDeserializer() }, { typeof(DictionaryNodeDeserializer), (Nothing _) => new DictionaryNodeDeserializer(objectFactory.Value) }, { typeof(CollectionNodeDeserializer), (Nothing _) => new CollectionNodeDeserializer(objectFactory.Value) }, { typeof(EnumerableNodeDeserializer), (Nothing _) => new EnumerableNodeDeserializer() }, { typeof(ObjectNodeDeserializer), (Nothing _) => new ObjectNodeDeserializer(objectFactory.Value, BuildTypeInspector(), ignoreUnmatched) } }; nodeTypeResolverFactories = new LazyComponentRegistrationList { { typeof(MappingNodeTypeResolver), (Nothing _) => new MappingNodeTypeResolver(typeMappings) }, { typeof(YamlConvertibleTypeResolver), (Nothing _) => new YamlConvertibleTypeResolver() }, { typeof(YamlSerializableTypeResolver), (Nothing _) => new YamlSerializableTypeResolver() }, { typeof(TagNodeTypeResolver), (Nothing _) => new TagNodeTypeResolver(tagMappings) }, { typeof(PreventUnknownTagsNodeTypeResolver), (Nothing _) => new PreventUnknownTagsNodeTypeResolver() }, { typeof(DefaultContainersNodeTypeResolver), (Nothing _) => new DefaultContainersNodeTypeResolver() } }; } public DeserializerBuilder WithObjectFactory(IObjectFactory objectFactory) { IObjectFactory objectFactory2 = objectFactory; if (objectFactory2 == null) { throw new ArgumentNullException("objectFactory"); } this.objectFactory = new Lazy(() => objectFactory2, isThreadSafe: true); return this; } public DeserializerBuilder WithObjectFactory(Func objectFactory) { if (objectFactory == null) { throw new ArgumentNullException("objectFactory"); } return WithObjectFactory(new LambdaObjectFactory(objectFactory)); } public DeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer) { return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public DeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer, Action> where) { INodeDeserializer nodeDeserializer2 = nodeDeserializer; if (nodeDeserializer2 == null) { throw new ArgumentNullException("nodeDeserializer"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeDeserializerFactories.CreateRegistrationLocationSelector(nodeDeserializer2.GetType(), (Nothing _) => nodeDeserializer2)); return this; } public DeserializerBuilder WithNodeDeserializer(WrapperFactory nodeDeserializerFactory, Action> where) where TNodeDeserializer : INodeDeserializer { WrapperFactory nodeDeserializerFactory2 = nodeDeserializerFactory; if (nodeDeserializerFactory2 == null) { throw new ArgumentNullException("nodeDeserializerFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeDeserializerFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeDeserializer), (INodeDeserializer wrapped, Nothing _) => nodeDeserializerFactory2(wrapped))); return this; } public DeserializerBuilder WithoutNodeDeserializer() where TNodeDeserializer : INodeDeserializer { return WithoutNodeDeserializer(typeof(TNodeDeserializer)); } public DeserializerBuilder WithoutNodeDeserializer(Type nodeDeserializerType) { if (nodeDeserializerType == null) { throw new ArgumentNullException("nodeDeserializerType"); } nodeDeserializerFactories.Remove(nodeDeserializerType); return this; } public DeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver) { return WithNodeTypeResolver(nodeTypeResolver, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public DeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver, Action> where) { INodeTypeResolver nodeTypeResolver2 = nodeTypeResolver; if (nodeTypeResolver2 == null) { throw new ArgumentNullException("nodeTypeResolver"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeTypeResolverFactories.CreateRegistrationLocationSelector(nodeTypeResolver2.GetType(), (Nothing _) => nodeTypeResolver2)); return this; } public DeserializerBuilder WithNodeTypeResolver(WrapperFactory nodeTypeResolverFactory, Action> where) where TNodeTypeResolver : INodeTypeResolver { WrapperFactory nodeTypeResolverFactory2 = nodeTypeResolverFactory; if (nodeTypeResolverFactory2 == null) { throw new ArgumentNullException("nodeTypeResolverFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(nodeTypeResolverFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeTypeResolver), (INodeTypeResolver wrapped, Nothing _) => nodeTypeResolverFactory2(wrapped))); return this; } public DeserializerBuilder WithoutNodeTypeResolver() where TNodeTypeResolver : INodeTypeResolver { return WithoutNodeTypeResolver(typeof(TNodeTypeResolver)); } public DeserializerBuilder WithoutNodeTypeResolver(Type nodeTypeResolverType) { if (nodeTypeResolverType == null) { throw new ArgumentNullException("nodeTypeResolverType"); } nodeTypeResolverFactories.Remove(nodeTypeResolverType); return this; } public override DeserializerBuilder WithTagMapping(TagName tag, Type type) { if (tag.IsEmpty) { throw new ArgumentException("Non-specific tags cannot be maped"); } if (type == null) { throw new ArgumentNullException("type"); } if (tagMappings.TryGetValue(tag, out Type value)) { throw new ArgumentException($"Type already has a registered type '{value.FullName}' for tag '{tag}'", "tag"); } tagMappings.Add(tag, type); return this; } public DeserializerBuilder WithTypeMapping() where TConcrete : TInterface { Type typeFromHandle = typeof(TInterface); Type typeFromHandle2 = typeof(TConcrete); if (!typeFromHandle.IsAssignableFrom(typeFromHandle2)) { throw new InvalidOperationException("The type '" + typeFromHandle2.Name + "' does not implement interface '" + typeFromHandle.Name + "'."); } if (typeMappings.ContainsKey(typeFromHandle)) { typeMappings[typeFromHandle] = typeFromHandle2; } else { typeMappings.Add(typeFromHandle, typeFromHandle2); } return this; } public DeserializerBuilder WithoutTagMapping(TagName tag) { if (tag.IsEmpty) { throw new ArgumentException("Non-specific tags cannot be maped"); } if (!tagMappings.Remove(tag)) { throw new KeyNotFoundException($"Tag '{tag}' is not registered"); } return this; } public DeserializerBuilder IgnoreUnmatchedProperties() { ignoreUnmatched = true; return this; } public IDeserializer Build() { return Deserializer.FromValueDeserializer(BuildValueDeserializer()); } public IValueDeserializer BuildValueDeserializer() { return new AliasValueDeserializer(new NodeValueDeserializer(nodeDeserializerFactories.BuildComponentList(), nodeTypeResolverFactories.BuildComponentList())); } } internal sealed class EmissionPhaseObjectGraphVisitorArgs { private readonly IEnumerable> preProcessingPhaseVisitors; public IObjectGraphVisitor InnerVisitor { get; private set; } public IEventEmitter EventEmitter { get; private set; } public ObjectSerializer NestedObjectSerializer { get; private set; } public IEnumerable TypeConverters { get; private set; } public EmissionPhaseObjectGraphVisitorArgs(IObjectGraphVisitor innerVisitor, IEventEmitter eventEmitter, IEnumerable> preProcessingPhaseVisitors, IEnumerable typeConverters, ObjectSerializer nestedObjectSerializer) { InnerVisitor = innerVisitor ?? throw new ArgumentNullException("innerVisitor"); EventEmitter = eventEmitter ?? throw new ArgumentNullException("eventEmitter"); this.preProcessingPhaseVisitors = preProcessingPhaseVisitors ?? throw new ArgumentNullException("preProcessingPhaseVisitors"); TypeConverters = typeConverters ?? throw new ArgumentNullException("typeConverters"); NestedObjectSerializer = nestedObjectSerializer ?? throw new ArgumentNullException("nestedObjectSerializer"); } public T GetPreProcessingPhaseObjectGraphVisitor() where T : IObjectGraphVisitor { return preProcessingPhaseVisitors.OfType().Single(); } } internal abstract class EventInfo { public IObjectDescriptor Source { get; } protected EventInfo(IObjectDescriptor source) { Source = source ?? throw new ArgumentNullException("source"); } } internal class AliasEventInfo : EventInfo { public AnchorName Alias { get; } public bool NeedsExpansion { get; set; } public AliasEventInfo(IObjectDescriptor source, AnchorName alias) : base(source) { if (alias.IsEmpty) { throw new ArgumentNullException("alias"); } Alias = alias; } } internal class ObjectEventInfo : EventInfo { public AnchorName Anchor { get; set; } public TagName Tag { get; set; } protected ObjectEventInfo(IObjectDescriptor source) : base(source) { } } internal sealed class ScalarEventInfo : ObjectEventInfo { public string RenderedValue { get; set; } public ScalarStyle Style { get; set; } public bool IsPlainImplicit { get; set; } public bool IsQuotedImplicit { get; set; } public ScalarEventInfo(IObjectDescriptor source) : base(source) { Style = source.ScalarStyle; RenderedValue = string.Empty; } } internal sealed class MappingStartEventInfo : ObjectEventInfo { public bool IsImplicit { get; set; } public MappingStyle Style { get; set; } public MappingStartEventInfo(IObjectDescriptor source) : base(source) { } } internal sealed class MappingEndEventInfo : EventInfo { public MappingEndEventInfo(IObjectDescriptor source) : base(source) { } } internal sealed class SequenceStartEventInfo : ObjectEventInfo { public bool IsImplicit { get; set; } public SequenceStyle Style { get; set; } public SequenceStartEventInfo(IObjectDescriptor source) : base(source) { } } internal sealed class SequenceEndEventInfo : EventInfo { public SequenceEndEventInfo(IObjectDescriptor source) : base(source) { } } internal interface IAliasProvider { AnchorName GetAlias(object target); } internal interface IDeserializer { T Deserialize(string input); T Deserialize(TextReader input); object? Deserialize(TextReader input); object? Deserialize(string input, Type type); object? Deserialize(TextReader input, Type type); T Deserialize(IParser parser); object? Deserialize(IParser parser); object? Deserialize(IParser parser, Type type); } internal interface IEventEmitter { void Emit(AliasEventInfo eventInfo, IEmitter emitter); void Emit(ScalarEventInfo eventInfo, IEmitter emitter); void Emit(MappingStartEventInfo eventInfo, IEmitter emitter); void Emit(MappingEndEventInfo eventInfo, IEmitter emitter); void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter); void Emit(SequenceEndEventInfo eventInfo, IEmitter emitter); } internal interface INamingConvention { string Apply(string value); } internal interface INodeDeserializer { bool Deserialize(IParser reader, Type expectedType, Func nestedObjectDeserializer, out object? value); } internal interface INodeTypeResolver { bool Resolve(NodeEvent? nodeEvent, ref Type currentType); } internal interface IObjectDescriptor { object? Value { get; } Type Type { get; } Type StaticType { get; } ScalarStyle ScalarStyle { get; } } internal static class ObjectDescriptorExtensions { public static object NonNullValue(this IObjectDescriptor objectDescriptor) { return objectDescriptor.Value ?? throw new InvalidOperationException("Attempted to use a IObjectDescriptor of type '" + objectDescriptor.Type.FullName + "' whose Value is null at a point whete it is invalid to do so. This may indicate a bug in YamlDotNet."); } } internal interface IObjectFactory { object Create(Type type); } internal interface IObjectGraphTraversalStrategy { void Traverse(IObjectDescriptor graph, IObjectGraphVisitor visitor, TContext context); } internal interface IObjectGraphVisitor { bool Enter(IObjectDescriptor value, TContext context); bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, TContext context); bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, TContext context); void VisitScalar(IObjectDescriptor scalar, TContext context); void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, TContext context); void VisitMappingEnd(IObjectDescriptor mapping, TContext context); void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, TContext context); void VisitSequenceEnd(IObjectDescriptor sequence, TContext context); } internal interface IPropertyDescriptor { string Name { get; } bool CanWrite { get; } Type Type { get; } Type? TypeOverride { get; set; } int Order { get; set; } ScalarStyle ScalarStyle { get; set; } T GetCustomAttribute() where T : Attribute; IObjectDescriptor Read(object target); void Write(object target, object? value); } internal interface IRegistrationLocationSelectionSyntax { void InsteadOf() where TRegistrationType : TBaseRegistrationType; void Before() where TRegistrationType : TBaseRegistrationType; void After() where TRegistrationType : TBaseRegistrationType; void OnTop(); void OnBottom(); } internal interface ITrackingRegistrationLocationSelectionSyntax { void InsteadOf() where TRegistrationType : TBaseRegistrationType; } internal interface ISerializer { void Serialize(TextWriter writer, object graph); string Serialize(object graph); void Serialize(TextWriter writer, object graph, Type type); void Serialize(IEmitter emitter, object graph); void Serialize(IEmitter emitter, object graph, Type type); } internal interface ITypeInspector { IEnumerable GetProperties(Type type, object? container); IPropertyDescriptor GetProperty(Type type, object? container, string name, [MaybeNullWhen(true)] bool ignoreUnmatched); } internal interface ITypeResolver { Type Resolve(Type staticType, object? actualValue); } internal interface IValueDeserializer { object? DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer); } internal interface IValuePromise { event Action ValueAvailable; } internal interface IValueSerializer { void SerializeValue(IEmitter emitter, object? value, Type? type); } internal interface IYamlConvertible { void Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer); void Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer); } internal delegate object? ObjectDeserializer(Type type); internal delegate void ObjectSerializer(object? value, Type? type = null); [Obsolete("Please use IYamlConvertible instead")] internal interface IYamlSerializable { void ReadYaml(IParser parser); void WriteYaml(IEmitter emitter); } internal interface IYamlTypeConverter { bool Accepts(Type type); object? ReadYaml(IParser parser, Type type); void WriteYaml(IEmitter emitter, object? value, Type type); } internal sealed class LazyComponentRegistrationList : IEnumerable>, IEnumerable { public sealed class LazyComponentRegistration { public readonly Type ComponentType; public readonly Func Factory; public LazyComponentRegistration(Type componentType, Func factory) { ComponentType = componentType; Factory = factory; } } public sealed class TrackingLazyComponentRegistration { public readonly Type ComponentType; public readonly Func Factory; public TrackingLazyComponentRegistration(Type componentType, Func factory) { ComponentType = componentType; Factory = factory; } } private class RegistrationLocationSelector : IRegistrationLocationSelectionSyntax { private readonly LazyComponentRegistrationList registrations; private readonly LazyComponentRegistration newRegistration; public RegistrationLocationSelector(LazyComponentRegistrationList registrations, LazyComponentRegistration newRegistration) { this.registrations = registrations; this.newRegistration = newRegistration; } void IRegistrationLocationSelectionSyntax.InsteadOf() { if (newRegistration.ComponentType != typeof(TRegistrationType)) { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); } int index = registrations.EnsureRegistrationExists(); registrations.entries[index] = newRegistration; } void IRegistrationLocationSelectionSyntax.After() { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); int num = registrations.EnsureRegistrationExists(); registrations.entries.Insert(num + 1, newRegistration); } void IRegistrationLocationSelectionSyntax.Before() { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); int index = registrations.EnsureRegistrationExists(); registrations.entries.Insert(index, newRegistration); } void IRegistrationLocationSelectionSyntax.OnBottom() { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); registrations.entries.Add(newRegistration); } void IRegistrationLocationSelectionSyntax.OnTop() { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); registrations.entries.Insert(0, newRegistration); } } private class TrackingRegistrationLocationSelector : ITrackingRegistrationLocationSelectionSyntax { private readonly LazyComponentRegistrationList registrations; private readonly TrackingLazyComponentRegistration newRegistration; public TrackingRegistrationLocationSelector(LazyComponentRegistrationList registrations, TrackingLazyComponentRegistration newRegistration) { this.registrations = registrations; this.newRegistration = newRegistration; } void ITrackingRegistrationLocationSelectionSyntax.InsteadOf() { if (newRegistration.ComponentType != typeof(TRegistrationType)) { registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType); } int index = registrations.EnsureRegistrationExists(); Func innerComponentFactory = registrations.entries[index].Factory; registrations.entries[index] = new LazyComponentRegistration(newRegistration.ComponentType, (TArgument arg) => newRegistration.Factory(innerComponentFactory(arg), arg)); } } private readonly List entries = new List(); public int Count => entries.Count; public IEnumerable> InReverseOrder { get { int i = entries.Count - 1; while (i >= 0) { yield return entries[i].Factory; int num = i - 1; i = num; } } } public LazyComponentRegistrationList Clone() { LazyComponentRegistrationList lazyComponentRegistrationList = new LazyComponentRegistrationList(); foreach (LazyComponentRegistration entry in entries) { lazyComponentRegistrationList.entries.Add(entry); } return lazyComponentRegistrationList; } public void Add(Type componentType, Func factory) { entries.Add(new LazyComponentRegistration(componentType, factory)); } public void Remove(Type componentType) { for (int i = 0; i < entries.Count; i++) { if (entries[i].ComponentType == componentType) { entries.RemoveAt(i); return; } } throw new KeyNotFoundException("A component registration of type '" + componentType.FullName + "' was not found."); } public IRegistrationLocationSelectionSyntax CreateRegistrationLocationSelector(Type componentType, Func factory) { return new RegistrationLocationSelector(this, new LazyComponentRegistration(componentType, factory)); } public ITrackingRegistrationLocationSelectionSyntax CreateTrackingRegistrationLocationSelector(Type componentType, Func factory) { return new TrackingRegistrationLocationSelector(this, new TrackingLazyComponentRegistration(componentType, factory)); } public IEnumerator> GetEnumerator() { return entries.Select((LazyComponentRegistration e) => e.Factory).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private int IndexOfRegistration(Type registrationType) { for (int i = 0; i < entries.Count; i++) { if (registrationType == entries[i].ComponentType) { return i; } } return -1; } private void EnsureNoDuplicateRegistrationType(Type componentType) { if (IndexOfRegistration(componentType) != -1) { throw new InvalidOperationException("A component of type '" + componentType.FullName + "' has already been registered."); } } private int EnsureRegistrationExists() { int num = IndexOfRegistration(typeof(TRegistrationType)); if (num == -1) { throw new InvalidOperationException("A component of type '" + typeof(TRegistrationType).FullName + "' has not been registered."); } return num; } } internal static class LazyComponentRegistrationListExtensions { public static TComponent BuildComponentChain(this LazyComponentRegistrationList registrations, TComponent innerComponent) { return registrations.InReverseOrder.Aggregate(innerComponent, (TComponent inner, Func factory) => factory(inner)); } public static TComponent BuildComponentChain(this LazyComponentRegistrationList registrations, TComponent innerComponent, Func argumentBuilder) { Func argumentBuilder2 = argumentBuilder; return registrations.InReverseOrder.Aggregate(innerComponent, (TComponent inner, Func factory) => factory(argumentBuilder2(inner))); } public static List BuildComponentList(this LazyComponentRegistrationList registrations) { return registrations.Select((Func factory) => factory(default(Nothing))).ToList(); } public static List BuildComponentList(this LazyComponentRegistrationList registrations, TArgument argument) { TArgument argument2 = argument; return registrations.Select((Func factory) => factory(argument2)).ToList(); } } [StructLayout(LayoutKind.Sequential, Size = 1)] internal struct Nothing { } internal sealed class ObjectDescriptor : IObjectDescriptor { public object? Value { get; private set; } public Type Type { get; private set; } public Type StaticType { get; private set; } public ScalarStyle ScalarStyle { get; private set; } public ObjectDescriptor(object? value, Type type, Type staticType) : this(value, type, staticType, ScalarStyle.Any) { } public ObjectDescriptor(object? value, Type type, Type staticType, ScalarStyle scalarStyle) { Value = value; Type = type ?? throw new ArgumentNullException("type"); StaticType = staticType ?? throw new ArgumentNullException("staticType"); ScalarStyle = scalarStyle; } } internal delegate IObjectGraphTraversalStrategy ObjectGraphTraversalStrategyFactory(ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable typeConverters, int maximumRecursion); internal sealed class PropertyDescriptor : IPropertyDescriptor { private readonly IPropertyDescriptor baseDescriptor; public string Name { get; set; } public Type Type => baseDescriptor.Type; public Type? TypeOverride { get { return baseDescriptor.TypeOverride; } set { baseDescriptor.TypeOverride = value; } } public int Order { get; set; } public ScalarStyle ScalarStyle { get { return baseDescriptor.ScalarStyle; } set { baseDescriptor.ScalarStyle = value; } } public bool CanWrite => baseDescriptor.CanWrite; public PropertyDescriptor(IPropertyDescriptor baseDescriptor) { this.baseDescriptor = baseDescriptor; Name = baseDescriptor.Name; } public void Write(object target, object? value) { baseDescriptor.Write(target, value); } public T GetCustomAttribute() where T : Attribute { return baseDescriptor.GetCustomAttribute(); } public IObjectDescriptor Read(object target) { return baseDescriptor.Read(target); } } internal sealed class Serializer : ISerializer { private readonly IValueSerializer valueSerializer; private readonly EmitterSettings emitterSettings; public Serializer() : this(new SerializerBuilder().BuildValueSerializer(), EmitterSettings.Default) { } private Serializer(IValueSerializer valueSerializer, EmitterSettings emitterSettings) { this.valueSerializer = valueSerializer ?? throw new ArgumentNullException("valueSerializer"); this.emitterSettings = emitterSettings ?? throw new ArgumentNullException("emitterSettings"); } public static Serializer FromValueSerializer(IValueSerializer valueSerializer, EmitterSettings emitterSettings) { return new Serializer(valueSerializer, emitterSettings); } public void Serialize(TextWriter writer, object graph) { Serialize(new Emitter(writer, emitterSettings), graph); } public string Serialize(object graph) { using StringWriter stringWriter = new StringWriter(); Serialize(stringWriter, graph); return stringWriter.ToString(); } public void Serialize(TextWriter writer, object graph, Type type) { Serialize(new Emitter(writer, emitterSettings), graph, type); } public void Serialize(IEmitter emitter, object graph) { if (emitter == null) { throw new ArgumentNullException("emitter"); } EmitDocument(emitter, graph, null); } public void Serialize(IEmitter emitter, object graph, Type type) { if (emitter == null) { throw new ArgumentNullException("emitter"); } if (type == null) { throw new ArgumentNullException("type"); } EmitDocument(emitter, graph, type); } private void EmitDocument(IEmitter emitter, object graph, Type? type) { emitter.Emit(new YamlDotNet.Core.Events.StreamStart()); emitter.Emit(new YamlDotNet.Core.Events.DocumentStart()); valueSerializer.SerializeValue(emitter, graph, type); emitter.Emit(new YamlDotNet.Core.Events.DocumentEnd(isImplicit: true)); emitter.Emit(new YamlDotNet.Core.Events.StreamEnd()); } } internal sealed class SerializerBuilder : BuilderSkeleton { private class ValueSerializer : IValueSerializer { private readonly IObjectGraphTraversalStrategy traversalStrategy; private readonly IEventEmitter eventEmitter; private readonly IEnumerable typeConverters; private readonly LazyComponentRegistrationList, IObjectGraphVisitor> preProcessingPhaseObjectGraphVisitorFactories; private readonly LazyComponentRegistrationList> emissionPhaseObjectGraphVisitorFactories; public ValueSerializer(IObjectGraphTraversalStrategy traversalStrategy, IEventEmitter eventEmitter, IEnumerable typeConverters, LazyComponentRegistrationList, IObjectGraphVisitor> preProcessingPhaseObjectGraphVisitorFactories, LazyComponentRegistrationList> emissionPhaseObjectGraphVisitorFactories) { this.traversalStrategy = traversalStrategy; this.eventEmitter = eventEmitter; this.typeConverters = typeConverters; this.preProcessingPhaseObjectGraphVisitorFactories = preProcessingPhaseObjectGraphVisitorFactories; this.emissionPhaseObjectGraphVisitorFactories = emissionPhaseObjectGraphVisitorFactories; } public void SerializeValue(IEmitter emitter, object? value, Type? type) { IEmitter emitter2 = emitter; Type type2 = type ?? ((value != null) ? value.GetType() : typeof(object)); Type staticType = type ?? typeof(object); ObjectDescriptor graph = new ObjectDescriptor(value, type2, staticType); List> preProcessingPhaseObjectGraphVisitors = preProcessingPhaseObjectGraphVisitorFactories.BuildComponentList(typeConverters); foreach (IObjectGraphVisitor item in preProcessingPhaseObjectGraphVisitors) { traversalStrategy.Traverse(graph, item, default(Nothing)); } IObjectGraphVisitor visitor = emissionPhaseObjectGraphVisitorFactories.BuildComponentChain>(new EmittingObjectGraphVisitor(eventEmitter), (IObjectGraphVisitor inner) => new EmissionPhaseObjectGraphVisitorArgs(inner, eventEmitter, preProcessingPhaseObjectGraphVisitors, typeConverters, NestedObjectSerializer)); traversalStrategy.Traverse(graph, visitor, emitter2); void NestedObjectSerializer(object? v, Type? t) { SerializeValue(emitter2, v, t); } } } private ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory; private readonly LazyComponentRegistrationList, IObjectGraphVisitor> preProcessingPhaseObjectGraphVisitorFactories; private readonly LazyComponentRegistrationList> emissionPhaseObjectGraphVisitorFactories; private readonly LazyComponentRegistrationList eventEmitterFactories; private readonly IDictionary tagMappings = new Dictionary(); private int maximumRecursion = 50; private EmitterSettings emitterSettings = EmitterSettings.Default; private DefaultValuesHandling defaultValuesHandlingConfiguration; protected override SerializerBuilder Self => this; public SerializerBuilder() : base((ITypeResolver)new DynamicTypeResolver()) { typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner)); typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner); typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner)); typeInspectorFactories.Add(typeof(YamlAttributeOverridesInspector), (ITypeInspector inner) => (overrides == null) ? inner : new YamlAttributeOverridesInspector(inner, overrides.Clone())); preProcessingPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList, IObjectGraphVisitor> { { typeof(AnchorAssigner), (IEnumerable typeConverters) => new AnchorAssigner(typeConverters) } }; emissionPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList> { { typeof(CustomSerializationObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new CustomSerializationObjectGraphVisitor(args.InnerVisitor, args.TypeConverters, args.NestedObjectSerializer) }, { typeof(AnchorAssigningObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new AnchorAssigningObjectGraphVisitor(args.InnerVisitor, args.EventEmitter, args.GetPreProcessingPhaseObjectGraphVisitor()) }, { typeof(DefaultValuesObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new DefaultValuesObjectGraphVisitor(defaultValuesHandlingConfiguration, args.InnerVisitor) }, { typeof(CommentsObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => new CommentsObjectGraphVisitor(args.InnerVisitor) } }; eventEmitterFactories = new LazyComponentRegistrationList { { typeof(TypeAssigningEventEmitter), (IEventEmitter inner) => new TypeAssigningEventEmitter(inner, requireTagWhenStaticAndActualTypesAreDifferent: false, tagMappings) } }; objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable typeConverters, int maximumRecursion) => new FullObjectGraphTraversalStrategy(typeInspector, typeResolver, maximumRecursion, namingConvention); } public SerializerBuilder WithMaximumRecursion(int maximumRecursion) { if (maximumRecursion <= 0) { throw new ArgumentOutOfRangeException("maximumRecursion", $"The maximum recursion specified ({maximumRecursion}) is invalid. It should be a positive integer."); } this.maximumRecursion = maximumRecursion; return this; } public SerializerBuilder WithEventEmitter(Func eventEmitterFactory) where TEventEmitter : IEventEmitter { return WithEventEmitter(eventEmitterFactory, delegate(IRegistrationLocationSelectionSyntax w) { w.OnTop(); }); } public SerializerBuilder WithEventEmitter(Func eventEmitterFactory, Action> where) where TEventEmitter : IEventEmitter { Func eventEmitterFactory2 = eventEmitterFactory; if (eventEmitterFactory2 == null) { throw new ArgumentNullException("eventEmitterFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(eventEmitterFactories.CreateRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter inner) => eventEmitterFactory2(inner))); return Self; } public SerializerBuilder WithEventEmitter(WrapperFactory eventEmitterFactory, Action> where) where TEventEmitter : IEventEmitter { WrapperFactory eventEmitterFactory2 = eventEmitterFactory; if (eventEmitterFactory2 == null) { throw new ArgumentNullException("eventEmitterFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(eventEmitterFactories.CreateTrackingRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter wrapped, IEventEmitter inner) => eventEmitterFactory2(wrapped, inner))); return Self; } public SerializerBuilder WithoutEventEmitter() where TEventEmitter : IEventEmitter { return WithoutEventEmitter(typeof(TEventEmitter)); } public SerializerBuilder WithoutEventEmitter(Type eventEmitterType) { if (eventEmitterType == null) { throw new ArgumentNullException("eventEmitterType"); } eventEmitterFactories.Remove(eventEmitterType); return this; } public override SerializerBuilder WithTagMapping(TagName tag, Type type) { if (tag.IsEmpty) { throw new ArgumentException("Non-specific tags cannot be maped"); } if (type == null) { throw new ArgumentNullException("type"); } if (tagMappings.TryGetValue(type, out var value)) { throw new ArgumentException($"Type already has a registered tag '{value}' for type '{type.FullName}'", "type"); } tagMappings.Add(type, tag); return this; } public SerializerBuilder WithoutTagMapping(Type type) { if (type == null) { throw new ArgumentNullException("type"); } if (!tagMappings.Remove(type)) { throw new KeyNotFoundException("Tag for type '" + type.FullName + "' is not registered"); } return this; } public SerializerBuilder EnsureRoundtrip() { objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable typeConverters, int maximumRecursion) => new RoundtripObjectGraphTraversalStrategy(typeConverters, typeInspector, typeResolver, maximumRecursion, namingConvention); WithEventEmitter((IEventEmitter inner) => new TypeAssigningEventEmitter(inner, requireTagWhenStaticAndActualTypesAreDifferent: true, tagMappings), delegate(IRegistrationLocationSelectionSyntax loc) { loc.InsteadOf(); }); return WithTypeInspector((ITypeInspector inner) => new ReadableAndWritablePropertiesTypeInspector(inner), delegate(IRegistrationLocationSelectionSyntax loc) { loc.OnBottom(); }); } public SerializerBuilder DisableAliases() { preProcessingPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigner)); emissionPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigningObjectGraphVisitor)); return this; } [Obsolete("The default behavior is now to always emit default values, thefore calling this method has no effect. This behavior is now controlled by ConfigureDefaultValuesHandling.", true)] public SerializerBuilder EmitDefaults() { return ConfigureDefaultValuesHandling(DefaultValuesHandling.Preserve); } public SerializerBuilder ConfigureDefaultValuesHandling(DefaultValuesHandling configuration) { defaultValuesHandlingConfiguration = configuration; return this; } public SerializerBuilder JsonCompatible() { emitterSettings = emitterSettings.WithMaxSimpleKeyLength(int.MaxValue).WithoutAnchorName(); return WithTypeConverter(new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: true), delegate(IRegistrationLocationSelectionSyntax w) { w.InsteadOf(); }).WithEventEmitter((IEventEmitter inner) => new JsonEventEmitter(inner), delegate(IRegistrationLocationSelectionSyntax loc) { loc.InsteadOf(); }); } public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(TObjectGraphVisitor objectGraphVisitor) where TObjectGraphVisitor : IObjectGraphVisitor { return WithPreProcessingPhaseObjectGraphVisitor(objectGraphVisitor, delegate(IRegistrationLocationSelectionSyntax> w) { w.OnTop(); }); } public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(TObjectGraphVisitor objectGraphVisitor, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { TObjectGraphVisitor objectGraphVisitor2 = objectGraphVisitor; if (objectGraphVisitor2 == null) { throw new ArgumentNullException("objectGraphVisitor"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IEnumerable _) => objectGraphVisitor2)); return this; } public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor(WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(preProcessingPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor wrapped, IEnumerable _) => objectGraphVisitorFactory2(wrapped))); return this; } public SerializerBuilder WithoutPreProcessingPhaseObjectGraphVisitor() where TObjectGraphVisitor : IObjectGraphVisitor { return WithoutPreProcessingPhaseObjectGraphVisitor(typeof(TObjectGraphVisitor)); } public SerializerBuilder WithoutPreProcessingPhaseObjectGraphVisitor(Type objectGraphVisitorType) { if (objectGraphVisitorType == null) { throw new ArgumentNullException("objectGraphVisitorType"); } preProcessingPhaseObjectGraphVisitorFactories.Remove(objectGraphVisitorType); return this; } public SerializerBuilder WithObjectGraphTraversalStrategyFactory(ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory) { this.objectGraphTraversalStrategyFactory = objectGraphTraversalStrategyFactory; return this; } public SerializerBuilder WithEmissionPhaseObjectGraphVisitor(Func objectGraphVisitorFactory) where TObjectGraphVisitor : IObjectGraphVisitor { return WithEmissionPhaseObjectGraphVisitor(objectGraphVisitorFactory, delegate(IRegistrationLocationSelectionSyntax> w) { w.OnTop(); }); } public SerializerBuilder WithEmissionPhaseObjectGraphVisitor(Func objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { Func objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(emissionPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => objectGraphVisitorFactory2(args))); return this; } public SerializerBuilder WithEmissionPhaseObjectGraphVisitor(WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory, Action>> where) where TObjectGraphVisitor : IObjectGraphVisitor { WrapperFactory, TObjectGraphVisitor> objectGraphVisitorFactory2 = objectGraphVisitorFactory; if (objectGraphVisitorFactory2 == null) { throw new ArgumentNullException("objectGraphVisitorFactory"); } if (where == null) { throw new ArgumentNullException("where"); } where(emissionPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor wrapped, EmissionPhaseObjectGraphVisitorArgs args) => objectGraphVisitorFactory2(wrapped, args))); return this; } public SerializerBuilder WithoutEmissionPhaseObjectGraphVisitor() where TObjectGraphVisitor : IObjectGraphVisitor { return WithoutEmissionPhaseObjectGraphVisitor(typeof(TObjectGraphVisitor)); } public SerializerBuilder WithoutEmissionPhaseObjectGraphVisitor(Type objectGraphVisitorType) { if (objectGraphVisitorType == null) { throw new ArgumentNullException("objectGraphVisitorType"); } emissionPhaseObjectGraphVisitorFactories.Remove(objectGraphVisitorType); return this; } public SerializerBuilder WithIndentedSequences() { emitterSettings = emitterSettings.WithIndentedSequences(); return this; } public ISerializer Build() { return Serializer.FromValueSerializer(BuildValueSerializer(), emitterSettings); } public IValueSerializer BuildValueSerializer() { IEnumerable typeConverters = BuildTypeConverters(); ITypeInspector typeInspector = BuildTypeInspector(); IObjectGraphTraversalStrategy traversalStrategy = objectGraphTraversalStrategyFactory(typeInspector, typeResolver, typeConverters, maximumRecursion); IEventEmitter eventEmitter = eventEmitterFactories.BuildComponentChain(new WriterEventEmitter()); return new ValueSerializer(traversalStrategy, eventEmitter, typeConverters, preProcessingPhaseObjectGraphVisitorFactories.Clone(), emissionPhaseObjectGraphVisitorFactories.Clone()); } } internal sealed class StreamFragment : IYamlConvertible { private readonly List events = new List(); public IList Events => events; void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { events.Clear(); int num = 0; do { if (!parser.MoveNext()) { throw new InvalidOperationException("The parser has reached the end before deserialization completed."); } ParsingEvent current = parser.Current; events.Add(current); num += current.NestingIncrease; } while (num > 0); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { foreach (ParsingEvent @event in events) { emitter.Emit(@event); } } } internal sealed class TagMappings { private readonly IDictionary mappings; public TagMappings() { mappings = new Dictionary(); } public TagMappings(IDictionary mappings) { this.mappings = new Dictionary(mappings); } public void Add(string tag, Type mapping) { mappings.Add(tag, mapping); } internal Type? GetMapping(string tag) { if (!mappings.TryGetValue(tag, out Type value)) { return null; } return value; } } internal sealed class YamlAttributeOverrides { private struct AttributeKey { public readonly Type AttributeType; public readonly string PropertyName; public AttributeKey(Type attributeType, string propertyName) { AttributeType = attributeType; PropertyName = propertyName; } public override bool Equals(object? obj) { if (obj is AttributeKey attributeKey && AttributeType.Equals(attributeKey.AttributeType)) { return PropertyName.Equals(attributeKey.PropertyName); } return false; } public override int GetHashCode() { return YamlDotNet.Core.HashCode.CombineHashCodes(AttributeType.GetHashCode(), PropertyName.GetHashCode()); } } private sealed class AttributeMapping { public readonly Type RegisteredType; public readonly Attribute Attribute; public AttributeMapping(Type registeredType, Attribute attribute) { RegisteredType = registeredType; Attribute = attribute; } public override bool Equals(object? obj) { if (obj is AttributeMapping attributeMapping && RegisteredType.Equals(attributeMapping.RegisteredType)) { return Attribute.Equals(attributeMapping.Attribute); } return false; } public override int GetHashCode() { return YamlDotNet.Core.HashCode.CombineHashCodes(RegisteredType.GetHashCode(), Attribute.GetHashCode()); } public int Matches(Type matchType) { int num = 0; Type type = matchType; while (type != null) { num++; if (type == RegisteredType) { return num; } type = type.BaseType(); } if (matchType.GetInterfaces().Contains(RegisteredType)) { return num; } return 0; } } private readonly Dictionary> overrides = new Dictionary>(); public T? GetAttribute(Type type, string member) where T : Attribute { if (overrides.TryGetValue(new AttributeKey(typeof(T), member), out List value)) { int num = 0; AttributeMapping attributeMapping = null; foreach (AttributeMapping item in value) { int num2 = item.Matches(type); if (num2 > num) { num = num2; attributeMapping = item; } } if (num > 0) { return (T)attributeMapping.Attribute; } } return null; } public void Add(Type type, string member, Attribute attribute) { AttributeMapping item = new AttributeMapping(type, attribute); AttributeKey key = new AttributeKey(attribute.GetType(), member); if (!overrides.TryGetValue(key, out List value)) { value = new List(); overrides.Add(key, value); } else if (value.Contains(item)) { throw new InvalidOperationException($"Attribute ({attribute}) already set for Type {type.FullName}, Member {member}"); } value.Add(item); } public YamlAttributeOverrides Clone() { YamlAttributeOverrides yamlAttributeOverrides = new YamlAttributeOverrides(); foreach (KeyValuePair> @override in overrides) { foreach (AttributeMapping item in @override.Value) { yamlAttributeOverrides.Add(item.RegisteredType, @override.Key.PropertyName, item.Attribute); } } return yamlAttributeOverrides; } public void Add(Expression> propertyAccessor, Attribute attribute) { PropertyInfo propertyInfo = propertyAccessor.AsProperty(); Add(typeof(TClass), propertyInfo.Name, attribute); } } internal sealed class YamlAttributeOverridesInspector : TypeInspectorSkeleton { public sealed class OverridePropertyDescriptor : IPropertyDescriptor { private readonly IPropertyDescriptor baseDescriptor; private readonly YamlAttributeOverrides overrides; private readonly Type classType; public string Name => baseDescriptor.Name; public bool CanWrite => baseDescriptor.CanWrite; public Type Type => baseDescriptor.Type; public Type? TypeOverride { get { return baseDescriptor.TypeOverride; } set { baseDescriptor.TypeOverride = value; } } public int Order { get { return baseDescriptor.Order; } set { baseDescriptor.Order = value; } } public ScalarStyle ScalarStyle { get { return baseDescriptor.ScalarStyle; } set { baseDescriptor.ScalarStyle = value; } } public OverridePropertyDescriptor(IPropertyDescriptor baseDescriptor, YamlAttributeOverrides overrides, Type classType) { this.baseDescriptor = baseDescriptor; this.overrides = overrides; this.classType = classType; } public void Write(object target, object? value) { baseDescriptor.Write(target, value); } public T GetCustomAttribute() where T : Attribute { return overrides.GetAttribute(classType, Name) ?? baseDescriptor.GetCustomAttribute(); } public IObjectDescriptor Read(object target) { return baseDescriptor.Read(target); } } private readonly ITypeInspector innerTypeDescriptor; private readonly YamlAttributeOverrides overrides; public YamlAttributeOverridesInspector(ITypeInspector innerTypeDescriptor, YamlAttributeOverrides overrides) { this.innerTypeDescriptor = innerTypeDescriptor; this.overrides = overrides; } public override IEnumerable GetProperties(Type type, object? container) { Type type2 = type; IEnumerable enumerable = innerTypeDescriptor.GetProperties(type2, container); if (overrides != null) { enumerable = enumerable.Select((Func)((IPropertyDescriptor p) => new OverridePropertyDescriptor(p, overrides, type2))); } return enumerable; } } internal sealed class YamlAttributesTypeInspector : TypeInspectorSkeleton { private readonly ITypeInspector innerTypeDescriptor; public YamlAttributesTypeInspector(ITypeInspector innerTypeDescriptor) { this.innerTypeDescriptor = innerTypeDescriptor; } public override IEnumerable GetProperties(Type type, object? container) { return from p in (from p in innerTypeDescriptor.GetProperties(type, container) where p.GetCustomAttribute() == null select p).Select((Func)delegate(IPropertyDescriptor p) { PropertyDescriptor propertyDescriptor = new PropertyDescriptor(p); YamlMemberAttribute customAttribute = p.GetCustomAttribute(); if (customAttribute != null) { if (customAttribute.SerializeAs != null) { propertyDescriptor.TypeOverride = customAttribute.SerializeAs; } propertyDescriptor.Order = customAttribute.Order; propertyDescriptor.ScalarStyle = customAttribute.ScalarStyle; if (customAttribute.Alias != null) { propertyDescriptor.Name = customAttribute.Alias; } } return propertyDescriptor; }) orderby p.Order select p; } } internal static class YamlFormatter { public static readonly NumberFormatInfo NumberFormat = new NumberFormatInfo { CurrencyDecimalSeparator = ".", CurrencyGroupSeparator = "_", CurrencyGroupSizes = new int[1] { 3 }, CurrencySymbol = string.Empty, CurrencyDecimalDigits = 99, NumberDecimalSeparator = ".", NumberGroupSeparator = "_", NumberGroupSizes = new int[1] { 3 }, NumberDecimalDigits = 99, NaNSymbol = ".nan", PositiveInfinitySymbol = ".inf", NegativeInfinitySymbol = "-.inf" }; public static string FormatNumber(object number) { return Convert.ToString(number, NumberFormat); } public static string FormatNumber(double number) { return number.ToString("G17", NumberFormat); } public static string FormatNumber(float number) { return number.ToString("G17", NumberFormat); } public static string FormatBoolean(object boolean) { if (!boolean.Equals(true)) { return "false"; } return "true"; } public static string FormatDateTime(object dateTime) { return ((DateTime)dateTime).ToString("o", CultureInfo.InvariantCulture); } public static string FormatTimeSpan(object timeSpan) { return ((TimeSpan)timeSpan).ToString(); } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] internal sealed class YamlIgnoreAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] internal sealed class YamlMemberAttribute : Attribute { private DefaultValuesHandling? defaultValuesHandling; public string? Description { get; set; } public Type? SerializeAs { get; set; } public int Order { get; set; } public string? Alias { get; set; } public bool ApplyNamingConventions { get; set; } public ScalarStyle ScalarStyle { get; set; } public DefaultValuesHandling DefaultValuesHandling { get { return defaultValuesHandling.GetValueOrDefault(); } set { defaultValuesHandling = value; } } public bool IsDefaultValuesHandlingSpecified => defaultValuesHandling.HasValue; public YamlMemberAttribute() { ScalarStyle = ScalarStyle.Any; ApplyNamingConventions = true; } public YamlMemberAttribute(Type serializeAs) : this() { SerializeAs = serializeAs ?? throw new ArgumentNullException("serializeAs"); } } } namespace YamlDotNet.Serialization.ValueDeserializers { internal sealed class AliasValueDeserializer : IValueDeserializer { private sealed class AliasState : Dictionary, IPostDeserializationCallback { public void OnDeserialization() { foreach (ValuePromise value in base.Values) { if (!value.HasValue) { YamlDotNet.Core.Events.AnchorAlias alias = value.Alias; throw new AnchorNotFoundException(alias.Start, alias.End, $"Anchor '{alias.Value}' not found"); } } } } private sealed class ValuePromise : IValuePromise { private object? value; public readonly YamlDotNet.Core.Events.AnchorAlias? Alias; public bool HasValue { get; private set; } public object? Value { get { if (!HasValue) { throw new InvalidOperationException("Value not set"); } return value; } set { if (HasValue) { throw new InvalidOperationException("Value already set"); } HasValue = true; this.value = value; this.ValueAvailable?.Invoke(value); } } public event Action? ValueAvailable; public ValuePromise(YamlDotNet.Core.Events.AnchorAlias alias) { Alias = alias; } public ValuePromise(object? value) { HasValue = true; this.value = value; } } private readonly IValueDeserializer innerDeserializer; public AliasValueDeserializer(IValueDeserializer innerDeserializer) { this.innerDeserializer = innerDeserializer ?? throw new ArgumentNullException("innerDeserializer"); } public object? DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer) { if (parser.TryConsume(out var @event)) { if (!state.Get().TryGetValue(@event.Value, out ValuePromise value)) { throw new AnchorNotFoundException(@event.Start, @event.End, $"Alias ${@event.Value} cannot precede anchor declaration"); } if (!value.HasValue) { return value; } return value.Value; } AnchorName anchorName = AnchorName.Empty; if (parser.Accept(out var event2) && !event2.Anchor.IsEmpty) { anchorName = event2.Anchor; AliasState aliasState = state.Get(); if (!aliasState.ContainsKey(anchorName)) { aliasState[anchorName] = new ValuePromise(new YamlDotNet.Core.Events.AnchorAlias(anchorName)); } } object obj = innerDeserializer.DeserializeValue(parser, expectedType, state, nestedObjectDeserializer); if (!anchorName.IsEmpty) { AliasState aliasState2 = state.Get(); if (!aliasState2.TryGetValue(anchorName, out ValuePromise value2)) { aliasState2.Add(anchorName, new ValuePromise(obj)); } else if (!value2.HasValue) { value2.Value = obj; } else { aliasState2[anchorName] = new ValuePromise(obj); } } return obj; } } internal sealed class NodeValueDeserializer : IValueDeserializer { private readonly IList deserializers; private readonly IList typeResolvers; public NodeValueDeserializer(IList deserializers, IList typeResolvers) { this.deserializers = deserializers ?? throw new ArgumentNullException("deserializers"); this.typeResolvers = typeResolvers ?? throw new ArgumentNullException("typeResolvers"); } public object? DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer) { IValueDeserializer nestedObjectDeserializer2 = nestedObjectDeserializer; SerializerState state2 = state; parser.Accept(out var @event); Type typeFromEvent = GetTypeFromEvent(@event, expectedType); try { foreach (INodeDeserializer deserializer in deserializers) { if (deserializer.Deserialize(parser, typeFromEvent, (IParser r, Type t) => nestedObjectDeserializer2.DeserializeValue(r, t, state2, nestedObjectDeserializer2), out object value)) { return YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(value, expectedType); } } } catch (YamlException) { throw; } catch (Exception innerException) { throw new YamlException(@event?.Start ?? Mark.Empty, @event?.End ?? Mark.Empty, "Exception during deserialization", innerException); } throw new YamlException(@event?.Start ?? Mark.Empty, @event?.End ?? Mark.Empty, "No node deserializer was able to deserialize the node into type " + expectedType.AssemblyQualifiedName); } private Type GetTypeFromEvent(NodeEvent? nodeEvent, Type currentType) { using (IEnumerator enumerator = typeResolvers.GetEnumerator()) { while (enumerator.MoveNext() && !enumerator.Current.Resolve(nodeEvent, ref currentType)) { } } return currentType; } } } namespace YamlDotNet.Serialization.Utilities { internal interface IPostDeserializationCallback { void OnDeserialization(); } internal sealed class ObjectAnchorCollection { private readonly IDictionary objectsByAnchor = new Dictionary(); private readonly IDictionary anchorsByObject = new Dictionary(); public object this[string anchor] { get { if (objectsByAnchor.TryGetValue(anchor, out object value)) { return value; } throw new AnchorNotFoundException("The anchor '" + anchor + "' does not exists"); } } public void Add(string anchor, object @object) { objectsByAnchor.Add(anchor, @object); if (@object != null) { anchorsByObject.Add(@object, anchor); } } public bool TryGetAnchor(object @object, [MaybeNullWhen(false)] out string? anchor) { return anchorsByObject.TryGetValue(@object, out anchor); } } internal static class ReflectionUtility { public static Type? GetImplementedGenericInterface(Type type, Type genericInterfaceType) { foreach (Type implementedInterface in GetImplementedInterfaces(type)) { if (implementedInterface.IsGenericType() && implementedInterface.GetGenericTypeDefinition() == genericInterfaceType) { return implementedInterface; } } return null; } public static IEnumerable GetImplementedInterfaces(Type type) { if (type.IsInterface()) { yield return type; } Type[] interfaces = type.GetInterfaces(); for (int i = 0; i < interfaces.Length; i++) { yield return interfaces[i]; } } } internal sealed class SerializerState : IDisposable { private readonly IDictionary items = new Dictionary(); public T Get() where T : class, new() { if (!items.TryGetValue(typeof(T), out object value)) { value = new T(); items.Add(typeof(T), value); } return (T)value; } public void OnDeserialization() { foreach (IPostDeserializationCallback item in items.Values.OfType()) { item.OnDeserialization(); } } public void Dispose() { foreach (IDisposable item in items.Values.OfType()) { item.Dispose(); } } } internal static class StringExtensions { private static string ToCamelOrPascalCase(string str, Func firstLetterTransform) { string text = Regex.Replace(str, "([_\\-])(?[a-z])", (Match match) => match.Groups["char"].Value.ToUpperInvariant(), RegexOptions.IgnoreCase); return firstLetterTransform(text[0]) + text.Substring(1); } public static string ToCamelCase(this string str) { return ToCamelOrPascalCase(str, char.ToLowerInvariant); } public static string ToPascalCase(this string str) { return ToCamelOrPascalCase(str, char.ToUpperInvariant); } public static string FromCamelCase(this string str, string separator) { string separator2 = separator; str = char.ToLower(str[0]) + str.Substring(1); str = Regex.Replace(str.ToCamelCase(), "(?[A-Z])", (Match match) => separator2 + match.Groups["char"].Value.ToLowerInvariant()); return str; } } internal static class TypeConverter { public static T ChangeType(object? value) { return (T)ChangeType(value, typeof(T)); } public static T ChangeType(object? value, IFormatProvider provider) { return (T)ChangeType(value, typeof(T), provider); } public static T ChangeType(object? value, CultureInfo culture) { return (T)ChangeType(value, typeof(T), culture); } public static object? ChangeType(object? value, Type destinationType) { return ChangeType(value, destinationType, CultureInfo.InvariantCulture); } public static object? ChangeType(object? value, Type destinationType, IFormatProvider provider) { return ChangeType(value, destinationType, new CultureInfoAdapter(CultureInfo.CurrentCulture, provider)); } public static object? ChangeType(object? value, Type destinationType, CultureInfo culture) { if (value == null || value.IsDbNull()) { if (!destinationType.IsValueType()) { return null; } return Activator.CreateInstance(destinationType); } Type type = value.GetType(); if (destinationType == type || destinationType.IsAssignableFrom(type)) { return value; } if (destinationType.IsGenericType() && destinationType.GetGenericTypeDefinition() == typeof(Nullable<>)) { Type destinationType2 = destinationType.GetGenericArguments()[0]; object obj = ChangeType(value, destinationType2, culture); return Activator.CreateInstance(destinationType, obj); } if (destinationType.IsEnum()) { if (!(value is string value2)) { return value; } return Enum.Parse(destinationType, value2, ignoreCase: true); } if (destinationType == typeof(bool)) { if ("0".Equals(value)) { return false; } if ("1".Equals(value)) { return true; } } System.ComponentModel.TypeConverter converter = TypeDescriptor.GetConverter(type); if (converter != null && converter.CanConvertTo(destinationType)) { return converter.ConvertTo(null, culture, value, destinationType); } System.ComponentModel.TypeConverter converter2 = TypeDescriptor.GetConverter(destinationType); if (converter2 != null && converter2.CanConvertFrom(type)) { return converter2.ConvertFrom(null, culture, value); } Type[] array = new Type[2] { type, destinationType }; for (int i = 0; i < array.Length; i++) { foreach (MethodInfo publicStaticMethod2 in array[i].GetPublicStaticMethods()) { if (!publicStaticMethod2.IsSpecialName || (!(publicStaticMethod2.Name == "op_Implicit") && !(publicStaticMethod2.Name == "op_Explicit")) || !destinationType.IsAssignableFrom(publicStaticMethod2.ReturnParameter.ParameterType)) { continue; } ParameterInfo[] parameters = publicStaticMethod2.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType.IsAssignableFrom(type)) { try { return publicStaticMethod2.Invoke(null, new object[1] { value }); } catch (TargetInvocationException ex) { throw ex.Unwrap(); } } } } if (type == typeof(string)) { try { MethodInfo publicStaticMethod = destinationType.GetPublicStaticMethod("Parse", typeof(string), typeof(IFormatProvider)); if (publicStaticMethod != null) { return publicStaticMethod.Invoke(null, new object[2] { value, culture }); } publicStaticMethod = destinationType.GetPublicStaticMethod("Parse", typeof(string)); if (publicStaticMethod != null) { return publicStaticMethod.Invoke(null, new object[1] { value }); } } catch (TargetInvocationException ex2) { throw ex2.Unwrap(); } } if (destinationType == typeof(TimeSpan)) { return TimeSpan.Parse((string)ChangeType(value, typeof(string), CultureInfo.InvariantCulture)); } return Convert.ChangeType(value, destinationType, CultureInfo.InvariantCulture); } [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")] public static void RegisterTypeConverter() where TConverter : System.ComponentModel.TypeConverter { if (!TypeDescriptor.GetAttributes(typeof(TConvertible)).OfType().Any((TypeConverterAttribute a) => a.ConverterTypeName == typeof(TConverter).AssemblyQualifiedName)) { TypeDescriptor.AddAttributes(typeof(TConvertible), new TypeConverterAttribute(typeof(TConverter))); } } } } namespace YamlDotNet.Serialization.TypeResolvers { internal sealed class DynamicTypeResolver : ITypeResolver { public Type Resolve(Type staticType, object? actualValue) { if (actualValue == null) { return staticType; } return actualValue.GetType(); } } internal sealed class StaticTypeResolver : ITypeResolver { public Type Resolve(Type staticType, object? actualValue) { return staticType; } } } namespace YamlDotNet.Serialization.TypeInspectors { internal sealed class CachedTypeInspector : TypeInspectorSkeleton { private readonly ITypeInspector innerTypeDescriptor; private readonly ConcurrentDictionary> cache = new ConcurrentDictionary>(); public CachedTypeInspector(ITypeInspector innerTypeDescriptor) { this.innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor"); } public override IEnumerable GetProperties(Type type, object? container) { object container2 = container; return cache.GetOrAdd(type, (Type t) => innerTypeDescriptor.GetProperties(t, container2).ToList()); } } internal sealed class CompositeTypeInspector : TypeInspectorSkeleton { private readonly IEnumerable typeInspectors; public CompositeTypeInspector(params ITypeInspector[] typeInspectors) : this((IEnumerable)typeInspectors) { } public CompositeTypeInspector(IEnumerable typeInspectors) { this.typeInspectors = typeInspectors?.ToList() ?? throw new ArgumentNullException("typeInspectors"); } public override IEnumerable GetProperties(Type type, object? container) { Type type2 = type; object container2 = container; return typeInspectors.SelectMany((ITypeInspector i) => i.GetProperties(type2, container2)); } } internal sealed class NamingConventionTypeInspector : TypeInspectorSkeleton { private readonly ITypeInspector innerTypeDescriptor; private readonly INamingConvention namingConvention; public NamingConventionTypeInspector(ITypeInspector innerTypeDescriptor, INamingConvention namingConvention) { this.innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor"); this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention"); } public override IEnumerable GetProperties(Type type, object? container) { return innerTypeDescriptor.GetProperties(type, container).Select(delegate(IPropertyDescriptor p) { YamlMemberAttribute customAttribute = p.GetCustomAttribute(); return (customAttribute != null && !customAttribute.ApplyNamingConventions) ? p : new PropertyDescriptor(p) { Name = namingConvention.Apply(p.Name) }; }); } } internal sealed class ReadableAndWritablePropertiesTypeInspector : TypeInspectorSkeleton { private readonly ITypeInspector innerTypeDescriptor; public ReadableAndWritablePropertiesTypeInspector(ITypeInspector innerTypeDescriptor) { this.innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor"); } public override IEnumerable GetProperties(Type type, object? container) { return from p in innerTypeDescriptor.GetProperties(type, container) where p.CanWrite select p; } } internal sealed class ReadableFieldsTypeInspector : TypeInspectorSkeleton { private sealed class ReflectionFieldDescriptor : IPropertyDescriptor { private readonly FieldInfo fieldInfo; private readonly ITypeResolver typeResolver; public string Name => fieldInfo.Name; public Type Type => fieldInfo.FieldType; public Type? TypeOverride { get; set; } public int Order { get; set; } public bool CanWrite => !fieldInfo.IsInitOnly; public ScalarStyle ScalarStyle { get; set; } public ReflectionFieldDescriptor(FieldInfo fieldInfo, ITypeResolver typeResolver) { this.fieldInfo = fieldInfo; this.typeResolver = typeResolver; ScalarStyle = ScalarStyle.Any; } public void Write(object target, object? value) { fieldInfo.SetValue(target, value); } public T GetCustomAttribute() where T : Attribute { return (T)fieldInfo.GetCustomAttributes(typeof(T), inherit: true).FirstOrDefault(); } public IObjectDescriptor Read(object target) { object value = fieldInfo.GetValue(target); Type type = TypeOverride ?? typeResolver.Resolve(Type, value); return new ObjectDescriptor(value, type, Type, ScalarStyle); } } private readonly ITypeResolver typeResolver; public ReadableFieldsTypeInspector(ITypeResolver typeResolver) { this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); } public override IEnumerable GetProperties(Type type, object? container) { return type.GetPublicFields().Select((Func)((FieldInfo p) => new ReflectionFieldDescriptor(p, typeResolver))); } } internal sealed class ReadablePropertiesTypeInspector : TypeInspectorSkeleton { private sealed class ReflectionPropertyDescriptor : IPropertyDescriptor { private readonly PropertyInfo propertyInfo; private readonly ITypeResolver typeResolver; public string Name => propertyInfo.Name; public Type Type => propertyInfo.PropertyType; public Type? TypeOverride { get; set; } public int Order { get; set; } public bool CanWrite => propertyInfo.CanWrite; public ScalarStyle ScalarStyle { get; set; } public ReflectionPropertyDescriptor(PropertyInfo propertyInfo, ITypeResolver typeResolver) { this.propertyInfo = propertyInfo ?? throw new ArgumentNullException("propertyInfo"); this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); ScalarStyle = ScalarStyle.Any; } public void Write(object target, object? value) { propertyInfo.SetValue(target, value, null); } public T GetCustomAttribute() where T : Attribute { return (T)propertyInfo.GetAllCustomAttributes().FirstOrDefault(); } public IObjectDescriptor Read(object target) { object obj = propertyInfo.ReadValue(target); Type type = TypeOverride ?? typeResolver.Resolve(Type, obj); return new ObjectDescriptor(obj, type, Type, ScalarStyle); } } private readonly ITypeResolver typeResolver; private readonly bool includeNonPublicProperties; public ReadablePropertiesTypeInspector(ITypeResolver typeResolver) : this(typeResolver, includeNonPublicProperties: false) { } public ReadablePropertiesTypeInspector(ITypeResolver typeResolver, bool includeNonPublicProperties) { this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); this.includeNonPublicProperties = includeNonPublicProperties; } private static bool IsValidProperty(PropertyInfo property) { if (property.CanRead) { return property.GetGetMethod(nonPublic: true).GetParameters().Length == 0; } return false; } public override IEnumerable GetProperties(Type type, object? container) { return type.GetProperties(includeNonPublicProperties).Where(IsValidProperty).Select((Func)((PropertyInfo p) => new ReflectionPropertyDescriptor(p, typeResolver))); } } internal abstract class TypeInspectorSkeleton : ITypeInspector { public abstract IEnumerable GetProperties(Type type, object? container); public IPropertyDescriptor GetProperty(Type type, object? container, string name, [MaybeNullWhen(true)] bool ignoreUnmatched) { string name2 = name; IEnumerable enumerable = from p in GetProperties(type, container) where p.Name == name2 select p; using IEnumerator enumerator = enumerable.GetEnumerator(); if (!enumerator.MoveNext()) { if (ignoreUnmatched) { return null; } throw new SerializationException("Property '" + name2 + "' not found on type '" + type.FullName + "'."); } IPropertyDescriptor current = enumerator.Current; if (enumerator.MoveNext()) { throw new SerializationException("Multiple properties with the name/alias '" + name2 + "' already exists on type '" + type.FullName + "', maybe you're misusing YamlAlias or maybe you are using the wrong naming convention? The matching properties are: " + string.Join(", ", enumerable.Select((IPropertyDescriptor p) => p.Name).ToArray())); } return current; } } } namespace YamlDotNet.Serialization.Schemas { internal sealed class FailsafeSchema { public static class Tags { public static readonly TagName Map = new TagName("tag:yaml.org,2002:map"); public static readonly TagName Seq = new TagName("tag:yaml.org,2002:seq"); public static readonly TagName Str = new TagName("tag:yaml.org,2002:str"); } } internal sealed class JsonSchema { public static class Tags { public static readonly TagName Null = new TagName("tag:yaml.org,2002:null"); public static readonly TagName Bool = new TagName("tag:yaml.org,2002:bool"); public static readonly TagName Int = new TagName("tag:yaml.org,2002:int"); public static readonly TagName Float = new TagName("tag:yaml.org,2002:float"); } } internal sealed class CoreSchema { public static class Tags { } } internal sealed class DefaultSchema { public static class Tags { public static readonly TagName Timestamp = new TagName("tag:yaml.org,2002:timestamp"); } } } namespace YamlDotNet.Serialization.ObjectGraphVisitors { internal sealed class AnchorAssigner : PreProcessingPhaseObjectGraphVisitorSkeleton, IAliasProvider { private class AnchorAssignment { public AnchorName Anchor; } private readonly IDictionary assignments = new Dictionary(); private uint nextId; public AnchorAssigner(IEnumerable typeConverters) : base(typeConverters) { } protected override bool Enter(IObjectDescriptor value) { if (value.Value != null && assignments.TryGetValue(value.Value, out AnchorAssignment value2)) { if (value2.Anchor.IsEmpty) { value2.Anchor = new AnchorName("o" + nextId.ToString(CultureInfo.InvariantCulture)); nextId++; } return false; } return true; } protected override bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value) { return true; } protected override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value) { return true; } protected override void VisitScalar(IObjectDescriptor scalar) { } protected override void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType) { VisitObject(mapping); } protected override void VisitMappingEnd(IObjectDescriptor mapping) { } protected override void VisitSequenceStart(IObjectDescriptor sequence, Type elementType) { VisitObject(sequence); } protected override void VisitSequenceEnd(IObjectDescriptor sequence) { } private void VisitObject(IObjectDescriptor value) { if (value.Value != null) { assignments.Add(value.Value, new AnchorAssignment()); } } AnchorName IAliasProvider.GetAlias(object target) { if (target != null && assignments.TryGetValue(target, out AnchorAssignment value)) { return value.Anchor; } return AnchorName.Empty; } } internal sealed class AnchorAssigningObjectGraphVisitor : ChainedObjectGraphVisitor { private readonly IEventEmitter eventEmitter; private readonly IAliasProvider aliasProvider; private readonly HashSet emittedAliases = new HashSet(); public AnchorAssigningObjectGraphVisitor(IObjectGraphVisitor nextVisitor, IEventEmitter eventEmitter, IAliasProvider aliasProvider) : base(nextVisitor) { this.eventEmitter = eventEmitter; this.aliasProvider = aliasProvider; } public override bool Enter(IObjectDescriptor value, IEmitter context) { if (value.Value != null) { AnchorName alias = aliasProvider.GetAlias(value.Value); if (!alias.IsEmpty && !emittedAliases.Add(alias)) { AliasEventInfo aliasEventInfo = new AliasEventInfo(value, alias); eventEmitter.Emit(aliasEventInfo, context); return aliasEventInfo.NeedsExpansion; } } return base.Enter(value, context); } public override void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, IEmitter context) { AnchorName alias = aliasProvider.GetAlias(mapping.NonNullValue()); eventEmitter.Emit(new MappingStartEventInfo(mapping) { Anchor = alias }, context); } public override void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, IEmitter context) { AnchorName alias = aliasProvider.GetAlias(sequence.NonNullValue()); eventEmitter.Emit(new SequenceStartEventInfo(sequence) { Anchor = alias }, context); } public override void VisitScalar(IObjectDescriptor scalar, IEmitter context) { ScalarEventInfo scalarEventInfo = new ScalarEventInfo(scalar); if (scalar.Value != null) { scalarEventInfo.Anchor = aliasProvider.GetAlias(scalar.Value); } eventEmitter.Emit(scalarEventInfo, context); } } internal abstract class ChainedObjectGraphVisitor : IObjectGraphVisitor { private readonly IObjectGraphVisitor nextVisitor; protected ChainedObjectGraphVisitor(IObjectGraphVisitor nextVisitor) { this.nextVisitor = nextVisitor; } public virtual bool Enter(IObjectDescriptor value, IEmitter context) { return nextVisitor.Enter(value, context); } public virtual bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, IEmitter context) { return nextVisitor.EnterMapping(key, value, context); } public virtual bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) { return nextVisitor.EnterMapping(key, value, context); } public virtual void VisitScalar(IObjectDescriptor scalar, IEmitter context) { nextVisitor.VisitScalar(scalar, context); } public virtual void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, IEmitter context) { nextVisitor.VisitMappingStart(mapping, keyType, valueType, context); } public virtual void VisitMappingEnd(IObjectDescriptor mapping, IEmitter context) { nextVisitor.VisitMappingEnd(mapping, context); } public virtual void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, IEmitter context) { nextVisitor.VisitSequenceStart(sequence, elementType, context); } public virtual void VisitSequenceEnd(IObjectDescriptor sequence, IEmitter context) { nextVisitor.VisitSequenceEnd(sequence, context); } } internal sealed class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor { public CommentsObjectGraphVisitor(IObjectGraphVisitor nextVisitor) : base(nextVisitor) { } public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) { YamlMemberAttribute customAttribute = key.GetCustomAttribute(); if (customAttribute != null && customAttribute.Description != null) { context.Emit(new YamlDotNet.Core.Events.Comment(customAttribute.Description, isInline: false)); } return base.EnterMapping(key, value, context); } } internal sealed class CustomSerializationObjectGraphVisitor : ChainedObjectGraphVisitor { private readonly IEnumerable typeConverters; private readonly ObjectSerializer nestedObjectSerializer; public CustomSerializationObjectGraphVisitor(IObjectGraphVisitor nextVisitor, IEnumerable typeConverters, ObjectSerializer nestedObjectSerializer) : base(nextVisitor) { IEnumerable enumerable; if (typeConverters == null) { enumerable = Enumerable.Empty(); } else { IEnumerable enumerable2 = typeConverters.ToList(); enumerable = enumerable2; } this.typeConverters = enumerable; this.nestedObjectSerializer = nestedObjectSerializer; } public override bool Enter(IObjectDescriptor value, IEmitter context) { IObjectDescriptor value2 = value; IYamlTypeConverter yamlTypeConverter = typeConverters.FirstOrDefault((IYamlTypeConverter t) => t.Accepts(value2.Type)); if (yamlTypeConverter != null) { yamlTypeConverter.WriteYaml(context, value2.Value, value2.Type); return false; } if (value2.Value is IYamlConvertible yamlConvertible) { yamlConvertible.Write(context, nestedObjectSerializer); return false; } if (value2.Value is IYamlSerializable yamlSerializable) { yamlSerializable.WriteYaml(context); return false; } return base.Enter(value2, context); } } internal sealed class DefaultExclusiveObjectGraphVisitor : ChainedObjectGraphVisitor { public DefaultExclusiveObjectGraphVisitor(IObjectGraphVisitor nextVisitor) : base(nextVisitor) { } private static object? GetDefault(Type type) { if (!type.IsValueType()) { return null; } return Activator.CreateInstance(type); } public override bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, IEmitter context) { if (!object.Equals(value.Value, GetDefault(value.Type))) { return base.EnterMapping(key, value, context); } return false; } public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) { DefaultValueAttribute customAttribute = key.GetCustomAttribute(); object objB = ((customAttribute != null) ? customAttribute.Value : GetDefault(key.Type)); if (!object.Equals(value.Value, objB)) { return base.EnterMapping(key, value, context); } return false; } } internal sealed class DefaultValuesObjectGraphVisitor : ChainedObjectGraphVisitor { private readonly DefaultValuesHandling handling; public DefaultValuesObjectGraphVisitor(DefaultValuesHandling handling, IObjectGraphVisitor nextVisitor) : base(nextVisitor) { this.handling = handling; } private static object? GetDefault(Type type) { if (!type.IsValueType()) { return null; } return Activator.CreateInstance(type); } public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) { DefaultValuesHandling defaultValuesHandling = handling; YamlMemberAttribute customAttribute = key.GetCustomAttribute(); if (customAttribute != null && customAttribute.IsDefaultValuesHandlingSpecified) { defaultValuesHandling = customAttribute.DefaultValuesHandling; } if ((defaultValuesHandling & DefaultValuesHandling.OmitNull) != 0 && value.Value == null) { return false; } if ((defaultValuesHandling & DefaultValuesHandling.OmitEmptyCollections) != 0 && value.Value is IEnumerable enumerable) { IEnumerator enumerator = enumerable.GetEnumerator(); bool flag = enumerator.MoveNext(); if (enumerator is IDisposable disposable) { disposable.Dispose(); } if (!flag) { return false; } } if ((defaultValuesHandling & DefaultValuesHandling.OmitDefaults) != 0) { object objB = key.GetCustomAttribute()?.Value ?? GetDefault(key.Type); if (object.Equals(value.Value, objB)) { return false; } } return base.EnterMapping(key, value, context); } } internal sealed class EmittingObjectGraphVisitor : IObjectGraphVisitor { private readonly IEventEmitter eventEmitter; public EmittingObjectGraphVisitor(IEventEmitter eventEmitter) { this.eventEmitter = eventEmitter; } bool IObjectGraphVisitor.Enter(IObjectDescriptor value, IEmitter context) { return true; } bool IObjectGraphVisitor.EnterMapping(IObjectDescriptor key, IObjectDescriptor value, IEmitter context) { return true; } bool IObjectGraphVisitor.EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) { return true; } void IObjectGraphVisitor.VisitScalar(IObjectDescriptor scalar, IEmitter context) { eventEmitter.Emit(new ScalarEventInfo(scalar), context); } void IObjectGraphVisitor.VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, IEmitter context) { eventEmitter.Emit(new MappingStartEventInfo(mapping), context); } void IObjectGraphVisitor.VisitMappingEnd(IObjectDescriptor mapping, IEmitter context) { eventEmitter.Emit(new MappingEndEventInfo(mapping), context); } void IObjectGraphVisitor.VisitSequenceStart(IObjectDescriptor sequence, Type elementType, IEmitter context) { eventEmitter.Emit(new SequenceStartEventInfo(sequence), context); } void IObjectGraphVisitor.VisitSequenceEnd(IObjectDescriptor sequence, IEmitter context) { eventEmitter.Emit(new SequenceEndEventInfo(sequence), context); } } internal abstract class PreProcessingPhaseObjectGraphVisitorSkeleton : IObjectGraphVisitor { protected readonly IEnumerable typeConverters; public PreProcessingPhaseObjectGraphVisitorSkeleton(IEnumerable typeConverters) { IEnumerable enumerable; if (typeConverters == null) { enumerable = Enumerable.Empty(); } else { IEnumerable enumerable2 = typeConverters.ToList(); enumerable = enumerable2; } this.typeConverters = enumerable; } bool IObjectGraphVisitor.Enter(IObjectDescriptor value, Nothing context) { IObjectDescriptor value2 = value; if (typeConverters.FirstOrDefault((IYamlTypeConverter t) => t.Accepts(value2.Type)) != null) { return false; } if (value2.Value is IYamlConvertible) { return false; } if (value2.Value is IYamlSerializable) { return false; } return Enter(value2); } bool IObjectGraphVisitor.EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, Nothing context) { return EnterMapping(key, value); } bool IObjectGraphVisitor.EnterMapping(IObjectDescriptor key, IObjectDescriptor value, Nothing context) { return EnterMapping(key, value); } void IObjectGraphVisitor.VisitMappingEnd(IObjectDescriptor mapping, Nothing context) { VisitMappingEnd(mapping); } void IObjectGraphVisitor.VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, Nothing context) { VisitMappingStart(mapping, keyType, valueType); } void IObjectGraphVisitor.VisitScalar(IObjectDescriptor scalar, Nothing context) { VisitScalar(scalar); } void IObjectGraphVisitor.VisitSequenceEnd(IObjectDescriptor sequence, Nothing context) { VisitSequenceEnd(sequence); } void IObjectGraphVisitor.VisitSequenceStart(IObjectDescriptor sequence, Type elementType, Nothing context) { VisitSequenceStart(sequence, elementType); } protected abstract bool Enter(IObjectDescriptor value); protected abstract bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value); protected abstract bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value); protected abstract void VisitMappingEnd(IObjectDescriptor mapping); protected abstract void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType); protected abstract void VisitScalar(IObjectDescriptor scalar); protected abstract void VisitSequenceEnd(IObjectDescriptor sequence); protected abstract void VisitSequenceStart(IObjectDescriptor sequence, Type elementType); } } namespace YamlDotNet.Serialization.ObjectGraphTraversalStrategies { internal class FullObjectGraphTraversalStrategy : IObjectGraphTraversalStrategy { protected struct ObjectPathSegment { public readonly object Name; public readonly IObjectDescriptor Value; public ObjectPathSegment(object name, IObjectDescriptor value) { Name = name; Value = value; } } private readonly int maxRecursion; private readonly ITypeInspector typeDescriptor; private readonly ITypeResolver typeResolver; private readonly INamingConvention namingConvention; public FullObjectGraphTraversalStrategy(ITypeInspector typeDescriptor, ITypeResolver typeResolver, int maxRecursion, INamingConvention namingConvention) { if (maxRecursion <= 0) { throw new ArgumentOutOfRangeException("maxRecursion", maxRecursion, "maxRecursion must be greater than 1"); } this.typeDescriptor = typeDescriptor ?? throw new ArgumentNullException("typeDescriptor"); this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver"); this.maxRecursion = maxRecursion; this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention"); } void IObjectGraphTraversalStrategy.Traverse(IObjectDescriptor graph, IObjectGraphVisitor visitor, TContext context) { Traverse("", graph, visitor, context, new Stack(maxRecursion)); } protected virtual void Traverse(object name, IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path) { if (path.Count >= maxRecursion) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Too much recursion when traversing the object graph."); stringBuilder.AppendLine("The path to reach this recursion was:"); Stack> stack = new Stack>(path.Count); int num = 0; foreach (ObjectPathSegment item in path) { string text = YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(item.Name); num = Math.Max(num, text.Length); stack.Push(new KeyValuePair(text, item.Value.Type.FullName)); } foreach (KeyValuePair item2 in stack) { stringBuilder.Append(" -> ").Append(item2.Key.PadRight(num)).Append(" [") .Append(item2.Value) .AppendLine("]"); } throw new MaximumRecursionLevelReachedException(stringBuilder.ToString()); } if (!visitor.Enter(value, context)) { return; } path.Push(new ObjectPathSegment(name, value)); try { TypeCode typeCode = value.Type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: case TypeCode.DateTime: case TypeCode.String: visitor.VisitScalar(value, context); return; case TypeCode.Empty: throw new NotSupportedException($"TypeCode.{typeCode} is not supported."); } if (value.IsDbNull()) { visitor.VisitScalar(new ObjectDescriptor(null, typeof(object), typeof(object)), context); } if (value.Value == null || value.Type == typeof(TimeSpan)) { visitor.VisitScalar(value, context); return; } Type underlyingType = Nullable.GetUnderlyingType(value.Type); if (underlyingType != null) { Traverse("Value", new ObjectDescriptor(value.Value, underlyingType, value.Type, value.ScalarStyle), visitor, context, path); } else { TraverseObject(value, visitor, context, path); } } finally { path.Pop(); } } protected virtual void TraverseObject(IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path) { if (typeof(IDictionary).IsAssignableFrom(value.Type)) { TraverseDictionary(value, visitor, typeof(object), typeof(object), context, path); return; } Type implementedGenericInterface = ReflectionUtility.GetImplementedGenericInterface(value.Type, typeof(IDictionary<, >)); if (implementedGenericInterface != null) { Type[] genericArguments = implementedGenericInterface.GetGenericArguments(); object value2 = Activator.CreateInstance(typeof(GenericDictionaryToNonGenericAdapter<, >).MakeGenericType(genericArguments), value.Value); TraverseDictionary(new ObjectDescriptor(value2, value.Type, value.StaticType, value.ScalarStyle), visitor, genericArguments[0], genericArguments[1], context, path); } else if (typeof(IEnumerable).IsAssignableFrom(value.Type)) { TraverseList(value, visitor, context, path); } else { TraverseProperties(value, visitor, context, path); } } protected virtual void TraverseDictionary(IObjectDescriptor dictionary, IObjectGraphVisitor visitor, Type keyType, Type valueType, TContext context, Stack path) { visitor.VisitMappingStart(dictionary, keyType, valueType, context); bool flag = dictionary.Type.FullName.Equals("System.Dynamic.ExpandoObject"); foreach (DictionaryEntry? item in (IDictionary)dictionary.NonNullValue()) { DictionaryEntry value = item.Value; object obj = (flag ? namingConvention.Apply(value.Key.ToString()) : value.Key); IObjectDescriptor objectDescriptor = GetObjectDescriptor(obj, keyType); IObjectDescriptor objectDescriptor2 = GetObjectDescriptor(value.Value, valueType); if (visitor.EnterMapping(objectDescriptor, objectDescriptor2, context)) { Traverse(obj, objectDescriptor, visitor, context, path); Traverse(obj, objectDescriptor2, visitor, context, path); } } visitor.VisitMappingEnd(dictionary, context); } private void TraverseList(IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path) { Type implementedGenericInterface = ReflectionUtility.GetImplementedGenericInterface(value.Type, typeof(IEnumerable<>)); Type type = ((implementedGenericInterface != null) ? implementedGenericInterface.GetGenericArguments()[0] : typeof(object)); visitor.VisitSequenceStart(value, type, context); int num = 0; foreach (object item in (IEnumerable)value.NonNullValue()) { Traverse(num, GetObjectDescriptor(item, type), visitor, context, path); num++; } visitor.VisitSequenceEnd(value, context); } protected virtual void TraverseProperties(IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path) { visitor.VisitMappingStart(value, typeof(string), typeof(object), context); object obj = value.NonNullValue(); foreach (IPropertyDescriptor property in typeDescriptor.GetProperties(value.Type, obj)) { IObjectDescriptor value2 = property.Read(obj); if (visitor.EnterMapping(property, value2, context)) { Traverse(property.Name, new ObjectDescriptor(property.Name, typeof(string), typeof(string)), visitor, context, path); Traverse(property.Name, value2, visitor, context, path); } } visitor.VisitMappingEnd(value, context); } private IObjectDescriptor GetObjectDescriptor(object? value, Type staticType) { return new ObjectDescriptor(value, typeResolver.Resolve(staticType, value), staticType); } } internal class RoundtripObjectGraphTraversalStrategy : FullObjectGraphTraversalStrategy { private readonly IEnumerable converters; public RoundtripObjectGraphTraversalStrategy(IEnumerable converters, ITypeInspector typeDescriptor, ITypeResolver typeResolver, int maxRecursion, INamingConvention namingConvention) : base(typeDescriptor, typeResolver, maxRecursion, namingConvention) { this.converters = converters; } protected override void TraverseProperties(IObjectDescriptor value, IObjectGraphVisitor visitor, TContext context, Stack path) { IObjectDescriptor value2 = value; if (!value2.Type.HasDefaultConstructor() && !converters.Any((IYamlTypeConverter c) => c.Accepts(value2.Type))) { throw new InvalidOperationException($"Type '{value2.Type}' cannot be deserialized because it does not have a default constructor or a type converter."); } base.TraverseProperties(value2, visitor, context, path); } } } namespace YamlDotNet.Serialization.ObjectFactories { internal sealed class DefaultObjectFactory : IObjectFactory { private readonly Dictionary DefaultGenericInterfaceImplementations = new Dictionary { { typeof(IEnumerable<>), typeof(List<>) }, { typeof(ICollection<>), typeof(List<>) }, { typeof(IList<>), typeof(List<>) }, { typeof(IDictionary<, >), typeof(Dictionary<, >) } }; private readonly Dictionary DefaultNonGenericInterfaceImplementations = new Dictionary { { typeof(IEnumerable), typeof(List) }, { typeof(ICollection), typeof(List) }, { typeof(IList), typeof(List) }, { typeof(IDictionary), typeof(Dictionary) } }; public DefaultObjectFactory() { } public DefaultObjectFactory(IDictionary mappings) { foreach (KeyValuePair mapping in mappings) { if (!mapping.Key.IsAssignableFrom(mapping.Value)) { throw new InvalidOperationException($"Type '{mapping.Value}' does not implement type '{mapping.Key}'."); } DefaultNonGenericInterfaceImplementations.Add(mapping.Key, mapping.Value); } } public object Create(Type type) { if (type.IsInterface()) { Type value2; if (type.IsGenericType()) { if (DefaultGenericInterfaceImplementations.TryGetValue(type.GetGenericTypeDefinition(), out Type value)) { type = value.MakeGenericType(type.GetGenericArguments()); } } else if (DefaultNonGenericInterfaceImplementations.TryGetValue(type, out value2)) { type = value2; } } try { return Activator.CreateInstance(type); } catch (Exception innerException) { throw new InvalidOperationException("Failed to create an instance of type '" + type.FullName + "'.", innerException); } } } internal sealed class LambdaObjectFactory : IObjectFactory { private readonly Func factory; public LambdaObjectFactory(Func factory) { this.factory = factory ?? throw new ArgumentNullException("factory"); } public object Create(Type type) { return factory(type); } } } namespace YamlDotNet.Serialization.NodeTypeResolvers { internal sealed class DefaultContainersNodeTypeResolver : INodeTypeResolver { bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (currentType == typeof(object)) { if (nodeEvent is SequenceStart) { currentType = typeof(List); return true; } if (nodeEvent is MappingStart) { currentType = typeof(Dictionary); return true; } } return false; } } internal class MappingNodeTypeResolver : INodeTypeResolver { private readonly IDictionary _mappings; public MappingNodeTypeResolver(IDictionary mappings) { if (mappings == null) { throw new ArgumentNullException("mappings"); } foreach (KeyValuePair mapping in mappings) { if (!mapping.Key.IsAssignableFrom(mapping.Value)) { throw new InvalidOperationException($"Type '{mapping.Value}' does not implement type '{mapping.Key}'."); } } _mappings = mappings; } public bool Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (_mappings.TryGetValue(currentType, out Type value)) { currentType = value; return true; } return false; } } internal class PreventUnknownTagsNodeTypeResolver : INodeTypeResolver { bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (nodeEvent != null && !nodeEvent.Tag.IsEmpty) { throw new YamlException(nodeEvent.Start, nodeEvent.End, $"Encountered an unresolved tag '{nodeEvent.Tag}'"); } return false; } } internal sealed class TagNodeTypeResolver : INodeTypeResolver { private readonly IDictionary tagMappings; public TagNodeTypeResolver(IDictionary tagMappings) { this.tagMappings = tagMappings ?? throw new ArgumentNullException("tagMappings"); } bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (nodeEvent != null && !nodeEvent.Tag.IsEmpty && tagMappings.TryGetValue(nodeEvent.Tag, out Type value)) { currentType = value; return true; } return false; } } [Obsolete("The mechanism that this class uses to specify type names is non-standard. Register the tags explicitly instead of using this convention.")] internal sealed class TypeNameInTagNodeTypeResolver : INodeTypeResolver { bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) { if (nodeEvent != null && !nodeEvent.Tag.IsEmpty) { Type type = Type.GetType(nodeEvent.Tag.Value.Substring(1), throwOnError: false); if (type != null) { currentType = type; return true; } } return false; } } internal sealed class YamlConvertibleTypeResolver : INodeTypeResolver { public bool Resolve(NodeEvent? nodeEvent, ref Type currentType) { return typeof(IYamlConvertible).IsAssignableFrom(currentType); } } internal sealed class YamlSerializableTypeResolver : INodeTypeResolver { public bool Resolve(NodeEvent? nodeEvent, ref Type currentType) { return typeof(IYamlSerializable).IsAssignableFrom(currentType); } } } namespace YamlDotNet.Serialization.NodeDeserializers { internal sealed class ArrayNodeDeserializer : INodeDeserializer { private sealed class ArrayList : IList, ICollection, IEnumerable { private object?[] data; public bool IsFixedSize => false; public bool IsReadOnly => false; public object? this[int index] { get { return data[index]; } set { data[index] = value; } } public int Count { get; private set; } public bool IsSynchronized => false; public object SyncRoot => data; public ArrayList() { Clear(); } public int Add(object? value) { if (Count == data.Length) { Array.Resize(ref data, data.Length * 2); } data[Count] = value; return Count++; } public void Clear() { data = new object[10]; Count = 0; } bool IList.Contains(object? value) { throw new NotSupportedException(); } int IList.IndexOf(object? value) { throw new NotSupportedException(); } void IList.Insert(int index, object? value) { throw new NotSupportedException(); } void IList.Remove(object? value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } public void CopyTo(Array array, int index) { Array.Copy(data, 0, array, index, Count); } public IEnumerator GetEnumerator() { int i = 0; while (i < Count) { yield return data[i]; int num = i + 1; i = num; } } } bool INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { if (!expectedType.IsArray) { value = false; return false; } Type? elementType = expectedType.GetElementType(); ArrayList arrayList = new ArrayList(); CollectionNodeDeserializer.DeserializeHelper(elementType, parser, nestedObjectDeserializer, arrayList, canUpdate: true); Array array = Array.CreateInstance(elementType, arrayList.Count); arrayList.CopyTo(array, 0); value = array; return true; } } internal sealed class CollectionNodeDeserializer : INodeDeserializer { private readonly IObjectFactory objectFactory; public CollectionNodeDeserializer(IObjectFactory objectFactory) { this.objectFactory = objectFactory ?? throw new ArgumentNullException("objectFactory"); } bool INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { bool canUpdate = true; Type implementedGenericInterface = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(ICollection<>)); Type type; IList list; if (implementedGenericInterface != null) { type = implementedGenericInterface.GetGenericArguments()[0]; value = objectFactory.Create(expectedType); list = value as IList; if (list == null) { canUpdate = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IList<>)) != null; list = (IList)Activator.CreateInstance(typeof(GenericCollectionToNonGenericAdapter<>).MakeGenericType(type), value); } } else { if (!typeof(IList).IsAssignableFrom(expectedType)) { value = null; return false; } type = typeof(object); value = objectFactory.Create(expectedType); list = (IList)value; } DeserializeHelper(type, parser, nestedObjectDeserializer, list, canUpdate); return true; } internal static void DeserializeHelper(Type tItem, IParser parser, Func nestedObjectDeserializer, IList result, bool canUpdate) { IList result2 = result; Type tItem2 = tItem; parser.Consume(); SequenceEnd @event; while (!parser.TryConsume(out @event)) { ParsingEvent current = parser.Current; object obj = nestedObjectDeserializer(parser, tItem2); if (obj is IValuePromise valuePromise) { if (!canUpdate) { throw new ForwardAnchorNotSupportedException(current?.Start ?? Mark.Empty, current?.End ?? Mark.Empty, "Forward alias references are not allowed because this type does not implement IList<>"); } int index = result2.Add(tItem2.IsValueType() ? Activator.CreateInstance(tItem2) : null); valuePromise.ValueAvailable += delegate(object? v) { result2[index] = YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(v, tItem2); }; } else { result2.Add(YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(obj, tItem2)); } } } } internal sealed class DictionaryNodeDeserializer : INodeDeserializer { private readonly IObjectFactory objectFactory; public DictionaryNodeDeserializer(IObjectFactory objectFactory) { this.objectFactory = objectFactory ?? throw new ArgumentNullException("objectFactory"); } bool INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { Type implementedGenericInterface = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IDictionary<, >)); Type type; Type type2; IDictionary dictionary; if (implementedGenericInterface != null) { Type[] genericArguments = implementedGenericInterface.GetGenericArguments(); type = genericArguments[0]; type2 = genericArguments[1]; value = objectFactory.Create(expectedType); dictionary = value as IDictionary; if (dictionary == null) { dictionary = (IDictionary)Activator.CreateInstance(typeof(GenericDictionaryToNonGenericAdapter<, >).MakeGenericType(type, type2), value); } } else { if (!typeof(IDictionary).IsAssignableFrom(expectedType)) { value = null; return false; } type = typeof(object); type2 = typeof(object); value = objectFactory.Create(expectedType); dictionary = (IDictionary)value; } DeserializeHelper(type, type2, parser, nestedObjectDeserializer, dictionary); return true; } private static void DeserializeHelper(Type tKey, Type tValue, IParser parser, Func nestedObjectDeserializer, IDictionary result) { IDictionary result2 = result; parser.Consume(); MappingEnd @event; while (!parser.TryConsume(out @event)) { object key = nestedObjectDeserializer(parser, tKey); object value = nestedObjectDeserializer(parser, tValue); IValuePromise valuePromise = value as IValuePromise; if (key is IValuePromise valuePromise2) { if (valuePromise == null) { valuePromise2.ValueAvailable += delegate(object? v) { result2[v] = value; }; continue; } bool hasFirstPart = false; valuePromise2.ValueAvailable += delegate(object? v) { if (hasFirstPart) { result2[v] = value; } else { key = v; hasFirstPart = true; } }; valuePromise.ValueAvailable += delegate(object? v) { if (hasFirstPart) { result2[key] = v; } else { value = v; hasFirstPart = true; } }; } else if (valuePromise == null) { result2[key] = value; } else { valuePromise.ValueAvailable += delegate(object? v) { result2[key] = v; }; } } } } internal sealed class EnumerableNodeDeserializer : INodeDeserializer { bool INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { Type type; if (expectedType == typeof(IEnumerable)) { type = typeof(object); } else { Type implementedGenericInterface = ReflectionUtility.GetImplementedGenericInterface(expectedType, typeof(IEnumerable<>)); if (implementedGenericInterface != expectedType) { value = null; return false; } type = implementedGenericInterface.GetGenericArguments()[0]; } Type arg = typeof(List<>).MakeGenericType(type); value = nestedObjectDeserializer(parser, arg); return true; } } internal sealed class NullNodeDeserializer : INodeDeserializer { bool INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { value = null; if (parser.Accept(out var @event) && NodeIsNull(@event)) { parser.SkipThisAndNestedEvents(); return true; } return false; } private bool NodeIsNull(NodeEvent nodeEvent) { if (nodeEvent.Tag == "tag:yaml.org,2002:null") { return true; } if (nodeEvent is YamlDotNet.Core.Events.Scalar scalar && scalar.Style == ScalarStyle.Plain) { string value = scalar.Value; switch (value) { default: return value == "NULL"; case "": case "~": case "null": case "Null": return true; } } return false; } } internal sealed class ObjectNodeDeserializer : INodeDeserializer { private readonly IObjectFactory objectFactory; private readonly ITypeInspector typeDescriptor; private readonly bool ignoreUnmatched; public ObjectNodeDeserializer(IObjectFactory objectFactory, ITypeInspector typeDescriptor, bool ignoreUnmatched) { this.objectFactory = objectFactory ?? throw new ArgumentNullException("objectFactory"); this.typeDescriptor = typeDescriptor ?? throw new ArgumentNullException("typeDescriptor"); this.ignoreUnmatched = ignoreUnmatched; } bool INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { if (!parser.TryConsume(out var _)) { value = null; return false; } Type type = Nullable.GetUnderlyingType(expectedType) ?? expectedType; value = objectFactory.Create(type); MappingEnd event2; while (!parser.TryConsume(out event2)) { YamlDotNet.Core.Events.Scalar scalar = parser.Consume(); IPropertyDescriptor property = typeDescriptor.GetProperty(type, null, scalar.Value, ignoreUnmatched); if (property == null) { parser.SkipThisAndNestedEvents(); continue; } object obj = nestedObjectDeserializer(parser, property.Type); if (obj is IValuePromise valuePromise) { object valueRef = value; valuePromise.ValueAvailable += delegate(object? v) { object value3 = YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(v, property.Type); property.Write(valueRef, value3); }; } else { object value2 = YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(obj, property.Type); property.Write(value, value2); } } return true; } } internal sealed class ScalarNodeDeserializer : INodeDeserializer { private const string BooleanTruePattern = "^(true|y|yes|on)$"; private const string BooleanFalsePattern = "^(false|n|no|off)$"; bool INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { if (!parser.TryConsume(out var @event)) { value = null; return false; } Type type = Nullable.GetUnderlyingType(expectedType) ?? expectedType; if (type.IsEnum()) { value = Enum.Parse(type, @event.Value, ignoreCase: true); return true; } TypeCode typeCode = type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: value = DeserializeBooleanHelper(@event.Value); break; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: value = DeserializeIntegerHelper(typeCode, @event.Value); break; case TypeCode.Single: value = float.Parse(@event.Value, YamlFormatter.NumberFormat); break; case TypeCode.Double: value = double.Parse(@event.Value, YamlFormatter.NumberFormat); break; case TypeCode.Decimal: value = decimal.Parse(@event.Value, YamlFormatter.NumberFormat); break; case TypeCode.String: value = @event.Value; break; case TypeCode.Char: value = @event.Value[0]; break; case TypeCode.DateTime: value = DateTime.Parse(@event.Value, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); break; default: if (expectedType == typeof(object)) { value = @event.Value; } else { value = YamlDotNet.Serialization.Utilities.TypeConverter.ChangeType(@event.Value, expectedType); } break; } return true; } private object DeserializeBooleanHelper(string value) { bool flag; if (Regex.IsMatch(value, "^(true|y|yes|on)$", RegexOptions.IgnoreCase)) { flag = true; } else { if (!Regex.IsMatch(value, "^(false|n|no|off)$", RegexOptions.IgnoreCase)) { throw new FormatException("The value \"" + value + "\" is not a valid YAML Boolean"); } flag = false; } return flag; } private object DeserializeIntegerHelper(TypeCode typeCode, string value) { StringBuilder stringBuilder = new StringBuilder(); int i = 0; bool flag = false; ulong num = 0uL; if (value[0] == '-') { i++; flag = true; } else if (value[0] == '+') { i++; } if (value[i] == '0') { int num2; if (i == value.Length - 1) { num2 = 10; num = 0uL; } else { i++; if (value[i] == 'b') { num2 = 2; i++; } else if (value[i] == 'x') { num2 = 16; i++; } else { num2 = 8; } } for (; i < value.Length; i++) { if (value[i] != '_') { stringBuilder.Append(value[i]); } } switch (num2) { case 2: case 8: num = Convert.ToUInt64(stringBuilder.ToString(), num2); break; case 16: num = ulong.Parse(stringBuilder.ToString(), NumberStyles.HexNumber, YamlFormatter.NumberFormat); break; } } else { string[] array = value.Substring(i).Split(new char[1] { ':' }); num = 0uL; for (int j = 0; j < array.Length; j++) { num *= 60; num += ulong.Parse(array[j].Replace("_", "")); } } if (flag) { return CastInteger(checked(-(long)num), typeCode); } return CastInteger(num, typeCode); } private static object CastInteger(long number, TypeCode typeCode) { return checked(typeCode switch { TypeCode.Byte => (byte)number, TypeCode.Int16 => (short)number, TypeCode.Int32 => (int)number, TypeCode.Int64 => number, TypeCode.SByte => (sbyte)number, TypeCode.UInt16 => (ushort)number, TypeCode.UInt32 => (uint)number, TypeCode.UInt64 => (ulong)number, _ => number, }); } private static object CastInteger(ulong number, TypeCode typeCode) { return checked(typeCode switch { TypeCode.Byte => (byte)number, TypeCode.Int16 => (short)number, TypeCode.Int32 => (int)number, TypeCode.Int64 => (long)number, TypeCode.SByte => (sbyte)number, TypeCode.UInt16 => (ushort)number, TypeCode.UInt32 => (uint)number, TypeCode.UInt64 => number, _ => number, }); } } internal sealed class TypeConverterNodeDeserializer : INodeDeserializer { private readonly IEnumerable converters; public TypeConverterNodeDeserializer(IEnumerable converters) { this.converters = converters ?? throw new ArgumentNullException("converters"); } bool INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { Type expectedType2 = expectedType; IYamlTypeConverter yamlTypeConverter = converters.FirstOrDefault((IYamlTypeConverter c) => c.Accepts(expectedType2)); if (yamlTypeConverter == null) { value = null; return false; } value = yamlTypeConverter.ReadYaml(parser, expectedType2); return true; } } internal sealed class YamlConvertibleNodeDeserializer : INodeDeserializer { private readonly IObjectFactory objectFactory; public YamlConvertibleNodeDeserializer(IObjectFactory objectFactory) { this.objectFactory = objectFactory; } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { Func nestedObjectDeserializer2 = nestedObjectDeserializer; IParser parser2 = parser; if (typeof(IYamlConvertible).IsAssignableFrom(expectedType)) { IYamlConvertible yamlConvertible = (IYamlConvertible)objectFactory.Create(expectedType); yamlConvertible.Read(parser2, expectedType, (Type type) => nestedObjectDeserializer2(parser2, type)); value = yamlConvertible; return true; } value = null; return false; } } internal sealed class YamlSerializableNodeDeserializer : INodeDeserializer { private readonly IObjectFactory objectFactory; public YamlSerializableNodeDeserializer(IObjectFactory objectFactory) { this.objectFactory = objectFactory; } public bool Deserialize(IParser parser, Type expectedType, Func nestedObjectDeserializer, out object? value) { if (typeof(IYamlSerializable).IsAssignableFrom(expectedType)) { IYamlSerializable yamlSerializable = (IYamlSerializable)objectFactory.Create(expectedType); yamlSerializable.ReadYaml(parser); value = yamlSerializable; return true; } value = null; return false; } } } namespace YamlDotNet.Serialization.NamingConventions { internal sealed class CamelCaseNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new CamelCaseNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public CamelCaseNamingConvention() { } public string Apply(string value) { return value.ToCamelCase(); } } internal sealed class HyphenatedNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new HyphenatedNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public HyphenatedNamingConvention() { } public string Apply(string value) { return value.FromCamelCase("-"); } } internal sealed class LowerCaseNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new LowerCaseNamingConvention(); private LowerCaseNamingConvention() { } public string Apply(string value) { return value.ToCamelCase().ToLower(); } } internal sealed class NullNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new NullNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public NullNamingConvention() { } public string Apply(string value) { return value; } } internal sealed class PascalCaseNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new PascalCaseNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public PascalCaseNamingConvention() { } public string Apply(string value) { return value.ToPascalCase(); } } internal sealed class UnderscoredNamingConvention : INamingConvention { public static readonly INamingConvention Instance = new UnderscoredNamingConvention(); [Obsolete("Use the Instance static field instead of creating new instances")] public UnderscoredNamingConvention() { } public string Apply(string value) { return value.FromCamelCase("_"); } } } namespace YamlDotNet.Serialization.EventEmitters { internal abstract class ChainedEventEmitter : IEventEmitter { protected readonly IEventEmitter nextEmitter; protected ChainedEventEmitter(IEventEmitter nextEmitter) { this.nextEmitter = nextEmitter ?? throw new ArgumentNullException("nextEmitter"); } public virtual void Emit(AliasEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(ScalarEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(MappingStartEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(MappingEndEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } public virtual void Emit(SequenceEndEventInfo eventInfo, IEmitter emitter) { nextEmitter.Emit(eventInfo, emitter); } } internal sealed class JsonEventEmitter : ChainedEventEmitter { public JsonEventEmitter(IEventEmitter nextEmitter) : base(nextEmitter) { } public override void Emit(AliasEventInfo eventInfo, IEmitter emitter) { eventInfo.NeedsExpansion = true; } public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) { eventInfo.IsPlainImplicit = true; eventInfo.Style = ScalarStyle.Plain; object value = eventInfo.Source.Value; if (value == null) { eventInfo.RenderedValue = "null"; } else { TypeCode typeCode = eventInfo.Source.Type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: eventInfo.RenderedValue = YamlFormatter.FormatBoolean(value); break; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: if (eventInfo.Source.Type.IsEnum()) { eventInfo.RenderedValue = value.ToString(); eventInfo.Style = ScalarStyle.DoubleQuoted; } else { eventInfo.RenderedValue = YamlFormatter.FormatNumber(value); } break; case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: eventInfo.RenderedValue = YamlFormatter.FormatNumber(value); break; case TypeCode.Char: case TypeCode.String: eventInfo.RenderedValue = value.ToString(); eventInfo.Style = ScalarStyle.DoubleQuoted; break; case TypeCode.DateTime: eventInfo.RenderedValue = YamlFormatter.FormatDateTime(value); break; case TypeCode.Empty: eventInfo.RenderedValue = "null"; break; default: if (eventInfo.Source.Type == typeof(TimeSpan)) { eventInfo.RenderedValue = YamlFormatter.FormatTimeSpan(value); break; } throw new NotSupportedException($"TypeCode.{typeCode} is not supported."); } } base.Emit(eventInfo, emitter); } public override void Emit(MappingStartEventInfo eventInfo, IEmitter emitter) { eventInfo.Style = MappingStyle.Flow; base.Emit(eventInfo, emitter); } public override void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter) { eventInfo.Style = SequenceStyle.Flow; base.Emit(eventInfo, emitter); } } internal sealed class TypeAssigningEventEmitter : ChainedEventEmitter { private readonly bool requireTagWhenStaticAndActualTypesAreDifferent; private readonly IDictionary tagMappings; public TypeAssigningEventEmitter(IEventEmitter nextEmitter, bool requireTagWhenStaticAndActualTypesAreDifferent, IDictionary tagMappings) : base(nextEmitter) { this.requireTagWhenStaticAndActualTypesAreDifferent = requireTagWhenStaticAndActualTypesAreDifferent; this.tagMappings = tagMappings ?? throw new ArgumentNullException("tagMappings"); } public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) { ScalarStyle style = ScalarStyle.Plain; object value = eventInfo.Source.Value; if (value == null) { eventInfo.Tag = JsonSchema.Tags.Null; eventInfo.RenderedValue = ""; } else { TypeCode typeCode = eventInfo.Source.Type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: eventInfo.Tag = JsonSchema.Tags.Bool; eventInfo.RenderedValue = YamlFormatter.FormatBoolean(value); break; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: eventInfo.Tag = JsonSchema.Tags.Int; eventInfo.RenderedValue = YamlFormatter.FormatNumber(value); break; case TypeCode.Single: eventInfo.Tag = JsonSchema.Tags.Float; eventInfo.RenderedValue = YamlFormatter.FormatNumber((float)value); break; case TypeCode.Double: eventInfo.Tag = JsonSchema.Tags.Float; eventInfo.RenderedValue = YamlFormatter.FormatNumber((double)value); break; case TypeCode.Decimal: eventInfo.Tag = JsonSchema.Tags.Float; eventInfo.RenderedValue = YamlFormatter.FormatNumber(value); break; case TypeCode.Char: case TypeCode.String: eventInfo.Tag = FailsafeSchema.Tags.Str; eventInfo.RenderedValue = value.ToString(); style = ScalarStyle.Any; break; case TypeCode.DateTime: eventInfo.Tag = DefaultSchema.Tags.Timestamp; eventInfo.RenderedValue = YamlFormatter.FormatDateTime(value); break; case TypeCode.Empty: eventInfo.Tag = JsonSchema.Tags.Null; eventInfo.RenderedValue = ""; break; default: if (eventInfo.Source.Type == typeof(TimeSpan)) { eventInfo.RenderedValue = YamlFormatter.FormatTimeSpan(value); break; } throw new NotSupportedException($"TypeCode.{typeCode} is not supported."); } } eventInfo.IsPlainImplicit = true; if (eventInfo.Style == ScalarStyle.Any) { eventInfo.Style = style; } base.Emit(eventInfo, emitter); } public override void Emit(MappingStartEventInfo eventInfo, IEmitter emitter) { AssignTypeIfNeeded(eventInfo); base.Emit(eventInfo, emitter); } public override void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter) { AssignTypeIfNeeded(eventInfo); base.Emit(eventInfo, emitter); } private void AssignTypeIfNeeded(ObjectEventInfo eventInfo) { if (tagMappings.TryGetValue(eventInfo.Source.Type, out var value)) { eventInfo.Tag = value; } else if (requireTagWhenStaticAndActualTypesAreDifferent && eventInfo.Source.Value != null && eventInfo.Source.Type != eventInfo.Source.StaticType) { throw new YamlException("Cannot serialize type '" + eventInfo.Source.Type.FullName + "' where a '" + eventInfo.Source.StaticType.FullName + "' was expected because no tag mapping has been registered for '" + eventInfo.Source.Type.FullName + "', which means that it won't be possible to deserialize the document.\nRegister a tag mapping using the SerializerBuilder.WithTagMapping method.\n\nE.g: builder.WithTagMapping(\"!" + eventInfo.Source.Type.Name + "\", typeof(" + eventInfo.Source.Type.FullName + "));"); } } } internal sealed class WriterEventEmitter : IEventEmitter { void IEventEmitter.Emit(AliasEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new YamlDotNet.Core.Events.AnchorAlias(eventInfo.Alias)); } void IEventEmitter.Emit(ScalarEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new YamlDotNet.Core.Events.Scalar(eventInfo.Anchor, eventInfo.Tag, eventInfo.RenderedValue, eventInfo.Style, eventInfo.IsPlainImplicit, eventInfo.IsQuotedImplicit)); } void IEventEmitter.Emit(MappingStartEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new MappingStart(eventInfo.Anchor, eventInfo.Tag, eventInfo.IsImplicit, eventInfo.Style)); } void IEventEmitter.Emit(MappingEndEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new MappingEnd()); } void IEventEmitter.Emit(SequenceStartEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new SequenceStart(eventInfo.Anchor, eventInfo.Tag, eventInfo.IsImplicit, eventInfo.Style)); } void IEventEmitter.Emit(SequenceEndEventInfo eventInfo, IEmitter emitter) { emitter.Emit(new SequenceEnd()); } } } namespace YamlDotNet.Serialization.Converters { internal class DateTimeConverter : IYamlTypeConverter { private readonly DateTimeKind kind; private readonly IFormatProvider provider; private readonly string[] formats; public DateTimeConverter(DateTimeKind kind = DateTimeKind.Utc, IFormatProvider? provider = null, params string[] formats) { this.kind = ((kind == DateTimeKind.Unspecified) ? DateTimeKind.Utc : kind); this.provider = provider ?? CultureInfo.InvariantCulture; this.formats = formats.DefaultIfEmpty("G").ToArray(); } public bool Accepts(Type type) { return type == typeof(DateTime); } public object ReadYaml(IParser parser, Type type) { return EnsureDateTimeKind(DateTime.ParseExact(parser.Consume().Value, style: (kind == DateTimeKind.Local) ? DateTimeStyles.AssumeLocal : DateTimeStyles.AssumeUniversal, formats: formats, provider: provider), kind); } public void WriteYaml(IEmitter emitter, object? value, Type type) { DateTime dateTime = (DateTime)value; string value2 = ((kind == DateTimeKind.Local) ? dateTime.ToLocalTime() : dateTime.ToUniversalTime()).ToString(formats.First(), provider); emitter.Emit(new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, value2, ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: false)); } private static DateTime EnsureDateTimeKind(DateTime dt, DateTimeKind kind) { if (dt.Kind == DateTimeKind.Local && kind == DateTimeKind.Utc) { return dt.ToUniversalTime(); } if (dt.Kind == DateTimeKind.Utc && kind == DateTimeKind.Local) { return dt.ToLocalTime(); } return dt; } } internal class GuidConverter : IYamlTypeConverter { private readonly bool jsonCompatible; public GuidConverter(bool jsonCompatible) { this.jsonCompatible = jsonCompatible; } public bool Accepts(Type type) { return type == typeof(Guid); } public object ReadYaml(IParser parser, Type type) { return new Guid(parser.Consume().Value); } public void WriteYaml(IEmitter emitter, object? value, Type type) { Guid guid = (Guid)value; emitter.Emit(new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, guid.ToString("D"), jsonCompatible ? ScalarStyle.DoubleQuoted : ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: false)); } } internal class SystemTypeConverter : IYamlTypeConverter { public bool Accepts(Type type) { return typeof(Type).IsAssignableFrom(type); } public object ReadYaml(IParser parser, Type type) { return Type.GetType(parser.Consume().Value, throwOnError: true); } public void WriteYaml(IEmitter emitter, object? value, Type type) { Type type2 = (Type)value; emitter.Emit(new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, type2.AssemblyQualifiedName, ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: false)); } } } namespace YamlDotNet.RepresentationModel { internal class DocumentLoadingState { private readonly IDictionary anchors = new Dictionary(); private readonly IList nodesWithUnresolvedAliases = new List(); public void AddAnchor(YamlNode node) { if (node.Anchor.IsEmpty) { throw new ArgumentException("The specified node does not have an anchor"); } if (anchors.ContainsKey(node.Anchor)) { anchors[node.Anchor] = node; } else { anchors.Add(node.Anchor, node); } } public YamlNode GetNode(AnchorName anchor, Mark start, Mark end) { if (anchors.TryGetValue(anchor, out YamlNode value)) { return value; } throw new AnchorNotFoundException(start, end, $"The anchor '{anchor}' does not exists"); } public bool TryGetNode(AnchorName anchor, [NotNullWhen(true)] out YamlNode? node) { return anchors.TryGetValue(anchor, out node); } public void AddNodeWithUnresolvedAliases(YamlNode node) { nodesWithUnresolvedAliases.Add(node); } public void ResolveAliases() { foreach (YamlNode nodesWithUnresolvedAlias in nodesWithUnresolvedAliases) { nodesWithUnresolvedAlias.ResolveAliases(this); } } } internal class EmitterState { public HashSet EmittedAnchors { get; } = new HashSet(); } internal interface IYamlVisitor { void Visit(YamlStream stream); void Visit(YamlDocument document); void Visit(YamlScalarNode scalar); void Visit(YamlSequenceNode sequence); void Visit(YamlMappingNode mapping); } internal class LibYamlEventStream { private readonly IParser parser; public LibYamlEventStream(IParser iParser) { parser = iParser ?? throw new ArgumentNullException("iParser"); } public void WriteTo(TextWriter textWriter) { while (parser.MoveNext()) { ParsingEvent current = parser.Current; if (!(current is YamlDotNet.Core.Events.AnchorAlias anchorAlias)) { if (!(current is YamlDotNet.Core.Events.DocumentEnd documentEnd)) { if (!(current is YamlDotNet.Core.Events.DocumentStart documentStart)) { if (!(current is MappingEnd)) { if (!(current is MappingStart nodeEvent)) { if (!(current is YamlDotNet.Core.Events.Scalar scalar)) { if (!(current is SequenceEnd)) { if (!(current is SequenceStart nodeEvent2)) { if (!(current is YamlDotNet.Core.Events.StreamEnd)) { if (current is YamlDotNet.Core.Events.StreamStart) { textWriter.Write("+STR"); } } else { textWriter.Write("-STR"); } } else { textWriter.Write("+SEQ"); WriteAnchorAndTag(textWriter, nodeEvent2); } } else { textWriter.Write("-SEQ"); } } else { textWriter.Write("=VAL"); WriteAnchorAndTag(textWriter, scalar); switch (scalar.Style) { case ScalarStyle.DoubleQuoted: textWriter.Write(" \""); break; case ScalarStyle.SingleQuoted: textWriter.Write(" '"); break; case ScalarStyle.Folded: textWriter.Write(" >"); break; case ScalarStyle.Literal: textWriter.Write(" |"); break; default: textWriter.Write(" :"); break; } string value = scalar.Value; foreach (char c in value) { switch (c) { case '\b': textWriter.Write("\\b"); break; case '\t': textWriter.Write("\\t"); break; case '\n': textWriter.Write("\\n"); break; case '\r': textWriter.Write("\\r"); break; case '\\': textWriter.Write("\\\\"); break; default: textWriter.Write(c); break; } } } } else { textWriter.Write("+MAP"); WriteAnchorAndTag(textWriter, nodeEvent); } } else { textWriter.Write("-MAP"); } } else { textWriter.Write("+DOC"); if (!documentStart.IsImplicit) { textWriter.Write(" ---"); } } } else { textWriter.Write("-DOC"); if (!documentEnd.IsImplicit) { textWriter.Write(" ..."); } } } else { textWriter.Write("=ALI *"); textWriter.Write(anchorAlias.Value); } textWriter.WriteLine(); } } private void WriteAnchorAndTag(TextWriter textWriter, NodeEvent nodeEvent) { if (!nodeEvent.Anchor.IsEmpty) { textWriter.Write(" &"); textWriter.Write(nodeEvent.Anchor); } if (!nodeEvent.Tag.IsEmpty) { textWriter.Write(" <"); textWriter.Write(nodeEvent.Tag.Value); textWriter.Write(">"); } } } internal class YamlAliasNode : YamlNode { public override YamlNodeType NodeType => YamlNodeType.Alias; internal YamlAliasNode(AnchorName anchor) { base.Anchor = anchor; } internal override void ResolveAliases(DocumentLoadingState state) { throw new NotSupportedException("Resolving an alias on an alias node does not make sense"); } internal override void Emit(IEmitter emitter, EmitterState state) { throw new NotSupportedException("A YamlAliasNode is an implementation detail and should never be saved."); } public override void Accept(IYamlVisitor visitor) { throw new NotSupportedException("A YamlAliasNode is an implementation detail and should never be visited."); } public override bool Equals(object? obj) { if (obj is YamlAliasNode yamlAliasNode && Equals(yamlAliasNode)) { return object.Equals(base.Anchor, yamlAliasNode.Anchor); } return false; } public override int GetHashCode() { return base.GetHashCode(); } internal override string ToString(RecursionLevel level) { return "*" + base.Anchor.ToString(); } internal override IEnumerable SafeAllNodes(RecursionLevel level) { yield return this; } } internal class YamlDocument { private class AnchorAssigningVisitor : YamlVisitorBase { private readonly HashSet existingAnchors = new HashSet(); private readonly Dictionary visitedNodes = new Dictionary(); public void AssignAnchors(YamlDocument document) { existingAnchors.Clear(); visitedNodes.Clear(); document.Accept(this); Random random = new Random(); foreach (KeyValuePair visitedNode in visitedNodes) { if (!visitedNode.Value) { continue; } AnchorName anchorName; if (!visitedNode.Key.Anchor.IsEmpty && !existingAnchors.Contains(visitedNode.Key.Anchor)) { anchorName = visitedNode.Key.Anchor; } else { do { anchorName = new AnchorName(random.Next().ToString(CultureInfo.InvariantCulture)); } while (existingAnchors.Contains(anchorName)); } existingAnchors.Add(anchorName); visitedNode.Key.Anchor = anchorName; } } private bool VisitNodeAndFindDuplicates(YamlNode node) { if (visitedNodes.TryGetValue(node, out var value)) { if (!value) { visitedNodes[node] = true; } return !value; } visitedNodes.Add(node, value: false); return false; } public override void Visit(YamlScalarNode scalar) { VisitNodeAndFindDuplicates(scalar); } public override void Visit(YamlMappingNode mapping) { if (!VisitNodeAndFindDuplicates(mapping)) { base.Visit(mapping); } } public override void Visit(YamlSequenceNode sequence) { if (!VisitNodeAndFindDuplicates(sequence)) { base.Visit(sequence); } } } public YamlNode RootNode { get; private set; } public IEnumerable AllNodes => RootNode.AllNodes; public YamlDocument(YamlNode rootNode) { RootNode = rootNode; } public YamlDocument(string rootNode) { RootNode = new YamlScalarNode(rootNode); } internal YamlDocument(IParser parser) { DocumentLoadingState documentLoadingState = new DocumentLoadingState(); parser.Consume(); YamlDotNet.Core.Events.DocumentEnd @event; while (!parser.TryConsume(out @event)) { RootNode = YamlNode.ParseNode(parser, documentLoadingState); if (RootNode is YamlAliasNode) { throw new YamlException("A document cannot contain only an alias"); } } documentLoadingState.ResolveAliases(); if (RootNode == null) { throw new ArgumentException("Atempted to parse an empty document"); } } private void AssignAnchors() { new AnchorAssigningVisitor().AssignAnchors(this); } internal void Save(IEmitter emitter, bool assignAnchors = true) { if (assignAnchors) { AssignAnchors(); } emitter.Emit(new YamlDotNet.Core.Events.DocumentStart()); RootNode.Save(emitter, new EmitterState()); emitter.Emit(new YamlDotNet.Core.Events.DocumentEnd(isImplicit: false)); } public void Accept(IYamlVisitor visitor) { visitor.Visit(this); } } internal sealed class YamlMappingNode : YamlNode, IEnumerable>, IEnumerable, IYamlConvertible { private readonly IOrderedDictionary children = new OrderedDictionary(); public IOrderedDictionary Children => children; public MappingStyle Style { get; set; } public override YamlNodeType NodeType => YamlNodeType.Mapping; internal YamlMappingNode(IParser parser, DocumentLoadingState state) { Load(parser, state); } private void Load(IParser parser, DocumentLoadingState state) { MappingStart mappingStart = parser.Consume(); Load(mappingStart, state); Style = mappingStart.Style; bool flag = false; MappingEnd @event; while (!parser.TryConsume(out @event)) { YamlNode yamlNode = YamlNode.ParseNode(parser, state); YamlNode yamlNode2 = YamlNode.ParseNode(parser, state); try { children.Add(yamlNode, yamlNode2); } catch (ArgumentException innerException) { throw new YamlException(yamlNode.Start, yamlNode.End, "Duplicate key", innerException); } flag = flag || yamlNode is YamlAliasNode || yamlNode2 is YamlAliasNode; } if (flag) { state.AddNodeWithUnresolvedAliases(this); } } public YamlMappingNode() { } public YamlMappingNode(params KeyValuePair[] children) : this((IEnumerable>)children) { } public YamlMappingNode(IEnumerable> children) { foreach (KeyValuePair child in children) { this.children.Add(child); } } public YamlMappingNode(params YamlNode[] children) : this((IEnumerable)children) { } public YamlMappingNode(IEnumerable children) { using IEnumerator enumerator = children.GetEnumerator(); while (enumerator.MoveNext()) { YamlNode current = enumerator.Current; if (!enumerator.MoveNext()) { throw new ArgumentException("When constructing a mapping node with a sequence, the number of elements of the sequence must be even."); } Add(current, enumerator.Current); } } public void Add(YamlNode key, YamlNode value) { children.Add(key, value); } public void Add(string key, YamlNode value) { children.Add(new YamlScalarNode(key), value); } public void Add(YamlNode key, string value) { children.Add(key, new YamlScalarNode(value)); } public void Add(string key, string value) { children.Add(new YamlScalarNode(key), new YamlScalarNode(value)); } internal override void ResolveAliases(DocumentLoadingState state) { Dictionary dictionary = null; Dictionary dictionary2 = null; foreach (KeyValuePair child in children) { if (child.Key is YamlAliasNode) { if (dictionary == null) { dictionary = new Dictionary(); } dictionary.Add(child.Key, state.GetNode(child.Key.Anchor, child.Key.Start, child.Key.End)); } if (child.Value is YamlAliasNode) { if (dictionary2 == null) { dictionary2 = new Dictionary(); } dictionary2.Add(child.Key, state.GetNode(child.Value.Anchor, child.Value.Start, child.Value.End)); } } if (dictionary2 != null) { foreach (KeyValuePair item in dictionary2) { children[item.Key] = item.Value; } } if (dictionary == null) { return; } foreach (KeyValuePair item2 in dictionary) { YamlNode value = children[item2.Key]; children.Remove(item2.Key); children.Add(item2.Value, value); } } internal override void Emit(IEmitter emitter, EmitterState state) { emitter.Emit(new MappingStart(base.Anchor, base.Tag, isImplicit: true, Style)); foreach (KeyValuePair child in children) { child.Key.Save(emitter, state); child.Value.Save(emitter, state); } emitter.Emit(new MappingEnd()); } public override void Accept(IYamlVisitor visitor) { visitor.Visit(this); } public override bool Equals(object? obj) { if (!(obj is YamlMappingNode yamlMappingNode) || !object.Equals(base.Tag, yamlMappingNode.Tag) || children.Count != yamlMappingNode.children.Count) { return false; } foreach (KeyValuePair child in children) { if (!yamlMappingNode.children.TryGetValue(child.Key, out YamlNode value) || !object.Equals(child.Value, value)) { return false; } } return true; } public override int GetHashCode() { int num = base.GetHashCode(); foreach (KeyValuePair child in children) { num = YamlDotNet.Core.HashCode.CombineHashCodes(num, child.Key); num = YamlDotNet.Core.HashCode.CombineHashCodes(num, child.Value); } return num; } internal override IEnumerable SafeAllNodes(RecursionLevel level) { level.Increment(); yield return this; foreach (KeyValuePair child in children) { foreach (YamlNode item in child.Key.SafeAllNodes(level)) { yield return item; } foreach (YamlNode item2 in child.Value.SafeAllNodes(level)) { yield return item2; } } level.Decrement(); } internal override string ToString(RecursionLevel level) { if (!level.TryIncrement()) { return "WARNING! INFINITE RECURSION!"; } StringBuilder stringBuilder = new StringBuilder("{ "); foreach (KeyValuePair child in children) { if (stringBuilder.Length > 2) { stringBuilder.Append(", "); } stringBuilder.Append("{ ").Append(child.Key.ToString(level)).Append(", ") .Append(child.Value.ToString(level)) .Append(" }"); } stringBuilder.Append(" }"); level.Decrement(); return stringBuilder.ToString(); } public IEnumerator> GetEnumerator() { return children.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { Load(parser, new DocumentLoadingState()); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { Emit(emitter, new EmitterState()); } public static YamlMappingNode FromObject(object mapping) { if (mapping == null) { throw new ArgumentNullException("mapping"); } YamlMappingNode yamlMappingNode = new YamlMappingNode(); foreach (PropertyInfo publicProperty in mapping.GetType().GetPublicProperties()) { if (publicProperty.CanRead && publicProperty.GetGetMethod(nonPublic: false).GetParameters().Length == 0) { object value = publicProperty.GetValue(mapping, null); YamlNode yamlNode = value as YamlNode; if (yamlNode == null) { yamlNode = Convert.ToString(value) ?? string.Empty; } yamlMappingNode.Add(publicProperty.Name, yamlNode); } } return yamlMappingNode; } } internal abstract class YamlNode { private const int MaximumRecursionLevel = 1000; internal const string MaximumRecursionLevelReachedToStringValue = "WARNING! INFINITE RECURSION!"; public AnchorName Anchor { get; set; } public TagName Tag { get; set; } public Mark Start { get; private set; } = Mark.Empty; public Mark End { get; private set; } = Mark.Empty; public IEnumerable AllNodes { get { RecursionLevel level = new RecursionLevel(1000); return SafeAllNodes(level); } } public abstract YamlNodeType NodeType { get; } public YamlNode this[int index] { get { if (!(this is YamlSequenceNode yamlSequenceNode)) { throw new ArgumentException($"Accessed '{NodeType}' with an invalid index: {index}. Only Sequences can be indexed by number."); } return yamlSequenceNode.Children[index]; } } public YamlNode this[YamlNode key] { get { if (!(this is YamlMappingNode yamlMappingNode)) { throw new ArgumentException($"Accessed '{NodeType}' with an invalid index: {key}. Only Mappings can be indexed by key."); } return yamlMappingNode.Children[key]; } } internal void Load(NodeEvent yamlEvent, DocumentLoadingState state) { Tag = yamlEvent.Tag; if (!yamlEvent.Anchor.IsEmpty) { Anchor = yamlEvent.Anchor; state.AddAnchor(this); } Start = yamlEvent.Start; End = yamlEvent.End; } internal static YamlNode ParseNode(IParser parser, DocumentLoadingState state) { if (parser.Accept(out var _)) { return new YamlScalarNode(parser, state); } if (parser.Accept(out var _)) { return new YamlSequenceNode(parser, state); } if (parser.Accept(out var _)) { return new YamlMappingNode(parser, state); } if (parser.TryConsume(out var event4)) { if (!state.TryGetNode(event4.Value, out YamlNode node)) { return new YamlAliasNode(event4.Value); } return node; } throw new ArgumentException("The current event is of an unsupported type.", "parser"); } internal abstract void ResolveAliases(DocumentLoadingState state); internal void Save(IEmitter emitter, EmitterState state) { if (!Anchor.IsEmpty && !state.EmittedAnchors.Add(Anchor)) { emitter.Emit(new YamlDotNet.Core.Events.AnchorAlias(Anchor)); } else { Emit(emitter, state); } } internal abstract void Emit(IEmitter emitter, EmitterState state); public abstract void Accept(IYamlVisitor visitor); public override string ToString() { RecursionLevel recursionLevel = new RecursionLevel(1000); return ToString(recursionLevel); } internal abstract string ToString(RecursionLevel level); internal abstract IEnumerable SafeAllNodes(RecursionLevel level); public static implicit operator YamlNode(string value) { return new YamlScalarNode(value); } public static implicit operator YamlNode(string[] sequence) { return new YamlSequenceNode(((IEnumerable)sequence).Select((Func)((string i) => i))); } public static explicit operator string?(YamlNode node) { if (!(node is YamlScalarNode yamlScalarNode)) { throw new ArgumentException($"Attempted to convert a '{node.NodeType}' to string. This conversion is valid only for Scalars."); } return yamlScalarNode.Value; } } internal sealed class YamlNodeIdentityEqualityComparer : IEqualityComparer { public bool Equals([AllowNull] YamlNode x, [AllowNull] YamlNode y) { return x == y; } public int GetHashCode(YamlNode obj) { return obj.GetHashCode(); } } internal enum YamlNodeType { Alias, Mapping, Scalar, Sequence } [DebuggerDisplay("{Value}")] internal sealed class YamlScalarNode : YamlNode, IYamlConvertible { public string? Value { get; set; } public ScalarStyle Style { get; set; } public override YamlNodeType NodeType => YamlNodeType.Scalar; internal YamlScalarNode(IParser parser, DocumentLoadingState state) { Load(parser, state); } private void Load(IParser parser, DocumentLoadingState state) { YamlDotNet.Core.Events.Scalar scalar = parser.Consume(); Load(scalar, state); Value = scalar.Value; Style = scalar.Style; } public YamlScalarNode() { } public YamlScalarNode(string? value) { Value = value; } internal override void ResolveAliases(DocumentLoadingState state) { throw new NotSupportedException("Resolving an alias on a scalar node does not make sense"); } internal override void Emit(IEmitter emitter, EmitterState state) { emitter.Emit(new YamlDotNet.Core.Events.Scalar(base.Anchor, base.Tag, Value ?? string.Empty, Style, base.Tag.IsEmpty, isQuotedImplicit: false)); } public override void Accept(IYamlVisitor visitor) { visitor.Visit(this); } public override bool Equals(object? obj) { if (obj is YamlScalarNode yamlScalarNode && object.Equals(base.Tag, yamlScalarNode.Tag)) { return object.Equals(Value, yamlScalarNode.Value); } return false; } public override int GetHashCode() { return YamlDotNet.Core.HashCode.CombineHashCodes(base.Tag, Value); } public static explicit operator string?(YamlScalarNode value) { return value.Value; } internal override string ToString(RecursionLevel level) { return Value ?? string.Empty; } internal override IEnumerable SafeAllNodes(RecursionLevel level) { yield return this; } void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { Load(parser, new DocumentLoadingState()); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { Emit(emitter, new EmitterState()); } } [DebuggerDisplay("Count = {children.Count}")] internal sealed class YamlSequenceNode : YamlNode, IEnumerable, IEnumerable, IYamlConvertible { private readonly IList children = new List(); public IList Children => children; public SequenceStyle Style { get; set; } public override YamlNodeType NodeType => YamlNodeType.Sequence; internal YamlSequenceNode(IParser parser, DocumentLoadingState state) { Load(parser, state); } private void Load(IParser parser, DocumentLoadingState state) { SequenceStart sequenceStart = parser.Consume(); Load(sequenceStart, state); Style = sequenceStart.Style; bool flag = false; SequenceEnd @event; while (!parser.TryConsume(out @event)) { YamlNode yamlNode = YamlNode.ParseNode(parser, state); children.Add(yamlNode); flag = flag || yamlNode is YamlAliasNode; } if (flag) { state.AddNodeWithUnresolvedAliases(this); } } public YamlSequenceNode() { } public YamlSequenceNode(params YamlNode[] children) : this((IEnumerable)children) { } public YamlSequenceNode(IEnumerable children) { foreach (YamlNode child in children) { this.children.Add(child); } } public void Add(YamlNode child) { children.Add(child); } public void Add(string child) { children.Add(new YamlScalarNode(child)); } internal override void ResolveAliases(DocumentLoadingState state) { for (int i = 0; i < children.Count; i++) { if (children[i] is YamlAliasNode) { children[i] = state.GetNode(children[i].Anchor, children[i].Start, children[i].End); } } } internal override void Emit(IEmitter emitter, EmitterState state) { emitter.Emit(new SequenceStart(base.Anchor, base.Tag, base.Tag.IsEmpty, Style)); foreach (YamlNode child in children) { child.Save(emitter, state); } emitter.Emit(new SequenceEnd()); } public override void Accept(IYamlVisitor visitor) { visitor.Visit(this); } public override bool Equals(object? obj) { if (!(obj is YamlSequenceNode yamlSequenceNode) || !object.Equals(base.Tag, yamlSequenceNode.Tag) || children.Count != yamlSequenceNode.children.Count) { return false; } for (int i = 0; i < children.Count; i++) { if (!object.Equals(children[i], yamlSequenceNode.children[i])) { return false; } } return true; } public override int GetHashCode() { int h = 0; foreach (YamlNode child in children) { h = YamlDotNet.Core.HashCode.CombineHashCodes(h, child); } return YamlDotNet.Core.HashCode.CombineHashCodes(h, base.Tag); } internal override IEnumerable SafeAllNodes(RecursionLevel level) { level.Increment(); yield return this; foreach (YamlNode child in children) { foreach (YamlNode item in child.SafeAllNodes(level)) { yield return item; } } level.Decrement(); } internal override string ToString(RecursionLevel level) { if (!level.TryIncrement()) { return "WARNING! INFINITE RECURSION!"; } StringBuilder stringBuilder = new StringBuilder("[ "); foreach (YamlNode child in children) { if (stringBuilder.Length > 2) { stringBuilder.Append(", "); } stringBuilder.Append(child.ToString(level)); } stringBuilder.Append(" ]"); level.Decrement(); return stringBuilder.ToString(); } public IEnumerator GetEnumerator() { return Children.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { Load(parser, new DocumentLoadingState()); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { Emit(emitter, new EmitterState()); } } internal class YamlStream : IEnumerable, IEnumerable { private readonly IList documents = new List(); public IList Documents => documents; public YamlStream() { } public YamlStream(params YamlDocument[] documents) : this((IEnumerable)documents) { } public YamlStream(IEnumerable documents) { foreach (YamlDocument document in documents) { this.documents.Add(document); } } public void Add(YamlDocument document) { documents.Add(document); } public void Load(TextReader input) { Load(new Parser(input)); } public void Load(IParser parser) { documents.Clear(); parser.Consume(); YamlDotNet.Core.Events.StreamEnd @event; while (!parser.TryConsume(out @event)) { YamlDocument item = new YamlDocument(parser); documents.Add(item); } } public void Save(TextWriter output) { Save(output, assignAnchors: true); } public void Save(TextWriter output, bool assignAnchors) { Save(new Emitter(output), assignAnchors); } public void Save(IEmitter emitter, bool assignAnchors) { emitter.Emit(new YamlDotNet.Core.Events.StreamStart()); foreach (YamlDocument document in documents) { document.Save(emitter, assignAnchors); } emitter.Emit(new YamlDotNet.Core.Events.StreamEnd()); } public void Accept(IYamlVisitor visitor) { visitor.Visit(this); } public IEnumerator GetEnumerator() { return documents.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [Obsolete("Use YamlVisitorBase")] internal abstract class YamlVisitor : IYamlVisitor { protected virtual void Visit(YamlStream stream) { } protected virtual void Visited(YamlStream stream) { } protected virtual void Visit(YamlDocument document) { } protected virtual void Visited(YamlDocument document) { } protected virtual void Visit(YamlScalarNode scalar) { } protected virtual void Visited(YamlScalarNode scalar) { } protected virtual void Visit(YamlSequenceNode sequence) { } protected virtual void Visited(YamlSequenceNode sequence) { } protected virtual void Visit(YamlMappingNode mapping) { } protected virtual void Visited(YamlMappingNode mapping) { } protected virtual void VisitChildren(YamlStream stream) { foreach (YamlDocument document in stream.Documents) { document.Accept(this); } } protected virtual void VisitChildren(YamlDocument document) { if (document.RootNode != null) { document.RootNode.Accept(this); } } protected virtual void VisitChildren(YamlSequenceNode sequence) { foreach (YamlNode child in sequence.Children) { child.Accept(this); } } protected virtual void VisitChildren(YamlMappingNode mapping) { foreach (KeyValuePair child in mapping.Children) { child.Key.Accept(this); child.Value.Accept(this); } } void IYamlVisitor.Visit(YamlStream stream) { Visit(stream); VisitChildren(stream); Visited(stream); } void IYamlVisitor.Visit(YamlDocument document) { Visit(document); VisitChildren(document); Visited(document); } void IYamlVisitor.Visit(YamlScalarNode scalar) { Visit(scalar); Visited(scalar); } void IYamlVisitor.Visit(YamlSequenceNode sequence) { Visit(sequence); VisitChildren(sequence); Visited(sequence); } void IYamlVisitor.Visit(YamlMappingNode mapping) { Visit(mapping); VisitChildren(mapping); Visited(mapping); } } internal abstract class YamlVisitorBase : IYamlVisitor { public virtual void Visit(YamlStream stream) { VisitChildren(stream); } public virtual void Visit(YamlDocument document) { VisitChildren(document); } public virtual void Visit(YamlScalarNode scalar) { } public virtual void Visit(YamlSequenceNode sequence) { VisitChildren(sequence); } public virtual void Visit(YamlMappingNode mapping) { VisitChildren(mapping); } protected virtual void VisitPair(YamlNode key, YamlNode value) { key.Accept(this); value.Accept(this); } protected virtual void VisitChildren(YamlStream stream) { foreach (YamlDocument document in stream.Documents) { document.Accept(this); } } protected virtual void VisitChildren(YamlDocument document) { if (document.RootNode != null) { document.RootNode.Accept(this); } } protected virtual void VisitChildren(YamlSequenceNode sequence) { foreach (YamlNode child in sequence.Children) { child.Accept(this); } } protected virtual void VisitChildren(YamlMappingNode mapping) { foreach (KeyValuePair child in mapping.Children) { VisitPair(child.Key, child.Value); } } } } namespace YamlDotNet.Helpers { internal static class ExpressionExtensions { public static PropertyInfo AsProperty(this LambdaExpression propertyAccessor) { PropertyInfo? propertyInfo = TryGetMemberExpression(propertyAccessor); if (propertyInfo == null) { throw new ArgumentException("Expected a lambda expression in the form: x => x.SomeProperty", "propertyAccessor"); } return propertyInfo; } private static TMemberInfo? TryGetMemberExpression(LambdaExpression lambdaExpression) where TMemberInfo : MemberInfo { if (lambdaExpression.Parameters.Count != 1) { return null; } Expression expression = lambdaExpression.Body; if (expression is UnaryExpression unaryExpression) { if (unaryExpression.NodeType != ExpressionType.Convert) { return null; } expression = unaryExpression.Operand; } if (expression is MemberExpression memberExpression) { if (memberExpression.Expression != lambdaExpression.Parameters[0]) { return null; } return memberExpression.Member as TMemberInfo; } return null; } } internal sealed class GenericCollectionToNonGenericAdapter : IList, ICollection, IEnumerable { private readonly ICollection genericCollection; public bool IsFixedSize { get { throw new NotSupportedException(); } } public bool IsReadOnly { get { throw new NotSupportedException(); } } public object? this[int index] { get { throw new NotSupportedException(); } set { ((IList)genericCollection)[index] = (T)value; } } public int Count { get { throw new NotSupportedException(); } } public bool IsSynchronized { get { throw new NotSupportedException(); } } public object SyncRoot { get { throw new NotSupportedException(); } } public GenericCollectionToNonGenericAdapter(ICollection genericCollection) { this.genericCollection = genericCollection ?? throw new ArgumentNullException("genericCollection"); } public int Add(object? value) { int count = genericCollection.Count; genericCollection.Add((T)value); return count; } public void Clear() { genericCollection.Clear(); } public bool Contains(object? value) { throw new NotSupportedException(); } public int IndexOf(object? value) { throw new NotSupportedException(); } public void Insert(int index, object? value) { throw new NotSupportedException(); } public void Remove(object? value) { throw new NotSupportedException(); } public void RemoveAt(int index) { throw new NotSupportedException(); } public void CopyTo(Array array, int index) { throw new NotSupportedException(); } public IEnumerator GetEnumerator() { return genericCollection.GetEnumerator(); } } internal sealed class GenericDictionaryToNonGenericAdapter : IDictionary, ICollection, IEnumerable where TKey : notnull { private class DictionaryEnumerator : IDictionaryEnumerator, IEnumerator { private readonly IEnumerator> enumerator; public DictionaryEntry Entry => new DictionaryEntry(Key, Value); public object Key => enumerator.Current.Key; public object? Value => enumerator.Current.Value; public object Current => Entry; public DictionaryEnumerator(IEnumerator> enumerator) { this.enumerator = enumerator; } public bool MoveNext() { return enumerator.MoveNext(); } public void Reset() { enumerator.Reset(); } } private readonly IDictionary genericDictionary; public bool IsFixedSize { get { throw new NotSupportedException(); } } public bool IsReadOnly { get { throw new NotSupportedException(); } } public ICollection Keys { get { throw new NotSupportedException(); } } public ICollection Values { get { throw new NotSupportedException(); } } public object? this[object key] { get { throw new NotSupportedException(); } set { genericDictionary[(TKey)key] = (TValue)value; } } public int Count { get { throw new NotSupportedException(); } } public bool IsSynchronized { get { throw new NotSupportedException(); } } public object SyncRoot { get { throw new NotSupportedException(); } } public GenericDictionaryToNonGenericAdapter(IDictionary genericDictionary) { this.genericDictionary = genericDictionary ?? throw new ArgumentNullException("genericDictionary"); } public void Add(object key, object? value) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public bool Contains(object key) { throw new NotSupportedException(); } public IDictionaryEnumerator GetEnumerator() { return new DictionaryEnumerator(genericDictionary.GetEnumerator()); } public void Remove(object key) { throw new NotSupportedException(); } public void CopyTo(Array array, int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } internal interface IOrderedDictionary : IDictionary, ICollection>, IEnumerable>, IEnumerable where TKey : notnull { KeyValuePair this[int index] { get; set; } void Insert(int index, TKey key, TValue value); void RemoveAt(int index); } internal static class NumberExtensions { public static bool IsPowerOfTwo(this int value) { return (value & (value - 1)) == 0; } } [Serializable] internal class OrderedDictionary : IOrderedDictionary, IDictionary, ICollection>, IEnumerable>, IEnumerable where TKey : notnull { private class KeyCollection : ICollection, IEnumerable, IEnumerable { private readonly OrderedDictionary orderedDictionary; public int Count => orderedDictionary.list.Count; public bool IsReadOnly => true; public void Add(TKey item) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public bool Contains(TKey item) { return orderedDictionary.dictionary.Keys.Contains(item); } public KeyCollection(OrderedDictionary orderedDictionary) { this.orderedDictionary = orderedDictionary; } public void CopyTo(TKey[] array, int arrayIndex) { for (int i = 0; i < orderedDictionary.list.Count; i++) { array[i] = orderedDictionary.list[i + arrayIndex].Key; } } public IEnumerator GetEnumerator() { return orderedDictionary.list.Select((KeyValuePair kvp) => kvp.Key).GetEnumerator(); } public bool Remove(TKey item) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } private class ValueCollection : ICollection, IEnumerable, IEnumerable { private readonly OrderedDictionary orderedDictionary; public int Count => orderedDictionary.list.Count; public bool IsReadOnly => true; public void Add(TValue item) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public bool Contains(TValue item) { return orderedDictionary.dictionary.Values.Contains(item); } public ValueCollection(OrderedDictionary orderedDictionary) { this.orderedDictionary = orderedDictionary; } public void CopyTo(TValue[] array, int arrayIndex) { for (int i = 0; i < orderedDictionary.list.Count; i++) { array[i] = orderedDictionary.list[i + arrayIndex].Value; } } public IEnumerator GetEnumerator() { return orderedDictionary.list.Select((KeyValuePair kvp) => kvp.Value).GetEnumerator(); } public bool Remove(TValue item) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [NonSerialized] private Dictionary dictionary; private readonly List> list; private readonly IEqualityComparer comparer; public TValue this[TKey key] { get { return dictionary[key]; } set { TKey key2 = key; if (dictionary.ContainsKey(key2)) { int index = list.FindIndex((KeyValuePair kvp) => comparer.Equals(kvp.Key, key2)); dictionary[key2] = value; list[index] = new KeyValuePair(key2, value); } else { Add(key2, value); } } } public ICollection Keys => new KeyCollection(this); public ICollection Values => new ValueCollection(this); public int Count => dictionary.Count; public bool IsReadOnly => false; public KeyValuePair this[int index] { get { return list[index]; } set { list[index] = value; } } public OrderedDictionary() : this((IEqualityComparer)EqualityComparer.Default) { } public OrderedDictionary(IEqualityComparer comparer) { list = new List>(); dictionary = new Dictionary(comparer); this.comparer = comparer; } public void Add(TKey key, TValue value) { Add(new KeyValuePair(key, value)); } public void Add(KeyValuePair item) { dictionary.Add(item.Key, item.Value); list.Add(item); } public void Clear() { dictionary.Clear(); list.Clear(); } public bool Contains(KeyValuePair item) { return dictionary.Contains(item); } public bool ContainsKey(TKey key) { return dictionary.ContainsKey(key); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { list.CopyTo(array, arrayIndex); } public IEnumerator> GetEnumerator() { return list.GetEnumerator(); } public void Insert(int index, TKey key, TValue value) { dictionary.Add(key, value); list.Insert(index, new KeyValuePair(key, value)); } public bool Remove(TKey key) { TKey key2 = key; if (dictionary.ContainsKey(key2)) { int index = list.FindIndex((KeyValuePair kvp) => comparer.Equals(kvp.Key, key2)); list.RemoveAt(index); if (!dictionary.Remove(key2)) { throw new InvalidOperationException(); } return true; } return false; } public bool Remove(KeyValuePair item) { return Remove(item.Key); } public void RemoveAt(int index) { TKey key = list[index].Key; dictionary.Remove(key); list.RemoveAt(index); } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { return dictionary.TryGetValue(key, out value); } IEnumerator IEnumerable.GetEnumerator() { return list.GetEnumerator(); } [OnDeserialized] internal void OnDeserializedMethod(StreamingContext context) { dictionary = new Dictionary(); foreach (KeyValuePair item in list) { dictionary[item.Key] = item.Value; } } } internal static class Lazy { public static Lazy FromValue(T value) { T value2 = value; Lazy lazy = new Lazy(() => value2, isThreadSafe: false); _ = lazy.Value; return lazy; } } internal static class ReadOnlyCollectionExtensions { public static IReadOnlyList AsReadonlyList(this List list) { return list; } public static IReadOnlyDictionary AsReadonlyDictionary(this Dictionary dictionary) where TKey : notnull { return dictionary; } } } namespace YamlDotNet.Core { internal struct AnchorName : IEquatable { public static readonly AnchorName Empty = default(AnchorName); private static readonly Regex AnchorPattern = new Regex("^[^\\[\\]\\{\\},]+$", RegexOptions.Compiled); private readonly string? value; public string Value => value ?? throw new InvalidOperationException("Cannot read the Value of an empty anchor"); public bool IsEmpty => value == null; public AnchorName(string value) { this.value = value ?? throw new ArgumentNullException("value"); if (!AnchorPattern.IsMatch(value)) { throw new ArgumentException("Anchor cannot be empty or contain disallowed characters: []{},\nThe value was '" + value + "'.", "value"); } } public override string ToString() { return value ?? "[empty]"; } public bool Equals(AnchorName other) { return object.Equals(value, other.value); } public override bool Equals(object? obj) { if (obj is AnchorName other) { return Equals(other); } return false; } public override int GetHashCode() { return value?.GetHashCode() ?? 0; } public static bool operator ==(AnchorName left, AnchorName right) { return left.Equals(right); } public static bool operator !=(AnchorName left, AnchorName right) { return !(left == right); } public static implicit operator AnchorName(string? value) { if (value != null) { return new AnchorName(value); } return Empty; } } internal class AnchorNotFoundException : YamlException { public AnchorNotFoundException(string message) : base(message) { } public AnchorNotFoundException(Mark start, Mark end, string message) : base(start, end, message) { } public AnchorNotFoundException(string message, Exception inner) : base(message, inner) { } } internal sealed class CharacterAnalyzer where TBuffer : class, ILookAheadBuffer { public TBuffer Buffer { get; } public bool EndOfInput => Buffer.EndOfInput; public CharacterAnalyzer(TBuffer buffer) { Buffer = buffer ?? throw new ArgumentNullException("buffer"); } public char Peek(int offset) { return Buffer.Peek(offset); } public void Skip(int length) { Buffer.Skip(length); } public bool IsAlphaNumericDashOrUnderscore(int offset = 0) { char c = Buffer.Peek(offset); if ((c < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && c != '_') { return c == '-'; } return true; } public bool IsAscii(int offset = 0) { return Buffer.Peek(offset) <= '\u007f'; } public bool IsPrintable(int offset = 0) { char c = Buffer.Peek(offset); switch (c) { default: if (c != '\u0085' && (c < '\u00a0' || c > '\ud7ff')) { if (c >= '\ue000') { return c <= '\ufffd'; } return false; } break; case '\t': case '\n': case '\r': case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case '`': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '{': case '|': case '}': case '~': break; } return true; } public bool IsDigit(int offset = 0) { char c = Buffer.Peek(offset); if (c >= '0') { return c <= '9'; } return false; } public int AsDigit(int offset = 0) { return Buffer.Peek(offset) - 48; } public bool IsHex(int offset) { char c = Buffer.Peek(offset); if ((c < '0' || c > '9') && (c < 'A' || c > 'F')) { if (c >= 'a') { return c <= 'f'; } return false; } return true; } public int AsHex(int offset) { char c = Buffer.Peek(offset); if (c <= '9') { return c - 48; } if (c <= 'F') { return c - 65 + 10; } return c - 97 + 10; } public bool IsSpace(int offset = 0) { return Check(' ', offset); } public bool IsZero(int offset = 0) { return Check('\0', offset); } public bool IsTab(int offset = 0) { return Check('\t', offset); } public bool IsWhite(int offset = 0) { if (!IsSpace(offset)) { return IsTab(offset); } return true; } public bool IsBreak(int offset = 0) { return Check("\r\n\u0085\u2028\u2029", offset); } public bool IsCrLf(int offset = 0) { if (Check('\r', offset)) { return Check('\n', offset + 1); } return false; } public bool IsBreakOrZero(int offset = 0) { if (!IsBreak(offset)) { return IsZero(offset); } return true; } public bool IsWhiteBreakOrZero(int offset = 0) { if (!IsWhite(offset)) { return IsBreakOrZero(offset); } return true; } public bool Check(char expected, int offset = 0) { return Buffer.Peek(offset) == expected; } public bool Check(string expectedCharacters, int offset = 0) { char value = Buffer.Peek(offset); return expectedCharacters.IndexOf(value) != -1; } } internal static class Constants { public static readonly TagDirective[] DefaultTagDirectives = new TagDirective[2] { new TagDirective("!", "!"), new TagDirective("!!", "tag:yaml.org,2002:") }; public const int MajorVersion = 1; public const int MinorVersion = 3; } internal sealed class Cursor { public int Index { get; private set; } public int Line { get; private set; } public int LineOffset { get; private set; } public Cursor() { Line = 1; } public Cursor(Cursor cursor) { Index = cursor.Index; Line = cursor.Line; LineOffset = cursor.LineOffset; } public Mark Mark() { return new Mark(Index, Line, LineOffset + 1); } public void Skip() { Index++; LineOffset++; } public void SkipLineByOffset(int offset) { Index += offset; Line++; LineOffset = 0; } public void ForceSkipLineAfterNonBreak() { if (LineOffset != 0) { Line++; LineOffset = 0; } } } internal class Emitter : IEmitter { private class AnchorData { public AnchorName Anchor; public bool IsAlias; } private class TagData { public string? Handle; public string? Suffix; } private class ScalarData { public string Value = string.Empty; public bool IsMultiline; public bool IsFlowPlainAllowed; public bool IsBlockPlainAllowed; public bool IsSingleQuotedAllowed; public bool IsBlockAllowed; public bool HasSingleQuotes; public ScalarStyle Style; } private static readonly Regex UriReplacer = new Regex("[^0-9A-Za-z_\\-;?@=$~\\\\\\)\\]/:&+,\\.\\*\\(\\[!]", RegexOptions.Compiled | RegexOptions.Singleline); private readonly TextWriter output; private readonly bool outputUsesUnicodeEncoding; private readonly int maxSimpleKeyLength; private readonly bool isCanonical; private readonly bool skipAnchorName; private readonly int bestIndent; private readonly int bestWidth; private EmitterState state; private readonly Stack states = new Stack(); private readonly Queue events = new Queue(); private readonly Stack indents = new Stack(); private readonly TagDirectiveCollection tagDirectives = new TagDirectiveCollection(); private int indent; private int flowLevel; private bool isMappingContext; private bool isSimpleKeyContext; private int column; private bool isWhitespace; private bool isIndentation; private readonly bool forceIndentLess; private bool isDocumentEndWritten; private readonly AnchorData anchorData = new AnchorData(); private readonly TagData tagData = new TagData(); private readonly ScalarData scalarData = new ScalarData(); public Emitter(TextWriter output) : this(output, EmitterSettings.Default) { } public Emitter(TextWriter output, int bestIndent) : this(output, bestIndent, int.MaxValue) { } public Emitter(TextWriter output, int bestIndent, int bestWidth) : this(output, bestIndent, bestWidth, isCanonical: false) { } public Emitter(TextWriter output, int bestIndent, int bestWidth, bool isCanonical) : this(output, new EmitterSettings(bestIndent, bestWidth, isCanonical, 1024)) { } public Emitter(TextWriter output, EmitterSettings settings) { bestIndent = settings.BestIndent; bestWidth = settings.BestWidth; isCanonical = settings.IsCanonical; maxSimpleKeyLength = settings.MaxSimpleKeyLength; skipAnchorName = settings.SkipAnchorName; forceIndentLess = !settings.IndentSequences; this.output = output; outputUsesUnicodeEncoding = IsUnicode(output.Encoding); } public void Emit(ParsingEvent @event) { events.Enqueue(@event); while (!NeedMoreEvents()) { ParsingEvent evt = events.Peek(); try { AnalyzeEvent(evt); StateMachine(evt); } finally { events.Dequeue(); } } } private bool NeedMoreEvents() { if (events.Count == 0) { return true; } int num; switch (events.Peek().Type) { case EventType.DocumentStart: num = 1; break; case EventType.SequenceStart: num = 2; break; case EventType.MappingStart: num = 3; break; default: return false; } if (events.Count > num) { return false; } int num2 = 0; using (Queue.Enumerator enumerator = events.GetEnumerator()) { while (enumerator.MoveNext()) { switch (enumerator.Current.Type) { case EventType.DocumentStart: case EventType.SequenceStart: case EventType.MappingStart: num2++; break; case EventType.DocumentEnd: case EventType.SequenceEnd: case EventType.MappingEnd: num2--; break; } if (num2 == 0) { return false; } } } return true; } private void AnalyzeEvent(ParsingEvent evt) { anchorData.Anchor = AnchorName.Empty; tagData.Handle = null; tagData.Suffix = null; if (evt is YamlDotNet.Core.Events.AnchorAlias anchorAlias) { AnalyzeAnchor(anchorAlias.Value, isAlias: true); } else if (evt is NodeEvent nodeEvent) { if (evt is YamlDotNet.Core.Events.Scalar scalar) { AnalyzeScalar(scalar); } AnalyzeAnchor(nodeEvent.Anchor, isAlias: false); if (!nodeEvent.Tag.IsEmpty && (isCanonical || nodeEvent.IsCanonical)) { AnalyzeTag(nodeEvent.Tag); } } } private void AnalyzeAnchor(AnchorName anchor, bool isAlias) { anchorData.Anchor = anchor; anchorData.IsAlias = isAlias; } private void AnalyzeScalar(YamlDotNet.Core.Events.Scalar scalar) { string value = scalar.Value; scalarData.Value = value; if (value.Length == 0) { if (scalar.Tag == "tag:yaml.org,2002:null") { scalarData.IsMultiline = false; scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = true; scalarData.IsSingleQuotedAllowed = false; scalarData.IsBlockAllowed = false; } else { scalarData.IsMultiline = false; scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; scalarData.IsSingleQuotedAllowed = true; scalarData.IsBlockAllowed = false; } return; } bool flag = false; bool flag2 = false; if (value.StartsWith("---", StringComparison.Ordinal) || value.StartsWith("...", StringComparison.Ordinal)) { flag = true; flag2 = true; } CharacterAnalyzer characterAnalyzer = new CharacterAnalyzer(new StringLookAheadBuffer(value)); bool flag3 = true; bool flag4 = characterAnalyzer.IsWhiteBreakOrZero(1); bool flag5 = false; bool flag6 = false; bool flag7 = false; bool flag8 = false; bool flag9 = false; bool flag10 = false; bool flag11 = false; bool flag12 = false; bool flag13 = false; bool flag14 = false; bool flag15 = false; bool flag16 = !ValueIsRepresentableInOutputEncoding(value); bool flag17 = false; bool flag18 = false; bool flag19 = true; while (!characterAnalyzer.EndOfInput) { if (flag19) { if (characterAnalyzer.Check("#,[]{}&*!|>\\\"%@`'")) { flag = true; flag2 = true; flag9 = characterAnalyzer.Check('\''); flag17 |= characterAnalyzer.Check('\''); } if (characterAnalyzer.Check("?:")) { flag = true; if (flag4) { flag2 = true; } } if (characterAnalyzer.Check('-') && flag4) { flag = true; flag2 = true; } } else { if (characterAnalyzer.Check(",?[]{}")) { flag = true; } if (characterAnalyzer.Check(':')) { flag = true; if (flag4) { flag2 = true; } } if (characterAnalyzer.Check('#') && flag3) { flag = true; flag2 = true; } flag17 |= characterAnalyzer.Check('\''); } if (!flag16 && !characterAnalyzer.IsPrintable()) { flag16 = true; } if (characterAnalyzer.IsBreak()) { flag15 = true; } if (characterAnalyzer.IsSpace()) { if (flag19) { flag5 = true; } if (characterAnalyzer.Buffer.Position >= characterAnalyzer.Buffer.Length - 1) { flag7 = true; } if (flag13) { flag10 = true; flag14 = true; } flag12 = true; flag13 = false; } else if (characterAnalyzer.IsBreak()) { if (flag19) { flag6 = true; } if (characterAnalyzer.Buffer.Position >= characterAnalyzer.Buffer.Length - 1) { flag8 = true; } if (flag12) { flag11 = true; } if (flag14) { flag18 = true; } flag12 = false; flag13 = true; } else { flag12 = false; flag13 = false; flag14 = false; } flag3 = characterAnalyzer.IsWhiteBreakOrZero(); characterAnalyzer.Skip(1); if (!characterAnalyzer.EndOfInput) { flag4 = characterAnalyzer.IsWhiteBreakOrZero(1); } flag19 = false; } scalarData.IsFlowPlainAllowed = true; scalarData.IsBlockPlainAllowed = true; scalarData.IsSingleQuotedAllowed = true; scalarData.IsBlockAllowed = true; if (flag5 || flag6 || flag7 || flag8 || flag9) { scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; } if (flag7) { scalarData.IsBlockAllowed = false; } if (flag10) { scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; scalarData.IsSingleQuotedAllowed = false; } if (flag11 || flag16) { scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; scalarData.IsSingleQuotedAllowed = false; } if (flag18) { scalarData.IsBlockAllowed = false; } scalarData.IsMultiline = flag15; if (flag15) { scalarData.IsFlowPlainAllowed = false; scalarData.IsBlockPlainAllowed = false; } if (flag) { scalarData.IsFlowPlainAllowed = false; } if (flag2) { scalarData.IsBlockPlainAllowed = false; } scalarData.HasSingleQuotes = flag17; } private bool ValueIsRepresentableInOutputEncoding(string value) { if (outputUsesUnicodeEncoding) { return true; } try { byte[] bytes = output.Encoding.GetBytes(value); return output.Encoding.GetString(bytes, 0, bytes.Length).Equals(value); } catch (EncoderFallbackException) { return false; } catch (ArgumentOutOfRangeException) { return false; } } private bool IsUnicode(Encoding encoding) { if (!(encoding is UTF8Encoding) && !(encoding is UnicodeEncoding)) { return encoding is UTF7Encoding; } return true; } private void AnalyzeTag(TagName tag) { tagData.Handle = tag.Value; foreach (TagDirective tagDirective in tagDirectives) { if (tag.Value.StartsWith(tagDirective.Prefix, StringComparison.Ordinal)) { tagData.Handle = tagDirective.Handle; tagData.Suffix = tag.Value.Substring(tagDirective.Prefix.Length); break; } } } private void StateMachine(ParsingEvent evt) { if (evt is YamlDotNet.Core.Events.Comment comment) { EmitComment(comment); return; } switch (state) { case EmitterState.StreamStart: EmitStreamStart(evt); break; case EmitterState.FirstDocumentStart: EmitDocumentStart(evt, isFirst: true); break; case EmitterState.DocumentStart: EmitDocumentStart(evt, isFirst: false); break; case EmitterState.DocumentContent: EmitDocumentContent(evt); break; case EmitterState.DocumentEnd: EmitDocumentEnd(evt); break; case EmitterState.FlowSequenceFirstItem: EmitFlowSequenceItem(evt, isFirst: true); break; case EmitterState.FlowSequenceItem: EmitFlowSequenceItem(evt, isFirst: false); break; case EmitterState.FlowMappingFirstKey: EmitFlowMappingKey(evt, isFirst: true); break; case EmitterState.FlowMappingKey: EmitFlowMappingKey(evt, isFirst: false); break; case EmitterState.FlowMappingSimpleValue: EmitFlowMappingValue(evt, isSimple: true); break; case EmitterState.FlowMappingValue: EmitFlowMappingValue(evt, isSimple: false); break; case EmitterState.BlockSequenceFirstItem: EmitBlockSequenceItem(evt, isFirst: true); break; case EmitterState.BlockSequenceItem: EmitBlockSequenceItem(evt, isFirst: false); break; case EmitterState.BlockMappingFirstKey: EmitBlockMappingKey(evt, isFirst: true); break; case EmitterState.BlockMappingKey: EmitBlockMappingKey(evt, isFirst: false); break; case EmitterState.BlockMappingSimpleValue: EmitBlockMappingValue(evt, isSimple: true); break; case EmitterState.BlockMappingValue: EmitBlockMappingValue(evt, isSimple: false); break; case EmitterState.StreamEnd: throw new YamlException("Expected nothing after STREAM-END"); default: throw new InvalidOperationException(); } } private void EmitComment(YamlDotNet.Core.Events.Comment comment) { if (comment.IsInline) { Write(' '); } else { WriteIndent(); } Write("# "); Write(comment.Value); WriteBreak(); isIndentation = true; } private void EmitStreamStart(ParsingEvent evt) { if (!(evt is YamlDotNet.Core.Events.StreamStart)) { throw new ArgumentException("Expected STREAM-START.", "evt"); } indent = -1; column = 0; isWhitespace = true; isIndentation = true; state = EmitterState.FirstDocumentStart; } private void EmitDocumentStart(ParsingEvent evt, bool isFirst) { if (evt is YamlDotNet.Core.Events.DocumentStart documentStart) { bool flag = documentStart.IsImplicit && isFirst && !isCanonical; TagDirectiveCollection tagDirectiveCollection = NonDefaultTagsAmong(documentStart.Tags); if (!isFirst && !isDocumentEndWritten && (documentStart.Version != null || tagDirectiveCollection.Count > 0)) { isDocumentEndWritten = false; WriteIndicator("...", needWhitespace: true, whitespace: false, indentation: false); WriteIndent(); } if (documentStart.Version != null) { AnalyzeVersionDirective(documentStart.Version); Version version = documentStart.Version.Version; flag = false; WriteIndicator("%YAML", needWhitespace: true, whitespace: false, indentation: false); WriteIndicator(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[2] { version.Major, version.Minor }), needWhitespace: true, whitespace: false, indentation: false); WriteIndent(); } foreach (TagDirective item in tagDirectiveCollection) { AppendTagDirectiveTo(item, allowDuplicates: false, tagDirectives); } TagDirective[] defaultTagDirectives = Constants.DefaultTagDirectives; for (int i = 0; i < defaultTagDirectives.Length; i++) { AppendTagDirectiveTo(defaultTagDirectives[i], allowDuplicates: true, tagDirectives); } if (tagDirectiveCollection.Count > 0) { flag = false; defaultTagDirectives = Constants.DefaultTagDirectives; for (int i = 0; i < defaultTagDirectives.Length; i++) { AppendTagDirectiveTo(defaultTagDirectives[i], allowDuplicates: true, tagDirectiveCollection); } foreach (TagDirective item2 in tagDirectiveCollection) { WriteIndicator("%TAG", needWhitespace: true, whitespace: false, indentation: false); WriteTagHandle(item2.Handle); WriteTagContent(item2.Prefix, needsWhitespace: true); WriteIndent(); } } if (CheckEmptyDocument()) { flag = false; } if (!flag) { WriteIndent(); WriteIndicator("---", needWhitespace: true, whitespace: false, indentation: false); if (isCanonical) { WriteIndent(); } } state = EmitterState.DocumentContent; } else { if (!(evt is YamlDotNet.Core.Events.StreamEnd)) { throw new YamlException("Expected DOCUMENT-START or STREAM-END"); } state = EmitterState.StreamEnd; } } private TagDirectiveCollection NonDefaultTagsAmong(IEnumerable? tagCollection) { TagDirectiveCollection tagDirectiveCollection = new TagDirectiveCollection(); if (tagCollection == null) { return tagDirectiveCollection; } foreach (TagDirective item2 in tagCollection) { AppendTagDirectiveTo(item2, allowDuplicates: false, tagDirectiveCollection); } TagDirective[] defaultTagDirectives = Constants.DefaultTagDirectives; foreach (TagDirective item in defaultTagDirectives) { tagDirectiveCollection.Remove(item); } return tagDirectiveCollection; } private void AnalyzeVersionDirective(VersionDirective versionDirective) { if (versionDirective.Version.Major != 1 || versionDirective.Version.Minor > 3) { throw new YamlException("Incompatible %YAML directive"); } } private static void AppendTagDirectiveTo(TagDirective value, bool allowDuplicates, TagDirectiveCollection tagDirectives) { if (tagDirectives.Contains(value)) { if (!allowDuplicates) { throw new YamlException("Duplicate %TAG directive."); } } else { tagDirectives.Add(value); } } private void EmitDocumentContent(ParsingEvent evt) { states.Push(EmitterState.DocumentEnd); EmitNode(evt, isMapping: false, isSimpleKey: false); } private void EmitNode(ParsingEvent evt, bool isMapping, bool isSimpleKey) { isMappingContext = isMapping; isSimpleKeyContext = isSimpleKey; switch (evt.Type) { case EventType.Alias: EmitAlias(); break; case EventType.Scalar: EmitScalar(evt); break; case EventType.SequenceStart: EmitSequenceStart(evt); break; case EventType.MappingStart: EmitMappingStart(evt); break; default: throw new YamlException($"Expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, got {evt.Type}"); } } private void EmitAlias() { ProcessAnchor(); state = states.Pop(); } private void EmitScalar(ParsingEvent evt) { SelectScalarStyle(evt); ProcessAnchor(); ProcessTag(); IncreaseIndent(isFlow: true, isIndentless: false); ProcessScalar(); indent = indents.Pop(); state = states.Pop(); } private void SelectScalarStyle(ParsingEvent evt) { YamlDotNet.Core.Events.Scalar scalar = (YamlDotNet.Core.Events.Scalar)evt; ScalarStyle scalarStyle = scalar.Style; bool flag = tagData.Handle == null && tagData.Suffix == null; if (flag && !scalar.IsPlainImplicit && !scalar.IsQuotedImplicit) { throw new YamlException("Neither tag nor isImplicit flags are specified."); } if (scalarStyle == ScalarStyle.Any) { scalarStyle = ((!scalarData.IsMultiline) ? ScalarStyle.Plain : ScalarStyle.Folded); } if (isCanonical) { scalarStyle = ScalarStyle.DoubleQuoted; } if (isSimpleKeyContext && scalarData.IsMultiline) { scalarStyle = ScalarStyle.DoubleQuoted; } if (scalarStyle == ScalarStyle.Plain) { if ((flowLevel != 0 && !scalarData.IsFlowPlainAllowed) || (flowLevel == 0 && !scalarData.IsBlockPlainAllowed)) { scalarStyle = ((scalarData.IsSingleQuotedAllowed && !scalarData.HasSingleQuotes) ? ScalarStyle.SingleQuoted : ScalarStyle.DoubleQuoted); } if (string.IsNullOrEmpty(scalarData.Value) && (flowLevel != 0 || isSimpleKeyContext)) { scalarStyle = ScalarStyle.SingleQuoted; } if (flag && !scalar.IsPlainImplicit) { scalarStyle = ScalarStyle.SingleQuoted; } } if (scalarStyle == ScalarStyle.SingleQuoted && !scalarData.IsSingleQuotedAllowed) { scalarStyle = ScalarStyle.DoubleQuoted; } if ((scalarStyle == ScalarStyle.Literal || scalarStyle == ScalarStyle.Folded) && (!scalarData.IsBlockAllowed || flowLevel != 0 || isSimpleKeyContext)) { scalarStyle = ScalarStyle.DoubleQuoted; } scalarData.Style = scalarStyle; } private void ProcessScalar() { switch (scalarData.Style) { case ScalarStyle.Plain: WritePlainScalar(scalarData.Value, !isSimpleKeyContext); break; case ScalarStyle.SingleQuoted: WriteSingleQuotedScalar(scalarData.Value, !isSimpleKeyContext); break; case ScalarStyle.DoubleQuoted: WriteDoubleQuotedScalar(scalarData.Value, !isSimpleKeyContext); break; case ScalarStyle.Literal: WriteLiteralScalar(scalarData.Value); break; case ScalarStyle.Folded: WriteFoldedScalar(scalarData.Value); break; default: throw new InvalidOperationException(); } } private void WritePlainScalar(string value, bool allowBreaks) { if (!isWhitespace) { Write(' '); } bool flag = false; bool flag2 = false; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (IsSpace(c)) { if (allowBreaks && !flag && column > bestWidth && i + 1 < value.Length && value[i + 1] != ' ') { WriteIndent(); } else { Write(c); } flag = true; continue; } if (IsBreak(c, out var breakChar)) { if (!flag2 && c == '\n') { WriteBreak(); } WriteBreak(breakChar); isIndentation = true; flag2 = true; continue; } if (flag2) { WriteIndent(); } Write(c); isIndentation = false; flag = false; flag2 = false; } isWhitespace = false; isIndentation = false; } private void WriteSingleQuotedScalar(string value, bool allowBreaks) { WriteIndicator("'", needWhitespace: true, whitespace: false, indentation: false); bool flag = false; bool flag2 = false; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (c == ' ') { if (allowBreaks && !flag && column > bestWidth && i != 0 && i + 1 < value.Length && value[i + 1] != ' ') { WriteIndent(); } else { Write(c); } flag = true; continue; } if (IsBreak(c, out var breakChar)) { if (!flag2 && c == '\n') { WriteBreak(); } WriteBreak(breakChar); isIndentation = true; flag2 = true; continue; } if (flag2) { WriteIndent(); } if (c == '\'') { Write(c); } Write(c); isIndentation = false; flag = false; flag2 = false; } WriteIndicator("'", needWhitespace: false, whitespace: false, indentation: false); isWhitespace = false; isIndentation = false; } private void WriteDoubleQuotedScalar(string value, bool allowBreaks) { WriteIndicator("\"", needWhitespace: true, whitespace: false, indentation: false); bool flag = false; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (IsPrintable(c) && !IsBreak(c, out var _)) { switch (c) { case '"': case '\\': break; case ' ': if (allowBreaks && !flag && column > bestWidth && i > 0 && i + 1 < value.Length) { WriteIndent(); if (value[i + 1] == ' ') { Write('\\'); } } else { Write(c); } flag = true; continue; default: Write(c); flag = false; continue; } } Write('\\'); switch (c) { case '\0': Write('0'); break; case '\a': Write('a'); break; case '\b': Write('b'); break; case '\t': Write('t'); break; case '\n': Write('n'); break; case '\v': Write('v'); break; case '\f': Write('f'); break; case '\r': Write('r'); break; case '\u001b': Write('e'); break; case '"': Write('"'); break; case '\\': Write('\\'); break; case '\u0085': Write('N'); break; case '\u00a0': Write('_'); break; case '\u2028': Write('L'); break; case '\u2029': Write('P'); break; default: { ushort num = c; if (num <= 255) { Write('x'); Write(num.ToString("X02", CultureInfo.InvariantCulture)); } else if (IsHighSurrogate(c)) { if (i + 1 >= value.Length || !IsLowSurrogate(value[i + 1])) { throw new SyntaxErrorException("While writing a quoted scalar, found an orphaned high surrogate."); } Write('U'); Write(char.ConvertToUtf32(c, value[i + 1]).ToString("X08", CultureInfo.InvariantCulture)); i++; } else { Write('u'); Write(num.ToString("X04", CultureInfo.InvariantCulture)); } break; } } flag = false; } WriteIndicator("\"", needWhitespace: false, whitespace: false, indentation: false); isWhitespace = false; isIndentation = false; } private void WriteLiteralScalar(string value) { bool flag = true; WriteIndicator("|", needWhitespace: true, whitespace: false, indentation: false); WriteBlockScalarHints(value); WriteBreak(); isIndentation = true; isWhitespace = true; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (c == '\r' && i + 1 < value.Length && value[i + 1] == '\n') { continue; } if (IsBreak(c, out var breakChar)) { WriteBreak(breakChar); isIndentation = true; flag = true; continue; } if (flag) { WriteIndent(); } Write(c); isIndentation = false; flag = false; } } private void WriteFoldedScalar(string value) { bool flag = true; bool flag2 = true; WriteIndicator(">", needWhitespace: true, whitespace: false, indentation: false); WriteBlockScalarHints(value); WriteBreak(); isIndentation = true; isWhitespace = true; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (IsBreak(c, out var breakChar)) { if (!flag && !flag2 && c == '\n') { int j; char breakChar2; for (j = 0; i + j < value.Length && IsBreak(value[i + j], out breakChar2); j++) { } if (i + j < value.Length && !IsBlank(value[i + j]) && !IsBreak(value[i + j], out breakChar2)) { WriteBreak(); } } WriteBreak(breakChar); isIndentation = true; flag = true; } else { if (flag) { WriteIndent(); flag2 = IsBlank(c); } if (!flag && c == ' ' && i + 1 < value.Length && value[i + 1] != ' ' && column > bestWidth) { WriteIndent(); } else { Write(c); } isIndentation = false; flag = false; } } } private static bool IsSpace(char character) { return character == ' '; } private static bool IsBreak(char character, out char breakChar) { switch (character) { case '\n': case '\r': case '\u0085': breakChar = '\n'; return true; case '\u2028': case '\u2029': breakChar = character; return true; default: breakChar = '\0'; return false; } } private static bool IsBlank(char character) { if (character != ' ') { return character == '\t'; } return true; } private static bool IsPrintable(char character) { switch (character) { default: if (character != '\u0085' && (character < '\u00a0' || character > '\ud7ff')) { if (character >= '\ue000') { return character <= '\ufffd'; } return false; } break; case '\t': case '\n': case '\r': case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case '\\': case ']': case '^': case '_': case '`': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '{': case '|': case '}': case '~': break; } return true; } private static bool IsHighSurrogate(char c) { if ('\ud800' <= c) { return c <= '\udbff'; } return false; } private static bool IsLowSurrogate(char c) { if ('\udc00' <= c) { return c <= '\udfff'; } return false; } private void EmitSequenceStart(ParsingEvent evt) { ProcessAnchor(); ProcessTag(); SequenceStart sequenceStart = (SequenceStart)evt; if (flowLevel != 0 || isCanonical || sequenceStart.Style == SequenceStyle.Flow || CheckEmptySequence()) { state = EmitterState.FlowSequenceFirstItem; } else { state = EmitterState.BlockSequenceFirstItem; } } private void EmitMappingStart(ParsingEvent evt) { ProcessAnchor(); ProcessTag(); MappingStart mappingStart = (MappingStart)evt; if (flowLevel != 0 || isCanonical || mappingStart.Style == MappingStyle.Flow || CheckEmptyMapping()) { state = EmitterState.FlowMappingFirstKey; } else { state = EmitterState.BlockMappingFirstKey; } } private void ProcessAnchor() { if (!anchorData.Anchor.IsEmpty && !skipAnchorName) { WriteIndicator(anchorData.IsAlias ? "*" : "&", needWhitespace: true, whitespace: false, indentation: false); WriteAnchor(anchorData.Anchor); } } private void ProcessTag() { if (tagData.Handle == null && tagData.Suffix == null) { return; } if (tagData.Handle != null) { WriteTagHandle(tagData.Handle); if (tagData.Suffix != null) { WriteTagContent(tagData.Suffix, needsWhitespace: false); } } else { WriteIndicator("!<", needWhitespace: true, whitespace: false, indentation: false); WriteTagContent(tagData.Suffix, needsWhitespace: false); WriteIndicator(">", needWhitespace: false, whitespace: false, indentation: false); } } private void EmitDocumentEnd(ParsingEvent evt) { if (evt is YamlDotNet.Core.Events.DocumentEnd documentEnd) { WriteIndent(); if (!documentEnd.IsImplicit) { WriteIndicator("...", needWhitespace: true, whitespace: false, indentation: false); WriteIndent(); isDocumentEndWritten = true; } state = EmitterState.DocumentStart; tagDirectives.Clear(); return; } throw new YamlException("Expected DOCUMENT-END."); } private void EmitFlowSequenceItem(ParsingEvent evt, bool isFirst) { if (isFirst) { WriteIndicator("[", needWhitespace: true, whitespace: true, indentation: false); IncreaseIndent(isFlow: true, isIndentless: false); flowLevel++; } if (evt is SequenceEnd) { flowLevel--; indent = indents.Pop(); if (isCanonical && !isFirst) { WriteIndicator(",", needWhitespace: false, whitespace: false, indentation: false); WriteIndent(); } WriteIndicator("]", needWhitespace: false, whitespace: false, indentation: false); state = states.Pop(); } else { if (!isFirst) { WriteIndicator(",", needWhitespace: false, whitespace: false, indentation: false); } if (isCanonical || column > bestWidth) { WriteIndent(); } states.Push(EmitterState.FlowSequenceItem); EmitNode(evt, isMapping: false, isSimpleKey: false); } } private void EmitFlowMappingKey(ParsingEvent evt, bool isFirst) { if (isFirst) { WriteIndicator("{", needWhitespace: true, whitespace: true, indentation: false); IncreaseIndent(isFlow: true, isIndentless: false); flowLevel++; } if (evt is MappingEnd) { flowLevel--; indent = indents.Pop(); if (isCanonical && !isFirst) { WriteIndicator(",", needWhitespace: false, whitespace: false, indentation: false); WriteIndent(); } WriteIndicator("}", needWhitespace: false, whitespace: false, indentation: false); state = states.Pop(); return; } if (!isFirst) { WriteIndicator(",", needWhitespace: false, whitespace: false, indentation: false); } if (isCanonical || column > bestWidth) { WriteIndent(); } if (!isCanonical && CheckSimpleKey()) { states.Push(EmitterState.FlowMappingSimpleValue); EmitNode(evt, isMapping: true, isSimpleKey: true); } else { WriteIndicator("?", needWhitespace: true, whitespace: false, indentation: false); states.Push(EmitterState.FlowMappingValue); EmitNode(evt, isMapping: true, isSimpleKey: false); } } private void EmitFlowMappingValue(ParsingEvent evt, bool isSimple) { if (isSimple) { WriteIndicator(":", needWhitespace: false, whitespace: false, indentation: false); } else { if (isCanonical || column > bestWidth) { WriteIndent(); } WriteIndicator(":", needWhitespace: true, whitespace: false, indentation: false); } states.Push(EmitterState.FlowMappingKey); EmitNode(evt, isMapping: true, isSimpleKey: false); } private void EmitBlockSequenceItem(ParsingEvent evt, bool isFirst) { if (isFirst) { IncreaseIndent(isFlow: false, isMappingContext && !isIndentation); } if (evt is SequenceEnd) { indent = indents.Pop(); state = states.Pop(); return; } WriteIndent(); WriteIndicator("-", needWhitespace: true, whitespace: false, indentation: true); states.Push(EmitterState.BlockSequenceItem); EmitNode(evt, isMapping: false, isSimpleKey: false); } private void EmitBlockMappingKey(ParsingEvent evt, bool isFirst) { if (isFirst) { IncreaseIndent(isFlow: false, isIndentless: false); } if (evt is MappingEnd) { indent = indents.Pop(); state = states.Pop(); return; } WriteIndent(); if (CheckSimpleKey()) { states.Push(EmitterState.BlockMappingSimpleValue); EmitNode(evt, isMapping: true, isSimpleKey: true); } else { WriteIndicator("?", needWhitespace: true, whitespace: false, indentation: true); states.Push(EmitterState.BlockMappingValue); EmitNode(evt, isMapping: true, isSimpleKey: false); } } private void EmitBlockMappingValue(ParsingEvent evt, bool isSimple) { if (isSimple) { WriteIndicator(":", needWhitespace: false, whitespace: false, indentation: false); } else { WriteIndent(); WriteIndicator(":", needWhitespace: true, whitespace: false, indentation: true); } states.Push(EmitterState.BlockMappingKey); EmitNode(evt, isMapping: true, isSimpleKey: false); } private void IncreaseIndent(bool isFlow, bool isIndentless) { indents.Push(indent); if (indent < 0) { indent = (isFlow ? bestIndent : 0); } else if (!isIndentless || !forceIndentLess) { indent += bestIndent; } } private bool CheckEmptyDocument() { int num = 0; foreach (ParsingEvent @event in events) { num++; if (num == 2) { if (@event is YamlDotNet.Core.Events.Scalar scalar) { return string.IsNullOrEmpty(scalar.Value); } break; } } return false; } private bool CheckSimpleKey() { if (events.Count < 1) { return false; } int num; switch (events.Peek().Type) { case EventType.Alias: num = AnchorNameLength(anchorData.Anchor); break; case EventType.Scalar: if (scalarData.IsMultiline) { return false; } num = AnchorNameLength(anchorData.Anchor) + SafeStringLength(tagData.Handle) + SafeStringLength(tagData.Suffix) + SafeStringLength(scalarData.Value); break; case EventType.SequenceStart: if (!CheckEmptySequence()) { return false; } num = AnchorNameLength(anchorData.Anchor) + SafeStringLength(tagData.Handle) + SafeStringLength(tagData.Suffix); break; case EventType.MappingStart: if (!CheckEmptySequence()) { return false; } num = AnchorNameLength(anchorData.Anchor) + SafeStringLength(tagData.Handle) + SafeStringLength(tagData.Suffix); break; default: return false; } return num <= maxSimpleKeyLength; } private int AnchorNameLength(AnchorName value) { if (!value.IsEmpty) { return value.Value.Length; } return 0; } private int SafeStringLength(string? value) { return value?.Length ?? 0; } private bool CheckEmptySequence() { return CheckEmptyStructure(); } private bool CheckEmptyMapping() { return CheckEmptyStructure(); } private bool CheckEmptyStructure() where TStart : NodeEvent where TEnd : ParsingEvent { if (events.Count < 2) { return false; } using Queue.Enumerator enumerator = events.GetEnumerator(); return enumerator.MoveNext() && enumerator.Current is TStart && enumerator.MoveNext() && enumerator.Current is TEnd; } private void WriteBlockScalarHints(string value) { CharacterAnalyzer characterAnalyzer = new CharacterAnalyzer(new StringLookAheadBuffer(value)); if (characterAnalyzer.IsSpace() || characterAnalyzer.IsBreak()) { int num = bestIndent; string indicator = num.ToString(CultureInfo.InvariantCulture); WriteIndicator(indicator, needWhitespace: false, whitespace: false, indentation: false); } string text = null; if (value.Length == 0 || !characterAnalyzer.IsBreak(value.Length - 1)) { text = "-"; } else if (value.Length >= 2 && characterAnalyzer.IsBreak(value.Length - 2)) { text = "+"; } if (text != null) { WriteIndicator(text, needWhitespace: false, whitespace: false, indentation: false); } } private void WriteIndicator(string indicator, bool needWhitespace, bool whitespace, bool indentation) { if (needWhitespace && !isWhitespace) { Write(' '); } Write(indicator); isWhitespace = whitespace; isIndentation &= indentation; } private void WriteIndent() { int num = Math.Max(indent, 0); if (!isIndentation || column > num || (column == num && !isWhitespace)) { WriteBreak(); } while (column < num) { Write(' '); } isWhitespace = true; isIndentation = true; } private void WriteAnchor(AnchorName value) { Write(value.Value); isWhitespace = false; isIndentation = false; } private void WriteTagHandle(string value) { if (!isWhitespace) { Write(' '); } Write(value); isWhitespace = false; isIndentation = false; } private void WriteTagContent(string value, bool needsWhitespace) { if (needsWhitespace && !isWhitespace) { Write(' '); } Write(UrlEncode(value)); isWhitespace = false; isIndentation = false; } private string UrlEncode(string text) { return UriReplacer.Replace(text, delegate(Match match) { StringBuilder stringBuilder = new StringBuilder(); byte[] bytes = Encoding.UTF8.GetBytes(match.Value); foreach (byte b in bytes) { stringBuilder.AppendFormat("%{0:X02}", b); } return stringBuilder.ToString(); }); } private void Write(char value) { output.Write(value); column++; } private void Write(string value) { output.Write(value); column += value.Length; } private void WriteBreak(char breakCharacter = '\n') { if (breakCharacter == '\n') { output.WriteLine(); } else { output.Write(breakCharacter); } column = 0; } } internal sealed class EmitterSettings { public static readonly EmitterSettings Default = new EmitterSettings(); public int BestIndent { get; } = 2; public int BestWidth { get; } = int.MaxValue; public bool IsCanonical { get; } public bool SkipAnchorName { get; private set; } public int MaxSimpleKeyLength { get; } = 1024; public bool IndentSequences { get; } public EmitterSettings() { } public EmitterSettings(int bestIndent, int bestWidth, bool isCanonical, int maxSimpleKeyLength, bool skipAnchorName = false, bool indentSequences = false) { if (bestIndent < 2 || bestIndent > 9) { throw new ArgumentOutOfRangeException("bestIndent", "BestIndent must be between 2 and 9, inclusive"); } if (bestWidth <= bestIndent * 2) { throw new ArgumentOutOfRangeException("bestWidth", "BestWidth must be greater than BestIndent x 2."); } if (maxSimpleKeyLength < 0) { throw new ArgumentOutOfRangeException("maxSimpleKeyLength", "MaxSimpleKeyLength must be >= 0"); } BestIndent = bestIndent; BestWidth = bestWidth; IsCanonical = isCanonical; MaxSimpleKeyLength = maxSimpleKeyLength; SkipAnchorName = skipAnchorName; IndentSequences = indentSequences; } public EmitterSettings WithBestIndent(int bestIndent) { return new EmitterSettings(bestIndent, BestWidth, IsCanonical, MaxSimpleKeyLength, SkipAnchorName); } public EmitterSettings WithBestWidth(int bestWidth) { return new EmitterSettings(BestIndent, bestWidth, IsCanonical, MaxSimpleKeyLength, SkipAnchorName); } public EmitterSettings WithMaxSimpleKeyLength(int maxSimpleKeyLength) { return new EmitterSettings(BestIndent, BestWidth, IsCanonical, maxSimpleKeyLength, SkipAnchorName); } public EmitterSettings Canonical() { return new EmitterSettings(BestIndent, BestWidth, isCanonical: true, MaxSimpleKeyLength, SkipAnchorName); } public EmitterSettings WithoutAnchorName() { return new EmitterSettings(BestIndent, BestWidth, IsCanonical, MaxSimpleKeyLength, skipAnchorName: true); } public EmitterSettings WithIndentedSequences() { return new EmitterSettings(BestIndent, BestWidth, IsCanonical, MaxSimpleKeyLength, SkipAnchorName, indentSequences: true); } } internal enum EmitterState { StreamStart, StreamEnd, FirstDocumentStart, DocumentStart, DocumentContent, DocumentEnd, FlowSequenceFirstItem, FlowSequenceItem, FlowMappingFirstKey, FlowMappingKey, FlowMappingSimpleValue, FlowMappingValue, BlockSequenceFirstItem, BlockSequenceItem, BlockMappingFirstKey, BlockMappingKey, BlockMappingSimpleValue, BlockMappingValue } internal sealed class ForwardAnchorNotSupportedException : YamlException { public ForwardAnchorNotSupportedException(string message) : base(message) { } public ForwardAnchorNotSupportedException(Mark start, Mark end, string message) : base(start, end, message) { } public ForwardAnchorNotSupportedException(string message, Exception inner) : base(message, inner) { } } internal static class HashCode { public static int CombineHashCodes(int h1, int h2) { return ((h1 << 5) + h1) ^ h2; } public static int CombineHashCodes(int h1, object? o2) { return CombineHashCodes(h1, GetHashCode(o2)); } public static int CombineHashCodes(object? first, params object?[] others) { int num = GetHashCode(first); foreach (object o in others) { num = CombineHashCodes(num, o); } return num; } private static int GetHashCode(object? obj) { return obj?.GetHashCode() ?? 0; } } internal interface IEmitter { void Emit(ParsingEvent @event); } internal interface ILookAheadBuffer { bool EndOfInput { get; } char Peek(int offset); void Skip(int length); } internal sealed class InsertionQueue : IEnumerable, IEnumerable { private const int DefaultInitialCapacity = 128; private T[] items; private int readPtr; private int writePtr; private int mask; private int count; public int Count => count; public int Capacity => items.Length; public InsertionQueue(int initialCapacity = 128) { if (initialCapacity <= 0) { throw new ArgumentOutOfRangeException("initialCapacity", "The initial capacity must be a positive number."); } if (!initialCapacity.IsPowerOfTwo()) { throw new ArgumentException("The initial capacity must be a power of 2.", "initialCapacity"); } items = new T[initialCapacity]; readPtr = initialCapacity / 2; writePtr = initialCapacity / 2; mask = initialCapacity - 1; } public void Enqueue(T item) { ResizeIfNeeded(); items[writePtr] = item; writePtr = (writePtr - 1) & mask; count++; } public T Dequeue() { if (count == 0) { throw new InvalidOperationException("The queue is empty"); } T result = items[readPtr]; readPtr = (readPtr - 1) & mask; count--; return result; } public void Insert(int index, T item) { if (index > count) { throw new InvalidOperationException("Cannot insert outside of the bounds of the queue"); } ResizeIfNeeded(); CalculateInsertionParameters(mask, count, index, ref readPtr, ref writePtr, out var insertPtr, out var copyIndex, out var copyOffset, out var copyLength); if (copyLength != 0) { Array.Copy(items, copyIndex, items, copyIndex + copyOffset, copyLength); } items[insertPtr] = item; count++; } private void ResizeIfNeeded() { int num = items.Length; if (count == num) { T[] destinationArray = new T[num * 2]; int num2 = readPtr + 1; if (num2 > 0) { Array.Copy(items, 0, destinationArray, 0, num2); } writePtr += num; int num3 = num - num2; if (num3 > 0) { Array.Copy(items, readPtr + 1, destinationArray, writePtr + 1, num3); } items = destinationArray; mask = mask * 2 + 1; } } internal static void CalculateInsertionParameters(int mask, int count, int index, ref int readPtr, ref int writePtr, out int insertPtr, out int copyIndex, out int copyOffset, out int copyLength) { int num = (readPtr + 1) & mask; if (index == 0) { insertPtr = (readPtr = num); copyIndex = 0; copyOffset = 0; copyLength = 0; return; } insertPtr = (readPtr - index) & mask; if (index == count) { writePtr = (writePtr - 1) & mask; copyIndex = 0; copyOffset = 0; copyLength = 0; return; } int num2 = ((num >= insertPtr) ? (readPtr - insertPtr) : int.MaxValue); int num3 = ((writePtr <= insertPtr) ? (insertPtr - writePtr) : int.MaxValue); if (num2 <= num3) { insertPtr++; readPtr++; copyIndex = insertPtr; copyOffset = 1; copyLength = num2; } else { copyIndex = writePtr + 1; copyOffset = -1; copyLength = num3; writePtr = (writePtr - 1) & mask; } } public IEnumerator GetEnumerator() { int ptr = readPtr; for (int i = 0; i < Count; i++) { yield return items[ptr]; ptr = (ptr - 1) & mask; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } internal interface IParser { ParsingEvent? Current { get; } bool MoveNext(); } internal interface IScanner { Mark CurrentPosition { get; } Token? Current { get; } bool MoveNext(); bool MoveNextWithoutConsuming(); void ConsumeCurrent(); } internal sealed class LookAheadBuffer : ILookAheadBuffer { private readonly TextReader input; private readonly char[] buffer; private readonly int blockSize; private readonly int mask; private int firstIndex; private int writeOffset; private int count; private bool endOfInput; public bool EndOfInput { get { if (endOfInput) { return count == 0; } return false; } } public LookAheadBuffer(TextReader input, int capacity) { if (capacity < 1) { throw new ArgumentOutOfRangeException("capacity", "The capacity must be positive."); } if (!capacity.IsPowerOfTwo()) { throw new ArgumentException("The capacity must be a power of 2.", "capacity"); } this.input = input ?? throw new ArgumentNullException("input"); blockSize = capacity; buffer = new char[capacity * 2]; mask = capacity * 2 - 1; } private int GetIndexForOffset(int offset) { return (firstIndex + offset) & mask; } public char Peek(int offset) { if (offset >= count) { FillBuffer(); } if (offset < count) { return buffer[(firstIndex + offset) & mask]; } return '\0'; } public void Cache(int length) { if (length >= count) { FillBuffer(); } } private void FillBuffer() { if (endOfInput) { return; } int num = blockSize; do { int num2 = input.Read(buffer, writeOffset, num); if (num2 == 0) { endOfInput = true; return; } num -= num2; writeOffset += num2; count += num2; } while (num > 0); if (writeOffset == buffer.Length) { writeOffset = 0; } } public void Skip(int length) { if (length < 1 || length > blockSize) { throw new ArgumentOutOfRangeException("length", "The length must be between 1 and the number of characters in the buffer. Use the Peek() and / or Cache() methods to fill the buffer."); } firstIndex = GetIndexForOffset(length); count -= length; } } internal sealed class Mark : IEquatable, IComparable, IComparable { public static readonly Mark Empty = new Mark(); public int Index { get; } public int Line { get; } public int Column { get; } public Mark() { Line = 1; Column = 1; } public Mark(int index, int line, int column) { if (index < 0) { throw new ArgumentOutOfRangeException("index", "Index must be greater than or equal to zero."); } if (line < 1) { throw new ArgumentOutOfRangeException("line", "Line must be greater than or equal to 1."); } if (column < 1) { throw new ArgumentOutOfRangeException("column", "Column must be greater than or equal to 1."); } Index = index; Line = line; Column = column; } public override string ToString() { return $"Line: {Line}, Col: {Column}, Idx: {Index}"; } public override bool Equals(object? obj) { return Equals(obj as Mark); } public bool Equals(Mark? other) { if (other != null && Index == other.Index && Line == other.Line) { return Column == other.Column; } return false; } public override int GetHashCode() { return HashCode.CombineHashCodes(Index.GetHashCode(), HashCode.CombineHashCodes(Line.GetHashCode(), Column.GetHashCode())); } public int CompareTo(object? obj) { if (obj == null) { throw new ArgumentNullException("obj"); } return CompareTo(obj as Mark); } public int CompareTo(Mark? other) { if (other == null) { throw new ArgumentNullException("other"); } int num = Line.CompareTo(other.Line); if (num == 0) { num = Column.CompareTo(other.Column); } return num; } } internal sealed class MaximumRecursionLevelReachedException : YamlException { public MaximumRecursionLevelReachedException(string message) : base(message) { } public MaximumRecursionLevelReachedException(Mark start, Mark end, string message) : base(start, end, message) { } public MaximumRecursionLevelReachedException(string message, Exception inner) : base(message, inner) { } } internal sealed class MergingParser : IParser { private sealed class ParsingEventCollection : IEnumerable>, IEnumerable { private readonly LinkedList events; private readonly HashSet> deleted; private readonly Dictionary> references; public ParsingEventCollection() { events = new LinkedList(); deleted = new HashSet>(); references = new Dictionary>(); } public void AddAfter(LinkedListNode node, IEnumerable items) { foreach (ParsingEvent item in items) { node = events.AddAfter(node, item); } } public void Add(ParsingEvent item) { LinkedListNode node = events.AddLast(item); AddReference(item, node); } public void MarkDeleted(LinkedListNode node) { deleted.Add(node); } public void CleanMarked() { foreach (LinkedListNode item in deleted) { events.Remove(item); } } public IEnumerable> FromAnchor(AnchorName anchor) { LinkedListNode next = references[anchor].Next; return Enumerate(next); } public IEnumerator> GetEnumerator() { return Enumerate(events.First).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private IEnumerable> Enumerate(LinkedListNode? node) { while (node != null) { yield return node; node = node.Next; } } private void AddReference(ParsingEvent item, LinkedListNode node) { if (item is MappingStart mappingStart) { AnchorName anchor = mappingStart.Anchor; if (!anchor.IsEmpty) { references[anchor] = node; } } } } private sealed class ParsingEventCloner : IParsingEventVisitor { private ParsingEvent? clonedEvent; public ParsingEvent Clone(ParsingEvent e) { e.Accept(this); if (clonedEvent == null) { throw new InvalidOperationException($"Could not clone event of type '{e.Type}'"); } return clonedEvent; } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.AnchorAlias e) { clonedEvent = new YamlDotNet.Core.Events.AnchorAlias(e.Value, e.Start, e.End); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.StreamStart e) { throw new NotSupportedException(); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.StreamEnd e) { throw new NotSupportedException(); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.DocumentStart e) { throw new NotSupportedException(); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.DocumentEnd e) { throw new NotSupportedException(); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.Scalar e) { clonedEvent = new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, e.Tag, e.Value, e.Style, e.IsPlainImplicit, e.IsQuotedImplicit, e.Start, e.End); } void IParsingEventVisitor.Visit(SequenceStart e) { clonedEvent = new SequenceStart(AnchorName.Empty, e.Tag, e.IsImplicit, e.Style, e.Start, e.End); } void IParsingEventVisitor.Visit(SequenceEnd e) { clonedEvent = new SequenceEnd(e.Start, e.End); } void IParsingEventVisitor.Visit(MappingStart e) { clonedEvent = new MappingStart(AnchorName.Empty, e.Tag, e.IsImplicit, e.Style, e.Start, e.End); } void IParsingEventVisitor.Visit(MappingEnd e) { clonedEvent = new MappingEnd(e.Start, e.End); } void IParsingEventVisitor.Visit(YamlDotNet.Core.Events.Comment e) { throw new NotSupportedException(); } } private readonly ParsingEventCollection events; private readonly IParser innerParser; private IEnumerator> iterator; private bool merged; public ParsingEvent? Current => iterator.Current?.Value; public MergingParser(IParser innerParser) { events = new ParsingEventCollection(); merged = false; iterator = events.GetEnumerator(); this.innerParser = innerParser; } public bool MoveNext() { if (!merged) { Merge(); events.CleanMarked(); iterator = events.GetEnumerator(); merged = true; } return iterator.MoveNext(); } private void Merge() { while (innerParser.MoveNext()) { events.Add(innerParser.Current); } foreach (LinkedListNode @event in events) { if (IsMergeToken(@event)) { events.MarkDeleted(@event); if (!HandleMerge(@event.Next)) { throw new SemanticErrorException(@event.Value.Start, @event.Value.End, "Unrecognized merge key pattern"); } } } } private bool HandleMerge(LinkedListNode? node) { if (node == null) { return false; } if (node.Value is YamlDotNet.Core.Events.AnchorAlias anchorAlias) { return HandleAnchorAlias(node, node, anchorAlias); } if (node.Value is SequenceStart) { return HandleSequence(node); } return false; } private bool HandleMergeSequence(LinkedListNode sequenceStart, LinkedListNode? node) { if (node == null) { return false; } if (node.Value is YamlDotNet.Core.Events.AnchorAlias anchorAlias) { return HandleAnchorAlias(sequenceStart, node, anchorAlias); } if (node.Value is SequenceStart) { return HandleSequence(node); } return false; } private bool IsMergeToken(LinkedListNode node) { if (node.Value is YamlDotNet.Core.Events.Scalar scalar) { return scalar.Value == "<<"; } return false; } private bool HandleAnchorAlias(LinkedListNode node, LinkedListNode anchorNode, YamlDotNet.Core.Events.AnchorAlias anchorAlias) { IEnumerable mappingEvents = GetMappingEvents(anchorAlias.Value); events.AddAfter(node, mappingEvents); events.MarkDeleted(anchorNode); return true; } private bool HandleSequence(LinkedListNode node) { events.MarkDeleted(node); LinkedListNode linkedListNode = node; while (linkedListNode != null) { if (linkedListNode.Value is SequenceEnd) { events.MarkDeleted(linkedListNode); return true; } LinkedListNode next = linkedListNode.Next; HandleMergeSequence(node, next); linkedListNode = next; } return true; } private IEnumerable GetMappingEvents(AnchorName anchor) { ParsingEventCloner cloner = new ParsingEventCloner(); int nesting = 0; return from e in (from e in events.FromAnchor(anchor) select e.Value).TakeWhile((ParsingEvent e) => (nesting += e.NestingIncrease) >= 0) select cloner.Clone(e); } } internal class Parser : IParser { private class EventQueue { private readonly Queue highPriorityEvents = new Queue(); private readonly Queue normalPriorityEvents = new Queue(); public int Count => highPriorityEvents.Count + normalPriorityEvents.Count; public void Enqueue(ParsingEvent @event) { EventType type = @event.Type; if (type == EventType.StreamStart || type == EventType.DocumentStart) { highPriorityEvents.Enqueue(@event); } else { normalPriorityEvents.Enqueue(@event); } } public ParsingEvent Dequeue() { if (highPriorityEvents.Count <= 0) { return normalPriorityEvents.Dequeue(); } return highPriorityEvents.Dequeue(); } } private readonly Stack states = new Stack(); private readonly TagDirectiveCollection tagDirectives = new TagDirectiveCollection(); private ParserState state; private readonly IScanner scanner; private Token? currentToken; private VersionDirective? version; private readonly EventQueue pendingEvents = new EventQueue(); public ParsingEvent? Current { get; private set; } private Token? GetCurrentToken() { if (currentToken == null) { while (scanner.MoveNextWithoutConsuming()) { currentToken = scanner.Current; if (!(currentToken is YamlDotNet.Core.Tokens.Comment comment)) { break; } pendingEvents.Enqueue(new YamlDotNet.Core.Events.Comment(comment.Value, comment.IsInline, comment.Start, comment.End)); scanner.ConsumeCurrent(); } } return currentToken; } public Parser(TextReader input) : this(new Scanner(input)) { } public Parser(IScanner scanner) { this.scanner = scanner; } public bool MoveNext() { if (state == ParserState.StreamEnd) { Current = null; return false; } if (pendingEvents.Count == 0) { pendingEvents.Enqueue(StateMachine()); } Current = pendingEvents.Dequeue(); return true; } private ParsingEvent StateMachine() { return state switch { ParserState.StreamStart => ParseStreamStart(), ParserState.ImplicitDocumentStart => ParseDocumentStart(isImplicit: true), ParserState.DocumentStart => ParseDocumentStart(isImplicit: false), ParserState.DocumentContent => ParseDocumentContent(), ParserState.DocumentEnd => ParseDocumentEnd(), ParserState.BlockNode => ParseNode(isBlock: true, isIndentlessSequence: false), ParserState.BlockNodeOrIndentlessSequence => ParseNode(isBlock: true, isIndentlessSequence: true), ParserState.FlowNode => ParseNode(isBlock: false, isIndentlessSequence: false), ParserState.BlockSequenceFirstEntry => ParseBlockSequenceEntry(isFirst: true), ParserState.BlockSequenceEntry => ParseBlockSequenceEntry(isFirst: false), ParserState.IndentlessSequenceEntry => ParseIndentlessSequenceEntry(), ParserState.BlockMappingFirstKey => ParseBlockMappingKey(isFirst: true), ParserState.BlockMappingKey => ParseBlockMappingKey(isFirst: false), ParserState.BlockMappingValue => ParseBlockMappingValue(), ParserState.FlowSequenceFirstEntry => ParseFlowSequenceEntry(isFirst: true), ParserState.FlowSequenceEntry => ParseFlowSequenceEntry(isFirst: false), ParserState.FlowSequenceEntryMappingKey => ParseFlowSequenceEntryMappingKey(), ParserState.FlowSequenceEntryMappingValue => ParseFlowSequenceEntryMappingValue(), ParserState.FlowSequenceEntryMappingEnd => ParseFlowSequenceEntryMappingEnd(), ParserState.FlowMappingFirstKey => ParseFlowMappingKey(isFirst: true), ParserState.FlowMappingKey => ParseFlowMappingKey(isFirst: false), ParserState.FlowMappingValue => ParseFlowMappingValue(isEmpty: false), ParserState.FlowMappingEmptyValue => ParseFlowMappingValue(isEmpty: true), _ => throw new InvalidOperationException(), }; } private void Skip() { if (currentToken != null) { currentToken = null; scanner.ConsumeCurrent(); } } private ParsingEvent ParseStreamStart() { Token token = GetCurrentToken(); if (!(token is YamlDotNet.Core.Tokens.StreamStart streamStart)) { throw new SemanticErrorException(token?.Start ?? Mark.Empty, token?.End ?? Mark.Empty, "Did not find expected ."); } Skip(); state = ParserState.ImplicitDocumentStart; return new YamlDotNet.Core.Events.StreamStart(streamStart.Start, streamStart.End); } private ParsingEvent ParseDocumentStart(bool isImplicit) { if (currentToken is VersionDirective) { throw new SyntaxErrorException("While parsing a document start node, could not find document end marker before version directive."); } Token token = GetCurrentToken(); if (!isImplicit) { while (token is YamlDotNet.Core.Tokens.DocumentEnd) { Skip(); token = GetCurrentToken(); } } if (token == null) { throw new SyntaxErrorException("Reached the end of the stream while parsing a document start."); } if (token is YamlDotNet.Core.Tokens.Scalar && (state == ParserState.ImplicitDocumentStart || state == ParserState.DocumentStart)) { isImplicit = true; } if ((isImplicit && !(token is VersionDirective) && !(token is TagDirective) && !(token is YamlDotNet.Core.Tokens.DocumentStart) && !(token is YamlDotNet.Core.Tokens.StreamEnd) && !(token is YamlDotNet.Core.Tokens.DocumentEnd)) || token is BlockMappingStart) { TagDirectiveCollection tags = new TagDirectiveCollection(); ProcessDirectives(tags); states.Push(ParserState.DocumentEnd); state = ParserState.BlockNode; return new YamlDotNet.Core.Events.DocumentStart(null, tags, isImplicit: true, token.Start, token.End); } if (!(token is YamlDotNet.Core.Tokens.StreamEnd) && !(token is YamlDotNet.Core.Tokens.DocumentEnd)) { Mark start = token.Start; TagDirectiveCollection tags2 = new TagDirectiveCollection(); VersionDirective? versionDirective = ProcessDirectives(tags2); token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a document start"); if (!(token is YamlDotNet.Core.Tokens.DocumentStart)) { throw new SemanticErrorException(token.Start, token.End, "Did not find expected ."); } states.Push(ParserState.DocumentEnd); state = ParserState.DocumentContent; Mark end = token.End; Skip(); return new YamlDotNet.Core.Events.DocumentStart(versionDirective, tags2, isImplicit: false, start, end); } if (token is YamlDotNet.Core.Tokens.DocumentEnd) { Skip(); } state = ParserState.StreamEnd; token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a document start"); YamlDotNet.Core.Events.StreamEnd result = new YamlDotNet.Core.Events.StreamEnd(token.Start, token.End); if (scanner.MoveNextWithoutConsuming()) { throw new InvalidOperationException("The scanner should contain no more tokens."); } return result; } private VersionDirective? ProcessDirectives(TagDirectiveCollection tags) { bool flag = false; VersionDirective result = null; while (true) { if (GetCurrentToken() is VersionDirective versionDirective) { if (version != null) { throw new SemanticErrorException(versionDirective.Start, versionDirective.End, "Found duplicate %YAML directive."); } if (versionDirective.Version.Major != 1 || versionDirective.Version.Minor > 3) { throw new SemanticErrorException(versionDirective.Start, versionDirective.End, "Found incompatible YAML document."); } result = (version = versionDirective); flag = true; } else { if (!(GetCurrentToken() is TagDirective tagDirective)) { break; } if (tags.Contains(tagDirective.Handle)) { throw new SemanticErrorException(tagDirective.Start, tagDirective.End, "Found duplicate %TAG directive."); } tags.Add(tagDirective); flag = true; } Skip(); } if (GetCurrentToken() is YamlDotNet.Core.Tokens.DocumentStart && (version == null || (version.Version.Major == 1 && version.Version.Minor > 1))) { if (GetCurrentToken() is YamlDotNet.Core.Tokens.DocumentStart && version == null) { version = new VersionDirective(new Version(1, 2)); } flag = true; } AddTagDirectives(tags, Constants.DefaultTagDirectives); if (flag) { tagDirectives.Clear(); } AddTagDirectives(tagDirectives, tags); return result; } private static void AddTagDirectives(TagDirectiveCollection directives, IEnumerable source) { foreach (TagDirective item in source) { if (!directives.Contains(item)) { directives.Add(item); } } } private ParsingEvent ParseDocumentContent() { if (GetCurrentToken() is VersionDirective || GetCurrentToken() is TagDirective || GetCurrentToken() is YamlDotNet.Core.Tokens.DocumentStart || GetCurrentToken() is YamlDotNet.Core.Tokens.DocumentEnd || GetCurrentToken() is YamlDotNet.Core.Tokens.StreamEnd) { state = states.Pop(); return ProcessEmptyScalar(scanner.CurrentPosition); } return ParseNode(isBlock: true, isIndentlessSequence: false); } private static ParsingEvent ProcessEmptyScalar(Mark position) { return new YamlDotNet.Core.Events.Scalar(AnchorName.Empty, TagName.Empty, string.Empty, ScalarStyle.Plain, isPlainImplicit: true, isQuotedImplicit: false, position, position); } private ParsingEvent ParseNode(bool isBlock, bool isIndentlessSequence) { if (GetCurrentToken() is Error error) { throw new SemanticErrorException(error.Start, error.End, error.Value); } Token token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a node"); if (token is YamlDotNet.Core.Tokens.AnchorAlias anchorAlias) { state = states.Pop(); YamlDotNet.Core.Events.AnchorAlias result = new YamlDotNet.Core.Events.AnchorAlias(anchorAlias.Value, anchorAlias.Start, anchorAlias.End); Skip(); return result; } Mark start = token.Start; AnchorName anchor = AnchorName.Empty; TagName tag = TagName.Empty; Anchor anchor2 = null; Tag tag2 = null; while (true) { if (anchor.IsEmpty && token is Anchor anchor3) { anchor2 = anchor3; anchor = anchor3.Value; Skip(); } else { if (!tag.IsEmpty || !(token is Tag tag3)) { if (token is Anchor anchor4) { throw new SemanticErrorException(anchor4.Start, anchor4.End, "While parsing a node, found more than one anchor."); } if (token is YamlDotNet.Core.Tokens.AnchorAlias anchorAlias2) { throw new SemanticErrorException(anchorAlias2.Start, anchorAlias2.End, "While parsing a node, did not find expected token."); } if (!(token is Error error2)) { break; } if (tag2 != null && anchor2 != null && !anchor.IsEmpty) { return new YamlDotNet.Core.Events.Scalar(anchor, default(TagName), string.Empty, ScalarStyle.Any, isPlainImplicit: false, isQuotedImplicit: false, anchor2.Start, anchor2.End); } throw new SemanticErrorException(error2.Start, error2.End, error2.Value); } tag2 = tag3; if (string.IsNullOrEmpty(tag3.Handle)) { tag = new TagName(tag3.Suffix); } else { if (!tagDirectives.Contains(tag3.Handle)) { throw new SemanticErrorException(tag3.Start, tag3.End, "While parsing a node, found undefined tag handle."); } tag = new TagName(tagDirectives[tag3.Handle].Prefix + tag3.Suffix); } Skip(); } token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a node"); } bool isEmpty = tag.IsEmpty; if (isIndentlessSequence && GetCurrentToken() is BlockEntry) { state = ParserState.IndentlessSequenceEntry; return new SequenceStart(anchor, tag, isEmpty, SequenceStyle.Block, start, token.End); } if (token is YamlDotNet.Core.Tokens.Scalar scalar) { bool isPlainImplicit = false; bool isQuotedImplicit = false; if ((scalar.Style == ScalarStyle.Plain && tag.IsEmpty) || tag.IsNonSpecific) { isPlainImplicit = true; } else if (tag.IsEmpty) { isQuotedImplicit = true; } state = states.Pop(); Skip(); YamlDotNet.Core.Events.Scalar result2 = new YamlDotNet.Core.Events.Scalar(anchor, tag, scalar.Value, scalar.Style, isPlainImplicit, isQuotedImplicit, start, scalar.End); if (!anchor.IsEmpty && scanner.MoveNextWithoutConsuming()) { currentToken = scanner.Current; if (currentToken is Error) { Error error3 = currentToken as Error; throw new SemanticErrorException(error3.Start, error3.End, error3.Value); } } if (state == ParserState.FlowMappingKey && scanner.MoveNextWithoutConsuming()) { currentToken = scanner.Current; if (currentToken != null && !(currentToken is FlowEntry) && !(currentToken is FlowMappingEnd)) { throw new SemanticErrorException(currentToken.Start, currentToken.End, "While parsing a flow mapping, did not find expected ',' or '}'."); } } return result2; } if (token is FlowSequenceStart flowSequenceStart) { state = ParserState.FlowSequenceFirstEntry; return new SequenceStart(anchor, tag, isEmpty, SequenceStyle.Flow, start, flowSequenceStart.End); } if (token is FlowMappingStart flowMappingStart) { state = ParserState.FlowMappingFirstKey; return new MappingStart(anchor, tag, isEmpty, MappingStyle.Flow, start, flowMappingStart.End); } if (isBlock) { if (token is BlockSequenceStart blockSequenceStart) { state = ParserState.BlockSequenceFirstEntry; return new SequenceStart(anchor, tag, isEmpty, SequenceStyle.Block, start, blockSequenceStart.End); } if (token is BlockMappingStart blockMappingStart) { state = ParserState.BlockMappingFirstKey; return new MappingStart(anchor, tag, isEmpty, MappingStyle.Block, start, blockMappingStart.End); } } if (!anchor.IsEmpty || !tag.IsEmpty) { state = states.Pop(); return new YamlDotNet.Core.Events.Scalar(anchor, tag, string.Empty, ScalarStyle.Plain, isEmpty, isQuotedImplicit: false, start, token.End); } throw new SemanticErrorException(token.Start, token.End, "While parsing a node, did not find expected node content."); } private ParsingEvent ParseDocumentEnd() { Token token = GetCurrentToken() ?? throw new SemanticErrorException("Reached the end of the stream while parsing a document end"); bool isImplicit = true; Mark start = token.Start; Mark end = start; if (token is YamlDotNet.Core.Tokens.DocumentEnd) { end = token.End; Skip(); isImplicit = false; } else if (!(currentToken is YamlDotNet.Core.Tokens.StreamEnd) && !(currentToken is YamlDotNet.Core.Tokens.DocumentStart) && !(currentToken is FlowSequenceEnd) && !(currentToken is VersionDirective) && (!(Current is YamlDotNet.Core.Events.Scalar) || !(currentToken is Error))) { throw new SemanticErrorException(start, end, "Did not find expected ."); } if (version != null && version.Version.Major == 1 && version.Version.Minor > 1) { version = null; } state = ParserState.DocumentStart; return new YamlDotNet.Core.Events.DocumentEnd(isImplicit, start, end); } private ParsingEvent ParseBlockSequenceEntry(bool isFirst) { if (isFirst) { GetCurrentToken(); Skip(); } Token token = GetCurrentToken(); if (token is BlockEntry blockEntry) { Mark end = blockEntry.End; Skip(); token = GetCurrentToken(); if (!(token is BlockEntry) && !(token is BlockEnd)) { states.Push(ParserState.BlockSequenceEntry); return ParseNode(isBlock: true, isIndentlessSequence: false); } state = ParserState.BlockSequenceEntry; return ProcessEmptyScalar(end); } if (token is BlockEnd blockEnd) { state = states.Pop(); SequenceEnd result = new SequenceEnd(blockEnd.Start, blockEnd.End); Skip(); return result; } throw new SemanticErrorException(token?.Start ?? Mark.Empty, token?.End ?? Mark.Empty, "While parsing a block collection, did not find expected '-' indicator."); } private ParsingEvent ParseIndentlessSequenceEntry() { Token token = GetCurrentToken(); if (token is BlockEntry blockEntry) { Mark end = blockEntry.End; Skip(); token = GetCurrentToken(); if (!(token is BlockEntry) && !(token is Key) && !(token is Value) && !(token is BlockEnd)) { states.Push(ParserState.IndentlessSequenceEntry); return ParseNode(isBlock: true, isIndentlessSequence: false); } state = ParserState.IndentlessSequenceEntry; return ProcessEmptyScalar(end); } state = states.Pop(); return new SequenceEnd(token?.Start ?? Mark.Empty, token?.End ?? Mark.Empty); } private ParsingEvent ParseBlockMappingKey(bool isFirst) { if (isFirst) { GetCurrentToken(); Skip(); } Token token = GetCurrentToken(); if (token is Key key) { Mark end = key.End; Skip(); token = GetCurrentToken(); if (!(token is Key) && !(token is Value) && !(token is BlockEnd)) { states.Push(ParserState.BlockMappingValue); return ParseNode(isBlock: true, isIndentlessSequence: true); } state = ParserState.BlockMappingValue; return ProcessEmptyScalar(end); } if (token is Value value) { Skip(); return ProcessEmptyScalar(value.End); } if (token is YamlDotNet.Core.Tokens.AnchorAlias anchorAlias) { Skip(); return new YamlDotNet.Core.Events.AnchorAlias(anchorAlias.Value, anchorAlias.Start, anchorAlias.End); } if (token is BlockEnd blockEnd) { state = states.Pop(); MappingEnd result = new MappingEnd(blockEnd.Start, blockEnd.End); Skip(); return result; } if (GetCurrentToken() is Error error) { throw new SyntaxErrorException(error.Start, error.End, error.Value); } throw new SemanticErrorException(token?.Start ?? Mark.Empty, token?.End ?? Mark.Empty, "While parsing a block mapping, did not find expected key."); } private ParsingEvent ParseBlockMappingValue() { Token token = GetCurrentToken(); if (token is Value value) { Mark end = value.End; Skip(); token = GetCurrentToken(); if (!(token is Key) && !(token is Value) && !(token is BlockEnd)) { states.Push(ParserState.BlockMappingKey); return ParseNode(isBlock: true, isIndentlessSequence: true); } state = ParserState.BlockMappingKey; return ProcessEmptyScalar(end); } if (token is Error error) { throw new SemanticErrorException(error.Start, error.End, error.Value); } state = ParserState.BlockMappingKey; return ProcessEmptyScalar(token?.Start ?? Mark.Empty); } private ParsingEvent ParseFlowSequenceEntry(bool isFirst) { if (isFirst) { GetCurrentToken(); Skip(); } Token token = GetCurrentToken(); if (!(token is FlowSequenceEnd)) { if (!isFirst) { if (!(token is FlowEntry)) { throw new SemanticErrorException(token?.Start ?? Mark.Empty, token?.End ?? Mark.Empty, "While parsing a flow sequence, did not find expected ',' or ']'."); } Skip(); token = GetCurrentToken(); } if (token is Key) { state = ParserState.FlowSequenceEntryMappingKey; MappingStart result = new MappingStart(AnchorName.Empty, TagName.Empty, isImplicit: true, MappingStyle.Flow); Skip(); return result; } if (!(token is FlowSequenceEnd)) { states.Push(ParserState.FlowSequenceEntry); return ParseNode(isBlock: false, isIndentlessSequence: false); } } state = states.Pop(); SequenceEnd result2 = new SequenceEnd(token?.Start ?? Mark.Empty, token?.End ?? Mark.Empty); Skip(); return result2; } private ParsingEvent ParseFlowSequenceEntryMappingKey() { Token token = GetCurrentToken(); if (!(token is Value) && !(token is FlowEntry) && !(token is FlowSequenceEnd)) { states.Push(ParserState.FlowSequenceEntryMappingValue); return ParseNode(isBlock: false, isIndentlessSequence: false); } Mark position = token?.End ?? Mark.Empty; Skip(); state = ParserState.FlowSequenceEntryMappingValue; return ProcessEmptyScalar(position); } private ParsingEvent ParseFlowSequenceEntryMappingValue() { Token token = GetCurrentToken(); if (token is Value) { Skip(); token = GetCurrentToken(); if (!(token is FlowEntry) && !(token is FlowSequenceEnd)) { states.Push(ParserState.FlowSequenceEntryMappingEnd); return ParseNode(isBlock: false, isIndentlessSequence: false); } } state = ParserState.FlowSequenceEntryMappingEnd; return ProcessEmptyScalar(token?.Start ?? Mark.Empty); } private ParsingEvent ParseFlowSequenceEntryMappingEnd() { state = ParserState.FlowSequenceEntry; Token token = GetCurrentToken(); return new MappingEnd(token?.Start ?? Mark.Empty, token?.End ?? Mark.Empty); } private ParsingEvent ParseFlowMappingKey(bool isFirst) { if (isFirst) { GetCurrentToken(); Skip(); } Token token = GetCurrentToken(); if (!(token is FlowMappingEnd)) { if (!isFirst) { if (!(token is FlowEntry)) { throw new SemanticErrorException(token?.Start ?? Mark.Empty, token?.End ?? Mark.Empty, "While parsing a flow mapping, did not find expected ',' or '}'."); } Skip(); token = GetCurrentToken(); } if (token is Key) { Skip(); token = GetCurrentToken(); if (!(token is Value) && !(token is FlowEntry) && !(token is FlowMappingEnd)) { states.Push(ParserState.FlowMappingValue); return ParseNode(isBlock: false, isIndentlessSequence: false); } state = ParserState.FlowMappingValue; return ProcessEmptyScalar(token?.Start ?? Mark.Empty); } if (token is YamlDotNet.Core.Tokens.Scalar) { states.Push(ParserState.FlowMappingValue); return ParseNode(isBlock: false, isIndentlessSequence: false); } if (!(token is FlowMappingEnd)) { states.Push(ParserState.FlowMappingEmptyValue); return ParseNode(isBlock: false, isIndentlessSequence: false); } } state = states.Pop(); Skip(); return new MappingEnd(token?.Start ?? Mark.Empty, token?.End ?? Mark.Empty); } private ParsingEvent ParseFlowMappingValue(bool isEmpty) { Token token = GetCurrentToken(); if (isEmpty) { state = ParserState.FlowMappingKey; return ProcessEmptyScalar(token?.Start ?? Mark.Empty); } if (token is Value) { Skip(); token = GetCurrentToken(); if (!(token is FlowEntry) && !(token is FlowMappingEnd)) { states.Push(ParserState.FlowMappingKey); return ParseNode(isBlock: false, isIndentlessSequence: false); } } state = ParserState.FlowMappingKey; return ProcessEmptyScalar(token?.Start ?? Mark.Empty); } } internal static class ParserExtensions { public static T Consume(this IParser parser) where T : ParsingEvent { T result = parser.Require(); parser.MoveNext(); return result; } public static bool TryConsume(this IParser parser, [MaybeNullWhen(false)] out T @event) where T : ParsingEvent { if (parser.Accept(out @event)) { parser.MoveNext(); return true; } return false; } public static T Require(this IParser parser) where T : ParsingEvent { if (!parser.Accept(out var @event)) { ParsingEvent current = parser.Current; if (current == null) { throw new YamlException("Expected '" + typeof(T).Name + "', got nothing."); } throw new YamlException(current.Start, current.End, $"Expected '{typeof(T).Name}', got '{current.GetType().Name}' (at {current.Start})."); } return @event; } public static bool Accept(this IParser parser, [MaybeNullWhen(false)] out T @event) where T : ParsingEvent { if (parser.Current == null && !parser.MoveNext()) { throw new EndOfStreamException(); } if (parser.Current is T val) { @event = val; return true; } @event = null; return false; } public static void SkipThisAndNestedEvents(this IParser parser) { int num = 0; do { ParsingEvent parsingEvent = parser.Consume(); num += parsingEvent.NestingIncrease; } while (num > 0); } [Obsolete("Please use Consume() instead")] public static T Expect(this IParser parser) where T : ParsingEvent { return parser.Consume(); } [Obsolete("Please use TryConsume(out var evt) instead")] public static T? Allow(this IParser parser) where T : ParsingEvent { if (!parser.TryConsume(out var @event)) { return null; } return @event; } [Obsolete("Please use Accept(out var evt) instead")] public static T? Peek(this IParser parser) where T : ParsingEvent { if (!parser.Accept(out var @event)) { return null; } return @event; } [Obsolete("Please use TryConsume(out var evt) or Accept(out var evt) instead")] public static bool Accept(this IParser parser) where T : ParsingEvent { T @event; return parser.Accept(out @event); } } internal enum ParserState { StreamStart, StreamEnd, ImplicitDocumentStart, DocumentStart, DocumentContent, DocumentEnd, BlockNode, BlockNodeOrIndentlessSequence, FlowNode, BlockSequenceFirstEntry, BlockSequenceEntry, IndentlessSequenceEntry, BlockMappingFirstKey, BlockMappingKey, BlockMappingValue, FlowSequenceFirstEntry, FlowSequenceEntry, FlowSequenceEntryMappingKey, FlowSequenceEntryMappingValue, FlowSequenceEntryMappingEnd, FlowMappingFirstKey, FlowMappingKey, FlowMappingValue, FlowMappingEmptyValue } internal sealed class RecursionLevel { private int current; public int Maximum { get; } public RecursionLevel(int maximum) { Maximum = maximum; } public void Increment() { if (!TryIncrement()) { throw new MaximumRecursionLevelReachedException("Maximum level of recursion reached"); } } public bool TryIncrement() { if (current < Maximum) { current++; return true; } return false; } public void Decrement() { if (current == 0) { throw new InvalidOperationException("Attempted to decrement RecursionLevel to a negative value"); } current--; } } internal enum ScalarStyle { Any, Plain, SingleQuoted, DoubleQuoted, Literal, Folded } internal class Scanner : IScanner { private const int MaxVersionNumberLength = 9; private static readonly IDictionary SimpleEscapeCodes = new SortedDictionary { { '0', '\0' }, { 'a', '\a' }, { 'b', '\b' }, { 't', '\t' }, { '\t', '\t' }, { 'n', '\n' }, { 'v', '\v' }, { 'f', '\f' }, { 'r', '\r' }, { 'e', '\u001b' }, { ' ', ' ' }, { '"', '"' }, { '\\', '\\' }, { '/', '/' }, { 'N', '\u0085' }, { '_', '\u00a0' }, { 'L', '\u2028' }, { 'P', '\u2029' } }; private readonly Stack indents = new Stack(); private readonly InsertionQueue tokens = new InsertionQueue(); private readonly Stack simpleKeys = new Stack(); private readonly CharacterAnalyzer analyzer; private readonly Cursor cursor; private bool streamStartProduced; private bool streamEndProduced; private bool plainScalarFollowedByComment; private int flowSequenceStartLine; private int indent = -1; private bool simpleKeyAllowed; private int flowLevel; private int tokensParsed; private bool tokenAvailable; private Token? previous; private Anchor? previousAnchor; private static readonly byte[] EmptyBytes = new byte[0]; public bool SkipComments { get; private set; } public Token? Current { get; private set; } public Mark CurrentPosition => cursor.Mark(); private bool IsDocumentStart() { if (!analyzer.EndOfInput && cursor.LineOffset == 0 && analyzer.Check('-') && analyzer.Check('-', 1) && analyzer.Check('-', 2)) { return analyzer.IsWhiteBreakOrZero(3); } return false; } private bool IsDocumentEnd() { if (!analyzer.EndOfInput && cursor.LineOffset == 0 && analyzer.Check('.') && analyzer.Check('.', 1) && analyzer.Check('.', 2)) { return analyzer.IsWhiteBreakOrZero(3); } return false; } private bool IsDocumentIndicator() { if (!IsDocumentStart()) { return IsDocumentEnd(); } return true; } public Scanner(TextReader input, bool skipComments = true) { analyzer = new CharacterAnalyzer(new LookAheadBuffer(input, 1024)); cursor = new Cursor(); SkipComments = skipComments; } public bool MoveNext() { if (Current != null) { ConsumeCurrent(); } return MoveNextWithoutConsuming(); } public bool MoveNextWithoutConsuming() { if (!tokenAvailable && !streamEndProduced) { FetchMoreTokens(); } if (tokens.Count > 0) { Current = tokens.Dequeue(); tokenAvailable = false; return true; } Current = null; return false; } public void ConsumeCurrent() { tokensParsed++; tokenAvailable = false; previous = Current; Current = null; } private char ReadCurrentCharacter() { char result = analyzer.Peek(0); Skip(); return result; } private char ReadLine() { if (analyzer.Check("\r\n\u0085")) { SkipLine(); return '\n'; } char result = analyzer.Peek(0); SkipLine(); return result; } private void FetchMoreTokens() { while (true) { bool flag = false; if (tokens.Count == 0) { flag = true; } else { foreach (SimpleKey simpleKey in simpleKeys) { if (simpleKey.IsPossible && simpleKey.TokenNumber == tokensParsed) { flag = true; break; } } } if (!flag) { break; } FetchNextToken(); } tokenAvailable = true; } private static bool StartsWith(StringBuilder what, char start) { if (what.Length > 0) { return what[0] == start; } return false; } private void StaleSimpleKeys() { foreach (SimpleKey simpleKey in simpleKeys) { if (simpleKey.IsPossible && (simpleKey.Line < cursor.Line || simpleKey.Index + 1024 < cursor.Index)) { if (simpleKey.IsRequired) { Mark mark = cursor.Mark(); tokens.Enqueue(new Error("While scanning a simple key, could not find expected ':'.", mark, mark)); } simpleKey.MarkAsImpossible(); } } } private void FetchNextToken() { if (!streamStartProduced) { FetchStreamStart(); return; } ScanToNextToken(); StaleSimpleKeys(); UnrollIndent(cursor.LineOffset); analyzer.Buffer.Cache(4); if (analyzer.Buffer.EndOfInput) { FetchStreamEnd(); return; } if (cursor.LineOffset == 0 && analyzer.Check('%')) { FetchDirective(); return; } if (IsDocumentStart()) { FetchDocumentIndicator(isStartToken: true); return; } if (IsDocumentEnd()) { FetchDocumentIndicator(isStartToken: false); return; } if (analyzer.Check('[')) { FetchFlowCollectionStart(isSequenceToken: true); return; } if (analyzer.Check('{')) { FetchFlowCollectionStart(isSequenceToken: false); return; } if (analyzer.Check(']')) { FetchFlowCollectionEnd(isSequenceToken: true); return; } if (analyzer.Check('}')) { FetchFlowCollectionEnd(isSequenceToken: false); return; } if (analyzer.Check(',')) { FetchFlowEntry(); return; } if (analyzer.Check('-') && analyzer.IsWhiteBreakOrZero(1)) { FetchBlockEntry(); return; } if (analyzer.Check('?') && (flowLevel > 0 || analyzer.IsWhiteBreakOrZero(1))) { FetchKey(); return; } if (analyzer.Check(':') && (flowLevel > 0 || analyzer.IsWhiteBreakOrZero(1)) && (!simpleKeyAllowed || flowLevel <= 0)) { FetchValue(); return; } if (analyzer.Check('*')) { FetchAnchor(isAlias: true); return; } if (analyzer.Check('&')) { FetchAnchor(isAlias: false); return; } if (analyzer.Check('!')) { FetchTag(); return; } if (analyzer.Check('|') && flowLevel == 0) { FetchBlockScalar(isLiteral: true); return; } if (analyzer.Check('>') && flowLevel == 0) { FetchBlockScalar(isLiteral: false); return; } if (analyzer.Check('\'')) { FetchFlowScalar(isSingleQuoted: true); return; } if (analyzer.Check('"')) { FetchFlowScalar(isSingleQuoted: false); return; } if ((!analyzer.IsWhiteBreakOrZero() && !analyzer.Check("-?:,[]{}#&*!|>'\"%@`")) || (analyzer.Check('-') && !analyzer.IsWhite(1)) || (flowLevel == 0 && analyzer.Check("?:") && !analyzer.IsWhiteBreakOrZero(1)) || (simpleKeyAllowed && flowLevel > 0 && analyzer.Check("?:"))) { if (plainScalarFollowedByComment) { Mark mark = cursor.Mark(); tokens.Enqueue(new Error("While scanning plain scalar, found a comment between adjacent scalars.", mark, mark)); } plainScalarFollowedByComment = false; FetchPlainScalar(); return; } if (simpleKeyAllowed && indent >= cursor.LineOffset && analyzer.IsTab()) { throw new SyntaxErrorException("While scanning a mapping, found invalid tab as indentation."); } if (analyzer.IsWhiteBreakOrZero()) { Skip(); return; } Mark start = cursor.Mark(); Skip(); Mark end = cursor.Mark(); throw new SyntaxErrorException(start, end, "While scanning for the next token, found character that cannot start any token."); } private bool CheckWhiteSpace() { if (!analyzer.Check(' ')) { if (flowLevel > 0 || !simpleKeyAllowed) { return analyzer.Check('\t'); } return false; } return true; } private void Skip() { cursor.Skip(); analyzer.Buffer.Skip(1); } private void SkipLine() { if (analyzer.IsCrLf()) { cursor.SkipLineByOffset(2); analyzer.Buffer.Skip(2); } else if (analyzer.IsBreak()) { cursor.SkipLineByOffset(1); analyzer.Buffer.Skip(1); } else if (!analyzer.IsZero()) { throw new InvalidOperationException("Not at a break."); } } private void ScanToNextToken() { while (true) { if (CheckWhiteSpace()) { Skip(); continue; } ProcessComment(); if (analyzer.IsBreak()) { SkipLine(); if (flowLevel == 0) { simpleKeyAllowed = true; } continue; } break; } } private void ProcessComment() { if (analyzer.Check('#')) { Mark mark = cursor.Mark(); Skip(); while (analyzer.IsSpace()) { Skip(); } StringBuilder stringBuilder = new StringBuilder(); while (!analyzer.IsBreakOrZero()) { stringBuilder.Append(ReadCurrentCharacter()); } if (!SkipComments) { bool isInline = previous != null && previous.End.Line == mark.Line && previous.End.Column != 1 && !(previous is YamlDotNet.Core.Tokens.StreamStart); tokens.Enqueue(new YamlDotNet.Core.Tokens.Comment(stringBuilder.ToString(), isInline, mark, cursor.Mark())); } } } private void FetchStreamStart() { simpleKeys.Push(new SimpleKey()); simpleKeyAllowed = true; streamStartProduced = true; Mark mark = cursor.Mark(); tokens.Enqueue(new YamlDotNet.Core.Tokens.StreamStart(mark, mark)); } private void UnrollIndent(int column) { if (flowLevel == 0) { while (indent > column) { Mark mark = cursor.Mark(); tokens.Enqueue(new BlockEnd(mark, mark)); indent = indents.Pop(); } } } private void FetchStreamEnd() { cursor.ForceSkipLineAfterNonBreak(); UnrollIndent(-1); RemoveSimpleKey(); simpleKeyAllowed = false; streamEndProduced = true; Mark mark = cursor.Mark(); tokens.Enqueue(new YamlDotNet.Core.Tokens.StreamEnd(mark, mark)); } private void FetchDirective() { UnrollIndent(-1); RemoveSimpleKey(); simpleKeyAllowed = false; Token token = ScanDirective(); if (token != null) { tokens.Enqueue(token); } } private Token? ScanDirective() { Mark start = cursor.Mark(); Skip(); string text = ScanDirectiveName(start); Token result; if (!(text == "YAML")) { if (!(text == "TAG")) { while (!analyzer.Check('#') && !analyzer.IsBreak()) { Skip(); } return null; } result = ScanTagDirectiveValue(start); } else { if (!(previous is YamlDotNet.Core.Tokens.DocumentStart) && !(previous is YamlDotNet.Core.Tokens.StreamStart) && !(previous is YamlDotNet.Core.Tokens.DocumentEnd)) { throw new SemanticErrorException(start, cursor.Mark(), "While scanning a version directive, did not find preceding ."); } result = ScanVersionDirectiveValue(start); } while (analyzer.IsWhite()) { Skip(); } ProcessComment(); if (!analyzer.IsBreakOrZero()) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a directive, did not find expected comment or line break."); } if (analyzer.IsBreak()) { SkipLine(); } return result; } private void FetchDocumentIndicator(bool isStartToken) { UnrollIndent(-1); RemoveSimpleKey(); simpleKeyAllowed = false; Mark mark = cursor.Mark(); Skip(); Skip(); Skip(); if (isStartToken) { tokens.Enqueue(new YamlDotNet.Core.Tokens.DocumentStart(mark, cursor.Mark())); return; } Token token = null; while (!analyzer.EndOfInput && !analyzer.IsBreak() && !analyzer.Check('#')) { if (!analyzer.IsWhite()) { token = new Error("While scanning a document end, found invalid content after '...' marker.", mark, cursor.Mark()); break; } Skip(); } tokens.Enqueue(new YamlDotNet.Core.Tokens.DocumentEnd(mark, mark)); if (token != null) { tokens.Enqueue(token); } } private void FetchFlowCollectionStart(bool isSequenceToken) { SaveSimpleKey(); IncreaseFlowLevel(); simpleKeyAllowed = true; Mark mark = cursor.Mark(); Skip(); Token token; if (isSequenceToken) { token = new FlowSequenceStart(mark, mark); flowSequenceStartLine = token.Start.Line; } else { token = new FlowMappingStart(mark, mark); } tokens.Enqueue(token); } private void IncreaseFlowLevel() { simpleKeys.Push(new SimpleKey()); flowLevel++; } private void FetchFlowCollectionEnd(bool isSequenceToken) { RemoveSimpleKey(); DecreaseFlowLevel(); simpleKeyAllowed = false; Mark mark = cursor.Mark(); Skip(); Token token = null; Token item; if (isSequenceToken) { if (analyzer.Check('#')) { token = new Error("While scanning a flow sequence end, found invalid comment after ']'.", mark, mark); } if (previous is YamlDotNet.Core.Tokens.StreamStart && flowSequenceStartLine != mark.Line) { tokens.Enqueue(new Error("While scanning a flow sequence end, found mapping key spanning across multiple lines.", mark, mark)); } item = new FlowSequenceEnd(mark, mark); } else { item = new FlowMappingEnd(mark, mark); } tokens.Enqueue(item); if (token != null) { tokens.Enqueue(token); } } private void DecreaseFlowLevel() { if (flowLevel > 0) { flowLevel--; simpleKeys.Pop(); } } private void FetchFlowEntry() { RemoveSimpleKey(); simpleKeyAllowed = true; Mark start = cursor.Mark(); Skip(); Mark end = cursor.Mark(); if (analyzer.Check('#')) { tokens.Enqueue(new Error("While scanning a flow entry, found invalid comment after comma.", start, end)); } else { tokens.Enqueue(new FlowEntry(start, end)); } } private void FetchBlockEntry() { if (flowLevel == 0) { if (!simpleKeyAllowed) { if (previousAnchor != null && previousAnchor.End.Line == cursor.Line) { throw new SemanticErrorException(previousAnchor.Start, previousAnchor.End, "Anchor before sequence entry on same line is not allowed."); } Mark mark = cursor.Mark(); tokens.Enqueue(new Error("Block sequence entries are not allowed in this context.", mark, mark)); } RollIndent(cursor.LineOffset, -1, isSequence: true, cursor.Mark()); } RemoveSimpleKey(); simpleKeyAllowed = true; Mark start = cursor.Mark(); Skip(); tokens.Enqueue(new BlockEntry(start, cursor.Mark())); } private void FetchKey() { if (flowLevel == 0) { if (!simpleKeyAllowed) { Mark mark = cursor.Mark(); throw new SyntaxErrorException(mark, mark, "Mapping keys are not allowed in this context."); } RollIndent(cursor.LineOffset, -1, isSequence: false, cursor.Mark()); } RemoveSimpleKey(); simpleKeyAllowed = flowLevel == 0; Mark start = cursor.Mark(); Skip(); tokens.Enqueue(new Key(start, cursor.Mark())); } private void FetchValue() { SimpleKey simpleKey = simpleKeys.Peek(); if (simpleKey.IsPossible) { tokens.Insert(simpleKey.TokenNumber - tokensParsed, new Key(simpleKey.Mark, simpleKey.Mark)); RollIndent(simpleKey.LineOffset, simpleKey.TokenNumber, isSequence: false, simpleKey.Mark); simpleKey.MarkAsImpossible(); simpleKeyAllowed = false; } else { bool flag = flowLevel == 0; if (flag) { if (!simpleKeyAllowed) { Mark mark = cursor.Mark(); tokens.Enqueue(new Error("Mapping values are not allowed in this context.", mark, mark)); return; } RollIndent(cursor.LineOffset, -1, isSequence: false, cursor.Mark()); if (cursor.LineOffset == 0 && simpleKey.LineOffset == 0) { tokens.Insert(tokens.Count, new Key(simpleKey.Mark, simpleKey.Mark)); flag = false; } } simpleKeyAllowed = flag; } Mark start = cursor.Mark(); Skip(); tokens.Enqueue(new Value(start, cursor.Mark())); } private void RollIndent(int column, int number, bool isSequence, Mark position) { if (flowLevel <= 0 && indent < column) { indents.Push(indent); indent = column; Token item = ((!isSequence) ? ((Token)new BlockMappingStart(position, position)) : ((Token)new BlockSequenceStart(position, position))); if (number == -1) { tokens.Enqueue(item); } else { tokens.Insert(number - tokensParsed, item); } } } private void FetchAnchor(bool isAlias) { SaveSimpleKey(); simpleKeyAllowed = false; tokens.Enqueue(ScanAnchor(isAlias)); } private Token ScanAnchor(bool isAlias) { Mark start = cursor.Mark(); Skip(); bool flag = false; if (isAlias) { SimpleKey simpleKey = simpleKeys.Peek(); flag = simpleKey.IsRequired && simpleKey.IsPossible; } StringBuilder stringBuilder = new StringBuilder(); while (!analyzer.IsWhiteBreakOrZero() && !analyzer.Check("[]{},") && (!flag || !analyzer.Check(':') || !analyzer.IsWhiteBreakOrZero(1))) { stringBuilder.Append(ReadCurrentCharacter()); } if (stringBuilder.Length == 0 || (!analyzer.IsWhiteBreakOrZero() && !analyzer.Check("?:,]}%@`"))) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning an anchor or alias, found value containing disallowed: []{},"); } AnchorName value = new AnchorName(stringBuilder.ToString()); if (isAlias) { return new YamlDotNet.Core.Tokens.AnchorAlias(value, start, cursor.Mark()); } return previousAnchor = new Anchor(value, start, cursor.Mark()); } private void FetchTag() { SaveSimpleKey(); simpleKeyAllowed = false; tokens.Enqueue(ScanTag()); } private Token ScanTag() { Mark start = cursor.Mark(); string text; string text2; if (analyzer.Check('<', 1)) { text = string.Empty; Skip(); Skip(); text2 = ScanTagUri(null, start); if (!analyzer.Check('>')) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a tag, did not find the expected '>'."); } Skip(); } else { string text3 = ScanTagHandle(isDirective: false, start); if (text3.Length > 1 && text3[0] == '!' && text3[text3.Length - 1] == '!') { text = text3; text2 = ScanTagUri(null, start); } else { text2 = ScanTagUri(text3, start); text = "!"; if (text2.Length == 0) { text2 = text; text = string.Empty; } } } if (!analyzer.IsWhiteBreakOrZero() && !analyzer.Check(',')) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a tag, did not find expected whitespace, comma or line break."); } return new Tag(text, text2, start, cursor.Mark()); } private void FetchBlockScalar(bool isLiteral) { RemoveSimpleKey(); simpleKeyAllowed = true; tokens.Enqueue(ScanBlockScalar(isLiteral)); } private Token ScanBlockScalar(bool isLiteral) { StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = new StringBuilder(); StringBuilder stringBuilder3 = new StringBuilder(); int num = 0; int num2 = 0; int currentIndent = 0; bool flag = false; bool? isFirstLine = null; Mark start = cursor.Mark(); Skip(); if (analyzer.Check("+-")) { num = (analyzer.Check('+') ? 1 : (-1)); Skip(); if (analyzer.IsDigit()) { if (analyzer.Check('0')) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a block scalar, found an indentation indicator equal to 0."); } num2 = analyzer.AsDigit(); Skip(); } } else if (analyzer.IsDigit()) { if (analyzer.Check('0')) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a block scalar, found an indentation indicator equal to 0."); } num2 = analyzer.AsDigit(); Skip(); if (analyzer.Check("+-")) { num = (analyzer.Check('+') ? 1 : (-1)); Skip(); } } if (analyzer.Check('#')) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a block scalar, found a comment without whtespace after '>' indicator."); } while (analyzer.IsWhite()) { Skip(); } ProcessComment(); if (!analyzer.IsBreakOrZero()) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a block scalar, did not find expected comment or line break."); } if (analyzer.IsBreak()) { SkipLine(); if (!isFirstLine.HasValue) { isFirstLine = true; } else if (isFirstLine == true) { isFirstLine = false; } } Mark end = cursor.Mark(); if (num2 != 0) { currentIndent = ((indent >= 0) ? (indent + num2) : num2); } currentIndent = ScanBlockScalarBreaks(currentIndent, stringBuilder3, isLiteral, ref end, ref isFirstLine); isFirstLine = false; while (cursor.LineOffset == currentIndent && !analyzer.IsZero() && !IsDocumentEnd()) { bool flag2 = analyzer.IsWhite(); if (!isLiteral && StartsWith(stringBuilder2, '\n') && !flag && !flag2) { if (stringBuilder3.Length == 0) { stringBuilder.Append(' '); } stringBuilder2.Length = 0; } else { stringBuilder.Append(stringBuilder2.ToString()); stringBuilder2.Length = 0; } stringBuilder.Append(stringBuilder3.ToString()); stringBuilder3.Length = 0; flag = analyzer.IsWhite(); while (!analyzer.IsBreakOrZero()) { stringBuilder.Append(ReadCurrentCharacter()); } char c = ReadLine(); if (c != 0) { stringBuilder2.Append(c); } currentIndent = ScanBlockScalarBreaks(currentIndent, stringBuilder3, isLiteral, ref end, ref isFirstLine); } if (num != -1) { stringBuilder.Append((object?)stringBuilder2); } if (num == 1) { stringBuilder.Append((object?)stringBuilder3); } ScalarStyle style = (isLiteral ? ScalarStyle.Literal : ScalarStyle.Folded); return new YamlDotNet.Core.Tokens.Scalar(stringBuilder.ToString(), style, start, end); } private int ScanBlockScalarBreaks(int currentIndent, StringBuilder breaks, bool isLiteral, ref Mark end, ref bool? isFirstLine) { int num = 0; int num2 = -1; end = cursor.Mark(); while (true) { if ((currentIndent == 0 || cursor.LineOffset < currentIndent) && analyzer.IsSpace()) { Skip(); continue; } if (cursor.LineOffset > num) { num = cursor.LineOffset; } if (!analyzer.IsBreak()) { break; } if (isFirstLine == true) { isFirstLine = false; num2 = cursor.LineOffset; } breaks.Append(ReadLine()); end = cursor.Mark(); } if (isLiteral && isFirstLine == true) { int num3 = cursor.LineOffset; int num4 = 0; while (!analyzer.IsBreak(num4) && analyzer.IsSpace(num4)) { num4++; num3++; } if (analyzer.IsBreak(num4) && num3 > cursor.LineOffset) { isFirstLine = false; num2 = num3; } } if (isLiteral && num2 > 1 && currentIndent < num2 - 1) { throw new SemanticErrorException(end, cursor.Mark(), "While scanning a literal block scalar, found extra spaces in first line."); } if (!isLiteral && num > cursor.LineOffset && num2 > -1) { throw new SemanticErrorException(end, cursor.Mark(), "While scanning a literal block scalar, found more spaces in lines above first content line."); } if (currentIndent == 0 && (cursor.LineOffset > 0 || indent > -1)) { currentIndent = Math.Max(num, Math.Max(indent + 1, 1)); } return currentIndent; } private void FetchFlowScalar(bool isSingleQuoted) { SaveSimpleKey(); simpleKeyAllowed = false; tokens.Enqueue(ScanFlowScalar(isSingleQuoted)); if (!isSingleQuoted && analyzer.Check('#')) { Mark mark = cursor.Mark(); tokens.Enqueue(new Error("While scanning a flow sequence end, found invalid comment after double-quoted scalar.", mark, mark)); } } private Token ScanFlowScalar(bool isSingleQuoted) { Mark start = cursor.Mark(); Skip(); StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = new StringBuilder(); StringBuilder stringBuilder3 = new StringBuilder(); StringBuilder stringBuilder4 = new StringBuilder(); bool flag = false; while (true) { if (IsDocumentIndicator()) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a quoted scalar, found unexpected document indicator."); } if (analyzer.IsZero()) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a quoted scalar, found unexpected end of stream."); } if (flag && !isSingleQuoted && indent >= cursor.LineOffset) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a multi-line double-quoted scalar, found wrong indentation."); } flag = false; while (!analyzer.IsWhiteBreakOrZero()) { if (isSingleQuoted && analyzer.Check('\'') && analyzer.Check('\'', 1)) { stringBuilder.Append('\''); Skip(); Skip(); continue; } if (analyzer.Check(isSingleQuoted ? '\'' : '"')) { break; } if (!isSingleQuoted && analyzer.Check('\\') && analyzer.IsBreak(1)) { Skip(); SkipLine(); flag = true; break; } if (!isSingleQuoted && analyzer.Check('\\')) { int num = 0; char c = analyzer.Peek(1); switch (c) { case 'x': num = 2; break; case 'u': num = 4; break; case 'U': num = 8; break; default: { if (SimpleEscapeCodes.TryGetValue(c, out var value)) { stringBuilder.Append(value); break; } throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a quoted scalar, found unknown escape character."); } } Skip(); Skip(); if (num <= 0) { continue; } int num2 = 0; for (int i = 0; i < num; i++) { if (!analyzer.IsHex(i)) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a quoted scalar, did not find expected hexadecimal number."); } num2 = (num2 << 4) + analyzer.AsHex(i); } if ((num2 >= 55296 && num2 <= 57343) || num2 > 1114111) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a quoted scalar, found invalid Unicode character escape code."); } stringBuilder.Append(char.ConvertFromUtf32(num2)); for (int j = 0; j < num; j++) { Skip(); } } else { stringBuilder.Append(ReadCurrentCharacter()); } } if (analyzer.Check(isSingleQuoted ? '\'' : '"')) { break; } while (analyzer.IsWhite() || analyzer.IsBreak()) { if (analyzer.IsWhite()) { if (!flag) { stringBuilder2.Append(ReadCurrentCharacter()); } else { Skip(); } } else if (!flag) { stringBuilder2.Length = 0; stringBuilder3.Append(ReadLine()); flag = true; } else { stringBuilder4.Append(ReadLine()); } } if (flag) { if (StartsWith(stringBuilder3, '\n')) { if (stringBuilder4.Length == 0) { stringBuilder.Append(' '); } else { stringBuilder.Append(stringBuilder4.ToString()); } } else { stringBuilder.Append(stringBuilder3.ToString()); stringBuilder.Append(stringBuilder4.ToString()); } stringBuilder3.Length = 0; stringBuilder4.Length = 0; } else { stringBuilder.Append(stringBuilder2.ToString()); stringBuilder2.Length = 0; } } Skip(); return new YamlDotNet.Core.Tokens.Scalar(stringBuilder.ToString(), isSingleQuoted ? ScalarStyle.SingleQuoted : ScalarStyle.DoubleQuoted, start, cursor.Mark()); } private void FetchPlainScalar() { SaveSimpleKey(); simpleKeyAllowed = false; bool isMultiline = false; YamlDotNet.Core.Tokens.Scalar item = ScanPlainScalar(ref isMultiline); if (isMultiline && analyzer.Check(':') && flowLevel == 0 && indent < cursor.LineOffset) { tokens.Enqueue(new Error("While scanning a multiline plain scalar, found invalid mapping.", cursor.Mark(), cursor.Mark())); } tokens.Enqueue(item); } private YamlDotNet.Core.Tokens.Scalar ScanPlainScalar(ref bool isMultiline) { StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = new StringBuilder(); StringBuilder stringBuilder3 = new StringBuilder(); StringBuilder stringBuilder4 = new StringBuilder(); bool flag = false; int num = indent + 1; Mark mark = cursor.Mark(); Mark end = mark; SimpleKey simpleKey = simpleKeys.Peek(); while (!IsDocumentIndicator()) { if (analyzer.Check('#')) { if (indent < 0 && flowLevel == 0) { plainScalarFollowedByComment = true; } break; } bool flag2 = analyzer.Check('*') && (!simpleKey.IsPossible || !simpleKey.IsRequired); while (!analyzer.IsWhiteBreakOrZero()) { if ((analyzer.Check(':') && !flag2 && (analyzer.IsWhiteBreakOrZero(1) || (flowLevel > 0 && analyzer.Check(',', 1)))) || (flowLevel > 0 && analyzer.Check(",?[]{}"))) { if (flowLevel == 0 && !simpleKey.IsPossible) { tokens.Enqueue(new Error("While scanning a plain scalar value, found invalid mapping.", cursor.Mark(), cursor.Mark())); } break; } if (flag || stringBuilder2.Length > 0) { if (flag) { if (StartsWith(stringBuilder3, '\n')) { if (stringBuilder4.Length == 0) { stringBuilder.Append(' '); } else { stringBuilder.Append((object?)stringBuilder4); } } else { stringBuilder.Append((object?)stringBuilder3); stringBuilder.Append((object?)stringBuilder4); } stringBuilder3.Length = 0; stringBuilder4.Length = 0; flag = false; } else { stringBuilder.Append((object?)stringBuilder2); stringBuilder2.Length = 0; } } if (flowLevel > 0 && cursor.LineOffset < num) { throw new Exception(); } stringBuilder.Append(ReadCurrentCharacter()); end = cursor.Mark(); } if (!analyzer.IsWhite() && !analyzer.IsBreak()) { break; } while (analyzer.IsWhite() || analyzer.IsBreak()) { if (analyzer.IsWhite()) { if (flag && cursor.LineOffset < num && analyzer.IsTab()) { throw new SyntaxErrorException(mark, cursor.Mark(), "While scanning a plain scalar, found a tab character that violate indentation."); } if (!flag) { stringBuilder2.Append(ReadCurrentCharacter()); } else { Skip(); } } else { isMultiline = true; if (!flag) { stringBuilder2.Length = 0; stringBuilder3.Append(ReadLine()); flag = true; } else { stringBuilder4.Append(ReadLine()); } } } if (flowLevel == 0 && cursor.LineOffset < num) { break; } } if (flag) { simpleKeyAllowed = true; } return new YamlDotNet.Core.Tokens.Scalar(stringBuilder.ToString(), ScalarStyle.Plain, mark, end); } private void RemoveSimpleKey() { SimpleKey simpleKey = simpleKeys.Peek(); if (simpleKey.IsPossible && simpleKey.IsRequired) { throw new SyntaxErrorException(simpleKey.Mark, simpleKey.Mark, "While scanning a simple key, could not find expected ':'."); } simpleKey.MarkAsImpossible(); } private string ScanDirectiveName(Mark start) { StringBuilder stringBuilder = new StringBuilder(); while (analyzer.IsAlphaNumericDashOrUnderscore()) { stringBuilder.Append(ReadCurrentCharacter()); } if (stringBuilder.Length == 0) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a directive, could not find expected directive name."); } if (!analyzer.IsWhiteBreakOrZero()) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a directive, found unexpected non-alphabetical character."); } return stringBuilder.ToString(); } private void SkipWhitespaces() { while (analyzer.IsWhite()) { Skip(); } } private Token ScanVersionDirectiveValue(Mark start) { SkipWhitespaces(); int major = ScanVersionDirectiveNumber(start); if (!analyzer.Check('.')) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a %YAML directive, did not find expected digit or '.' character."); } Skip(); int minor = ScanVersionDirectiveNumber(start); return new VersionDirective(new Version(major, minor), start, start); } private Token ScanTagDirectiveValue(Mark start) { SkipWhitespaces(); string handle = ScanTagHandle(isDirective: true, start); if (!analyzer.IsWhite()) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a %TAG directive, did not find expected whitespace."); } SkipWhitespaces(); string prefix = ScanTagUri(null, start); if (!analyzer.IsWhiteBreakOrZero()) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a %TAG directive, did not find expected whitespace or line break."); } return new TagDirective(handle, prefix, start, start); } private string ScanTagUri(string? head, Mark start) { StringBuilder stringBuilder = new StringBuilder(); if (head != null && head.Length > 1) { stringBuilder.Append(head.Substring(1)); } while (analyzer.IsAlphaNumericDashOrUnderscore() || analyzer.Check(";/?:@&=+$.!~*'()[]%") || (analyzer.Check(',') && !analyzer.IsBreak(1))) { if (analyzer.Check('%')) { stringBuilder.Append(ScanUriEscapes(start)); } else if (analyzer.Check('+')) { stringBuilder.Append(' '); Skip(); } else { stringBuilder.Append(ReadCurrentCharacter()); } } if (stringBuilder.Length == 0) { return string.Empty; } return stringBuilder.ToString(); } private string ScanUriEscapes(Mark start) { byte[] array = EmptyBytes; int count = 0; int num = 0; do { if (!analyzer.Check('%') || !analyzer.IsHex(1) || !analyzer.IsHex(2)) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a tag, did not find URI escaped octet."); } int num2 = (analyzer.AsHex(1) << 4) + analyzer.AsHex(2); if (num == 0) { num = (((num2 & 0x80) == 0) ? 1 : (((num2 & 0xE0) == 192) ? 2 : (((num2 & 0xF0) == 224) ? 3 : (((num2 & 0xF8) == 240) ? 4 : 0)))); if (num == 0) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a tag, found an incorrect leading UTF-8 octet."); } array = new byte[num]; } else if ((num2 & 0xC0) != 128) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a tag, found an incorrect trailing UTF-8 octet."); } array[count++] = (byte)num2; Skip(); Skip(); Skip(); } while (--num > 0); string @string = Encoding.UTF8.GetString(array, 0, count); if (@string.Length == 0 || @string.Length > 2) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a tag, found an incorrect UTF-8 sequence."); } return @string; } private string ScanTagHandle(bool isDirective, Mark start) { if (!analyzer.Check('!')) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a tag, did not find expected '!'."); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(ReadCurrentCharacter()); while (analyzer.IsAlphaNumericDashOrUnderscore()) { stringBuilder.Append(ReadCurrentCharacter()); } if (analyzer.Check('!')) { stringBuilder.Append(ReadCurrentCharacter()); } else if (isDirective && (stringBuilder.Length != 1 || stringBuilder[0] != '!')) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a tag directive, did not find expected '!'."); } return stringBuilder.ToString(); } private int ScanVersionDirectiveNumber(Mark start) { int num = 0; int num2 = 0; while (analyzer.IsDigit()) { if (++num2 > 9) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a %YAML directive, found extremely long version number."); } num = num * 10 + analyzer.AsDigit(); Skip(); } if (num2 == 0) { throw new SyntaxErrorException(start, cursor.Mark(), "While scanning a %YAML directive, did not find expected version number."); } return num; } private void SaveSimpleKey() { bool isRequired = flowLevel == 0 && indent == cursor.LineOffset; if (simpleKeyAllowed) { SimpleKey item = new SimpleKey(isRequired, tokensParsed + tokens.Count, cursor); RemoveSimpleKey(); simpleKeys.Pop(); simpleKeys.Push(item); } } } internal class SemanticErrorException : YamlException { public SemanticErrorException(string message) : base(message) { } public SemanticErrorException(Mark start, Mark end, string message) : base(start, end, message) { } public SemanticErrorException(string message, Exception inner) : base(message, inner) { } } internal sealed class SimpleKey { private readonly Cursor cursor; public bool IsPossible { get; private set; } public bool IsRequired { get; } public int TokenNumber { get; } public int Index => cursor.Index; public int Line => cursor.Line; public int LineOffset => cursor.LineOffset; public Mark Mark => cursor.Mark(); public void MarkAsImpossible() { IsPossible = false; } public SimpleKey() { cursor = new Cursor(); } public SimpleKey(bool isRequired, int tokenNumber, Cursor cursor) { IsPossible = true; IsRequired = isRequired; TokenNumber = tokenNumber; this.cursor = new Cursor(cursor); } } internal sealed class StringLookAheadBuffer : ILookAheadBuffer { private readonly string value; public int Position { get; private set; } public int Length => value.Length; public bool EndOfInput => IsOutside(Position); public StringLookAheadBuffer(string value) { this.value = value; } public char Peek(int offset) { int index = Position + offset; if (!IsOutside(index)) { return value[index]; } return '\0'; } private bool IsOutside(int index) { return index >= value.Length; } public void Skip(int length) { if (length < 0) { throw new ArgumentOutOfRangeException("length", "The length must be positive."); } Position += length; } } internal sealed class SyntaxErrorException : YamlException { public SyntaxErrorException(string message) : base(message) { } public SyntaxErrorException(Mark start, Mark end, string message) : base(start, end, message) { } public SyntaxErrorException(string message, Exception inner) : base(message, inner) { } } internal sealed class TagDirectiveCollection : KeyedCollection { public TagDirectiveCollection() { } public TagDirectiveCollection(IEnumerable tagDirectives) { foreach (TagDirective tagDirective in tagDirectives) { Add(tagDirective); } } protected override string GetKeyForItem(TagDirective item) { return item.Handle; } public new bool Contains(TagDirective directive) { return Contains(GetKeyForItem(directive)); } } internal struct TagName : IEquatable { public static readonly TagName Empty; private readonly string? value; public string Value => value ?? throw new InvalidOperationException("Cannot read the Value of a non-specific tag"); public bool IsEmpty => value == null; public bool IsNonSpecific { get { if (!IsEmpty) { if (!(value == "!")) { return value == "?"; } return true; } return false; } } public bool IsLocal { get { if (!IsEmpty) { return Value[0] == '!'; } return false; } } public bool IsGlobal { get { if (!IsEmpty) { return !IsLocal; } return false; } } public TagName(string value) { this.value = value ?? throw new ArgumentNullException("value"); if (value.Length == 0) { throw new ArgumentException("Tag value must not be empty.", "value"); } if (IsGlobal && !Uri.IsWellFormedUriString(value, UriKind.RelativeOrAbsolute)) { throw new ArgumentException("Global tags must be valid URIs.", "value"); } } public override string ToString() { return value ?? "?"; } public bool Equals(TagName other) { return object.Equals(value, other.value); } public override bool Equals(object? obj) { if (obj is TagName other) { return Equals(other); } return false; } public override int GetHashCode() { return value?.GetHashCode() ?? 0; } public static bool operator ==(TagName left, TagName right) { return left.Equals(right); } public static bool operator !=(TagName left, TagName right) { return !(left == right); } public static bool operator ==(TagName left, string right) { return object.Equals(left.value, right); } public static bool operator !=(TagName left, string right) { return !(left == right); } public static implicit operator TagName(string? value) { if (value != null) { return new TagName(value); } return Empty; } } internal sealed class Version { public int Major { get; } public int Minor { get; } public Version(int major, int minor) { if (major < 0) { throw new ArgumentOutOfRangeException("major", $"{major} should be >= 0"); } Major = major; if (minor < 0) { throw new ArgumentOutOfRangeException("minor", $"{minor} should be >= 0"); } Minor = minor; } public override bool Equals(object? obj) { if (obj is Version version && Major == version.Major) { return Minor == version.Minor; } return false; } public override int GetHashCode() { return HashCode.CombineHashCodes(Major.GetHashCode(), Minor.GetHashCode()); } } internal class YamlException : Exception { public Mark Start { get; } public Mark End { get; } public YamlException(string message) : this(Mark.Empty, Mark.Empty, message) { } public YamlException(Mark start, Mark end, string message) : this(start, end, message, null) { } public YamlException(Mark start, Mark end, string message, Exception? innerException) : base($"({start}) - ({end}): {message}", innerException) { Start = start; End = end; } public YamlException(string message, Exception inner) : this(Mark.Empty, Mark.Empty, message, inner) { } } } namespace YamlDotNet.Core.Tokens { internal class Anchor : Token { public AnchorName Value { get; } public Anchor(AnchorName value) : this(value, Mark.Empty, Mark.Empty) { } public Anchor(AnchorName value, Mark start, Mark end) : base(start, end) { if (value.IsEmpty) { throw new ArgumentNullException("value"); } Value = value; } } internal sealed class AnchorAlias : Token { public AnchorName Value { get; } public AnchorAlias(AnchorName value) : this(value, Mark.Empty, Mark.Empty) { } public AnchorAlias(AnchorName value, Mark start, Mark end) : base(start, end) { if (value.IsEmpty) { throw new ArgumentNullException("value"); } Value = value; } } internal sealed class BlockEnd : Token { public BlockEnd() : this(Mark.Empty, Mark.Empty) { } public BlockEnd(Mark start, Mark end) : base(start, end) { } } internal sealed class BlockEntry : Token { public BlockEntry() : this(Mark.Empty, Mark.Empty) { } public BlockEntry(Mark start, Mark end) : base(start, end) { } } internal sealed class BlockMappingStart : Token { public BlockMappingStart() : this(Mark.Empty, Mark.Empty) { } public BlockMappingStart(Mark start, Mark end) : base(start, end) { } } internal sealed class BlockSequenceStart : Token { public BlockSequenceStart() : this(Mark.Empty, Mark.Empty) { } public BlockSequenceStart(Mark start, Mark end) : base(start, end) { } } internal sealed class Comment : Token { public string Value { get; } public bool IsInline { get; } public Comment(string value, bool isInline) : this(value, isInline, Mark.Empty, Mark.Empty) { } public Comment(string value, bool isInline, Mark start, Mark end) : base(start, end) { Value = value ?? throw new ArgumentNullException("value"); IsInline = isInline; } } internal sealed class DocumentEnd : Token { public DocumentEnd() : this(Mark.Empty, Mark.Empty) { } public DocumentEnd(Mark start, Mark end) : base(start, end) { } } internal sealed class DocumentStart : Token { public DocumentStart() : this(Mark.Empty, Mark.Empty) { } public DocumentStart(Mark start, Mark end) : base(start, end) { } } internal class Error : Token { internal string Value { get; } internal Error(string value, Mark start, Mark end) : base(start, end) { Value = value; } } internal sealed class FlowEntry : Token { public FlowEntry() : this(Mark.Empty, Mark.Empty) { } public FlowEntry(Mark start, Mark end) : base(start, end) { } } internal sealed class FlowMappingEnd : Token { public FlowMappingEnd() : this(Mark.Empty, Mark.Empty) { } public FlowMappingEnd(Mark start, Mark end) : base(start, end) { } } internal sealed class FlowMappingStart : Token { public FlowMappingStart() : this(Mark.Empty, Mark.Empty) { } public FlowMappingStart(Mark start, Mark end) : base(start, end) { } } internal sealed class FlowSequenceEnd : Token { public FlowSequenceEnd() : this(Mark.Empty, Mark.Empty) { } public FlowSequenceEnd(Mark start, Mark end) : base(start, end) { } } internal sealed class FlowSequenceStart : Token { public FlowSequenceStart() : this(Mark.Empty, Mark.Empty) { } public FlowSequenceStart(Mark start, Mark end) : base(start, end) { } } internal sealed class Key : Token { public Key() : this(Mark.Empty, Mark.Empty) { } public Key(Mark start, Mark end) : base(start, end) { } } internal sealed class Scalar : Token { public string Value { get; } public ScalarStyle Style { get; } public Scalar(string value) : this(value, ScalarStyle.Any) { } public Scalar(string value, ScalarStyle style) : this(value, style, Mark.Empty, Mark.Empty) { } public Scalar(string value, ScalarStyle style, Mark start, Mark end) : base(start, end) { Value = value ?? throw new ArgumentNullException("value"); Style = style; } } internal sealed class StreamEnd : Token { public StreamEnd() : this(Mark.Empty, Mark.Empty) { } public StreamEnd(Mark start, Mark end) : base(start, end) { } } internal sealed class StreamStart : Token { public StreamStart() : this(Mark.Empty, Mark.Empty) { } public StreamStart(Mark start, Mark end) : base(start, end) { } } internal sealed class Tag : Token { public string Handle { get; } public string Suffix { get; } public Tag(string handle, string suffix) : this(handle, suffix, Mark.Empty, Mark.Empty) { } public Tag(string handle, string suffix, Mark start, Mark end) : base(start, end) { Handle = handle ?? throw new ArgumentNullException("handle"); Suffix = suffix ?? throw new ArgumentNullException("suffix"); } } internal class TagDirective : Token { private static readonly Regex TagHandlePattern = new Regex("^!([0-9A-Za-z_\\-]*!)?$", RegexOptions.Compiled); public string Handle { get; } public string Prefix { get; } public TagDirective(string handle, string prefix) : this(handle, prefix, Mark.Empty, Mark.Empty) { } public TagDirective(string handle, string prefix, Mark start, Mark end) : base(start, end) { if (string.IsNullOrEmpty(handle)) { throw new ArgumentNullException("handle", "Tag handle must not be empty."); } if (!TagHandlePattern.IsMatch(handle)) { throw new ArgumentException("Tag handle must start and end with '!' and contain alphanumerical characters only.", "handle"); } Handle = handle; if (string.IsNullOrEmpty(prefix)) { throw new ArgumentNullException("prefix", "Tag prefix must not be empty."); } Prefix = prefix; } public override bool Equals(object? obj) { if (obj is TagDirective tagDirective && Handle.Equals(tagDirective.Handle)) { return Prefix.Equals(tagDirective.Prefix); } return false; } public override int GetHashCode() { return Handle.GetHashCode() ^ Prefix.GetHashCode(); } public override string ToString() { return Handle + " => " + Prefix; } } internal abstract class Token { public Mark Start { get; } public Mark End { get; } protected Token(Mark start, Mark end) { Start = start ?? throw new ArgumentNullException("start"); End = end ?? throw new ArgumentNullException("end"); } } internal sealed class Value : Token { public Value() : this(Mark.Empty, Mark.Empty) { } public Value(Mark start, Mark end) : base(start, end) { } } internal sealed class VersionDirective : Token { public Version Version { get; } public VersionDirective(Version version) : this(version, Mark.Empty, Mark.Empty) { } public VersionDirective(Version version, Mark start, Mark end) : base(start, end) { Version = version; } public override bool Equals(object? obj) { if (obj is VersionDirective versionDirective) { return Version.Equals(versionDirective.Version); } return false; } public override int GetHashCode() { return Version.GetHashCode(); } } } namespace YamlDotNet.Core.Events { internal sealed class AnchorAlias : ParsingEvent { internal override EventType Type => EventType.Alias; public AnchorName Value { get; } public AnchorAlias(AnchorName value, Mark start, Mark end) : base(start, end) { if (value.IsEmpty) { throw new YamlException(start, end, "Anchor value must not be empty."); } Value = value; } public AnchorAlias(AnchorName value) : this(value, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Alias [value = {Value}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class Comment : ParsingEvent { public string Value { get; } public bool IsInline { get; } internal override EventType Type => EventType.Comment; public Comment(string value, bool isInline) : this(value, isInline, Mark.Empty, Mark.Empty) { } public Comment(string value, bool isInline, Mark start, Mark end) : base(start, end) { Value = value; IsInline = isInline; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } public override string ToString() { return (IsInline ? "Inline" : "Block") + " Comment [" + Value + "]"; } } internal sealed class DocumentEnd : ParsingEvent { public override int NestingIncrease => -1; internal override EventType Type => EventType.DocumentEnd; public bool IsImplicit { get; } public DocumentEnd(bool isImplicit, Mark start, Mark end) : base(start, end) { IsImplicit = isImplicit; } public DocumentEnd(bool isImplicit) : this(isImplicit, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Document end [isImplicit = {IsImplicit}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class DocumentStart : ParsingEvent { public override int NestingIncrease => 1; internal override EventType Type => EventType.DocumentStart; public TagDirectiveCollection? Tags { get; } public VersionDirective? Version { get; } public bool IsImplicit { get; } public DocumentStart(VersionDirective? version, TagDirectiveCollection? tags, bool isImplicit, Mark start, Mark end) : base(start, end) { Version = version; Tags = tags; IsImplicit = isImplicit; } public DocumentStart(VersionDirective? version, TagDirectiveCollection? tags, bool isImplicit) : this(version, tags, isImplicit, Mark.Empty, Mark.Empty) { } public DocumentStart(Mark start, Mark end) : this(null, null, isImplicit: true, start, end) { } public DocumentStart() : this(null, null, isImplicit: true, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Document start [isImplicit = {IsImplicit}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal enum EventType { None, StreamStart, StreamEnd, DocumentStart, DocumentEnd, Alias, Scalar, SequenceStart, SequenceEnd, MappingStart, MappingEnd, Comment } internal interface IParsingEventVisitor { void Visit(AnchorAlias e); void Visit(StreamStart e); void Visit(StreamEnd e); void Visit(DocumentStart e); void Visit(DocumentEnd e); void Visit(Scalar e); void Visit(SequenceStart e); void Visit(SequenceEnd e); void Visit(MappingStart e); void Visit(MappingEnd e); void Visit(Comment e); } internal class MappingEnd : ParsingEvent { public override int NestingIncrease => -1; internal override EventType Type => EventType.MappingEnd; public MappingEnd(Mark start, Mark end) : base(start, end) { } public MappingEnd() : this(Mark.Empty, Mark.Empty) { } public override string ToString() { return "Mapping end"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class MappingStart : NodeEvent { public override int NestingIncrease => 1; internal override EventType Type => EventType.MappingStart; public bool IsImplicit { get; } public override bool IsCanonical => !IsImplicit; public MappingStyle Style { get; } public MappingStart(AnchorName anchor, TagName tag, bool isImplicit, MappingStyle style, Mark start, Mark end) : base(anchor, tag, start, end) { IsImplicit = isImplicit; Style = style; } public MappingStart(AnchorName anchor, TagName tag, bool isImplicit, MappingStyle style) : this(anchor, tag, isImplicit, style, Mark.Empty, Mark.Empty) { } public MappingStart() : this(AnchorName.Empty, TagName.Empty, isImplicit: true, MappingStyle.Any, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Mapping start [anchor = {base.Anchor}, tag = {base.Tag}, isImplicit = {IsImplicit}, style = {Style}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal enum MappingStyle { Any, Block, Flow } internal abstract class NodeEvent : ParsingEvent { public AnchorName Anchor { get; } public TagName Tag { get; } public abstract bool IsCanonical { get; } protected NodeEvent(AnchorName anchor, TagName tag, Mark start, Mark end) : base(start, end) { Anchor = anchor; Tag = tag; } protected NodeEvent(AnchorName anchor, TagName tag) : this(anchor, tag, Mark.Empty, Mark.Empty) { } } internal abstract class ParsingEvent { public virtual int NestingIncrease => 0; internal abstract EventType Type { get; } public Mark Start { get; } public Mark End { get; } public abstract void Accept(IParsingEventVisitor visitor); internal ParsingEvent(Mark start, Mark end) { Start = start ?? throw new ArgumentNullException("start"); End = end ?? throw new ArgumentNullException("end"); } } internal sealed class Scalar : NodeEvent { internal override EventType Type => EventType.Scalar; public string Value { get; } public ScalarStyle Style { get; } public bool IsPlainImplicit { get; } public bool IsQuotedImplicit { get; } public override bool IsCanonical { get { if (!IsPlainImplicit) { return !IsQuotedImplicit; } return false; } } public Scalar(AnchorName anchor, TagName tag, string value, ScalarStyle style, bool isPlainImplicit, bool isQuotedImplicit, Mark start, Mark end) : base(anchor, tag, start, end) { Value = value; Style = style; IsPlainImplicit = isPlainImplicit; IsQuotedImplicit = isQuotedImplicit; } public Scalar(AnchorName anchor, TagName tag, string value, ScalarStyle style, bool isPlainImplicit, bool isQuotedImplicit) : this(anchor, tag, value, style, isPlainImplicit, isQuotedImplicit, Mark.Empty, Mark.Empty) { } public Scalar(string value) : this(AnchorName.Empty, TagName.Empty, value, ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: true, Mark.Empty, Mark.Empty) { } public Scalar(TagName tag, string value) : this(AnchorName.Empty, tag, value, ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: true, Mark.Empty, Mark.Empty) { } public Scalar(AnchorName anchor, TagName tag, string value) : this(anchor, tag, value, ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: true, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Scalar [anchor = {base.Anchor}, tag = {base.Tag}, value = {Value}, style = {Style}, isPlainImplicit = {IsPlainImplicit}, isQuotedImplicit = {IsQuotedImplicit}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class SequenceEnd : ParsingEvent { public override int NestingIncrease => -1; internal override EventType Type => EventType.SequenceEnd; public SequenceEnd(Mark start, Mark end) : base(start, end) { } public SequenceEnd() : this(Mark.Empty, Mark.Empty) { } public override string ToString() { return "Sequence end"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class SequenceStart : NodeEvent { public override int NestingIncrease => 1; internal override EventType Type => EventType.SequenceStart; public bool IsImplicit { get; } public override bool IsCanonical => !IsImplicit; public SequenceStyle Style { get; } public SequenceStart(AnchorName anchor, TagName tag, bool isImplicit, SequenceStyle style, Mark start, Mark end) : base(anchor, tag, start, end) { IsImplicit = isImplicit; Style = style; } public SequenceStart(AnchorName anchor, TagName tag, bool isImplicit, SequenceStyle style) : this(anchor, tag, isImplicit, style, Mark.Empty, Mark.Empty) { } public override string ToString() { return $"Sequence start [anchor = {base.Anchor}, tag = {base.Tag}, isImplicit = {IsImplicit}, style = {Style}]"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal enum SequenceStyle { Any, Block, Flow } internal sealed class StreamEnd : ParsingEvent { public override int NestingIncrease => -1; internal override EventType Type => EventType.StreamEnd; public StreamEnd(Mark start, Mark end) : base(start, end) { } public StreamEnd() : this(Mark.Empty, Mark.Empty) { } public override string ToString() { return "Stream end"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } internal sealed class StreamStart : ParsingEvent { public override int NestingIncrease => 1; internal override EventType Type => EventType.StreamStart; public StreamStart() : this(Mark.Empty, Mark.Empty) { } public StreamStart(Mark start, Mark end) : base(start, end) { } public override string ToString() { return "Stream start"; } public override void Accept(IParsingEventVisitor visitor) { visitor.Visit(this); } } }