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 ServerManager v1.0.9
ServerManager.dll
Decompiled 2 days 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.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Data; using System.Data.SqlTypes; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Dynamic; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Sockets; using System.Net.WebSockets; using System.Numerics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Cronos; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Bson; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq.JsonPath; using Newtonsoft.Json.Schema; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Utilities; using ServerManager.Commands; using ServerManager.Configuration; using ServerManager.Discord; using ServerManager.Events; using ServerManager.PlayerLogging; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.ObjectPool; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.RepresentationModel; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Callbacks; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ServerManager")] [assembly: AssemblyDescription("Steamworks-only integrity, authoritative characters, anti-cheat, events, and embedded Discord control")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyProduct("ServerManager")] [assembly: AssemblyCopyright("Copyright © 2026 sighsorry")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.0.9")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.9.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace ServerManager { internal static class ClientMenuBranding { private sealed class LabelOverride { internal TMP_Text Text { get; } internal string OriginalText { get; } internal bool OriginalEnableAutoSizing { get; } internal TextWrappingModes OriginalWrappingMode { get; } internal float OriginalFontSizeMin { get; } internal float OriginalFontSizeMax { get; } internal bool HadLocalizationSource { get; } internal string? LocalizationSource { get; } internal bool LocalizationDetached { get; set; } internal LabelOverride(TMP_Text text) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Text = text; OriginalText = text.text; OriginalEnableAutoSizing = text.enableAutoSizing; OriginalWrappingMode = text.textWrappingMode; OriginalFontSizeMin = text.fontSizeMin; OriginalFontSizeMax = text.fontSizeMax; Localization instance = Localization.instance; if (instance != null && TryGetLocalizationTextMeshStrings(instance, out Dictionary<TMP_Text, string> textMeshStrings) && textMeshStrings.TryGetValue(text, out var value)) { HadLocalizationSource = true; LocalizationSource = value; } } } private sealed class RemoteLogoLoad { internal readonly FejdStartup Startup; internal readonly Image Image; internal readonly string Source; internal readonly string? CachePath; internal readonly CancellationTokenSource Stop = new CancellationTokenSource(); internal readonly Task<byte[]> Download; internal RemoteLogoLoad(FejdStartup startup, Image image, string source, Uri url, string? cachePath) { Startup = startup; Image = image; Source = source; CachePath = cachePath; CancellationToken token = Stop.Token; Download = Task.Run(() => DownloadLogoAsync(url, token)); } } private sealed class MenuGuide { private readonly FejdStartup _startup; private readonly List<KeyValuePair<GameObject, bool>> _hidden = new List<KeyValuePair<GameObject, bool>>(); private MenuTextPanel? _panel; private MenuTextPanel? _optionalPanel; private GameObject? _launcher; private GameObject? _dialog; private GameObject? _previousSelection; private bool _open; private bool _showMods; private Button? _modsButton; private Button? _guideButton; private Button? _closeButton; private OptionalModQuery? _optionalQuery; private OptionalModLobbyQuery? _optionalLobbyQuery; private bool _optionalLobbyMode; private string? _optionalEndpointInput; private bool _optionalFailed; private long _optionalRevision = -1L; private string? _optionalLanguage; private string? _language; private string? _hintEndpoint; private bool _visible; private void SetOpen(bool open) { _open = open; if (open) { EventSystem current = EventSystem.current; _previousSelection = ((current != null) ? current.currentSelectedGameObject : null); _dialog.SetActive(true); ((Selectable)_dialog.GetComponentInChildren<Button>()).Select(); return; } GameObject? dialog = _dialog; if (dialog != null) { dialog.SetActive(false); } if ((Object)(object)_previousSelection != (Object)null && _previousSelection.activeInHierarchy) { EventSystem current2 = EventSystem.current; if (current2 != null) { current2.SetSelectedGameObject(_previousSelection); } } _previousSelection = null; } internal bool HandleDialogInput() { if (!_open || !CanShow(_startup)) { return false; } if (ZInput.GetKeyDown((KeyCode)27, true) || ZInput.GetButtonDown("JoyButtonB")) { SetOpen(open: false); return true; } return false; } private Button AddButton(Transform parent, string text, Vector2 position, UnityAction action) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ServerManager " + text, new Type[3] { typeof(RectTransform), typeof(Image), typeof(Button) }); val.transform.SetParent(parent, false); RectTransform val2 = (RectTransform)val.transform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 1f); val2.pivot = val3; Vector2 anchorMin = (val2.anchorMax = val3); val2.anchorMin = anchorMin; val2.anchoredPosition = position; val2.sizeDelta = new Vector2(150f, 36f); Image component = val.GetComponent<Image>(); ((Graphic)component).color = new Color(0.18f, 0.14f, 0.09f, 1f); TMP_Text obj = MenuTextPanel.CreateText(val.transform, _startup.m_connectionFailedError, "Label", 20f, new Color(1f, 0.8f, 0.4f)); obj.text = text; obj.alignment = (TextAlignmentOptions)514; ((Graphic)obj).raycastTarget = false; MenuTextPanel.Stretch(obj.rectTransform, Vector2.zero, Vector2.zero); Button component2 = val.GetComponent<Button>(); ((Selectable)component2).targetGraphic = (Graphic)(object)component; ((UnityEvent)component2.onClick).AddListener(action); return component2; } private void EnsureDialog() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_0115: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Expected O, but got Unknown //IL_01b9: 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_01cf: Expected O, but got Unknown //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_launcher != (Object)null)) { _launcher = ((Component)AddButton(_startup.m_mainMenu.transform, "Server Info", new Vector2(0f, -20f), (UnityAction)delegate { SetOpen(open: true); })).gameObject; RectTransform val = (RectTransform)_launcher.transform; Vector2 val2 = (val.pivot = Vector2.one); Vector2 anchorMin = (val.anchorMax = val2); val.anchorMin = anchorMin; val.anchoredPosition = new Vector2(-24f, -24f); _dialog = new GameObject("ServerManager Info", new Type[4] { typeof(RectTransform), typeof(Image), typeof(Canvas), typeof(GraphicRaycaster) }); _dialog.SetActive(false); _dialog.transform.SetParent(_startup.m_mainMenu.transform, false); MenuTextPanel.Stretch((RectTransform)_dialog.transform, Vector2.zero, Vector2.zero); ((Graphic)_dialog.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.94f); Canvas component = _dialog.GetComponent<Canvas>(); component.overrideSorting = true; component.sortingOrder = 100; Button val4 = AddButton(_dialog.transform, "Guide", new Vector2(-160f, -20f), (UnityAction)delegate { _showMods = false; }); _modsButton = AddButton(_dialog.transform, "Allowed Mods", new Vector2(0f, -20f), (UnityAction)delegate { _showMods = true; }); Button val5 = AddButton(_dialog.transform, "Close", new Vector2(160f, -20f), (UnityAction)delegate { SetOpen(open: false); }); _guideButton = val4; _closeButton = val5; Button[] array = (Button[])(object)new Button[3] { val4, _modsButton, val5 }; for (int num = 0; num < array.Length; num++) { Button obj = array[num]; Navigation navigation = default(Navigation); ((Navigation)(ref navigation)).mode = (Mode)4; ((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)array[(num + 2) % 3]; ((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)array[(num + 1) % 3]; ((Selectable)obj).navigation = navigation; } } } internal MenuGuide(FejdStartup startup) { _startup = startup; } private static bool Active(GameObject? value) { if ((Object)(object)value != (Object)null) { return value.activeInHierarchy; } return false; } internal static bool CanShow(FejdStartup startup) { if (Active(startup.m_mainMenu) && Active(startup.m_menuList) && !Active(startup.m_connectionFailedPanel) && !Active(startup.m_worldVersionPanel) && !Active(startup.m_playerVersionPanel) && !Active(startup.m_newGameVersionPanel) && !Active(startup.m_ndaPanel) && !Active(startup.m_loading) && !Active(startup.m_pleaseWait) && !UnifiedPopup.IsVisible()) { return !Feedback.IsVisible(); } return false; } internal void Update(bool refreshText) { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) if (!CanShow(_startup)) { if (_open) { SetOpen(open: false); } GameObject? launcher = _launcher; if (launcher != null) { launcher.SetActive(false); } SetVisible(visible: false); return; } if (_customMenuActive) { EnsureDialog(); _launcher.SetActive(true); if (!_open) { SetVisible(visible: false); return; } _dialog.transform.SetAsLastSibling(); } if (_panel == null) { _panel = new MenuTextPanel(_startup, left: false); } if (_customMenuActive) { _panel.UseDialog(_dialog.transform); } Localization instance = Localization.instance; string text = ((instance != null) ? instance.GetSelectedLanguage() : null) ?? "English"; string text2 = ServerManagerPlugin.BrandingServerAddress?.Value ?? string.Empty; if ((Object)(object)_modsButton != (Object)null) { bool flag = !string.IsNullOrWhiteSpace(text2); if (((Selectable)_modsButton).interactable != flag) { ((Selectable)_modsButton).interactable = flag; Navigation navigation = ((Selectable)_guideButton).navigation; ((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)(flag ? _modsButton : _closeButton); ((Selectable)_guideButton).navigation = navigation; Navigation navigation2 = ((Selectable)_closeButton).navigation; ((Navigation)(ref navigation2)).selectOnLeft = (Selectable)(object)(flag ? _modsButton : _guideButton); ((Selectable)_closeButton).navigation = navigation2; if (!flag) { EventSystem current = EventSystem.current; if ((Object)(object)((current != null) ? current.currentSelectedGameObject : null) == (Object)(object)((Component)_modsButton).gameObject) { ((Selectable)_guideButton).Select(); } } } if (!((Selectable)_modsButton).interactable) { _showMods = false; } } if (refreshText || !string.Equals(_language, text, StringComparison.Ordinal) || !string.Equals(_hintEndpoint, text2, StringComparison.Ordinal)) { _language = text; _hintEndpoint = text2; string text3 = string.Join("\n\n", PlayerLocalizer.Text("sm_menu_guide_character"), PlayerLocalizer.Text("sm_menu_guide_mods"), PlayerLocalizer.Text("sm_menu_guide_update")); if (ShouldShowWorldMenuHint(text2)) { text3 = text3 + "\n\n" + PlayerLocalizer.Text("sm_menu_guide_worlds"); } _panel.SetText(PlayerLocalizer.Text("sm_menu_guide_title"), text3); } SetVisible(visible: true); _panel.UpdateLayout(); UpdateOptionalList(text2, text, refreshText); if (_customMenuActive) { _panel.SetVisible(!_showMods || string.IsNullOrWhiteSpace(text2)); _optionalPanel?.SetVisible(_showMods && !string.IsNullOrWhiteSpace(text2)); } if (_customMenuActive && _showMods) { _optionalPanel?.HandleGuideKeys(); } else { _panel.HandleGuideKeys(); } } private void UpdateOptionalList(string endpoint, string language, bool refreshText) { if (string.IsNullOrWhiteSpace(endpoint)) { _optionalPanel?.SetVisible(visible: false); _optionalQuery?.Dispose(); _optionalQuery = null; _optionalLobbyQuery?.Dispose(); _optionalLobbyQuery = null; _optionalRevision = -1L; } else { if (_optionalFailed) { return; } try { if (!string.Equals(_optionalEndpointInput, endpoint, StringComparison.Ordinal)) { _optionalEndpointInput = endpoint; bool flag = endpoint.Trim().StartsWith("steam:", StringComparison.OrdinalIgnoreCase); if (_optionalLobbyMode != flag) { _optionalQuery?.Pause(); _optionalLobbyQuery?.Pause(); _optionalLobbyMode = flag; _optionalRevision = -1L; } } bool optionalLobbyMode = _optionalLobbyMode; OptionalModQueryState state; bool isStale; long displayRevision; IReadOnlyList<OptionalModCatalogEntry> entries; if (optionalLobbyMode) { if (_optionalLobbyQuery == null) { _optionalLobbyQuery = new OptionalModLobbyQuery(); } _optionalLobbyQuery.Tick(endpoint); state = _optionalLobbyQuery.State; isStale = _optionalLobbyQuery.IsStale; displayRevision = _optionalLobbyQuery.DisplayRevision; entries = _optionalLobbyQuery.Entries; } else { if (_optionalQuery == null) { _optionalQuery = new OptionalModQuery(); } _optionalQuery.Tick(endpoint); state = _optionalQuery.State; isStale = _optionalQuery.IsStale; displayRevision = _optionalQuery.DisplayRevision; entries = _optionalQuery.Entries; } if (_optionalPanel == null) { _optionalPanel = new MenuTextPanel(_startup, left: true); } if (_customMenuActive) { _optionalPanel.UseDialog(_dialog.transform); } if (refreshText || _optionalRevision != displayRevision || !string.Equals(_optionalLanguage, language, StringComparison.Ordinal)) { _optionalRevision = displayRevision; _optionalLanguage = language; string text = FormatOptionalList(state, isStale, entries, CaptureLoadedOptionalModVersions()); if (optionalLobbyMode && (state == OptionalModQueryState.Unavailable || state == OptionalModQueryState.Unsupported)) { text = text + "\n\n" + PlayerLocalizer.Text("sm_menu_optional_host_help"); } _optionalPanel.SetText(PlayerLocalizer.Text("sm_menu_optional_title"), text); } _optionalPanel.SetVisible(!_customMenuActive || _showMods); _optionalPanel.UpdateLayout(); } catch (Exception ex) when (!IntegrityCanonical.IsFatal(ex)) { _optionalPanel?.Dispose(); _optionalPanel = null; _optionalQuery?.Dispose(); _optionalQuery = null; _optionalFailed = true; _optionalLobbyQuery?.Dispose(); _optionalLobbyQuery = null; ServerManagerPlugin.Log.LogWarning((object)("Optional-mod menu preview unavailable: " + ex.Message)); } } } internal void Reflow() { _panel?.Reflow(); } internal void SetVisible(bool visible) { if (visible && !_visible) { CaptureTargets(); } else if (!visible && _visible) { RestoreTargets(); _optionalQuery?.Pause(); _optionalLobbyQuery?.Pause(); } _visible = visible; _panel?.SetVisible(visible && (!_customMenuActive || !_showMods)); if (!visible) { _optionalPanel?.SetVisible(visible: false); } if (!visible) { return; } foreach (KeyValuePair<GameObject, bool> item in _hidden) { if ((Object)(object)item.Key != (Object)null) { item.Key.SetActive(false); } } } private bool IsSafeTarget(GameObject? target) { GameObject mainMenu = _startup.m_mainMenu; if ((Object)(object)mainMenu == (Object)null || (Object)(object)_startup.m_menuList == (Object)null) { return false; } Transform val = mainMenu.transform.Find("Logo/LOGO"); if ((Object)(object)target != (Object)null && (Object)(object)target != (Object)(object)((Component)_startup).gameObject && (Object)(object)target != (Object)(object)mainMenu && (Object)(object)target != (Object)(object)_startup.m_menuList && !mainMenu.transform.IsChildOf(target.transform) && !_startup.m_menuList.transform.IsChildOf(target.transform)) { if (!((Object)(object)val == (Object)null)) { return !val.IsChildOf(target.transform); } return true; } return false; } private void Hide(GameObject? target) { if (!IsSafeTarget(target)) { return; } foreach (KeyValuePair<GameObject, bool> item in _hidden) { if ((Object)(object)item.Key == (Object)(object)target) { return; } } _hidden.Add(new KeyValuePair<GameObject, bool>(target, target.activeSelf)); } private void CaptureTargets() { if (_customMenuActive) { return; } ChangeLog[] componentsInChildren = ((Component)_startup).GetComponentsInChildren<ChangeLog>(true); foreach (ChangeLog val in componentsInChildren) { if (!((Object)(object)val.m_scrollbar != (Object)(object)_startup.m_patchLogScroll) && !((Object)(object)val.m_textField == (Object)null)) { Scrollbar scrollbar = val.m_scrollbar; Transform val2 = ((scrollbar != null) ? ((Component)scrollbar).transform.parent : null); if ((Object)(object)val2 != (Object)null && val.m_textField.transform.IsChildOf(val2) && IsSafeTarget(((Component)val2).gameObject) && ((Object)(object)val.m_showPlayerLog == (Object)null || !val.m_showPlayerLog.transform.IsChildOf(val2))) { Hide(((Component)val2).gameObject); continue; } Hide(((Component)val.m_textField).gameObject); Scrollbar scrollbar2 = val.m_scrollbar; Hide((scrollbar2 != null) ? ((Component)scrollbar2).gameObject : null); } } Hide(_startup.m_moddedText); Button[] componentsInChildren2 = ((Component)_startup).GetComponentsInChildren<Button>(true); foreach (Button val3 in componentsInChildren2) { for (int j = 0; j < ((UnityEventBase)val3.onClick).GetPersistentEventCount(); j++) { if (((UnityEventBase)val3.onClick).GetPersistentTarget(j) == (Object)(object)_startup && ((UnityEventBase)val3.onClick).GetPersistentMethodName(j) == "OnMerchStoreButton") { Hide(((Component)val3).gameObject); break; } } } } private void RestoreTargets() { foreach (KeyValuePair<GameObject, bool> item in _hidden) { if ((Object)(object)item.Key != (Object)null) { item.Key.SetActive(item.Value); } } _hidden.Clear(); } internal void Dispose() { if (_open) { SetOpen(open: false); } if ((Object)(object)_launcher != (Object)null) { Object.Destroy((Object)(object)_launcher); } if ((Object)(object)_dialog != (Object)null) { Object.Destroy((Object)(object)_dialog); } _launcher = (_dialog = null); _optionalQuery?.Dispose(); _optionalQuery = null; _optionalLobbyQuery?.Dispose(); _optionalLobbyQuery = null; _optionalPanel?.Dispose(); _optionalPanel = null; _panel?.Dispose(); _panel = null; RestoreTargets(); _visible = false; } } private sealed class MenuTextPanel { private readonly FejdStartup _startup; private readonly bool _left; private RectTransform? _menu; private GameObject? _root; private ScrollRect? _scroll; private RectTransform? _content; private TMP_Text? _title; private TMP_Text? _body; private Scrollbar? _scrollbar; private Vector2 _lastSize; private bool _visible; private bool _needsLayout = true; private bool _inDialog; internal void UseDialog(Transform parent) { if (!_inDialog) { _inDialog = true; _root.transform.SetParent(parent, false); _needsLayout = true; } } internal MenuTextPanel(FejdStartup startup, bool left) { _startup = startup; _left = left; try { Create(); } catch { Dispose(); throw; } } internal void SetText(string title, string body) { _title.text = title; _body.text = body; _scroll.verticalNormalizedPosition = 1f; _needsLayout = true; } internal void UpdateLayout() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!_needsLayout) { Vector2 lastSize = _lastSize; Rect rect = _menu.rect; Vector2 val = lastSize - ((Rect)(ref rect)).size; if (!(((Vector2)(ref val)).sqrMagnitude > 0.25f)) { return; } } Reflow(); _needsLayout = false; } internal void HandleGuideKeys() { if (_scroll.vertical) { if (ZInput.GetKeyDown((KeyCode)281, true) || ZInput.GetButtonDown("JoyRBumper")) { _scroll.verticalNormalizedPosition = Mathf.Clamp01(_scroll.verticalNormalizedPosition - 0.25f); } else if (ZInput.GetKeyDown((KeyCode)280, true) || ZInput.GetButtonDown("JoyLBumper")) { _scroll.verticalNormalizedPosition = Mathf.Clamp01(_scroll.verticalNormalizedPosition + 0.25f); } } } private void Create() { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00e0: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_00f0: 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_011d: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Expected O, but got Unknown //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) _menu = _startup.m_mainMenu.GetComponent<RectTransform>(); TMP_Text connectionFailedError = _startup.m_connectionFailedError; if ((Object)(object)_menu == (Object)null || (Object)(object)connectionFailedError == (Object)null) { throw new InvalidOperationException("The vanilla menu canvas/font is unavailable."); } _root = new GameObject(_left ? "ServerManagerOptionalMods" : "ServerManagerJoinGuide", new Type[3] { typeof(RectTransform), typeof(Image), typeof(ScrollRect) }); _root.SetActive(false); _root.transform.SetParent((Transform)(object)_menu, false); RectTransform val = (RectTransform)_root.transform; Vector2 val2 = (val.pivot = (Vector2)(_left ? new Vector2(0f, 1f) : Vector2.one)); Vector2 anchorMin = (val.anchorMax = val2); val.anchorMin = anchorMin; ((Graphic)_root.GetComponent<Image>()).color = new Color(0.08f, 0.065f, 0.045f, 0.72f); GameObject val5 = new GameObject("Viewport", new Type[2] { typeof(RectTransform), typeof(RectMask2D) }); val5.transform.SetParent((Transform)(object)val, false); RectTransform val6 = (RectTransform)val5.transform; Stretch(val6, Vector2.zero, Vector2.zero); GameObject val7 = new GameObject("Content", new Type[1] { typeof(RectTransform) }); val7.transform.SetParent((Transform)(object)val6, false); _content = (RectTransform)val7.transform; _content.anchorMin = new Vector2(0f, 1f); _content.anchorMax = Vector2.one; _content.pivot = new Vector2(0.5f, 1f); _title = CreateText((Transform)(object)_content, connectionFailedError, "Heading", 26f, new Color(1f, 0.73f, 0.3f)); _body = CreateText((Transform)(object)_content, connectionFailedError, "Tips", 20f, new Color(0.96f, 0.94f, 0.88f)); _scroll = _root.GetComponent<ScrollRect>(); _scroll.viewport = val6; _scroll.content = _content; _scroll.horizontal = false; _scroll.movementType = (MovementType)2; _scroll.inertia = false; _scroll.scrollSensitivity = 28f; _scrollbar = CreateScrollbar(val); _scroll.verticalScrollbar = _scrollbar; _scroll.verticalScrollbarVisibility = (ScrollbarVisibility)0; } internal static TMP_Text CreateText(Transform parent, TMP_Text fontSource, string name, float size, Color color) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0054: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.SetActive(false); val.transform.SetParent(parent, false); TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).font = fontSource.font; ((TMP_Text)obj).fontSharedMaterial = fontSource.fontSharedMaterial; ((TMP_Text)obj).fontSize = size; ((Graphic)obj).color = color; ((TMP_Text)obj).alignment = (TextAlignmentOptions)257; ((TMP_Text)obj).enableAutoSizing = false; ((TMP_Text)obj).textWrappingMode = (TextWrappingModes)1; ((TMP_Text)obj).overflowMode = (TextOverflowModes)0; ((TMP_Text)obj).richText = false; ((TMP_Text)obj).margin = Vector4.zero; int num = (((TMP_Text)obj).maxVisibleLines = int.MaxValue); int maxVisibleCharacters = (((TMP_Text)obj).maxVisibleWords = num); ((TMP_Text)obj).maxVisibleCharacters = maxVisibleCharacters; ((TMP_Text)obj).rectTransform.anchorMin = new Vector2(0f, 1f); ((TMP_Text)obj).rectTransform.anchorMax = Vector2.one; ((TMP_Text)obj).rectTransform.pivot = new Vector2(0.5f, 1f); val.SetActive(true); return (TMP_Text)(object)obj; } internal static void Stretch(RectTransform rect, Vector2 minimum, Vector2 maximum) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.offsetMin = minimum; rect.offsetMax = maximum; } private static Scrollbar CreateScrollbar(RectTransform parent) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_004b: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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_00fd: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ScrollTrack", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Scrollbar) }); val.transform.SetParent((Transform)(object)parent, false); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = new Vector2(1f, 0f); val2.anchorMax = Vector2.one; val2.pivot = new Vector2(1f, 0.5f); val2.sizeDelta = new Vector2(6f, -40f); val2.anchoredPosition = new Vector2(-9f, 0f); ((Graphic)val.GetComponent<Image>()).color = new Color(1f, 1f, 1f, 0.09f); GameObject val3 = new GameObject("Handle", new Type[2] { typeof(RectTransform), typeof(Image) }); val3.transform.SetParent(val.transform, false); Image component = val3.GetComponent<Image>(); ((Graphic)component).color = new Color(0.85f, 0.72f, 0.48f, 0.8f); Stretch((RectTransform)val3.transform, Vector2.zero, Vector2.zero); Scrollbar component2 = val.GetComponent<Scrollbar>(); component2.direction = (Direction)2; component2.handleRect = (RectTransform)val3.transform; ((Selectable)component2).targetGraphic = (Graphic)(object)component; Navigation navigation = default(Navigation); ((Navigation)(ref navigation)).mode = (Mode)0; ((Selectable)component2).navigation = navigation; return component2; } internal void Reflow() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0227: 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_0253: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: 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_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) Rect rect = _menu.rect; _lastSize = ((Rect)(ref rect)).size; float verticalNormalizedPosition = _scroll.verticalNormalizedPosition; float y = _lastSize.y; Vector2 val = CalculateGuideSize(_lastSize.x, y, 0f); if (_inDialog) { val.x = Mathf.Min(800f, _lastSize.x * 0.9f); } float num = Mathf.Min(20f, val.x * 0.1f); float num2 = Mathf.Min(28f, val.x * 0.14f); float num3 = Mathf.Max(1f, val.x - num - num2); float num4 = _title.GetPreferredValues(_title.text, num3, float.PositiveInfinity).y + 4f; float num5 = _body.GetPreferredValues(_body.text, num3, float.PositiveInfinity).y + 4f; float num6 = num4 + 16f + num5; val = CalculateGuideSize(_lastSize.x, y, num6); RectTransform val2 = (RectTransform)_root.transform; val2.anchoredPosition = new Vector2((_left ? 1f : (-1f)) * Mathf.Min(24f, _lastSize.x * 0.05f), 0f - Mathf.Min(24f, _lastSize.y * 0.05f)); if (_inDialog) { ((Vector2)(ref val))..ctor(Mathf.Min(800f, _lastSize.x * 0.9f), Mathf.Max(1f, _lastSize.y - 100f)); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 1f); val2.pivot = val3; Vector2 anchorMin = (val2.anchorMax = val3); val2.anchorMin = anchorMin; val2.anchoredPosition = new Vector2(0f, -76f); } val2.sizeDelta = val; float num7 = Mathf.Min(20f, val.y * 0.1f); Stretch(_scroll.viewport, new Vector2(num, num7), new Vector2(0f - num2, 0f - num7)); RectTransform val5 = (RectTransform)((Component)_scrollbar).transform; val5.sizeDelta = new Vector2(Mathf.Min(6f, val.x * 0.04f), -2f * num7); val5.anchoredPosition = new Vector2(0f - Mathf.Min(9f, val.x * 0.05f), 0f); _content.sizeDelta = new Vector2(0f, num6); _title.rectTransform.sizeDelta = new Vector2(0f, num4); _title.rectTransform.anchoredPosition = Vector2.zero; _body.rectTransform.sizeDelta = new Vector2(0f, num5); _body.rectTransform.anchoredPosition = new Vector2(0f, 0f - num4 - 16f); val2.ForceUpdateRectTransforms(); _title.ForceMeshUpdate(false, false); _body.ForceMeshUpdate(false, false); _scroll.vertical = num6 > Mathf.Max(1f, val.y - 2f * num7) + 0.5f; ((Component)_scrollbar).gameObject.SetActive(_scroll.vertical); _scroll.verticalNormalizedPosition = (_scroll.vertical ? Mathf.Clamp01(verticalNormalizedPosition) : 1f); } internal void SetVisible(bool visible) { if (!((Object)(object)_root == (Object)null)) { if (visible && !_visible) { _scroll.verticalNormalizedPosition = 1f; _needsLayout = true; } _visible = visible; _root.SetActive(visible); } } internal void Dispose() { _visible = false; if ((Object)(object)_root != (Object)null) { _root.SetActive(false); Object.Destroy((Object)(object)_root); } _root = null; } } private enum LogoDownloadFailure { HttpStatus, Network, Redirect, TooLarge, InvalidPng } private sealed class LogoDownloadException : Exception { internal readonly LogoDownloadFailure Failure; internal readonly int Status; internal LogoDownloadException(LogoDownloadFailure failure, int status = 0) : base("HTTPS logo download failed.") { Failure = failure; Status = status; } } internal const ushort DefaultServerPort = 2456; internal const int MaximumEndpointCharacters = 512; internal const int MaximumLogoBytes = 8388608; internal const int MaximumLogoDimension = 4096; internal const long MaximumLogoPixels = 16777216L; internal const int MaximumLogoUrlCharacters = 2048; internal const int LogoDownloadTimeoutSeconds = 30; internal const int MaximumLogoRedirects = 3; private static readonly FieldInfo? QueuedJoinServerField = AccessTools.Field(typeof(FejdStartup), "m_queuedJoinServer"); private static readonly PropertyInfo? ServerPasswordProperty = AccessTools.Property(typeof(FejdStartup), "ServerPassword"); private static readonly FieldInfo? LocalizationTextMeshStringsField = AccessTools.Field(typeof(Localization), "textMeshStrings"); private static FejdStartup? _startup; private static LabelOverride? _mainButtonLabel; private static LabelOverride? _characterButtonLabel; private static bool _armed; private static bool _passwordAwaitingHandshake; private static bool _brandedJoinDispatched; private static string _pendingPassword = string.Empty; private static string? _ownedPassword; private static string? _previousPassword; private static bool _passwordWasOverridden; private static Image? _logoImage; private static Sprite? _vanillaLogo; private static bool _vanillaLogoPreserveAspect; private static Sprite? _customLogo; private static Texture2D? _customLogoTexture; private static string? _logoSource; private static RemoteLogoLoad? _remoteLogoLoad; private static string? _remoteLogoAttemptedSource; private static string _lastEndpointWarning = string.Empty; private static string _lastLogoWarning = string.Empty; private static string _lastQueuedJoinAccessWarning = string.Empty; private static string _lastServerPasswordAccessWarning = string.Empty; private static string _lastLocalizationCacheAccessWarning = string.Empty; private static MenuGuide? _menuGuide; private static bool _menuGuideFailed; private static bool _customMenuActive; private static bool IsCustomMenuActive() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown if (!Chainloader.PluginInfos.TryGetValue("rdmods.custommainmenu", out var value) || (Object)(object)value.Instance == (Object)null) { return false; } ConfigEntry<bool> val = default(ConfigEntry<bool>); if (value.Instance.Config.TryGetEntry<bool>(new ConfigDefinition("General", "Enabled"), ref val)) { return val.Value; } return true; } private static void RefreshMenuCompatibility(FejdStartup startup) { bool flag = IsCustomMenuActive(); if (flag != _customMenuActive) { _customMenuActive = flag; ResetMenuGuide(); ApplyLogo(startup); } } internal static bool BeforeUiUpdate() { MenuGuide? menuGuide = _menuGuide; if (menuGuide == null) { return true; } return !menuGuide.HandleDialogInput(); } private static void ResetMenuGuide() { _menuGuide?.Dispose(); _menuGuide = null; _menuGuideFailed = false; } private static void UpdateMenuGuide(FejdStartup startup, bool refreshText = false) { if (!CanUseClientUi(startup)) { ResetMenuGuide(); return; } ObserveStartup(startup); if (_menuGuideFailed) { return; } try { if (_menuGuide == null) { _menuGuide = new MenuGuide(startup); } _menuGuide.Update(refreshText); } catch (Exception ex) when (!IntegrityCanonical.IsFatal(ex)) { ResetMenuGuide(); _menuGuideFailed = true; ServerManagerPlugin.Log.LogWarning((object)("Client menu guidance was unavailable; vanilla UI restored: " + ex.Message)); } } internal static bool ShouldShowWorldMenuHint(string? endpoint) { string host; ushort port; string rejection; if (endpoint == null || !endpoint.Trim().StartsWith("steam:", StringComparison.OrdinalIgnoreCase)) { return TryParseDedicatedEndpoint(endpoint, out host, out port, out rejection); } ulong host2; return OptionalModLobbyQuery.TryParseHostEndpoint(endpoint, out host2); } internal static Vector2 CalculateGuideSize(float menuWidth, float menuHeight, float preferredHeight) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (float.IsNaN(menuWidth) || float.IsInfinity(menuWidth) || menuWidth <= 0f || float.IsNaN(menuHeight) || float.IsInfinity(menuHeight) || menuHeight <= 0f) { return Vector2.zero; } float num = Mathf.Min(440f, menuWidth * 0.27f); float num2 = menuHeight - Mathf.Min(48f, menuHeight * 0.1f); float num3 = ((float.IsNaN(preferredHeight) || float.IsInfinity(preferredHeight)) ? num2 : (Mathf.Max(0f, preferredHeight) + 40f)); return new Vector2(num, Mathf.Min(num2, num3)); } private static IReadOnlyDictionary<string, System.Version> CaptureLoadedOptionalModVersions() { Dictionary<string, System.Version> dictionary = new Dictionary<string, System.Version>(StringComparer.Ordinal); try { foreach (PluginInfo value in Chainloader.PluginInfos.Values) { object obj; if (value == null) { obj = null; } else { BepInPlugin metadata = value.Metadata; obj = ((metadata != null) ? metadata.Version : null); } if (!((System.Version?)obj == null) && !((Object)(object)value.Instance == (Object)null) && IntegrityCanonical.TryNormalizeGuid(value.Metadata.GUID, IntegrityLimits.Default, "manifest.invalid_guid", out string canonical, out IntegrityDiagnostic _)) { if (dictionary.ContainsKey(canonical)) { dictionary.Clear(); return dictionary; } dictionary.Add(canonical, value.Metadata.Version); } } } catch (Exception exception) when (!IntegrityCanonical.IsFatal(exception)) { dictionary.Clear(); } return dictionary; } internal static bool IsOptionalModLoaded(OptionalModCatalogEntry entry, IReadOnlyDictionary<string, System.Version>? loaded) { if (loaded == null || !loaded.TryGetValue(entry.PluginGuid, out System.Version value)) { return false; } foreach (string version in entry.Versions) { if (System.Version.TryParse(version, out System.Version result) && result.Equals(value)) { return true; } } return false; } internal static string FormatOptionalList(OptionalModQueryState state, bool stale, IReadOnlyList<OptionalModCatalogEntry> entries, IReadOnlyDictionary<string, System.Version>? loaded) { StringBuilder stringBuilder = new StringBuilder(PlayerLocalizer.Text(state switch { OptionalModQueryState.Loading => "sm_menu_optional_loading", OptionalModQueryState.Unsupported => "sm_menu_optional_unsupported", OptionalModQueryState.TooLarge => "sm_menu_optional_too_large", OptionalModQueryState.Unavailable => "sm_menu_optional_unavailable", _ => "sm_menu_optional_note", })); if (stale) { stringBuilder.Append("\n\n").Append(PlayerLocalizer.Text("sm_menu_optional_stale")); } if (state != OptionalModQueryState.Available && !stale) { return stringBuilder.ToString(); } if (entries.Count == 0) { return stringBuilder.Append("\n\n").Append(PlayerLocalizer.Text("sm_menu_optional_empty")).ToString(); } int num = 0; foreach (OptionalModCatalogEntry entry in entries) { if (!IsOptionalModLoaded(entry, loaded)) { num++; stringBuilder.Append("\n\n").Append(entry.Name).Append("\n"); stringBuilder.Append((entry.Versions.Count == 0) ? PlayerLocalizer.Text("sm_menu_optional_version_unknown") : string.Join(", ", entry.Versions)); } } if (num == 0) { stringBuilder.Append("\n\n").Append(PlayerLocalizer.Text("sm_menu_optional_installed")); } return stringBuilder.ToString(); } internal static bool TryParseDedicatedEndpoint(string? value, out string host, out ushort port, out string rejection) { host = string.Empty; port = 0; rejection = string.Empty; string text = value?.Trim() ?? string.Empty; if (text.Length == 0) { rejection = "Server Address is empty."; return false; } if (text.Length > 512) { rejection = "Server Address is too long."; return false; } string text2 = text; foreach (char c in text2) { if (char.IsControl(c) || char.IsWhiteSpace(c)) { rejection = "Server Address may not contain whitespace or control characters."; return false; } } if (text.IndexOf("://", StringComparison.Ordinal) >= 0 || text.IndexOf('/') >= 0 || text.IndexOf('\\') >= 0 || text.IndexOf('@') >= 0 || text.IndexOf('?') >= 0 || text.IndexOf('#') >= 0) { rejection = "Server Address must be a host or IP with an optional port, not a URL."; return false; } ushort port2 = 2456; string ipString; if (text[0] == '[') { int num = text.IndexOf(']'); if (num <= 1) { rejection = "The bracketed IPv6 host is invalid."; return false; } ipString = text.Substring(1, num - 1); string text3 = text.Substring(num + 1); if (text3.Length > 0 && (text3[0] != ':' || !TryParsePort(text3.Substring(1), out port2))) { rejection = "The server port is invalid."; return false; } if (!IPAddress.TryParse(ipString, out IPAddress address) || address.AddressFamily != AddressFamily.InterNetworkV6) { rejection = "The bracketed host is not a valid IPv6 address."; return false; } ipString = address.ToString(); } else { int num2 = 0; text2 = text; for (int i = 0; i < text2.Length; i++) { if (text2[i] == ':') { num2++; } } switch (num2) { case 0: ipString = text; break; case 1: { int num3 = text.LastIndexOf(':'); ipString = text.Substring(0, num3); if (!TryParsePort(text.Substring(num3 + 1), out port2)) { rejection = "The server port is invalid."; return false; } break; } default: { if (!IPAddress.TryParse(text, out IPAddress address2) || address2.AddressFamily != AddressFamily.InterNetworkV6) { rejection = "IPv6 addresses with an explicit port must use [address]:port."; return false; } ipString = address2.ToString(); break; } } } if (ipString.Length == 0 || ipString.Length > 253) { rejection = "The server host is empty or too long."; return false; } if (IPAddress.TryParse(ipString, out IPAddress address3)) { ipString = address3.ToString(); } else if (Uri.CheckHostName(ipString) != UriHostNameType.Dns) { rejection = "The server host is not a valid DNS name or IP address."; return false; } host = ipString; port = port2; return true; } internal static bool TryParseLogoUrl(string? value, out Uri url, out string rejection) { url = null; rejection = "Logo URL must be an HTTPS address without credentials, fragments or whitespace."; string text = value ?? string.Empty; if (text.Length == 0 || text.Length > 2048) { return false; } string text2 = text; foreach (char c in text2) { if (char.IsControl(c) || char.IsWhiteSpace(c)) { return false; } } if (text.IndexOf('\\') >= 0 || !Uri.TryCreate(text, UriKind.Absolute, out Uri result) || result.Scheme != Uri.UriSchemeHttps || string.IsNullOrEmpty(result.Host) || result.UserInfo.Length != 0 || result.Fragment.Length != 0 || result.HostNameType == UriHostNameType.Unknown) { return false; } url = result; rejection = string.Empty; return true; } private static string LogoDownloadFailureMessage(Exception exception) { if (exception is TimeoutException) { return "The HTTPS menu logo download timed out after " + 30.ToString(CultureInfo.InvariantCulture) + " seconds; keeping the cached or vanilla logo."; } if (exception is OperationCanceledException) { return "The HTTPS menu logo download was cancelled; keeping the cached or vanilla logo."; } if (exception is LogoDownloadException ex) { switch (ex.Failure) { case LogoDownloadFailure.HttpStatus: { string text; if (ex.Status < 100 || ex.Status > 599) { text = string.Empty; } else { int status = ex.Status; text = " (HTTP " + status.ToString(CultureInfo.InvariantCulture) + ")"; } return "The HTTPS menu logo server returned an HTTP error" + text + "; keeping the cached or vanilla logo."; } case LogoDownloadFailure.Network: return "The HTTPS menu logo download failed (network/TLS transport error); keeping the cached or vanilla logo."; case LogoDownloadFailure.Redirect: return "The HTTPS menu logo redirect was invalid or exceeded " + 3.ToString(CultureInfo.InvariantCulture) + " redirects; keeping the cached or vanilla logo."; case LogoDownloadFailure.TooLarge: return "The HTTPS menu logo response exceeds the 8 MiB size limit; keeping the cached or vanilla logo."; case LogoDownloadFailure.InvalidPng: return "The HTTPS menu logo response failed PNG validation; keeping the cached or vanilla logo."; } } return "The HTTPS menu logo download failed; keeping the cached or vanilla logo."; } internal static async Task<byte[]> DownloadLogoAsync(Uri url, CancellationToken cancellation, HttpMessageHandler? handler = null) { if (url == null || !url.IsAbsoluteUri || !TryParseLogoUrl(url.AbsoluteUri, out Uri destination, out string rejection)) { throw new InvalidDataException("Invalid HTTPS logo address."); } using CancellationTokenSource deadline = CancellationTokenSource.CreateLinkedTokenSource(new CancellationToken[1] { cancellation }); deadline.CancelAfter(TimeSpan.FromSeconds(30.0)); CancellationToken token = deadline.Token; try { if (handler == null) { handler = (HttpMessageHandler?)new HttpClientHandler { AllowAutoRedirect = false, UseCookies = false, UseDefaultCredentials = false, Credentials = null, AutomaticDecompression = DecompressionMethods.None, MaxResponseHeadersLength = 16 }; } HttpClient client = new HttpClient(handler, true) { Timeout = Timeout.InfiniteTimeSpan }; try { int redirects = 0; while (true) { token.ThrowIfCancellationRequested(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, destination); int height; try { request.Headers.Accept.ParseAdd("image/png"); HttpResponseMessage response = await AwaitLogoTask(client.SendAsync(request, (HttpCompletionOption)1, token), token, delegate(HttpResponseMessage late) { late.Dispose(); }).ConfigureAwait(continueOnCapturedContext: false); try { int statusCode = (int)response.StatusCode; switch (statusCode) { case 301: case 302: case 303: case 307: case 308: { Uri location = response.Headers.Location; if (redirects >= 3 || location == null || !Uri.TryCreate(destination, location, out Uri result) || !TryParseLogoUrl(result.AbsoluteUri, out destination, out rejection)) { throw new LogoDownloadException(LogoDownloadFailure.Redirect); } break; } default: throw new LogoDownloadException(LogoDownloadFailure.HttpStatus, statusCode); case 200: { if (response.Content == null) { throw new LogoDownloadException(LogoDownloadFailure.InvalidPng); } if (response.Content.Headers.ContentLength > 8388608) { throw new LogoDownloadException(LogoDownloadFailure.TooLarge); } using Stream stream = await AwaitLogoTask(response.Content.ReadAsStreamAsync(), token, delegate(Stream late) { late.Dispose(); }).ConfigureAwait(continueOnCapturedContext: false); using MemoryStream output = new MemoryStream(); byte[] buffer = new byte[16384]; while (true) { int num = await AwaitLogoTask(stream.ReadAsync(buffer, 0, buffer.Length, token), token).ConfigureAwait(continueOnCapturedContext: false); token.ThrowIfCancellationRequested(); if (num == 0) { break; } if (output.Length + num > 8388608) { throw new LogoDownloadException(LogoDownloadFailure.TooLarge); } output.Write(buffer, 0, num); } byte[] array = output.ToArray(); if (!TryValidatePng(array, out int _, out height, out rejection)) { throw new LogoDownloadException(LogoDownloadFailure.InvalidPng); } return array; } } } finally { ((IDisposable)response)?.Dispose(); } } finally { ((IDisposable)request)?.Dispose(); } height = redirects + 1; redirects = height; } } finally { ((IDisposable)client)?.Dispose(); } } catch (OperationCanceledException) when (!cancellation.IsCancellationRequested && deadline.IsCancellationRequested) { throw new TimeoutException("HTTPS logo download deadline exceeded."); } catch (OperationCanceledException) { throw; } catch (LogoDownloadException) { throw; } catch (Exception exception) when (!IntegrityCanonical.IsFatal(exception)) { throw new LogoDownloadException(LogoDownloadFailure.Network); } } private static async Task<T> AwaitLogoTask<T>(Task<T> task, CancellationToken token, Action<T>? abandoned = null) { if (task.IsCompleted) { return await task.ConfigureAwait(continueOnCapturedContext: false); } TaskCompletionSource<bool> cancelled = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously); using (token.Register(delegate { cancelled.TrySetResult(result: true); })) { if (await Task.WhenAny(new Task[2] { task, cancelled.Task }).ConfigureAwait(continueOnCapturedContext: false) != task) { task.ContinueWith(delegate(Task<T> completed) { if (completed.IsFaulted) { _ = completed.Exception; } else if (completed.Status == TaskStatus.RanToCompletion && abandoned != null) { try { abandoned(completed.Result); } catch (Exception) { } } }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); throw new OperationCanceledException(token); } return await task.ConfigureAwait(continueOnCapturedContext: false); } } internal static string GetLogoCachePath(string cacheRoot, Uri url) { if (string.IsNullOrWhiteSpace(cacheRoot) || url == null || !url.IsAbsoluteUri || !TryParseLogoUrl(url.AbsoluteUri, out Uri url2, out string _)) { throw new InvalidDataException("The logo cache location is unavailable."); } using SHA256 sHA = SHA256.Create(); string text = BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(url2.AbsoluteUri))).Replace("-", string.Empty).ToLowerInvariant(); return Path.Combine(Path.GetFullPath(cacheRoot), "logos", text + ".png"); } internal static byte[] ReadLogoBytes(string path) { using FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); long length = fileStream.Length; if (length > 8388608) { throw new InvalidDataException("The logo exceeds the byte limit."); } byte[] array = new byte[checked((int)length)]; int num; for (int i = 0; i < array.Length; i += num) { num = fileStream.Read(array, i, array.Length - i); if (num == 0) { throw new EndOfStreamException("The logo file is incomplete."); } } if (fileStream.ReadByte() != -1 || !TryValidatePng(array, out int _, out int _, out string _)) { throw new InvalidDataException("The logo file is not a valid bounded PNG."); } return array; } internal static void WriteLogoCache(string path, byte[] data) { if (!TryValidatePng(data, out int _, out int _, out string rejection)) { throw new InvalidDataException(rejection); } string? path2 = Path.GetDirectoryName(path) ?? throw new InvalidDataException("Invalid logo cache path."); Directory.CreateDirectory(path2); if ((File.GetAttributes(path2) & FileAttributes.ReparsePoint) != FileAttributes.None || (File.Exists(path) && (File.GetAttributes(path) & FileAttributes.ReparsePoint) != FileAttributes.None)) { throw new InvalidDataException("The logo cache must use regular files and directories."); } string text = path + "." + Guid.NewGuid().ToString("N") + ".tmp"; bool flag = false; try { using (FileStream fileStream = new FileStream(text, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { flag = true; fileStream.Write(data, 0, data.Length); fileStream.Flush(flushToDisk: true); } if (File.Exists(path)) { File.Replace(text, path, null); } else { File.Move(text, path); } flag = false; } finally { if (flag) { try { File.Delete(text); } catch (IOException) { } catch (UnauthorizedAccessException) { } } } } internal static bool TryResolveLogoPath(string? bepinexRoot, string? relativePath, out string fullPath, out string rejection) { fullPath = string.Empty; rejection = string.Empty; string text = bepinexRoot?.Trim() ?? string.Empty; string text2 = relativePath?.Trim() ?? string.Empty; if (text.Length == 0) { rejection = "The BepInEx root is unavailable."; return false; } if (text2.Length == 0) { rejection = "Logo Path is empty."; return false; } if (Path.IsPathRooted(text2) || text2.IndexOf(':') >= 0) { rejection = "Logo Path must be relative to the BepInEx directory."; return false; } if (!string.Equals(Path.GetExtension(text2), ".png", StringComparison.OrdinalIgnoreCase)) { rejection = "Logo Path must name a PNG file."; return false; } try { string text3 = Path.GetFullPath(text).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); string fullPath2 = Path.GetFullPath(Path.Combine(text3, text2)); char directorySeparatorChar = Path.DirectorySeparatorChar; string value = text3 + directorySeparatorChar; StringComparison comparisonType = ((Path.DirectorySeparatorChar == '\\') ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); if (!fullPath2.StartsWith(value, comparisonType)) { rejection = "Logo Path may not leave the BepInEx directory."; return false; } fullPath = fullPath2; return true; } catch (Exception ex) when (ex is ArgumentException || ex is NotSupportedException || ex is PathTooLongException) { rejection = "Logo Path is invalid: " + ex.Message; return false; } } internal static bool TryValidatePng(byte[]? data, out int width, out int height, out string rejection) { width = 0; height = 0; rejection = string.Empty; if (data == null || data.Length < 33) { rejection = "The logo is not a complete PNG file."; return false; } if (data.Length > 8388608) { rejection = $"The logo exceeds the {8388608} byte limit."; return false; } byte[] array = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 }; for (int i = 0; i < array.Length; i++) { if (data[i] != array[i]) { rejection = "The logo does not have a valid PNG signature."; return false; } } if (ReadBigEndianUInt32(data, 8) != 13 || data[12] != 73 || data[13] != 72 || data[14] != 68 || data[15] != 82) { rejection = "The logo PNG does not begin with a valid IHDR chunk."; return false; } uint num = ReadBigEndianUInt32(data, 16); uint num2 = ReadBigEndianUInt32(data, 20); if (num == 0 || num2 == 0 || num > 4096 || num2 > 4096 || (long)num * (long)num2 > 16777216) { rejection = $"The logo dimensions must be between 1 and {4096} pixels " + "and remain within the decoded pixel limit."; return false; } width = (int)num; height = (int)num2; return true; } internal static void OnSetupGui(FejdStartup startup) { if (CanUseClientUi(startup)) { ObserveStartup(startup); RefreshMenuCompatibility(startup); ResetMenuGuide(); UpdateMenuGuide(startup); ApplyLogo(startup); if (TryGetConfiguredEndpoint(out var _)) { ApplyMainButtonText(startup); } } } internal static void BeforeMainStart(FejdStartup startup) { CancelFlow(clearConnectionPassword: true); if (CanUseClientUi(startup) && !IsAltBypassPressed() && !HasQueuedJoinOrCannotInspect(startup) && TryGetConfiguredEndpoint(out var _)) { _armed = true; } } internal static void AfterMainStart(FejdStartup startup) { if (CanUseClientUi(startup)) { ObserveStartup(startup); ApplyCharacterButtonText(startup); } } internal static void AfterCharacterListUpdated(FejdStartup startup) { if (CanUseClientUi(startup)) { ObserveStartup(startup); ApplyCharacterButtonText(startup); } } internal static void OnUiUpdate(FejdStartup startup) { if (CanUseClientUi(startup)) { RefreshMenuCompatibility(startup); } UpdateMenuGuide(startup); TickRemoteLogo(startup); if (_armed && CanUseClientUi(startup) && HasQueuedJoinOrCannotInspect(startup)) { CancelFlow(clearConnectionPassword: true); ApplyCharacterButtonText(startup); } } internal static void BeforeCharacterStart(FejdStartup startup) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (!_armed) { return; } if (!CanUseClientUi(startup) || IsAltBypassPressed() || HasQueuedJoinOrCannotInspect(startup) || !TryGetConfiguredEndpoint(out var destination)) { CancelFlow(clearConnectionPassword: true); ApplyCharacterButtonText(startup); return; } string pendingPassword = ServerManagerPlugin.BrandingServerPassword?.Value ?? string.Empty; if (!TrySetQueuedJoinServer(startup, destination)) { CancelFlow(clearConnectionPassword: true); ApplyCharacterButtonText(startup); return; } _pendingPassword = pendingPassword; _passwordAwaitingHandshake = true; _brandedJoinDispatched = false; _armed = false; RestoreLabel(ref _characterButtonLabel); } internal static void AfterCharacterStart(FejdStartup startup) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (_passwordAwaitingHandshake && !_brandedJoinDispatched) { TrySetQueuedJoinServer(startup, ServerJoinData.None); ClearConnectionPasswordState(); } } internal static void BeforeTransitionToMainScene(FejdStartup startup) { if (_passwordAwaitingHandshake && _startup == startup) { _brandedJoinDispatched = true; } } internal static void AfterCharacterSelectionBack(FejdStartup startup) { CancelFlow(clearConnectionPassword: true); if (CanUseClientUi(startup)) { ApplyCharacterButtonText(startup); } } internal static void AfterLanguageChanged(FejdStartup startup) { if (CanUseClientUi(startup)) { ObserveStartup(startup); UpdateMenuGuide(startup, refreshText: true); if (TryGetConfiguredEndpoint(out var _)) { ApplyMainButtonText(startup); } ApplyCharacterButtonText(startup); } } internal static void BeforeClientHandshake(ZNet znet) { if (!((Object)(object)znet == (Object)null) && !znet.IsServer() && _passwordAwaitingHandshake && _brandedJoinDispatched) { string text = ((_pendingPassword.Length == 0) ? null : _pendingPassword); if (!TryGetServerPassword(out string password) || !TrySetServerPassword(text)) { ClearConnectionPasswordState(); return; } _previousPassword = password; _ownedPassword = text; _passwordWasOverridden = true; } } internal static void AfterClientHandshake(ZNet znet) { if ((Object)(object)znet != (Object)null && !znet.IsServer()) { ClearConnectionPasswordState(); } } internal static void BeforeStartupDestroyed(FejdStartup startup) { if (_startup == startup) { ResetMenuGuide(); _armed = false; if (!_brandedJoinDispatched) { ClearConnectionPasswordState(); } else { ClearOwnedPassword(); } RestoreLabel(ref _mainButtonLabel); RestoreLabel(ref _characterButtonLabel); ReleaseCustomLogo(restoreVanilla: true); _startup = null; } } internal static void OnConnectionError() { CancelFlow(clearConnectionPassword: true); } internal static void Shutdown() { ResetMenuGuide(); CancelFlow(clearConnectionPassword: true); RestoreLabel(ref _mainButtonLabel); RestoreLabel(ref _characterButtonLabel); ReleaseCustomLogo(restoreVanilla: true); _startup = null; _lastEndpointWarning = string.Empty; _lastLogoWarning = string.Empty; _lastQueuedJoinAccessWarning = string.Empty; _lastServerPasswordAccessWarning = string.Empty; _lastLocalizationCacheAccessWarning = string.Empty; } private static bool TryParsePort(string value, out ushort port) { if (ushort.TryParse(value, out port)) { return port != 0; } return false; } private static uint ReadBigEndianUInt32(byte[] data, int offset) { return (uint)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); } private static bool CanUseClientUi(FejdStartup? startup) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 if ((Object)(object)startup != (Object)null && !Application.isBatchMode) { return (int)SystemInfo.graphicsDeviceType != 4; } return false; } private static bool HasQueuedJoinOrCannotInspect(FejdStartup startup) { if (TryGetQueuedJoinServer(startup, out var queuedJoin)) { return ((ServerJoinData)(ref queuedJoin)).IsValid; } return true; } private static bool TryGetQueuedJoinServer(FejdStartup startup, out ServerJoinData queuedJoin) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) queuedJoin = ServerJoinData.None; FieldInfo queuedJoinServerField = QueuedJoinServerField; if (queuedJoinServerField == null) { WarnOnce(ref _lastQueuedJoinAccessWarning, "missing", "Client branding quick-connect is disabled because Valheim's queued-join field could not be found."); return false; } try { if (queuedJoinServerField.GetValue(startup) is ServerJoinData val) { queuedJoin = val; return true; } WarnOnce(ref _lastQueuedJoinAccessWarning, "unexpected-type", "Client branding quick-connect is disabled because Valheim's queued-join field has an unexpected type."); } catch (Exception ex) { WarnOnce(ref _lastQueuedJoinAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding quick-connect could not inspect Valheim's queued destination: " + ex.Message); } return false; } private static bool TrySetQueuedJoinServer(FejdStartup startup, ServerJoinData queuedJoin) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) FieldInfo queuedJoinServerField = QueuedJoinServerField; if (queuedJoinServerField == null) { WarnOnce(ref _lastQueuedJoinAccessWarning, "missing", "Client branding quick-connect is disabled because Valheim's queued-join field could not be found."); return false; } try { queuedJoinServerField.SetValue(startup, queuedJoin); return true; } catch (Exception ex) { WarnOnce(ref _lastQueuedJoinAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding quick-connect could not update Valheim's queued destination: " + ex.Message); return false; } } private static bool TryGetServerPassword(out string? password) { password = null; PropertyInfo serverPasswordProperty = ServerPasswordProperty; if (serverPasswordProperty == null || !serverPasswordProperty.CanRead) { WarnOnce(ref _lastServerPasswordAccessWarning, "missing-getter", "Client branding could not locate Valheim's server-password property."); return false; } try { object value = serverPasswordProperty.GetValue(null, null); if (value == null || value is string) { password = (string)value; return true; } WarnOnce(ref _lastServerPasswordAccessWarning, "unexpected-type", "Client branding found an unexpected Valheim server-password type."); } catch (Exception ex) { WarnOnce(ref _lastServerPasswordAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding could not read Valheim's server password: " + ex.Message); } return false; } private static bool TrySetServerPassword(string? password) { PropertyInfo serverPasswordProperty = ServerPasswordProperty; if (serverPasswordProperty?.GetSetMethod(nonPublic: true) == null) { WarnOnce(ref _lastServerPasswordAccessWarning, "missing-setter", "Client branding could not locate Valheim's server-password setter."); return false; } try { serverPasswordProperty.SetValue(null, password, null); return true; } catch (Exception ex) { WarnOnce(ref _lastServerPasswordAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding could not update Valheim's server password: " + ex.Message); return false; } } internal static bool TryGetLocalizationTextMeshStrings(Localization localization, out Dictionary<TMP_Text, string> textMeshStrings) { textMeshStrings = null; FieldInfo localizationTextMeshStringsField = LocalizationTextMeshStringsField; if (localizationTextMeshStringsField == null) { WarnOnce(ref _lastLocalizationCacheAccessWarning, "missing", "Client branding could not locate Valheim's TMP localization cache."); return false; } try { if (localizationTextMeshStringsField.GetValue(localization) is Dictionary<TMP_Text, string> dictionary) { textMeshStrings = dictionary; return true; } WarnOnce(ref _lastLocalizationCacheAccessWarning, "unexpected-type", "Client branding found an unexpected TMP localization-cache type."); } catch (Exception ex) { WarnOnce(ref _lastLocalizationCacheAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding could not inspect Valheim's TMP localization cache: " + ex.Message); } return false; } private static bool IsAltBypassPressed() { if (!ZInput.GetKey((KeyCode)308, true)) { return ZInput.GetKey((KeyCode)307, true); } return true; } internal static bool TryCreateJoinDestination(string? value, out ServerJoinData destination, out string rejection) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) destination = ServerJoinData.None; if (value != null && value.Trim().StartsWith("steam:", StringComparison.OrdinalIgnoreCase)) { rejection = "Use steam:<host Steam64 ID> for a Steam local-host server."; if (!OptionalModLobbyQuery.TryParseHostEndpoint(value, out var host)) { return false; } destination = new ServerJoinData(new ServerJoinDataSteamUser(host)); rejection = string.Empty; return true; } if (!TryParseDedicatedEndpoint(value, out string host2, out ushort port, out rejection)) { return false; } destination = new ServerJoinData(new ServerJoinDataDedicated(host2, port)); return true; } private static bool TryGetConfiguredEndpoint(out ServerJoinData destination) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) string text = ServerManagerPlugin.BrandingServerAddress?.Value ?? string.Empty; if (string.IsNullOrWhiteSpace(text)) { destination = ServerJoinData.None; _lastEndpointWarning = string.Empty; return false; } if (TryCreateJoinDestination(text, out destination, out string rejection)) { _lastEndpointWarning = string.Empty; return true; } WarnOnce(ref _lastEndpointWarning, text + "\n" + rejection, "Client branding quick-connect is disabled for this menu session: " + rejection); return false; } private static void ObserveStartup(FejdStartup startup) { if (_startup != startup) { ResetMenuGuide(); CancelFlow(clearConnectionPassword: true); RestoreLabel(ref _mainButtonLabel); RestoreLabel(ref _characterButtonLabel); ReleaseCustomLogo(restoreVanilla: true); _startup = startup; } } private static void ApplyMainButtonText(FejdStartup startup) { TMP_Text val = FindMainStartButtonText(startup); string configuredButtonText = GetConfiguredButtonText(); if (!((Object)(object)val == (Object)null) && configuredButtonText.Length != 0) { ApplyLabel(ref _mainButtonLabel, val, configuredButtonText); } } private static void ApplyCharacterButtonText(FejdStartup startup) { TMP_Text val = (((Object)(object)startup.m_csStartButton == (Object)null) ? null : ((Component)startup.m_csStartButton).GetComponentInChildren<TMP_Text>(true)); if ((Object)(object)val == (Object)null) { return; } if (_armed) { string configuredButtonText = GetConfiguredButtonText(); if (configuredButtonText.Length != 0) { ApplyLabel(ref _characterButtonLabel, val, configuredButtonText); } } else { RestoreLabel(ref _characterButtonLabel); } } private static TMP_Text? FindMainStartButtonText(FejdStartup startup) { if (_mainButtonLabel != null) { return _mainButtonLabel.Text; } if ((Object)(object)startup.m_menuList == (Object)null) { return null; } Button[] componentsInChildren = startup.m_menuList.GetComponentsInChildren<Button>(true); Button val = ((componentsInChildren.Length != 0) ? componentsInChildren[0] : null); Button[] array = componentsInChildren; foreach (Button val2 in array) { int persistentEventCount = ((UnityEventBase)val2.onClick).GetPersistentEventCount(); for (int j = 0; j < persistentEventCount; j++) { if (string.Equals(((UnityEventBase)val2.onClick).GetPersistentMethodName(j), "OnStartGame", StringComparison.Ordinal)) { return ((Component)val2).GetComponentInChildren<TMP_Text>(true); } } } if (!((Object)(object)val == (Object)null)) { return ((Component)val).GetComponentInChildren<TMP_Text>(true); } return null; } private static string GetConfiguredButtonText() { string text = ServerManagerPlugin.BrandingButtonText?.Value?.Trim() ?? string.Empty; if (text.Length > 128) { return text.Substring(0, 128); } return text; } private static void ApplyLabel(ref LabelOverride? current, TMP_Text text, string label) { if (current == null || current.Text != text) { RestoreLabel(ref current); current = new LabelOverride(text); } if (!current.LocalizationDetached) { Localization instance = Localization.instance; if (instance != null) { instance.RemoveTextFromCache(text); current.LocalizationDetached = true; } } ConfigureLabelForLongText(text); text.text = label; } private static void ConfigureLabelForLongText(TMP_Text text) { text.enableAutoSizing = true; text.textWrappingMode = (TextWrappingModes)0; text.fontSizeMin = Mathf.Min((text.fontSizeMin > 0f) ? text.fontSizeMin : 12f, 12f); text.fontSizeMax = Mathf.Max(text.fontSizeMax, text.fontSize); } private static void RestoreLabel(ref LabelOverride? current) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) LabelOverride labelOverride = current; current = null; if (labelOverride != null && !((Object)(object)labelOverride.Text == (Object)null)) { TMP_Text text = labelOverride.Text; Localization instance = Localization.instance; if (labelOverride.LocalizationDetached && labelOverride.HadLocalizationSource && labelOverride.LocalizationSource != null && instance != null && TryGetLocalizationTextMeshStrings(instance, out Dictionary<TMP_Text, string> textMeshStrings)) { textMeshStrings[text] = labelOverride.LocalizationSource; text.text = instance.Localize(labelOverride.LocalizationSource); } else { text.text = labelOverride.OriginalText; } text.enableAutoSizing = labelOverride.OriginalEnableAutoSizing; text.textWrappingMode = labelOverride.OriginalWrappingMode; text.fontSizeMin = labelOverride.OriginalFontSizeMin; text.fontSizeMax = labelOverride.OriginalFontSizeMax; } } private static void ApplyLogo(FejdStartup startup) { if (_customMenuActive) { ReleaseCustomLogo(restoreVanilla: true); return; } GameObject mainMenu = startup.m_mainMenu; Transform val = ((mainMenu != null) ? mainMenu.transform.Find("Logo/LOGO") : null); Image val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<Image>()); if ((Object)(object)val2 == (Object)null) { WarnOnce(ref _lastLogoWarning, "missing-logo-image", "Client branding could not find the vanilla Logo/LOGO image; the vanilla logo was retained."); return; } string text = ServerManagerPlugin.BrandingLogoPath?.Value ?? string.Empty; if (_logoImage != val2 || !string.Equals(_logoSource, text, StringComparison.Ordinal)) { ReleaseCustomLogo(restoreVanilla: true); _logoImage = val2; _vanillaLogo = val2.sprite; _vanillaLogoPreserveAspect = val2.preserveAspect; _logoSource = text; } if (string.IsNullOrWhiteSpace(text)) { return; } string bepInExRootPath = Paths.BepInExRootPath; if (text.IndexOf("://", StringComparison.Ordinal) >= 0) { if (!TryParseLogoUrl(text, out Uri url, out string rejection)) { WarnOnce(ref _lastLogoWarning, "invalid-logo-url", rejection); } else { if (string.Equals(_remoteLogoAttemptedSource, text, StringComparison.Ordinal)) { return; } CancelRemoteLogo(); _remoteLogoAttemptedSource = text; string text2 = null; try { text2 = GetLogoCachePath(Path.Combine(ServerDataRoot.ResolveCurrentPath(), "cache"), url); if (File.Exists(text2)) { ApplyLogoBytes(val2, ReadLogoBytes(text2)); } } catch (Exception exception) when (!IntegrityCanonical.IsFatal(exception)) { WarnOnce(ref _lastLogoWarning, "logo-cache-read", "The cached menu logo was unavailable; trying HTTPS."); } _remoteLogoLoad = new RemoteLogoLoad(startup, val2, text, url, text2); } return; } if (!TryResolveLogoPath(bepInExRootPath, text, out string fullPath, out string rejection2)) { WarnOnce(ref _lastLogoWarning, text + "\n" + rejection2, "Client branding retained the vanilla logo: " + rejection2); return; } try { ApplyLogoBytes(val2, ReadLogoBytes(fullPath)); } catch (Exception ex) when (!IntegrityCanonical.IsFatal(ex)) { WarnOnce(ref _lastLogoWarning, fullPath + "\n" + ex.GetType().FullName + "\n" + ex.Message, "Client branding retained the vanilla logo: " + ex.Message); } } private static void TickRemoteLogo(FejdStartup startup) { RemoteLogoLoad remoteLogoLoad = _remoteLogoLoad; if (remoteLogoLoad == null) { return; } if (remoteLogoLoad.Startup != startup || _startup != startup || remoteLogoLoad.Image != _logoImage || (Object)(object)remoteLogoLoad.Image == (Object)null || !CanUseClientUi(startup) || !string.Equals(remoteLogoLoad.Source, ServerManagerPlugin.BrandingLogoPath?.Value, StringComparison.Ordinal)) { CancelRemoteLogo(); } else { if (!remoteLogoLoad.Download.IsCompleted) { return; } _remoteLogoLoad = null; remoteLogoLoad.Stop.Dispose(); byte[] result; try { result = remoteLogoLoad.Download.GetAwaiter().GetResult(); } catch (Exception exception) when (!IntegrityCanonical.IsFatal(exception)) { WarnOnce(ref _lastLogoWarning, "logo-download-failed", LogoDownloadFailureMessage(exception)); return; } try { ApplyLogoBytes(remoteLogoLoad.Image, result); } catch (Exception exception2) when (!IntegrityCanonical.IsFatal(exception2)) { WarnOnce(ref _lastLogoWarning, "logo-decode-failed", "The HTTPS menu logo failed during Unity PNG decode/apply; keeping the cached or vanilla logo."); return; } if (remoteLogoLoad.CachePath != null) { try { WriteLogoCache(remoteLogoLoad.CachePath, result); } catch (Exception exception3) when (!IntegrityCanonical.IsFatal(exception3)) { WarnOnce(ref _lastLogoWarning, "logo-cache-write", "The HTTPS menu logo was applied, but its cache could not be saved."); } } } } private static void CancelRemoteLogo() { RemoteLogoLoad load = _remoteLogoLoad; _remoteLogoLoad = null; if (load == null) { return; } load.Stop.Cancel(); load.Download.ContinueWith(delegate(Task<byte[]> completed) { if (completed.IsFaulted) { _ = completed.Exception; } load.Stop.Dispose(); }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } private static void ApplyLogoBytes(Image image, byte[] data) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_006e: 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) Texture2D val = null; Sprite val2 = null; try { if (!TryValidatePng(data, out int width, out int height, out string rejection)) { throw new InvalidDataException(rejection); } val = new Texture2D(2, 2, (TextureFormat)4, false) { name = "ServerManager.ClientMenuLogo" }; if (!TryLoadPng(val, data) || ((Texture)val).width != width || ((Texture)val).height != height) { throw new InvalidDataException("Unity could not decode the validated PNG dimensions."); } val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)val2).name = "ServerManager.ClientMenuLogo"; Sprite? customLogo = _customLogo; Texture2D customLogoTexture = _customLogoTexture; image.preserveAspect = true; image.sprite = val2; _customLogo = val2; _customLogoTexture = val; val2 = null; val = null; DestroyCustomLogo(customLogo, customLogoTexture); _lastLogoWarning = string.Empty; ServerManagerPlugin.Log.LogInfo((object)$"Applied client menu logo ({width}x{height})."); } finally { DestroyCustomLogo(val2, val); } } private static void ReleaseCustomLogo(bool restoreVanilla) { CancelRemoteLogo(); _remoteLogoAttemptedSource = null; _logoSource = null; if (restoreVanilla && (Object)(object)_logoImage != (Object)null && (Object)(object)_customLogo != (Object)null && _logoImage.sprite == _customLogo) { _logoImage.sprite = _vanillaLogo; _logoImage.preserveAspect = _vanillaLogoPreserveAspect; } DestroyCustomLogo(_customLogo, _customLogoTexture); _customLogo = null; _customLogoTexture = null; _logoImage = null; _vanillaLogo = null; _vanillaLogoPreserveAspect = false; } private static bool TryLoadPng(Texture2D texture, byte[] data) { MethodInfo methodInfo = AccessTools.Method(typeof(ImageConversion), "LoadImage", new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, (Type[])null); if (methodInfo == null) { return false; } object obj = methodInfo.Invoke(null, new object[3] { texture, data, true }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static void DestroyCustomLogo(Sprite? sprite, Texture2D? texture) { if ((Object)(object)sprite != (Object)null) { Object.Destroy((Object)(object)sprite); } if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } } private static void CancelFlow(bool clearConnectionPassword) { _armed = false; if (clearConnectionPassword) { ClearConnectionPasswordState(); } } private static void ClearConnectionPasswordState() { ClearOwnedPassword(); _pendingPassword = string.Empty; _passwordAwaitingHandshake = false; _brandedJoinDispatched = false; } private static void ClearOwnedPassword() { if (_passwordWasOverridden && TryGetServerPassword(out string password) && string.Equals(password, _ownedPassword, StringComparison.Ordinal)) { TrySetServerPassword(_previousPassword); } _ownedPassword = null; _previousPassword = null; _passwordWasOverridden = false; } private static void WarnOnce(ref string previousKey, string key, string message) { if (!string.Equals(previousKey, key, StringComparison.Ordinal)) { previousKey = key; ServerManagerPlugin.Log.LogWarning((object)message); } } } [HarmonyPatch(typeof(FejdStartup), "SetupGui")] internal static class ClientMenuBrandingSetupGuiPatch { [HarmonyPriority(0)] private static void Postfix(FejdStartup __instance) { ClientMenuBranding.OnSetupGui(__instance); } } [HarmonyPatch(typeof(FejdStartup), "Update")] internal static class ClientMenuBrandingUiUpdatePatch { [HarmonyPriority(800)] private static bool Prefix() { return ClientMenuBranding.BeforeUiUpdate(); } private static void Postfix(FejdStartup __instance) { ClientMenuBranding.OnUiUpdate(__instance); } } [HarmonyPatch(typeof(FejdStartup), "OnStartGame")] internal static class ClientMenuBrandingMainStartPatch { private static void Prefix(FejdStartup __instance) { ClientMenuBranding.BeforeMainStart(__instance); } private static void Postfix(FejdStartup __instance) { ClientMenuBranding.AfterMainStart(__instance); } } [HarmonyPatch(typeof(FejdStartup), "UpdateCharacterList")] internal static class ClientMenuBrandingCharacterListPatch { private static void Postfix(FejdStartup __instance) { ClientMenuBranding.AfterCharacterListUpdated(__instance); } } [HarmonyPatch(typeof(FejdStartup), "OnCharacterStart")] internal static class ClientMenuBrandingCharacterStartPatch { [HarmonyPriority(0)] private static void Prefix(FejdStartup __instance) { ClientMenuBranding.BeforeCharacterStart(__instance); } private static Exception? Finalizer(FejdStartup __instance, Exception? __exception) { ClientMenuBranding.AfterCharacterStart(__instance); return __exception; } } [HarmonyPatch(typeof(FejdStartup), "TransitionToMainScene")] internal static class ClientMenuBrandingTransitionPatch { private static void Prefix(FejdStartup __instance) { ClientMenuBranding.BeforeTransitionToMainScene(__instance); } } [HarmonyPatch(typeof(FejdStartup), "OnSelelectCharacterBack")] internal static class ClientMenuBrandingCharacterBackPatch { private static void Postfix(FejdStartup __instance) { ClientMenuBranding.AfterCharacterSelectionBack(__instance); } } [HarmonyPatch(typeof(FejdStartup), "OnLanguageChange")] internal static class ClientMenuBrandingLanguagePatch { private static void Postfix(FejdStartup __instance) { ClientMenuBranding.AfterLanguageChanged(__instance); } } [HarmonyPatch(typeof(ZNet), "RPC_ClientHandshake")] internal static class ClientMenuBrandingPasswordCleanupPatch { private static void Prefix(ZNet __instance) { ClientMenuBranding.BeforeClientHandshake(__instance); } private static Exception? Finalizer(ZNet __instance, Exception? __exception) { ClientMenuBranding.AfterClientHandshake(__instance); return __exception; } } [BepInPlugin("sighsorry.ServerManager", "ServerManager", "1.0.9")] [BepInIncompatibility("Azumatt.MaxPlayerCount")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class ServerManagerPlugin : BaseUnityPlugin { private sealed class ConfigurationManagerAttributes { public int? Order; } internal const string ModName = "ServerManager"; internal const string ModVersion = "1.0.9"; internal const string Author = "sighsorry"; internal const string ModGuid = "sighsorry.ServerManager"; internal const bool DefaultEnforceModPolicy = true; private readonly Harmony _harmony = new Harmony("sighsorry.ServerManager"); private bool _shuttingDown; private bool _quitHandlerRegistered; internal static ManualLogSource Log { get; private set; } = null; internal static string ConnectionError { get; set; } = string.Empty;