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 FehuServerNotice v420.101.1
BepInEx/plugins/FehuServerNotice/FehuServerNotice.dll
Decompiled a day agousing System; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using System.Text; using System.Xml; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("BlackViking")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("420.101.1.0")] [assembly: AssemblyInformationalVersion("420.101.1")] [assembly: AssemblyProduct("FehuServerNotice")] [assembly: AssemblyTitle("FehuServerNotice")] [assembly: AssemblyVersion("420.101.1.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 FehuServerNotice { public static class EndpointMatcher { public static bool IsApproved(string host, int port, string approvedEndpoints) { if (port < 1 || port > 65535 || string.IsNullOrWhiteSpace(host)) { return false; } string[] array = (approvedEndpoints ?? "").Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { if (TryParse(array[i], out var host2, out var port2) && port == port2 && string.Equals(NormalizeHost(host), NormalizeHost(host2), StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static string NormalizeHost(string host) { return host.Trim().Trim('[', ']').TrimEnd(new char[1] { '.' }); } public static bool TryParse(string endpoint, out string host, out int port) { host = ""; port = 0; if (string.IsNullOrWhiteSpace(endpoint)) { return false; } endpoint = endpoint.Trim(); int num = endpoint.LastIndexOf(':'); if (num <= 0 || !int.TryParse(endpoint.Substring(num + 1), NumberStyles.None, CultureInfo.InvariantCulture, out port) || port < 1 || port > 65535) { return false; } host = endpoint.Substring(0, num); if (host.Contains(":") && (!host.StartsWith("[") || !host.EndsWith("]"))) { return false; } if (host.IndexOfAny(new char[7] { '/', '\\', '@', ' ', '\t', '\r', '\n' }) >= 0) { return false; } return NormalizeHost(host).Length > 0; } public static bool TryGetSafeJoinUrl(string input, out string url) { url = null; if (!Uri.TryCreate(input, UriKind.Absolute, out Uri result) || result.Scheme != Uri.UriSchemeHttps || string.IsNullOrWhiteSpace(result.Host) || !string.IsNullOrEmpty(result.UserInfo)) { return false; } url = result.AbsoluteUri; return true; } } internal static class NoticeContent { internal const string Body = "This mod is designed primarily for <b>active, populated multiplayer servers</b>, where clans, territories, trade, events and warfare can work as intended.\n\nFor this reason, multiplayer access while using this mod is limited to <b>official Forteca servers</b>.\n\n<b>PLAY WITH US — FREE</b>\n\nYou are welcome to join the <b>Forteca Community</b> and play with us completely free of charge.\n\n<b>Forteca is a 27-year-old gaming community</b> built around long-term worlds, cooperation, competition, playing together, learning and creating together.\n\nThere is no paywall required to play, progress, fight, build or explore.\n\n<b>All supporter perks are cosmetic or community-focused.</b>\n\n<b>No gameplay advantages. No pay-to-win.</b>\n\nCome experience the mod the way it was designed to be played:\n\nactive players • clans • wars • territories • economy • events\n\n<b>Join Forteca. Bring your friends. Build your clan. Create your legacy.</b>"; internal static readonly string[] Paragraphs = "This mod is designed primarily for <b>active, populated multiplayer servers</b>, where clans, territories, trade, events and warfare can work as intended.\n\nFor this reason, multiplayer access while using this mod is limited to <b>official Forteca servers</b>.\n\n<b>PLAY WITH US — FREE</b>\n\nYou are welcome to join the <b>Forteca Community</b> and play with us completely free of charge.\n\n<b>Forteca is a 27-year-old gaming community</b> built around long-term worlds, cooperation, competition, playing together, learning and creating together.\n\nThere is no paywall required to play, progress, fight, build or explore.\n\n<b>All supporter perks are cosmetic or community-focused.</b>\n\n<b>No gameplay advantages. No pay-to-win.</b>\n\nCome experience the mod the way it was designed to be played:\n\nactive players • clans • wars • territories • economy • events\n\n<b>Join Forteca. Bring your friends. Build your clan. Create your legacy.</b>".Split(new string[1] { "\n\n" }, StringSplitOptions.None); internal static NoticeDocument CreateDefault() { NoticeParagraph[] array = new NoticeParagraph[Paragraphs.Length]; for (int i = 0; i < array.Length; i++) { array[i] = new NoticeParagraph { Text = Paragraphs[i], Style = ((i == 9) ? "feature" : "body") }; } return new NoticeDocument { Title = "MULTIPLAYER NOTICE", ButtonText = "CONTINUE", Paragraphs = array }; } } [DataContract] internal sealed class NoticeDocument { [DataMember(Name = "title", Order = 0, IsRequired = true)] public string Title { get; set; } [DataMember(Name = "buttonText", Order = 1, IsRequired = true)] public string ButtonText { get; set; } [DataMember(Name = "paragraphs", Order = 2, IsRequired = true)] public NoticeParagraph[] Paragraphs { get; set; } } [DataContract] internal sealed class NoticeParagraph { [DataMember(Name = "text", Order = 0, IsRequired = true)] public string Text { get; set; } [DataMember(Name = "style", Order = 1)] public string Style { get; set; } internal bool IsFeature => Style == "feature"; } internal static class NoticeContentFile { internal const int MaximumFileBytes = 131072; internal static NoticeDocument LoadOrCreate(string path, Action<string> warn) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Invalid comparison between Unknown and I4 try { if (!File.Exists(path)) { CreateDefaultFile(path); } using FileStream fileStream = File.OpenRead(path); if (fileStream.Length > 131072) { throw new InvalidDataException("Notice JSON exceeds 128 KiB."); } if (fileStream.Length >= 3 && (fileStream.ReadByte() != 239 || fileStream.ReadByte() != 187 || fileStream.ReadByte() != 191)) { fileStream.Position = 0L; } XmlDictionaryReader val = JsonReaderWriterFactory.CreateJsonReader((Stream)fileStream, XmlDictionaryReaderQuotas.Max); try { NoticeDocument noticeDocument = (NoticeDocument)((XmlObjectSerializer)new DataContractJsonSerializer(typeof(NoticeDocument))).ReadObject(val); while (((XmlReader)val).Read()) { if ((int)((XmlReader)val).NodeType != 13) { throw new InvalidDataException("Unexpected data after the notice JSON."); } } Validate(noticeDocument); return noticeDocument; } finally { ((IDisposable)val)?.Dispose(); } } catch (Exception ex) when (ex is IOException || ex is InvalidDataException || ex is UnauthorizedAccessException || ex is SerializationException || ex is XmlException || ex is FormatException) { warn?.Invoke("Notice text JSON could not be loaded; using built-in text. " + ex.Message); return NoticeContent.CreateDefault(); } } private static void Validate(NoticeDocument document) { if (document == null || string.IsNullOrWhiteSpace(document.Title) || string.IsNullOrWhiteSpace(document.ButtonText)) { throw new InvalidDataException("Notice title and buttonText must be non-empty strings."); } if (document.Paragraphs == null || document.Paragraphs.Length == 0 || document.Paragraphs.Length > 64) { throw new InvalidDataException("Notice paragraphs must contain between 1 and 64 entries."); } NoticeParagraph[] paragraphs = document.Paragraphs; foreach (NoticeParagraph noticeParagraph in paragraphs) { if (noticeParagraph == null || string.IsNullOrWhiteSpace(noticeParagraph.Text)) { throw new InvalidDataException("Each notice paragraph needs non-empty text."); } if (string.IsNullOrEmpty(noticeParagraph.Style)) { noticeParagraph.Style = "body"; } if (noticeParagraph.Style != "body" && noticeParagraph.Style != "feature") { throw new InvalidDataException("Paragraph style must be body or feature."); } } } private static void CreateDefaultFile(string path) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) Directory.CreateDirectory(Path.GetDirectoryName(path)); string text = path + "." + Guid.NewGuid().ToString("N") + ".tmp"; try { using (FileStream fileStream = new FileStream(text, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { XmlDictionaryWriter val = JsonReaderWriterFactory.CreateJsonWriter((Stream)fileStream, (Encoding)new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), false, true, " "); try { ((XmlObjectSerializer)new DataContractJsonSerializer(typeof(NoticeDocument))).WriteObject(val, (object)NoticeContent.CreateDefault()); ((XmlWriter)val).Flush(); } finally { ((IDisposable)val)?.Dispose(); } fileStream.Flush(flushToDisk: true); } File.Move(text, path); } finally { if (File.Exists(text)) { File.Delete(text); } } } } public static class NoticeLayout { public const float DesignWidth = 940f; public const float DesignHeight = 620f; public const float PreviousTopInset = 92f; public const float UpwardOffset = 18f; public const float TopInset = 74f; public const float BottomEdgeInset = 20f; public const float BodyTop = 86f; public const float ButtonGap = 16f; public const float ButtonHeight = 52f; public const float ButtonWidth = 230f; public const float BottomPadding = 18f; public static float ButtonTopForBody(float bodyHeight) { return 86f + Math.Max(0f, bodyHeight) + 16f; } public static float HeightForBody(float bodyHeight) { return ButtonTopForBody(bodyHeight) + 52f + 18f; } public static float FitScale(float availableWidth, float availableHeight, float userScale, float panelHeight = 620f) { return Math.Max(0.01f, Math.Min(userScale, Math.Min(Math.Max(1f, availableWidth - 40f) / 940f, Math.Max(1f, availableHeight - 92f - 20f) / Math.Max(1f, panelHeight)))); } public static float SpaceAfterParagraph(int index) { return index switch { 0 => 14f, 1 => 16f, 2 => 10f, 3 => 10f, 4 => 12f, 5 => 14f, 6 => 9f, 7 => 16f, 8 => 16f, 9 => 16f, _ => 0f, }; } } public static class NoticePolicy { public static bool ShouldShow(bool enabled, bool showOnFirstRun, int version, int reminderDays, NoticeState state, DateTimeOffset now, bool showEveryStart = false) { if (!enabled) { return false; } if (showEveryStart) { return true; } if (state == null || !state.HasDisplay) { return showOnFirstRun; } if (state.NoticeVersion != version) { return true; } return now - state.Timestamp >= TimeSpan.FromDays(Math.Max(1, reminderDays)); } } [DataContract] public sealed class NoticeState { [DataMember(Order = 0)] public string LastNoticeShown { get; set; } = ""; [DataMember(Order = 1)] public int NoticeVersion { get; set; } public DateTimeOffset Timestamp { get { if (!DateTimeOffset.TryParse(LastNoticeShown, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var result)) { return DateTimeOffset.MinValue; } return result; } } public bool HasDisplay => Timestamp != DateTimeOffset.MinValue; public static NoticeState Displayed(int version, DateTimeOffset now) { return new NoticeState { LastNoticeShown = now.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture), NoticeVersion = version }; } } public sealed class NoticeStateStore { private readonly string path; public NoticeStateStore(string path) { this.path = path; } private static NoticeState Read(string file) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) using FileStream fileStream = File.OpenRead(file); NoticeState noticeState = (NoticeState)((XmlObjectSerializer)new DataContractJsonSerializer(typeof(NoticeState))).ReadObject((Stream)fileStream); if (noticeState == null || !noticeState.HasDisplay || noticeState.NoticeVersion < 1) { throw new InvalidDataException("Invalid notice timestamp or version."); } return noticeState; } public NoticeState Load(Action<string> warn) { if (!File.Exists(path)) { return new NoticeState(); } try { return Read(path); } catch (Exception ex) when (ex is IOException || ex is InvalidDataException || ex is UnauthorizedAccessException || ex is SerializationException || ex is FormatException) { warn?.Invoke("Notice state could not be read: " + ex.Message); try { if (File.Exists(path + ".bak")) { return Read(path + ".bak"); } } catch (Exception ex2) when (ex2 is IOException || ex2 is InvalidDataException || ex2 is UnauthorizedAccessException || ex2 is SerializationException || ex2 is FormatException) { } return new NoticeState(); } } public void Save(NoticeState state) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) Directory.CreateDirectory(Path.GetDirectoryName(path)); string sourceFileName = path + "." + Guid.NewGuid().ToString("N") + ".tmp"; try { using (FileStream fileStream = new FileStream(sourceFileName, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { ((XmlObjectSerializer)new DataContractJsonSerializer(typeof(NoticeState))).WriteObject((Stream)fileStream, (object)state); fileStream.Flush(flushToDisk: true); } if (File.Exists(path)) { File.Replace(sourceFileName, path, path + ".bak"); } else { File.Move(sourceFileName, path); } } finally { if (File.Exists(sourceFileName)) { File.Delete(sourceFileName); } } } } internal sealed class NoticeView { private const int ModalDepth = -10000; private const int WindowId = 145901101; private GameObject root; private RectTransform host; private GameObject previousSelection; private GUIStyle titleStyle; private GUIStyle bodyStyle; private GUIStyle featureStyle; private GUIStyle buttonStyle; private Texture2D runeImage; private Action acknowledge; private bool focusPrimary; private bool bodyMeasured; private bool buttonPressed; private float drawScale = 1f; private float currentUiScale = 1f; private float panelHeight = 620f; private Rect screenPanel; private NoticeDocument content; private Rect[] paragraphRects; private Rect continueRect; internal bool Visible { get { if ((Object)(object)root != (Object)null) { return root.activeInHierarchy; } return false; } } internal void Show(Action acknowledge, string joinUrl, Action<string> openUrl, float uiScale, NoticeDocument content) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) GUIManager instance = GUIManager.Instance; GameObject customGUIFront = GUIManager.CustomGUIFront; if ((Object)(object)customGUIFront == (Object)null) { throw new InvalidOperationException("Native GUI is not ready."); } this.acknowledge = acknowledge; this.content = content; paragraphRects = (Rect[])(object)new Rect[content.Paragraphs.Length]; host = customGUIFront.GetComponent<RectTransform>(); root = new GameObject("FehuServerNoticePointerBlocker", new Type[2] { typeof(RectTransform), typeof(Image) }); root.SetActive(false); root.transform.SetParent(customGUIFront.transform, false); RectTransform component = root.GetComponent<RectTransform>(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; ((Graphic)root.GetComponent<Image>()).color = Color.clear; ((Graphic)root.GetComponent<Image>()).canvasRenderer.cullTransparentMesh = false; Font averiaSerif = instance.AveriaSerif; titleStyle = TextStyle(averiaSerif, 26, new Color(0.84f, 0.68f, 0.4f), (TextAnchor)4); bodyStyle = TextStyle(averiaSerif, 20, new Color(0.94f, 0.91f, 0.84f), (TextAnchor)0); featureStyle = TextStyle(averiaSerif, 20, new Color(0.88f, 0.77f, 0.55f), (TextAnchor)4); buttonStyle = TextStyle(instance.AveriaSerifBold, 19, new Color(0.94f, 0.82f, 0.6f), (TextAnchor)4); buttonStyle.hover.textColor = new Color(1f, 0.89f, 0.66f); buttonStyle.active.textColor = new Color(0.86f, 0.72f, 0.46f); buttonStyle.focused.textColor = new Color(1f, 0.89f, 0.66f); runeImage = CreateRuneImage(); previousSelection = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null); if ((Object)(object)EventSystem.current != (Object)null) { EventSystem.current.SetSelectedGameObject((GameObject)null); } focusPrimary = true; bodyMeasured = false; root.SetActive(true); root.transform.SetAsLastSibling(); Resize(uiScale); } internal void Resize(float uiScale) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) currentUiScale = uiScale; if (!((Object)(object)host == (Object)null)) { Rect rect = host.rect; Vector2 size = ((Rect)(ref rect)).size; float num = Mathf.Min((float)Screen.width / Mathf.Max(1f, size.x), (float)Screen.height / Mathf.Max(1f, size.y)); num = Mathf.Max(0.01f, num); drawScale = num * NoticeLayout.FitScale((float)Screen.width / num, (float)Screen.height / num, uiScale, panelHeight); float num2 = 940f * drawScale; float num3 = panelHeight * drawScale; screenPanel = new Rect(((float)Screen.width - num2) / 2f, 74f * num, num2, num3); } } internal void Draw() { //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Invalid comparison between Unknown and I4 //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Invalid comparison between Unknown and I4 //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) if (!Visible) { return; } int depth = GUI.depth; Matrix4x4 matrix = GUI.matrix; Color color = GUI.color; Color backgroundColor = GUI.backgroundColor; Color contentColor = GUI.contentColor; bool enabled = GUI.enabled; try { GUI.depth = -10000; GUI.matrix = Matrix4x4.identity; GUI.enabled = true; GUI.backgroundColor = Color.white; GUI.contentColor = Color.white; if (!bodyMeasured) { float num = 86f; for (int i = 0; i < content.Paragraphs.Length; i++) { float num2 = Mathf.Ceil((content.Paragraphs[i].IsFeature ? featureStyle : bodyStyle).CalcHeight(new GUIContent(content.Paragraphs[i].Text), 876f)); paragraphRects[i] = new Rect(32f, num, 876f, num2); num += num2 + NoticeLayout.SpaceAfterParagraph(i); } float bodyHeight = num - 86f; continueRect = new Rect(355f, NoticeLayout.ButtonTopForBody(bodyHeight), 230f, 52f); panelHeight = NoticeLayout.HeightForBody(bodyHeight); bodyMeasured = true; Resize(currentUiScale); } Solid(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), new Color(0f, 0f, 0f, 0.67f)); GUI.color = Color.white; GUI.matrix = Matrix4x4.TRS(new Vector3(((Rect)(ref screenPanel)).x, ((Rect)(ref screenPanel)).y, 0f), Quaternion.identity, new Vector3(drawScale, drawScale, 1f)); GUI.ModalWindow(145901101, new Rect(0f, 0f, 940f, panelHeight), new WindowFunction(DrawPanel), GUIContent.none, GUIStyle.none); Event current = Event.current; if ((int)current.type == 0 || (int)current.type == 1 || (int)current.type == 6) { current.Use(); } } finally { GUI.depth = depth; GUI.matrix = matrix; GUI.color = color; GUI.enabled = enabled; GUI.backgroundColor = backgroundColor; GUI.contentColor = contentColor; } } private void DrawPanel(int id) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Invalid comparison between Unknown and I4 Rect rect = default(Rect); ((Rect)(ref rect))..ctor(0f, 0f, 940f, panelHeight); Solid(rect, new Color(0.38f, 0.29f, 0.17f, 1f)); Solid(new Rect(2f, 2f, ((Rect)(ref rect)).width - 4f, ((Rect)(ref rect)).height - 4f), new Color(0.075f, 0.06f, 0.04f, 1f)); GUI.Label(new Rect(30f, 14f, ((Rect)(ref rect)).width - 60f, 32f), content.Title, titleStyle); Rect rect2 = default(Rect); ((Rect)(ref rect2))..ctor((((Rect)(ref rect)).width - 24f) / 2f, 47f, 24f, 20f); DrawFehuRune(rect2); Solid(new Rect(32f, 74f, ((Rect)(ref rect)).width - 64f, 1f), new Color(0.6f, 0.44f, 0.22f, 0.7f)); for (int i = 0; i < content.Paragraphs.Length; i++) { if (content.Paragraphs[i].IsFeature) { Solid(new Rect(((Rect)(ref rect)).width * 0.2f, ((Rect)(ref paragraphRects[i])).y - 7f, ((Rect)(ref rect)).width * 0.6f, 1f), new Color(0.53f, 0.4f, 0.22f, 0.35f)); } GUI.Label(paragraphRects[i], content.Paragraphs[i].Text, content.Paragraphs[i].IsFeature ? featureStyle : bodyStyle); } if (DrawButton(continueRect, content.ButtonText, "FehuServerNoticeContinue")) { acknowledge(); } if (focusPrimary && (int)Event.current.type == 7) { GUI.FocusControl("FehuServerNoticeContinue"); focusPrimary = false; } } private bool DrawButton(Rect rect, string text, string controlName) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) bool flag = ((Rect)(ref rect)).Contains(Event.current.mousePosition); if ((int)Event.current.type == 0 && Event.current.button == 0 && flag) { buttonPressed = true; } if ((int)Event.current.rawType == 1) { buttonPressed = false; } bool flag2 = buttonPressed && flag; if (flag && !flag2) { Solid(new Rect(((Rect)(ref rect)).x - 2f, ((Rect)(ref rect)).y - 2f, ((Rect)(ref rect)).width + 4f, ((Rect)(ref rect)).height + 4f), new Color(0.65f, 0.49f, 0.27f, 0.1f)); } Solid(rect, flag2 ? new Color(0.39f, 0.29f, 0.17f, 1f) : (flag ? new Color(0.62f, 0.47f, 0.27f, 1f) : new Color(0.5f, 0.38f, 0.22f, 1f))); Solid(new Rect(((Rect)(ref rect)).x + 2f, ((Rect)(ref rect)).y + 2f, ((Rect)(ref rect)).width - 4f, ((Rect)(ref rect)).height - 4f), flag2 ? new Color(0.11f, 0.085f, 0.05f, 1f) : (flag ? new Color(0.23f, 0.18f, 0.11f, 1f) : new Color(0.15f, 0.12f, 0.075f, 1f))); GUI.SetNextControlName(controlName); return GUI.Button(rect, text, buttonStyle); } private static GUIStyle TextStyle(Font font, int size, Color color, TextAnchor alignment) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown GUIStyle val = new GUIStyle { font = font, fontSize = size, alignment = alignment, fontStyle = (FontStyle)0, wordWrap = true, richText = true, padding = new RectOffset(0, 0, 0, 0) }; val.normal.textColor = color; return val; } private static void Solid(Rect rect, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Color color2 = GUI.color; GUI.color = color; GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture); GUI.color = color2; } private void DrawFehuRune(Rect rect) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; try { GUI.color = new Color(0.7f, 0.54f, 0.3f, 1f); GUI.DrawTexture(rect, (Texture)(object)runeImage); } finally { GUI.color = color; } } private static Texture2D CreateRuneImage() { //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) Color32[] array = (Color32[])(object)new Color32[30720]; Vector2 point = default(Vector2); for (int i = 0; i < 160; i++) { for (int j = 0; j < 192; j++) { ((Vector2)(ref point))..ctor(((float)j + 0.5f) / 8f, 20f - ((float)i + 0.5f) / 8f); float num = Mathf.Min(DistanceToStroke(point, new Vector2(6f, 1f), new Vector2(6f, 19f)), Mathf.Min(DistanceToStroke(point, new Vector2(6f, 7.5f), new Vector2(18f, 1f)), DistanceToStroke(point, new Vector2(6f, 14.5f), new Vector2(18f, 8f)))); byte b = (byte)Mathf.RoundToInt(255f * Mathf.Clamp01((0.9375f - num) * 8f + 0.5f)); array[i * 192 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b); } } Texture2D val = new Texture2D(192, 160, (TextureFormat)4, false) { name = "FehuServerNoticeRune", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; val.SetPixels32(array); val.Apply(false, true); return val; } private static float DistanceToStroke(Vector2 point, Vector2 start, Vector2 end) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Vector2 val = end - start; float num = Mathf.Clamp01(Vector2.Dot(point - start, val) / ((Vector2)(ref val)).sqrMagnitude); return Vector2.Distance(point, start + num * val); } internal void Close() { if ((Object)(object)root != (Object)null) { Object.Destroy((Object)(object)root); } root = null; if ((Object)(object)runeImage != (Object)null) { Object.Destroy((Object)(object)runeImage); } runeImage = null; if ((Object)(object)EventSystem.current != (Object)null && (Object)(object)previousSelection != (Object)null && previousSelection.activeInHierarchy) { EventSystem.current.SetSelectedGameObject(previousSelection); } previousSelection = null; } } internal enum Destination { None, Unknown, Official, Other } internal static class OfficialServerDetector { private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; internal static Destination Read(FejdStartup startup, string endpoints, Action<string> debug) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)startup != (Object)null && startup.HasServerToJoin()) { object obj = startup.GetServerToJoin(); object obj2 = obj.GetType().GetProperty("Dedicated", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj); if (obj2 == null) { return Destination.Unknown; } string text = obj2.GetType().GetMethod("GetHost", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(obj2, null) as string; object obj3 = obj2.GetType().GetField("m_port", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj2); if (text == null || obj3 == null) { return Destination.Unknown; } return EndpointMatcher.IsApproved(text, Convert.ToInt32(obj3), endpoints) ? Destination.Official : Destination.Other; } if (!ZNet.HasServerHost()) { return Destination.None; } string serverString = ZNet.GetServerString(true); if (serverString == null || serverString.StartsWith("playfab/", StringComparison.Ordinal)) { return Destination.Unknown; } if (!EndpointMatcher.TryParse(serverString.Substring(serverString.LastIndexOf('/') + 1), out var host, out var port)) { return Destination.Unknown; } return EndpointMatcher.IsApproved(host, port, endpoints) ? Destination.Official : Destination.Other; } catch (Exception ex) { debug?.Invoke("Destination unavailable: " + ex.GetType().Name); return Destination.Unknown; } } } [BepInPlugin("forteca.fehuservernotice", "FehuServerNotice", "420.101.1")] [BepInDependency("com.jotunn.jotunn", "2.30.2")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "forteca.fehuservernotice"; public const string Name = "FehuServerNotice"; public const string Version = "420.101.1"; internal static Plugin Instance; private ConfigEntry<bool> noticeEnabled; private ConfigEntry<bool> firstRun; private ConfigEntry<bool> debugLogging; private ConfigEntry<bool> showEveryStart; private ConfigEntry<int> noticeVersion; private ConfigEntry<int> reminderDays; private ConfigEntry<string> joinUrl; private ConfigEntry<string> officialEndpoints; private ConfigEntry<float> uiScale; private readonly NoticeView view = new NoticeView(); private NoticeStateStore store; private NoticeState state; private NoticeDocument content; private Harmony harmony; private bool finishedThisSession; private bool warnedSave; private bool warnedDestination; private bool displayedInTestMode; private int displayedVersion; private float nextCheck; private float readySince = -1f; private static readonly FieldInfo MainMenu = typeof(FejdStartup).GetField("m_mainMenu", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static bool NoticeVisible { get { if ((Object)(object)Instance != (Object)null) { return Instance.view.Visible; } return false; } } private void Awake() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Expected O, but got Unknown //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown if (GUIManager.IsHeadless()) { ((Behaviour)this).enabled = false; return; } try { noticeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Notice", "Enabled", true, "Enable the informational notice."); noticeVersion = ((BaseUnityPlugin)this).Config.Bind<int>("Notice", "NoticeVersion", 1, new ConfigDescription("Increment to show updated notice text again.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, int.MaxValue), Array.Empty<object>())); reminderDays = ((BaseUnityPlugin)this).Config.Bind<int>("Notice", "ReminderDays", 7, new ConfigDescription("Minimum days between notices.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 3650), Array.Empty<object>())); firstRun = ((BaseUnityPlugin)this).Config.Bind<bool>("Notice", "ShowOnFirstRun", true, "Show automatically when there is no local display history."); showEveryStart = ((BaseUnityPlugin)this).Config.Bind<bool>("Notice", "ShowEveryStart", false, "Temporary UI test mode: show once on every eligible game start, ignoring display history. Does not overwrite normal notice state. Set false to restore normal reminders."); joinUrl = ((BaseUnityPlugin)this).Config.Bind<string>("Notice", "JoinFortecaUrl", "", "Optional absolute HTTPS community URL. Blank or invalid hides JOIN FORTECA."); debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Notice", "DebugLogging", false, "Enable detailed DEBUG diagnostics."); officialEndpoints = ((BaseUnityPlugin)this).Config.Bind<string>("Notice", "OfficialServerEndpoints", "", "Exact approved host:game-port pairs separated by semicolons. IPv6: [address]:port. Blank disables positive identification. No server-name matching or remote lookup."); uiScale = ((BaseUnityPlugin)this).Config.Bind<float>("Notice", "UiScale", 1f, new ConfigDescription("Notice size multiplier; always fitted inside the available screen.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.75f, 1.5f), Array.Empty<object>())); store = new NoticeStateStore(Path.Combine(Paths.ConfigPath, "FehuServerNotice", "state.json")); state = store.Load(delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }); content = NoticeContentFile.LoadOrCreate(Path.Combine(Paths.ConfigPath, "FehuServerNotice", "notice.json"), delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }); Instance = this; harmony = new Harmony("forteca.fehuservernotice"); harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Loaded. Notice version {noticeVersion.Value}, reminder {reminderDays.Value} days." + (showEveryStart.Value ? " Test mode: every start." : ""))); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Notice initialization skipped safely: " + ex.Message)); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Instance = null; ((Behaviour)this).enabled = false; } } private void Update() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < nextCheck) { return; } nextCheck = Time.unscaledTime + 0.5f; try { Scene activeScene; if (view.Visible) { if (noticeEnabled.Value) { activeScene = SceneManager.GetActiveScene(); if (!(((Scene)(ref activeScene)).name != "start")) { view.Resize(uiScale.Value); return; } } view.Close(); } else { if (finishedThisSession || !NoticePolicy.ShouldShow(noticeEnabled.Value, firstRun.Value, noticeVersion.Value, reminderDays.Value, state, DateTimeOffset.UtcNow, showEveryStart.Value)) { return; } activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "start" || (Object)(object)FejdStartup.instance == (Object)null) { readySince = -1f; return; } FejdStartup instance = FejdStartup.instance; switch (OfficialServerDetector.Read(instance, officialEndpoints.Value, delegate(string message) { if (!warnedDestination) { Debug(message); warnedDestination = true; } })) { case Destination.Official: finishedThisSession = true; Debug("Official destination; notice skipped for this session."); break; default: readySince = -1f; break; case Destination.None: { object? obj = MainMenu?.GetValue(instance); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if ((Object)(object)val == (Object)null || !val.activeInHierarchy || (Object)(object)GUIManager.CustomGUIFront == (Object)null) { readySince = -1f; break; } if (readySince < 0f) { readySince = Time.unscaledTime; } if (!(Time.unscaledTime - readySince < 5f)) { displayedVersion = noticeVersion.Value; displayedInTestMode = showEveryStart.Value; view.Show(Acknowledge, joinUrl.Value, OpenUrl, uiScale.Value, content); finishedThisSession = true; if (!displayedInTestMode) { Persist(displayedVersion); } Debug("Notice displayed."); } break; } } } } catch (Exception ex) { view.Close(); finishedThisSession = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Notice skipped safely: " + ex.Message)); } } private void OnGUI() { if (!view.Visible) { return; } try { view.Draw(); } catch (Exception ex) { view.Close(); finishedThisSession = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Notice rendering skipped safely: " + ex.Message)); } } private void Acknowledge() { if (!displayedInTestMode) { Persist(displayedVersion); } view.Close(); Debug("Notice acknowledged."); } private void Persist(int version) { state = NoticeState.Displayed(version, DateTimeOffset.UtcNow); try { store.Save(state); } catch (Exception ex) { if (!warnedSave) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Local notice state could not be saved: " + ex.Message)); warnedSave = true; } } } private void OpenUrl(string url) { if (!EndpointMatcher.TryGetSafeJoinUrl(url, out var url2)) { return; } try { Application.OpenURL(url2); } catch (Exception ex) { Debug("Community URL unavailable: " + ex.GetType().Name); } } private void Debug(string message) { if (debugLogging.Value) { ((BaseUnityPlugin)this).Logger.LogDebug((object)message); } } private void OnDestroy() { view.Close(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } } [HarmonyPatch(typeof(FejdStartup), "UpdateKeyboard")] internal static class MenuKeyboardPatch { private static bool Prefix() { return !Plugin.NoticeVisible; } } [HarmonyPatch(typeof(FejdStartup), "UpdateGamepad")] internal static class MenuGamepadPatch { private static bool Prefix() { return !Plugin.NoticeVisible; } } }