Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CommunityPatchExtras v0.5.2
plugins/CommunityPatchExtras.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CommunityPatchExtras.Common; using CommunityPatchExtras.Patches; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using SimpleJson; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("CommunityPatchExtras")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CommunityPatchExtras")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.5.2")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.5.2.0")] namespace CommunityPatchExtras { internal static class ConfigFileWatcher { private class WatchEntry { internal DateTime LastWriteUTC; internal long FileLength; internal Action<string> Callback; } internal class ConfigFileWatcherBehaviour : MonoBehaviour { private float nextPollTime; public void Update() { if (!(Time.unscaledTime < nextPollTime)) { nextPollTime = Time.unscaledTime + PollInterval(); Poll(); } } private static float PollInterval() { if (ValConfig.ConfigPollIntervalSeconds == null) { return 30f; } return ValConfig.ConfigPollIntervalSeconds.Value; } private static void Poll() { if (WatchedFiles.Count == 0) { return; } string[] array = WatchedFiles.Keys.ToArray(); foreach (string text in array) { if (!WatchedFiles.TryGetValue(text, out var value) || !File.Exists(text)) { continue; } FileInfo fileInfo = new FileInfo(text); DateTime lastWriteTimeUtc = fileInfo.LastWriteTimeUtc; long length = fileInfo.Length; if (!(lastWriteTimeUtc == value.LastWriteUTC) || length != value.FileLength) { value.LastWriteUTC = lastWriteTimeUtc; value.FileLength = length; try { value.Callback?.Invoke(text); } catch (Exception ex) { Logger.LogWarning("ConfigFileWatcher callback for " + text + " threw: " + ex.Message); } } } } } private const float FallbackPollSeconds = 30f; private static readonly Dictionary<string, WatchEntry> WatchedFiles = new Dictionary<string, WatchEntry>(StringComparer.OrdinalIgnoreCase); private static ConfigFileWatcherBehaviour watchProcess; internal static void Initialize() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)watchProcess != (Object)null)) { GameObject val = new GameObject("ValheimCommunityPatchExtras_ConfigFileWatcher"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; watchProcess = val.AddComponent<ConfigFileWatcherBehaviour>(); Logger.LogDebug("ConfigFileWatcher initialized."); } } internal static void Register(string fullPath, Action<string> onChanged) { if (!string.IsNullOrEmpty(fullPath)) { DateTime lastWriteUTC = DateTime.MinValue; long fileLength = 0L; if (File.Exists(fullPath)) { FileInfo fileInfo = new FileInfo(fullPath); lastWriteUTC = fileInfo.LastWriteTimeUtc; fileLength = fileInfo.Length; } WatchedFiles[fullPath] = new WatchEntry { LastWriteUTC = lastWriteUTC, FileLength = fileLength, Callback = onChanged }; Logger.LogDebug("ConfigFileWatcher watching " + fullPath); } } internal static void RefreshStamp(string fullPath) { if (string.IsNullOrEmpty(fullPath) || !WatchedFiles.TryGetValue(fullPath, out var value)) { return; } try { FileInfo fileInfo = new FileInfo(fullPath); value.LastWriteUTC = fileInfo.LastWriteTimeUtc; value.FileLength = fileInfo.Length; } catch (Exception) { value.LastWriteUTC = DateTime.MinValue; value.FileLength = 0L; } } } internal static class ConfigNetwork { private static bool initialized; private static Harmony harmony; private static readonly HashSet<string> usedRpcNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private const byte EditProtocolVersion = 1; internal static bool ServerConfigsSynced { get; private set; } internal static event Action<YamlConfigFile, bool, string> EditResult; internal static void Init() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown if (initialized) { return; } initialized = true; SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized; try { harmony = new Harmony("MidnightsFX.ValheimCommunityPatchExtras.config"); harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNet), "Shutdown", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ConfigNetwork), "ResetOnWorldUnload", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception ex) { Logger.LogWarning("Could not patch ZNet.Shutdown for config sync teardown: " + ex.Message); } } internal static void RegisterFile(YamlConfigFile file) { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_00ea: Expected O, but got Unknown //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected O, but got Unknown //IL_01a5: Expected O, but got Unknown if (file == null || file.Sync == ConfigSyncMode.LocalOnly) { return; } if (string.IsNullOrEmpty(file.RpcName)) { file.RpcName = "ValheimCommunityPatchExtras_" + Path.GetFileNameWithoutExtension(file.FileName); } if (!usedRpcNames.Add(file.RpcName)) { Logger.LogError("Config RPC name '" + file.RpcName + "' is already in use; " + file.FileName + " will not be synced. Give it an explicit RpcName."); return; } file.Rpc = NetworkManager.Instance.AddRPC(file.RpcName, (CoroutineHandler)((long sender, ZPackage package) => OnServerReceive(file, sender, package)), (CoroutineHandler)((long sender, ZPackage package) => OnClientReceive(file, sender, package))); SynchronizationManager.Instance.AddInitialSynchronization(file.Rpc, (Func<ZPackage>)(() => SendFileAsZPackage(file))); if (!file.AllowAdminEdit) { return; } string text = file.RpcName + "_Edit"; if (!usedRpcNames.Add(text)) { Logger.LogError("Config RPC name '" + text + "' is already in use; " + file.FileName + " will not accept admin edits."); } else { file.EditRpc = NetworkManager.Instance.AddRPC(text, (CoroutineHandler)((long sender, ZPackage package) => OnServerReceiveEdit(file, sender, package)), (CoroutineHandler)((long sender, ZPackage package) => OnClientReceiveEditResult(file, sender, package))); } } internal static bool RequestEdit(YamlConfigFile file, string yaml, out string refusal) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown refusal = ""; if (file == null || file.EditRpc == null) { refusal = "this config cannot be edited remotely."; return false; } if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { refusal = "not connected to a server as a client."; return false; } if (SynchronizationManager.Instance != null && !SynchronizationManager.Instance.PlayerIsAdmin) { refusal = "only server admins can change this."; return false; } ZPackage val = new ZPackage(); val.Write((byte)1); val.Write(yaml); file.EditRpc.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), val); return true; } private static IEnumerator OnServerReceiveEdit(YamlConfigFile file, long sender, ZPackage package) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { yield break; } byte b = package.ReadByte(); if (b != 1) { SendEditResult(sender, file, accepted: false, $"This server expects edit protocol v{(byte)1}, " + $"the sender used v{b}. Update so both sides match."); yield break; } string yaml = package.ReadString(); string message; if (!SenderIsAdmin(sender)) { Logger.LogWarning($"Rejecting an edit of {file.FileName} from non-admin peer {sender}."); SendEditResult(sender, file, accepted: false, "Only server admins can change " + file.FileName + "."); } else if (!YamlConfigManager.ApplyEdited(file, yaml, out message)) { Logger.LogWarning($"Admin peer {sender} sent a {file.FileName} that was rejected: {message}"); SendEditResult(sender, file, accepted: false, message); } else { Logger.LogInfo($"{file.FileName} was replaced by admin peer {sender}."); SendEditResult(sender, file, accepted: true, message); yield return null; } } private static IEnumerator OnClientReceiveEditResult(YamlConfigFile file, long sender, ZPackage package) { if (package.ReadByte() != 1) { ConfigNetwork.EditResult?.Invoke(file, arg2: false, "The server answered with an edit protocol this build does not understand."); yield break; } bool arg = package.ReadBool(); string arg2 = package.ReadString(); ConfigNetwork.EditResult?.Invoke(file, arg, arg2); yield return null; } private static void SendEditResult(long peer, YamlConfigFile file, bool accepted, string message) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown if (file.EditRpc != null) { ZPackage val = new ZPackage(); val.Write((byte)1); val.Write(accepted); val.Write(message ?? ""); file.EditRpc.SendPackage(peer, val); } } internal static void Broadcast(YamlConfigFile file) { if (file != null && file.Rpc != null && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { file.Rpc.SendPackage(ZNet.instance.m_peers, SendFileAsZPackage(file)); } } internal static void ResetServerSyncState() { ServerConfigsSynced = false; } private static void OnConfigurationSynchronized(object sender, EventArgs e) { ServerConfigsSynced = true; } private static void ResetOnWorldUnload() { ResetServerSyncState(); } private static IEnumerator OnServerReceive(YamlConfigFile file, long sender, ZPackage package) { Logger.LogDebug($"Peer {sender} sent {file.FileName}; this config is server-authoritative, ignoring."); yield break; } private static IEnumerator OnClientReceive(YamlConfigFile file, long sender, ZPackage package) { string text = package.ReadString(); file.LoadFrom(text, ConfigOrigin.ServerSync); if (file.ClientWritesToDisk) { YamlConfigManager.WriteRawToDisk(file, text); } yield return null; } private static ZPackage SendFileAsZPackage(YamlConfigFile file) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); try { val.Write(File.Exists(file.Path) ? File.ReadAllText(file.Path) : file.SerializeCurrent()); } catch (Exception ex) { Logger.LogError("Could not read " + file.FileName + " to send to peers: " + ex.Message); val.Write(""); } return val; } internal static bool SenderIsAdmin(long sender) { ZNet instance = ZNet.instance; ZNetPeer val = ((instance != null) ? instance.GetPeer(sender) : null); if (val == null || val.m_socket == null) { return false; } return ZNet.instance.IsAdmin(val.m_socket.GetHostName()); } } internal class ValidationReport { internal readonly List<string> Warnings = new List<string>(); internal readonly List<string> Errors = new List<string>(); internal bool HasErrors => Errors.Count > 0; internal ValidationReport Warn(string message) { Warnings.Add(message); return this; } internal ValidationReport Error(string message) { Errors.Add(message); return this; } internal ValidationReport Absorb(ValidationReport other) { if (other == null) { return this; } Warnings.AddRange(other.Warnings); Errors.AddRange(other.Errors); return this; } } internal static class ConfigValidation { internal static float Prefer(float bepInExValue, float yamlValue, float sentinel = 0f) { if (bepInExValue != sentinel) { return bepInExValue; } return yamlValue; } internal static string SuggestKey(string unknownKey, IEnumerable<string> knownKeys) { if (string.IsNullOrEmpty(unknownKey) || knownKeys == null) { return ""; } int num = Math.Max(1, unknownKey.Length / 4); string text = null; int num2 = int.MaxValue; foreach (string knownKey in knownKeys) { if (!string.IsNullOrEmpty(knownKey)) { int num3 = Distance(unknownKey, knownKey); if (num3 < num2) { num2 = num3; text = knownKey; } } } if (text == null || num2 > num) { return ""; } return " Did you mean '" + text + "'?"; } private static int Distance(string a, string b) { a = a.ToLowerInvariant(); b = b.ToLowerInvariant(); if (a == b) { return 0; } if (a.Length == 0) { return b.Length; } if (b.Length == 0) { return a.Length; } int[] array = new int[b.Length + 1]; int[] array2 = new int[b.Length + 1]; for (int i = 0; i <= b.Length; i++) { array[i] = i; } for (int j = 1; j <= a.Length; j++) { array2[0] = j; for (int k = 1; k <= b.Length; k++) { int num = ((a[j - 1] != b[k - 1]) ? 1 : 0); array2[k] = Math.Min(Math.Min(array2[k - 1] + 1, array[k] + 1), array[k - 1] + num); } int[] array3 = array; array = array2; array2 = array3; } return array[b.Length]; } } internal static class YamlConfigManager { internal static YamlConfigFile<ExampleSettings> ExampleFile; internal static YamlConfigFile<Dictionary<string, int>> ExampleSavedDataFile; private const string ExampleHeader = "#################################################\n# CommunityPatchExtras - Example settings\n#\n# Entries is a map of <key>: <entry>. The key is the identity used elsewhere in this mod, so\n# renaming one is a breaking change; DisplayName is only a label and is safe to change.\n#\n# DisplayName string Shown to the player.\n# Multiplier float Scales the thing. 1.0 is unchanged. Range 0.1 - 10.\n# Mode enum Off | Add | Multiply\n# Prefabs list Prefab names this entry applies to. Unknown names are warned about\n# and skipped, they do not break the file.\n#\n# A typo in a key or an enum value costs you that one setting and logs a warning naming the\n# line; the rest of the file still loads.\n#################################################"; private static bool initialized; private static readonly List<YamlConfigFile> Files = new List<YamlConfigFile>(); private static readonly Dictionary<string, YamlConfigFile> ByPath = new Dictionary<string, YamlConfigFile>(StringComparer.OrdinalIgnoreCase); internal static IEnumerable<YamlConfigFile> All => Files; private static void RegisterConfigFiles() { RegisterExampleConfigs(); } private static void RegisterExampleConfigs() { ExampleFile = Register(new YamlConfigFile<ExampleSettings>("ExampleSettings.yaml") { Header = "#################################################\n# CommunityPatchExtras - Example settings\n#\n# Entries is a map of <key>: <entry>. The key is the identity used elsewhere in this mod, so\n# renaming one is a breaking change; DisplayName is only a label and is safe to change.\n#\n# DisplayName string Shown to the player.\n# Multiplier float Scales the thing. 1.0 is unchanged. Range 0.1 - 10.\n# Mode enum Off | Add | Multiply\n# Prefabs list Prefab names this entry applies to. Unknown names are warned about\n# and skipped, they do not break the file.\n#\n# A typo in a key or an enum value costs you that one setting and logs a warning naming the\n# line; the rest of the file still loads.\n#################################################", Defaults = () => ExampleData.BuildDefaults(), Apply = delegate(ExampleSettings parsed) { ExampleData.Current = parsed; }, Validate = ExampleData.Validate, NeedsPrefabs = true, SchemaVersion = 1, GetSchemaVersion = (ExampleSettings settings) => settings.Version, SetSchemaVersion = delegate(ExampleSettings settings, int version) { settings.Version = version; } }); ExampleSavedDataFile = Register(new YamlConfigFile<Dictionary<string, int>>("ExampleSavedData.yaml") { SubFolder = "SavedData", Header = "# Save data written by this mod. Edit it with the game closed.", Defaults = () => new Dictionary<string, int>(), Apply = delegate(Dictionary<string, int> parsed) { ExampleData.SavedCounters = parsed; }, Sync = ConfigSyncMode.LocalOnly, Watch = false }); Register(new YamlConfigFile<Dictionary<string, ExampleEntry>>("ExampleLegacyFormat.yaml") { Header = "# A config kept in its original camelCase form for backwards compatibility.", Format = YamlFormat.CamelCase, Defaults = () => new Dictionary<string, ExampleEntry>(), Apply = delegate(Dictionary<string, ExampleEntry> parsed) { ExampleData.LegacyEntries = parsed; }, ClientWritesToDisk = true }); } internal static void Init() { if (!initialized) { initialized = true; ConfigNetwork.Init(); YamlFormat.AddTypeConverter((IYamlTypeConverter)(object)new TolerantEnumConverter()); RegisterConfigFiles(); ConfigFileWatcher.Initialize(); Logger.LogDebug($"Registered {Files.Count} yaml config files."); } } internal static TFile Register<TFile>(TFile file) where TFile : YamlConfigFile { if (file == null) { return null; } Files.Add(file); if (initialized) { Prepare(file); } return file; } internal static YamlConfigFile Find(string fileNameOrPath) { if (string.IsNullOrEmpty(fileNameOrPath)) { return null; } if (ByPath.TryGetValue(fileNameOrPath, out var value)) { return value; } for (int i = 0; i < Files.Count; i++) { if (string.Equals(Files[i].FileName, fileNameOrPath, StringComparison.OrdinalIgnoreCase)) { return Files[i]; } } return null; } internal static string ConfigDirectory(string subFolder = null) { string text = Path.Combine(Paths.ConfigPath, ValConfig.cfgFolder); if (!string.IsNullOrEmpty(subFolder)) { text = Path.Combine(text, subFolder); } return Directory.CreateDirectory(text).FullName; } internal static void ReloadFromDisk(YamlConfigFile file, bool broadcast = true) { if (file == null) { return; } try { if (!File.Exists(file.Path)) { Logger.LogWarning(file.FileName + " is no longer on disk; rewriting it with this mod's built-in defaults."); RestoreDefaults(file); } if (file.LoadFrom(File.ReadAllText(file.Path), ConfigOrigin.LocalFile) && broadcast) { ConfigNetwork.Broadcast(file); } } catch (Exception ex) { Logger.LogError("Could not reload " + file.FileName + ": " + ex.Message); } } internal static bool ApplyEdited(YamlConfigFile file, string yaml, out string message) { message = ""; if (file == null) { message = "no config file was named"; return false; } if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { message = file.FileName + " belongs to the server; changes have to be sent to it."; return false; } string parseError; ValidationReport validationReport = file.DryRun(yaml, out parseError); if (parseError != null) { message = file.FileName + " was rejected because " + parseError + "."; return false; } if (validationReport.HasErrors) { message = string.Join(" ", validationReport.Errors.ToArray()); return false; } if (!file.LoadFrom(yaml, ConfigOrigin.Api)) { message = file.LastError ?? (file.FileName + " could not be applied."); return false; } WriteRawToDisk(file, yaml); ConfigNetwork.Broadcast(file); message = ((validationReport.Warnings.Count == 0) ? "" : string.Join(" ", validationReport.Warnings.ToArray())); return true; } internal static string SerializeForEdit<T>(YamlConfigFile<T> file, T value) where T : class { if (file == null || value == null) { return ""; } return file.EffectiveFormat.Serializer.Serialize((object)value); } internal static void RestoreDefaults(YamlConfigFile file) { WriteRawToDisk(file, file?.SerializeDefaults()); } internal static void WriteCurrentToDisk(YamlConfigFile file) { WriteRawToDisk(file, file?.SerializeCurrent()); } internal static void WriteRawToDisk(YamlConfigFile file, string serializedYaml) { if (file == null || string.IsNullOrEmpty(file.Path)) { return; } try { Directory.CreateDirectory(Path.GetDirectoryName(file.Path)); using (StreamWriter streamWriter = new StreamWriter(file.Path)) { if (!string.IsNullOrEmpty(file.Header)) { streamWriter.WriteLine(file.Header); } streamWriter.WriteLine(serializedYaml); } ConfigFileWatcher.RefreshStamp(file.Path); } catch (Exception ex) { Logger.LogError("Could not write " + file.FileName + ": " + ex.Message); } } internal static void RevalidateAll() { for (int i = 0; i < Files.Count; i++) { try { Files[i].Revalidate(); } catch (Exception ex) { Logger.LogError("Revalidating " + Files[i].FileName + " threw: " + ex.Message); } } } internal static bool HasNoUsableConfig(string yamlText) { if (string.IsNullOrWhiteSpace(yamlText)) { return true; } string[] array = yamlText.Split(new char[1] { '\n' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0 && !text.StartsWith("#") && !(text == "---") && !(text == "...")) { return false; } } return true; } private static void Prepare(YamlConfigFile file) { try { file.Path = Path.Combine(ConfigDirectory(file.SubFolder), file.FileName); ByPath[file.Path] = file; if (!File.Exists(file.Path)) { Logger.LogDebug(file.FileName + " missing, writing this mod's built-in defaults."); RestoreDefaults(file); } else if (HasNoUsableConfig(File.ReadAllText(file.Path))) { Logger.LogWarning(file.FileName + " was empty and has been overwritten with this mod's built-in defaults. File: " + file.Path); RestoreDefaults(file); } file.LoadFrom(File.Exists(file.Path) ? File.ReadAllText(file.Path) : "", ConfigOrigin.Startup); ConfigNetwork.RegisterFile(file); if (file.Watch) { ConfigFileWatcher.Register(file.Path, OnWatchedFileChanged); } } catch (Exception arg) { Logger.LogError($"Could not prepare {file.FileName}: {arg}"); } } private static void OnWatchedFileChanged(string path) { if (ByPath.TryGetValue(path, out var file)) { ConfigChangeDebouncer.Schedule(file, delegate { ReloadFromDisk(file); }); } } } public enum ExampleMode { Off, Add, Multiply } public class ExampleEntry { public string DisplayName { get; set; } [DefaultValue(1f)] public float Multiplier { get; set; } = 1f; public ExampleMode Mode { get; set; } public List<string> Prefabs { get; set; } = new List<string>(); } public class ExampleSettings { public int Version { get; set; } = 1; public Dictionary<string, ExampleEntry> Entries { get; set; } = new Dictionary<string, ExampleEntry>(); } internal static class ExampleData { internal static ExampleSettings Current = new ExampleSettings(); internal static Dictionary<string, int> SavedCounters = new Dictionary<string, int>(); internal static Dictionary<string, ExampleEntry> LegacyEntries = new Dictionary<string, ExampleEntry>(); internal static ExampleSettings BuildDefaults() { return new ExampleSettings { Version = 1, Entries = new Dictionary<string, ExampleEntry> { { "Example", new ExampleEntry { DisplayName = "An example", Multiplier = 1.5f, Mode = ExampleMode.Multiply } } } }; } internal static ValidationReport Validate(ExampleSettings next, ExampleSettings previous) { ValidationReport validationReport = new ValidationReport(); if (next.Entries == null || next.Entries.Count == 0) { return validationReport.Error("it defines no entries"); } foreach (KeyValuePair<string, ExampleEntry> entry in next.Entries) { if (entry.Value == null) { validationReport.Error("entry '" + entry.Key + "' has no settings under it"); continue; } if (entry.Value.Multiplier < 0.1f || entry.Value.Multiplier > 10f) { validationReport.Warn($"entry '{entry.Key}' has Multiplier {entry.Value.Multiplier}, outside the " + "supported range of 0.1 - 10. It will be used as written."); } if (entry.Value.Prefabs == null) { continue; } foreach (string prefab in entry.Value.Prefabs) { if (PrefabManager.Instance != null && (Object)(object)PrefabManager.Instance.GetPrefab(prefab) == (Object)null) { validationReport.Warn("entry '" + entry.Key + "' names prefab '" + prefab + "', which does not exist. That prefab will be skipped."); } } } if (previous != null && previous.Entries != null) { foreach (string key in previous.Entries.Keys) { if (!next.Entries.ContainsKey(key)) { validationReport.Warn("entry '" + key + "' was removed. Anything still referring to it will fall back."); } } } return validationReport; } } internal class TolerantEnumConverter : IYamlTypeConverter { private static readonly Dictionary<Type, object> fallbacks = new Dictionary<Type, object>(); internal static void SetFallback(Type enumType, object fallback) { if (!(enumType == null) && enumType.IsEnum) { fallbacks[enumType] = fallback; } } public bool Accepts(Type type) { if (type != null) { return type.IsEnum; } return false; } public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) Scalar val = ParserExtensions.Consume<Scalar>(parser); string value = val.Value; if (!string.IsNullOrWhiteSpace(value)) { try { return Enum.Parse(type, value.Trim(), ignoreCase: true); } catch (Exception) { } } object obj = FallbackFor(type); object[] array = new object[4]; Mark start = ((ParsingEvent)val).Start; array[0] = ((Mark)(ref start)).Line; array[1] = value; array[2] = type.Name; array[3] = obj; Logger.LogWarning(string.Format("line {0}: '{1}' is not a valid {2}. Using {3}. ", array) + "Valid values: " + string.Join(", ", Enum.GetNames(type)) + "."); return obj; } public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown emitter.Emit((ParsingEvent)new Scalar((value == null) ? "" : value.ToString())); } private static object FallbackFor(Type type) { if (fallbacks.TryGetValue(type, out var value)) { return value; } return Activator.CreateInstance(type); } } internal static class ConfigUI { internal class ConfigUIInputGuard : MonoBehaviour { private bool held; internal void Hold() { if (!held) { held = true; PushInputBlock(); } } public void OnDestroy() { if (held) { held = false; PopInputBlock(); } } } internal const float RowHeight = 34f; internal const float SubRowHeight = 26f; internal const float RowGap = 4f; internal const float CloseXSize = 28f; private static int inputBlockDepth; internal static void PushInputBlock() { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { inputBlockDepth++; if (inputBlockDepth == 1) { GUIManager.BlockInput(true); } } } internal static void PopInputBlock() { if (inputBlockDepth > 0) { inputBlockDepth--; if (inputBlockDepth == 0) { GUIManager.BlockInput(false); } } } internal static GameObject NewUI(string name, Transform parent, params Type[] components) { //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_000f: Expected O, but got Unknown GameObject val = new GameObject(name, components) { layer = 5 }; if ((Object)(object)val.GetComponent<RectTransform>() == (Object)null) { val.AddComponent<RectTransform>(); } val.transform.SetParent(parent, false); return val; } internal static GameObject NewRect(string name, Transform parent, float x, float y, float w, float h) { //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_0030: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) GameObject obj = NewUI(name, parent, typeof(RectTransform)); RectTransform val = (RectTransform)obj.transform; val.anchorMin = new Vector2(0f, 1f); val.anchorMax = new Vector2(0f, 1f); val.pivot = new Vector2(0f, 1f); val.sizeDelta = new Vector2(w, h); val.anchoredPosition = new Vector2(x, 0f - y); return obj; } internal static GameObject NewRow(Transform parent, float width, float height) { return NewRect("Row", parent, 0f, 0f, width, height); } internal static GameObject NewLayoutRow(Transform content, float width, float height) { //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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_0060: 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_0077: Unknown result type (might be due to invalid IL or missing references) GameObject obj = NewUI("LayoutRow", content, typeof(RectTransform), typeof(LayoutElement)); RectTransform val = (RectTransform)obj.transform; val.anchorMin = new Vector2(0f, 1f); val.anchorMax = new Vector2(0f, 1f); val.pivot = new Vector2(0f, 1f); val.sizeDelta = new Vector2(width, height); LayoutElement component = obj.GetComponent<LayoutElement>(); component.minHeight = height; component.preferredHeight = height; component.minWidth = width; component.preferredWidth = width; return obj; } internal static void LayoutColumn(List<GameObject> rows, float x, float startY, float gap = 4f) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) float num = startY; foreach (GameObject row in rows) { if (!((Object)(object)row == (Object)null) && row.activeSelf) { RectTransform val = (RectTransform)row.transform; val.anchoredPosition = new Vector2(x, 0f - num); num += val.sizeDelta.y + gap; } } } internal static void PositionRow(GameObject row, float x, float y) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)row == (Object)null)) { ((RectTransform)row.transform).anchoredPosition = new Vector2(x, 0f - y); } } internal static GameObject CreatePanel(string title, float w, float h, out Transform body) { //IL_0019: 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_0037: 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) GameObject val = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), w, h, true); val.AddComponent<ConfigUIInputGuard>().Hold(); AddText(val.transform, 0f, 16f, w, 34f, title, 22, (TextAnchor)4, GUIManager.Instance.ValheimYellow); body = val.transform; return val; } internal static GameObject CreateScroll(Transform parent, float x, float y, float w, float h, out Transform content, out float contentWidth) { //IL_002d: 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) GameObject val = NewRect("ScrollHolder", parent, x, y, w, h); GameObject val2 = GUIManager.Instance.CreateScrollView(val.transform, false, true, 8f, 4f, GUIManager.Instance.ValheimScrollbarHandleColorBlock, new Color(0f, 0f, 0f, 0.5f), w, h); content = val2.transform.Find("Scroll View/Viewport/Content"); contentWidth = w - 16f; ScrollRect componentInChildren = val2.GetComponentInChildren<ScrollRect>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.scrollSensitivity = 200f; } return val2; } internal static string L(string text) { if (string.IsNullOrEmpty(text)) { return ""; } if (Localization.instance == null) { return text; } return Localization.instance.Localize(text); } internal static Text AddText(Transform parent, float x, float y, float w, float h, string text, int fontSize, TextAnchor anchor, Color? color = null) { //IL_0017: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0073: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GUIManager.Instance.CreateText(L(text), parent, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, 0f - y), GUIManager.Instance.AveriaSerifBold, fontSize, (Color)(((??)color) ?? GUIManager.Instance.ValheimBeige), true, Color.black, w, h, false); RectTransform val = (RectTransform)obj.transform; val.pivot = new Vector2(0f, 1f); val.anchoredPosition = new Vector2(x, 0f - y); Text component = obj.GetComponent<Text>(); component.alignment = anchor; component.horizontalOverflow = (HorizontalWrapMode)0; component.verticalOverflow = (VerticalWrapMode)0; return component; } internal static GameObject AddHeaderRow(Transform parent, float colWidth, string text, TextAnchor anchor = (TextAnchor)3) { //IL_0025: 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) GameObject obj = NewRow(parent, colWidth, 34f); AddText(obj.transform, 0f, 0f, colWidth, 34f, text, 18, anchor, GUIManager.Instance.ValheimYellow); return obj; } internal static GameObject AddTextRow(Transform parent, float colWidth, float height, string text, int fontSize, Color color, TextAnchor anchor = (TextAnchor)0) { //IL_001d: 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) GameObject obj = NewRow(parent, colWidth, height); AddText(obj.transform, 0f, 0f, colWidth, height, text, fontSize, anchor, color); return obj; } internal static GameObject AddSpacerRow(Transform parent, float colWidth, float height) { return NewRow(parent, colWidth, height); } internal static GameObject AddDividerRow(Transform parent, float colWidth, float height = 12f) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0076: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) GameObject val = NewRow(parent, colWidth, height); GameObject obj = NewUI("Divider", val.transform, typeof(Image)); RectTransform val2 = (RectTransform)obj.transform; val2.anchorMin = new Vector2(0f, 1f); val2.anchorMax = new Vector2(0f, 1f); val2.pivot = new Vector2(0f, 1f); val2.sizeDelta = new Vector2(colWidth, 2f); val2.anchoredPosition = new Vector2(0f, 0f - height * 0.5f); Image component = obj.GetComponent<Image>(); ((Graphic)component).color = new Color(0.6f, 0.5f, 0.35f, 0.6f); ((Graphic)component).raycastTarget = false; return val; } internal static void SetMessages(Text target, IList<string> errors, IList<string> warnings) { if ((Object)(object)target == (Object)null) { return; } List<string> list = new List<string>(); if (errors != null) { foreach (string error in errors) { list.Add("<color=#F87171>" + error + "</color>"); } } if (warnings != null) { foreach (string warning in warnings) { list.Add("<color=#FBBF24>" + warning + "</color>"); } } target.text = string.Join("\n", list.ToArray()); } internal static GameObject AddButton(Transform parent, float x, float y, float w, string text, UnityAction onClick, float h = 40f) { //IL_0017: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_005f: Unknown result type (might be due to invalid IL or missing references) GameObject val = GUIManager.Instance.CreateButton(L(text), parent, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, 0f - y), w, h); RectTransform val2 = (RectTransform)val.transform; val2.pivot = new Vector2(0f, 1f); val2.anchoredPosition = new Vector2(x, 0f - y); if (onClick != null) { ((UnityEvent)val.GetComponent<Button>().onClick).AddListener(onClick); } return val; } internal static GameObject AddCloseX(Transform panel, float panelWidth, UnityAction onClick) { return AddButton(panel, panelWidth - 28f - 16f, 12f, 28f, "X", onClick, 28f); } internal static Toggle AddToggle(Transform parent, float x, float y, float size, bool value, Action<bool> onChange) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GUIManager.Instance.CreateToggle(parent, size, size); obj.transform.SetParent(parent, false); RectTransform val = (RectTransform)obj.transform; ((Transform)val).localScale = Vector3.one; val.anchorMin = new Vector2(0f, 1f); val.anchorMax = new Vector2(0f, 1f); val.pivot = new Vector2(0f, 1f); val.anchoredPosition = new Vector2(x, 0f - y); Toggle component = obj.GetComponent<Toggle>(); component.isOn = value; if (onChange != null) { ((UnityEvent<bool>)(object)component.onValueChanged).AddListener((UnityAction<bool>)delegate(bool b) { onChange(b); }); } return component; } internal static GameObject AddToggleRow(Transform parent, float colWidth, float labelW, string label, bool value, Action<bool> onChange, bool toggleOnLeft = false) { GameObject obj = NewRow(parent, colWidth, 34f); float x = (toggleOnLeft ? 0f : (labelW + 6f)); float x2 = (toggleOnLeft ? 34f : 0f); AddText(obj.transform, x2, 0f, labelW, 34f, label, 15, (TextAnchor)3); AddToggle(obj.transform, x, 3f, 26f, value, onChange); return obj; } internal static string Fmt(float v, bool whole) { if (!whole) { return v.ToString("0.00"); } return ((int)Mathf.Round(v)).ToString(); } internal static Slider BuildSlider(Transform parent, float x, float y, float width, float min, float max, float value, bool wholeNumbers) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0076: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: 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) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_023d: 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_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Expected O, but got Unknown //IL_02a3: Unknown result type (might be due to invalid IL or missing references) GameObject val = NewUI("Slider", parent, typeof(RectTransform), typeof(Slider)); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = new Vector2(0f, 1f); val2.anchorMax = new Vector2(0f, 1f); val2.pivot = new Vector2(0f, 1f); val2.sizeDelta = new Vector2(width, 20f); val2.anchoredPosition = new Vector2(x, 0f - y); GameObject obj = NewUI("Background", val.transform, typeof(Image)); RectTransform val3 = (RectTransform)obj.transform; val3.anchorMin = new Vector2(0f, 0.25f); val3.anchorMax = new Vector2(1f, 0.75f); val3.sizeDelta = Vector2.zero; val3.anchoredPosition = Vector2.zero; ((Graphic)obj.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.6f); GameObject val4 = NewUI("Fill Area", val.transform, typeof(RectTransform)); RectTransform val5 = (RectTransform)val4.transform; val5.anchorMin = new Vector2(0f, 0.25f); val5.anchorMax = new Vector2(1f, 0.75f); val5.sizeDelta = new Vector2(-20f, 0f); val5.anchoredPosition = Vector2.zero; GameObject obj2 = NewUI("Fill", val4.transform, typeof(Image)); RectTransform val6 = (RectTransform)obj2.transform; val6.sizeDelta = new Vector2(10f, 0f); ((Graphic)obj2.GetComponent<Image>()).color = new Color(0.7f, 0.6f, 0.4f, 0.9f); GameObject val7 = NewUI("Handle Slide Area", val.transform, typeof(RectTransform)); RectTransform val8 = (RectTransform)val7.transform; val8.anchorMin = Vector2.zero; val8.anchorMax = Vector2.one; val8.sizeDelta = new Vector2(-20f, 0f); val8.anchoredPosition = Vector2.zero; GameObject obj3 = NewUI("Handle", val7.transform, typeof(Image)); RectTransform val9 = (RectTransform)obj3.transform; val9.sizeDelta = new Vector2(20f, 0f); Image component = obj3.GetComponent<Image>(); component.sprite = GUIManager.Instance.GetSprite("checkbox_marker"); component.type = (Type)1; Slider component2 = val.GetComponent<Slider>(); component2.fillRect = val6; component2.handleRect = val9; ((Selectable)component2).targetGraphic = (Graphic)(object)component; component2.direction = (Direction)0; component2.minValue = min; component2.maxValue = max; component2.wholeNumbers = wholeNumbers; component2.value = Mathf.Clamp(value, min, max); GUIManager.Instance.ApplySliderStyle(component2); return component2; } internal static GameObject AddSliderRow(Transform parent, float colWidth, float labelW, float sliderW, float valueW, string label, float min, float max, float value, bool wholeNumbers, Action<float> onChange) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) GameObject val = NewRow(parent, colWidth, 34f); AddText(val.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3); Slider slider = BuildSlider(val.transform, labelW, 7f, sliderW, min, max, value, wholeNumbers); float num = labelW + sliderW + 10f; GameObject val2 = GUIManager.Instance.CreateInputField(val.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(num, -3f), (ContentType)(wholeNumbers ? 2 : 3), (string)null, 15, valueW, 28f); RectTransform val3 = (RectTransform)val2.transform; val3.pivot = new Vector2(0f, 1f); val3.anchoredPosition = new Vector2(num, -3f); InputField box = val2.GetComponent<InputField>(); box.SetTextWithoutNotify(Fmt(slider.value, wholeNumbers)); ((UnityEvent<float>)(object)slider.onValueChanged).AddListener((UnityAction<float>)delegate(float v) { if (wholeNumbers) { v = Mathf.Round(v); } box.SetTextWithoutNotify(Fmt(v, wholeNumbers)); onChange?.Invoke(v); }); ((UnityEvent<string>)(object)box.onEndEdit).AddListener((UnityAction<string>)delegate(string str) { if (!float.TryParse(str, out var result)) { result = slider.value; } result = Mathf.Clamp(result, min, max); if (wholeNumbers) { result = Mathf.Round(result); } box.SetTextWithoutNotify(Fmt(result, wholeNumbers)); if (slider.value != result) { slider.value = result; } else { onChange?.Invoke(result); } }); return val; } internal static InputField AddTextField(Transform parent, float x, float y, float w, string value, Action<string> onCommit, ContentType contentType = (ContentType)0, string placeholder = null, int charLimit = 0) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GUIManager.Instance.CreateInputField(parent, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, 0f - y), contentType, placeholder, 15, w, 28f); RectTransform val = (RectTransform)obj.transform; val.pivot = new Vector2(0f, 1f); val.anchoredPosition = new Vector2(x, 0f - y); InputField component = obj.GetComponent<InputField>(); if (charLimit > 0) { component.characterLimit = charLimit; } component.SetTextWithoutNotify(value ?? ""); if (onCommit != null) { ((UnityEvent<string>)(object)component.onEndEdit).AddListener((UnityAction<string>)delegate(string s) { onCommit(s); }); } return component; } internal static GameObject AddTextFieldRow(Transform parent, float colWidth, float labelW, float fieldW, string label, string value, Action<string> onCommit, string placeholder = null, int charLimit = 0) { GameObject obj = NewRow(parent, colWidth, 34f); AddText(obj.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3); AddTextField(obj.transform, labelW + 6f, 3f, fieldW, value, onCommit, (ContentType)0, placeholder, charLimit); return obj; } internal static GameObject AddEnumCycleRow(Transform parent, float colWidth, float labelW, float ctrlW, string label, string[] options, int currentIndex, Action<int> onChange) { //IL_009d: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown GameObject val = NewRow(parent, colWidth, 34f); AddText(val.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3); int idx = Mathf.Clamp(currentIndex, 0, Math.Max(0, options.Length - 1)); GameObject val2 = GUIManager.Instance.CreateButton((options.Length != 0) ? options[idx] : "", val.transform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(labelW + 6f, -2f), ctrlW, 28f); RectTransform val3 = (RectTransform)val2.transform; val3.pivot = new Vector2(0f, 1f); val3.anchoredPosition = new Vector2(labelW + 6f, -2f); Text caption = val2.GetComponentInChildren<Text>(); ((UnityEvent)val2.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { if (options.Length != 0) { idx = (idx + 1) % options.Length; caption.text = options[idx]; onChange?.Invoke(idx); } }); return val; } internal static GameObject AddEnumFlagsRow(Transform parent, float colWidth, float labelW, string label, string[] names, Func<int, bool> isOn, Action<int, bool> set) { GameObject val = NewRow(parent, colWidth, 34f); AddText(val.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3); float num = labelW + 6f; for (int i = 0; i < names.Length; i++) { int index = i; AddToggle(val.transform, num, 4f, 22f, isOn(index), delegate(bool on) { set(index, on); }); AddText(val.transform, num + 26f, 0f, 90f, 34f, names[index], 13, (TextAnchor)3); num += 120f; } return val; } internal static GameObject AddPickerRow(Transform parent, float colWidth, float labelW, float ctrlW, string label, string current, Func<IList<string>> options, Action<string> onPick, Func<string, bool> isKnown = null) { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Expected O, but got Unknown GameObject val = NewRow(parent, colWidth, 34f); AddText(val.transform, 0f, 0f, labelW, 34f, label, 15, (TextAnchor)3); float num = ctrlW - 40f; InputField field = AddTextField(val.transform, labelW + 6f, 3f, num, current, delegate(string s) { onPick?.Invoke(s); }, (ContentType)0); Text marker = AddText(val.transform, labelW + 6f + num + 44f, 0f, 20f, 34f, "", 15, (TextAnchor)3, (Color?)new Color(0.98f, 0.75f, 0.14f)); Action refreshMarker = delegate { bool flag = isKnown != null && !string.IsNullOrEmpty(field.text) && !isKnown(field.text); marker.text = (flag ? "!" : ""); }; refreshMarker(); ((UnityEvent<string>)(object)field.onEndEdit).AddListener((UnityAction<string>)delegate { refreshMarker(); }); AddButton(val.transform, labelW + 6f + num + 4f, 3f, 34f, "...", (UnityAction)delegate { string title = label; IList<string> options2; if (options == null) { IList<string> list = new List<string>(); options2 = list; } else { options2 = options(); } ConfigUIPicker.ShowPicker(title, options2, field.text, delegate(string picked) { field.SetTextWithoutNotify(picked); refreshMarker(); onPick?.Invoke(picked); }); }, 28f); return val; } internal static GameObject AddStringListEditor(Transform content, float width, string label, List<string> items, Action onChanged, Func<IList<string>> options = null, Func<string, bool> isKnown = null) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Expected O, but got Unknown //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown GameObject val = NewLayoutRow(content, width, 26f); AddText(val.transform, 0f, 0f, width - 90f, 26f, label, 14, (TextAnchor)3, GUIManager.Instance.ValheimOrange); AddButton(val.transform, width - 84f, 0f, 80f, "Add", (UnityAction)delegate { items.Add(""); onChanged?.Invoke(); }, 24f); for (int num = 0; num < items.Count; num++) { int index = num; GameObject val2 = NewLayoutRow(content, width, 26f); InputField field = AddTextField(val2.transform, 12f, 0f, width - 92f, items[index], delegate(string s) { items[index] = s; }, (ContentType)0); Text marker = AddText(val2.transform, width - 74f, 0f, 16f, 26f, "", 14, (TextAnchor)3, (Color?)new Color(0.98f, 0.75f, 0.14f)); Action refreshMarker = delegate { bool flag = isKnown != null && !string.IsNullOrEmpty(field.text) && !isKnown(field.text); marker.text = (flag ? "!" : ""); }; refreshMarker(); ((UnityEvent<string>)(object)field.onEndEdit).AddListener((UnityAction<string>)delegate { refreshMarker(); }); if (options != null) { AddButton(val2.transform, width - 56f, 0f, 26f, "...", (UnityAction)delegate { ConfigUIPicker.ShowPicker(label, options(), field.text, delegate(string picked) { field.SetTextWithoutNotify(picked); items[index] = picked; refreshMarker(); }); }, 24f); } AddButton(val2.transform, width - 26f, 0f, 24f, "x", (UnityAction)delegate { items.RemoveAt(index); onChanged?.Invoke(); }, 24f); } return val; } } internal static class ConfigUIPicker { private const float PanelW = 420f; private const float PanelH = 520f; private const float RowH = 30f; private const int MaxRows = 400; private static GameObject overlay; internal static bool IsOpen => (Object)(object)overlay != (Object)null; internal static void ShowPicker(string title, IList<string> options, string current, Action<string> onPick) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Expected O, but got Unknown Close(); if (GUIManager.Instance == null || (Object)(object)GUIManager.CustomGUIFront == (Object)null) { return; } List<string> all = new List<string>(); if (options != null) { foreach (string option in options) { if (!string.IsNullOrEmpty(option)) { all.Add(option); } } } all.Sort(StringComparer.OrdinalIgnoreCase); overlay = ConfigUI.NewUI("ConfigUIPickerOverlay", GUIManager.CustomGUIFront.transform, typeof(Image)); RectTransform val = (RectTransform)overlay.transform; val.anchorMin = Vector2.zero; val.anchorMax = Vector2.one; val.offsetMin = Vector2.zero; val.offsetMax = Vector2.zero; ((Graphic)overlay.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.35f); Button obj = overlay.AddComponent<Button>(); ((Selectable)obj).transition = (Transition)0; ((UnityEvent)obj.onClick).AddListener(new UnityAction(Close)); overlay.AddComponent<ConfigUI.ConfigUIInputGuard>().Hold(); GameObject obj2 = GUIManager.Instance.CreateWoodpanel(overlay.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 420f, 520f, true); ConfigUI.AddText(obj2.transform, 0f, 14f, 420f, 30f, title, 18, (TextAnchor)4, GUIManager.Instance.ValheimYellow); InputField val2 = ConfigUI.AddTextField(obj2.transform, 16f, 52f, 320f, "", null, (ContentType)0, "Filter..."); ConfigUI.AddButton(obj2.transform, 344f, 52f, 60f, "Close", new UnityAction(Close), 28f); ConfigUI.CreateScroll(obj2.transform, 16f, 92f, 388f, 404f, out var content, out var contentW); if ((Object)(object)content == (Object)null) { return; } Action<string> rebuild = null; rebuild = delegate(string needle) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown foreach (Transform item in content) { Object.Destroy((Object)(object)((Component)item).gameObject); } int num = 0; foreach (string item2 in all) { if (string.IsNullOrEmpty(needle) || item2.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0) { if (num >= 400) { break; } num++; string picked = item2; ConfigUI.AddButton(ConfigUI.NewLayoutRow(content, contentW, 30f).transform, 0f, 0f, contentW, picked, (UnityAction)delegate { Close(); onPick?.Invoke(picked); }, 28f); } } if (num == 0) { ConfigUI.AddText(ConfigUI.NewLayoutRow(content, contentW, 30f).transform, 4f, 0f, contentW, 30f, "No matches", 14, (TextAnchor)3); } else if (num >= 400) { ConfigUI.AddText(ConfigUI.NewLayoutRow(content, contentW, 30f).transform, 4f, 0f, contentW, 30f, $"... {all.Count - num} more, type to narrow", 13, (TextAnchor)3); } }; ((UnityEvent<string>)(object)val2.onValueChanged).AddListener((UnityAction<string>)delegate(string needle) { rebuild(needle); }); rebuild(""); } internal static void Close() { if (!((Object)(object)overlay == (Object)null)) { Object.Destroy((Object)(object)overlay); overlay = null; } } } internal static class ConfigUIPrompt { private const float PanelW = 460f; private static GameObject overlay; internal static void Show(string title, string label, string initial, string warning, Action<string> onAccept) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_0155: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Expected O, but got Unknown //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) Close(); if (GUIManager.Instance != null && !((Object)(object)GUIManager.CustomGUIFront == (Object)null)) { bool flag = !string.IsNullOrEmpty(warning); float num = (flag ? 96f : 0f); float num2 = 190f + num; overlay = ConfigUI.NewUI("ConfigUIPromptOverlay", GUIManager.CustomGUIFront.transform, typeof(Image)); RectTransform val = (RectTransform)overlay.transform; val.anchorMin = Vector2.zero; val.anchorMax = Vector2.one; val.offsetMin = Vector2.zero; val.offsetMax = Vector2.zero; ((Graphic)overlay.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.45f); overlay.AddComponent<ConfigUI.ConfigUIInputGuard>().Hold(); GameObject val2 = GUIManager.Instance.CreateWoodpanel(overlay.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 460f, num2, true); ConfigUI.AddText(val2.transform, 0f, 14f, 460f, 30f, title, 18, (TextAnchor)4, GUIManager.Instance.ValheimYellow); float num3 = 56f; if (flag) { ConfigUI.AddText(val2.transform, 20f, num3, 420f, num - 8f, warning, 13, (TextAnchor)0, (Color?)new Color(0.98f, 0.75f, 0.14f)); num3 += num; } ConfigUI.AddText(val2.transform, 20f, num3, 120f, 28f, label, 15, (TextAnchor)3); InputField field = ConfigUI.AddTextField(val2.transform, 140f, num3, 300f, initial, null, (ContentType)0, null, 64); num3 += 46f; ConfigUI.AddButton(val2.transform, 20f, num3, 190f, "Cancel", new UnityAction(Close), 34f); ConfigUI.AddButton(val2.transform, 250f, num3, 190f, "OK", (UnityAction)delegate { string text = field.text; Close(); onAccept?.Invoke(text); }, 34f); ((Selectable)field).Select(); field.ActivateInputField(); } } internal static void Close() { if (!((Object)(object)overlay == (Object)null)) { Object.Destroy((Object)(object)overlay); overlay = null; } } } internal enum ConfigOrigin { Startup, LocalFile, ServerSync, Api } internal enum ConfigFailurePolicy { KeepLastGood, RevertToDefaults, RestoreFileOnDisk } internal enum ConfigSyncMode { ServerAuthoritative, LocalOnly } internal enum UnknownKeyPolicy { WarnAndContinue, Strict, Silent } internal abstract class YamlConfigFile { internal string FileName { get; set; } internal string SubFolder { get; set; } internal string Header { get; set; } internal string RpcName { get; set; } internal YamlFormat Format { get; set; } internal ConfigFailurePolicy OnFailure { get; set; } internal ConfigSyncMode Sync { get; set; } internal UnknownKeyPolicy UnknownKeys { get; set; } internal bool ClientWritesToDisk { get; set; } internal bool Watch { get; set; } = true; internal bool NeedsPrefabs { get; set; } internal int SchemaVersion { get; set; } internal bool AllowAdminEdit { get; set; } internal string Path { get; set; } internal CustomRPC Rpc { get; set; } internal CustomRPC EditRpc { get; set; } internal bool LastLoadFailed { get; set; } internal string LastError { get; set; } internal DateTime LastLoadedUtc { get; set; } internal ValidationReport LastReport { get; set; } internal YamlFormat EffectiveFormat => Format ?? YamlFormat.Default; internal abstract Type ValueType { get; } internal abstract string SerializeDefaults(); internal abstract string SerializeCurrent(); internal abstract bool LoadFrom(string yaml, ConfigOrigin origin); internal abstract ValidationReport Revalidate(); internal abstract ValidationReport DryRun(string yaml, out string parseError); } internal sealed class YamlConfigFile<T> : YamlConfigFile where T : class { internal Func<T> Defaults { get; set; } internal Action<T> Apply { get; set; } internal Func<T, T, ValidationReport> Validate { get; set; } internal Func<T, T> Migrate { get; set; } internal Func<T, int> GetSchemaVersion { get; set; } internal Action<T, int> SetSchemaVersion { get; set; } internal Func<T, bool> MigrateInPlace { get; set; } internal T Value { get; private set; } internal override Type ValueType => typeof(T); internal YamlConfigFile(string fileName) { base.FileName = fileName; } internal override string SerializeDefaults() { T val = BuildDefaults(); if (val != null) { return base.EffectiveFormat.Serializer.Serialize((object)val); } return ""; } internal override string SerializeCurrent() { if (Value != null) { return base.EffectiveFormat.Serializer.Serialize((object)Value); } return SerializeDefaults(); } internal override ValidationReport DryRun(string yaml, out string parseError) { parseError = null; if (YamlConfigManager.HasNoUsableConfig(yaml)) { parseError = "it is empty or contains only comments"; return new ValidationReport(); } string reason; T val = Deserialize(yaml, out reason); if (val == null) { parseError = reason ?? "it could not be parsed"; return new ValidationReport(); } if (MigrateInPlace != null) { try { MigrateInPlace(val); } catch (Exception ex) { Logger.LogWarning(base.FileName + " migration threw during a dry run: " + ex.Message); } } if (Validate == null) { return new ValidationReport(); } try { return Validate(val, Value) ?? new ValidationReport(); } catch (Exception ex2) { return new ValidationReport().Error("the validator threw: " + ex2.Message); } } internal override ValidationReport Revalidate() { if (Validate == null || Value == null) { return new ValidationReport(); } ValidationReport validationReport; try { validationReport = Validate(Value, Value) ?? new ValidationReport(); } catch (Exception ex) { validationReport = new ValidationReport().Error("the validator threw: " + ex.Message); } base.LastReport = validationReport; LogReport(validationReport); return validationReport; } internal override bool LoadFrom(string yaml, ConfigOrigin origin) { T parsed = null; string reason; if (YamlConfigManager.HasNoUsableConfig(yaml)) { reason = "it is empty or contains only comments"; } else { parsed = Deserialize(yaml, out reason); } if (parsed == null) { return Fail(reason, origin); } bool changed = false; if (base.SchemaVersion > 0 && GetSchemaVersion != null && !ApplySchemaVersion(ref parsed, out var problem, out changed)) { return Fail(problem, origin); } if (MigrateInPlace != null) { try { if (MigrateInPlace(parsed)) { changed = true; } } catch (Exception ex) { Logger.LogWarning(base.FileName + " migration threw, the file was left as it is: " + ex.Message); } } ValidationReport validationReport = new ValidationReport(); if (Validate != null) { try { validationReport = Validate(parsed, Value) ?? new ValidationReport(); } catch (Exception ex2) { validationReport = new ValidationReport().Error("the validator threw: " + ex2.Message); } } base.LastReport = validationReport; LogReport(validationReport); if (validationReport.HasErrors) { return Fail(string.Join(" ", validationReport.Errors.ToArray()), origin); } Value = parsed; base.LastLoadFailed = false; base.LastError = null; base.LastLoadedUtc = DateTime.UtcNow; Publish(); if (changed && origin != ConfigOrigin.ServerSync && ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())) { Logger.LogInfo(base.FileName + " was migrated to the current format; rewriting it."); YamlConfigManager.WriteCurrentToDisk(this); } return true; } private T Deserialize(string yaml, out string reason) { //IL_00a6: Expected O, but got Unknown //IL_002c: Expected O, but got Unknown reason = null; YamlFormat effectiveFormat = base.EffectiveFormat; try { T val = effectiveFormat.Deserializer.Deserialize<T>(yaml); if (val == null) { reason = "it is empty or contains only comments"; } return val; } catch (YamlException ex) { YamlException e = ex; if (base.UnknownKeys == UnknownKeyPolicy.Strict) { reason = Describe(e); return null; } try { T val2 = effectiveFormat.TolerantDeserializer.Deserialize<T>(yaml); if (val2 == null) { reason = "it is empty or contains only comments"; return null; } if (base.UnknownKeys == UnknownKeyPolicy.WarnAndContinue) { Logger.LogWarning(base.FileName + " " + Describe(e) + " That setting was ignored; the rest of the file loaded normally."); } return val2; } catch (YamlException ex2) { YamlException e2 = ex2; reason = Describe(e2); return null; } } catch (Exception ex3) { reason = ex3.Message; return null; } } private bool ApplySchemaVersion(ref T parsed, out string problem, out bool changed) { problem = null; changed = false; int num; try { num = GetSchemaVersion(parsed); } catch (Exception ex) { problem = "the schema version could not be read: " + ex.Message; return false; } if (num == base.SchemaVersion) { return true; } if (Migrate == null) { problem = $"it is schema version {num} but this mod expects {base.SchemaVersion}, and there is no migration for it"; return false; } T val; try { val = Migrate(parsed); } catch (Exception ex2) { problem = $"migrating from schema version {num} to {base.SchemaVersion} threw: {ex2.Message}"; return false; } if (val == null) { problem = $"migrating from schema version {num} to {base.SchemaVersion} produced nothing"; return false; } parsed = val; SetSchemaVersion?.Invoke(parsed, base.SchemaVersion); changed = true; Logger.LogInfo($"{base.FileName} migrated from schema version {num} to {base.SchemaVersion}."); return true; } private bool Fail(string reason, ConfigOrigin origin) { base.LastLoadFailed = true; base.LastError = reason; switch (base.OnFailure) { case ConfigFailurePolicy.RevertToDefaults: PublishDefaults(); Logger.LogError(base.FileName + " could not be loaded because " + reason + ". This mod's built-in defaults are in use; your file was left alone."); break; case ConfigFailurePolicy.RestoreFileOnDisk: PublishDefaults(); if (origin != ConfigOrigin.ServerSync && ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())) { YamlConfigManager.RestoreDefaults(this); Logger.LogError(base.FileName + " could not be loaded because " + reason + ". It has been overwritten with this mod's built-in defaults."); } else { Logger.LogError(base.FileName + " could not be loaded because " + reason + ". This mod's built-in defaults are in use; the file was left alone because this machine does not own it."); } break; default: if (Value == null) { PublishDefaults(); Logger.LogError(base.FileName + " could not be loaded because " + reason + ". Nothing had loaded successfully yet, so this mod's built-in defaults are in use; your file was left alone."); } else { Logger.LogError(base.FileName + " could not be loaded because " + reason + ". The values that last loaded cleanly are still in use; your file was left alone."); } break; } return false; } private void PublishDefaults() { T val = BuildDefaults(); if (val != null) { Value = val; Publish(); } } private void Publish() { try { Apply?.Invoke(Value); } catch (Exception arg) { Logger.LogError($"{base.FileName} apply hook threw, the mod may be in a half-configured state: {arg}"); } } private T BuildDefaults() { if (Defaults == null) { return null; } try { return Defaults(); } catch (Exception arg) { Logger.LogError($"{base.FileName} default factory threw: {arg}"); return null; } } private void LogReport(ValidationReport report) { if (report != null) { for (int i = 0; i < report.Warnings.Count; i++) { Logger.LogWarning(base.FileName + ": " + report.Warnings[i]); } } } private static string Describe(YamlException e) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) string arg = ((((Exception)(object)e).InnerException != null) ? ((Exception)(object)e).InnerException.Message : ((Exception)(object)e).Message); Mark start = e.Start; return $"line {((Mark)(ref start)).Line}: {arg}"; } } internal sealed class YamlFormat { private readonly Action<SerializerBuilder> configureSerializer; private readonly Action<DeserializerBuilder> configureDeserializer; private static readonly List<YamlFormat> built; private static readonly List<IYamlTypeConverter> converters; internal ISerializer Serializer { get; private set; } internal IDeserializer Deserializer { get; private set; } internal IDeserializer TolerantDeserializer { get; private set; } internal static YamlFormat Default { get; private set; } internal static YamlFormat CamelCase { get; private set; } internal static YamlFormat JsonCompat { get; private set; } static YamlFormat() { built = new List<YamlFormat>(); converters = new List<IYamlTypeConverter>(); Default = Build(delegate(SerializerBuilder s) { ((BuilderSkeleton<SerializerBuilder>)(object)s).WithNamingConvention(PascalCaseNamingConvention.Instance); }, null); CamelCase = Build(delegate(SerializerBuilder s) { ((BuilderSkeleton<SerializerBuilder>)(object)s).WithNamingConvention(CamelCaseNamingConvention.Instance); }, null); JsonCompat = Build(delegate(SerializerBuilder s) { ((BuilderSkeleton<SerializerBuilder>)(object)s).WithNamingConvention(PascalCaseNamingConvention.Instance).JsonCompatible(); }, null); } private YamlFormat(Action<SerializerBuilder> serializerSetup, Action<DeserializerBuilder> deserializerSetup) { configureSerializer = serializerSetup; configureDeserializer = deserializerSetup; Rebuild(); } internal static YamlFormat Build(Action<SerializerBuilder> configureSerializer, Action<DeserializerBuilder> configureDeserializer) { YamlFormat yamlFormat = new YamlFormat(configureSerializer, configureDeserializer); built.Add(yamlFormat); return yamlFormat; } internal static void AddTypeConverter(IYamlTypeConverter converter) { if (converter != null) { converters.Add(converter); for (int i = 0; i < built.Count; i++) { built[i].Rebuild(); } } } private void Rebuild() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) SerializerBuilder val = new SerializerBuilder().DisableAliases().ConfigureDefaultValuesHandling((DefaultValuesHandling)2); configureSerializer?.Invoke(val); for (int i = 0; i < converters.Count; i++) { ((BuilderSkeleton<SerializerBuilder>)(object)val).WithTypeConverter(converters[i]); } Serializer = val.Build(); Deserializer = BuildDeserializer(tolerant: false); TolerantDeserializer = BuildDeserializer(tolerant: true); } private IDeserializer BuildDeserializer(bool tolerant) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) DeserializerBuilder val = new DeserializerBuilder().WithCaseInsensitivePropertyMatching(); if (tolerant) { val.IgnoreUnmatchedProperties(); } configureDeserializer?.Invoke(val); for (int i = 0; i < converters.Count; i++) { ((BuilderSkeleton<DeserializerBuilder>)(object)val).WithTypeConverter(converters[i]); } return val.Build(); } } internal class Logger { public static LogLevel Level = (LogLevel)16; public static void EnableDebugLogging(object sender, EventArgs e) { CheckEnableDebugLogging(); } public static void CheckEnableDebugLogging() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (ValConfig.EnableDebugMode.Value) { Level = (LogLevel)32; } else { Level = (LogLevel)16; } } public static void SetDebugLogging(bool state) { //IL_000d: 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) if (state) { Level = (LogLevel)32; } else { Level = (LogLevel)16; } } public static void LogDebug(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Level >= 32) { CommunityPatchExtras.Log.LogInfo((object)("[DEBUG]" + message)); } } public static void LogInfo(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Level >= 16) { CommunityPatchExtras.Log.LogInfo((object)message); } } public static void LogWarning(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Level >= 4) { CommunityPatchExtras.Log.LogWarning((object)message); } } public static void LogError(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Level >= 2) { CommunityPatchExtras.Log.LogError((object)message); } } } internal static class TerminalManager { internal const string CommandPrefix = "jms"; internal static readonly Dictionary<string, ModCommand> Registry = new Dictionary<string, ModCommand>(); private static Terminal responseTerminal; private static bool initialized; private static Harmony harmony; private static void RegisterCommands() { RegisterHelpCommand(); RegisterExampleCommands(); } private static void RegisterExampleCommands() { new ModCommand("jms-echo", "Format: [info/detail/warning/error] [message] Prints a message back at the given severity.", Echo, "demo", EchoOptions, false, false, false, false, null, "jms-e"); new ModCommand("jms-nearby", "Format: [optional: radius] Counts the creatures around you.", Nearby, "demo", TerminalArgs.RadiusPresets, false, false, false, false, null); new ModCommand("jms-worldinfo", "Reports server-side world state. Admins can run this from a connected client.", WorldInfo, "world", null, false, true, true, false, null); } private static List<string> EchoOptions(string[] input) { if (input.Length > 2) { return new List<string>(); } return TerminalArgs.Names<OutputLevel>(); } private static void Echo(ModCommandArgs args) { if (args.Length < 2) { args.Output.Error("Usage: jms-echo [info/detail/warning/error] [message]"); return; } OutputLevel level = args.Args.GetEnum(0, OutputLevel.Info); args.Output.Write(level, args.Args.GetStringFrom(1)); } private static void Nearby(ModCommandArgs args) { if (!args.HasCenter) { args.Output.Error("This needs a player position to measure from."); return; } float radius = args.ReadRadius(0, 32f, 256f); int num = Character.GetAllCharacters().Count((Character c) => (Object)(object)c != (Object)null && !c.IsPlayer() && Utils.DistanceXZ(((Component)c).transform.position, args.Center) <= radius); args.Output.Info($"{num} creatures within {radius}m."); } private static void WorldInfo(ModCommandArgs args) { args.Output.Info("World : " + ZNet.instance.GetWorldName()); args.Output.Detail("Seed : " + ZNet.m_world?.m_seedName); args.Output.Detail($"Peers : {ZNet.instance.GetPeers().Count}"); args.Output.Detail($"ZDOs : {((ZDOMan.instance != null) ? ZDOMan.instance.NrOfObjects() : 0)}"); args.Output.Detail($"Zones : {(((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.m_generatedZones.Count : 0)}"); if (args.HasCenter) { args.Output.Detail($"You are at : {args.Center.x:0}, {args.Center.z:0}"); } } private static void RegisterHelpCommand() { new ModCommand("jms-help", "Format: [optional: area] Lists this mod's console commands, optionally just one area.", Help, "meta", HelpOptions, false, false, false, false, null); } private static List<string> HelpOptions(string[] input) { if (input.Length > 2) { return new List<string>(); } return (from area in (from command in Registry.Values where !command.HideFromHelp select command.Area).Distinct() orderby area select area).ToList(); } private static void Help(ModCommandArgs args) { string filter = args.Args.GetString(0, null); if (filter != null && !HelpOptions(new string[2] { "", "" }).Contains(filter)) { args.Output.Warning("Unknown area '" + filter + "'. Areas: " + string.Join(", ", HelpOptions(new string[2] { "", "" }))); return; } args.Output.Info("ValheimCommunityPatchExtras commands:", log: false); foreach (IGrouping<string, ModCommand> item in from command in Registry.Values where !command.HideFromHelp where filter == null || command.Area == filter group command by command.Area into @group orderby @group.Key select @group) { args.Output.Info(" [" + item.Key + "]", log: false); foreach (ModCommand item2 in item.OrderBy((ModCommand command) => ((ConsoleCommand)command).Command)) { args.Output.Detail(" " + ((ConsoleCommand)item2).Command + Tags(item2) + " - " + ((ConsoleCommand)item2).Description, log: false); string text = AliasesOf(item2); if (text.Length > 0) { args.Output.Detail(" also accepts: " + text, log: false); } } } } private static string Tags(ModCommand command) { List<string> list = new List<string>(); if (((ConsoleCommand)command).IsCheat) { list.Add("cheat"); } if (command.RequiresAdmin) { list.Add("admin"); } if (command.ServerAuthoritative) { list.Add("server"); } if (list.Count != 0) { return " (" + string.Join(", ", list) + ")"; } return string.Empty; } private static string AliasesOf(ModCommand command) { return string.Join(", ", from other in Registry.Values where other.HideFromHelp && other.Canonical == ((ConsoleCommand)command).Command select ((ConsoleCommand)other).Command into name orderby name select name); } internal static void Init() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!initialized) { initialized = true; harmony = new Harmony("MidnightsFX.ValheimCommunityPatchExtras.terminal"); PatchTabCompletion("tabCycle"); PatchTabCompletion("updateSearch"); TerminalNetwork.Init(); RegisterCommands(); Logger.LogDebug($"Registered {Registry.Count} console commands."); } } private static void PatchTabCompletion(string methodName) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(Terminal), methodName, (Type[])null, (Type[])null); if (methodInfo == null) { Logger.LogWarning("Terminal." + methodName + " not found; per-argument tab completion is disabled."); } else { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(TerminalManager), "ContextOptionsPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex) { Logger.LogWarning("Could not patch Terminal." + methodName + " for tab completion: " + ex.Message); } } internal static void Register(ModCommand command) { Registry[Key(((ConsoleCommand)command).Command)] = command; } private static string Key(string name) { return (name ?? string.Empty).ToLowerInvariant(); } private static ModCommand Lookup(string name) { if (!Registry.TryGetValue(Key(name), out var value)) { return null; } return value; } internal static void Execute(string name, ConsoleEventArgs consoleArgs) { ModCommand modCommand = Lookup(name); if (modCommand == null) { return; } string[] args = consoleArgs.Args.Skip(1).ToArray(); TerminalOutput terminalOutput = TerminalOutput.Local(consoleArgs.Context); if (!SynchronizationManager.Instance.PlayerIsAdmin) { terminalOutput.Error("Only server admins can run " + modCommand.Canonical + "."); return; } if (!modCommand.ServerAuthoritative) { Invoke(modCommand, args, terminalOutput); return; } if ((Object)(object)ZNet.instance == (Object)null) { terminalOutput.Error("You must be in a world to use " + modCommand.Canonical + "."); return; } if (ZNet.instance.IsServer()) { Invoke(modCommand, args, terminalOutput); return; } if (modCommand.RequiresAdmin && !SynchronizationManager.Instance.PlayerIsAdmin) { terminalOutput.Error("Only server admins can run " + modCommand.Canonical + " from a client."); return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null) { terminalOutput.Error("No server connection, so " + modCommand.Canonical + " cannot be sent."); return; } responseTerminal = consoleArgs.Context; terminalOutput.Info("Asked the server to run " + modCommand.Canonical + "; its output follows."); TerminalNetwork.SendRequest(serverPeer.m_uid, modCommand.Canonical, args); } internal static void ExecuteFromNetwork(string name, string[] args, Vector3 center, bool hasCenter, TerminalOutput output) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) ModCommand modCommand = Lookup(name); if (modCommand == null || !modCommand.ServerAuthoritative) { output.Error("'" + name + "' is not a server-runnable command."); output.Flush(); } else { Invoke(modCommand, args, center, hasCenter, output); } } private static void Invoke(ModCommand command, string[] args, TerminalOutput output) { //IL_0000: 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_0029: 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) Vector3 center = Vector3.zero; bool hasCenter = false; if ((Object)(object)Player.m_localPlayer != (Object)null) { center = ((Component)Player.m_localPlayer).transform.position; hasCenter = true; } Invoke(command, args, center, hasCenter, output); } private static void Invoke(ModCommand command, string[] args, Vector3 center, bool hasCenter, TerminalOutput output) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) try { command.Action(new ModCommandArgs(args, center, hasCenter, output)); } catch (Exception ex) { output.Error(command.Canonical + " failed: " + ex.Message); Logger.LogError($"{command.Canonical} threw: {ex}"); } finally { output.Flush(); } } internal static void PrintResponse(OutputLevel level, string line) { TerminalOutput.LogLine(level, line); Terminal val = (((Object)(object)responseTerminal != (Object)null) ? responseTerminal : null); if ((Object)(object)val == (Object)null && (Object)(object)Console.instance != (Object)null) { val = (Terminal)(object)Console.instance; } TerminalOutput.PrintTo(val, level, line); } private static void ContextOptionsPrefix(Terminal __instance, ref string word, ref List<string> options, bool usePrefix) { if (usePrefix || (Object)(object)__instance == (Object)null || (Object)(object)__instance.m_input == (Object)null) { return; } string[] array = (((TMP_InputField)__instance.m_input).text ?? string.Empty).Split(new char[1] { ' ' }); if (array.Length < 2) { return; } ModCommand modCommand = Lookup((__instance.m_tabPrefix == '\0') ? array[0] : ((array[0].Length == 0) ? string.Empty : array[0].Substring(1))); if (modCommand != null) { List<string> tabOptions = modCommand.GetTabOptions(array); if (tabOptions != null && tabOptions.Count != 0) { options = tabOptions; word = array[^1]; } } } } internal enum OutputLevel : byte { Info, Detail, Warning, Error } internal delegate List<string> OptionProvider(string[] input); internal delegate void CommandAction(ModCommandArgs args); internal class ModCommand : ConsoleCommand { internal readonly string Canonical; internal readonly string Area; internal readonly CommandAction Action; internal readonly OptionProvider Options; internal readonly bool HideFromHelp; internal readonly bool ServerAuthoritative; internal readonly bool RequiresAdmin; internal ModCommand(string command, string description, CommandAction action, string area = "general", OptionProvider options = null, bool isCheat = false, bool serverAuthoritative = false, bool requiresAdmin = false, bool hideFromHelp = false, string canonical = null, params string[] aliases) : base(command, description, (ConsoleEvent)delegate(ConsoleEventArgs args) { TerminalManager.Execute(command, args); }, isCheat, false, false, hideFromHelp, false, false, (ConsoleOptionsFetcher)null, false, false, false) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown ModCommand modCommand = this; Canonical = canonical ?? command; Area = (string.IsNullOrEmpty(area) ? "general" : area); Action = action; Options = options; HideFromHelp = hideFromHelp; ServerAuthoritative = serverAuthoritative; RequiresAdmin = requiresAdmin; base.m_tabOptionsFetcher = (ConsoleOptionsFetcher)(() => modCommand.GetTabOptions(CurrentInput())); base.m_alwaysRefreshTabOptions = true; TerminalManager.Register(this); for (int num = 0; num < aliases.Length; num++) { new ModCommand(aliases[num], description, action, area, options, isCheat, serverAuthoritative, requiresAdmin, true, Canonical); } } internal List<string> GetTabOptions(string[] input) { if (Options == null) { return new List<string>(); } try { return Options(input) ?? new List<string>(); } catch (Exception ex) { Logger.LogDebug("Tab options for " + base.Command + " failed: " + ex.Message); return new List<string>(); } } private static string[] CurrentInput() { Terminal instance = (Terminal)(object)Console.instance; return ((((Object)(object)instance?.m_input == (Object)null) ? string.Empty : ((TMP_InputField)instance.m_input).text) ?? string.Empty).Split(new char[1] { ' ' }); } } internal class ModCommandArgs { internal readonly string[] Args; internal readonly TerminalOutput Output; internal readonly Vector3 Center; internal readonly bool HasCenter; internal int Length => Args.Length; internal ModCommandArgs(string[] args, Vector3 center, bool hasCenter, TerminalOutput output) { //IL_0018: 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) Args = args ?? new string[0]; Center = center; HasCenter = hasCenter; Output = output; } internal bool Has(string flag) { return Args.Any((string a) => string.Equals(a, flag, StringComparison.OrdinalIgnoreCase)); } } internal static class TerminalArgs { private const float CacheSeconds = 60f; private static readonly List<string> creatureNames = new List<string>(); private static float creatureNamesAt; internal static string GetString(this string[] args, int index, string fallback = "") { if (args == null || args.Length <= index) { return fallback; } return args[index]; } internal static string GetStringFrom(this string[] args, int index, string fallback = "") { if (args == null || args.Length <= index) { return fallback; } return string.Join(" ", args.Skip(index)); } internal static int GetInt(this string[] args, int index, int fallback = 0) { string text = args.GetString(index, null); if (text == null) { return fallback; } if (!int.TryParse(text, out