Decompiled source of HavensRespec v1.2.0
HavensRespec.dll
Decompiled 15 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.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using HavensRespec.Config; using HavensRespec.Patches; using HavensRespec.Services; using HavensRespec.UI; using Microsoft.CodeAnalysis; using SunhavenMods.Shared; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.UI; using Wish; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("HavensRespec")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+9c743905a6a1ecc5bdd54cfadfb24c03b53de21b")] [assembly: AssemblyProduct("HavensRespec")] [assembly: AssemblyTitle("HavensRespec")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 SunhavenMods.Shared { public static class ConfigFileHelper { public static ConfigFile CreateNamedConfig(string pluginGuid, string configFileName, Action<string> logWarning = null) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown string text = Path.Combine(Paths.ConfigPath, configFileName); string text2 = Path.Combine(Paths.ConfigPath, pluginGuid + ".cfg"); try { if (!File.Exists(text) && File.Exists(text2)) { File.Copy(text2, text); } } catch (Exception ex) { logWarning?.Invoke("[Config] Migration to " + configFileName + " failed: " + ex.Message); } return new ConfigFile(text, true); } public static bool ReplacePluginConfig(BaseUnityPlugin plugin, ConfigFile newConfig, Action<string> logWarning = null) { if ((Object)(object)plugin == (Object)null || newConfig == null) { return false; } try { Type typeFromHandle = typeof(BaseUnityPlugin); PropertyInfo property = typeFromHandle.GetProperty("Config", BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(plugin, newConfig, null); return true; } FieldInfo field = typeFromHandle.GetField("<Config>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { field.SetValue(plugin, newConfig); return true; } FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(ConfigFile)) { fieldInfo.SetValue(plugin, newConfig); return true; } } } catch (Exception ex) { logWarning?.Invoke("[Config] ReplacePluginConfig failed: " + ex.Message); } return false; } } public static class VersionChecker { public class VersionCheckResult { public bool Success { get; set; } public bool UpdateAvailable { get; set; } public string CurrentVersion { get; set; } public string LatestVersion { get; set; } public string ModName { get; set; } public string NexusUrl { get; set; } public string Changelog { get; set; } public string ErrorMessage { get; set; } } public class ModHealthSnapshot { public string PluginGuid { get; set; } public DateTime LastCheckUtc { get; set; } public int ExceptionCount { get; set; } public string LastError { get; set; } } private class VersionCheckRunner : MonoBehaviour { public void StartCheck(string pluginGuid, string currentVersion, Action<VersionCheckResult> onComplete) { ((MonoBehaviour)this).StartCoroutine(CheckVersionCoroutine(pluginGuid, currentVersion, onComplete)); } private IEnumerator CheckVersionCoroutine(string pluginGuid, string currentVersion, Action<VersionCheckResult> onComplete) { VersionCheckResult result = new VersionCheckResult { CurrentVersion = currentVersion }; UnityWebRequest www = UnityWebRequest.Get("https://azraelgodking.github.io/SunhavenMod/versions.json"); try { www.timeout = 10; yield return www.SendWebRequest(); if ((int)www.result == 2 || (int)www.result == 3) { result.Success = false; result.ErrorMessage = "Network error: " + www.error; RecordHealthError(pluginGuid, result.ErrorMessage); LogWarning(result.ErrorMessage); onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); yield break; } try { string text = www.downloadHandler.text; Match match = GetModPattern(pluginGuid).Match(text); if (!match.Success) { result.Success = false; result.ErrorMessage = "Mod '" + pluginGuid + "' not found in versions.json"; RecordHealthError(pluginGuid, result.ErrorMessage); LogWarning(result.ErrorMessage); onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); yield break; } string value = match.Groups[1].Value; result.LatestVersion = ExtractJsonString(value, "version"); result.ModName = ExtractJsonString(value, "name"); result.NexusUrl = ExtractJsonString(value, "nexus"); result.Changelog = ExtractJsonString(value, "changelog"); if (string.IsNullOrEmpty(result.LatestVersion)) { result.Success = false; result.ErrorMessage = "Could not parse version from response"; RecordHealthError(pluginGuid, result.ErrorMessage); LogWarning(result.ErrorMessage); onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); yield break; } result.Success = true; result.UpdateAvailable = CompareVersions(currentVersion, result.LatestVersion) < 0; if (result.UpdateAvailable) { Log("Update available for " + result.ModName + ": " + currentVersion + " -> " + result.LatestVersion); } else { Log(result.ModName + " is up to date (v" + currentVersion + ")"); } } catch (Exception ex) { result.Success = false; result.ErrorMessage = "Parse error: " + ex.Message; RecordHealthError(pluginGuid, result.ErrorMessage); LogError(result.ErrorMessage); } } finally { ((IDisposable)www)?.Dispose(); } onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); } private string ExtractJsonString(string json, string key) { Match match = ExtractFieldRegex.Match(json); while (match.Success) { if (string.Equals(match.Groups["key"].Value, key, StringComparison.Ordinal)) { return match.Groups["value"].Value; } match = match.NextMatch(); } return null; } } private const string VersionsUrl = "https://azraelgodking.github.io/SunhavenMod/versions.json"; private static ManualLogSource _logger; private static readonly Dictionary<string, ModHealthSnapshot> HealthByPluginGuid = new Dictionary<string, ModHealthSnapshot>(StringComparer.OrdinalIgnoreCase); private static readonly object HealthLock = new object(); private static readonly Dictionary<string, Regex> ModPatternCache = new Dictionary<string, Regex>(StringComparer.Ordinal); private static readonly object ModPatternCacheLock = new object(); private static readonly Regex ExtractFieldRegex = new Regex("\"(?<key>[^\"]+)\"\\s*:\\s*(?:\"(?<value>[^\"]*)\"|null)", RegexOptions.Compiled); public static void CheckForUpdate(string pluginGuid, string currentVersion, ManualLogSource logger = null, Action<VersionCheckResult> onComplete = null) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) _logger = logger; TouchHealth(pluginGuid); VersionCheckRunner versionCheckRunner = new GameObject("VersionChecker").AddComponent<VersionCheckRunner>(); Object.DontDestroyOnLoad((Object)(object)((Component)versionCheckRunner).gameObject); SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(((Component)versionCheckRunner).gameObject); versionCheckRunner.StartCheck(pluginGuid, currentVersion, onComplete); } public static ModHealthSnapshot GetHealthSnapshot(string pluginGuid) { if (string.IsNullOrWhiteSpace(pluginGuid)) { return null; } lock (HealthLock) { if (!HealthByPluginGuid.TryGetValue(pluginGuid, out var value)) { return null; } return new ModHealthSnapshot { PluginGuid = value.PluginGuid, LastCheckUtc = value.LastCheckUtc, ExceptionCount = value.ExceptionCount, LastError = value.LastError }; } } public static int CompareVersions(string v1, string v2) { if (string.IsNullOrEmpty(v1) || string.IsNullOrEmpty(v2)) { return 0; } v1 = v1.TrimStart('v', 'V'); v2 = v2.TrimStart('v', 'V'); string[] array = v1.Split(new char[1] { '.' }); string[] array2 = v2.Split(new char[1] { '.' }); int num = Math.Max(array.Length, array2.Length); for (int i = 0; i < num; i++) { int result; int num2 = ((i < array.Length && int.TryParse(array[i], out result)) ? result : 0); int result2; int num3 = ((i < array2.Length && int.TryParse(array2[i], out result2)) ? result2 : 0); if (num2 < num3) { return -1; } if (num2 > num3) { return 1; } } return 0; } internal static void Log(string message) { ManualLogSource logger = _logger; if (logger != null) { logger.LogInfo((object)("[VersionChecker] " + message)); } } internal static void LogWarning(string message) { ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)("[VersionChecker] " + message)); } } internal static void LogError(string message) { ManualLogSource logger = _logger; if (logger != null) { logger.LogError((object)("[VersionChecker] " + message)); } } private static void TouchHealth(string pluginGuid) { if (string.IsNullOrWhiteSpace(pluginGuid)) { return; } lock (HealthLock) { if (!HealthByPluginGuid.TryGetValue(pluginGuid, out var value)) { value = new ModHealthSnapshot { PluginGuid = pluginGuid }; HealthByPluginGuid[pluginGuid] = value; } value.LastCheckUtc = DateTime.UtcNow; } } private static void RecordHealthError(string pluginGuid, string errorMessage) { if (string.IsNullOrWhiteSpace(pluginGuid)) { return; } lock (HealthLock) { if (!HealthByPluginGuid.TryGetValue(pluginGuid, out var value)) { value = new ModHealthSnapshot { PluginGuid = pluginGuid }; HealthByPluginGuid[pluginGuid] = value; } value.LastCheckUtc = DateTime.UtcNow; value.ExceptionCount++; value.LastError = errorMessage; } } private static Regex GetModPattern(string pluginGuid) { lock (ModPatternCacheLock) { if (!ModPatternCache.TryGetValue(pluginGuid, out var value)) { value = new Regex("\"" + Regex.Escape(pluginGuid) + "\"\\s*:\\s*\\{([^}]+)\\}", RegexOptions.Compiled | RegexOptions.Singleline); ModPatternCache[pluginGuid] = value; } return value; } } } public static class VersionCheckerExtensions { public static void NotifyUpdateAvailable(this VersionChecker.VersionCheckResult result, ManualLogSource logger = null) { if (!result.UpdateAvailable) { return; } string text = result.ModName + " update available: v" + result.LatestVersion; try { Type type = ReflectionHelper.FindWishType("NotificationStack"); if (type != null) { Type type2 = ReflectionHelper.FindType("SingletonBehaviour`1", "Wish"); if (type2 != null) { object obj = type2.MakeGenericType(type).GetProperty("Instance")?.GetValue(null); if (obj != null) { MethodInfo method = type.GetMethod("SendNotification", new Type[5] { typeof(string), typeof(int), typeof(int), typeof(bool), typeof(bool) }); if (method != null) { method.Invoke(obj, new object[5] { text, 0, 1, false, true }); return; } } } } } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("Failed to send native notification: " + ex.Message)); } } if (logger != null) { logger.LogWarning((object)("[UPDATE AVAILABLE] " + text)); } if (!string.IsNullOrEmpty(result.NexusUrl) && logger != null) { logger.LogWarning((object)("Download at: " + result.NexusUrl)); } } } public static class SceneRootSurvivor { private static readonly object Lock = new object(); private static readonly List<string> NoKillSubstrings = new List<string>(); private static Harmony _harmony; public static void TryRegisterPersistentRunnerGameObject(GameObject go) { if (!((Object)(object)go == (Object)null)) { TryAddNoKillListSubstring(((Object)go).name); } } public static void TryAddNoKillListSubstring(string nameSubstring) { if (string.IsNullOrEmpty(nameSubstring)) { return; } lock (Lock) { bool flag = false; for (int i = 0; i < NoKillSubstrings.Count; i++) { if (string.Equals(NoKillSubstrings[i], nameSubstring, StringComparison.OrdinalIgnoreCase)) { flag = true; break; } } if (!flag) { NoKillSubstrings.Add(nameSubstring); } } EnsurePatched(); } private static void EnsurePatched() { //IL_0078: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00a3: Expected O, but got Unknown if (_harmony != null) { return; } lock (Lock) { if (_harmony == null) { MethodInfo methodInfo = AccessTools.Method(typeof(Scene), "GetRootGameObjects", Type.EmptyTypes, (Type[])null); if (!(methodInfo == null)) { string text = typeof(SceneRootSurvivor).Assembly.GetName().Name ?? "Unknown"; Harmony val = new Harmony("SunhavenMods.SceneRootSurvivor." + text); val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SceneRootSurvivor), "OnGetRootGameObjectsPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony = val; } } } } private static void OnGetRootGameObjectsPostfix(ref GameObject[] __result) { if (__result == null || __result.Length == 0) { return; } List<string> list; lock (Lock) { if (NoKillSubstrings.Count == 0) { return; } list = new List<string>(NoKillSubstrings); } List<GameObject> list2 = new List<GameObject>(__result); for (int i = 0; i < list.Count; i++) { string noKill = list[i]; list2.RemoveAll((GameObject a) => (Object)(object)a != (Object)null && ((Object)a).name.IndexOf(noKill, StringComparison.OrdinalIgnoreCase) >= 0); } __result = list2.ToArray(); } } public static class ReflectionHelper { public static readonly BindingFlags AllBindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; public static Type FindType(string typeName, params string[] namespaces) { Type type = AccessTools.TypeByName(typeName); if (type != null) { return type; } for (int i = 0; i < namespaces.Length; i++) { type = AccessTools.TypeByName(namespaces[i] + "." + typeName); if (type != null) { return type; } } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == typeName || t.FullName == typeName); if (type != null) { return type; } } catch (ReflectionTypeLoadException) { } } return null; } public static Type FindWishType(string typeName) { return FindType(typeName, "Wish"); } public static object GetStaticValue(Type type, string memberName) { if (type == null) { return null; } PropertyInfo property = type.GetProperty(memberName, AllBindingFlags); if (property != null && property.GetMethod != null) { return property.GetValue(null); } FieldInfo field = type.GetField(memberName, AllBindingFlags); if (field != null) { return field.GetValue(null); } return null; } public static object GetSingletonInstance(Type type) { if (type == null) { return null; } string[] array = new string[5] { "Instance", "instance", "_instance", "Singleton", "singleton" }; foreach (string memberName in array) { object staticValue = GetStaticValue(type, memberName); if (staticValue != null) { return staticValue; } } return null; } public static object GetInstanceValue(object instance, string memberName) { if (instance == null) { return null; } Type type = instance.GetType(); while (type != null) { PropertyInfo property = type.GetProperty(memberName, AllBindingFlags); if (property != null && property.GetMethod != null) { return property.GetValue(instance); } FieldInfo field = type.GetField(memberName, AllBindingFlags); if (field != null) { return field.GetValue(instance); } type = type.BaseType; } return null; } public static bool SetInstanceValue(object instance, string memberName, object value) { if (instance == null) { return false; } Type type = instance.GetType(); while (type != null) { PropertyInfo property = type.GetProperty(memberName, AllBindingFlags); if (property != null && property.SetMethod != null) { property.SetValue(instance, value); return true; } FieldInfo field = type.GetField(memberName, AllBindingFlags); if (field != null) { field.SetValue(instance, value); return true; } type = type.BaseType; } return false; } public static object InvokeMethod(object instance, string methodName, params object[] args) { if (instance == null) { return null; } Type type = instance.GetType(); Type[] array = args?.Select((object a) => a?.GetType() ?? typeof(object)).ToArray() ?? Type.EmptyTypes; MethodInfo methodInfo = AccessTools.Method(type, methodName, array, (Type[])null); if (methodInfo == null) { methodInfo = type.GetMethod(methodName, AllBindingFlags); } if (methodInfo == null) { return null; } return methodInfo.Invoke(instance, args); } public static object InvokeStaticMethod(Type type, string methodName, params object[] args) { if (type == null) { return null; } Type[] array = args?.Select((object a) => a?.GetType() ?? typeof(object)).ToArray() ?? Type.EmptyTypes; MethodInfo methodInfo = AccessTools.Method(type, methodName, array, (Type[])null); if (methodInfo == null) { methodInfo = type.GetMethod(methodName, AllBindingFlags); } if (methodInfo == null) { return null; } return methodInfo.Invoke(null, args); } public static FieldInfo[] GetAllFields(Type type) { if (type == null) { return Array.Empty<FieldInfo>(); } FieldInfo[] fields = type.GetFields(AllBindingFlags); IEnumerable<FieldInfo> second; if (!(type.BaseType != null) || !(type.BaseType != typeof(object))) { second = Enumerable.Empty<FieldInfo>(); } else { IEnumerable<FieldInfo> allFields = GetAllFields(type.BaseType); second = allFields; } return fields.Concat(second).Distinct().ToArray(); } public static PropertyInfo[] GetAllProperties(Type type) { if (type == null) { return Array.Empty<PropertyInfo>(); } PropertyInfo[] properties = type.GetProperties(AllBindingFlags); IEnumerable<PropertyInfo> second; if (!(type.BaseType != null) || !(type.BaseType != typeof(object))) { second = Enumerable.Empty<PropertyInfo>(); } else { IEnumerable<PropertyInfo> allProperties = GetAllProperties(type.BaseType); second = allProperties; } return (from p in properties.Concat(second) group p by p.Name into g select g.First()).ToArray(); } public static T TryGetValue<T>(object instance, string memberName, T defaultValue = default(T)) { try { object instanceValue = GetInstanceValue(instance, memberName); if (instanceValue is T result) { return result; } if (instanceValue != null && typeof(T).IsAssignableFrom(instanceValue.GetType())) { return (T)instanceValue; } return defaultValue; } catch { return defaultValue; } } } } namespace HavensRespec { [BepInPlugin("com.azraelgodking.havensrespec", "Haven's Respec", "1.2.0")] public class Plugin : BaseUnityPlugin { private Harmony _harmony; private RespecConfig _config; private SkillResetService _resetService; private CostService _costService; private RespecController _controller; public static ManualLogSource Log { get; private set; } public static Plugin Instance { get; private set; } public static bool IsDebugLoggingEnabled { get { Plugin instance = Instance; if (instance == null) { return false; } return (instance._config?.DebugLogging?.Value).GetValueOrDefault(); } } private void Awake() { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; try { ConfigFile val = ConfigFileHelper.CreateNamedConfig("com.azraelgodking.havensrespec", "HavensRespec.cfg", (Action<string>)Log.LogWarning); ConfigFileHelper.ReplacePluginConfig((BaseUnityPlugin)(object)this, val, (Action<string>)Log.LogWarning); _config = new RespecConfig(val); if (!_config.Enabled.Value) { Log.LogInfo((object)"Haven's Respec disabled in config."); return; } _resetService = new SkillResetService(Log, () => IsDebugLoggingEnabled); _costService = new CostService(Log, _config); _controller = new RespecController(Log, _config, _resetService, _costService); _controller.Install(); _harmony = new Harmony("com.azraelgodking.havensrespec"); _harmony.PatchAll(typeof(SkillsSetupProfessionPatch)); try { VersionChecker.CheckForUpdate("com.azraelgodking.havensrespec", "1.2.0", Log); } catch (Exception ex) { Log.LogDebug((object)("[Respec] VersionChecker swallowed: " + ex.Message)); } Log.LogInfo((object)"Haven's Respec v1.2.0 loaded."); } catch (Exception arg) { Log.LogError((object)string.Format("{0} Awake failed: {1}", "Haven's Respec", arg)); } } private void OnDestroy() { try { _controller?.Uninstall(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Haven's Respec OnDestroy swallowed: " + ex.Message)); } } } private void Update() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if (_controller == null || _config == null) { return; } KeyCode value = _config.ResetCurrentTabHotkey.Value; if ((int)value != 0 && Input.GetKeyDown(value)) { ProfessionType? val = _controller.TryGetActiveProfessionTab(); if (val.HasValue) { _controller.TryResetCurrentTab(val.Value, bypassConfirm: false); } } KeyCode value2 = _config.UndoHotkey.Value; if ((int)value2 != 0 && Input.GetKeyDown(value2)) { ProfessionType? val2 = _controller.TryGetActiveProfessionTab(); if (val2.HasValue) { _controller.TryUndoCurrentTab(val2.Value); } } } } internal static class PluginInfo { public const string PLUGIN_GUID = "com.azraelgodking.havensrespec"; public const string PLUGIN_NAME = "Haven's Respec"; public const string PLUGIN_VERSION = "1.2.0"; } } namespace HavensRespec.UI { internal sealed class ConfirmResetDialog : MonoBehaviour { private sealed class ButtonHoverTint : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler { public Image Target; public Color Normal; public Color Hover; public Color Pressed; private bool _isOver; public void OnPointerEnter(PointerEventData _) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _isOver = true; Apply(Hover); } public void OnPointerExit(PointerEventData _) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _isOver = false; Apply(Normal); } public void OnPointerDown(PointerEventData _) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Apply(Pressed); } public void OnPointerUp(PointerEventData _) { //IL_0012: 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) Apply(_isOver ? Hover : Normal); } private void Apply(Color fill) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Target == (Object)null)) { ((Graphic)Target).color = fill; } } } private TextMeshProUGUI _title; private TextMeshProUGUI _body; private Action _onConfirm; public static ConfirmResetDialog BuildUnder(Transform parent) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HavensRespec_ConfirmDialog", new Type[1] { typeof(RectTransform) }); RectTransform component = val.GetComponent<RectTransform>(); ((Transform)component).SetParent(parent, false); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; ((Transform)component).localScale = Vector3.one; Canvas val2 = ((Component)parent).GetComponent<Canvas>() ?? ((Component)parent).GetComponentInParent<Canvas>(); Canvas val3 = val.AddComponent<Canvas>(); if ((Object)(object)val2 != (Object)null) { val3.renderMode = val2.renderMode; val3.worldCamera = val2.worldCamera; val3.planeDistance = val2.planeDistance; } val3.overrideSorting = true; val3.sortingOrder = (((Object)(object)val2 != (Object)null) ? (val2.sortingOrder + 200) : 32000); val.AddComponent<GraphicRaycaster>(); ConfirmResetDialog confirmResetDialog = val.AddComponent<ConfirmResetDialog>(); confirmResetDialog.BuildHierarchy(); confirmResetDialog.Hide(); return confirmResetDialog; } public void Show(string title, string body, Action onConfirm) { ((TMP_Text)_title).text = title ?? "Confirm reset?"; ((TMP_Text)_body).text = body ?? string.Empty; _onConfirm = onConfirm; ((Component)this).gameObject.SetActive(true); ((Component)this).transform.SetAsLastSibling(); } public void Hide() { ((Component)this).gameObject.SetActive(false); _onConfirm = null; } private void BuildHierarchy() { //IL_0005: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Expected O, but got Unknown //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: 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_02f7: Expected O, but got Unknown //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03f2: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0459: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_0477: 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_0481: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Scrim"); val.transform.SetParent(((Component)this).transform, false); RectTransform obj = val.AddComponent<RectTransform>(); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.offsetMin = Vector2.zero; obj.offsetMax = Vector2.zero; Image obj2 = val.AddComponent<Image>(); obj2.sprite = RespecStyle.Solid(); ((Graphic)obj2).color = new Color(0f, 0f, 0f, 0.55f); ((Graphic)obj2).raycastTarget = true; Button obj3 = val.AddComponent<Button>(); ((Selectable)obj3).transition = (Transition)0; ((UnityEvent)obj3.onClick).AddListener(new UnityAction(Hide)); GameObject val2 = new GameObject("Card"); val2.transform.SetParent(((Component)this).transform, false); RectTransform obj4 = val2.AddComponent<RectTransform>(); obj4.anchorMin = new Vector2(0.5f, 0.5f); obj4.anchorMax = new Vector2(0.5f, 0.5f); obj4.pivot = new Vector2(0.5f, 0.5f); obj4.sizeDelta = new Vector2(420f, 200f); Image obj5 = val2.AddComponent<Image>(); obj5.sprite = RespecStyle.SolidRounded(RespecStyle.Wood, RespecStyle.WoodShadow, 28, 3, 8); obj5.type = (Type)1; ((Graphic)obj5).raycastTarget = false; GameObject val3 = new GameObject("Fill"); val3.transform.SetParent(val2.transform, false); RectTransform obj6 = val3.AddComponent<RectTransform>(); obj6.anchorMin = Vector2.zero; obj6.anchorMax = Vector2.one; obj6.offsetMin = new Vector2(4f, 4f); obj6.offsetMax = new Vector2(-4f, -4f); Image obj7 = val3.AddComponent<Image>(); obj7.sprite = RespecStyle.SolidRounded(new Color(0.08f, 0.06f, 0.05f, 0.95f), new Color(0.08f, 0.06f, 0.05f, 0.95f), 22, 0); obj7.type = (Type)1; ((Graphic)obj7).raycastTarget = true; GameObject val4 = new GameObject("Title"); val4.transform.SetParent(val3.transform, false); RectTransform obj8 = val4.AddComponent<RectTransform>(); obj8.anchorMin = new Vector2(0f, 1f); obj8.anchorMax = new Vector2(1f, 1f); obj8.pivot = new Vector2(0.5f, 1f); obj8.sizeDelta = new Vector2(0f, 36f); obj8.anchoredPosition = new Vector2(0f, -12f); _title = val4.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_title).alignment = (TextAlignmentOptions)514; ((TMP_Text)_title).fontSize = 20f; ((TMP_Text)_title).fontStyle = (FontStyles)1; ((Graphic)_title).color = RespecStyle.AccentGold; ((TMP_Text)_title).text = "Confirm reset?"; ((Graphic)_title).raycastTarget = false; GameObject val5 = new GameObject("Body"); val5.transform.SetParent(val3.transform, false); RectTransform obj9 = val5.AddComponent<RectTransform>(); obj9.anchorMin = new Vector2(0f, 0f); obj9.anchorMax = new Vector2(1f, 1f); obj9.offsetMin = new Vector2(18f, 60f); obj9.offsetMax = new Vector2(-18f, -52f); _body = val5.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_body).alignment = (TextAlignmentOptions)257; ((TMP_Text)_body).fontSize = 15f; ((Graphic)_body).color = new Color(0.95f, 0.92f, 0.83f, 1f); ((TMP_Text)_body).text = string.Empty; ((Graphic)_body).raycastTarget = false; BuildButton(val3.transform, "Cancel", new Vector2(-10f, 12f), new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(1f, 0f), RespecStyle.Neutral, RespecStyle.NeutralHover, RespecStyle.NeutralPressed, Hide); BuildButton(val3.transform, "Reset", new Vector2(-130f, 12f), new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(1f, 0f), RespecStyle.Danger, RespecStyle.DangerHover, RespecStyle.DangerPressed, delegate { Action onConfirm = _onConfirm; Hide(); onConfirm?.Invoke(); }); } private static void BuildButton(Transform parent, string label, Vector2 anchoredPos, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Color normal, Color hover, Color pressed, Action onClick) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_005e: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Btn_" + label); val.transform.SetParent(parent, false); RectTransform obj = val.AddComponent<RectTransform>(); obj.anchorMin = anchorMin; obj.anchorMax = anchorMax; obj.pivot = pivot; obj.sizeDelta = new Vector2(110f, 36f); obj.anchoredPosition = anchoredPos; Image val2 = val.AddComponent<Image>(); val2.sprite = RespecStyle.SolidRounded(Color.white, new Color(0f, 0f, 0f, 0.45f), 20, 1, 5); val2.type = (Type)1; ((Graphic)val2).color = normal; ((Graphic)val2).raycastTarget = true; Button obj2 = val.AddComponent<Button>(); ColorBlock colors = ((Selectable)obj2).colors; ((ColorBlock)(ref colors)).normalColor = Color.white; ((ColorBlock)(ref colors)).highlightedColor = Color.white; ((ColorBlock)(ref colors)).pressedColor = Color.white; ((ColorBlock)(ref colors)).selectedColor = Color.white; ((Selectable)obj2).colors = colors; ((Selectable)obj2).transition = (Transition)0; ((UnityEvent)obj2.onClick).AddListener((UnityAction)delegate { onClick?.Invoke(); }); ButtonHoverTint buttonHoverTint = val.AddComponent<ButtonHoverTint>(); buttonHoverTint.Target = val2; buttonHoverTint.Normal = normal; buttonHoverTint.Hover = hover; buttonHoverTint.Pressed = pressed; GameObject val3 = new GameObject("Text"); val3.transform.SetParent(val.transform, false); RectTransform obj3 = val3.AddComponent<RectTransform>(); obj3.anchorMin = Vector2.zero; obj3.anchorMax = Vector2.one; obj3.offsetMin = Vector2.zero; obj3.offsetMax = Vector2.zero; TextMeshProUGUI obj4 = val3.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj4).alignment = (TextAlignmentOptions)514; ((TMP_Text)obj4).fontSize = 16f; ((TMP_Text)obj4).fontStyle = (FontStyles)1; ((Graphic)obj4).color = Color.white; ((TMP_Text)obj4).text = label; ((Graphic)obj4).raycastTarget = false; } } internal sealed class RespecButtonInjector { private sealed class HoverTint : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler { public Image Fill; public RectTransform Root; public Color Normal; public Color Hover; public Color Pressed; private const float HoverScale = 1.04f; private const float PressedScale = 0.97f; private bool _isOver; public void OnPointerEnter(PointerEventData _) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _isOver = true; Apply(Hover, 1.04f); } public void OnPointerExit(PointerEventData _) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _isOver = false; Apply(Normal, 1f); } public void OnPointerDown(PointerEventData _) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Apply(Pressed, 0.97f); } public void OnPointerUp(PointerEventData _) { //IL_0012: 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) Apply(_isOver ? Hover : Normal, _isOver ? 1.04f : 1f); } private void Apply(Color fill, float scale) { //IL_0014: 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) if ((Object)(object)Fill != (Object)null) { ((Graphic)Fill).color = fill; } if ((Object)(object)Root != (Object)null) { ((Transform)Root).localScale = new Vector3(scale, scale, 1f); } } } private readonly ManualLogSource _log; private static FieldInfo _skillPointsTmpField; private const float ButtonWidth = 96f; private const float ButtonHeight = 26f; private const float FirstRowCenterOffset = 135f; private const float RowSpacing = 30f; private const float HorizontalOffset = -14f; private static Sprite _plaqueFillSprite; private static Sprite _plaqueBorderSprite; private static Sprite _plaqueShadowSprite; public GameObject ResetButton { get; private set; } public GameObject UndoButton { get; private set; } public event Action OnResetClicked; public event Action OnUndoClicked; public RespecButtonInjector(ManualLogSource log) { _log = log; } public bool TryAttach(SkillTree panel) { //IL_008e: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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_00c6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)panel == (Object)null) { return false; } try { if (_skillPointsTmpField == null) { _skillPointsTmpField = typeof(SkillTree).GetField("_skillPointsTMP", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } object? obj = _skillPointsTmpField?.GetValue(panel); TextMeshProUGUI val = (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null); if ((Object)(object)val == (Object)null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)"[Respec] _skillPointsTMP not found on SkillTree; cannot attach button."); } return false; } Transform parent = ((TMP_Text)val).transform.parent; RectTransform component = ((Component)val).GetComponent<RectTransform>(); ResetButton = BuildButton(parent, component, 0, "Reset", RespecStyle.Danger, RespecStyle.DangerHover, RespecStyle.DangerPressed, delegate { this.OnResetClicked?.Invoke(); }); UndoButton = BuildButton(parent, component, 1, "Undo", RespecStyle.Neutral, RespecStyle.NeutralHover, RespecStyle.NeutralPressed, delegate { this.OnUndoClicked?.Invoke(); }); UndoButton.SetActive(false); return true; } catch (Exception arg) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)$"[Respec] RespecButtonInjector.TryAttach failed: {arg}"); } return false; } } public void SetUndoVisible(bool visible) { if ((Object)(object)UndoButton != (Object)null) { UndoButton.SetActive(visible); } } public void Destroy() { if ((Object)(object)ResetButton != (Object)null) { Object.Destroy((Object)(object)ResetButton); } if ((Object)(object)UndoButton != (Object)null) { Object.Destroy((Object)(object)UndoButton); } ResetButton = null; UndoButton = null; } private static void EnsureSprites() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_007f: 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) if ((Object)(object)_plaqueFillSprite == (Object)null) { _plaqueFillSprite = RespecStyle.SolidRounded(Color.white, new Color(0f, 0f, 0f, 0f), 32, 0, 8); } if ((Object)(object)_plaqueBorderSprite == (Object)null) { _plaqueBorderSprite = RespecStyle.SolidRounded(new Color(0f, 0f, 0f, 0f), RespecStyle.AccentGold, 32, 2, 8); } if ((Object)(object)_plaqueShadowSprite == (Object)null) { _plaqueShadowSprite = RespecStyle.SolidRounded(Color.white, new Color(0f, 0f, 0f, 0f), 32, 0, 9); } } private static GameObject BuildButton(Transform parent, RectTransform anchorRt, int rowIndex, string label, Color normal, Color hover, Color pressed, Action onClick) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown //IL_0143: 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_018c: 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_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: 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_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0250: 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_0265: 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_0281: Expected O, but got Unknown //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) EnsureSprites(); GameObject val = new GameObject("HavensRespec_" + label + "Button"); val.transform.SetParent(parent, false); RectTransform val2 = val.AddComponent<RectTransform>(); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 0.5f); val2.anchorMax = val3; val2.anchorMin = val3; val2.pivot = new Vector2(0.5f, 0.5f); val2.sizeDelta = new Vector2(96f, 26f); ((Transform)val2).localScale = Vector3.one; float num = 0f - (135f + (float)rowIndex * 30f); ((Transform)val2).localPosition = ((Transform)anchorRt).localPosition + new Vector3(-14f, num, 0f); Image val4 = val.AddComponent<Image>(); ((Graphic)val4).color = new Color(0f, 0f, 0f, 0f); ((Graphic)val4).raycastTarget = true; Button obj = val.AddComponent<Button>(); ((Selectable)obj).transition = (Transition)0; ((Selectable)obj).targetGraphic = (Graphic)(object)val4; ((UnityEvent)obj.onClick).AddListener((UnityAction)delegate { onClick?.Invoke(); }); Image obj2 = AddChildImage(val.transform, "Shadow", _plaqueShadowSprite, new Color(0f, 0f, 0f, 0.45f)); StretchFill(((Graphic)obj2).rectTransform, new Vector2(-1f, -3f), new Vector2(2f, 0f)); ((Graphic)obj2).raycastTarget = false; Image val5 = AddChildImage(val.transform, "Fill", _plaqueFillSprite, normal); StretchFill(((Graphic)val5).rectTransform, Vector2.zero, Vector2.zero); ((Graphic)val5).raycastTarget = false; Image obj3 = AddChildImage(val.transform, "Gloss", _plaqueFillSprite, new Color(1f, 1f, 1f, 0.18f)); RectTransform rectTransform = ((Graphic)obj3).rectTransform; rectTransform.anchorMin = new Vector2(0f, 0.5f); rectTransform.anchorMax = new Vector2(1f, 1f); rectTransform.offsetMin = new Vector2(3f, 0f); rectTransform.offsetMax = new Vector2(-3f, -2f); ((Graphic)obj3).raycastTarget = false; Image obj4 = AddChildImage(val.transform, "Border", _plaqueBorderSprite, RespecStyle.AccentGold); StretchFill(((Graphic)obj4).rectTransform, Vector2.zero, Vector2.zero); ((Graphic)obj4).raycastTarget = false; GameObject val6 = new GameObject("Label"); val6.transform.SetParent(val.transform, false); RectTransform obj5 = val6.AddComponent<RectTransform>(); obj5.anchorMin = Vector2.zero; obj5.anchorMax = Vector2.one; obj5.offsetMin = new Vector2(0f, 0f); obj5.offsetMax = new Vector2(0f, -1f); TextMeshProUGUI obj6 = val6.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj6).alignment = (TextAlignmentOptions)514; ((TMP_Text)obj6).fontSize = 12f; ((TMP_Text)obj6).fontStyle = (FontStyles)1; ((TMP_Text)obj6).enableWordWrapping = false; ((TMP_Text)obj6).overflowMode = (TextOverflowModes)0; ((TMP_Text)obj6).characterSpacing = 8f; ((Graphic)obj6).color = RespecStyle.Parchment; ((TMP_Text)obj6).text = label.ToUpperInvariant(); ((Graphic)obj6).raycastTarget = false; Type type = Type.GetType("I2.Loc.Localize, I2Localization") ?? Type.GetType("I2.Loc.Localize, Assembly-CSharp"); if (type != null) { Component component = val6.GetComponent(type); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } } HoverTint hoverTint = val.AddComponent<HoverTint>(); hoverTint.Fill = val5; hoverTint.Root = val2; hoverTint.Normal = normal; hoverTint.Hover = hover; hoverTint.Pressed = pressed; return val; } private static Image AddChildImage(Transform parent, string name, Sprite sprite, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent, false); RectTransform obj = val.AddComponent<RectTransform>(); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.offsetMin = Vector2.zero; obj.offsetMax = Vector2.zero; Image obj2 = val.AddComponent<Image>(); obj2.sprite = sprite; obj2.type = (Type)1; ((Graphic)obj2).color = color; return obj2; } private static void StretchFill(RectTransform rt, Vector2 offsetMin, Vector2 offsetMax) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.offsetMin = offsetMin; rt.offsetMax = offsetMax; } } internal sealed class RespecController { private sealed class HoverTint : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler { public Image Target; public Color Normal; public Color Hover; public Color Pressed; private bool _isOver; public void OnPointerEnter(PointerEventData _) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _isOver = true; Apply(Hover); } public void OnPointerExit(PointerEventData _) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _isOver = false; Apply(Normal); } public void OnPointerDown(PointerEventData _) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Apply(Pressed); } public void OnPointerUp(PointerEventData _) { //IL_0012: 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) Apply(_isOver ? Hover : Normal); } private void Apply(Color fill) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Target == (Object)null)) { ((Graphic)Target).color = fill; } } } private readonly ManualLogSource _log; private readonly RespecConfig _config; private readonly SkillResetService _resetService; private readonly CostService _costService; private readonly Dictionary<ProfessionType, RespecButtonInjector> _injectors = new Dictionary<ProfessionType, RespecButtonInjector>(); private Skills _activeSkills; private ConfirmResetDialog _dialog; private GameObject _resetAllButton; public RespecController(ManualLogSource log, RespecConfig config, SkillResetService resetService, CostService costService) { _log = log; _config = config; _resetService = resetService; _costService = costService; } public void Install() { SkillsSetupProfessionPatch.OnSetup = HandleSetupProfession; } public void Uninstall() { SkillsSetupProfessionPatch.OnSetup = null; foreach (RespecButtonInjector value in _injectors.Values) { value.Destroy(); } _injectors.Clear(); if ((Object)(object)_dialog != (Object)null) { Object.Destroy((Object)(object)((Component)_dialog).gameObject); _dialog = null; } if ((Object)(object)_resetAllButton != (Object)null) { Object.Destroy((Object)(object)_resetAllButton); _resetAllButton = null; } } public void TryResetCurrentTab(ProfessionType profession, bool bypassConfirm) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_activeSkills == (Object)null)) { BeginResetFlow(_activeSkills, profession, bypassConfirm); } } public void TryUndoCurrentTab(ProfessionType profession) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_activeSkills == (Object)null)) { PerformUndo(_activeSkills, profession); } } public bool HasUndo(ProfessionType profession) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return _resetService.HasUndo(profession); } public ProfessionType? TryGetActiveProfessionTab() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_activeSkills == (Object)null) { return null; } try { ProfessionType[] orderedProfessions = ProfessionUiMap.OrderedProfessions; foreach (ProfessionType val in orderedProfessions) { string text = ProfessionUiMap.ResolvePanelFieldName(val); Component val2 = (Component)((text == null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)val2 != (Object)null && val2.gameObject.activeInHierarchy) { return val; } } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)("[Respec] TryGetActiveProfessionTab failed: " + ex.Message)); } } return null; } private void HandleSetupProfession(Skills skills, ProfessionType profession, SkillTree panel) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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) _activeSkills = skills; if (_injectors.TryGetValue(profession, out var value)) { value.Destroy(); _injectors.Remove(profession); } if (!_config.InjectButtons.Value) { return; } RespecButtonInjector respecButtonInjector = new RespecButtonInjector(_log); if (respecButtonInjector.TryAttach(panel)) { respecButtonInjector.OnResetClicked += delegate { //IL_000d: Unknown result type (might be due to invalid IL or missing references) BeginResetFlow(skills, profession, _config.ShiftSkipsConfirmation.Value && IsShiftHeld()); }; respecButtonInjector.OnUndoClicked += delegate { //IL_000d: Unknown result type (might be due to invalid IL or missing references) PerformUndo(skills, profession); }; respecButtonInjector.SetUndoVisible(_config.EnableUndo.Value && _resetService.HasUndo(profession)); _injectors[profession] = respecButtonInjector; EnsureDialog((Component)(object)panel); EnsureResetAllButton(skills, panel); } } private void BeginResetFlow(Skills skills, ProfessionType profession, bool bypassConfirm) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_009b: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) int estimatedPoints = ResolveEstimatedRefund(skills, profession); if (!_costService.CanAfford(estimatedPoints, out var balance, out var cost)) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"[Respec] Cannot afford reset of {profession}: cost={cost}, balance={balance}."); } return; } if (!_config.RequireConfirmation.Value || bypassConfirm) { PerformReset(skills, profession, estimatedPoints); return; } EnsureDialog((Component)(object)skills); if ((Object)(object)_dialog == (Object)null) { PerformReset(skills, profession, estimatedPoints); return; } string body = BuildConfirmBody(profession, estimatedPoints, cost); _dialog.Show($"Reset {profession}?", body, delegate { //IL_000d: Unknown result type (might be due to invalid IL or missing references) PerformReset(skills, profession, estimatedPoints); }); } private bool PerformReset(Skills skills, ProfessionType profession, int estimatedPoints) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if (!_resetService.ResetProfession(skills, profession, out var pointsRefunded)) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"[Respec] Reset of {profession} failed."); } return false; } int num = _costService.CalculateCost(pointsRefunded); if (num > 0) { ResetSnapshot restoredSnapshot; if (!_costService.CanAfford(pointsRefunded, out var balance, out var _)) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)$"[Respec] Actual reset cost check failed for {profession}: cost={num}, balance={balance}. Rolling back reset."); } _resetService.UndoLastReset(skills, profession, out restoredSnapshot); return false; } if (!_costService.TryDeduct(pointsRefunded)) { ManualLogSource log3 = _log; if (log3 != null) { log3.LogWarning((object)$"[Respec] Cost deduction failed for {profession} (actual cost {num}). Rolling back reset."); } _resetService.UndoLastReset(skills, profession, out restoredSnapshot); return false; } _resetService.AttachUndoCharge(profession, num, _config.CostMode.Value); } if (_injectors.TryGetValue(profession, out var value)) { value.SetUndoVisible(_config.EnableUndo.Value && _resetService.HasUndo(profession)); } if (pointsRefunded == 0) { ManualLogSource log4 = _log; if (log4 != null) { log4.LogInfo((object)$"[Respec] {profession} reset complete; nothing was allocated (0 active node(s) — skill-points counter unchanged)."); } } else { ManualLogSource log5 = _log; if (log5 != null) { log5.LogInfo((object)$"[Respec] {profession} reset complete; refunded {pointsRefunded} point(s){((estimatedPoints != pointsRefunded) ? $" (pre-flight estimate was {estimatedPoints})" : string.Empty)}."); } } return true; } private void PerformUndo(Skills skills, ProfessionType profession) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: 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_0059: Unknown result type (might be due to invalid IL or missing references) if (!_resetService.UndoLastReset(skills, profession, out var restoredSnapshot)) { return; } if (restoredSnapshot != null && restoredSnapshot.ChargedCost > 0 && restoredSnapshot.ChargedCostMode != 0) { if (!_costService.TryRefund(restoredSnapshot.ChargedCost, restoredSnapshot.ChargedCostMode)) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"[Respec] Undo restored {profession} nodes but failed to refund {restoredSnapshot.ChargedCost} ({restoredSnapshot.ChargedCostMode})."); } } else { ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)$"[Respec] Undo refunded {restoredSnapshot.ChargedCost} ({restoredSnapshot.ChargedCostMode}) for {profession}."); } } } if (_injectors.TryGetValue(profession, out var value)) { value.SetUndoVisible(_config.EnableUndo.Value && _resetService.HasUndo(profession)); } } private void BeginResetAllFlow(Skills skills, bool bypassConfirm) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) int num = 0; int num2 = 0; ProfessionType[] orderedProfessions = ProfessionUiMap.OrderedProfessions; int i; for (i = 0; i < orderedProfessions.Length; i++) { ProfessionType profession = orderedProfessions[i]; int num3 = ResolveEstimatedRefund(skills, profession); num += num3; num2 += _costService.CalculateCost(num3); } if (num2 > 0 && !_costService.CanAfford(num, out var balance, out i)) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"[Respec] Cannot afford Reset All preflight: total cost={num2}, balance={balance}."); } return; } if (!_config.RequireConfirmation.Value || bypassConfirm) { PerformResetAll(skills); return; } EnsureDialog((Component)(object)skills); if ((Object)(object)_dialog == (Object)null) { PerformResetAll(skills); return; } string body = $"This will reset all profession trees.\n\nEstimated total refund: {num} point(s)." + ((num2 > 0) ? ("\nEstimated total cost: " + _costService.CostLabel(num) + " (final charge uses actual refunded points).") : "\nCost: Free") + (_config.EnableUndo.Value ? "\n\nUndo remains per-profession and will refund each profession's charged cost." : "\n\nUndo is disabled in config — this cannot be reversed."); _dialog.Show("Reset all professions?", body, delegate { PerformResetAll(skills); }); } private void PerformResetAll(Skills skills) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_003c: 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) int num = 0; List<ProfessionType> list = new List<ProfessionType>(); ProfessionType[] orderedProfessions = ProfessionUiMap.OrderedProfessions; foreach (ProfessionType val in orderedProfessions) { if (!PerformReset(skills, val, ResolveEstimatedRefund(skills, val))) { for (int num2 = list.Count - 1; num2 >= 0; num2--) { PerformUndo(skills, list[num2]); } ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"[Respec] Reset All aborted on {val}; rolled back {list.Count} profession(s)."); } return; } list.Add(val); num++; } ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)$"[Respec] Reset All complete: processed {num} profession(s)."); } } private void EnsureDialog(Component sceneAnchor) { if (!((Object)(object)_dialog != (Object)null) && !((Object)(object)sceneAnchor == (Object)null)) { Canvas val = sceneAnchor.GetComponentInParent<Canvas>(); if ((Object)(object)val == (Object)null) { val = Object.FindObjectOfType<Canvas>(); } if (!((Object)(object)val == (Object)null)) { _dialog = ConfirmResetDialog.BuildUnder(((Component)val).transform); } } } private string BuildConfirmBody(ProfessionType profession, int pointsRefunded, int cost) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) string obj = ((pointsRefunded > 0) ? string.Format("This will clear every allocated node in {0}. Estimated refund: {1} skill point{2}.", profession, pointsRefunded, (pointsRefunded == 1) ? string.Empty : "s") : $"This will clear every allocated node in {profession}."); string text = ((cost > 0) ? ("\n\nEstimated cost: " + _costService.CostLabel(pointsRefunded) + " (final charge uses actual refunded points).") : string.Empty); string text2 = (_config.EnableUndo.Value ? "\n\nYou can press \"Undo\" to restore your previous allocation (and any charged cost) until the game closes." : "\n\nUndo is disabled in config — this cannot be reversed."); return obj + text + text2; } private static bool IsShiftHeld() { if (!Input.GetKey((KeyCode)304)) { return Input.GetKey((KeyCode)303); } return true; } private int ResolveEstimatedRefund(Skills skills, ProfessionType profession) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (_resetService.TryEstimateExactRefund(skills, profession, out var refundedPoints)) { return Mathf.Max(0, refundedPoints); } return Mathf.Max(0, _resetService.GetAllocatedPoints(profession)); } private void EnsureResetAllButton(Skills skills, SkillTree panel) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00b8: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) if (!_config.EnableResetAll.Value || !_config.InjectButtons.Value || (Object)(object)panel == (Object)null) { if ((Object)(object)_resetAllButton != (Object)null) { Object.Destroy((Object)(object)_resetAllButton); _resetAllButton = null; } } else { if ((Object)(object)_resetAllButton != (Object)null) { return; } Transform parent = ((Component)panel).transform.parent; if (!((Object)(object)parent == (Object)null)) { GameObject val = new GameObject("HavensRespec_ResetAllButton"); val.transform.SetParent(parent, false); RectTransform obj = val.AddComponent<RectTransform>(); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 1f); obj.anchorMax = val2; obj.anchorMin = val2; obj.pivot = new Vector2(0.5f, 1f); obj.sizeDelta = new Vector2(130f, 28f); obj.anchoredPosition = new Vector2(0f, -8f); ((Transform)obj).localScale = Vector3.one; Image val3 = val.AddComponent<Image>(); val3.sprite = RespecStyle.SolidRounded(Color.white, new Color(0f, 0f, 0f, 0f), 32, 0, 8); val3.type = (Type)1; ((Graphic)val3).color = RespecStyle.Danger; Button obj2 = val.AddComponent<Button>(); ((Selectable)obj2).transition = (Transition)0; ((UnityEvent)obj2.onClick).AddListener((UnityAction)delegate { BeginResetAllFlow(skills, _config.ShiftSkipsConfirmation.Value && IsShiftHeld()); }); HoverTint hoverTint = val.AddComponent<HoverTint>(); hoverTint.Target = val3; hoverTint.Normal = RespecStyle.Danger; hoverTint.Hover = RespecStyle.DangerHover; hoverTint.Pressed = RespecStyle.DangerPressed; GameObject val4 = new GameObject("Label"); val4.transform.SetParent(val.transform, false); RectTransform obj3 = val4.AddComponent<RectTransform>(); obj3.anchorMin = Vector2.zero; obj3.anchorMax = Vector2.one; obj3.offsetMin = Vector2.zero; obj3.offsetMax = Vector2.zero; TextMeshProUGUI obj4 = val4.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj4).alignment = (TextAlignmentOptions)514; ((TMP_Text)obj4).fontSize = 12f; ((TMP_Text)obj4).fontStyle = (FontStyles)1; ((TMP_Text)obj4).enableWordWrapping = false; ((Graphic)obj4).color = RespecStyle.Parchment; ((TMP_Text)obj4).text = "RESET ALL"; ((Graphic)obj4).raycastTarget = false; _resetAllButton = val; } } } } internal static class RespecStyle { public static readonly Color Ink = new Color(0.09f, 0.07f, 0.05f, 1f); public static readonly Color Parchment = new Color(0.96f, 0.9f, 0.75f, 1f); public static readonly Color Wood = new Color(0.38f, 0.25f, 0.16f, 1f); public static readonly Color WoodShadow = new Color(0.22f, 0.14f, 0.09f, 1f); public static readonly Color AccentGold = new Color(0.95f, 0.76f, 0.32f, 1f); public static readonly Color Danger = new Color(0.78f, 0.28f, 0.22f, 1f); public static readonly Color DangerHover = new Color(0.92f, 0.36f, 0.28f, 1f); public static readonly Color DangerPressed = new Color(0.62f, 0.2f, 0.16f, 1f); public static readonly Color Neutral = new Color(0.5f, 0.38f, 0.22f, 1f); public static readonly Color NeutralHover = new Color(0.64f, 0.49f, 0.28f, 1f); public static readonly Color NeutralPressed = new Color(0.36f, 0.27f, 0.16f, 1f); private static readonly Dictionary<string, Sprite> _cache = new Dictionary<string, Sprite>(); public static Sprite SolidRounded(Color fill, Color border, int size = 24, int borderThickness = 2, int cornerRadius = 6) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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) string key = $"rounded|{fill}|{border}|{size}|{borderThickness}|{cornerRadius}"; if (_cache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } Texture2D val = new Texture2D(size, size, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; Color val2 = default(Color); ((Color)(ref val2))..ctor(0f, 0f, 0f, 0f); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { bool num = IsInsideRoundedRect(j, i, size, size, cornerRadius); bool flag = num && !IsInsideRoundedRect(j, i, size, size, cornerRadius, borderThickness); if (!num) { val.SetPixel(j, i, val2); } else if (flag) { val.SetPixel(j, i, border); } else { val.SetPixel(j, i, fill); } } } val.Apply(); Sprite val3 = Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)cornerRadius, (float)cornerRadius, (float)cornerRadius, (float)cornerRadius)); _cache[key] = val3; return val3; } public static Sprite Solid() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (_cache.TryGetValue("solid", out var value) && (Object)(object)value != (Object)null) { return value; } Texture2D val = new Texture2D(4, 4, (TextureFormat)4, false) { filterMode = (FilterMode)1 }; Color[] array = (Color[])(object)new Color[16]; for (int i = 0; i < array.Length; i++) { array[i] = Color.white; } val.SetPixels(array); val.Apply(); Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, 4f, 4f), new Vector2(0.5f, 0.5f)); _cache["solid"] = val2; return val2; } private static bool IsInsideRoundedRect(int x, int y, int w, int h, int r, int inset = 0) { r = Mathf.Max(0, r - inset); int num = w - 1 - inset; int num2 = h - 1 - inset; if (x < inset || x > num || y < inset || y > num2) { return false; } int num3 = Mathf.Clamp(x, inset + r, num - r); int num4 = Mathf.Clamp(y, inset + r, num2 - r); int num5 = x - num3; int num6 = y - num4; return num5 * num5 + num6 * num6 <= r * r; } } } namespace HavensRespec.Services { internal sealed class CostService { private readonly ManualLogSource _log; private readonly RespecConfig _config; private static MethodInfo _addMoneyMethod; private static MethodInfo _addTicketsMethod; private static PropertyInfo _gameSaveCoinsProp; private static PropertyInfo _gameSaveTicketsProp; private static bool _reflectionInitialized; public CostService(ManualLogSource log, RespecConfig config) { _log = log; _config = config; } public int CalculateCost(int pointsRefunded) { if (pointsRefunded <= 0) { return 0; } return _config.CostMode.Value switch { RespecCostMode.Gold => pointsRefunded * Math.Max(0, _config.GoldPerPoint.Value), RespecCostMode.Gems => pointsRefunded * Math.Max(0, _config.GemsPerPoint.Value), _ => 0, }; } public string CostLabel(int pointsRefunded) { int num = CalculateCost(pointsRefunded); if (num <= 0) { return "Free"; } return _config.CostMode.Value switch { RespecCostMode.Gold => $"{num:N0} gold", RespecCostMode.Gems => $"{num:N0} tickets", _ => "Free", }; } public bool CanAfford(int pointsRefunded, out int balance, out int cost) { cost = CalculateCost(pointsRefunded); balance = ReadBalance(); if (cost <= 0) { return true; } if (balance < 0) { return false; } return balance >= cost; } public bool TryDeduct(int pointsRefunded) { int num = CalculateCost(pointsRefunded); if (num <= 0) { return true; } EnsureReflection(); try { Player instance = Player.Instance; if ((Object)(object)instance == (Object)null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)"[Respec] TryDeduct: Player.Instance was null."); } return false; } switch (_config.CostMode.Value) { case RespecCostMode.Gold: if (_addMoneyMethod == null) { return false; } _addMoneyMethod.Invoke(instance, new object[4] { -num, true, false, true }); return true; case RespecCostMode.Gems: if (_addTicketsMethod == null) { return false; } _addTicketsMethod.Invoke(instance, new object[1] { -num }); return true; default: return true; } } catch (Exception arg) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)$"[Respec] TryDeduct failed: {arg}"); } return false; } } public bool TryRefund(int amount, RespecCostMode mode) { if (amount <= 0 || mode == RespecCostMode.None) { return true; } EnsureReflection(); try { Player instance = Player.Instance; if ((Object)(object)instance == (Object)null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)"[Respec] TryRefund: Player.Instance was null."); } return false; } switch (mode) { case RespecCostMode.Gold: if (_addMoneyMethod == null) { return false; } _addMoneyMethod.Invoke(instance, new object[4] { amount, true, false, true }); return true; case RespecCostMode.Gems: if (_addTicketsMethod == null) { return false; } _addTicketsMethod.Invoke(instance, new object[1] { amount }); return true; default: return true; } } catch (Exception arg) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)$"[Respec] TryRefund failed: {arg}"); } return false; } } private int ReadBalance() { EnsureReflection(); try { switch (_config.CostMode.Value) { case RespecCostMode.Gold: if (_gameSaveCoinsProp != null) { return Convert.ToInt32(_gameSaveCoinsProp.GetValue(null)); } break; case RespecCostMode.Gems: if (_gameSaveTicketsProp != null) { return Convert.ToInt32(_gameSaveTicketsProp.GetValue(null)); } break; } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)("[Respec] ReadBalance swallowed: " + ex.Message)); } } return -1; } private static void EnsureReflection() { if (!_reflectionInitialized) { _addMoneyMethod = AccessTools.Method(typeof(Player), "AddMoney", new Type[4] { typeof(int), typeof(bool), typeof(bool), typeof(bool) }, (Type[])null); _addTicketsMethod = AccessTools.Method(typeof(Player), "AddTickets", new Type[1] { typeof(int) }, (Type[])null); _gameSaveCoinsProp = typeof(GameSave).GetProperty("Coins", BindingFlags.Static | BindingFlags.Public); _gameSaveTicketsProp = typeof(GameSave).GetProperty("Tickets", BindingFlags.Static | BindingFlags.Public); _reflectionInitialized = true; } } } internal static class ProfessionUiMap { public static readonly ProfessionType[] OrderedProfessions; public static string ResolvePanelFieldName(ProfessionType profession) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected I4, but got Unknown return (int)profession switch { 0 => "_combatPanel", 1 => "_farmingPanel", 3 => "_miningPanel", 4 => "_artisanryPanel", 2 => "_fishingPanel", _ => null, }; } static ProfessionUiMap() { ProfessionType[] array = new ProfessionType[5]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); OrderedProfessions = (ProfessionType[])(object)array; } } internal sealed class ResetSnapshot { public ProfessionType Profession { get; } public IReadOnlyDictionary<int, int> Nodes { get; } public int SkillPointsUsed { get; } public int NumActiveNodes { get; } public int ChargedCost { get; } public RespecCostMode ChargedCostMode { get; } public ResetSnapshot(ProfessionType profession, IReadOnlyDictionary<int, int> nodes, int skillPointsUsed, int numActiveNodes, int chargedCost = 0, RespecCostMode chargedCostMode = RespecCostMode.None) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) Profession = profession; Nodes = nodes; SkillPointsUsed = skillPointsUsed; NumActiveNodes = numActiveNodes; ChargedCost = chargedCost; ChargedCostMode = chargedCostMode; } } internal sealed class SkillResetService { private readonly ManualLogSource _log; private readonly Func<bool> _isDebug; private readonly Dictionary<ProfessionType, Stack<ResetSnapshot>> _undoByProfession = new Dictionary<ProfessionType, Stack<ResetSnapshot>>(); private static MethodInfo _updateProfessionMethod; private static FieldInfo _professionNodeDictionaryField; private static FieldInfo _skillPointsUsedField; private static FieldInfo _numActiveNodesField; private static bool _reflectionInitialized; public SkillResetService(ManualLogSource log, Func<bool> isDebug) { _log = log; _isDebug = isDebug; } public bool HasUndo(ProfessionType profession) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (_undoByProfession.TryGetValue(profession, out var value)) { return value.Count > 0; } return false; } public void AttachUndoCharge(ProfessionType profession, int chargedCost, RespecCostMode chargedCostMode) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (_undoByProfession.TryGetValue(profession, out var value) && value.Count != 0 && chargedCost > 0 && chargedCostMode != 0) { ResetSnapshot resetSnapshot = value.Pop(); value.Push(new ResetSnapshot(resetSnapshot.Profession, resetSnapshot.Nodes, resetSnapshot.SkillPointsUsed, resetSnapshot.NumActiveNodes, chargedCost, chargedCostMode)); } } public bool ResetProfession(Skills skills, ProfessionType profession, out int pointsRefunded) { //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) pointsRefunded = 0; if ((Object)(object)skills == (Object)null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)"[Respec] ResetProfession: Skills instance was null."); } return false; } EnsureReflection(); try { Profession val = ResolveProfessionData(profession); if (val == null) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)$"[Respec] ResetProfession({profession}): no Profession data on the current save."); } return false; } ResetSnapshot resetSnapshot = CaptureSnapshot(profession, val); int num = 0; int num2 = 0; int num3 = 0; try { if (_professionNodeDictionaryField?.GetValue(skills) is IDictionary dictionary && dictionary.Contains(profession) && dictionary[profession] is SkillNode[] array) { SkillNode[] array2 = array; foreach (SkillNode val2 in array2) { if (!((Object)(object)val2 == (Object)null)) { num++; if (val2.active) { num3 += Mathf.Max(1, val2.NodeAmount); num2++; val2.SetActive(false, false, 0); } } } } } catch (Exception ex) { ManualLogSource log3 = _log; if (log3 != null) { log3.LogDebug((object)("[Respec] Node-walk deactivation swallowed: " + ex.Message)); } } List<int> list = new List<int>(val.Nodes.Keys); foreach (int item in list) { val.Nodes[item] = 0; } foreach (int item2 in CollectNodeHashes(skills, profession, val)) { val.Nodes[item2] = 0; } SetSkillPointsUsed(profession, 0); SetNumActiveNodes(profession, 0); pointsRefunded = ((num > 0) ? num3 : resetSnapshot.SkillPointsUsed); TryRefreshProfessionPanel(skills, profession); PushUndoSnapshot(profession, resetSnapshot); if (num > 0) { ManualLogSource log4 = _log; if (log4 != null) { log4.LogInfo((object)$"[Respec] Reset {profession}: refunded {pointsRefunded} point(s) from {num2}/{num} active node(s); cleared {list.Count} save key(s)."); } } else { ManualLogSource log5 = _log; if (log5 != null) { log5.LogInfo((object)$"[Respec] Reset {profession}: refunded {pointsRefunded} point(s) (fallback from skillPointsUsed snapshot); cleared {list.Count} save key(s). _professionNodeDictionary was unreadable."); } } return true; } catch (Exception arg) { ManualLogSource log6 = _log; if (log6 != null) { log6.LogError((object)$"[Respec] ResetProfession({profession}) failed: {arg}"); } return false; } } public bool UndoLastReset(Skills skills, ProfessionType profession, out ResetSnapshot restoredSnapshot) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) restoredSnapshot = null; if (!_undoByProfession.TryGetValue(profession, out var value) || value.Count == 0) { return false; } ResetSnapshot resetSnapshot = value.Pop(); EnsureReflection(); try { Profession val = ResolveProfessionData(profession); if (val == null) { return false; } val.Nodes.Clear(); foreach (KeyValuePair<int, int> node in resetSnapshot.Nodes) { val.Nodes[node.Key] = node.Value; } SetSkillPointsUsed(profession, resetSnapshot.SkillPointsUsed); SetNumActiveNodes(profession, resetSnapshot.NumActiveNodes); TryRefreshProfessionPanel(skills, profession); if (value.Count == 0) { _undoByProfession.Remove(profession); } restoredSnapshot = resetSnapshot; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"[Respec] Undo {profession}: restored {resetSnapshot.Nodes.Count} node(s), {resetSnapshot.SkillPointsUsed} point(s) used."); } return true; } catch (Exception arg) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)$"[Respec] UndoLastReset({profession}) failed: {arg}"); } return false; } } public int GetAllocatedPoints(ProfessionType profession) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) try { if (_skillPointsUsedField?.GetValue(null) is Dictionary<ProfessionType, int> dictionary && dictionary.TryGetValue(profession, out var value)) { return value; } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)$"[Respec] GetAllocatedPoints({profession}) failed: {ex.Message}"); } } return 0; } public bool TryEstimateExactRefund(Skills skills, ProfessionType profession, out int refundedPoints) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) refundedPoints = 0; if ((Object)(object)skills == (Object)null) { return false; } EnsureReflection(); try { int num = 0; if (_professionNodeDictionaryField?.GetValue(skills) is IDictionary dictionary && dictionary.Contains(profession) && dictionary[profession] is SkillNode[] array) { SkillNode[] array2 = array; foreach (SkillNode val in array2) { if (!((Object)(object)val == (Object)null)) { num++; if (val.active) { refundedPoints += Mathf.Max(1, val.NodeAmount); } } } } if (num > 0) { return true; } refundedPoints = GetAllocatedPoints(profession); return refundedPoints > 0; } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)$"[Respec] TryEstimateExactRefund({profession}) fallback: {ex.Message}"); } refundedPoints = GetAllocatedPoints(profession); return refundedPoints >= 0; } } private Profession ResolveProfessionData(ProfessionType profession) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) GameSave instance = SingletonBehaviour<GameSave>.Instance; if ((Object)(object)instance == (Object)null || instance.CurrentSave == null || instance.CurrentSave.characterData == null) { return null; } if (!instance.CurrentSave.characterData.Professions.TryGetValue(profession, out var value)) { return null; } return value; } private ResetSnapshot CaptureSnapshot(ProfessionType profession, Profession profData) { //IL_00c6: 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_0078: 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) Dictionary<int, int> dictionary = new Dictionary<int, int>(profData.Nodes.Count); foreach (KeyValuePair<int, int> node in profData.Nodes) { dictionary[node.Key] = node.Value; } int skillPointsUsed = 0; int numActiveNodes = 0; try { if (_skillPointsUsedField?.GetValue(null) is Dictionary<ProfessionType, int> dictionary2 && dictionary2.TryGetValue(profession, out var value)) { skillPointsUsed = value; } if (_numActiveNodesField?.GetValue(null) is Dictionary<ProfessionType, int> dictionary3 && dictionary3.TryGetValue(profession, out var value2)) { n