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 ValhallaMenuCompanion v1.9.0
BepInEx/plugins/ValhallaMenuCompanion.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using SeneaL.API; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("ValhallaMenuCompanion")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.9.0.0")] [assembly: AssemblyInformationalVersion("1.9.0")] [assembly: AssemblyProduct("ValhallaMenuCompanion")] [assembly: AssemblyTitle("ValhallaMenuCompanion")] [assembly: AssemblyVersion("1.9.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ValhallaMenuCompanion { [BepInPlugin("valhalla.menu.companion", "Valhalla Menu Companion", "1.9.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { private sealed class ButtonLabels { internal TMP_Text[] Tmp; internal Text[] Legacy; } private sealed class NativeCharacterRow { public Button Source; public RectTransform Rect; public TMP_Text Text; public object Entry; } private struct MenuEntry { public Button Source; public string Text; public string Tag; public Action Action; public bool Disabled; } [HarmonyPatch(typeof(ZNet), "RPC_ClientHandshake")] private static class PasswordPatch { private static void Prefix() { if (!PendingPasswordActive) { return; } try { MethodInfo methodInfo = AccessTools.PropertySetter(typeof(FejdStartup), "ServerPassword"); if (methodInfo != null) { methodInfo.Invoke(null, new object[1] { PendingPassword }); Plugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)"Quick Connect: password handed to Valheim's native handshake (value not logged)."); } return; } FieldInfo fieldInfo = AccessTools.Field(typeof(FejdStartup), "<ServerPassword>k__BackingField"); if (fieldInfo != null) { fieldInfo.SetValue(null, PendingPassword); Plugin instance2 = Instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogInfo((object)"Quick Connect: password handed to Valheim via backing-field fallback (value not logged)."); } } else { Plugin instance3 = Instance; if (instance3 != null) { ((BaseUnityPlugin)instance3).Logger.LogWarning((object)"Quick Connect: Valheim ServerPassword setter and backing field unavailable; manual entry may be required."); } } } catch (Exception ex) { Plugin instance4 = Instance; if (instance4 != null) { ((BaseUnityPlugin)instance4).Logger.LogWarning((object)("Automatic password entry failed: " + ex.Message)); } } finally { PendingPassword = null; PendingPasswordActive = false; } } } private sealed class QuerySnapshot { public readonly string State; public readonly int Players; public readonly int Capacity; public readonly bool HasPlayers; public QuerySnapshot(string state, int players = 0, int capacity = 0, bool hasPlayers = false) { State = state; Players = players; Capacity = capacity; HasPlayers = hasPlayers; } } private Texture2D logo; private Sprite logoSprite; private Image nativeLogoImage; private RawImage nativeLogoRaw; private Sprite savedTitleSprite; private Texture savedTitleTexture; private bool savedTitlePreserveAspect; private float nextLogoProbe; private bool missingTitleLogoLogged; private bool missingLogoFileLogged; private readonly Dictionary<Graphic, bool> suppressedLogoGraphics = new Dictionary<Graphic, bool>(); private Color savedTitleImageColor = Color.white; private Color savedTitleRawColor = Color.white; private bool logoHierarchyLogged; private Transform cachedTitleLogoRoot; private Transform cachedTitleMenu; private string loadedLogoPath; private DateTime loadedLogoUtc = DateTime.MinValue; private long loadedLogoLength = -1L; private EventInfo canvasRenderEvent; private Delegate canvasRenderHandler; private Button localButton; private readonly Dictionary<Button, ButtonLabels> buttonLabels = new Dictionary<Button, ButtonLabels>(); private Button characterPrimaryButton; private Button characterNewButton; private Button characterRemoveButton; private ButtonClickedEvent savedStartClick; private ButtonClickedEvent savedNewClick; private ButtonClickedEvent savedRemoveClick; private bool nativeSlotActionsMapped; private readonly Dictionary<Component, string> renderedSlotLabels = new Dictionary<Component, string>(); private float nextSlotLabelProbe; private int slotProbeCount; private readonly float[] stableCharacterCenters = new float[6]; private bool hasStableCharacterCenters; private bool characterRefreshPending; private int characterRefreshTries; private int stableScreenWidth; private int stableScreenHeight; private float nextLayoutDiagnostic; private bool nativeCharacterRowsMatched; private bool nativeCharacterRowsLogged; private bool nativeCharacterTickSeen; private float nextVisibleLabelProbe; private int visibleLabelProbeCount; private TMP_Text activeVisibleStart; private Text activeLegacyStart; private RectTransform nativeLastStartRoot; private RectTransform nativeLastLocalRoot; private readonly Dictionary<string, Vector2> nativeOriginalSlots = new Dictionary<string, Vector2>(); private float nextCharacterLookupLog; private readonly Dictionary<RectTransform, Vector2> characterOriginalPositions = new Dictionary<RectTransform, Vector2>(); private bool menuBound; private bool menuLookHideLogged; private bool supportOverflowLogged; private bool firstMenuModelInitialized; internal static string PendingPassword; internal static bool PendingPasswordActive; private ConfigEntry<float> rulesNativeDialogScale; private object resizedNativeDialog; private object rulesSizingDialog; private int rulesSizingPage = -1; private float rulesSizingOriginalWidth; private float rulesSizingOriginalHeight; private float rulesSizingAppliedHeight; private bool rulesSizingLogComplete; private bool nativeResizeMissingLogged; private string rulesText = "Welcome to Valhalla!"; private Dialog activeRulesDialog; private bool activeRulesDialogWasOpen; private bool rulesOpen; private bool pendingJoin; private readonly List<string> rulesPages = new List<string>(); private int rulesPageIndex; private bool rulesPageTransitioning; private string loadedRulesPath; private DateTime loadedRulesUtc = DateTime.MinValue; private long loadedRulesLength = -1L; private bool rulesAvailable; private bool missingRulesLogged; private bool joinQueuedAfterRules; private volatile QuerySnapshot serverQuerySnapshot = new QuerySnapshot("NOT CONFIGURED"); private QuerySnapshot cachedLabelSnapshot; private string cachedLabelTitle; private string cachedLabelText; private bool cachedLabelStatusEnabled; private bool cachedLabelShowPlayers; private bool cachedLabelBelowTitle; private volatile string lastQueryTarget = ""; private int queryRunning; private float nextQueryTime; private float nextStatusMaintenance; private bool startupIntroBlocked; private ConfigEntry<bool> pluginEnabled; private ConfigEntry<bool> logoEnabled; private ConfigEntry<bool> rulesEnabled; private ConfigEntry<bool> showRulesButton; private ConfigEntry<bool> skipStartupCinematic; private ConfigEntry<bool> hideMenuLook; private ConfigEntry<bool> supportEnabled; private ConfigEntry<bool> supportAskBeforeOpen; private ConfigEntry<bool> statusEnabled; private ConfigEntry<bool> statusShowPlayers; private ConfigEntry<bool> statusBelowTitle; private ConfigEntry<bool> rulesOptimizePageSpace; private ConfigEntry<string> host; private ConfigEntry<string> password; private ConfigEntry<string> buttonTitle; private ConfigEntry<string> discord; private ConfigEntry<string> logoFilename; private ConfigEntry<string> rulesFilename; private ConfigEntry<string> rulesVersion; private ConfigEntry<string> supportTitle; private ConfigEntry<string> supportUrl; private ConfigEntry<string> supportDescription; private ConfigEntry<int> port; private ConfigEntry<int> statusQueryPort; private ConfigEntry<int> statusPollSeconds; private ConfigEntry<int> statusTimeoutMs; private ConfigEntry<int> rulesLinesPerPage; private ConfigEntry<bool> verboseDiagnostics; private string dataFolder; private float nextReload; private Harmony harmony; private float uiNextSearch; internal static Plugin Instance; private volatile bool shuttingDown; private void ReloadAssets() { //IL_0440: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Expected O, but got Unknown try { string text = Path.Combine(dataFolder, Path.GetFileName(rulesFilename.Value ?? "rules.txt")); if (!File.Exists(text)) { rulesAvailable = false; if (!missingRulesLogged) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Rules file missing; quick-connect agreement will not be offered until rules are available: " + text)); missingRulesLogged = true; } } else { FileInfo fileInfo = new FileInfo(text); if (!rulesAvailable || loadedRulesPath != text || loadedRulesUtc != fileInfo.LastWriteTimeUtc || loadedRulesLength != fileInfo.Length) { string value = File.ReadAllText(text); if (string.IsNullOrWhiteSpace(value)) { rulesAvailable = false; if (!missingRulesLogged) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Rules file is empty; rules acceptance is disabled until valid rules are supplied."); missingRulesLogged = true; } } else { rulesText = value; loadedRulesPath = text; loadedRulesUtc = fileInfo.LastWriteTimeUtc; loadedRulesLength = fileInfo.Length; rulesAvailable = true; missingRulesLogged = false; } } } } catch (Exception ex) { rulesAvailable = false; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Rules file read failed: " + ex.Message)); } if (!logoEnabled.Value) { RestoreNativeTitleLogo(); return; } try { string text2 = Path.Combine(dataFolder, Path.GetFileName(logoFilename.Value ?? "logo.png")); if (!File.Exists(text2)) { if (!missingLogoFileLogged) { missingLogoFileLogged = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Branding: logo PNG not found at " + text2 + ". Confirm Branding.LogoFile and the active BepInEx profile.")); } if ((Object)(object)logo != (Object)null) { RestoreNativeTitleLogo(); if ((Object)(object)logoSprite != (Object)null) { Object.Destroy((Object)(object)logoSprite); } if ((Object)(object)logo != (Object)null) { Object.Destroy((Object)(object)logo); } logoSprite = null; logo = null; loadedLogoPath = null; } return; } missingLogoFileLogged = false; FileInfo fileInfo2 = new FileInfo(text2); if (loadedLogoPath == text2 && loadedLogoUtc == fileInfo2.LastWriteTimeUtc && loadedLogoLength == fileInfo2.Length) { return; } if (fileInfo2.Length < 8 || fileInfo2.Length > 16777216) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Logo PNG skipped: file must be between 8 bytes and 16 MiB."); loadedLogoPath = text2; loadedLogoUtc = fileInfo2.LastWriteTimeUtc; loadedLogoLength = fileInfo2.Length; return; } byte[] array = File.ReadAllBytes(text2); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); bool flag = false; try { Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule", throwOnError: false) ?? typeof(Texture2D).Assembly.GetType("UnityEngine.ImageConversion"); if (type != null) { MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "LoadImage")) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length >= 2 && parameters.Length <= 3 && parameters[0].ParameterType == typeof(Texture2D) && parameters[1].ParameterType == typeof(byte[]) && (parameters.Length == 2 || parameters[2].ParameterType == typeof(bool))) { object[] parameters2 = ((parameters.Length != 2) ? new object[3] { val, array, false } : new object[2] { val, array }); flag = (bool)methodInfo.Invoke(null, parameters2); break; } } } } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Branding: Unity ImageConversion module not found; logo PNG could not load."); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Logo decode failed: " + ex2.Message)); } if (flag) { Sprite val2 = null; try { val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); if ((Object)(object)val2 == (Object)null) { throw new InvalidOperationException("Sprite.Create returned null."); } ((Object)val2).name = "ValhallaCompanion_TitleLogo"; Sprite val3 = logoSprite; Texture2D val4 = logo; logo = val; logoSprite = val2; if ((Object)(object)nativeLogoImage != (Object)null) { nativeLogoImage.sprite = logoSprite; } if ((Object)(object)nativeLogoRaw != (Object)null) { nativeLogoRaw.texture = (Texture)(object)logo; } if ((Object)(object)val3 != (Object)null) { Object.Destroy((Object)(object)val3); } if ((Object)(object)val4 != (Object)null) { Object.Destroy((Object)(object)val4); } nextLogoProbe = 0f; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Branding: loaded title logo PNG (" + ((Texture)val).width + "x" + ((Texture)val).height + ").")); } catch (Exception ex3) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Branding: could not create the logo sprite: " + ex3.Message)); if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } Object.Destroy((Object)(object)val); } } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Branding: failed to decode logo PNG; keep a transparent RGBA PNG in the config folder."); Object.Destroy((Object)(object)val); } loadedLogoPath = text2; loadedLogoUtc = fileInfo2.LastWriteTimeUtc; loadedLogoLength = fileInfo2.Length; } catch (Exception ex4) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Logo file read failed: " + ex4.Message)); } } private static bool LooksLikeLogoGraphic(Graphic graphic) { if ((Object)(object)graphic == (Object)null) { return false; } string text = ((Object)graphic).name ?? ""; if (text.Equals("LOGO", StringComparison.OrdinalIgnoreCase) || text.Equals("AshlandsLogo", StringComparison.OrdinalIgnoreCase) || text.Equals("DeepNorthLogo", StringComparison.OrdinalIgnoreCase) || text.Equals("GameLogo", StringComparison.OrdinalIgnoreCase) || text.Equals("MainLogo", StringComparison.OrdinalIgnoreCase) || text.Equals("ValheimLogo", StringComparison.OrdinalIgnoreCase)) { return true; } Image val = (Image)(object)((graphic is Image) ? graphic : null); if (val != null && (Object)(object)val.sprite != (Object)null && (((Object)val.sprite).name ?? "").IndexOf("logo", StringComparison.OrdinalIgnoreCase) >= 0 && text.IndexOf("glow", StringComparison.OrdinalIgnoreCase) < 0) { return true; } return false; } private static Transform FindTitleLogoRoot(Transform menu) { if ((Object)(object)menu == (Object)null) { return null; } Transform[] componentsInChildren = ((Component)menu).GetComponentsInChildren<Transform>(true); Transform val = null; Transform[] array = componentsInChildren; foreach (Transform val2 in array) { if ((Object)(object)val2 == (Object)null || !string.Equals(((Object)val2).name, "Logo", StringComparison.OrdinalIgnoreCase)) { continue; } if ((Object)(object)val == (Object)null) { val = val2; } Image[] componentsInChildren2 = ((Component)val2).GetComponentsInChildren<Image>(true); foreach (Image val3 in componentsInChildren2) { if ((Object)(object)val3 != (Object)null && LooksLikeLogoGraphic((Graphic)(object)val3)) { return val2; } } } return val; } private void LogLogoCandidatesOnce(Transform root) { if (logoHierarchyLogged || !verboseDiagnostics.Value) { return; } logoHierarchyLogged = true; if ((Object)(object)root == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Branding: no Logo group found within FejdStartup.m_mainMenu; active title hierarchy differs from the expected prefab."); return; } int num = 0; Graphic[] componentsInChildren = ((Component)root).GetComponentsInChildren<Graphic>(true); foreach (Graphic val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && num++ < 24) { Image val2 = (Image)(object)((val is Image) ? val : null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Branding: candidate " + ((Object)val).name + " (" + ((object)val).GetType().Name + ", active=" + ((Component)val).gameObject.activeInHierarchy + ", enabled=" + ((Behaviour)val).enabled + ", sprite=" + (((Object)(object)val2 != (Object)null && (Object)(object)val2.sprite != (Object)null) ? ((Object)val2.sprite).name : "n/a") + ")")); continue; } break; } } private void SuppressOtherTitleLogoGraphics(Transform root, Graphic target) { if ((Object)(object)root == (Object)null || (Object)(object)target == (Object)null) { return; } Graphic[] componentsInChildren = ((Component)root).GetComponentsInChildren<Graphic>(true); foreach (Graphic val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)target) && LooksLikeLogoGraphic(val)) { if (!suppressedLogoGraphics.ContainsKey(val)) { suppressedLogoGraphics.Add(val, ((Behaviour)val).enabled); } if (((Behaviour)val).enabled) { ((Behaviour)val).enabled = false; } } } } private void TryApplyNativeTitleLogo() { //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) if (!pluginEnabled.Value || !logoEnabled.Value || (Object)(object)logo == (Object)null || !OnMenu()) { return; } FejdStartup instance = FejdStartup.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_mainMenu == (Object)null || !instance.m_mainMenu.activeInHierarchy || ((Object)(object)instance.m_characterSelectScreen != (Object)null && instance.m_characterSelectScreen.activeInHierarchy)) { return; } try { Transform transform = instance.m_mainMenu.transform; if ((Object)(object)cachedTitleMenu != (Object)null && (Object)(object)cachedTitleMenu != (Object)(object)transform) { RestoreNativeTitleLogo(); cachedTitleLogoRoot = null; logoHierarchyLogged = false; } if ((Object)(object)cachedTitleMenu != (Object)(object)transform || (Object)(object)cachedTitleLogoRoot == (Object)null || !((Component)cachedTitleLogoRoot).gameObject.activeInHierarchy) { Transform val = cachedTitleLogoRoot; Transform val2 = FindTitleLogoRoot(transform); if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)val2) { RestoreNativeTitleLogo(); logoHierarchyLogged = false; } cachedTitleMenu = transform; cachedTitleLogoRoot = val2; } Transform val3 = cachedTitleLogoRoot; LogLogoCandidatesOnce(val3); if ((Object)(object)val3 == (Object)null) { return; } if (((Object)(object)nativeLogoImage != (Object)null && !((Component)nativeLogoImage).transform.IsChildOf(val3)) || ((Object)(object)nativeLogoRaw != (Object)null && !((Component)nativeLogoRaw).transform.IsChildOf(val3))) { RestoreNativeTitleLogo(); } if ((Object)(object)nativeLogoImage != (Object)null && ((Component)nativeLogoImage).gameObject.activeInHierarchy) { if ((Object)(object)nativeLogoImage.sprite != (Object)(object)logoSprite) { nativeLogoImage.sprite = logoSprite; } ((Behaviour)nativeLogoImage).enabled = true; SuppressOtherTitleLogoGraphics(val3, (Graphic)(object)nativeLogoImage); return; } if ((Object)(object)nativeLogoRaw != (Object)null && ((Component)nativeLogoRaw).gameObject.activeInHierarchy) { if ((Object)(object)nativeLogoRaw.texture != (Object)(object)logo) { nativeLogoRaw.texture = (Texture)(object)logo; } ((Behaviour)nativeLogoRaw).enabled = true; SuppressOtherTitleLogoGraphics(val3, (Graphic)(object)nativeLogoRaw); return; } RestoreNativeTitleLogo(); Image val4 = null; RawImage val5 = null; int num = -1; Image[] componentsInChildren = ((Component)val3).GetComponentsInChildren<Image>(true); foreach (Image val6 in componentsInChildren) { if (!((Object)(object)val6 == (Object)null) && ((Component)val6).gameObject.activeInHierarchy && ((Behaviour)val6).enabled && !((Object)(object)val6.sprite == (Object)null) && LooksLikeLogoGraphic((Graphic)(object)val6) && !((Object)(object)((Component)val6).GetComponentInParent<Button>() != (Object)null)) { int num2 = 50; if (((Object)val6).name.Equals("LOGO", StringComparison.OrdinalIgnoreCase)) { num2 += 40; } if (((Object)val6).name.Equals("DeepNorthLogo", StringComparison.OrdinalIgnoreCase)) { num2 += 30; } if (((Object)val6).name.Equals("AshlandsLogo", StringComparison.OrdinalIgnoreCase)) { num2 += 20; } if (num2 > num) { num = num2; val4 = val6; val5 = null; } } } if ((Object)(object)val4 == (Object)null) { RawImage[] componentsInChildren2 = ((Component)val3).GetComponentsInChildren<RawImage>(true); foreach (RawImage val7 in componentsInChildren2) { if (!((Object)(object)val7 == (Object)null) && ((Component)val7).gameObject.activeInHierarchy && ((Behaviour)val7).enabled && !((Object)(object)val7.texture == (Object)null) && LooksLikeLogoGraphic((Graphic)(object)val7) && !((Object)(object)((Component)val7).GetComponentInParent<Button>() != (Object)null)) { val5 = val7; break; } } } if ((Object)(object)val4 != (Object)null) { nativeLogoImage = val4; savedTitleSprite = val4.sprite; savedTitlePreserveAspect = val4.preserveAspect; savedTitleImageColor = ((Graphic)val4).color; val4.sprite = logoSprite; val4.preserveAspect = true; ((Graphic)val4).color = Color.white; SuppressOtherTitleLogoGraphics(val3, (Graphic)(object)val4); missingTitleLogoLogged = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Branding: replaced Valheim title logo Image '" + ((Object)val4).name + "' and suppressed competing title-logo graphics.")); } else if ((Object)(object)val5 != (Object)null) { nativeLogoRaw = val5; savedTitleTexture = val5.texture; savedTitleRawColor = ((Graphic)val5).color; val5.texture = (Texture)(object)logo; ((Graphic)val5).color = Color.white; SuppressOtherTitleLogoGraphics(val3, (Graphic)(object)val5); missingTitleLogoLogged = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Branding: replaced Valheim title RawImage '" + ((Object)val5).name + "'.")); } else if (!missingTitleLogoLogged) { missingTitleLogoLogged = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Branding: Logo group exists but has no active logo Image/RawImage; its visible artwork may be drawn elsewhere. Please send Branding lines from the log."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Branding: title logo replacement failed: " + ex.Message)); } } private void RestoreNativeTitleLogo() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)nativeLogoImage != (Object)null) { nativeLogoImage.sprite = savedTitleSprite; nativeLogoImage.preserveAspect = savedTitlePreserveAspect; ((Graphic)nativeLogoImage).color = savedTitleImageColor; } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Branding: image restore skipped: " + ex.Message)); } try { if ((Object)(object)nativeLogoRaw != (Object)null) { nativeLogoRaw.texture = savedTitleTexture; ((Graphic)nativeLogoRaw).color = savedTitleRawColor; } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Branding: raw-image restore skipped: " + ex2.Message)); } foreach (KeyValuePair<Graphic, bool> suppressedLogoGraphic in suppressedLogoGraphics) { try { if ((Object)(object)suppressedLogoGraphic.Key != (Object)null) { ((Behaviour)suppressedLogoGraphic.Key).enabled = suppressedLogoGraphic.Value; } } catch (Exception ex3) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Branding: overlay restore skipped: " + ex3.Message)); } } suppressedLogoGraphics.Clear(); nativeLogoImage = null; nativeLogoRaw = null; savedTitleSprite = null; savedTitleTexture = null; } private void PatchVisibleCharacterSlots(bool forceRescan = false) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) ApplyMappedCharacterLabels(); if (stableScreenWidth != Screen.width || stableScreenHeight != Screen.height) { stableScreenWidth = Screen.width; stableScreenHeight = Screen.height; hasStableCharacterCenters = false; forceRescan = true; } if (!forceRescan && !characterRefreshPending && renderedSlotLabels.Count >= 6 && !(Time.unscaledTime >= nextSlotLabelProbe)) { return; } nextSlotLabelProbe = Time.unscaledTime + (characterRefreshPending ? 0.015f : 1f); List<Tuple<Component, float, string>> list = new List<Tuple<Component, float, string>>(); TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>(); foreach (TMP_Text val in array) { if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy && IsCharacterProbeText((val.text ?? "").Trim())) { list.Add(Tuple.Create<Component, float, string>((Component)(object)val, val.transform.position.y, (val.text ?? "").Trim())); } } Text[] array2 = Resources.FindObjectsOfTypeAll<Text>(); foreach (Text val2 in array2) { if ((Object)(object)val2 != (Object)null && ((Component)val2).gameObject.activeInHierarchy && IsCharacterProbeText((val2.text ?? "").Trim())) { list.Add(Tuple.Create<Component, float, string>((Component)(object)val2, ((Component)val2).transform.position.y, (val2.text ?? "").Trim())); } } list.Sort((Tuple<Component, float, string> a, Tuple<Component, float, string> b) => b.Item2.CompareTo(a.Item2)); List<List<Tuple<Component, float, string>>> list2 = new List<List<Tuple<Component, float, string>>>(); foreach (Tuple<Component, float, string> item2 in list) { if (list2.Count == 0 || Mathf.Abs(list2[list2.Count - 1][0].Item2 - item2.Item2) > 13f) { list2.Add(new List<Tuple<Component, float, string>>()); } list2[list2.Count - 1].Add(item2); } List<int> list3 = new List<int>(); if (hasStableCharacterCenters) { HashSet<int> hashSet = new HashSet<int>(); for (int num = 0; num < 6; num++) { int num2 = -1; float num3 = 24f; for (int num4 = 0; num4 < list2.Count; num4++) { if (!hashSet.Contains(num4)) { float num5 = Mathf.Abs(list2[num4][0].Item2 - stableCharacterCenters[num]); if (num5 < num3) { num2 = num4; num3 = num5; } } } if (num2 < 0) { list3.Clear(); break; } hashSet.Add(num2); list3.Add(num2); } } if (list3.Count != 6) { list3.Clear(); for (int num6 = 0; num6 <= list2.Count - 6; num6++) { bool flag = false; foreach (Tuple<Component, float, string> item3 in list2[num6]) { string text = item3.Item3; int num7 = text.IndexOf("<size=", StringComparison.OrdinalIgnoreCase); if (num7 >= 0) { text = text.Substring(0, num7).TrimEnd(Array.Empty<char>()); } if (text.Equals("START", StringComparison.OrdinalIgnoreCase) || text.Equals(buttonTitle.Value, StringComparison.OrdinalIgnoreCase)) { flag = true; break; } } if (!flag) { continue; } bool flag2 = true; for (int num8 = 1; num8 < 6; num8++) { float num9 = list2[num6 + num8 - 1][0].Item2 - list2[num6 + num8][0].Item2; if (num9 < 18f || num9 > 120f) { flag2 = false; break; } } if (flag2) { for (int num10 = 0; num10 < 6; num10++) { list3.Add(num6 + num10); } break; } } } if (list3.Count == 6) { string[] array3 = new string[6] { buttonTitle.Value, "PLAY LOCAL", "NEW", "REMOVE", "MANAGE SAVES", "BACK" }; Dictionary<Component, string> dictionary = new Dictionary<Component, string>(); for (int num11 = 0; num11 < 6; num11++) { float item = list2[list3[num11]][0].Item2; stableCharacterCenters[num11] = item; foreach (Tuple<Component, float, string> item4 in list2[list3[num11]]) { dictionary[item4.Item1] = array3[num11]; } } hasStableCharacterCenters = true; renderedSlotLabels.Clear(); foreach (KeyValuePair<Component, string> item5 in dictionary) { renderedSlotLabels[item5.Key] = item5.Value; } ApplyMappedCharacterLabels(); characterRefreshPending = false; characterRefreshTries = 0; } else if (characterRefreshPending && ++characterRefreshTries >= 20) { characterRefreshPending = false; ((BaseUnityPlugin)this).Logger.LogWarning((object)"CHAR refresh: couldn't confirm all six slots; last known labels retained."); } if (verboseDiagnostics.Value && slotProbeCount < 3) { slotProbeCount++; ((BaseUnityPlugin)this).Logger.LogInfo((object)("CHAR refresh #" + slotProbeCount + ": bands=" + list2.Count + ", slots=" + list3.Count + ", stable=" + hasStableCharacterCenters + ", map=" + renderedSlotLabels.Count)); } } private void ApplyMappedCharacterLabels() { string value = buttonTitle.Value; string text = FormatEnterLabel(); foreach (KeyValuePair<Component, string> renderedSlotLabel in renderedSlotLabels) { if ((Object)(object)renderedSlotLabel.Key == (Object)null || !renderedSlotLabel.Key.gameObject.activeInHierarchy) { continue; } Component key = renderedSlotLabel.Key; TMP_Text val = (TMP_Text)(object)((key is TMP_Text) ? key : null); if ((Object)(object)val != (Object)null) { string text2 = ((renderedSlotLabel.Value == value) ? text : renderedSlotLabel.Value); if (val.text != text2) { val.text = text2; } continue; } Component key2 = renderedSlotLabel.Key; Text val2 = (Text)(object)((key2 is Text) ? key2 : null); if ((Object)(object)val2 != (Object)null) { string text3 = ((renderedSlotLabel.Value == value) ? text : renderedSlotLabel.Value); if (val2.text != text3) { val2.text = text3; } } } } private void TrySubscribeBeforeCanvasRender() { try { Type type = Type.GetType("UnityEngine.Canvas, UnityEngine.UIModule", throwOnError: false); if (type == null) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { type = assemblies[i].GetType("UnityEngine.Canvas", throwOnError: false); if (type != null) { break; } } } if (type == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Canvas pre-render hook unavailable: UnityEngine.Canvas type not found. The normal character refresh remains available."); return; } EventInfo eventInfo = type.GetEvent("willRenderCanvases", BindingFlags.Static | BindingFlags.Public); MethodInfo method = ((object)this).GetType().GetMethod("BeforeCharacterCanvasRender", BindingFlags.Instance | BindingFlags.NonPublic); if (eventInfo == null || method == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Canvas pre-render hook unavailable: event or callback not found."); return; } Delegate obj = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, method, throwOnBindFailure: false); if ((object)obj == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Canvas pre-render hook unavailable: callback signature mismatch."); return; } eventInfo.AddEventHandler(null, obj); canvasRenderEvent = eventInfo; canvasRenderHandler = obj; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Canvas pre-render hook attached without an additional Unity DLL reference."); } catch (Exception ex) { canvasRenderEvent = null; canvasRenderHandler = null; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Canvas pre-render hook unavailable; fallback refresh remains active: " + ex.Message)); } } private void BeforeCharacterCanvasRender() { if (!shuttingDown && ((Behaviour)this).isActiveAndEnabled && pluginEnabled.Value && nativeSlotActionsMapped && OnMenu()) { FejdStartup instance = FejdStartup.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.m_characterSelectScreen == (Object)null) && instance.m_characterSelectScreen.activeInHierarchy) { PatchVisibleCharacterSlots(); } } } private void PatchVisibleCharacterStart() { if ((Object)(object)activeVisibleStart != (Object)null && ((Component)activeVisibleStart).gameObject.activeInHierarchy) { activeVisibleStart.text = FormatEnterLabel(); } if ((Object)(object)activeLegacyStart != (Object)null && ((Component)activeLegacyStart).gameObject.activeInHierarchy) { activeLegacyStart.text = FormatEnterLabel(); } if (Time.unscaledTime < nextVisibleLabelProbe) { return; } nextVisibleLabelProbe = Time.unscaledTime + 0.35f; bool flag = verboseDiagnostics.Value && visibleLabelProbeCount < 3; int num = 0; List<string> list = new List<string>(); TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>(); foreach (TMP_Text val in array) { if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { continue; } string text = (val.text ?? string.Empty).Trim(); if (text.Equals("START", StringComparison.OrdinalIgnoreCase)) { num++; if ((Object)(object)activeVisibleStart == (Object)null || !((Component)activeVisibleStart).gameObject.activeInHierarchy) { activeVisibleStart = val; } } if (flag && IsCharacterProbeText(text) && list.Count < 22) { list.Add(DescribeVisibleLabel(val.transform, text)); } } Text[] array2 = Resources.FindObjectsOfTypeAll<Text>(); foreach (Text val2 in array2) { if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy) { continue; } string text2 = (val2.text ?? string.Empty).Trim(); if (text2.Equals("START", StringComparison.OrdinalIgnoreCase)) { num++; if ((Object)(object)activeLegacyStart == (Object)null || !((Component)activeLegacyStart).gameObject.activeInHierarchy) { activeLegacyStart = val2; } } if (flag && IsCharacterProbeText(text2) && list.Count < 22) { list.Add("LEGACY " + DescribeVisibleLabel(((Component)val2).transform, text2)); } } if (flag) { visibleLabelProbeCount++; ((BaseUnityPlugin)this).Logger.LogInfo((object)("CHAR visible UI probe #" + visibleLabelProbeCount + " foundUnchangedStartLabels=" + num + "; primary=" + (((Object)(object)characterPrimaryButton == (Object)null) ? "none" : ((Object)characterPrimaryButton).name) + "; entries=[" + string.Join(" || ", list.ToArray()) + "]")); } if ((Object)(object)activeVisibleStart != (Object)null && ((Component)activeVisibleStart).gameObject.activeInHierarchy) { activeVisibleStart.text = FormatEnterLabel(); } if ((Object)(object)activeLegacyStart != (Object)null && ((Component)activeLegacyStart).gameObject.activeInHierarchy) { activeLegacyStart.text = FormatEnterLabel(); } } private static bool IsCharacterProbeText(string value) { int num = value.IndexOf("<size=", StringComparison.OrdinalIgnoreCase); if (num >= 0) { value = value.Substring(0, num).TrimEnd(Array.Empty<char>()); } if (!value.Equals("START", StringComparison.OrdinalIgnoreCase) && !value.Equals("ENTER VALHALLA", StringComparison.OrdinalIgnoreCase) && !value.Equals("PLAY LOCAL", StringComparison.OrdinalIgnoreCase) && !value.Equals("NEW", StringComparison.OrdinalIgnoreCase) && !value.Equals("REMOVE", StringComparison.OrdinalIgnoreCase) && !value.Equals("MANAGE SAVES", StringComparison.OrdinalIgnoreCase)) { return value.Equals("BACK", StringComparison.OrdinalIgnoreCase); } return true; } private static string DescribeVisibleLabel(Transform tf, string content) { //IL_006e: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)(object)((tf is RectTransform) ? tf : null); Button componentInParent = ((Component)tf).GetComponentInParent<Button>(); string text = ((Object)tf).name; Transform parent = tf.parent; int num = 0; while ((Object)(object)parent != (Object)null && num++ < 5) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } string text2 = (((Object)(object)val == (Object)null) ? ((object)tf.position/*cast due to .constrained prefix*/).ToString() : ((object)((Transform)val).position/*cast due to .constrained prefix*/).ToString()); return "'" + content + "' path=" + text + " owner=" + (((Object)(object)componentInParent == (Object)null) ? "none" : ((Object)componentInParent).name) + " pos=" + text2; } private void LogLayoutSnapshot() { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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) if ((Object)(object)localButton != (Object)null && ((Component)localButton).gameObject.activeInHierarchy) { Transform parent = ((Component)localButton).transform.parent; LayoutGroup val = (((Object)(object)parent != (Object)null) ? ((Component)parent).GetComponent<LayoutGroup>() : null); RectTransform val2 = (((Object)(object)characterPrimaryButton != (Object)null) ? ((Component)characterPrimaryButton).GetComponent<RectTransform>() : null); RectTransform component = ((Component)localButton).GetComponent<RectTransform>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("CHAR rendered: parent=" + (((Object)(object)parent == (Object)null) ? "null" : ((Object)parent).name) + " layout=" + (((Object)(object)val == (Object)null) ? "none" : ((object)val).GetType().Name) + " enter=" + (((Object)(object)val2 == (Object)null) ? "null" : ((object)((Transform)val2).position/*cast due to .constrained prefix*/).ToString()) + " play=" + (((Object)(object)component == (Object)null) ? "null" : ((object)((Transform)component).position/*cast due to .constrained prefix*/).ToString()) + " order=" + (((Object)(object)characterPrimaryButton == (Object)null) ? (-1) : ((Component)characterPrimaryButton).transform.GetSiblingIndex()) + "/" + ((Component)localButton).transform.GetSiblingIndex() + " SeneaLRows=" + nativeCharacterRowsMatched)); } } private static bool HasText(Button b, string expected) { if ((Object)(object)b == (Object)null || !((Component)b).gameObject.activeInHierarchy) { return false; } TMP_Text[] componentsInChildren = ((Component)b).GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val in componentsInChildren) { if (val.text != null && val.text.Trim().Equals(expected, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private void SetButtonLabel(Button b, string label) { if ((Object)(object)b == (Object)null) { return; } ButtonLabels value; bool flag = !buttonLabels.TryGetValue(b, out value); TMP_Text[] tmp; Text[] legacy; if (!flag) { tmp = value.Tmp; for (int i = 0; i < tmp.Length; i++) { if ((Object)(object)tmp[i] == (Object)null) { flag = true; break; } } if (!flag) { legacy = value.Legacy; for (int i = 0; i < legacy.Length; i++) { if ((Object)(object)legacy[i] == (Object)null) { flag = true; break; } } } } if (flag) { value = new ButtonLabels { Tmp = ((Component)b).GetComponentsInChildren<TMP_Text>(true), Legacy = ((Component)b).GetComponentsInChildren<Text>(true) }; buttonLabels[b] = value; } bool flag2 = true; tmp = value.Tmp; foreach (TMP_Text val in tmp) { if (!((Object)(object)val == (Object)null)) { string text = (flag2 ? label : string.Empty); flag2 = false; if (!string.Equals(val.text, text, StringComparison.Ordinal)) { val.text = text; } } } bool flag3 = true; legacy = value.Legacy; foreach (Text val2 in legacy) { if (!((Object)(object)val2 == (Object)null)) { string text2 = (flag3 ? label : string.Empty); flag3 = false; if (!string.Equals(val2.text, text2, StringComparison.Ordinal)) { val2.text = text2; } } } } private void PatchSeneaLCharacterMenu() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown MethodInfo methodInfo = SeneaLCompatibility.CharacterMenuTick(); MethodInfo methodInfo2 = AccessTools.Method(typeof(Plugin), "AfterSeneaLCharacterTick", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"SeneaL character: MenuView.Tick missing; post-render integration unavailable."); return; } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SeneaL character: patched MenuView.Tick POSTFIX to update the actual rendered rows."); MethodInfo methodInfo3 = AccessTools.Method(typeof(FejdStartup), "ShowCharacterSelection", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(typeof(Plugin), "AfterCharacterSelectionShown", (Type[])null, (Type[])null); if (methodInfo3 != null && methodInfo4 != null) { harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(methodInfo4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Character menu: patched ShowCharacterSelection for immediate Play Local binding."); } } private static void AfterCharacterSelectionShown() { Plugin instance = Instance; if ((Object)(object)instance == (Object)null || instance.shuttingDown || !instance.pluginEnabled.Value) { return; } instance.activeVisibleStart = null; instance.activeLegacyStart = null; instance.buttonLabels.Clear(); instance.characterRefreshPending = true; instance.characterRefreshTries = 0; instance.slotProbeCount = 0; instance.nextSlotLabelProbe = 0f; instance.ApplyMappedCharacterLabels(); instance.visibleLabelProbeCount = 0; instance.nextVisibleLabelProbe = 0f; try { instance.AttachToCharacterMenu(); if (instance.nativeSlotActionsMapped) { instance.PatchVisibleCharacterSlots(forceRescan: true); } } catch (Exception ex) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Character select immediate bind failed: " + ex.Message)); } } private static void AfterSeneaLCharacterTick(object __instance) { Plugin instance = Instance; if ((Object)(object)instance == (Object)null || instance.shuttingDown || !instance.pluginEnabled.Value || !instance.OnMenu() || instance.nativeSlotActionsMapped) { return; } try { instance.UpdateNativeCharacterRows(__instance); } catch (Exception ex) { if (Time.unscaledTime >= instance.nextCharacterLookupLog) { instance.nextCharacterLookupLog = Time.unscaledTime + 8f; ((BaseUnityPlugin)instance).Logger.LogWarning((object)("SeneaL character post-render update failed: " + ex)); } } } private void UpdateNativeCharacterRows(object menu) { //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_055f: Unknown result type (might be due to invalid IL or missing references) //IL_0502: Unknown result type (might be due to invalid IL or missing references) //IL_05d5: Unknown result type (might be due to invalid IL or missing references) //IL_05da: Unknown result type (might be due to invalid IL or missing references) //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_05f4: Unknown result type (might be due to invalid IL or missing references) //IL_05fb: Unknown result type (might be due to invalid IL or missing references) FejdStartup instance = FejdStartup.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_characterSelectScreen == (Object)null || !instance.m_characterSelectScreen.activeInHierarchy) { return; } if (!nativeCharacterTickSeen) { nativeCharacterTickSeen = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"SeneaL character: post-render MenuView.Tick is active during character selection."); } if ((Object)(object)characterPrimaryButton == (Object)null || (Object)(object)localButton == (Object)null) { return; } FieldInfo fieldInfo = AccessTools.Field(menu.GetType(), "_entries"); Array array = ((fieldInfo == null) ? null : (fieldInfo.GetValue(menu) as Array)); if (array == null || array.Length == 0) { return; } Type? elementType = array.GetType().GetElementType(); FieldInfo fieldInfo2 = AccessTools.Field(elementType, "Vanilla"); FieldInfo fieldInfo3 = AccessTools.Field(elementType, "Label"); FieldInfo fieldInfo4 = AccessTools.Field(elementType, "Root"); FieldInfo fieldInfo5 = AccessTools.Field(elementType, "Click"); if (fieldInfo2 == null || fieldInfo3 == null || fieldInfo4 == null || fieldInfo5 == null) { return; } Dictionary<string, NativeCharacterRow> dictionary = new Dictionary<string, NativeCharacterRow>(StringComparer.OrdinalIgnoreCase); List<string> list = new List<string>(); foreach (object item in array) { if (item == null) { continue; } object? value = fieldInfo2.GetValue(item); Button val = (Button)((value is Button) ? value : null); object? value2 = fieldInfo3.GetValue(item); TMP_Text val2 = (TMP_Text)((value2 is TMP_Text) ? value2 : null); object? value3 = fieldInfo4.GetValue(item); object? obj = ((value3 is Transform) ? value3 : null); RectTransform val3 = (RectTransform)((obj is RectTransform) ? obj : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null)) { string text = (val2.text ?? "").Trim(); string text2 = null; if ((Object)(object)val == (Object)(object)characterPrimaryButton) { text2 = "ENTER"; } else if ((Object)(object)val == (Object)(object)localButton || ((Object)(object)val != (Object)null && ((Object)val).name == "Valhalla_PlayLocalButton")) { text2 = "LOCAL"; } else if (text.Equals("NEW", StringComparison.OrdinalIgnoreCase)) { text2 = "NEW"; } else if (text.Equals("REMOVE", StringComparison.OrdinalIgnoreCase)) { text2 = "REMOVE"; } else if (text.Equals("MANAGE SAVES", StringComparison.OrdinalIgnoreCase)) { text2 = "MANAGE"; } else if (text.Equals("BACK", StringComparison.OrdinalIgnoreCase)) { text2 = "BACK"; } if (list.Count < 14) { list.Add(text + ":" + (((Object)(object)val == (Object)null) ? "no button" : ((Object)val).name) + "@" + ((object)val3.anchoredPosition/*cast due to .constrained prefix*/).ToString()); } if (text2 != null && !dictionary.ContainsKey(text2)) { dictionary[text2] = new NativeCharacterRow { Source = val, Rect = val3, Text = val2, Entry = item }; } } } if (!dictionary.ContainsKey("ENTER") || !dictionary.ContainsKey("LOCAL") || !dictionary.ContainsKey("NEW") || !dictionary.ContainsKey("REMOVE") || !dictionary.ContainsKey("MANAGE") || !dictionary.ContainsKey("BACK")) { if (Time.unscaledTime >= nextCharacterLookupLog) { nextCharacterLookupLog = Time.unscaledTime + 8f; ((BaseUnityPlugin)this).Logger.LogInfo((object)("SeneaL character: post-render rows unmatched; have=" + string.Join(",", new List<string>(dictionary.Keys).ToArray()) + "; observed=" + string.Join(" | ", list.ToArray()))); } return; } dictionary["ENTER"].Text.text = FormatEnterLabel(); dictionary["LOCAL"].Text.text = "PLAY LOCAL"; fieldInfo5.SetValue(dictionary["ENTER"].Entry, new Action(OnEnterValhalla)); fieldInfo5.SetValue(dictionary["LOCAL"].Entry, new Action(OpenLocalWorldSelection)); if ((Object)(object)nativeLastStartRoot != (Object)(object)dictionary["ENTER"].Rect || (Object)(object)nativeLastLocalRoot != (Object)(object)dictionary["LOCAL"].Rect || nativeOriginalSlots.Count != 6) { nativeLastStartRoot = dictionary["ENTER"].Rect; nativeLastLocalRoot = dictionary["LOCAL"].Rect; nativeOriginalSlots.Clear(); foreach (KeyValuePair<string, NativeCharacterRow> item2 in dictionary) { nativeOriginalSlots[item2.Key] = item2.Value.Rect.anchoredPosition; } nativeCharacterRowsLogged = false; } List<Vector2> list2 = new List<Vector2>(nativeOriginalSlots.Values); bool startAboveNew = nativeOriginalSlots["ENTER"].y >= nativeOriginalSlots["NEW"].y; list2.Sort((Vector2 a, Vector2 b) => (!startAboveNew) ? a.y.CompareTo(b.y) : b.y.CompareTo(a.y)); string[] array2 = new string[6] { "ENTER", "LOCAL", "NEW", "REMOVE", "MANAGE", "BACK" }; for (int num = 0; num < array2.Length; num++) { NativeCharacterRow nativeCharacterRow = dictionary[array2[num]]; Vector2 val4 = list2[num]; nativeCharacterRow.Rect.anchoredPosition = new Vector2(nativeCharacterRow.Rect.anchoredPosition.x, val4.y); } nativeCharacterRowsMatched = true; if (!nativeCharacterRowsLogged) { nativeCharacterRowsLogged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("SeneaL character: POST-RENDER native rows reordered ENTER > LOCAL > NEW > REMOVE > MANAGE > BACK. slots=" + string.Join(",", list2.ConvertAll((Vector2 p) => p.y.ToString("0.0")).ToArray()))); } } private void OpenLocalWorldSelection() { if (savedStartClick != null) { ((UnityEvent)savedStartClick).Invoke(); } } private void AttachToCharacterMenu() { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Expected O, but got Unknown //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Expected O, but got Unknown FejdStartup instance = FejdStartup.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_characterSelectScreen == (Object)null || !instance.m_characterSelectScreen.activeInHierarchy || ((Object)(object)characterPrimaryButton != (Object)null && ((Component)characterPrimaryButton).gameObject.activeInHierarchy && (Object)(object)localButton != (Object)null)) { return; } buttonLabels.Clear(); FieldInfo fieldInfo = AccessTools.Field(typeof(FejdStartup), "m_csStartButton"); Button val = (Button)((fieldInfo == null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { if (Time.unscaledTime > nextCharacterLookupLog) { nextCharacterLookupLog = Time.unscaledTime + 10f; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Character menu: FejdStartup.m_csStartButton not active; no buttons changed."); } return; } characterPrimaryButton = val; savedStartClick = val.onClick; RectTransform component = ((Component)val).GetComponent<RectTransform>(); if ((Object)(object)component == (Object)null) { return; } characterOriginalPositions.Clear(); characterOriginalPositions[component] = component.anchoredPosition; Transform parent = ((Component)val).transform.parent; Button[] componentsInChildren = ((Component)parent).GetComponentsInChildren<Button>(true); foreach (Button val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)(object)val) && !((Object)(object)((Component)val2).transform.parent != (Object)(object)parent)) { RectTransform component2 = ((Component)val2).GetComponent<RectTransform>(); if (!((Object)(object)component2 == (Object)null) && (HasText(val2, "NEW") || HasText(val2, "REMOVE") || HasText(val2, "MANAGE SAVES") || HasText(val2, "BACK"))) { characterOriginalPositions[component2] = component2.anchoredPosition; } } } object? obj = AccessTools.Field(typeof(FejdStartup), "m_csNewButton")?.GetValue(instance); Button val3 = (Button)((obj is Button) ? obj : null); object? obj2 = AccessTools.Field(typeof(FejdStartup), "m_csRemoveButton")?.GetValue(instance); Button val4 = (Button)((obj2 is Button) ? obj2 : null); if ((Object)(object)val3 == (Object)null || !((Component)val3).gameObject.activeInHierarchy || (Object)(object)val3 == (Object)(object)val) { componentsInChildren = ((Component)parent).GetComponentsInChildren<Button>(true); foreach (Button val5 in componentsInChildren) { if ((Object)(object)val5 != (Object)(object)val && ((Component)val5).gameObject.activeInHierarchy && HasText(val5, "NEW")) { val3 = val5; break; } } } if ((Object)(object)val4 == (Object)null || !((Component)val4).gameObject.activeInHierarchy || (Object)(object)val4 == (Object)(object)val) { componentsInChildren = ((Component)parent).GetComponentsInChildren<Button>(true); foreach (Button val6 in componentsInChildren) { if ((Object)(object)val6 != (Object)(object)val && ((Component)val6).gameObject.activeInHierarchy && HasText(val6, "REMOVE")) { val4 = val6; break; } } } localButton = Object.Instantiate<GameObject>(((Component)val).gameObject, parent).GetComponent<Button>(); ((Object)localButton).name = "Valhalla_ExtraCharacterSlot"; RemoveLocalization(localButton); ((Component)localButton).transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex() + 1); val.onClick = new ButtonClickedEvent(); ((UnityEvent)val.onClick).AddListener(new UnityAction(OnEnterValhalla)); SetButtonLabel(val, buttonTitle.Value); nativeSlotActionsMapped = (Object)(object)val3 != (Object)null && (Object)(object)val4 != (Object)null && (Object)(object)val3 != (Object)(object)val4; if (nativeSlotActionsMapped) { characterNewButton = val3; characterRemoveButton = val4; savedNewClick = val3.onClick; savedRemoveClick = val4.onClick; val3.onClick = savedStartClick; val4.onClick = savedNewClick; localButton.onClick = savedRemoveClick; RemoveLocalization(val3); RemoveLocalization(val4); SetButtonLabel(val3, "PLAY LOCAL"); SetButtonLabel(val4, "NEW"); SetButtonLabel(localButton, "REMOVE"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"CHAR slots: remapped Start->Enter; New->Play Local; Remove->New; Extra->Remove. Click handlers preserved."); } else { localButton.onClick = savedStartClick; SetButtonLabel(localButton, "PLAY LOCAL"); ((BaseUnityPlugin)this).Logger.LogWarning((object)"CHAR slots: vanilla New/Remove buttons not both found. Original v1.5 arrangement retained to protect their actions."); } nativeCharacterRowsMatched = false; nativeCharacterRowsLogged = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Character menu: bound exact m_csStartButton=" + ((Object)val).name + ", parent=" + ((Object)parent).name + ", cloned extra; actionsMapped=" + nativeSlotActionsMapped)); } private static void RemoveLocalization(Button button) { MonoBehaviour[] componentsInChildren = ((Component)button).GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren) { if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "Localize") { Object.Destroy((Object)(object)val); } } } private void PatchSeneaLMenu() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown MethodInfo methodInfo = SeneaLCompatibility.MainMenuScan(); MethodInfo methodInfo2 = AccessTools.Method(typeof(Plugin), "AfterSeneaLScan", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"SeneaL UI 1.2.8 MainMenuView.Scan unavailable; native menu integration disabled."); return; } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched SeneaL native MainMenuView.Scan for fixed Discord / Rules / Quit ordering."); } private static void AfterSeneaLScan(object __instance) { try { if ((Object)(object)Instance != (Object)null && !Instance.shuttingDown && Instance.pluginEnabled.Value) { Instance.RewriteSeneaLRows(__instance); } } catch (Exception ex) { Plugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)("Native menu rows could not be updated: " + ex.Message)); } } } private void RewriteSeneaLRows(object menu) { Type type = menu.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "_count"); FieldInfo fieldInfo2 = AccessTools.Field(type, "_cin"); FieldInfo fieldInfo3 = AccessTools.Field(type, "_src"); FieldInfo fieldInfo4 = AccessTools.Field(type, "_text"); FieldInfo fieldInfo5 = AccessTools.Field(type, "_tag"); FieldInfo fieldInfo6 = AccessTools.Field(type, "_act"); FieldInfo fieldInfo7 = AccessTools.Field(type, "_off"); MethodInfo methodInfo = AccessTools.Method(type, "Layout", (Type[])null, (Type[])null); if (fieldInfo == null || fieldInfo2 == null || fieldInfo3 == null || fieldInfo4 == null || fieldInfo5 == null || fieldInfo6 == null || fieldInfo7 == null || methodInfo == null || (bool)fieldInfo2.GetValue(menu)) { return; } Button[] array = (Button[])fieldInfo3.GetValue(menu); string[] array2 = (string[])fieldInfo4.GetValue(menu); string[] array3 = (string[])fieldInfo5.GetValue(menu); Action[] array4 = (Action[])fieldInfo6.GetValue(menu); bool[] array5 = (bool[])fieldInfo7.GetValue(menu); int num = Math.Min((int)fieldInfo.GetValue(menu), array2.Length); List<MenuEntry> list = new List<MenuEntry>(num); MenuEntry item = default(MenuEntry); bool flag = false; for (int i = 0; i < num; i++) { string text = (array2[i] ?? "").Trim(); if (hideMenuLook.Value && text.Equals("Menu Look", StringComparison.OrdinalIgnoreCase)) { if (!menuLookHideLogged) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"SeneaL main menu: Menu Look entry hidden by [MainMenu] HideMenuLook."); menuLookHideLogged = true; } } else if (text.Equals("Quit", StringComparison.OrdinalIgnoreCase) || text.Equals("Exit", StringComparison.OrdinalIgnoreCase) || ((Object)(object)array[i] != (Object)null && ((Object)array[i]).name.Equals("Exit", StringComparison.OrdinalIgnoreCase))) { item = new MenuEntry { Source = array[i], Text = array2[i], Tag = null, Action = array4[i], Disabled = array5[i] }; flag = true; } else if (!text.Equals("Discord", StringComparison.OrdinalIgnoreCase) && !text.Equals("Server Rules", StringComparison.OrdinalIgnoreCase) && !text.Equals(supportTitle.Value.Trim(), StringComparison.OrdinalIgnoreCase)) { list.Add(new MenuEntry { Source = array[i], Text = array2[i], Tag = array3[i], Action = array4[i], Disabled = array5[i] }); } } int num2 = 1 + (showRulesButton.Value ? 1 : 0) + (supportEnabled.Value ? 1 : 0); if (list.Count + (flag ? 1 : 0) + num2 > array2.Length) { if (!supportOverflowLogged) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"SeneaL main menu has no free row for the optional Support entry; leaving its existing menu unchanged."); supportOverflowLogged = true; } return; } list.Add(new MenuEntry { Text = "Discord", Action = OpenDiscord, Tag = null }); if (showRulesButton.Value) { list.Add(new MenuEntry { Text = "Server Rules", Tag = null, Action = ShowRulesForReading }); } if (supportEnabled.Value) { list.Add(new MenuEntry { Text = supportTitle.Value.Trim(), Tag = null, Action = ShowSupport }); } if (flag) { list.Add(item); } for (int j = 0; j < array2.Length; j++) { if (j < list.Count) { array[j] = list[j].Source; array2[j] = list[j].Text; array3[j] = list[j].Tag; array4[j] = list[j].Action; array5[j] = list[j].Disabled; } else { array[j] = null; array2[j] = null; array3[j] = null; array4[j] = null; array5[j] = false; } } fieldInfo.SetValue(menu, list.Count); methodInfo.Invoke(menu, null); firstMenuModelInitialized = true; if (!menuBound) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"SeneaL native main-menu rows include the optional Support entry; Quit remains last."); menuBound = true; } } private void ShowSupport() { if (!TrySupportUrl(out var url)) { ShowNativeNotice("SUPPORT VALHALLA", "The support link has not been configured yet."); return; } if (!supportAskBeforeOpen.Value) { Application.OpenURL(url.AbsoluteUri); return; } try { Dialogs.Confirm("SUPPORT VALHALLA", supportDescription.Value, (Action)delegate { Application.OpenURL(url.AbsoluteUri); }, (Action)null, "OPEN SUPPORT PAGE", "CLOSE"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Support dialog could not open: " + ex.Message)); } } private bool TrySupportUrl(out Uri url) { url = null; if (!ReleaseConfigValidation.TryGetHttpsUrl(supportUrl.Value ?? "", out var url2) || url2.AbsoluteUri.IndexOf("YOURPAGE", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } url = url2; return true; } private void OpenDiscord() { if (ReleaseConfigValidation.TryGetHttpsUrl(discord.Value, out var url) && url.AbsoluteUri.IndexOf("YOURINVITE", StringComparison.OrdinalIgnoreCase) < 0) { Application.OpenURL(url.AbsoluteUri); } else { ShowNativeNotice("DISCORD LINK UNAVAILABLE", "The Discord invite URL is not configured correctly. Please contact the administrator."); } } private void OnEnterValhalla() { if (shuttingDown || rulesOpen) { return; } if (rulesEnabled.Value && !rulesAvailable) { ReloadAssets(); if (!rulesAvailable) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Cannot present rules agreement: rules file is unavailable or empty."); ShowNativeNotice("SERVER RULES UNAVAILABLE", "The server rules are missing or unreadable. Please contact the administrator before joining."); return; } } if (rulesEnabled.Value && !Accepted()) { ShowRulesForAgreement(); } else { BeginJoin(); } } private void BeginJoin() { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) if (shuttingDown || !pluginEnabled.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Connect: companion disabled; join not attempted."); return; } if (!ReleaseConfigValidation.TryGetServerAddress(host.Value, out var _) || port.Value < 1 || port.Value > 65535) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Connect: set a valid ServerAddress and ServerPort first."); ShowNativeNotice("CONNECTION NOT STARTED", "The server address or port is not configured."); return; } try { FejdStartup instance = FejdStartup.instance; if ((Object)(object)instance == (Object)null) { throw new InvalidOperationException("FejdStartup instance is not available."); } if ((Object)(object)instance.m_characterSelectScreen == (Object)null || !instance.m_characterSelectScreen.activeInHierarchy) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Connect: character selection is no longer open; join cancelled."); return; } ServerJoinDataDedicated val = default(ServerJoinDataDedicated); ((ServerJoinDataDedicated)(ref val))..ctor(host.Value.Trim(), (ushort)port.Value); ServerJoinData val2 = default(ServerJoinData); ((ServerJoinData)(ref val2))..ctor(val); if (!((ServerJoinData)(ref val2)).IsValid) { ((BaseUnityPlugin)this).Logger.LogError((object)"Quick Connect: dedicated server join data is invalid."); ShowNativeNotice("CONNECTION NOT STARTED", "The configured server address is not valid."); return; } MethodInfo methodInfo = AccessTools.Method(typeof(FejdStartup), "ProceedJoinRequest", new Type[1] { typeof(ServerJoinData) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(FejdStartup), "OnCharacterStart", Type.EmptyTypes, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(FejdStartup), "m_queuedJoinServer"); if (methodInfo == null || methodInfo2 == null || fieldInfo == null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Quick Connect: missing native join members (proceed=" + (methodInfo != null) + ", characterStart=" + (methodInfo2 != null) + ", queuedServer=" + (fieldInfo != null) + ").")); ShowNativeNotice("CONNECTION NOT STARTED", "This Valheim version has an unsupported server join API. Please share the BepInEx log."); return; } PendingPassword = password.Value; PendingPasswordActive = !string.IsNullOrEmpty(PendingPassword); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Quick Connect: queueing server join; port=" + port.Value + ", configuredPassword=" + PendingPasswordActive + ". Password value is never logged.")); methodInfo.Invoke(instance, new object[1] { val2 }); if (!(fieldInfo.GetValue(instance) is ServerJoinData val3)) { throw new InvalidOperationException("Valheim did not return queued ServerJoinData."); } if (((ServerJoinData)(ref val3)).IsValid && val3.m_type == val2.m_type && ((ServerJoinData)(ref val3)).Dedicated.m_port == (ushort)port.Value) { ServerJoinDataDedicated dedicated = ((ServerJoinData)(ref val3)).Dedicated; if (string.Equals(((ServerJoinDataDedicated)(ref dedicated)).m_host, host.Value.Trim(), StringComparison.OrdinalIgnoreCase)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Connect: queued endpoint verified; invoking native OnCharacterStart for selected character."); methodInfo2.Invoke(instance, null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Connect: selected-character join started. Watch Valheim networking messages for connection result."); return; } } PendingPassword = null; PendingPasswordActive = false; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Connect: Valheim did not queue the configured endpoint; selected-character start was not invoked."); ShowNativeNotice("CONNECTION NOT STARTED", "Valheim did not accept the server join request. Please retry or use Join IP."); } catch (Exception ex) { PendingPassword = null; PendingPasswordActive = false; Exception obj = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex); ((BaseUnityPlugin)this).Logger.LogError((object)("Quick Connect: native join request failed: " + obj)); ShowNativeNotice("CONNECTION NOT STARTED", "Valheim could not start the server connection. Check BepInEx/LogOutput.log for details."); } } private static List<string> WrapAndPaginateRules(string text, int linesPerPage, int lineWidth, bool balancePages) { int num = Mathf.Clamp(lineWidth, 45, 128); List<string> list = new List<string>(); string[] array = (text ?? "").Replace("\r\n", "\n").Replace('\r', '\n').Split(new char[1] { '\n' }); for (int i = 0; i < array.Length; i++) { string text2 = array[i].TrimEnd(Array.Empty<char>()); if (string.IsNullOrWhiteSpace(text2)) { if (list.Count > 0 && list[list.Count - 1].Length != 0) { list.Add(""); } continue; } while (text2.Length > num) { int num2 = text2.LastIndexOf(' ', num); if (num2 < num / 2) { num2 = num; } list.Add(text2.Substring(0, num2).TrimEnd(Array.Empty<char>())); text2 = text2.Substring(num2).TrimStart(Array.Empty<char>()); } if (text2.Length > 0) { list.Add(text2); } } while (list.Count > 0 && list[list.Count - 1].Length == 0) { list.RemoveAt(list.Count - 1); } List<string> list2 = new List<string>(); int num3 = Math.Max(6, Math.Min(36, linesPerPage)); if (!balancePages) { for (int j = 0; j < list.Count; j += num3) { int count = Math.Min(num3, list.Count - j); List<string> range = list.GetRange(j, count); while (range.Count > 0 && range[range.Count - 1].Length == 0) { range.RemoveAt(range.Count - 1); } if (range.Count > 0) { list2.Add(string.Join("\n", range.ToArray())); } } return list2; } int num4 = Math.Max(1, (list.Count + num3 - 1) / num3); int k = 0; for (int l = 0; l < num4; l++) { if (k >= list.Count) { break; } for (; k < list.Count && list[k].Length == 0; k++) { } if (k >= list.Count) { break; } int num5 = list.Count - k; int num6 = num4 - l; int num7 = Math.Min(num3, (num5 + num6 - 1) / num6); if (num6 > 1) { int num8 = num7; int num9 = int.MaxValue; int num10 = Math.Max(1, num7 - 4); int num11 = Math.Min(num3, num7 + 4); for (int m = num10; m <= num11 && k + m < list.Count; m++) { if (num5 - m <= (num6 - 1) * num3 && num5 - m >= num6 - 1 && (list[k + m - 1].Length == 0 || list[k + m].Length == 0)) { int num12 = Math.Abs(m - num7); if (num12 < num9) { num8 = m; num9 = num12; } } } num7 = num8; } List<string> range2 = list.GetRange(k, num7); while (range2.Count > 0 && range2[range2.Count - 1].Length == 0) { range2.RemoveAt(range2.Count - 1); } if (range2.Count > 0) { list2.Add(string.Join("\n", range2.ToArray())); } k += num7; } if (k < list.Count) { int num13; for (; k < list.Count; k += num13) { for (; k < list.Count && list[k].Length == 0; k++) { } if (k >= list.Count) { break; } num13 = Math.Min(num3, list.Count - k); List<string> range3 = list.GetRange(k, num13); while (range3.Count > 0 && range3[range3.Count - 1].Length == 0) { range3.RemoveAt(range3.Count - 1); } if (range3.Count > 0) { list2.Add(string.Join("\n", range3.ToArray())); } } } return list2; } private bool TryResizeCurrentNativeRulesDialog(Dialog expectedDialog, int expectedPage, bool remeasure = false) { //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: 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) //IL_024f: 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_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_0606: Unknown result type (might be due to invalid IL or missing references) //IL_060b: Unknown result type (might be due to invalid IL or missing references) //IL_06dd: Unknown result type (might be due to invalid IL or missing references) //IL_06e2: Unknown result type (might be due to invalid IL or missing references) //IL_07e1: Unknown result type (might be due to invalid IL or missing references) //IL_07e6: Unknown result type (might be due to invalid IL or missing references) if (!rulesOpen || rulesPageTransitioning || shuttingDown || expectedDialog == null || activeRulesDialog != expectedDialog || expectedPage != rulesPageIndex || !expectedDialog.IsOpen) { return false; } try { Type type = SeneaLCompatibility.NativeDialogType(); if (type == null) { return false; } PropertyInfo property = type.GetProperty("Top", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field = type.GetField("_w", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field2 = type.GetField("_h", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field3 = type.GetField("Root", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method = type.GetMethod("SetSize", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(float), typeof(float) }, null); if (property == null || field == null || field2 == null || field3 == null || method == null) { return false; } object value = property.GetValue(null, null); if (value == null) { return false; } if (resizedNativeDialog == value) { return true; } object? value2 = field3.GetValue(value); RectTransform val = (RectTransform)((value2 is RectTransform) ? value2 : null); if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { return false; } if (rulesSizingDialog != value || rulesSizingPage != expectedPage) { rulesSizingDialog = value; rulesSizingPage = expectedPage; rulesSizingOriginalWidth = Convert.ToSingle(field.GetValue(value)); rulesSizingOriginalHeight = Convert.ToSingle(field2.GetValue(value)); rulesSizingAppliedHeight = 0f; rulesSizingLogComplete = false; } float num = rulesSizingOriginalWidth; float num2 = rulesSizingOriginalHeight; if (num <= 1f || num2 <= 1f) { return false; } float num3 = Mathf.Clamp(rulesNativeDialogScale.Value, 1f, 2f); if (num3 <= 1.001f) { resizedNativeDialog = value; return true; } float num4 = Screen.width; float num5 = Screen.height; Transform parent = ((Transform)val).parent; int num6 = 0; Rect rect; while ((Object)(object)parent != (Object)null && num6 < 8) { RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val2 != (Object)null) { rect = val2.rect; if (((Rect)(ref rect)).width >= num) { rect = val2.rect; if (((Rect)(ref rect)).height >= num2) { rect = val2.rect; num4 = ((Rect)(ref rect)).width; rect = val2.rect; num5 = ((Rect)(ref rect)).height; break; } } } num6++; parent = parent.parent; } float num7 = Mathf.Max(num, Mathf.Min(num * num3, num4 * 0.92f)); float num8 = Mathf.Max(num2, Mathf.Min(num2 * num3, num5 * 0.86f)); float num9 = ((!remeasure || rulesSizingAppliedHeight <= 0f) ? num8 : rulesSizingAppliedHeight); method.Invoke(value, new object[2] { num7, num9 }); rulesSizingAppliedHeight = num9; if (!TryExpandNativeRulesBody(val, rulesPages[expectedPage], out var textRect, out var preferredBodyHeight) || (Object)(object)textRect == (Object)null || preferredBodyHeight <= 1f) { return false; } rect = textRect.rect; if (((Rect)(ref rect)).height < preferredBodyHeight + 4f) { if (num9 < num8 - 1f) { rulesSizingAppliedHeight = num8; method.Invoke(value, new object[2] { num7, num8 }); TryExpandNativeRulesBody(val, rulesPages[expectedPage], out var _, out var _); } ManualLogSource logger = ((BaseUnityPlugin)this).Logger; string[] obj = new string[6] { "Rules visual-fit text-area safety fallback on page ", (expectedPage + 1).ToString(), ": rect=", null, null, null }; rect = textRect.rect; obj[3] = ((Rect)(ref rect)).height.ToString("0"); obj[4] = ", required="; obj[5] = preferredBodyHeight.ToString("0"); logger.LogWarning((object)string.Concat(obj)); resizedNativeDialog = value; return true; } if (!TryFindRulesActionTop(val, out var topWorld)) { return false; } Vector3[] array = (Vector3[])(object)new Vector3[4]; textRect.GetWorldCorners(array); float num10 = Mathf.Max(0.0001f, Mathf.Abs(((Transform)textRect).lossyScale.y)); float num11 = Mathf.Max(0.0001f, Mathf.Abs(((Transform)val).lossyScale.y)); float num12 = (array[1].y - preferredBodyHeight * num10 - topWorld) / num11; if (float.IsNaN(num12) || float.IsInfinity(num12) || Mathf.Abs(num12) > num8 * 3f) { return false; } float num13 = Mathf.Min(num8, Mathf.Max(245f, Mathf.Max(num2 * 0.38f, preferredBodyHeight + 130f))); float num14 = Mathf.Clamp(num9 - (num12 - 34f), num13, num8); bool flag = Mathf.Abs(num14 - num9) < 2f; bool flag2 = Mathf.Abs(num12 - 34f) <= 12f; if (flag2 || flag) { resizedNativeDialog = value; if (!rulesSizingLogComplete) { rulesSizingLogComplete = true; ManualLogSource logger2 = ((BaseUnityPlugin)this).Logger; string[] obj2 = new string[18] { "Rules visual-fit page ", (expectedPage + 1).ToString(), ": measured gap=", num12.ToString("0"), ", target=", 34f.ToString("0"), ", content=", preferredBodyHeight.ToString("0"), ", frame request=", num9.ToString("0"), ", actual frame=", null, null, null, null, null, null, null }; rect = val.rect; obj2[11] = ((Rect)(ref rect)).height.ToString("0"); obj2[12] = ", original="; obj2[13] = num2.ToString("0"); obj2[14] = ", max="; obj2[15] = num8.ToString("0"); obj2[16] = ", limited="; obj2[17] = (!flag2).ToString(); logger2.LogInfo((object)string.Concat(obj2)); } return true; } method.Invoke(value, new object[2] { num7, num14 }); rulesSizingAppliedHeight = num14; if (TryExpandNativeRulesBody(val, rulesPages[expectedPage], out var textRect3, out var preferredBodyHeight3) && !((Object)(object)textRect3 == (Object)null) && !(preferredBodyHeight3 <= 1f)) { rect = textRect3.rect; if (!(((Rect)(ref rect)).height < preferredBodyHeight3 + 4f)) { ManualLogSource logger3 = ((BaseUnityPlugin)this).Logger; string[] obj3 = new string[10] { "Rules visual-fit page ", (expectedPage + 1).ToString(), " pass: gap=", num12.ToString("0"), ", request=", num9.ToString("0"), "->", num14.ToString("0"), ", actual frame=", null }; rect = val.rect; obj3[9] = ((Rect)(ref rect)).height.ToString("0"); logger3.LogInfo((object)string.Concat(obj3)); return false; } } method.Invoke(value, new object[2] { num7, num8 }); rulesSizingAppliedHeight = num8; TryExpandNativeRulesBody(val, rulesPages[expectedPage], out var _, out var _); ((BaseUnityPlugin)this).Logger.LogWarning((object)("Rules visual-fit shrink rejected: insufficient text area, page " + (expectedPage + 1))); resizedNativeDialog = value; return true; } catch (Exception ex) { if (!nativeResizeMissingLogged) { nativeResizeMissingLogged = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Rules native layout unavailable; leaving SeneaL window unchanged: " + ((ex.InnerException != null) ? ex.InnerException.Message : ex.Message))); } return false; } } private bool TryExpandNativeRulesBody(RectTransform dialogRoot, string expectedBody, out RectTransform textRect, out float preferredBodyHeight) { //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) textRect = null; preferredBodyHeight = 0f; if ((Object)(object)dialogRoot == (Object)null || string.IsNullOrEmpty(expectedBody)) { return false; } string text = expectedBody.TrimStart(Array.Empty<char>()); if (text.Length > 35) { text = text.Substring(0, 35); } if (text.Length < 5) { return false; } TMP_Text val = null; Text val2 = null; TMP_Text[] componentsInChildren = ((Component)dialogRoot).GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val3 in componentsInChildren) { if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.rectTransform == (Object)null) && (val3.text ?? "").IndexOf(text, StringComparison.Ordinal) >= 0) { val = val3; textRect = val3.rectTransform; break; } } if ((Object)(object)textRect == (Object)null) { Text[] componentsInChildren2 = ((Component)dialogRoot).GetComponentsInChildren<Text>(true); foreach (Text val4 in componentsInChildren2) { if (!((Object)(object)val4 == (Object)null) && (val4.text ?? "").IndexOf(text, StringComparison.Ordinal) >= 0) { val2 = val4; textRect = ((Graphic)val4).rectTransform; break; } } } if ((Object)(object)textRect == (Object)null) { return false; } Vector3[] array = (Vector3[])(object)new Vector3[4]; Vector3[] array2 = (Vector3[])(object)new Vector3[4]; dialogRoot.GetWorldCorners(array); textRect.GetWorldCorners(array2); Transform parent = ((Transform)textRect).parent; if ((Object)(object)parent == (Object)null) { return false; } float num = Mathf.Max(0.0001f, Mathf.Abs(parent.lossyScale.x)); float num2 = Mathf.Max(0.0001f, Mathf.Abs(parent.lossyScale.y)); float num3 = Mathf.Abs(array[2].x - array[0].x); float num4 = Mathf.Abs(array[2].y - array[0].y); float num5 = array[2].x - num3 * 0.045f; float topWorld; float num6 = (TryFindRulesActionTop(dialogRoot, out topWorld) ? (topWorld + num4 * 0.025f) : (array[0].y + num4 * 0.13f)); float num7 = (num5 - array2[0].x) / num; float num8 = (array2[1].y - num6) / num2; Rect rect = textRect.rect; float width = ((Rect)(ref rect)).width; rect = textRect.rect; float height = ((Rect)(ref rect)).height; if (num7 < 1f || num8 < 1f) { return false; } ContentSizeFitter component = ((Component)textRect).GetComponent<ContentSizeFitter>(); if ((Object)(object)component != (Object)null) { component.horizontalFit = (FitMode)0; component.verticalFit = (FitMode)0; } textRect.SetSizeWithCurrentAnchors((Axis)0, num7); textRect.SetSizeWithCurrentAnchors((Axis)1, num8); Vector3[] array3 = (Vector3[])(object)new Vector3[4]; textRect.GetWorldCorners(array3); RectTransform obj = textRect; ((Transform)obj).position = ((Transform)obj).position + (array2[1] - array3[1]); if ((Object)(object)val != (Object)null) { val.ForceMeshUpdate(false, false); TMP_Text obj2 = val; rect = textRect.rect; Vector2 preferredValues = obj2.GetPreferredValues(expectedBody, Mathf.Max(1f, ((Rect)(ref rect)).width), float.PositiveInfinity); if (preferredValues.y > 0f && !float.IsInfinity(preferredValues.y) && !float.IsNaN(preferredValues.y)) { preferredBodyHeight = preferredValues.y; } } else if ((Object)(object)val2 != (Object)null) { ((Graphic)val2).SetAllDirty(); } ManualLogSource logger = ((BaseUnityPlugin)this).Logger; string[] obj3 = new string[9] { "Rules native SeneaL message resized: ", width.ToString("0"), "x", height.ToString("0"), " -> ", null, null, null, null }; rect = textRect.rect; obj3[5] = ((Rect)(ref rect)).width.ToString("0"); obj3[6] = "x"; rect = textRect.rect; obj3[7] = ((Rect)(ref rect)).height.ToString("0"); obj3[8] = "; genuine provider text component."; logger.LogInfo((object)string.Concat(obj3)); return true; } private static bool TryFindRulesActionTop(RectTransform root, out float topWorld) { topWorld = float.NegativeInfinity; if ((Object)(object)root == (Object)null) { return false; } TMP_Text[] componentsInChildren = ((Component)root).GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && IsNativeRulesActionLabel(val.text)) { Vector3[] array = (Vector3[])(object)new Vector3[4]; val.rectTransform.GetWorldCorners(array); topWorld = Mathf.Max(topWorld, array[1].y); } } if (float.IsNegativeInfinity(topWorld)) { Text[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Text>(true); foreach (Text val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null) && IsNativeRulesActionLabel(val2.text)) { Vector3[] array2 = (Vector3[])(object)new Vector3[4]; ((Graphic)val2).rectTransform.GetWorldCorners(array2); topWorld = Mathf.Max(topWorld, array2[1].y); } } } return !float.IsNegativeInfinity(topWorld); } private static bool IsNativeRulesActionLabel(string label) { if (string.IsNullOrEmpty(label)) { return false; } string a = label.Trim(); if (!string.Equals(a, "NEXT PAGE", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "BACK", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "DECLINE", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "AGREE & JOIN", StringComparison.OrdinalIgnoreCase)) { return string.Equals(a, "CLOSE", StringComparison.OrdinalIgnoreCase); } return true; } private IEnumerator ResizeRulesDialogNextFrame(Dialog expectedDialog, int page) { for (int pass = 0; pass < 8; pass++) { yield return null; if (shuttingDown || !rulesOpen || rulesPageTransitioning || expectedDialog == null || activeRulesDialog != expectedDialog || page != rulesPageIndex || !expectedDialog.IsOpen || TryResizeCurrentNativeRulesDialog(expectedDialog, page, remeasure: true)) { yield break; } } ((BaseUnityPlugin)this).Logger.LogWarning((object)("Rules visual-fit did not converge within eight layout frames, page " + (page + 1) + ". Please provide BepInEx/LogOutput.log for diagnosis.")); } private void BeginRulesViewer(bool forAgreement) { if (shuttingDown || rulesOpen) { return; } if (!Dialogs.HasProvider) { ((BaseUnityPlugin)this).Logger.LogError((object)"Server Rules: native SeneaL dialog provider unavailable; rules window and join cancelled."); return; } ReloadAssets(); if (!rulesAvailable) { ShowNativeNotice("SERVER RULES", "The server rules file is missing or empty. Please contact the server administrator."); return; } float num = Mathf.Clamp(rulesNativeDialogScale.Value, 1f, 2f); int lineWidth = Mathf.Clamp(Mathf.RoundToInt(52f * num), 52, 112); int num2 = Mathf.Clamp(rulesLinesPerPage.Value, 6, 16); int linesPerPage = (rulesOptimizePageSpace.Value ? Mathf.Clamp(Mathf.RoundToInt((float)num2 * (1f + 2.2f * (num - 1f))), 6, 36) : Mathf.Clamp(Mathf.RoundToInt((float)num2 * num), 6, 24)); rulesPages.Clear(); rulesPages.AddRange(WrapAndPaginateRules(rulesText, linesPerPage, lineWidth, rulesOptimizePageSpace.Value)); if (rulesPages.Count < 1 || rulesPages.Count > 128) { rulesPages.Clear(); ShowNativeNotice("SERVER RULES", "The rules file cannot be displayed safely. Please contact an administrator."); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Rules pagination produced an invalid page count. Connection not attempted."); return; } rulesOpen = true; pendingJoin = forAgreement; rulesPageIndex = 0; rulesPageTransitioning = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Opening SeneaL rules " + (forAgreement ? "agreement" : "viewer") + "; pages=" + rulesPages.Count + "; max wrapped lines/page=" + linesPerPage + "; balanced=" + rulesOptimizePageSpace.Value + "; native provider=" + Dialogs.HasProvider)); OpenRulesPage(); } private void ShowRulesForReading() { BeginRulesViewer(forAgreement: false); } private void ShowNativeNotice(string title, string message) { try { Dialogs.Message(title, message, (Action)null, "CLOSE"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("SeneaL notice dialog unavailable: " + ex)); } } private void OpenRulesPage() { if (shuttingDown || !rulesOpen || rulesPageIndex < 0 || rulesPageIndex >= rulesPages.Count) { return; } try { activeRulesDialogWasOpen = false; bool flag = rulesPageIndex == 0; bool flag2 = rulesPageIndex == rulesPages.Count - 1; string text = "SERVER RULES (" + (rulesPageIndex + 1) + "/" + rulesPages.Count + ")"; string text2 = rulesPages[rulesPageIndex]; if (rulesPages.Count == 1) { activeRulesDialog = (Dialog)(pendingJoin ? ((object)Dialogs.Confirm(text, text2, (Action)OnRulesAccepted, (Action)OnRulesDialogClosed, "AGREE & JOIN", "DECLINE")) : ((object)Dialogs.Message(text, text2, (Action)OnRulesDialogClosed, "CLOSE"))); } else if (flag2) { activeRulesDialog = (Dialog)(object)(pendingJoin ? Dialogs.Confirm(text, text2, (Action)OnRulesAccepted, (Action)PreviousRulesPage, "AGREE & JOIN", "BACK") : Dialogs.Confirm(text, text2, (Action)OnRulesDialogClosed, (Action)PreviousRulesPage, "CLOSE", "BACK")); } else if (flag) { activeRulesDialog = (Dialog)(object)Dialogs.Confirm(text, text2, (Action)NextRulesPage, (Action)OnRulesDialogClosed, "NEXT PAGE", pendingJoin ? "DECLINE" : "CLOSE"); } else { activeRulesDialog = (Dialog)(object)Dialogs.Confirm(text, text2, (Action)NextRulesPage, (Action)PreviousRulesPage, "NEXT PAGE", "BACK"); } if (activeRulesDialog == null) { throw new InvalidOperationException("SeneaL API did not create a rules dialog."); } TryResizeCurrentNativeRulesDialog(activeRulesDialog, rulesPageIndex); ((MonoBehaviour)this).StartCoroutine(ResizeRulesDialogNextFrame(activeRulesDialog, rulesPageIndex)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("SeneaL rules page " + (rulesPageIndex + 1) + "/" + rulesPages.Count + " opened.")); } catch (Exception ex) { OnRulesDialogClosed(); ((BaseUnityPlugin)this).Logger.LogError((object)("Could not open SeneaL rules page; connection cancelled: " + ex)); } } private void NextRulesPage() { NavigateRulesPage(1); } private void PreviousRulesPage() { NavigateRulesPage(-1); } private void NavigateRulesPage(int direction) { if (!shuttingDown && rulesOpen && !rulesPageTransitioning) { int num = rulesPageIndex + direction; if (num >= 0 && num < rulesPages.Count) { rulesPageTransitioning = true; activeRulesDialog = null; resizedNativeDialog = null; rulesSizingDialog = null; rulesSizingPage = -1; rulesSizingAppliedHeight = 0f; activeRulesDialogWasOpen = false; ((MonoBehaviour)this).StartCoroutine(OpenRulesPageAfterClose(num)); } } } private IEnumerator OpenRulesPageAfterClose(int page) { yield return null; if (!shuttingDown && rulesOpen && !((Object)(object)this == (Object)null) && ((Behaviour)this).isActiveAndEnabled) { rulesPageIndex = page; rulesPageTransitioning = false; OpenRulesPage(); } } private void OnRulesDialogClosed() { rulesOpen = false; pendingJoin = false; activeRulesDialog = null; resizedNativeDialog = null; rulesSizingDialog = null; rulesSizingPage = -1; rulesSizingAppliedHeight = 0f; activeRulesDialogWasOpen = false; rulesPageTransitioning = false; rulesPages.Clear(); rulesPageIndex = 0; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Server Rules dialog closed without joining."); } private void OnRulesAccepted() { if (shuttingDown) { return; } if (!rulesOpen || !pendingJoin || rulesPages.Count == 0 || rulesPageIndex != rulesPages.Count - 1) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Ignoring rules acceptance outside the final agreement page."); OnRulesDialogClosed(); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Connect: rules AGREE callback received on final page; scheduling join."); OnRulesDialogClosed(); PlayerPrefs.SetInt(AcceptanceKey(), 1); PlayerPrefs.Save(); if (!joinQueuedAfterRules) { joinQueuedAfterRules = true; ((MonoBehaviour)this).StartCoroutine(JoinAfterRulesDialog()); } } private IEnumerator JoinAfterRulesDialog() { yield return null; joinQueuedAfterRules = false; if (!shuttingDown && (Object)(object)this != (Object)null && ((Behaviour)this).isActiveAndEnabled) { BeginJoin(); } } private void ShowRulesForAgreement() { BeginRulesViewer(forAgreement: true); } private void CheckRulesModalLifetime() { if (shuttingDown || !rulesOpen || rulesPageTransitioning || activeRulesDialog == null) { return; } try { if (activeRulesDialog.IsOpen) { activeRulesDialogWasOpen = true; } else if (activeRulesDialogWasOpen) { OnRulesDialogClosed(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Log