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.1.1
plugins/CommunityPatchExtras.dll
Decompiled 3 hours 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.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; 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.1.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.1.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 ConfigUILauncher { private static Component cachedBroker; private static MethodInfo cachedRegister; private static MethodInfo cachedUnregister; private static bool loggedOwner; internal static bool IsAvailable => (Object)(object)Resolve() != (Object)null; internal static void Init() { Resolve(); } internal static bool Register(string displayName, Action openPanel) { if (string.IsNullOrEmpty(displayName) || openPanel == null) { return false; } Component val = Resolve(); if ((Object)(object)val == (Object)null) { return false; } if (cachedRegister == null) { Logger.LogError("The QuickConfig launcher on this machine has no compatible Register method; '" + displayName + "' will not appear in it."); return false; } try { cachedRegister.Invoke(val, new object[2] { displayName, openPanel }); return true; } catch (Exception ex) { Logger.LogError("Could not register '" + displayName + "' with the QuickConfig launcher: " + ex.Message); return false; } } internal static void Unregister(string displayName) { if (string.IsNullOrEmpty(displayName)) { return; } Component val = Resolve(); if ((Object)(object)val == (Object)null || cachedUnregister == null) { return; } try { cachedUnregister.Invoke(val, new object[1] { displayName }); } catch (Exception ex) { Logger.LogWarning("Could not unregister '" + displayName + "' from the QuickConfig launcher: " + ex.Message); } } private static Component Resolve() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown if ((Object)(object)cachedBroker != (Object)null) { return cachedBroker; } cachedRegister = null; cachedUnregister = null; GameObject val = null; try { val = GameObject.Find("ModQuickConfigLauncher"); } catch (Exception) { } if ((Object)(object)val == (Object)null) { try { val = new GameObject("ModQuickConfigLauncher"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<QuickConfigBroker>(); } catch (Exception ex2) { Logger.LogError("Could not create the QuickConfig launcher: " + ex2.Message); return null; } } Component val2 = null; Component[] components = val.GetComponents<Component>(); foreach (Component val3 in components) { if ((Object)(object)val3 != (Object)null && ((object)val3).GetType().Name == "QuickConfigBroker") { val2 = val3; break; } } if ((Object)(object)val2 == (Object)null) { return null; } Type type = ((object)val2).GetType(); cachedRegister = type.GetMethod("Register", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(Action) }, null); cachedUnregister = type.GetMethod("Unregister", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (!loggedOwner) { loggedOwner = true; int num = 1; try { PropertyInfo property = type.GetProperty("BrokerVersion", BindingFlags.Instance | BindingFlags.Public); if (property != null) { num = (int)property.GetValue(val2, null); } } catch (Exception) { } Logger.LogInfo($"QuickConfig launcher v{num} owned by " + $"{type.Assembly.GetName().Name}; this mod carries v{2}."); if (num < 2) { Logger.LogInfo("That copy is older than this one. Registration still works; the launcher UI is whatever the owning mod shipped."); } } cachedBroker = val2; return cachedBroker; } } 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 static class ExampleConfigPanel { private const string EntryName = "CommunityPatchExtras"; private const float PanelW = 620f; private const float PanelH = 520f; private const float LabelW = 190f; private static GameObject panel; private static ExampleSettings staged; private static Text messages; internal static void Init() { ConfigUILauncher.Init(); ApplyRegistration(); } internal static void ApplyRegistration() { if (ValConfig.ShowQuickConfigButton == null || ValConfig.ShowQuickConfigButton.Value) { ConfigUILauncher.Register("CommunityPatchExtras", OpenPanel); } else { ConfigUILauncher.Unregister("CommunityPatchExtras"); } } internal static void OpenPanel() { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Expected O, but got Unknown //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Expected O, but got Unknown //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Expected O, but got Unknown ClosePanel(); YamlConfigFile<ExampleSettings> exampleFile = YamlConfigManager.ExampleFile; if (exampleFile == null) { return; } staged = exampleFile.EffectiveFormat.Deserializer.Deserialize<ExampleSettings>(exampleFile.EffectiveFormat.Serializer.Serialize((object)exampleFile.Value)); if (staged == null) { staged = ExampleData.BuildDefaults(); } panel = ConfigUI.CreatePanel("Example settings", 620f, 520f, out var body); List<GameObject> list = new List<GameObject>(); list.Add(ConfigUI.AddHeaderRow(body, 580f, "Entries", (TextAnchor)3)); foreach (KeyValuePair<string, ExampleEntry> entry2 in staged.Entries) { ExampleEntry entry = entry2.Value; list.Add(ConfigUI.AddTextRow(body, 580f, 26f, entry2.Key, 15, GUIManager.Instance.ValheimOrange, (TextAnchor)0)); list.Add(ConfigUI.AddTextFieldRow(body, 580f, 190f, 240f, "Display name", entry.DisplayName, delegate(string s) { entry.DisplayName = s; }, null, 64)); list.Add(ConfigUI.AddSliderRow(body, 580f, 190f, 200f, 60f, "Multiplier", 0.1f, 10f, entry.Multiplier, wholeNumbers: false, delegate(float v) { entry.Multiplier = v; })); list.Add(ConfigUI.AddEnumCycleRow(body, 580f, 190f, 150f, "Mode", Enum.GetNames(typeof(ExampleMode)), (int)entry.Mode, delegate(int i) { entry.Mode = (ExampleMode)i; })); list.Add(ConfigUI.AddPickerRow(body, 580f, 190f, 260f, "First prefab", (entry.Prefabs.Count > 0) ? entry.Prefabs[0] : "", PrefabNames, delegate(string s) { if (entry.Prefabs.Count > 0) { entry.Prefabs[0] = s; } else { entry.Prefabs.Add(s); } }, IsKnownPrefab)); list.Add(ConfigUI.AddDividerRow(body, 580f)); } ConfigUI.LayoutColumn(list, 20f, 60f); messages = ConfigUI.AddText(body, 20f, 412f, 580f, 46f, "", 13, (TextAnchor)0); ConfigUI.AddButton(body, 20f, 464f, 130f, "Validate", new UnityAction(Validate)); ConfigUI.AddButton(body, 300f, 464f, 130f, "Cancel", new UnityAction(ClosePanel)); ConfigUI.AddButton(body, 450f, 464f, 150f, "Apply & Save", new UnityAction(ApplyAndSave)); } private static void Validate() { YamlConfigFile<ExampleSettings> exampleFile = YamlConfigManager.ExampleFile; if (exampleFile != null && staged != null) { string parseError; ValidationReport validationReport = exampleFile.DryRun(YamlConfigManager.SerializeForEdit(exampleFile, staged), out parseError); if (parseError != null) { ConfigUI.SetMessages(messages, new List<string> { parseError }, null); } else if (validationReport.Errors.Count == 0 && validationReport.Warnings.Count == 0) { messages.text = "Looks good."; } else { ConfigUI.SetMessages(messages, validationReport.Errors, validationReport.Warnings); } } } private static void ApplyAndSave() { YamlConfigFile<ExampleSettings> exampleFile = YamlConfigManager.ExampleFile; if (exampleFile == null || staged == null) { return; } try { string yaml = YamlConfigManager.SerializeForEdit(exampleFile, staged); if (!YamlConfigManager.ApplyEdited(exampleFile, yaml, out var message)) { ConfigUI.SetMessages(messages, new List<string> { message }, null); } else { ClosePanel(); } } catch (Exception ex) { Logger.LogError($"Example config panel failed to apply: {ex}"); ConfigUI.SetMessages(messages, new List<string> { ex.Message }, null); } } private static void ClosePanel() { if (!((Object)(object)panel == (Object)null)) { Object.Destroy((Object)(object)panel); panel = null; messages = null; } } private static IList<string> PrefabNames() { List<string> list = new List<string>(); if ((Object)(object)ZNetScene.instance == (Object)null) { return list; } foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab != (Object)null) { list.Add(((Object)prefab).name); } } return list; } private static bool IsKnownPrefab(string name) { if (PrefabManager.Instance == null) { return true; } return (Object)(object)PrefabManager.Instance.GetPrefab(name) != (Object)null; } } internal class QuickConfigBroker : MonoBehaviour { internal const string BrokerObjectName = "ModQuickConfigLauncher"; internal const string BrokerTypeName = "QuickConfigBroker"; internal const string ButtonObjectName = "ModQuickConfigButton"; internal const int ContractVersion = 2; private const float ButtonW = 150f; private const float ButtonH = 38f; private const float PanelW = 320f; private static QuickConfigBroker Instance; private static Harmony harmony; private readonly Dictionary<string, Action> entries = new Dictionary<string, Action>(StringComparer.Ordinal); private readonly List<string> order = new List<string>(); private GameObject mainMenuButton; private GameObject pauseButton; private GameObject listPanel; public int BrokerVersion => 2; public void Register(string modName, Action openPanel) { if (!string.IsNullOrEmpty(modName) && openPanel != null) { if (!entries.ContainsKey(modName)) { order.Add(modName); } entries[modName] = openPanel; RefreshVisibility(); } } public void Unregister(string modName) { if (!string.IsNullOrEmpty(modName)) { if (entries.Remove(modName)) { order.Remove(modName); } if ((Object)(object)listPanel != (Object)null) { CloseList(); } RefreshVisibility(); } } public bool IsRegistered(string modName) { if (!string.IsNullOrEmpty(modName)) { return entries.ContainsKey(modName); } return false; } public void Awake() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown Instance = this; GUIManager.OnCustomGUIAvailable += OnCustomGUIAvailable; SynchronizationManager.OnAdminStatusChanged += OnAdminStatusChanged; SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized; try { if (harmony == null) { harmony = new Harmony("ModQuickConfigLauncher.broker"); harmony.Patch((MethodBase)AccessTools.Method(typeof(Menu), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(QuickConfigBroker), "OnMenuStart", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Menu), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(QuickConfigBroker), "OnMenuUpdate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex) { Logger.LogWarning("QuickConfig launcher could not patch Menu: " + ex.Message); } TryBuildButtons(); } public void OnDestroy() { GUIManager.OnCustomGUIAvailable -= OnCustomGUIAvailable; SynchronizationManager.OnAdminStatusChanged -= OnAdminStatusChanged; SynchronizationManager.OnConfigurationSynchronized -= OnConfigurationSynchronized; if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void OnAdminStatusChanged() { RefreshVisibility(); } private void OnConfigurationSynchronized(object sender, EventArgs e) { RefreshVisibility(); } private static void OnMenuStart(Menu __instance) { if (!((Object)(object)Instance == (Object)null)) { Instance.EnsurePauseButton(__instance); } } private static bool OnMenuUpdate() { if ((Object)(object)Instance == (Object)null || (Object)(object)Instance.listPanel == (Object)null) { return true; } if (!ZInput.GetKeyDown((KeyCode)27, true)) { return true; } Instance.CloseList(); return false; } public void Update() { if (!((Object)(object)listPanel == (Object)null) && !((Object)(object)Menu.instance != (Object)null) && Input.GetKeyDown((KeyCode)27)) { CloseList(); } } private void OnCustomGUIAvailable() { TryBuildButtons(); } private void TryBuildButtons() { if (!GUIManager.IsHeadless() && GUIManager.Instance != null) { if ((Object)(object)FejdStartup.instance != (Object)null && (Object)(object)GUIManager.CustomGUIFront != (Object)null) { mainMenuButton = EnsureCornerButton(mainMenuButton, GUIManager.CustomGUIFront.transform); } if ((Object)(object)Menu.instance != (Object)null) { EnsurePauseButton(Menu.instance); } RefreshVisibility(); } } private void EnsurePauseButton(Menu menu) { if (!((Object)(object)menu == (Object)null) && !((Object)(object)menu.m_root == (Object)null)) { pauseButton = EnsureCornerButton(pauseButton, menu.m_root); RefreshVisibility(); } } private GameObject EnsureCornerButton(GameObject existing, Transform parent) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown if (GUIManager.IsHeadless() || GUIManager.Instance == null || (Object)(object)parent == (Object)null) { return existing; } if ((Object)(object)existing != (Object)null && (Object)(object)existing.transform.parent == (Object)(object)parent) { return existing; } Transform val = parent.Find("ModQuickConfigButton"); if ((Object)(object)val != (Object)null) { return ((Component)val).gameObject; } GameObject obj = GUIManager.Instance.CreateButton(ConfigUI.L("Mod Config"), parent, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-20f, 20f), 150f, 38f); ((Object)obj).name = "ModQuickConfigButton"; RectTransform val2 = (RectTransform)obj.transform; val2.pivot = new Vector2(1f, 0f); val2.anchoredPosition = new Vector2(-20f, 20f); ((UnityEvent)obj.GetComponent<Button>().onClick).AddListener(new UnityAction(OpenList)); return obj; } private static bool CanConfigure() { if (GUIManager.IsHeadless() || GUIManager.Instance == null) { return false; } if ((Object)(object)ZNet.instance == (Object)null) { return true; } if (ZNet.instance.IsServer()) { return true; } if (SynchronizationManager.Instance != null) { return SynchronizationManager.Instance.PlayerIsAdmin; } return false; } private void RefreshVisibility() { bool flag = entries.Count > 0 && CanConfigure(); if ((Object)(object)mainMenuButton != (Object)null) { mainMenuButton.SetActive(flag && (Object)(object)FejdStartup.instance != (Object)null); } if ((Object)(object)pauseButton != (Object)null) { pauseButton.SetActive(flag); } if (!flag && (Object)(object)listPanel != (Object)null) { CloseList(); } } private void OpenList() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown CloseList(); if (!CanConfigure()) { return; } if (order.Count == 1) { Invoke(order[0]); return; } float h = Mathf.Clamp(80f + 42f * (float)order.Count, 122f, 560f); listPanel = ConfigUI.CreatePanel("Configure a mod", 320f, h, out var body); ConfigUI.AddCloseX(body, 320f, new UnityAction(CloseList)); float num = 64f; foreach (string item in order) { string entry = item; ConfigUI.AddButton(body, 20f, num, 280f, entry, (UnityAction)delegate { CloseList(); Invoke(entry); }); num += 42f; } } private void CloseList() { if (!((Object)(object)listPanel == (Object)null)) { Object.Destroy((Object)(object)listPanel); listPanel = null; } } private void Invoke(string modName) { if (!entries.TryGetValue(modName, out var value) || value == null) { return; } try { value(); } catch (Exception arg) { Logger.LogError($"The config panel for '{modName}' failed to open: {arg}"); } } } 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 = BuildDeserializ