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+5c08b5aa5d0be9c4b93df77f697dc55d5ac97088")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[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
{
private ManualLogSource _pluginLog;
public void StartCheck(string pluginGuid, string currentVersion, ManualLogSource pluginLog, Action<VersionCheckResult> onComplete)
{
_pluginLog = pluginLog;
((MonoBehaviour)this).StartCoroutine(CheckVersionCoroutine(pluginGuid, currentVersion, onComplete));
}
private void LogInfo(string message)
{
ManualLogSource pluginLog = _pluginLog;
if (pluginLog != null)
{
pluginLog.LogInfo((object)("[VersionChecker] " + message));
}
}
private void LogWarningMsg(string message)
{
ManualLogSource pluginLog = _pluginLog;
if (pluginLog != null)
{
pluginLog.LogWarning((object)("[VersionChecker] " + message));
}
}
private void LogErrorMsg(string message)
{
ManualLogSource pluginLog = _pluginLog;
if (pluginLog != null)
{
pluginLog.LogError((object)("[VersionChecker] " + message));
}
}
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);
LogWarningMsg(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);
LogWarningMsg(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);
LogWarningMsg(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)
{
LogInfo("Update available for " + result.ModName + ": " + currentVersion + " -> " + result.LatestVersion);
}
else
{
LogInfo(result.ModName + " is up to date (v" + currentVersion + ")");
}
}
catch (Exception ex)
{
result.Success = false;
result.ErrorMessage = "Parse error: " + ex.Message;
RecordHealthError(pluginGuid, result.ErrorMessage);
LogErrorMsg(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 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_000b: Unknown result type (might be due to invalid IL or missing references)
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, logger, onComplete);
}
public static ModHealthSnapshot GetHealthSnapshot(string pluginGuid)
{
if (string.IsNullOrWhiteSpace(pluginGuid))
{
return null;
}
lock (HealthLock)
{
if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot 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');
int num = v1.IndexOfAny(new char[2] { '-', '+' });
if (num >= 0)
{
v1 = v1.Substring(0, num);
}
int num2 = v2.IndexOfAny(new char[2] { '-', '+' });
if (num2 >= 0)
{
v2 = v2.Substring(0, num2);
}
string[] array = v1.Split(new char[1] { '.' });
string[] array2 = v2.Split(new char[1] { '.' });
int num3 = Math.Max(array.Length, array2.Length);
for (int i = 0; i < num3; i++)
{
int result;
int num4 = ((i < array.Length && int.TryParse(array[i], out result)) ? result : 0);
int result2;
int num5 = ((i < array2.Length && int.TryParse(array2[i], out result2)) ? result2 : 0);
if (num4 < num5)
{
return -1;
}
if (num4 > num5)
{
return 1;
}
}
return 0;
}
private static void TouchHealth(string pluginGuid)
{
if (string.IsNullOrWhiteSpace(pluginGuid))
{
return;
}
lock (HealthLock)
{
if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot 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 ModHealthSnapshot 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 Regex 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)
{
string typeName2 = typeName;
Type type = AccessTools.TypeByName(typeName2);
if (type != null)
{
return type;
}
for (int i = 0; i < namespaces.Length; i++)
{
type = AccessTools.TypeByName(namespaces[i] + "." + typeName2);
if (type != null)
{
return type;
}
}
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
try
{
type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == typeName2 || t.FullName == typeName2);
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;
}
try
{
PropertyInfo property = type.GetProperty(memberName, AllBindingFlags);
if (property != null && property.GetMethod != null && property.GetIndexParameters().Length == 0)
{
return property.GetValue(null);
}
}
catch (AmbiguousMatchException)
{
return 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.3.2")]
public class Plugin : BaseUnityPlugin
{
private Harmony _harmony;
private RespecConfig _config;
private SkillResetService _resetService;
private CostService _costService;
private RespecController _controller;
private bool _applicationQuitting;
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.3.2", Log);
}
catch (Exception ex)
{
Log.LogDebug((object)("[Respec] VersionChecker swallowed: " + ex.Message));
}
Log.LogInfo((object)"Haven's Respec v1.3.2 loaded.");
}
catch (Exception arg)
{
Log.LogError((object)string.Format("{0} Awake failed: {1}", "Haven's Respec", arg));
}
}
private void OnApplicationQuit()
{
_applicationQuitting = true;
}
private void OnDestroy()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
string text = ((Scene)(ref activeScene)).name ?? string.Empty;
string text2 = text.ToLowerInvariant();
if (_applicationQuitting || !Application.isPlaying || text2.Contains("menu") || text2.Contains("title"))
{
ManualLogSource log = Log;
if (log != null)
{
log.LogInfo((object)("[Lifecycle] Haven's Respec OnDestroy during expected teardown (scene: " + text + ")"));
}
}
else
{
ManualLogSource log2 = Log;
if (log2 != null)
{
log2.LogWarning((object)("[Lifecycle] Haven's Respec OnDestroy outside expected teardown (scene: " + text + ")"));
}
}
try
{
_controller?.Uninstall();
}
catch (Exception ex)
{
ManualLogSource log3 = Log;
if (log3 != null)
{
log3.LogWarning((object)("Haven's Respec OnDestroy: Uninstall failed: " + ex.Message));
}
}
finally
{
try
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
catch (Exception ex2)
{
ManualLogSource log4 = Log;
if (log4 != null)
{
log4.LogWarning((object)("Haven's Respec OnDestroy: UnpatchSelf failed: " + ex2.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.3.2";
}
}
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)
Action onClick2 = onClick;
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
{
onClick2?.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)
Action onClick2 = onClick;
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
{
onClick2?.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)
Skills skills2 = skills;
_activeSkills = skills2;
if (_injectors.TryGetValue(profession, out RespecButtonInjector 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(skills2, profession, _config.ShiftSkipsConfirmation.Value && IsShiftHeld());
};
respecButtonInjector.OnUndoClicked += delegate
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
PerformUndo(skills2, profession);
};
respecButtonInjector.SetUndoVisible(_config.EnableUndo.Value && _resetService.HasUndo(profession));
_injectors[profession] = respecButtonInjector;
EnsureDialog((Component)(object)panel);
EnsureResetAllButton(skills2, 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)
Skills skills2 = skills;
int estimatedPoints = ResolveEstimatedRefund(skills2, 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(skills2, profession, estimatedPoints);
return;
}
EnsureDialog((Component)(object)skills2);
if ((Object)(object)_dialog == (Object)null)
{
PerformReset(skills2, 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(skills2, 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 RespecButtonInjector 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 ResetSnapshot 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 RespecButtonInjector 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)
Skills skills2 = skills;
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(skills2, 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(skills2);
return;
}
EnsureDialog((Component)(object)skills2);
if ((Object)(object)_dialog == (Object)null)
{
PerformResetAll(skills2);
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(skills2);
});
}
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)
Skills skills2 = skills;
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(skills2, _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 Sprite 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 Sprite 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 Stack<ResetSnapshot> 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 Stack<ResetSnapshot> 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 Stack<ResetSnapshot> 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