Decompiled source of GK2Plus v0.1.0
BepInEx\plugins\GK2Plus\GK2Plus.dll
Decompiled 19 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GK2Plus.Core; using GK2Plus.Features.Cheats; using GK2Plus.Features.General; using GK2Plus.Framework; using GK2Plus.Framework.Crafting; using GK2Plus.Framework.Diagnostics; using GK2Plus.Framework.Events; using GK2Plus.Framework.Farming; using GK2Plus.Framework.Inventory; using GK2Plus.Framework.Localization; using GK2Plus.Framework.Quests; using GK2Plus.Framework.Saves; using GK2Plus.Framework.UI; using GK2Plus.Framework.World; using GK2Plus.Framework.Zombies; using HarmonyLib; using LazyBearTechnology; using Microsoft.CodeAnalysis; 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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("duhhbzz")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+76b76c9815df8dfd14cd1e3d11c5df32a3ded7e0")] [assembly: AssemblyProduct("GK2Plus")] [assembly: AssemblyTitle("GK2Plus")] [assembly: AssemblyVersion("0.1.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 GK2Plus { [BepInPlugin("com.duhhbzz.gk2plus", "GK2+", "0.1.0")] public sealed class Plugin : BaseUnityPlugin { private Harmony _harmony; private FeatureRegistry _featureRegistry; private CompatibilityManager _compatibilityManager; private GK2Services _services; internal static ConfigEntry<bool> MasterEnabled { get; private set; } private void Awake() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown ((BaseUnityPlugin)this).Logger.LogInfo((object)"----------------------------------------"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"GK2+ v0.1.0"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Graveyard Keeper Plus"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"----------------------------------------"); MasterEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for GK2+ gameplay features."); _harmony = new Harmony("com.duhhbzz.gk2plus"); _compatibilityManager = new CompatibilityManager(((BaseUnityPlugin)this).Logger); _compatibilityManager.Scan(); _services = new GK2Services(((BaseUnityPlugin)this).Logger); _services.Initialize(); FrameworkDiagnostics.LogReady(((BaseUnityPlugin)this).Logger); ((MonoBehaviour)this).StartCoroutine(MainMenuBadgeController.Run(((BaseUnityPlugin)this).Logger)); _featureRegistry = new FeatureRegistry(); RegisterFeatures(_featureRegistry); if (MasterEnabled.Value) { _featureRegistry.InitializeAll(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger, _harmony); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"GK2+ master switch is disabled. Gameplay features will not initialize."); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"GK2+ v0.1.0 loaded successfully."); } private void RegisterFeatures(FeatureRegistry registry) { registry.Register(new ManualSaveFeature(_services.Saves)); registry.Register(new BasicCheatsFeature(_services.Saves, _services.UI)); } private void OnDestroy() { _services?.Shutdown(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace GK2Plus.Framework { internal abstract class GK2ServiceBase : IGK2Service { protected ManualLogSource Logger { get; } public abstract string Name { get; } protected GK2ServiceBase(ManualLogSource logger) { Logger = logger; } public virtual void Initialize() { Logger.LogDebug((object)("Initializing framework service: " + Name)); } public virtual void Shutdown() { Logger.LogDebug((object)("Shutting down framework service: " + Name)); } } internal sealed class GK2Services { private readonly ManualLogSource _logger; private readonly List<IGK2Service> _services; public GK2EventService Events { get; } public GK2SaveService Saves { get; } public GK2WorldService World { get; } public GK2InventoryService Inventory { get; } public GK2CraftingService Crafting { get; } public GK2FarmingService Farming { get; } public GK2ZombieService Zombies { get; } public GK2QuestService Quests { get; } public GK2LocalizationService Localization { get; } public GK2UIService UI { get; } public GK2Services(ManualLogSource logger) { _logger = logger ?? throw new ArgumentNullException("logger"); Events = new GK2EventService(logger); Saves = new GK2SaveService(logger); World = new GK2WorldService(logger); Inventory = new GK2InventoryService(logger); Crafting = new GK2CraftingService(logger); Farming = new GK2FarmingService(logger); Zombies = new GK2ZombieService(logger); Quests = new GK2QuestService(logger); Localization = new GK2LocalizationService(logger); UI = new GK2UIService(logger); _services = new List<IGK2Service> { Events, Saves, World, Inventory, Crafting, Farming, Zombies, Quests, Localization, UI }; } public void Initialize() { _logger.LogInfo((object)$"Initializing {_services.Count} GK2+ framework service(s)..."); foreach (IGK2Service service in _services) { service.Initialize(); } } public void Shutdown() { for (int num = _services.Count - 1; num >= 0; num--) { try { _services[num].Shutdown(); } catch (Exception arg) { _logger.LogError((object)$"Failed to shut down framework service '{_services[num].Name}': {arg}"); } } } } internal interface IGK2Service { string Name { get; } void Initialize(); void Shutdown(); } } namespace GK2Plus.Framework.Zombies { internal sealed class GK2ZombieService : GK2ServiceBase { public override string Name => "Zombies"; public GK2ZombieService(ManualLogSource logger) : base(logger) { } } } namespace GK2Plus.Framework.World { internal sealed class GK2WorldService : GK2ServiceBase { public override string Name => "World"; public GK2WorldService(ManualLogSource logger) : base(logger) { } } } namespace GK2Plus.Framework.UI { internal sealed class GK2MenuAction { public string Id { get; } public string Tab { get; } public string Label { get; } public Action Execute { get; } public Func<bool> IsAvailable { get; } public GK2MenuAction(string id, string tab, string label, Action execute, Func<bool> isAvailable = null) { Id = id ?? throw new ArgumentNullException("id"); Tab = tab ?? throw new ArgumentNullException("tab"); Label = label ?? throw new ArgumentNullException("label"); Execute = execute ?? throw new ArgumentNullException("execute"); IsAvailable = isAvailable; } public bool CanExecute() { if (IsAvailable != null) { return IsAvailable(); } return true; } } internal sealed class GK2UIService : GK2ServiceBase { private readonly List<GK2MenuAction> _menuActions = new List<GK2MenuAction>(); private readonly Dictionary<string, Func<string>> _tabNotices = new Dictionary<string, Func<string>>(); private ModMenuController _modMenuController; public override string Name => "UI"; public GK2UIService(ManualLogSource logger) : base(logger) { } public override void Initialize() { base.Initialize(); _modMenuController = ModMenuController.Create(base.Logger); foreach (GK2MenuAction menuAction in _menuActions) { _modMenuController.RegisterMenuAction(menuAction); } foreach (KeyValuePair<string, Func<string>> tabNotice in _tabNotices) { _modMenuController.RegisterTabNotice(tabNotice.Key, tabNotice.Value); } base.Logger.LogInfo((object)"GK2+ UI service owns the persistent mod-menu controller."); } public void RegisterMenuAction(GK2MenuAction action) { if (action != null) { _menuActions.Add(action); if ((Object)(object)_modMenuController != (Object)null) { _modMenuController.RegisterMenuAction(action); } } } public void RegisterTabNotice(string tab, Func<string> noticeProvider) { if (!string.IsNullOrWhiteSpace(tab) && noticeProvider != null) { _tabNotices[tab] = noticeProvider; if ((Object)(object)_modMenuController != (Object)null) { _modMenuController.RegisterTabNotice(tab, noticeProvider); } } } public void RefreshMenu() { _modMenuController?.RefreshActiveTab(); } public void HideMenu() { _modMenuController?.HideMenu(); } public void ShowMenu() { _modMenuController?.ShowMenu(); } public override void Shutdown() { if ((Object)(object)_modMenuController != (Object)null) { _modMenuController.ShutdownController(); } _modMenuController = null; _menuActions.Clear(); _tabNotices.Clear(); base.Shutdown(); } } internal static class MainMenuBadgeController { private const string BadgeObjectName = "GK2PlusMainMenuBadge"; private static bool _created; public static IEnumerator Run(ManualLogSource logger) { if (_created) { yield break; } Component mainMenu = null; for (int frame = 0; frame < 7200; frame++) { if (!((Object)(object)mainMenu == (Object)null)) { break; } mainMenu = FindActiveMainMenuWindow(); if ((Object)(object)mainMenu == (Object)null) { yield return null; } } if ((Object)(object)mainMenu == (Object)null) { logger.LogWarning((object)"GK2+ main-menu badge could not find an active UIMainMenuWindow."); yield break; } for (int frame = 0; frame < 5; frame++) { yield return null; } try { CreateBadge(mainMenu.transform, logger); _created = true; logger.LogInfo((object)"GK2+ main-menu badge created."); } catch (Exception arg) { logger.LogError((object)$"Failed to create GK2+ main-menu badge: {arg}"); } } private static Component FindActiveMainMenuWindow() { MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>(); foreach (MonoBehaviour val in array) { if (!((Object)(object)val == (Object)null) && ((object)val).GetType().Name == "UIMainMenuWindow" && ((Component)val).gameObject.activeInHierarchy) { return (Component)(object)val; } } return null; } private static void CreateBadge(Transform mainMenuRoot, ManualLogSource logger) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0346: 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_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) Transform val = mainMenuRoot.Find("GK2PlusMainMenuBadge"); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } Sprite val2 = FindSprite("titlescreen-menu-bg"); Sprite val3 = FindSprite("comm-frame_1-border"); Sprite val4 = FindSprite("widget_perks-text_decor-drk_1"); Sprite val5 = FindSprite("wskull"); if ((Object)(object)val3 == (Object)null) { throw new InvalidOperationException("Native frame sprite was not found."); } GameObject val6 = FindBodyTextTemplate(mainMenuRoot); GameObject val7 = FindTitleButtonTemplate(mainMenuRoot); if ((Object)(object)val6 == (Object)null) { throw new InvalidOperationException("Could not find a native body text template."); } if ((Object)(object)val7 == (Object)null) { throw new InvalidOperationException("Could not find the native New Game button background/title template."); } GameObject val8 = new GameObject("GK2PlusMainMenuBadge", new Type[1] { typeof(RectTransform) }); val8.transform.SetParent(mainMenuRoot, false); RectTransform val9 = (RectTransform)val8.transform; val9.anchorMin = new Vector2(1f, 1f); val9.anchorMax = new Vector2(1f, 1f); val9.pivot = new Vector2(1f, 1f); val9.anchoredPosition = new Vector2(-14f, -12f); val9.sizeDelta = new Vector2(176f, 84f); if ((Object)(object)val2 != (Object)null) { CreateStretchImage(val8.transform, "Background", val2, (Type)1, new Vector2(-4f, -4f), new Vector2(4f, 4f)); } CreateStretchImage(val8.transform, "Frame", val3, (Type)1, Vector2.zero, Vector2.zero); GameObject obj = CreateNativeButtonTitle(val7, val8.transform, "GK2+ v0.1.0", new Vector2(0f, -15f)); if ((Object)(object)val5 != (Object)null) { CreateFixedImage(val8.transform, "SkullTop", val5, (Type)0, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 0.5f), new Vector2(0f, -4f), new Vector2(14f, 11f)); } CreateLabel(val6, val8.transform, "HotkeyText", "Press F2 for Mod Menu", new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -39f), new Vector2(152f, 16f), 9f, new Color(0.93f, 0.78f, 0.5f, 1f)); if ((Object)(object)val4 != (Object)null) { CreateFixedImage(val8.transform, "Divider", val4, (Type)1, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -55f), new Vector2(124f, 6f)); } CreateLabel(val6, val8.transform, "StatusText", "Status: Loaded", new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -63f), new Vector2(146f, 14f), 8.5f, new Color(0.87f, 0.8f, 0.62f, 1f)); obj.transform.SetAsLastSibling(); if ((Object)(object)val5 != (Object)null) { Transform val10 = val8.transform.Find("SkullTop"); if ((Object)(object)val10 != (Object)null) { val10.SetAsLastSibling(); } } logger.LogDebug((object)"GK2+ badge now uses a cloned native main-menu button as the title bar."); } private static GameObject FindTitleButtonTemplate(Transform root) { Transform val = root.Find("Bg/Vertical Group/NewGame/Content/Back"); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).gameObject; } private static GameObject FindBodyTextTemplate(Transform root) { Transform val = root.Find("Bg/Vertical Group/ButtonTipsStr"); if ((Object)(object)val != (Object)null) { return ((Component)val).gameObject; } Transform val2 = root.Find("Bg/Vertical Group/NewGame/Content/Back/Label"); if (!((Object)(object)val2 != (Object)null)) { return null; } return ((Component)val2).gameObject; } private static GameObject CreateNativeButtonTitle(GameObject template, Transform parent, string text, Vector2 anchoredPosition) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(template, parent, false); ((Object)val).name = "TitleButton"; val.SetActive(true); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 1f); component.anchorMax = new Vector2(0.5f, 1f); component.pivot = new Vector2(0.5f, 1f); component.anchoredPosition = anchoredPosition; component.sizeDelta = new Vector2(142f, 26f); ((Transform)component).localScale = Vector3.one; Component[] components = val.GetComponents<Component>(); foreach (Component val2 in components) { if (!((Object)(object)val2 == (Object)null) && ((object)val2).GetType().Name == "HorizontalLayoutGroup") { Object.Destroy((Object)(object)val2); } } Transform obj = val.transform.Find("Label"); if ((Object)(object)obj == (Object)null) { throw new InvalidOperationException("Cloned native button did not contain its Label child."); } GameObject gameObject = ((Component)obj).gameObject; components = gameObject.GetComponents<Component>(); foreach (Component val3 in components) { if (!((Object)(object)val3 == (Object)null)) { string name = ((object)val3).GetType().Name; if (name == "LocalizedLabel" || name == "LocalizedVerticalOffset") { Object.Destroy((Object)(object)val3); } } } RectTransform component2 = gameObject.GetComponent<RectTransform>(); component2.anchorMin = Vector2.zero; component2.anchorMax = Vector2.one; component2.pivot = new Vector2(0.5f, 0.5f); component2.anchoredPosition = Vector2.zero; component2.offsetMin = new Vector2(8f, 1f); component2.offsetMax = new Vector2(-8f, -1f); Component obj2 = FindTmp(gameObject); if ((Object)(object)obj2 == (Object)null) { throw new InvalidOperationException("Native title button label has no TextMeshProUGUI."); } SetProperty(obj2, "text", text); TrySetEnumProperty(obj2, "alignment", "Center"); Image component3 = val.GetComponent<Image>(); if ((Object)(object)component3 != (Object)null) { ((Graphic)component3).raycastTarget = false; } return val; } private static Sprite FindSprite(string name) { return ((IEnumerable<Sprite>)Resources.FindObjectsOfTypeAll<Sprite>()).FirstOrDefault((Func<Sprite, bool>)((Sprite sprite) => (Object)(object)sprite != (Object)null && string.Equals(((Object)sprite).name, name, StringComparison.Ordinal))); } private static GameObject CreateStretchImage(Transform parent, string name, Sprite sprite, Type type, Vector2 offsetMin, Vector2 offsetMax) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown GameObject val = new GameObject(name, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); val.transform.SetParent(parent, false); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.pivot = new Vector2(0.5f, 0.5f); val2.offsetMin = offsetMin; val2.offsetMax = offsetMax; Image component = val.GetComponent<Image>(); component.sprite = sprite; component.type = type; component.preserveAspect = false; ((Graphic)component).raycastTarget = false; return val; } private static GameObject CreateFixedImage(Transform parent, string name, Sprite sprite, Type type, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 anchoredPosition, Vector2 size) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0094: Expected O, but got Unknown GameObject val = new GameObject(name, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); val.transform.SetParent(parent, false); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = anchorMin; val2.anchorMax = anchorMax; val2.pivot = pivot; val2.anchoredPosition = anchoredPosition; val2.sizeDelta = size; Image component = val.GetComponent<Image>(); component.sprite = sprite; component.type = type; component.preserveAspect = true; ((Graphic)component).raycastTarget = false; return val; } private static GameObject CreateLabel(GameObject template, Transform parent, string name, string text, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 anchoredPosition, Vector2 size, float fontSize, Color color) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(template, parent, false); ((Object)val).name = name; val.SetActive(true); Component[] components = val.GetComponents<Component>(); foreach (Component val2 in components) { if (!((Object)(object)val2 == (Object)null)) { switch (((object)val2).GetType().Name) { case "LazyButtonTipsStr": case "LocalizedLabel": case "LocalizedVerticalOffset": Object.Destroy((Object)(object)val2); break; } } } RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = anchorMin; component.anchorMax = anchorMax; component.pivot = pivot; component.anchoredPosition = anchoredPosition; component.sizeDelta = size; Component obj = FindTmp(val); if ((Object)(object)obj == (Object)null) { throw new InvalidOperationException("Cloned native label has no TextMeshProUGUI."); } SetProperty(obj, "text", text); SetProperty(obj, "fontSize", fontSize); SetProperty(obj, "color", color); TrySetEnumProperty(obj, "fontStyle", "Normal"); TrySetEnumProperty(obj, "fontWeight", "Regular"); TrySetEnumProperty(obj, "alignment", "Center"); return val; } private static Component FindTmp(GameObject obj) { return ((IEnumerable<Component>)obj.GetComponents<Component>()).FirstOrDefault((Func<Component, bool>)((Component component) => (Object)(object)component != (Object)null && ((object)component).GetType().Name == "TextMeshProUGUI")); } private static void TrySetEnumProperty(Component component, string propertyName, string enumValue) { PropertyInfo property = ((object)component).GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null || !property.CanWrite || !property.PropertyType.IsEnum) { return; } try { object value = Enum.Parse(property.PropertyType, enumValue); property.SetValue(component, value, null); } catch { } } private static void SetProperty(Component component, string propertyName, object value) { if (!((Object)(object)component == (Object)null)) { PropertyInfo property = ((object)component).GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { property.SetValue(component, value, null); } } } } internal sealed class ModMenuController : MonoBehaviour { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__25_0; public static UnityAction <>9__25_1; public static UnityAction <>9__25_2; public static Func<GK2MenuAction, string> <>9__26_0; public static Func<Component, bool> <>9__47_0; internal void <BuildMenu>b__25_0() { Application.OpenURL("https://github.com/duhhbzz/GK2Plus"); } internal void <BuildMenu>b__25_1() { Application.OpenURL(""); } internal void <BuildMenu>b__25_2() { Application.OpenURL("https://github.com/duhhbzz/GK2Plus/issues/new"); } internal string <BuildRegisteredActionButtons>b__26_0(GK2MenuAction action) { return action.Tab; } internal bool <FindTmp>b__47_0(Component component) { if ((Object)(object)component != (Object)null) { return ((object)component).GetType().Name == "TextMeshProUGUI"; } return false; } } private const string RootObjectName = "GK2PlusModMenuRoot"; private static readonly string[] Tabs = new string[7] { "General", "Inventory", "Crafting", "Farming", "Zombies", "Cheats", "More" }; private ManualLogSource _logger; private GameObject _menuRoot; private GameObject _pageTitle; private GameObject _pageText; private GameObject _githubButton; private GameObject _nexusButton; private GameObject _bugButton; private GameObject _contentRoot; private GameObject _menuButtonLabelTemplate; private Sprite _menuButtonSprite; private readonly Dictionary<string, GameObject> _tabButtons = new Dictionary<string, GameObject>(); private readonly List<GK2MenuAction> _registeredMenuActions = new List<GK2MenuAction>(); private readonly Dictionary<GK2MenuAction, GameObject> _registeredActionButtons = new Dictionary<GK2MenuAction, GameObject>(); private readonly Dictionary<string, Func<string>> _tabNotices = new Dictionary<string, Func<string>>(StringComparer.OrdinalIgnoreCase); private string _activeTab = "General"; private bool _built; public static ModMenuController Create(ManualLogSource logger) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown GameObject val = GameObject.Find("GK2PlusModMenuController"); if ((Object)(object)val != (Object)null) { ModMenuController component = val.GetComponent<ModMenuController>(); if ((Object)(object)component != (Object)null) { return component; } } val = new GameObject("GK2PlusModMenuController"); Object.DontDestroyOnLoad((Object)(object)val); ModMenuController modMenuController = val.AddComponent<ModMenuController>(); modMenuController._logger = logger; return modMenuController; } public void RegisterMenuAction(GK2MenuAction action) { if (action == null) { return; } if (_registeredMenuActions.Any((GK2MenuAction existing) => string.Equals(existing.Id, action.Id, StringComparison.OrdinalIgnoreCase))) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("GK2+ ignored duplicate menu action id '" + action.Id + "'.")); } return; } _registeredMenuActions.Add(action); if (_built && (Object)(object)_contentRoot != (Object)null && (Object)(object)_menuButtonLabelTemplate != (Object)null && (Object)(object)_menuButtonSprite != (Object)null) { BuildRegisteredActionButtons(); SetActiveTab(_activeTab); } } public void RegisterTabNotice(string tab, Func<string> noticeProvider) { if (!string.IsNullOrWhiteSpace(tab) && noticeProvider != null) { _tabNotices[tab] = noticeProvider; if (_built && string.Equals(_activeTab, tab, StringComparison.OrdinalIgnoreCase)) { SetText(_pageText, GetPlaceholderText(_activeTab)); } } } private void Start() { ((MonoBehaviour)this).StartCoroutine(BootstrapWhenReady()); } private IEnumerator BootstrapWhenReady() { for (int frame = 0; frame < 7200; frame++) { if (TryGetReadyContext(out var _, out var uiRoot, out var bodyTemplate, out var buttonLabelTemplate)) { try { BuildMenu((Transform)(object)uiRoot, bodyTemplate, buttonLabelTemplate); _built = true; ManualLogSource logger = _logger; if (logger != null) { logger.LogInfo((object)"GK2+ mod menu shell ready under persistent GUIElements.Root. Press F2 to toggle."); } yield break; } catch (Exception arg) { CleanupPartialMenu(); ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogError((object)$"GK2+ mod menu shell build failed once: {arg}"); } yield break; } } yield return null; } ManualLogSource logger3 = _logger; if (logger3 != null) { logger3.LogWarning((object)"GK2+ mod menu shell timed out waiting for native UI."); } } private void Update() { if (!_built || (Object)(object)_menuRoot == (Object)null) { return; } if (Input.GetKeyDown((KeyCode)283)) { ManualLogSource logger = _logger; if (logger != null) { logger.LogInfo((object)"GK2+ F2 detected; toggling mod menu."); } ToggleMenu(); } else if (_menuRoot.activeSelf && Input.GetKeyDown((KeyCode)27)) { HideMenu(); } } private bool TryGetReadyContext(out Component mainMenu, out RectTransform uiRoot, out GameObject bodyTemplate, out GameObject buttonLabelTemplate) { mainMenu = null; uiRoot = null; bodyTemplate = null; buttonLabelTemplate = null; MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>(); foreach (MonoBehaviour val in array) { if (!((Object)(object)val == (Object)null) && !(((object)val).GetType().Name != "UIMainMenuWindow") && ((Component)val).gameObject.activeInHierarchy) { mainMenu = (Component)(object)val; break; } } if ((Object)(object)mainMenu == (Object)null) { return false; } GUIElements instance = GUIElements.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.Root == (Object)null || !((Component)instance).gameObject.activeInHierarchy) { return false; } uiRoot = instance.Root; Transform transform = mainMenu.transform; Transform val2 = transform.Find("Bg/Vertical Group/ButtonTipsStr"); Transform val3 = transform.Find("Bg/Vertical Group/NewGame/Content/Back/Label"); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { return false; } if ((Object)(object)FindTmp(((Component)val2).gameObject) == (Object)null || (Object)(object)FindTmp(((Component)val3).gameObject) == (Object)null) { return false; } bodyTemplate = ((Component)val2).gameObject; buttonLabelTemplate = ((Component)val3).gameObject; return true; } private void BuildMenu(Transform uiRoot, GameObject bodyTemplate, GameObject buttonLabelTemplate) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025b: 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_0283: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: 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_0334: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Expected O, but got Unknown //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_040b: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) //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_047c: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_049a: Unknown result type (might be due to invalid IL or missing references) //IL_04a9: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Unknown result type (might be due to invalid IL or missing references) //IL_04f9: Unknown result type (might be due to invalid IL or missing references) //IL_0508: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_0526: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_0567: Unknown result type (might be due to invalid IL or missing references) //IL_0576: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Unknown result type (might be due to invalid IL or missing references) //IL_0594: Unknown result type (might be due to invalid IL or missing references) //IL_05cb: 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_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_05f8: Unknown result type (might be due to invalid IL or missing references) //IL_0607: Unknown result type (might be due to invalid IL or missing references) //IL_069f: Unknown result type (might be due to invalid IL or missing references) //IL_06a8: Unknown result type (might be due to invalid IL or missing references) //IL_06c8: Unknown result type (might be due to invalid IL or missing references) //IL_06d2: Expected O, but got Unknown //IL_077b: Unknown result type (might be due to invalid IL or missing references) //IL_0782: Expected O, but got Unknown //IL_07a8: Unknown result type (might be due to invalid IL or missing references) //IL_07bd: Unknown result type (might be due to invalid IL or missing references) //IL_07d2: Unknown result type (might be due to invalid IL or missing references) //IL_07e7: Unknown result type (might be due to invalid IL or missing references) //IL_07fb: Unknown result type (might be due to invalid IL or missing references) //IL_0821: Unknown result type (might be due to invalid IL or missing references) //IL_0861: Unknown result type (might be due to invalid IL or missing references) //IL_0870: Unknown result type (might be due to invalid IL or missing references) //IL_08a2: Unknown result type (might be due to invalid IL or missing references) //IL_08b1: Unknown result type (might be due to invalid IL or missing references) //IL_08c0: Unknown result type (might be due to invalid IL or missing references) //IL_08cf: Unknown result type (might be due to invalid IL or missing references) //IL_08de: Unknown result type (might be due to invalid IL or missing references) //IL_0946: Unknown result type (might be due to invalid IL or missing references) //IL_0955: Unknown result type (might be due to invalid IL or missing references) //IL_071c: Unknown result type (might be due to invalid IL or missing references) //IL_072b: Unknown result type (might be due to invalid IL or missing references) //IL_073a: Unknown result type (might be due to invalid IL or missing references) //IL_0749: Unknown result type (might be due to invalid IL or missing references) //IL_0758: Unknown result type (might be due to invalid IL or missing references) //IL_0988: Unknown result type (might be due to invalid IL or missing references) //IL_098d: Unknown result type (might be due to invalid IL or missing references) //IL_0993: Expected O, but got Unknown //IL_09c1: Unknown result type (might be due to invalid IL or missing references) //IL_09d0: Unknown result type (might be due to invalid IL or missing references) //IL_0a45: Unknown result type (might be due to invalid IL or missing references) //IL_0a54: Unknown result type (might be due to invalid IL or missing references) //IL_0a87: Unknown result type (might be due to invalid IL or missing references) //IL_0a8c: Unknown result type (might be due to invalid IL or missing references) //IL_0a92: Expected O, but got Unknown //IL_0a1a: Unknown result type (might be due to invalid IL or missing references) //IL_0a1f: Unknown result type (might be due to invalid IL or missing references) //IL_0a25: Expected O, but got Unknown //IL_0b16: Unknown result type (might be due to invalid IL or missing references) //IL_0b25: Unknown result type (might be due to invalid IL or missing references) //IL_0b5b: Unknown result type (might be due to invalid IL or missing references) //IL_0b66: Unknown result type (might be due to invalid IL or missing references) //IL_0abf: Unknown result type (might be due to invalid IL or missing references) //IL_0ace: Unknown result type (might be due to invalid IL or missing references) //IL_0add: Unknown result type (might be due to invalid IL or missing references) //IL_0aec: Unknown result type (might be due to invalid IL or missing references) //IL_0afb: Unknown result type (might be due to invalid IL or missing references) //IL_0c8c: Unknown result type (might be due to invalid IL or missing references) //IL_0c99: Unknown result type (might be due to invalid IL or missing references) //IL_0cc6: Unknown result type (might be due to invalid IL or missing references) //IL_0cd0: Expected O, but got Unknown //IL_0d0d: Unknown result type (might be due to invalid IL or missing references) //IL_0d12: Unknown result type (might be due to invalid IL or missing references) Transform val = uiRoot.Find("GK2PlusModMenuRoot"); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } Sprite val2 = FindSprite("comm-frame_1-border"); Sprite val3 = FindSprite("titlescreen-menu-bg"); Sprite val4 = FindSprite("widget_perks-text_decor-drk_1"); Sprite val5 = FindSprite("comm-btn-simple_red-active"); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val5 == (Object)null) { throw new InvalidOperationException("Required native GK2 window/button sprites are not loaded."); } GameObject val6 = new GameObject("GK2PlusModMenuRoot", new Type[1] { typeof(RectTransform) }); val6.transform.SetParent(uiRoot, false); val6.transform.SetAsLastSibling(); RectTransform component = val6.GetComponent<RectTransform>(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; _menuRoot = val6; Canvas val7 = val6.AddComponent<Canvas>(); val7.overrideSorting = true; val7.sortingOrder = 30000; if ((Object)(object)val6.GetComponent<GraphicRaycaster>() == (Object)null) { val6.AddComponent<GraphicRaycaster>(); } GameObject obj = CreateImage(val6.transform, "Dimmer", null, (Type)0, Vector2.zero, Vector2.one, new Vector2(0.5f, 0.5f), Vector2.zero, Vector2.zero); Image component2 = obj.GetComponent<Image>(); ((Graphic)component2).color = new Color(0.03f, 0.01f, 0.03f, 0.18f); ((Graphic)component2).raycastTarget = true; obj.transform.SetAsFirstSibling(); GameObject val8 = new GameObject("Window", new Type[1] { typeof(RectTransform) }); val8.transform.SetParent(val6.transform, false); val8.transform.SetAsLastSibling(); RectTransform component3 = val8.GetComponent<RectTransform>(); component3.anchorMin = new Vector2(0.5f, 0.5f); component3.anchorMax = new Vector2(0.5f, 0.5f); component3.pivot = new Vector2(0.5f, 0.5f); component3.anchoredPosition = Vector2.zero; component3.sizeDelta = new Vector2(440f, 300f); ((Graphic)CreateImage(val8.transform, "SolidBacking", null, (Type)0, Vector2.zero, Vector2.one, new Vector2(0.5f, 0.5f), Vector2.zero, Vector2.zero).GetComponent<Image>()).color = new Color(0.24f, 0.05f, 0.13f, 0.99f); ((Graphic)CreateStretchImage(val8.transform, "Background", val3, (Type)1, new Vector2(-3f, -3f), new Vector2(3f, 3f)).GetComponent<Image>()).color = new Color(1f, 1f, 1f, 0.98f); CreateStretchImage(val8.transform, "Frame", val2, (Type)1, Vector2.zero, Vector2.zero); Vector4 val9 = default(Vector4); ((Vector4)(ref val9))..ctor(9f, 7f, 9f, 7f); GameObject val10 = new GameObject("ContentSafeArea", new Type[1] { typeof(RectTransform) }); val10.transform.SetParent(val8.transform, false); RectTransform component4 = val10.GetComponent<RectTransform>(); component4.anchorMin = Vector2.zero; component4.anchorMax = Vector2.one; component4.pivot = new Vector2(0.5f, 0.5f); component4.offsetMin = new Vector2(val9.x, val9.y); component4.offsetMax = new Vector2(0f - val9.z, 0f - val9.w); ((Transform)component4).localScale = Vector3.one; ManualLogSource logger = _logger; if (logger != null) { string text = $"spriteBorder={val2.border}, "; string text2 = $"visualInsetsUi(L,B,R,T)={val9}, "; Rect rect = component4.rect; logger.LogInfo((object)("GK2+ frame safe area: " + text + text2 + $"safeSize={((Rect)(ref rect)).size}")); } CreateNativeTitleText(buttonLabelTemplate, val8.transform, "GK2+ Mod Menu", new Vector2(0f, -16f), new Vector2(210f, 20f), 0.72f); CreateBodyText(bodyTemplate, val8.transform, "VersionText", "v0.1.0", new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(18f, -17f), new Vector2(64f, 14f), 8f, "Left"); CreateBodyText(bodyTemplate, val8.transform, "HeaderF2Hint", "F2 Toggle", new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-94f, -17f), new Vector2(58f, 14f), 8f, "Center"); CreateBodyText(bodyTemplate, val8.transform, "HeaderEscHint", "ESC Close", new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-18f, -17f), new Vector2(62f, 14f), 8f, "Center"); if ((Object)(object)val4 != (Object)null) { CreateFixedImage(val8.transform, "HeaderDivider", val4, (Type)1, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -35f), new Vector2(390f, 5f)); } float num = 54f; float num2 = 18f; float num3 = 2f; float num4 = (0f - ((float)Tabs.Length * num + (float)(Tabs.Length - 1) * num3)) / 2f + num / 2f; for (int i = 0; i < Tabs.Length; i++) { string tab = Tabs[i]; float num5 = num4 + (float)i * (num + num3); GameObject val11 = CreateActionButton(buttonLabelTemplate, val8.transform, val5, tab, new Vector2(num5, -52f), new Vector2(num, num2)); ((UnityEvent)val11.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { SetActiveTab(tab); }); _tabButtons[tab] = val11; } if ((Object)(object)val4 != (Object)null) { CreateFixedImage(val8.transform, "TabDivider", val4, (Type)1, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -69f), new Vector2(390f, 5f)); } GameObject val12 = new GameObject("Content", new Type[1] { typeof(RectTransform) }); val12.transform.SetParent(val8.transform, false); RectTransform component5 = val12.GetComponent<RectTransform>(); component5.anchorMin = new Vector2(0.5f, 1f); component5.anchorMax = new Vector2(0.5f, 1f); component5.pivot = new Vector2(0.5f, 1f); component5.anchoredPosition = new Vector2(0f, -77f); component5.sizeDelta = new Vector2(392f, 176f); Image obj2 = val12.AddComponent<Image>(); ((Graphic)obj2).color = new Color(0.12f, 0.02f, 0.07f, 0.86f); ((Graphic)obj2).raycastTarget = false; _contentRoot = val12; _menuButtonLabelTemplate = buttonLabelTemplate; _menuButtonSprite = val5; _pageTitle = CreateNativeTitleText(buttonLabelTemplate, val12.transform, "General", new Vector2(0f, -13f), new Vector2(190f, 20f), 0.62f); _pageText = CreateBodyText(bodyTemplate, val12.transform, "PageText", "", new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -40f), new Vector2(350f, 102f), 10f, "Center"); Component component6 = FindTmp(_pageText); SetProperty(component6, "characterSpacing", 2.45f); SetProperty(component6, "wordSpacing", 1.25f); _githubButton = CreateActionButton(buttonLabelTemplate, val12.transform, val5, "GitHub", new Vector2(-92f, -142f), new Vector2(78f, 20f)); ButtonClickedEvent onClick = _githubButton.GetComponent<Button>().onClick; object obj3 = <>c.<>9__25_0; if (obj3 == null) { UnityAction val13 = delegate { Application.OpenURL("https://github.com/duhhbzz/GK2Plus"); }; <>c.<>9__25_0 = val13; obj3 = (object)val13; } ((UnityEvent)onClick).AddListener((UnityAction)obj3); _nexusButton = CreateActionButton(buttonLabelTemplate, val12.transform, val5, ProjectLinks.HasNexusUrl ? "Nexus Mods" : "Nexus Soon", new Vector2(0f, -142f), new Vector2(92f, 20f)); Button component7 = _nexusButton.GetComponent<Button>(); ((Selectable)component7).interactable = ProjectLinks.HasNexusUrl; if (ProjectLinks.HasNexusUrl) { ButtonClickedEvent onClick2 = component7.onClick; object obj4 = <>c.<>9__25_1; if (obj4 == null) { UnityAction val14 = delegate { Application.OpenURL(""); }; <>c.<>9__25_1 = val14; obj4 = (object)val14; } ((UnityEvent)onClick2).AddListener((UnityAction)obj4); } _bugButton = CreateActionButton(buttonLabelTemplate, val12.transform, val5, "Report Bug", new Vector2(100f, -142f), new Vector2(92f, 20f)); ButtonClickedEvent onClick3 = _bugButton.GetComponent<Button>().onClick; object obj5 = <>c.<>9__25_2; if (obj5 == null) { UnityAction val15 = delegate { Application.OpenURL("https://github.com/duhhbzz/GK2Plus/issues/new"); }; <>c.<>9__25_2 = val15; obj5 = (object)val15; } ((UnityEvent)onClick3).AddListener((UnityAction)obj5); BuildRegisteredActionButtons(); if ((Object)(object)val4 != (Object)null) { CreateFixedImage(val8.transform, "FooterDivider", val4, (Type)1, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 36f), new Vector2(390f, 5f)); } GameObject val16 = CreateActionButton(buttonLabelTemplate, val10.transform, val5, "Close", Vector2.zero, new Vector2(72f, 20f)); RectTransform component8 = val16.GetComponent<RectTransform>(); component8.SetInsetAndSizeFromParentEdge((Edge)1, 4f, 72f); component8.SetInsetAndSizeFromParentEdge((Edge)3, 4f, 20f); ((Transform)component8).localScale = Vector3.one; ((Transform)component8).localRotation = Quaternion.identity; Vector3[] array = (Vector3[])(object)new Vector3[4]; Vector3[] array2 = (Vector3[])(object)new Vector3[4]; Vector3[] array3 = (Vector3[])(object)new Vector3[4]; component3.GetWorldCorners(array); component4.GetWorldCorners(array2); component8.GetWorldCorners(array3); float num6 = array2[2].x - array3[2].x; float num7 = array3[0].y - array2[0].y; float num8 = array[2].x - array3[2].x; float num9 = array3[0].y - array[0].y; ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogInfo((object)("GK2+ Close safe dock: " + $"safeRightGapPx={num6:0.##}, " + $"safeBottomGapPx={num7:0.##}, " + $"totalRightGapPx={num8:0.##}, " + $"totalBottomGapPx={num9:0.##}, " + $"buttonBL={array3[0]}, buttonTR={array3[2]}")); } ((UnityEvent)val16.GetComponent<Button>().onClick).AddListener(new UnityAction(HideMenu)); SetActiveTab("General"); _menuRoot.SetActive(false); ManualLogSource logger3 = _logger; if (logger3 != null) { string name = ((Object)uiRoot).name; Scene scene = ((Component)uiRoot).gameObject.scene; logger3.LogInfo((object)("GK2+ mod menu host attached to '" + name + "' " + $"(scene='{((Scene)(ref scene)).name}', sortingOrder={val7.sortingOrder}).")); } } private void BuildRegisteredActionButtons() { //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Expected O, but got Unknown foreach (GameObject value in _registeredActionButtons.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } _registeredActionButtons.Clear(); if ((Object)(object)_contentRoot == (Object)null || (Object)(object)_menuButtonLabelTemplate == (Object)null || (Object)(object)_menuButtonSprite == (Object)null) { return; } foreach (IGrouping<string, GK2MenuAction> item in from gK2MenuAction in _registeredMenuActions group gK2MenuAction by gK2MenuAction.Tab) { List<GK2MenuAction> list = item.ToList(); int count = list.Count; if (count == 0) { continue; } for (int num = 0; num < count; num++) { GK2MenuAction action = list[num]; int num2 = num / 4; int num3 = num % 4; int num4 = num2 * 4; int num5 = Mathf.Min(4, count - num4); float num6 = Mathf.Min(108f, (350f - (float)(num5 - 1) * 6f) / (float)num5); float num7 = (0f - ((float)num5 * num6 + (float)(num5 - 1) * 6f)) / 2f + num6 / 2f + (float)num3 * (num6 + 6f); float num8 = -92f - (float)num2 * 27f; GameObject val = CreateActionButton(_menuButtonLabelTemplate, _contentRoot.transform, _menuButtonSprite, action.Label, new Vector2(num7, num8), new Vector2(num6, 20f)); ((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { if (!action.CanExecute()) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("GK2+ menu action '" + action.Id + "' is currently unavailable.")); } RefreshRegisteredActionButtons(); } else { try { action.Execute(); } catch (Exception arg) { ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogError((object)$"GK2+ menu action '{action.Id}' failed: {arg}"); } } RefreshRegisteredActionButtons(); } }); _registeredActionButtons[action] = val; } } RefreshRegisteredActionButtons(); } private void RefreshRegisteredActionButtons() { foreach (KeyValuePair<GK2MenuAction, GameObject> registeredActionButton in _registeredActionButtons) { GK2MenuAction key = registeredActionButton.Key; GameObject value = registeredActionButton.Value; if ((Object)(object)value == (Object)null) { continue; } bool flag = string.Equals(key.Tab, _activeTab, StringComparison.OrdinalIgnoreCase); value.SetActive(flag); if (flag) { Button component = value.GetComponent<Button>(); if ((Object)(object)component != (Object)null) { ((Selectable)component).interactable = key.CanExecute(); } } } } private GameObject CreateActionButton(GameObject textTemplate, Transform parent, Sprite sprite, string text, Vector2 anchoredPosition, Vector2 size) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_011c: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(text + "Button", new Type[4] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 1f); component.anchorMax = new Vector2(0.5f, 1f); component.pivot = new Vector2(0.5f, 1f); component.anchoredPosition = anchoredPosition; component.sizeDelta = size; Image component2 = val.GetComponent<Image>(); component2.sprite = sprite; component2.type = (Type)1; ((Graphic)component2).raycastTarget = true; Button component3 = val.GetComponent<Button>(); ((Selectable)component3).targetGraphic = (Graphic)(object)component2; ((Selectable)component3).transition = (Transition)1; Navigation navigation = ((Selectable)component3).navigation; ((Navigation)(ref navigation)).mode = (Mode)3; ((Selectable)component3).navigation = navigation; ColorBlock colors = ((Selectable)component3).colors; ((ColorBlock)(ref colors)).normalColor = Color.white; ((ColorBlock)(ref colors)).highlightedColor = new Color(1f, 1f, 1f, 0.92f); ((ColorBlock)(ref colors)).pressedColor = new Color(0.82f, 0.82f, 0.82f, 0.92f); ((ColorBlock)(ref colors)).selectedColor = Color.white; ((ColorBlock)(ref colors)).disabledColor = new Color(0.58f, 0.58f, 0.58f, 0.6f); ((ColorBlock)(ref colors)).fadeDuration = 0.05f; ((Selectable)component3).colors = colors; CreateNativeButtonLabel(textTemplate, val.transform, text, 0.55f); return val; } private GameObject CreateNativeButtonLabel(GameObject template, Transform parent, string text, float scale) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(template, parent, false); ((Object)val).name = "Label"; val.SetActive(true); StripLocalization(val); RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = Vector2.zero; ((Transform)component).localRotation = Quaternion.identity; ((Transform)component).localScale = new Vector3(scale, scale, 1f); if ((Object)(object)val2 != (Object)null) { Rect rect = val2.rect; float num = Mathf.Max(1f, ((Rect)(ref rect)).width / scale); rect = val2.rect; float num2 = Mathf.Max(1f, ((Rect)(ref rect)).height / scale); component.sizeDelta = new Vector2(num, num2); } Component obj = FindTmp(val); if ((Object)(object)obj == (Object)null) { throw new InvalidOperationException("Native button label template has no TextMeshProUGUI."); } SetProperty(obj, "text", text); SetProperty(obj, "enableAutoSizing", false); SetProperty(obj, "characterSpacing", 0.75f); SetProperty(obj, "wordSpacing", 0.3f); TrySetEnumProperty(obj, "alignment", "Center"); return val; } private void SetActiveTab(string tabName) { //IL_005e: 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) _activeTab = tabName; foreach (KeyValuePair<string, GameObject> tabButton in _tabButtons) { Image component = tabButton.Value.GetComponent<Image>(); if (!((Object)(object)component == (Object)null)) { ((Graphic)component).color = (Color)((tabButton.Key == tabName) ? Color.white : new Color(0.72f, 0.72f, 0.78f, 0.88f)); } } SetText(_pageTitle, tabName); SetText(_pageText, GetPlaceholderText(tabName)); LayoutPageTextForTab(tabName); bool active = tabName == "More"; if ((Object)(object)_githubButton != (Object)null) { _githubButton.SetActive(active); } if ((Object)(object)_nexusButton != (Object)null) { _nexusButton.SetActive(active); } if ((Object)(object)_bugButton != (Object)null) { _bugButton.SetActive(active); } RefreshRegisteredActionButtons(); } private void LayoutPageTextForTab(string tab) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_pageText == (Object)null)) { RectTransform component = _pageText.GetComponent<RectTransform>(); if (!((Object)(object)component == (Object)null)) { bool flag = string.Equals(tab, "Cheats", StringComparison.OrdinalIgnoreCase); component.anchoredPosition = (flag ? new Vector2(0f, -40f) : new Vector2(0f, -40f)); component.sizeDelta = (flag ? new Vector2(350f, 42f) : new Vector2(350f, 102f)); } } } private string GetPlaceholderText(string tab) { string text = (ProjectLinks.HasNexusUrl ? "Follow development on GitHub or visit the GK2+ page on Nexus Mods." : "Follow development on GitHub. The Nexus Mods page is coming soon."); switch (tab) { case "General": return "Coming Soon\n\nGK2+ is still under active development.\nThis page will contain global mod settings, UI options, and hotkeys.\n\n" + text; case "Inventory": return "Coming Soon\n\nPlanned: unified storage, shared chest resources, search/filtering,\nand stack-size quality-of-life options.\n\n" + text; case "Crafting": return "Coming Soon\n\nPlanned: recipe pinning, resource-pull behavior, and crafting QoL.\n\n" + text; case "Farming": return "Coming Soon\n\nPlanned: continuous planting, seed-selection behavior, and farming QoL.\n\n" + text; case "Zombies": return "Coming Soon\n\nPlanned: a central zombie manager, stats overview, and equipment tools.\n\n" + text; case "Cheats": { if (_tabNotices.TryGetValue("Cheats", out var value)) { string text2 = value(); if (!string.IsNullOrWhiteSpace(text2)) { return text2; } } return "Money cheats use a save-safety checkpoint.\nHealth and stamina refills use native player systems."; } case "More": return "GK2+ Project Links\n\nGitHub: source, development progress, and releases.\n" + (ProjectLinks.HasNexusUrl ? "Nexus Mods: public mod page and downloads.\n" : "Nexus Mods: public mod page coming soon.\n") + "Report Bug: opens a new GitHub issue for GK2+.\n\nQuest/map tools, compatibility, diagnostics, and About will live here."; default: return tab; } } public void RefreshActiveTab() { if (_built && (Object)(object)_pageTitle != (Object)null && (Object)(object)_pageText != (Object)null) { SetActiveTab(_activeTab); } } public void ToggleMenu() { if (!_built || (Object)(object)_menuRoot == (Object)null) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)"GK2+ F2 toggle ignored because the menu shell is not ready."); } return; } bool flag = !_menuRoot.activeSelf; _menuRoot.SetActive(flag); if (flag) { _menuRoot.transform.SetAsLastSibling(); SetActiveTab(_activeTab); } ManualLogSource logger2 = _logger; if (logger2 != null) { string[] obj = new string[7] { "GK2+ mod menu ", flag ? "shown" : "hidden", " in ", DetectContext(), " context; parent='", null, null }; Transform parent = _menuRoot.transform.parent; obj[5] = ((parent != null) ? ((Object)parent).name : null) ?? "<none>"; obj[6] = "'."; logger2.LogInfo((object)string.Concat(obj)); } } public void ShowMenu() { if (_built && !((Object)(object)_menuRoot == (Object)null)) { _menuRoot.SetActive(true); _menuRoot.transform.SetAsLastSibling(); SetActiveTab(_activeTab); } } public void HideMenu() { if ((Object)(object)_menuRoot != (Object)null) { _menuRoot.SetActive(false); } } public void ShutdownController() { HideMenu(); CleanupPartialMenu(); if ((Object)(object)this != (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } } private static string DetectContext() { MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>(); foreach (MonoBehaviour val in array) { if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "UIMainMenuWindow" && ((Component)val).gameObject.activeInHierarchy) { return "MainMenu"; } } return "Gameplay"; } private void CleanupPartialMenu() { if ((Object)(object)_menuRoot != (Object)null) { Object.Destroy((Object)(object)_menuRoot); _menuRoot = null; } _tabButtons.Clear(); _registeredActionButtons.Clear(); _tabNotices.Clear(); _pageTitle = null; _pageText = null; _githubButton = null; _nexusButton = null; _bugButton = null; _contentRoot = null; _menuButtonLabelTemplate = null; _menuButtonSprite = null; _built = false; } private GameObject CreateNativeTitleText(GameObject template, Transform parent, string text, Vector2 anchoredPosition, Vector2 size, float scale) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(template, parent, false); ((Object)val).name = "NativeTitle"; val.SetActive(true); StripLocalization(val); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 1f); component.anchorMax = new Vector2(0.5f, 1f); component.pivot = new Vector2(0.5f, 1f); component.anchoredPosition = anchoredPosition; component.sizeDelta = size; ((Transform)component).localScale = new Vector3(scale, scale, 1f); Component component2 = FindTmp(val); SetProperty(component2, "text", text); TrySetEnumProperty(component2, "alignment", "Center"); return val; } private GameObject CreateBodyText(GameObject template, Transform parent, string name, string text, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 anchoredPosition, Vector2 size, float fontSize, string alignment) { //IL_0069: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(template, parent, false); ((Object)val).name = name; val.SetActive(true); StripLocalization(val); Component[] components = val.GetComponents<Component>(); foreach (Component val2 in components) { if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().Name == "LazyButtonTipsStr") { Object.Destroy((Object)(object)val2); } } RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = anchorMin; component.anchorMax = anchorMax; component.pivot = pivot; ((Transform)component).localScale = Vector3.one; ((Transform)component).localRotation = Quaternion.identity; if (anchorMin == Vector2.zero && anchorMax == Vector2.one && size == Vector2.zero) { component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; } else { component.anchoredPosition = anchoredPosition; component.sizeDelta = size; } Component component2 = FindTmp(val); SetProperty(component2, "text", text); SetProperty(component2, "enableAutoSizing", false); SetProperty(component2, "fontSize", fontSize); SetProperty(component2, "fontSizeMin", fontSize); SetProperty(component2, "fontSizeMax", fontSize); SetProperty(component2, "characterSpacing", 1.45f); SetProperty(component2, "wordSpacing", 0.75f); SetProperty(component2, "lineSpacing", 2f); SetProperty(component2, "paragraphSpacing", 2f); SetProperty(component2, "margin", Vector4.zero); SetProperty(component2, "color", (object)new Color(1f, 0.84f, 0.48f, 1f)); TrySetEnumProperty(component2, "fontStyle", "Normal"); TrySetEnumProperty(component2, "fontWeight", "Regular"); TrySetEnumProperty(component2, "alignment", alignment); return val; } private GameObject CreateImage(Transform parent, string name, Sprite sprite, Type type, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 anchoredPosition, Vector2 size) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = anchorMin; component.anchorMax = anchorMax; component.pivot = pivot; if (anchorMin == Vector2.zero && anchorMax == Vector2.one && size == Vector2.zero) { component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; } else { component.anchoredPosition = anchoredPosition; component.sizeDelta = size; } Image component2 = val.GetComponent<Image>(); component2.sprite = sprite; component2.type = type; ((Graphic)component2).raycastTarget = false; return val; } private GameObject CreateStretchImage(Transform parent, string name, Sprite sprite, Type type, Vector2 offsetMin, Vector2 offsetMax) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) GameObject obj = CreateImage(parent, name, sprite, type, Vector2.zero, Vector2.one, new Vector2(0.5f, 0.5f), Vector2.zero, Vector2.zero); RectTransform component = obj.GetComponent<RectTransform>(); component.offsetMin = offsetMin; component.offsetMax = offsetMax; return obj; } private GameObject CreateFixedImage(Transform parent, string name, Sprite sprite, Type type, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 anchoredPosition, Vector2 size) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) return CreateImage(parent, name, sprite, type, anchorMin, anchorMax, pivot, anchoredPosition, size); } private void StripLocalization(GameObject obj) { Component[] components = obj.GetComponents<Component>(); foreach (Component val in components) { if (!((Object)(object)val == (Object)null)) { string name = ((object)val).GetType().Name; if (name == "LocalizedLabel" || name == "LocalizedVerticalOffset") { Object.Destroy((Object)(object)val); } } } } private void SetText(GameObject obj, string text) { Component val = FindTmp(obj); if ((Object)(object)val != (Object)null) { SetProperty(val, "text", text); } } private static Component FindTmp(GameObject obj) { if ((Object)(object)obj == (Object)null) { return null; } return ((IEnumerable<Component>)obj.GetComponents<Component>()).FirstOrDefault((Func<Component, bool>)((Component component) => (Object)(object)component != (Object)null && ((object)component).GetType().Name == "TextMeshProUGUI")); } private static Sprite FindSprite(string name) { return ((IEnumerable<Sprite>)Resources.FindObjectsOfTypeAll<Sprite>()).FirstOrDefault((Func<Sprite, bool>)((Sprite sprite) => (Object)(object)sprite != (Object)null && string.Equals(((Object)sprite).name, name, StringComparison.Ordinal))); } private static void TrySetEnumProperty(Component component, string propertyName, string enumValue) { if ((Object)(object)component == (Object)null) { return; } PropertyInfo property = ((object)component).GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null || !property.CanWrite || !property.PropertyType.IsEnum) { return; } try { object value = Enum.Parse(property.PropertyType, enumValue); property.SetValue(component, value, null); } catch { } } private static void SetProperty(Component component, string propertyName, object value) { if (!((Object)(object)component == (Object)null)) { PropertyInfo property = ((object)component).GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { property.SetValue(component, value, null); } } } } } namespace GK2Plus.Framework.Saves { internal sealed class GK2SaveService : GK2ServiceBase { private const string SaveDataExtension = ".dat"; private const string SaveInfoExtension = ".info"; private const string CheatTaintExtension = ".gk2plus-cheat-taint"; private const string CheatTaintBackupFileName = "GK2Plus-CheatTaint.txt"; private const int MaxBackupsPerSlot = 5; private bool _initialized; private bool _saveLoading; private bool _saveWriting; private long _saveGeneration; private long _checkpointGeneration = -1L; private string _checkpointSlotName; private string _checkpointBackupDirectory; public override string Name => "Saves"; public string BackupRootPath => Path.Combine(Paths.ConfigPath, "GK2Plus", "SaveBackups"); public bool IsSaveOperationInProgress { get { if (!_saveLoading) { return _saveWriting; } return true; } } public int BackupRetentionPerSlot => 5; public bool IsActiveSaveCheatTainted { get { try { MainGame instance = MainGame.Instance; SaveSlotData val = ((instance != null) ? instance.SaveSlotData : null); return val != null && !string.IsNullOrWhiteSpace(val.slotName) && IsSlotCheatTainted(val.slotName); } catch { return false; } } } public bool HasLoadedSave { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 try { return (Object)(object)MainGame.Instance != (Object)null && (int)MainGame.Instance.gameState == 1 && MainGame.Instance.GameSave != null && MainGame.Instance.SaveSlotData != null && !string.IsNullOrWhiteSpace(MainGame.Instance.SaveSlotData.slotName); } catch { return false; } } } public GK2SaveService(ManualLogSource logger) : base(logger) { } public override void Initialize() { base.Initialize(); if (!_initialized) { SaveSystem.OnSaveLoadingStarted += OnSaveLoadingStarted; SaveSystem.OnSaveLoadingEnded += OnSaveLoadingEnded; SaveSystem.OnSaveWriteStarted += OnSaveWriteStarted; SaveSystem.OnSaveWriteStartedInstant += OnSaveWriteStartedInstant; SaveSystem.OnSaveWriteEnded += OnSaveWriteEnded; _initialized = true; base.Logger.LogInfo((object)("GK2+ save safety ready. Persistent mutations use on-demand " + $"checkpoints with a {5}-backup per-slot retention cap.")); } } public override void Shutdown() { if (_initialized) { SaveSystem.OnSaveLoadingStarted -= OnSaveLoadingStarted; SaveSystem.OnSaveLoadingEnded -= OnSaveLoadingEnded; SaveSystem.OnSaveWriteStarted -= OnSaveWriteStarted; SaveSystem.OnSaveWriteStartedInstant -= OnSaveWriteStartedInstant; SaveSystem.OnSaveWriteEnded -= OnSaveWriteEnded; _initialized = false; } _saveLoading = false; _saveWriting = false; ClearCheckpoint(); base.Shutdown(); } public bool TryPrepareMutation(string operationName, SaveMutationRisk risk, out SaveMutationContext context) { context = null; if (string.IsNullOrWhiteSpace(operationName)) { base.Logger.LogError((object)"GK2+ save safety rejected an unnamed mutation."); return false; } if (!TryGetActiveSlot(out var slotData, out var error)) { base.Logger.LogWarning((object)("GK2+ save safety blocked '" + operationName + "': " + error)); return false; } if (IsSaveOperationInProgress) { base.Logger.LogWarning((object)("GK2+ save safety blocked '" + operationName + "' because GK2 is currently loading or writing a save.")); return false; } string text = null; if (risk >= SaveMutationRisk.Moderate) { if (!TryGetOrCreateCheckpoint(operationName, slotData, out var result)) { base.Logger.LogError((object)("GK2+ save safety blocked '" + operationName + "' because the pre-mutation checkpoint failed: " + result.Error)); return false; } text = result.BackupDirectory; } context = new SaveMutationContext(operationName, risk, slotData.slotName, DateTime.UtcNow, text); base.Logger.LogInfo((object)("GK2+ mutation prepared: operation='" + operationName + "', " + $"risk={risk}, slot='{slotData.slotName}', " + "backup=" + (text ?? "<not required>") + ".")); return true; } public bool TryRunProtectedMutation(string operationName, SaveMutationRisk risk, Action mutation, Func<bool> validator = null) { if (mutation == null) { throw new ArgumentNullException("mutation"); } if (!TryPrepareMutation(operationName, risk, out var context)) { return false; } try { mutation(); if (validator != null && !validator()) { base.Logger.LogError((object)("GK2+ mutation validation failed: operation='" + operationName + "', " + string.Format("risk={0}, backup={1}.", risk, context.BackupDirectory ?? "<none>"))); return false; } base.Logger.LogInfo((object)("GK2+ mutation completed: operation='" + operationName + "', " + $"risk={risk}, slot='{context.SlotName}'.")); return true; } catch (Exception arg) { base.Logger.LogError((object)("GK2+ mutation failed: operation='" + operationName + "', " + string.Format("risk={0}, backup={1}, ", risk, context.BackupDirectory ?? "<none>") + $"exception={arg}")); return false; } } public bool TryManualSave(out string error) { error = null; if (!TryGetActiveSlot(out var slotData, out error)) { return false; } if (IsSaveOperationInProgress) { error = "GK2 is already loading or writing a save."; return false; } MainGame instance = MainGame.Instance; GameSave val = ((instance != null) ? instance.GameSave : null); if (val == null) { error = "The active GameSave is unavailable."; return false; } bool callbackReceived = false; bool success = false; try { base.Logger.LogInfo((object)("GK2+ manual save requested for slot '" + slotData.slotName + "'.")); SaveSystem.Save(slotData, val, (Action)delegate { callbackReceived = true; success = true; }, (Action)delegate { callbackReceived = true; success = false; }, true, (Action<SaveSlotData, GameSave>)null); if (!callbackReceived) { error = "GK2 SaveSystem returned without a completion callback."; base.Logger.LogError((object)("GK2+ manual save failed: " + error)); return false; } if (!success) { error = "GK2 SaveSystem reported that the save failed."; base.Logger.LogError((object)("GK2+ manual save failed: " + error)); return false; } base.Logger.LogInfo((object)("GK2+ manual save completed for slot '" + slotData.slotName + "'.")); return true; } catch (Exception ex) { error = ex.Message; base.Logger.LogError((object)$"GK2+ manual save threw an unexpected exception: {ex}"); return false; } } public bool TryGetLastSaveDateTime(out DateTime savedAt) { savedAt = default(DateTime); if (!TryGetActiveSlot(out var slotData, out var _)) { return false; } try { savedAt = slotData.GetSaveDateTime(); return savedAt != default(DateTime); } catch { savedAt = default(DateTime); return false; } } public bool TryMarkActiveSaveCheatTainted(string cheatId, out string error) { error = null; if (!TryGetActiveSlot(out var slotData, out error)) { return false; } if (IsSaveOperationInProgress) { error = "GK2 is currently loading or writing a save."; return false; } try { string cheatTaintPath = GetCheatTaintPath(slotData.slotName); if (!File.Exists(cheatTaintPath)) { WriteCheatTaintMarker(cheatTaintPath, slotData.slotName, cheatId); } if (!TryMarkExistingBackupsCheatTainted(slotData.slotName, cheatTaintPath, out error)) { base.Logger.LogError((object)("GK2+ cheat taint was written for slot '" + slotData.slotName + "', but one or more existing backups could not be marked: " + error)); return false; } base.Logger.LogWarning((object)("GK2+ cheat taint active for slot '" + slotData.slotName + "'. Platform achievements will be blocked while this save is loaded.")); return true; } catch (Exception ex) { error = ex.Message; base.Logger.LogError((object)$"GK2+ failed to mark the active save as cheat-tainted: {ex}"); return false; } } public bool IsSlotCheatTainted(string slotName) { if (string.IsNullOrWhiteSpace(slotName)) { return false; } try { return File.Exists(GetCheatTaintPath(slotName)); } catch { return false; } } public bool TryCreateBackup(string reason, out SaveBackupResult result) { result = null; if (!TryGetActiveSlot(out var slotData, out var error)) { result = new SaveBackupResult(success: false, null, null, error); return false; } if (IsSaveOperationInProgress) { error = "GK2 is currently loading or writing a save."; result = new SaveBackupResult(success: false, slotData.slotName, null, error); return false; } return TryCreateBackupCore(reason, slotData, out result); } private bool TryGetOrCreateCheckpoint(string reason, SaveSlotData slotData, out SaveBackupResult result) { if (_checkpointGeneration == _saveGeneration && string.Equals(_checkpointSlotName, slotData.slotName, StringComparison.Ordinal) && !string.IsNullOrEmpty(_checkpointBackupDirectory) && Directory.Exists(_checkpointBackupDirectory)) { result = new SaveBackupResult(success: true, slotData.slotName, _checkpointBackupDirectory, null); base.Logger.LogDebug((object)("GK2+ save safety reused checkpoint for slot " + $"'{slotData.slotName}' generation {_saveGeneration}.")); return true; } if (!TryCreateBackupCore(reason, slotData, out result)) { return false; } _checkpointGeneration = _saveGeneration; _checkpointSlotName = slotData.slotName; _checkpointBackupDirectory = result.BackupDirectory; return true; } private bool TryCreateBackupCore(string reason, SaveSlotData slotData, out SaveBackupResult result) { result = null; string saveFolder = SaveSystem.SaveFolder; string text = Path.Combine(saveFolder, slotData.slotName + ".dat"); string text2 = Path.Combine(saveFolder, slotData.slotName + ".info"); if (!File.Exists(text) || !File.Exists(text2)) { string text3 = string.Join(", ", new string[2] { (!File.Exists(text)) ? Path.GetFileName(text) : null, (!File.Exists(text2)) ? Path.GetFileName(text2) : null }.Where((string value) => value != null)); string error = "Required active-slot file(s) are missing: " + text3 + ". Save folder: " + saveFolder; result = new SaveBackupResult(success: false, slotData.slotName, null, error); return false; } string path = SanitizePathPart(slotData.slotName, 64); string text4 = SanitizePathPart(string.IsNullOrWhiteSpace(reason) ? "manual" : reason, 48); string text5 = DateTime.UtcNow.ToString("yyyyMMdd-HHmmssfff"); string text6 = Path.Combine(BackupRootPath, path); string text7 = Path.Combine(text6, text5 + "_" + text4); string text8 = text7 + ".tmp"; try { Directory.CreateDirectory(text6); if (Directory.Exists(text8)) { Directory.Delete(text8, recursive: true); } Directory.CreateDirectory(text8); CopyStableFile(text, Path.Combine(text8, Path.GetFileName(text))); CopyStableFile(text2, Path.Combine(text8, Path.GetFileName(text2))); bool flag = IsSlotCheatTainted(slotData.slotName); if (flag) { CopyStableFile(GetCheatTaintPath(slotData.slotName), Path.Combine(text8, "GK2Plus-CheatTaint.txt")); } File.WriteAllText(Path.Combine(text8, "GK2Plus-Backup.txt"), BuildManifest(slotData.slotName, reason, saveFolder, text, text2, flag), Encoding.UTF8); Directory.Move(text8, text7); PruneOldBackups(text6, text7); result = new SaveBackupResult(success: true, slotData.slotName, text7, null); base.Logger.LogWarning((object)("GK2+ save backup created for slot '" + slotData.slotName + "': " + text7)); return true; } catch (Exception ex) { TryDeleteDirectory(text8); result = new SaveBackupResult(success: false, slotData.slotName, null, ex.Message); base.Logger.LogError((object)$"GK2+ failed to back up slot '{slotData.slotName}': {ex}"); return false; } } private static void PruneOldBackups(string slotBackupRoot, string protectedDirectory) { foreach (DirectoryInfo item in (from directory in new DirectoryInfo(slotBackupRoot).GetDirectories() where !directory.Name.EndsWith(".tmp", StringComparison.OrdinalIgnoreCase) select directory).OrderByDescending<DirectoryInfo, string>((DirectoryInfo directory) => directory.Name, StringComparer.Ordinal).ToArray().Skip(5)) { if (!string.Equals(item.FullName, protectedDirectory, StringComparison.OrdinalIgnoreCase)) { TryDeleteDirectory(item.FullName); } } } private bool TryGetActiveSlot(out SaveSlotData slotData, out string error) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 slotData = null; error = null; try { MainGame instance = MainGame.Instance; if ((Object)(object)instance == (Object)null) { error = "MainGame is not initialized."; return false; } if ((int)instance.gameState != 1) { error = "No gameplay save is currently loaded."; return false; } if (instance.GameSave == null) { error = "The active GameSave is unavailable."; return false; } slotData = instance.SaveSlotData; if (slotData == null || string.IsNullOrWhiteSpace(slotData.slotName)) { error = "The active save slot is unavailable."; slotData = null; return false; } return true; } catch (Exception ex) { error = "Failed to resolve the active save slot: " + ex.Message; slotData = null; return false; } } private static void CopyStableFile(string sourcePath, string destinationPath) { long length; using (FileStream fileStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { length = fileStream.Length; using FileStream fileStream2 = new FileStream(destinationPath, FileMode.CreateNew, FileAccess.Write, FileShare.None); fileStream.CopyTo(fileStream2); fileStream2.Flush(); } FileInfo fileInfo = new FileInfo(destinationPath); if (!fileInfo.Exists || fileInfo.Length != length) { throw new IOException("Backup verification failed for '" + Path.GetFileName(sourcePath) + "'. " + $"Expected {length} bytes, copied " + $"{(fileInfo.Exists ? fileInfo.Length : 0)} bytes."); } } private static string BuildManifest(string slotName, string reason, string saveFolder, string dataSource, string infoSource, bool cheatTainted) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("GK2+ Save Safety Backup"); stringBuilder.AppendLine("======================="); stringBuilder.AppendLine("GK2PlusVersion=0.1.0"); stringBuilder.AppendLine("CreatedUtc=" + DateTime.UtcNow.ToString("O")); stringBuilder.AppendLine("SlotName=" + slotName); stringBuilder.AppendLine("Reason=" + (reason ?? string.Empty)); stringBuilder.AppendLine("SourceSaveFolder=" + saveFolder); stringBuilder.AppendLine("DataFile=" + Path.GetFileName(dataSource)); stringBuilder.AppendLine("InfoFile=" + Path.GetFileName(infoSource)); stringBuilder.AppendLine("CheatTainted=" + cheatTainted); return stringBuilder.ToString(); } private string GetCheatTaintPath(string slotName) { return Path.Combine(SaveSystem.SaveFolder, slotName + ".gk2plus-cheat-taint"); } private void WriteCheatTaintMarker(string destinationPath, string slotName, string cheatId) { string text = destinationPath + ".tmp"; try { string contents = "GK2+ Cheat Taint\n================\nFormatVersion=1\nGK2PlusVersion=0.1.0\nSlotName=" + slotName + "\nFirstCheatId=" + (cheatId ?? string.Empty) + "\nFirstCheatUtc=" + DateTime.UtcNow.ToString("O") + "\nAchievementsDisabled=True\n"; File.WriteAllText(text, contents, Encoding.UTF8); if (File.Exists(destinationPath)) { File.Delete(text); } else { File.Move(text, destinationPath); } } finally { if (File.Exists(text)) { try { File.Delete(text); } catch { } } } } private bool TryMarkExistingBackupsCheatTainted(string slotName, string activeMarkerPath, out string error) { error = null; string path = SanitizePathPart(slotName, 64); string path2 = Path.Combine(BackupRootPath, path); if (!Directory.Exists(path2)) { return true; } try { DirectoryInfo[] directories = new DirectoryInfo(path2).GetDirectories(); foreach (DirectoryInfo directoryInfo in directories) { if (!directoryInfo.Name.EndsWith(".tmp", StringComparison.OrdinalIgnoreCase)) { string text = Path.Combine(directoryInfo.FullName, "GK2Plus-CheatTaint.txt"); if (!File.Exists(text)) { CopyStableFile(activeMarkerPath, text); } } } return true; } catch (Exception ex) { error = ex.Message; return false; } } private static string SanitizePathPart(string value, int maxLength) { if (string.IsNullOrWhiteSpace(value)) { return "unnamed"; } char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); StringBuilder stringBuilder = new StringBuilder(value.Length); foreach (char c in value) { if (invalidFileNameChars.Contains(c) || char.IsControl(c) || c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar) { stringBuilder.Append('_'); } else if (char.IsWhiteSpace(c)) { stringBuilder.Append('-'); } else { stringBuilder.Append(c); } if (stringBuilder.Length >= maxLength) { break; } } string text = stringBuilder.ToString().Trim(' ', '.', '-', '_'); if (!string.IsNullOrEmpty(text)) { return text; } return "unnamed"; } private static void TryDeleteDirectory(string path) { if (string.IsNullOrEmpty(path) || !Directory.Exists(path)) { return; } try { Directory.Delete(path, recursive: true); } catch { } } private void AdvanceSaveGeneration(string reason) { _saveGeneration++; ClearCheckpoint(); base.Logger.LogDebug((object)("GK2+ save checkpoint invalidated after " + reason + "; " + $"generation={_saveGeneration}.")); } private void ClearCheckpoint() { _checkpointGeneration = -1L; _checkpointSlotName = null; _checkpointBackupDirectory = null; } private void OnSaveLoadingStarted() { _saveLoading = true; ClearCheckpoint();