Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LevelingSystem SharingXP v2.5.5
DW.CharacterProgression.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CharacterProgressionMod.Commands; using CharacterProgressionMod.Core; using CharacterProgressionMod.Patches; using CharacterProgressionMod.Skills; using CharacterProgressionMod.UI; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using MonoMod.Utils; using Newtonsoft.Json; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("LevelingSystem")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("LevelingSystem")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4d2a4a69-cbcf-4527-b504-7c1d1d3b3696")] [assembly: AssemblyFileVersion("2.5.5")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.5.5.0")] [module: UnverifiableCode] namespace CharacterProgressionMod { public sealed class RewardExpOnDeath : MonoBehaviour { private Character _character; private XpTable _creatureExperienceTable; private Player _lastPlayerAttacker; private float _lastPlayerAttackTime; public static XpTable CreatureExperienceTable { get; set; } public static float NearbyPlayerXpRadius { get; set; } = 50f; public static float LevelXpBonusPerStar { get; set; } = 0.5f; private void Start() { if (((Component)this).TryGetComponent<Character>(ref _character)) { _creatureExperienceTable = CreatureExperienceTable; Character character = _character; character.m_onDeath = (Action)Delegate.Combine(character.m_onDeath, new Action(Character_OnDeath)); } } private void Character_OnDeath() { //IL_0110: 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_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) Logger.LogDebug((object)$"Are we the owner of {((Object)_character).name}?: {_character.IsOwner()}"); Character character = _character; character.m_onDeath = (Action)Delegate.Remove(character.m_onDeath, new Action(Character_OnDeath)); if (!_character.IsOwner()) { return; } string key = ((Object)_character).name.Replace("(Clone)", "").Trim(); int num = (_creatureExperienceTable ?? CreatureExperienceTable)?.GetXp(key) ?? 0; if (num <= 0) { return; } int num2 = Mathf.Max(0, _character.GetLevel() - 1); float num3 = PluginRuntime.Config?.CreatureLevelXpBonusPerStar.Value ?? LevelXpBonusPerStar; float num4 = PluginRuntime.Config?.NearbyXpRadius.Value ?? NearbyPlayerXpRadius; num = Mathf.Max(1, Mathf.RoundToInt((float)num * (1f + (float)num2 * num3))); Vector3 position = ((Component)_character).transform.position; PlayerLevelProgression playerLevelProgression = default(PlayerLevelProgression); foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null) && !((Character)allPlayer).IsDead() && !(Vector3.Distance(((Component)allPlayer).transform.position, position) > num4) && ((Component)allPlayer).TryGetComponent<PlayerLevelProgression>(ref playerLevelProgression)) { playerLevelProgression.AddExperience(num); } } } public void RegisterPlayerAttacker(Player player) { if (!((Object)(object)player == (Object)null)) { _lastPlayerAttacker = player; _lastPlayerAttackTime = Time.time; } } public Player GetRecentPlayerAttacker(float maximumAgeSeconds = 30f) { if (!((Object)(object)_lastPlayerAttacker != (Object)null) || !(Time.time - _lastPlayerAttackTime <= maximumAgeSeconds)) { return null; } return _lastPlayerAttacker; } } public class BiomeExperienceConfig { public class ExperienceCategory { public string Name { get; } public int BaseExp { get; set; } public float TierMultiplier { get; set; } public ExperienceCategory(string name, int baseExp, float tierMultiplier = 1f) { Name = name; BaseExp = baseExp; TierMultiplier = tierMultiplier; } } public ExperienceCategory Foraging { get; } = new ExperienceCategory("Foraging", 5); public ExperienceCategory Woodcutting { get; } = new ExperienceCategory("Woodcutting", 10, 1.2f); public ExperienceCategory Mining { get; } = new ExperienceCategory("Mining", 5, 1.2f); public ExperienceCategory CreatureKilling { get; } = new ExperienceCategory("CreatureKilling", 2, 2f); } public readonly struct LevelEvaluationResult { public int Level { get; } public int MaxExperience { get; } public int TotalExperience { get; } public int NextLevelTotalExperience { get; } public bool IsMaxLevel { get; } public LevelEvaluationResult(int level, int maxExperience, int totalExperience, int nextLevelTotalExperience, bool isMaxLevel) { Level = level; MaxExperience = maxExperience; TotalExperience = totalExperience; NextLevelTotalExperience = nextLevelTotalExperience; IsMaxLevel = isMaxLevel; } public float EvaluateProgressPercentage(int currentTotalExperience) { if (IsMaxLevel || MaxExperience <= 0) { return 100f; } return Mathf.Clamp((float)(currentTotalExperience - TotalExperience) / (float)MaxExperience * 100f, 0f, 100f); } public override string ToString() { return $"{Level} | {MaxExperience} | {TotalExperience} | {NextLevelTotalExperience} | {IsMaxLevel}"; } } public class LevelTableGenerationSettings { public int MaxLevel { get; } public int InitialMaxExperience { get; } public MaxExperienceModifierFormula MaxExperienceModifierFormula { get; } public LevelTableGenerationSettings(int maxLevel, int initialMaxExperience, string maxExperienceModifierFormula) { MaxLevel = maxLevel; InitialMaxExperience = initialMaxExperience; MaxExperienceModifierFormula = new MaxExperienceModifierFormula(maxExperienceModifierFormula); } } public class MaxExperienceModifierFormula { private struct Modifier { public int Level { get; } public int Value { get; } public bool IsValuePercentage { get; } public Modifier(int level, int value, bool isValuePercentage) { Level = level; Value = value; IsValuePercentage = isValuePercentage; } } private readonly Modifier[] _modifiers; public MaxExperienceModifierFormula(string formula) { List<Modifier> list = new List<Modifier>(5); string[] array = new string(formula.Where((char c) => !char.IsWhiteSpace(c)).ToArray()).Split(new char[1] { ';' }); for (int num = 0; num < array.Length; num++) { string[] array2 = array[num].Split(new char[1] { '=' }); if (array2.Length != 2) { continue; } string text = array2[0]; if (!IsInteger(text)) { continue; } int level = int.Parse(text, NumberStyles.Integer); string text2 = array2[1]; bool isValuePercentage = false; int value; if (IsPercentage(text2)) { text2 = text2.TrimEnd(new char[1] { '%' }); value = int.Parse(text2, NumberStyles.Integer); isValuePercentage = true; } else { if (!IsInteger(text2)) { if (!IsArray(text2)) { continue; } text2 = text2.Trim('[', ']'); string[] array3 = text2.Split(new char[1] { ',' }); foreach (string text3 in array3) { if (IsPercentage(text3) && int.TryParse(text3.TrimEnd(new char[1] { '%' }), out var result)) { list.Add(new Modifier(level, result, isValuePercentage: true)); } else if (IsInteger(text3)) { value = int.Parse(text3, NumberStyles.Integer); list.Add(new Modifier(level, value, isValuePercentage: false)); } } continue; } value = int.Parse(text2, NumberStyles.Integer); } list.Add(new Modifier(level, value, isValuePercentage)); static bool IsArray(string text4) { return text4.StartsWith("["); } static bool IsInteger(string source) { return source.All(char.IsDigit); } static bool IsPercentage(string text4) { return text4.EndsWith("%"); } } _modifiers = list.ToArray(); } public int Evaluate(int level, int oldMaxExperience) { Modifier lastValidKey = _modifiers.LastOrDefault((Modifier key) => level >= key.Level); IEnumerable<Modifier> enumerable = _modifiers.Where((Modifier key) => key.Level == lastValidKey.Level); int num = oldMaxExperience; foreach (Modifier item in enumerable) { num = ((!item.IsValuePercentage) ? (num + item.Value) : (num + Mathf.CeilToInt((float)oldMaxExperience * ((float)item.Value / 100f)))); } return num; } } public class LevelExperienceTable { private readonly int[] _entries; public int MaxLevel { get; } public LevelExperienceTable(int[] entries) { _entries = (int[])entries.Clone(); MaxLevel = _entries.Length + 1; Logger.LogDebug((object)$"Player level table has been created! Max level is {MaxLevel}."); } public LevelExperienceTable(LevelTableGenerationSettings generationSettings) { int num = generationSettings.MaxLevel - 1; _entries = new int[num]; int num2 = generationSettings.InitialMaxExperience; for (int i = 0; i < _entries.Length; i++) { _entries[i] = num2; int level = i + 2; num2 = generationSettings.MaxExperienceModifierFormula.Evaluate(level, num2); } MaxLevel = _entries.Length + 1; Logger.LogDebug((object)$"Player level table has been created! Max level is {MaxLevel}."); } internal int[] ExportEntries() { return (int[])_entries.Clone(); } public int GetMaxExperience(int level) { int num = level - 1; if (num < 0 || num >= _entries.Length) { Logger.LogError((object)$"Level {level} is out of range. Max level is {_entries.Length}."); return 1; } return _entries[num]; } public int GetTotalExperience(int level) { if (MaxLevel <= 1) { return 0; } int num = 0; for (int i = 0; i < _entries.Length && i + 1 < level; i++) { num += _entries[i]; } return num; } public LevelEvaluationResult EvaluateLevel(int totalExperience) { totalExperience = Math.Max(0, totalExperience); int num = 0; for (int i = 0; i < _entries.Length; i++) { int num2 = _entries[i]; num += num2; if (totalExperience < num) { int nextLevelTotalExperience = num; int totalExperience2 = num - num2; return new LevelEvaluationResult(i + 1, num2, totalExperience2, nextLevelTotalExperience, isMaxLevel: false); } } return new LevelEvaluationResult(MaxLevel, 0, num, num, isMaxLevel: true); } } public sealed class PlayerLevelProgression : MonoBehaviour { private const string TotalExpSaveKey = "Cozyheim!TotalExperience"; private const string LevelSaveKey = "Cozyheim!Level"; private const string LegacyExpSaveKey = "CozyXP"; private const string LegacyLevelSaveKey = "CozyLevel"; private static readonly int NetworkLevelKey = StringExtensionMethods.GetStableHashCode("LevelingSystem.Level"); private Player _player; private string _addExperienceRpcId; private string _setLevelRpcId; private LevelExperienceTable _levelExperienceTable; private LevelEvaluationResult _currentLevelEvaluation; private bool _legacyMigrationChecked; private bool _playerDataLoading; private bool _playerDataReady; private bool _hasCurrentLevelEvaluation; private int _totalExperience; public PluginConfig Config { get; set; } public LevelExperienceTable LevelExperienceTable { get { return _levelExperienceTable; } set { if (_levelExperienceTable != value) { _levelExperienceTable = value; if ((Object)(object)_player != (Object)null && _playerDataReady) { UpdateLevel(); } } } } public LevelEvaluationResult CurrentLevelEvaluation => _currentLevelEvaluation; public event Action<int, int> ExperienceChanged; public event Action<int, int> LevelChanged; private void Awake() { _addExperienceRpcId = RpcId.Generate("AddExperience"); _setLevelRpcId = RpcId.Generate("SetLevel"); _player = ((Component)this).GetComponent<Player>(); ZNetView nview = ((Character)_player).m_nview; if (((nview != null) ? nview.GetZDO() : null) != null) { ((Character)_player).m_nview.Register<int>(_addExperienceRpcId, (Action<long, int>)RPC_AddExperience); ((Character)_player).m_nview.Register<int>(_setLevelRpcId, (Action<long, int>)RPC_SetLevel); } } private void Start() { if (!_playerDataReady && !_playerDataLoading) { LoadProgressionFromPlayerData(); } } public void BeginPlayerDataLoad() { _playerDataLoading = true; _playerDataReady = false; _hasCurrentLevelEvaluation = false; } public void CompletePlayerDataLoad() { _playerDataLoading = false; _legacyMigrationChecked = false; LoadProgressionFromPlayerData(); } public void PrepareForPlayerSave() { if (_playerDataReady && !_playerDataLoading && (Object)(object)_player != (Object)null && ((Character)_player).IsOwner()) { PersistProgression(); } } public void AddExperience(int expReward) { if (expReward <= 0 || (Object)(object)_player == (Object)null) { return; } ZNetView nview = ((Character)_player).m_nview; if (((nview != null) ? nview.GetZDO() : null) != null) { if (((Character)_player).IsOwner()) { RPC_AddExperience(0L, expReward); return; } ((Character)_player).m_nview.InvokeRPC(_addExperienceRpcId, new object[1] { expReward }); } } public void SetLevel(int level) { if (((Character)_player).IsOwner() && _levelExperienceTable != null) { level = Mathf.Clamp(level, 1, _levelExperienceTable.MaxLevel); SetTotalExperience(_levelExperienceTable.GetTotalExperience(level), 0); } } public void RequestSetLevel(int level) { if ((Object)(object)_player == (Object)null) { return; } ZNetView nview = ((Character)_player).m_nview; if (((nview != null) ? nview.GetZDO() : null) != null) { if (((Character)_player).IsOwner()) { SetLevel(level); return; } ((Character)_player).m_nview.InvokeRPC(_setLevelRpcId, new object[1] { level }); } } private void RPC_SetLevel(long sender, int level) { if (!((Character)_player).IsOwner()) { return; } if (sender != 0L && (Object)(object)ZNet.instance != (Object)null) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null || serverPeer.m_uid != sender) { Logger.LogWarning((object)$"Rejected a progression level change from peer {sender}."); return; } } SetLevel(level); } private void RPC_AddExperience(long sender, int expReward) { if (((Character)_player).IsOwner() && expReward > 0) { float num = 1f; float num2 = Config?.XpRewardRandomSpread.Value ?? 0.05f; num *= Random.Range(1f - num2, 1f + num2); if (((Character)_player).GetSEMan().HaveStatusEffect(SEMan.s_statusEffectRested)) { num *= Config?.RestedXpMultiplier.Value ?? 1.3f; } PlayerSkillProgression playerSkillProgression = default(PlayerSkillProgression); if (((Component)_player).TryGetComponent<PlayerSkillProgression>(ref playerSkillProgression)) { num *= playerSkillProgression.GetMultiplier(SkillId.ExperienceGain); } float num3 = (float)expReward * num; int num4 = ((num3 >= 2.1474836E+09f) ? int.MaxValue : Mathf.Max(1, Mathf.RoundToInt(num3))); int totalExperience = (int)Math.Min(2147483647L, (long)GetTotalExperience() + (long)num4); Logger.LogDebug((object)$"Added {num4:N0} experience (x{num:F2})"); SetTotalExperience(totalExperience, num4); } } private void SetTotalExperience(int totalExperience, int awardedExperience) { if (!_playerDataReady && !_playerDataLoading) { LoadProgressionFromPlayerData(); } if (_playerDataReady) { _totalExperience = Mathf.Max(0, totalExperience); _player.m_customData["Cozyheim!TotalExperience"] = _totalExperience.ToString(CultureInfo.InvariantCulture); UpdateLevel(); float num = _currentLevelEvaluation.EvaluateProgressPercentage(_totalExperience); Logger.LogDebug((object)($"Level progress: {_totalExperience - _currentLevelEvaluation.TotalExperience:N0} / " + $"{_currentLevelEvaluation.MaxExperience:N0} ({num:F0}%)")); this.ExperienceChanged?.Invoke(awardedExperience, _totalExperience); } } public int GetTotalExperience() { if (_playerDataReady) { return _totalExperience; } return ReadTotalExperienceFromPlayerData(); } public int GetLevel() { if ((Object)(object)_player != (Object)null && !((Character)_player).IsOwner()) { ZNetView nview = ((Character)_player).m_nview; int? obj; if (nview == null) { obj = null; } else { ZDO zDO = nview.GetZDO(); obj = ((zDO != null) ? new int?(zDO.GetInt(NetworkLevelKey, 1)) : ((int?)null)); } return Mathf.Max(1, obj ?? 1); } if (_playerDataReady && _hasCurrentLevelEvaluation) { return Mathf.Max(1, _currentLevelEvaluation.Level); } if (!_player.m_customData.TryGetValue("Cozyheim!Level", out var value) || !int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return 1; } return Mathf.Max(1, result); } public float GetProgress01() { if (_hasCurrentLevelEvaluation) { return _currentLevelEvaluation.EvaluateProgressPercentage(GetTotalExperience()) / 100f; } return 0f; } private void UpdateLevel() { if (_levelExperienceTable == null || (Object)(object)_player == (Object)null || !_playerDataReady) { return; } MigrateLegacyProgression(); int level = GetLevel(); _currentLevelEvaluation = _levelExperienceTable.EvaluateLevel(GetTotalExperience()); _hasCurrentLevelEvaluation = true; int level2 = _currentLevelEvaluation.Level; _player.m_customData["Cozyheim!Level"] = level2.ToString(CultureInfo.InvariantCulture); if (((Character)_player).IsOwner()) { ZNetView nview = ((Character)_player).m_nview; if (nview != null) { ZDO zDO = nview.GetZDO(); if (zDO != null) { zDO.Set(NetworkLevelKey, level2, false); } } } if (level != level2) { this.LevelChanged?.Invoke(level, level2); } Logger.LogDebug((object)_currentLevelEvaluation.ToString()); } private void LoadProgressionFromPlayerData() { if (!((Object)(object)_player == (Object)null) && _levelExperienceTable != null && !_playerDataLoading) { _playerDataReady = true; if (!((Character)_player).IsOwner()) { _totalExperience = 0; _hasCurrentLevelEvaluation = false; return; } MigrateLegacyProgression(); _totalExperience = ReadTotalExperienceFromPlayerData(); _hasCurrentLevelEvaluation = false; UpdateLevel(); } } private int ReadTotalExperienceFromPlayerData() { if ((Object)(object)_player == (Object)null) { return 0; } int result = 0; result = ((_player.m_customData.TryGetValue("Cozyheim!TotalExperience", out var value) && int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)) ? Mathf.Max(0, result) : 0); if (result == 0 && _player.m_customData.TryGetValue("Cozyheim!Level", out var value2) && int.TryParse(value2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && result2 > 1) { int num = Mathf.Clamp(result2, 1, _levelExperienceTable.MaxLevel); int totalExperience = _levelExperienceTable.GetTotalExperience(num); Logger.LogWarning((object)($"Recovered missing total XP from saved level {num}: " + $"{totalExperience:N0} total XP.")); return totalExperience; } return result; } private void PersistProgression() { _totalExperience = Mathf.Max(0, _totalExperience); if (!_hasCurrentLevelEvaluation) { _currentLevelEvaluation = _levelExperienceTable.EvaluateLevel(_totalExperience); _hasCurrentLevelEvaluation = true; } _player.m_customData["Cozyheim!TotalExperience"] = _totalExperience.ToString(CultureInfo.InvariantCulture); _player.m_customData["Cozyheim!Level"] = Mathf.Max(1, _currentLevelEvaluation.Level).ToString(CultureInfo.InvariantCulture); ZNetView nview = ((Character)_player).m_nview; if (nview != null) { ZDO zDO = nview.GetZDO(); if (zDO != null) { zDO.Set(NetworkLevelKey, Mathf.Max(1, _currentLevelEvaluation.Level), false); } } } private void MigrateLegacyProgression() { if (_legacyMigrationChecked || !((Character)_player).IsOwner() || _levelExperienceTable == null) { return; } _legacyMigrationChecked = true; if (_player.m_customData.ContainsKey("Cozyheim!TotalExperience")) { return; } int value; bool flag = TryReadCustomInt("CozyLevel", out value); int value2; bool flag2 = TryReadCustomInt("CozyXP", out value2); if (flag || flag2) { value = ((!flag) ? 1 : Mathf.Max(1, value)); value2 = (flag2 ? Mathf.Max(0, value2) : 0); int num = Mathf.Clamp(value, 1, _levelExperienceTable.MaxLevel); int num2 = _levelExperienceTable.GetTotalExperience(num); if (num < _levelExperienceTable.MaxLevel && value2 > 0) { int maxExperience = _levelExperienceTable.GetMaxExperience(num); int num3 = TryGetLegacyLevelRequirement(value); float num4 = ((num3 > 0) ? Mathf.Clamp01((float)value2 / (float)num3) : Mathf.Clamp01((float)value2 / (float)maxExperience)); int num5 = Mathf.Min(Mathf.RoundToInt((float)maxExperience * num4), Mathf.Max(0, maxExperience - 1)); num2 += num5; } _player.m_customData["Cozyheim!TotalExperience"] = num2.ToString(CultureInfo.InvariantCulture); _player.m_customData["Cozyheim!Level"] = num.ToString(CultureInfo.InvariantCulture); Logger.LogInfo((object)($"Migrated legacy progression: level {value}, {value2} XP -> " + $"level {num}, {num2} total XP.")); } } private bool TryReadCustomInt(string key, out int value) { value = 0; if (_player.m_customData.TryGetValue(key, out var value2)) { return int.TryParse(value2, NumberStyles.Integer, CultureInfo.InvariantCulture, out value); } return false; } private static int TryGetLegacyLevelRequirement(int level) { try { string path = Path.Combine(Paths.ConfigPath, "LevelingSystem", "PlayerXP", "Player XP Table.json"); if (!File.Exists(path)) { return 0; } Dictionary<string, int> dictionary = JsonConvert.DeserializeObject<Dictionary<string, int>>(File.ReadAllText(path)); int value; return (dictionary != null && dictionary.TryGetValue("Lv" + level, out value)) ? Mathf.Max(0, value) : 0; } catch (Exception ex) { Logger.LogWarning((object)("Could not read the legacy player XP table; raw progress will be preserved instead: " + ex.Message)); return 0; } } } public sealed class XpTable { private const string EmbeddedConfigPath = "CharacterProgressionMod.Resources.default_configs"; private readonly Dictionary<string, int> _entries = new Dictionary<string, int>(); private readonly Dictionary<string, string> _groups = new Dictionary<string, string>(); public string NameId { get; } public bool AllowGroups { get; } public string CustomConfigFolderPath { get; } public string CustomGroupsFolderPath { get; } public XpTable(Assembly resourceAssembly, string customFolderPath, bool allowGroups) { if (string.IsNullOrEmpty(customFolderPath)) { Logger.LogError((object)"A critical error occurred during the initialization of the leveling system. Please report this to the mod author."); throw new ArgumentException("The customFolderPath parameter cannot be null or empty."); } NameId = Path.GetFileName(customFolderPath).ToLowerInvariant(); AllowGroups = allowGroups; CustomConfigFolderPath = customFolderPath; CustomGroupsFolderPath = Path.Combine(customFolderPath, "groups"); VerifyAndSetupConfigDirectory(); if ((object)resourceAssembly == null) { Logger.LogError((object)"A critical error occurred during the initialization of the leveling system. Please report this to the mod author."); throw new ArgumentNullException("The resourceAssembly parameter cannot be null."); } LoadEmbeddedResources(resourceAssembly); LoadCustomResources(); Logger.LogDebug((object)$"Loaded {NameId} xp table with {_entries.Count} entries."); if (AllowGroups) { Logger.LogDebug((object)$"Loaded {NameId} groups with {_groups.Count} entries."); } } internal Dictionary<string, int> ExportEntries() { return new Dictionary<string, int>(_entries); } internal Dictionary<string, string> ExportGroups() { return new Dictionary<string, string>(_groups); } internal void ReplaceEntries(Dictionary<string, int> entries, Dictionary<string, string> groups) { _entries.Clear(); _groups.Clear(); foreach (KeyValuePair<string, int> entry in entries) { _entries[entry.Key] = entry.Value; } foreach (KeyValuePair<string, string> group in groups) { _groups[group.Key] = group.Value; } } private void VerifyAndSetupConfigDirectory() { bool num = Directory.Exists(CustomConfigFolderPath); bool flag = Directory.Exists(CustomGroupsFolderPath); if (!(num && flag)) { Logger.LogDebug((object)("Creating directories for custom " + NameId + " configs.")); Directory.CreateDirectory(CustomConfigFolderPath); Directory.CreateDirectory(CustomGroupsFolderPath); } } private void LoadEmbeddedResources(Assembly resourceAssembly) { string[] manifestResourceNames = resourceAssembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { string pattern = "^CharacterProgressionMod.Resources.default_configs\\." + NameId + "\\.xp_tables\\.(?:[\\w-]+).json"; if (Regex.IsMatch(text, pattern)) { Dictionary<string, int> dictionary = JsonConvert.DeserializeObject<Dictionary<string, int>>(AssetUtils.LoadTextFromResources(text, resourceAssembly)); if (dictionary.Count == 0) { Logger.LogError((object)("Skipped loading embedded " + NameId + " xp table file at '" + text + "' - no entries found. Please report this to the mod author.")); } else { Extensions.AddRange<string, int>(_entries, dictionary); } } else { if (!AllowGroups) { continue; } string pattern2 = "^CharacterProgressionMod.Resources.default_configs\\." + NameId + "\\.groups\\.(?:[\\w-]+).json"; if (!Regex.IsMatch(text, pattern2)) { continue; } Dictionary<string, string[]> dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, string[]>>(AssetUtils.LoadTextFromResources(text, resourceAssembly)); if (dictionary2.Count == 0) { Logger.LogError((object)("Skipped loading embedded " + NameId + " group file at '" + text + "' - no entries found. Please report this to the mod author.")); continue; } CollectionExtensions.Do<KeyValuePair<string, string[]>>((IEnumerable<KeyValuePair<string, string[]>>)dictionary2, (Action<KeyValuePair<string, string[]>>)delegate(KeyValuePair<string, string[]> pair) { CollectionExtensions.Do<string>((IEnumerable<string>)pair.Value, (Action<string>)delegate(string groupEntry) { _groups[groupEntry] = pair.Key; }); }); } } } private void LoadCustomResources() { if (!Directory.Exists(CustomConfigFolderPath)) { VerifyAndSetupConfigDirectory(); return; } string[] files = Directory.GetFiles(CustomConfigFolderPath, "*.json", SearchOption.TopDirectoryOnly); if (files.Length == 0) { Logger.LogDebug((object)("Skipping loading custom " + NameId + " configs - no files found in the custom config folder.")); return; } string[] array = files; foreach (string text in array) { Dictionary<string, int> dictionary = JsonConvert.DeserializeObject<Dictionary<string, int>>(File.ReadAllText(text)); if (dictionary.Count == 0) { Logger.LogWarning((object)("Skipped loading custom " + NameId + " xp table file at '" + text + "' - no entries found.")); } else { CollectionExtensions.Do<KeyValuePair<string, int>>((IEnumerable<KeyValuePair<string, int>>)dictionary, (Action<KeyValuePair<string, int>>)delegate(KeyValuePair<string, int> pair) { _entries[pair.Key] = pair.Value; }); } } if (!AllowGroups || !Directory.Exists(CustomGroupsFolderPath)) { return; } files = Directory.GetFiles(CustomGroupsFolderPath, "*.json", SearchOption.TopDirectoryOnly); array = files; foreach (string text2 in array) { Dictionary<string, string[]> dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, string[]>>(File.ReadAllText(text2)); if (dictionary2.Count == 0) { Logger.LogWarning((object)("Skipped loading custom " + NameId + " group file at '" + text2 + "' - no entries found.")); continue; } CollectionExtensions.Do<KeyValuePair<string, string[]>>((IEnumerable<KeyValuePair<string, string[]>>)dictionary2, (Action<KeyValuePair<string, string[]>>)delegate(KeyValuePair<string, string[]> pair) { CollectionExtensions.Do<string>((IEnumerable<string>)pair.Value, (Action<string>)delegate(string groupEntry) { _groups[groupEntry] = pair.Key; }); }); } } public void ReloadResources() { _entries.Clear(); _groups.Clear(); Assembly callingAssembly = ReflectionHelper.GetCallingAssembly(); LoadEmbeddedResources(callingAssembly); LoadCustomResources(); } public int GetXp(string key) { key = key.Replace("(Clone)", ""); if (_entries.TryGetValue(key, out var value)) { Logger.LogDebug((object)$"Found xp for '{key}': {value} xp"); return value; } if (!AllowGroups || _groups.Count == 0) { Logger.LogDebug((object)("Skipping group check - groups are not allowed for the " + NameId + " xp table.")); return 0; } if (!_groups.TryGetValue(key, out var value2)) { Logger.LogDebug((object)("Failed to find a group for '" + key + "'.")); return 0; } Logger.LogDebug((object)("Found group '" + value2 + "' for '" + key + "'.")); if (!_entries.TryGetValue(value2, out value)) { return 0; } return value; } } } namespace CharacterProgressionMod.UI { internal sealed class FloatingTextEffect : MonoBehaviour { private string _value; private Color _color = Color.white; public void Configure(string value, Color color) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) _value = value; _color = color; } private IEnumerator Start() { Text componentInChildren = ((Component)this).GetComponentInChildren<Text>(); CanvasGroup group = ((Component)this).GetComponentInChildren<CanvasGroup>() ?? ((Component)this).gameObject.AddComponent<CanvasGroup>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = _value; ((Graphic)componentInChildren).color = _color; } Vector3 origin = ((Component)this).transform.position; Vector3 initialScale = ((Component)this).transform.localScale; for (float time = 0f; time < 2.2f; time += Time.deltaTime) { float num = time / 2.2f; ((Component)this).transform.position = origin + Vector3.up * (0.85f * num); group.alpha = Mathf.Sin(num * (float)Math.PI); ((Component)this).transform.localScale = initialScale * Mathf.Lerp(0.75f, 1.1f, Mathf.Sin(num * (float)Math.PI)); yield return null; } Object.Destroy((Object)(object)((Component)this).gameObject); } private void LateUpdate() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Camera.main != (Object)null) { ((Component)this).transform.rotation = ((Component)Camera.main).transform.rotation; } } } internal sealed class LocalPlayerUiSpawner : MonoBehaviour { private IEnumerator Start() { Player player = ((Component)this).GetComponent<Player>(); while ((Object)(object)player != (Object)null && (Object)(object)Player.m_localPlayer != (Object)(object)player) { yield return null; } while ((Object)(object)player != (Object)null && (Object)(object)ProgressionUiController.Instance == (Object)null) { GameObject val = PluginRuntime.Resources?.LevelingSystemUiPrefab; if ((Object)(object)val != (Object)null) { GameObject obj = Object.Instantiate<GameObject>(val); ((Object)obj).name = "LevelingSystemUI_Modern"; ((Object)obj).hideFlags = (HideFlags)0; obj.SetActive(true); break; } yield return null; } } } internal sealed class ProgressionUiController : MonoBehaviour { private readonly List<Button> _categoryButtons = new List<Button>(); private readonly List<RectTransform> _categoryContainers = new List<RectTransform>(); private readonly List<SkillCardView> _cards = new List<SkillCardView>(); private Player _player; private PlayerLevelProgression _progression; private PlayerSkillProgression _skills; private CanvasGroup _xpBarGroup; private CanvasGroup _skillsGroup; private Canvas _menuCanvas; private CanvasGroup _levelUpGroup; private RectTransform _xpBarRect; private RectTransform _xpBarContainer; private RectTransform _content; private Text _levelText; private Text _levelShadow; private Text _xpText; private Text _xpShadow; private Text _levelUpText; private Text _levelUpShadow; private Text _remainingPoints; private Image _xpFill; private ScrollRect _scrollRect; private Scrollbar _scrollbar; private Button _closeButton; private Button _resetButton; private GameObject _skillPrefab; private GameObject _skillDetailsPanel; private Text _skillDetailsTitle; private Text _skillDetailsBody; private GameObject _skillsShortcutHud; private bool _initialized; private bool _menuVisible; private int _currentCategory; private float _targetFill; private float _fillVelocity; private float _nextIntegrityCheck; public static ProgressionUiController Instance { get; private set; } private void Awake() { //IL_01d7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; _levelText = Find<Text>("XP Bar/LevelText"); _levelShadow = Find<Text>("XP Bar/LevelText/Shadow"); _xpText = Find<Text>("XP Bar/XP Bar/XPText"); _xpShadow = Find<Text>("XP Bar/XP Bar/XPText/Shadow"); _xpFill = Find<Image>("XP Bar/XP Bar/XPFill"); _xpBarGroup = Find<CanvasGroup>("XP Bar"); _xpBarContainer = ((Component)((Component)this).transform.Find("XP Bar")).GetComponent<RectTransform>(); _xpBarRect = ((Component)((Component)this).transform.Find("XP Bar/XP Bar")).GetComponent<RectTransform>(); _levelUpText = Find<Text>("LevelUp Pop-Up/LevelUpText"); _levelUpShadow = Find<Text>("LevelUp Pop-Up/LevelUpText/Shadow"); _levelUpGroup = Find<CanvasGroup>("LevelUp Pop-Up"); _skillsGroup = Find<CanvasGroup>("Skills UI"); _remainingPoints = Find<Text>("Skills UI/Remaining Points"); _closeButton = Find<Button>("Skills UI/Close Menu"); _resetButton = Find<Button>("Skills UI/Reset Skills Button"); _content = ((Component)((Component)this).transform.Find("Skills UI/Scroll View/Viewport/Content")).GetComponent<RectTransform>(); _scrollRect = Find<ScrollRect>("Skills UI"); _scrollbar = Find<Scrollbar>("Skills UI/Scrollbar"); Transform val = ((Component)this).transform.Find("Skills UI/Scroll View/Category Buttons"); while (val.childCount < Enum.GetValues(typeof(SkillCategory)).Length) { GameObject obj = Object.Instantiate<GameObject>(((Component)val.GetChild(val.childCount - 1)).gameObject, val); ((Object)obj).name = "Category Button (Rare)"; Image component = obj.GetComponent<Image>(); if ((Object)(object)component != (Object)null) { ((Graphic)component).color = new Color(0.48f, 0.25f, 0.68f, 1f); } } for (int i = 0; i < val.childCount; i++) { _categoryButtons.Add(((Component)val.GetChild(i)).GetComponent<Button>()); } while (((Transform)_content).childCount < Enum.GetValues(typeof(SkillCategory)).Length) { ((Object)Object.Instantiate<GameObject>(((Component)((Transform)_content).GetChild(((Transform)_content).childCount - 1)).gameObject, (Transform)(object)_content)).name = "Rare Skills"; } for (int j = 0; j < ((Transform)_content).childCount; j++) { _categoryContainers.Add(((Component)((Transform)_content).GetChild(j)).GetComponent<RectTransform>()); } } private IEnumerator Start() { _levelUpGroup.alpha = 0f; ToggleMenu(visible: false); while ((Object)(object)Player.m_localPlayer == (Object)null || !((Component)Player.m_localPlayer).TryGetComponent<PlayerLevelProgression>(ref _progression) || !((Component)Player.m_localPlayer).TryGetComponent<PlayerSkillProgression>(ref _skills)) { yield return null; } BindPlayer(Player.m_localPlayer, _progression, _skills); _skillPrefab = PluginRuntime.Resources?.SkillUiPrefab; if ((Object)(object)_skillPrefab == (Object)null) { Logger.LogError((object)"SkillUI prefab was not registered."); yield break; } ConfigureLayout(); ConfigureButtons(); CreateSkillDetailsPanel(); CreateSkillsShortcutHud(); OpenCategory(0); RefreshAll(); _initialized = true; int num = SkillCatalog.Definitions.Count((SkillDefinition definition) => definition.Enabled); Logger.LogInfo((object)($"Modern progression UI initialized with {num} skills; " + "localization probe: '" + Localize("$ls_level") + "'.")); } private void Update() { //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) if (!_initialized) { return; } if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)Player.m_localPlayer != (Object)(object)_player) { TryRebindLocalPlayer(); } if (_menuVisible && Input.GetKeyDown((KeyCode)27)) { ToggleMenu(visible: false); } else if (!IsTyping()) { KeyboardShortcut value = PluginRuntime.Config.OpenSkillsMenu.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { ToggleMenu(!_menuVisible); } } _xpFill.fillAmount = Mathf.SmoothDamp(_xpFill.fillAmount, _targetFill, ref _fillVelocity, 0.18f, 8f); if (_menuVisible && Time.unscaledTime >= _nextIntegrityCheck) { _nextIntegrityCheck = Time.unscaledTime + 0.75f; EnsureCurrentCategoryIntegrity(); } } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } if (_menuVisible) { GUIManager.BlockInput(false); } UnbindPlayer(); } private void LateUpdate() { if (_menuVisible) { ConfigureMenuSorting(); } } private void ConfigureLayout() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00d8: Unknown result type (might be due to invalid IL or missing references) PluginConfig config = PluginRuntime.Config; ConfigureSkillsWindowLayout(); ConfigureRaycastTargets(); _xpBarGroup.alpha = ((config.ShowXp.Value || config.ShowLevel.Value) ? 1f : 0f); ((Component)_levelText).gameObject.SetActive(config.ShowLevel.Value); ((Component)_xpFill).gameObject.SetActive(config.ShowXp.Value); ((Component)_xpText).gameObject.SetActive(config.ShowXp.Value); _xpBarContainer.anchoredPosition = config.XpBarPosition.Value; Vector2 sizeDelta = _xpBarRect.sizeDelta; sizeDelta.x *= config.XpBarScale.Value / 100f; _xpBarRect.sizeDelta = sizeDelta; _scrollRect.verticalScrollbar = (config.ShowScrollbar.Value ? _scrollbar : null); ((Component)_scrollbar).gameObject.SetActive(config.ShowScrollbar.Value); } private void ConfigureRaycastTargets() { _menuCanvas = ((Component)_skillsGroup).gameObject.GetComponent<Canvas>() ?? ((Component)_skillsGroup).gameObject.AddComponent<Canvas>(); if ((Object)(object)((Component)_skillsGroup).GetComponent<GraphicRaycaster>() == (Object)null) { ((Component)_skillsGroup).gameObject.AddComponent<GraphicRaycaster>(); } _xpBarGroup.blocksRaycasts = false; _levelUpGroup.blocksRaycasts = false; Graphic[] componentsInChildren = ((Component)_skillsGroup).GetComponentsInChildren<Graphic>(true); foreach (Graphic obj in componentsInChildren) { obj.raycastTarget = (Object)(object)((Component)obj).GetComponent<Selectable>() != (Object)null; } Graphic component = ((Component)_scrollRect.viewport).GetComponent<Graphic>(); if ((Object)(object)component != (Object)null) { component.raycastTarget = true; } if ((Object)(object)((Selectable)_scrollbar).targetGraphic != (Object)null) { ((Selectable)_scrollbar).targetGraphic.raycastTarget = true; } } private void ConfigureMenuSorting() { if (!((Object)(object)_menuCanvas == (Object)null)) { Canvas val = (((Object)(object)Hud.instance != (Object)null) ? ((Component)Hud.instance).GetComponentInParent<Canvas>() : null); int num = (((Object)(object)val != (Object)null) ? val.sortingLayerID : ((Component)this).GetComponent<Canvas>().sortingLayerID); int num2 = (((Object)(object)val != (Object)null) ? Mathf.Max(500, val.sortingOrder + 1) : 500); if (!_menuCanvas.overrideSorting) { _menuCanvas.overrideSorting = true; } if (_menuCanvas.sortingLayerID != num) { _menuCanvas.sortingLayerID = num; } if (_menuCanvas.sortingOrder != num2) { _menuCanvas.sortingOrder = num2; } } } private void ConfigureSkillsWindowLayout() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00c4: 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_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: 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_0163: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) RectTransform component = ((Component)_skillsGroup).GetComponent<RectTransform>(); Vector2 sizeDelta = component.sizeDelta; sizeDelta.x = Mathf.Max(sizeDelta.x, 735f); sizeDelta.y = Mathf.Max(sizeDelta.y, 820f); component.sizeDelta = sizeDelta; Canvas.ForceUpdateCanvases(); Transform val = ((Component)this).transform.Find("Skills UI/Scroll View/Category Buttons"); RectTransform component2 = ((Component)val).GetComponent<RectTransform>(); GridLayoutGroup component3 = ((Component)val).GetComponent<GridLayoutGroup>(); int length = Enum.GetValues(typeof(SkillCategory)).Length; if ((Object)(object)component3 == (Object)null || length == 0) { return; } component3.constraint = (Constraint)1; component3.constraintCount = length; component3.startAxis = (Axis)0; ((LayoutGroup)component3).childAlignment = (TextAnchor)1; float num = component3.spacing.x * (float)(length - 1); Rect rect = component2.rect; float num2 = Mathf.Floor((((Rect)(ref rect)).width - num) / (float)length); component3.cellSize = new Vector2(num2, 40f); for (int i = 0; i < val.childCount; i++) { Text componentInChildren = ((Component)val.GetChild(i)).GetComponentInChildren<Text>(); if (!((Object)(object)componentInChildren == (Object)null)) { RectTransform component4 = ((Component)componentInChildren).GetComponent<RectTransform>(); ((Transform)component4).localScale = Vector3.one; component4.anchorMin = Vector2.zero; component4.anchorMax = Vector2.one; component4.pivot = new Vector2(0.5f, 0.5f); component4.anchoredPosition = Vector2.zero; component4.sizeDelta = new Vector2(-8f, -6f); componentInChildren.resizeTextForBestFit = false; componentInChildren.fontSize = 18; componentInChildren.alignment = (TextAnchor)4; componentInChildren.horizontalOverflow = (HorizontalWrapMode)1; componentInChildren.verticalOverflow = (VerticalWrapMode)1; } } LayoutRebuilder.ForceRebuildLayoutImmediate(component2); RectTransform component5 = ((Component)((Component)this).transform.Find("Skills UI/Scroll View/Viewport")).GetComponent<RectTransform>(); Canvas.ForceUpdateCanvases(); foreach (RectTransform categoryContainer in _categoryContainers) { GridLayoutGroup component6 = ((Component)categoryContainer).GetComponent<GridLayoutGroup>(); if (!((Object)(object)component6 == (Object)null)) { component6.constraint = (Constraint)1; component6.constraintCount = 3; component6.startAxis = (Axis)0; ((LayoutGroup)component6).childAlignment = (TextAnchor)1; rect = component5.rect; float num3 = ((Rect)(ref rect)).width - (float)((LayoutGroup)component6).padding.left - (float)((LayoutGroup)component6).padding.right - component6.spacing.x * 2f; component6.cellSize = new Vector2(Mathf.Floor(num3 / 3f), 200f); LayoutRebuilder.ForceRebuildLayoutImmediate(categoryContainer); } } } private void ConfigureButtons() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown for (int i = 0; i < _categoryButtons.Count; i++) { int categoryIndex = i; ((UnityEventBase)_categoryButtons[i].onClick).RemoveAllListeners(); ((UnityEvent)_categoryButtons[i].onClick).AddListener((UnityAction)delegate { OpenCategory(categoryIndex); }); } ((UnityEventBase)_closeButton.onClick).RemoveAllListeners(); ((UnityEvent)_closeButton.onClick).AddListener((UnityAction)delegate { ToggleMenu(visible: false); }); ((UnityEventBase)_resetButton.onClick).RemoveAllListeners(); ((UnityEvent)_resetButton.onClick).AddListener((UnityAction)delegate { _skills.ResetAll(); }); Text componentInChildren = ((Component)_resetButton).GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = Localize("$ls_reset_skills"); } Text componentInChildren2 = ((Component)_closeButton).GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.text = Localize("$ls_close_menu"); } } public void ToggleMenu(bool visible) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) bool num = _menuVisible != visible; _menuVisible = visible; _skillsGroup.alpha = (visible ? 1f : 0f); _skillsGroup.interactable = visible; _skillsGroup.blocksRaycasts = visible; ((Component)_skillsGroup).gameObject.SetActive(visible); if (visible) { ConfigureMenuSorting(); } if ((Object)(object)_skillsShortcutHud != (Object)null) { _skillsShortcutHud.SetActive(!visible); } if ((Object)(object)_content != (Object)null) { _content.anchoredPosition = Vector2.zero; } if (num) { GUIManager.BlockInput(visible); } if (visible && _initialized) { RefreshAll(); } if (!visible) { HideSkillDetails(); } } public void ShowSkillDetails(SkillDefinition definition, Vector2 screenPosition) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_skillDetailsPanel == (Object)null) && definition != null && !((Object)(object)_skills == (Object)null)) { string text = _skills.GetBonus(definition.Id).ToString("0.##", CultureInfo.InvariantCulture); string arg = definition.BonusPerRank.ToString("0.##", CultureInfo.InvariantCulture); _skillDetailsTitle.text = Localize(definition.NameToken); if (definition.Category == SkillCategory.Rare) { _skillDetailsBody.text = Localize(definition.DescriptionToken) + "\n" + string.Format(Localize("$ls_rare_cost"), definition.PointCost); } else { _skillDetailsBody.text = Localize(definition.DescriptionToken) + "\n" + string.Format(Localize("$ls_per_rank"), arg, definition.Unit) + " " + Localize("$ls_total_bonus") + ": +" + text + definition.Unit; } _skillDetailsPanel.SetActive(true); ResizeSkillDetails(); _skillDetailsPanel.transform.SetAsLastSibling(); PositionSkillDetails(screenPosition); } } public void HideSkillDetails() { if ((Object)(object)_skillDetailsPanel != (Object)null) { _skillDetailsPanel.SetActive(false); } } private void CreateSkillDetailsPanel() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_00ab: 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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Skill Details", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); val.layer = ((Component)_skillsGroup).gameObject.layer; val.transform.SetParent(((Component)_skillsGroup).transform, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = Vector2.zero; component.sizeDelta = new Vector2(440f, 135f); Image component2 = val.GetComponent<Image>(); ((Graphic)component2).color = new Color(0.035f, 0.045f, 0.055f, 0.97f); ((Graphic)component2).raycastTarget = false; _skillDetailsTitle = CreateDetailsText(val.transform, "Title", 21, (FontStyle)1, new Vector2(14f, -10f), new Vector2(-28f, 35f)); ((Graphic)_skillDetailsTitle).color = new Color(0.95f, 0.78f, 0.35f, 1f); _skillDetailsBody = CreateDetailsText(val.transform, "Description", 16, (FontStyle)0, new Vector2(14f, -47f), new Vector2(-28f, 80f)); ((Graphic)_skillDetailsBody).color = new Color(0.95f, 0.95f, 0.93f, 1f); _skillDetailsPanel = val; _skillDetailsPanel.SetActive(false); } private void CreateSkillsShortcutHud() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0079: 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_00a3: 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_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0144: 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_0167: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Expected O, but got Unknown GameObject val = new GameObject("SharingXP Skills Shortcut", new Type[4] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button) }); val.layer = ((Component)this).gameObject.layer; val.transform.SetParent(((Component)this).transform, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(1f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(1f, 1f); component.anchoredPosition = new Vector2(-275f, -18f); component.sizeDelta = new Vector2(190f, 58f); Image component2 = val.GetComponent<Image>(); ((Graphic)component2).color = new Color(0.025f, 0.035f, 0.045f, 0.88f); GameObject val2 = new GameObject("Icon", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }) { layer = ((Component)this).gameObject.layer }; val2.transform.SetParent(val.transform, false); RectTransform component3 = val2.GetComponent<RectTransform>(); component3.anchorMin = new Vector2(0f, 0.5f); component3.anchorMax = new Vector2(0f, 0.5f); component3.pivot = new Vector2(0f, 0.5f); component3.anchoredPosition = new Vector2(4f, 0f); component3.sizeDelta = new Vector2(50f, 50f); Image component4 = val2.GetComponent<Image>(); component4.sprite = SkillIconProvider.Load("HUDSharingXP"); component4.preserveAspect = true; ((Graphic)component4).raycastTarget = false; GameObject val3 = new GameObject("Label", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Text) }) { layer = ((Component)this).gameObject.layer }; val3.transform.SetParent(val.transform, false); RectTransform component5 = val3.GetComponent<RectTransform>(); component5.anchorMin = new Vector2(0f, 0f); component5.anchorMax = new Vector2(1f, 1f); component5.offsetMin = new Vector2(58f, 4f); component5.offsetMax = new Vector2(-5f, -4f); Text component6 = val3.GetComponent<Text>(); component6.font = _remainingPoints.font; component6.fontSize = 17; component6.fontStyle = (FontStyle)1; component6.alignment = (TextAnchor)4; ((Graphic)component6).color = new Color(0.94f, 0.8f, 0.42f, 1f); KeyboardShortcut value = PluginRuntime.Config.OpenSkillsMenu.Value; component6.text = "SharingXP\n[" + ((object)((KeyboardShortcut)(ref value)).MainKey/*cast due to .constrained prefix*/).ToString() + "]"; ((Graphic)component6).raycastTarget = false; Button component7 = val.GetComponent<Button>(); ((Selectable)component7).targetGraphic = (Graphic)(object)component2; ((UnityEvent)component7.onClick).AddListener((UnityAction)delegate { ToggleMenu(!_menuVisible); }); _skillsShortcutHud = val; } private void ResizeSkillDetails() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) RectTransform component = _skillDetailsPanel.GetComponent<RectTransform>(); RectTransform component2 = ((Component)_skillsGroup).GetComponent<RectTransform>(); Rect rect = component2.rect; component.SetSizeWithCurrentAnchors((Axis)0, Mathf.Min(460f, ((Rect)(ref rect)).width - 24f)); RectTransform rectTransform = ((Graphic)_skillDetailsTitle).rectTransform; RectTransform rectTransform2 = ((Graphic)_skillDetailsBody).rectTransform; float num = Mathf.Max(28f, _skillDetailsTitle.preferredHeight); rectTransform.SetSizeWithCurrentAnchors((Axis)1, num); rectTransform2.anchoredPosition = new Vector2(14f, -18f - num); float num2 = Mathf.Max(40f, _skillDetailsBody.preferredHeight); rectTransform2.SetSizeWithCurrentAnchors((Axis)1, num2); component.SetSizeWithCurrentAnchors((Axis)1, num + num2 + 32f); } private void PositionSkillDetails(Vector2 screenPosition) { //IL_0019: 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_0027: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) RectTransform component = ((Component)_skillsGroup).GetComponent<RectTransform>(); RectTransform component2 = _skillDetailsPanel.GetComponent<RectTransform>(); Vector2 val = default(Vector2); if (RectTransformUtility.ScreenPointToLocalPointInRectangle(component, screenPosition, (Camera)null, ref val)) { Vector2 val2 = val + new Vector2(component2.sizeDelta.x * 0.52f, -75f); Rect rect = component.rect; float num = component2.sizeDelta.x * 0.5f; float num2 = component2.sizeDelta.y * 0.5f; val2.x = Mathf.Clamp(val2.x, ((Rect)(ref rect)).xMin + num, ((Rect)(ref rect)).xMax - num); val2.y = Mathf.Clamp(val2.y, ((Rect)(ref rect)).yMin + num2, ((Rect)(ref rect)).yMax - num2); component2.anchoredPosition = val2; } } private Text CreateDetailsText(Transform parent, string objectName, int fontSize, FontStyle fontStyle, Vector2 anchoredPosition, Vector2 sizeDelta) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0077: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(objectName, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Text) }) { layer = ((Component)parent).gameObject.layer }; val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0f, 1f); component.anchoredPosition = anchoredPosition; component.sizeDelta = sizeDelta; Text component2 = val.GetComponent<Text>(); component2.font = _remainingPoints.font; component2.fontSize = fontSize; component2.fontStyle = fontStyle; component2.alignment = (TextAnchor)0; component2.horizontalOverflow = (HorizontalWrapMode)0; component2.verticalOverflow = (VerticalWrapMode)0; ((Graphic)component2).raycastTarget = false; component2.supportRichText = true; return component2; } private void OpenCategory(int categoryIndex) { //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) if (categoryIndex < 0 || categoryIndex >= _categoryContainers.Count) { return; } _currentCategory = categoryIndex; HideSkillDetails(); _cards.Clear(); for (int i = 0; i < _categoryContainers.Count; i++) { ((Component)_categoryContainers[i]).gameObject.SetActive(false); } RectTransform val = _categoryContainers[categoryIndex]; ClearContainer(val); SkillCategory category = (SkillCategory)categoryIndex; SkillDefinition[] array = SkillCatalog.Definitions.Where((SkillDefinition definition) => definition.Enabled && definition.Category == category).ToArray(); Color color = ((Graphic)((Component)_categoryButtons[categoryIndex]).GetComponent<Image>()).color; SkillDefinition[] array2 = array; foreach (SkillDefinition skillDefinition in array2) { GameObject val2 = Object.Instantiate<GameObject>(_skillPrefab, (Transform)(object)val); val2.SetActive(false); ((Object)val2).name = "SharingXP Skill Card - " + skillDefinition.Id; ((Object)val2).hideFlags = (HideFlags)0; try { Image component = val2.GetComponent<Image>(); if ((Object)(object)component != (Object)null) { ((Graphic)component).color = color; } SkillCardView skillCardView = val2.AddComponent<SkillCardView>(); skillCardView.Initialize(skillDefinition, _skills); _cards.Add(skillCardView); val2.SetActive(true); } catch (Exception arg) { val2.transform.SetParent((Transform)null, false); val2.SetActive(false); Object.Destroy((Object)(object)val2); Logger.LogError((object)$"Could not initialize skill card {skillDefinition.Id}: {arg}"); } } ((Component)val).gameObject.SetActive(true); float num2 = Mathf.Max(215f, Mathf.Ceil((float)array.Length / 3f) * 215f); _content.sizeDelta = new Vector2(_content.sizeDelta.x, num2); _content.anchoredPosition = Vector2.zero; UpdateCategoryLabels(); } private void ClearContainer(RectTransform container) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown List<Transform> list = new List<Transform>(); foreach (Transform item2 in (Transform)container) { Transform item = item2; list.Add(item); } foreach (Transform item3 in list) { item3.SetParent((Transform)null, false); ((Component)item3).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)item3).gameObject); } } private void EnsureCurrentCategoryIntegrity() { if ((Object)(object)_skills == (Object)null || _currentCategory < 0 || _currentCategory >= _categoryContainers.Count) { return; } SkillCategory category = (SkillCategory)_currentCategory; SkillDefinition[] array = SkillCatalog.Definitions.Where((SkillDefinition definition) => definition.Enabled && definition.Category == category).ToArray(); RectTransform val = _categoryContainers[_currentCategory]; bool flag = _cards.Count == array.Length && ((Transform)val).childCount == array.Length; if (flag) { for (int num = 0; num < array.Length; num++) { SkillCardView skillCardView = _cards[num]; if ((Object)(object)skillCardView == (Object)null || (Object)(object)((Component)skillCardView).transform.parent != (Object)(object)val || !skillCardView.Matches(array[num])) { flag = false; break; } } } if (!flag) { Logger.LogWarning((object)($"Repairing skill UI category {category}: expected {array.Length} cards, " + $"found {((Transform)val).childCount}.")); OpenCategory(_currentCategory); return; } foreach (SkillCardView card in _cards) { card.Refresh(); } } private bool TryRebindLocalPlayer() { Player localPlayer = Player.m_localPlayer; PlayerLevelProgression progression = default(PlayerLevelProgression); PlayerSkillProgression skills = default(PlayerSkillProgression); if ((Object)(object)localPlayer == (Object)null || !((Component)localPlayer).TryGetComponent<PlayerLevelProgression>(ref progression) || !((Component)localPlayer).TryGetComponent<PlayerSkillProgression>(ref skills)) { return false; } BindPlayer(localPlayer, progression, skills); HideSkillDetails(); OpenCategory(_currentCategory); RefreshAll(); Logger.LogInfo((object)"Progression UI rebound to the new local player instance."); return true; } private void BindPlayer(Player player, PlayerLevelProgression progression, PlayerSkillProgression skills) { UnbindPlayer(); _player = player; _progression = progression; _skills = skills; _progression.ExperienceChanged += OnExperienceChanged; _progression.LevelChanged += OnLevelChanged; _skills.RankChanged += OnRankChanged; _skills.SkillsReset += OnSkillsReset; _skills.CombatEffectRequested += SkillVisualEffects.Play; } private void UnbindPlayer() { if ((Object)(object)_progression != (Object)null) { _progression.ExperienceChanged -= OnExperienceChanged; _progression.LevelChanged -= OnLevelChanged; } if ((Object)(object)_skills != (Object)null) { _skills.RankChanged -= OnRankChanged; _skills.SkillsReset -= OnSkillsReset; _skills.CombatEffectRequested -= SkillVisualEffects.Play; } _player = null; _progression = null; _skills = null; } private void OnExperienceChanged(int awarded, int totalExperience) { RefreshExperience(); if (awarded > 0) { SpawnExperienceText(awarded); } } private void OnLevelChanged(int oldLevel, int newLevel) { RefreshAll(); if (newLevel > oldLevel) { ((MonoBehaviour)this).StartCoroutine(ShowLevelUp(newLevel)); SkillVisualEffects.PlayLevelUp(_player); } } private void OnRankChanged(SkillId id, int oldRank, int newRank) { RefreshSkills(); } private void OnSkillsReset() { RefreshSkills(); } private void RefreshAll() { RefreshExperience(); RefreshSkills(); } private void RefreshExperience() { LevelEvaluationResult currentLevelEvaluation = _progression.CurrentLevelEvaluation; string value = Localize("$ls_level") + " " + _progression.GetLevel(); SetText(_levelText, _levelShadow, value); if (currentLevelEvaluation.IsMaxLevel) { SetText(_xpText, _xpShadow, Localize("$ls_max_level")); _targetFill = 1f; } else { string value2 = Mathf.Max(0, _progression.GetTotalExperience() - currentLevelEvaluation.TotalExperience).ToString("N0", CultureInfo.CurrentCulture) + " / " + currentLevelEvaluation.MaxExperience.ToString("N0", CultureInfo.CurrentCulture); SetText(_xpText, _xpShadow, value2); _targetFill = _progression.GetProgress01(); } } private void RefreshSkills() { if ((Object)(object)_skills == (Object)null) { return; } _remainingPoints.text = string.Format(Localize("$ls_remaining_points"), _skills.GetAvailablePoints()); UpdateCategoryLabels(); foreach (SkillCardView card in _cards) { card?.Refresh(); } } private void UpdateCategoryLabels() { if ((Object)(object)_skills == (Object)null) { return; } for (int i = 0; i < _categoryButtons.Count; i++) { SkillCategory category = (SkillCategory)i; int num = SkillCatalog.Definitions.Where((SkillDefinition definition) => definition.Category == category).Sum((SkillDefinition definition) => _skills.GetRank(definition.Id)); Text componentInChildren = ((Component)_categoryButtons[i]).GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = Localize("$ls_category_" + category.ToString().ToLowerInvariant()) + " (" + num + ")"; } } } private IEnumerator ShowLevelUp(int level) { SetText(_levelUpText, _levelUpShadow, Localize("$ls_level") + " " + level); yield return Fade(_levelUpGroup, 0f, 1f, 0.5f); yield return (object)new WaitForSeconds(2.2f); yield return Fade(_levelUpGroup, 1f, 0f, 1.2f); } private static IEnumerator Fade(CanvasGroup group, float from, float to, float duration) { for (float time = 0f; time < duration; time += Time.deltaTime) { group.alpha = Mathf.Lerp(from, to, time / duration); yield return null; } group.alpha = to; } private void SpawnExperienceText(int awarded) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_00a5: Unknown result type (might be due to invalid IL or missing references) GameObject val = PluginRuntime.Resources?.ExperienceTextPrefab; if (!((Object)(object)val == (Object)null) && !((Object)(object)_player == (Object)null)) { Vector3 val2 = Random.insideUnitSphere * 0.22f; val2.y = Mathf.Abs(val2.y); GameObject obj = Object.Instantiate<GameObject>(val, ((Character)_player).GetTopPoint() + val2, Quaternion.identity); ((Object)obj).hideFlags = (HideFlags)0; obj.SetActive(true); obj.AddComponent<FloatingTextEffect>().Configure("+" + awarded + " XP", new Color(0.45f, 0.9f, 1f, 1f)); } } private T Find<T>(string path) where T : Component { return ((Component)((Component)this).transform.Find(path)).GetComponent<T>(); } private static void SetText(Text text, Text shadow, string value) { text.text = value; shadow.text = value; } private static string Localize(string token) { return LocalizationSetup.Translate(token); } private static bool IsTyping() { if (!Console.IsVisible() && !TextInput.IsVisible()) { if ((Object)(object)Chat.instance != (Object)null) { return Chat.instance.HasFocus(); } return false; } return true; } } internal sealed class SkillCardView : MonoBehaviour { private SkillDefinition _definition; private PlayerSkillProgression _progression; private Text _nameText; private Text _nameShadow; private Text _bonusText; private Text _bonusShadow; private Text _description; private Text _levelText; private Text _levelShadow; private Text _maxLevelText; private Text _maxLabelText; private Text _totalBonusText; private Text _totalBonusShadow; private Image _icon; private Image _levelFill; private Button _addButton; private Button _removeButton; private Button _resetButton; private CanvasGroup _addGroup; private CanvasGroup _removeGroup; private CanvasGroup _resetGroup; private GameObject _resetText; private static Sprite _detailsButtonSprite; public bool IsInitialized { get { if (_definition != null) { return (Object)(object)_progression != (Object)null; } return false; } } public bool Matches(SkillDefinition definition) { if (IsInitialized && definition != null) { return _definition.Id == definition.Id; } return false; } public void Initialize(SkillDefinition definition, PlayerSkillProgression progression) { //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected O, but got Unknown //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Expected O, but got Unknown //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Expected O, but got Unknown _definition = definition; _progression = progression; _nameText = Find<Text>("Skill Name"); _nameShadow = Find<Text>("Skill Name/Skill Name Shadow"); _bonusText = Find<Text>("Bonus Text"); _bonusShadow = Find<Text>("Bonus Text/Bonus Text Shadow"); _description = Find<Text>("Description"); _levelText = Find<Text>("Skill Level"); _levelShadow = Find<Text>("Skill Level/Skill Level Shadow"); _maxLevelText = Find<Text>("Skill Level Ring/Skill Level Max"); _maxLabelText = Find<Text>("Skill Level Ring/Skill Level Max/Skill Level Max Text"); _totalBonusText = Find<Text>("Total Bonus"); _totalBonusShadow = Find<Text>("Total Bonus/Total Bonus Shadow"); _icon = Find<Image>("Skill Icon"); _levelFill = Find<Image>("Skill Level Ring/Skill Level Fill Slider"); _addButton = Find<Button>("Add Skill Point (Mask)/Add Skill Point"); _removeButton = Find<Button>("Remove Skill Point (Mask)/Remove Skill Point"); _resetButton = Find<Button>("Reset Skill Point (Mask)/Reset Skill Point"); _addGroup = ((Component)_addButton).GetComponent<CanvasGroup>(); _removeGroup = ((Component)_removeButton).GetComponent<CanvasGroup>(); _resetGroup = ((Component)_resetButton).GetComponent<CanvasGroup>(); Transform obj = ((Component)this).transform.Find("Reset Skill Point (Mask)/Reset Text"); _resetText = ((obj != null) ? ((Component)obj).gameObject : null); ((UnityEventBase)_addButton.onClick).RemoveAllListeners(); ((UnityEventBase)_removeButton.onClick).RemoveAllListeners(); ((UnityEventBase)_resetButton.onClick).RemoveAllListeners(); ((UnityEvent)_addButton.onClick).AddListener((UnityAction)delegate { _progression.TryAddRanks(_definition.Id, (!IsShiftPressed()) ? 1 : 10); }); ((UnityEvent)_removeButton.onClick).AddListener((UnityAction)delegate { _progression.TryRemoveRanks(_definition.Id, (!IsShiftPressed()) ? 1 : 10); }); ((UnityEvent)_resetButton.onClick).AddListener((UnityAction)delegate { _progression.ResetRank(_definition.Id); }); _icon.sprite = SkillIconProvider.Load(_definition.IconName); ((Component)_description).gameObject.SetActive(false); SetText(_totalBonusText, _totalBonusShadow, Localize("$ls_total_bonus")); _maxLabelText.text = Localize("$ls_max"); CreateDetailsButton(); _progression.RankChanged += OnRankChanged; _progression.SkillsReset += Refresh; Refresh(); } private void OnEnable() { if (IsInitialized) { Refresh(); } } private void OnDestroy() { if (!((Object)(object)_progression == (Object)null)) { _progression.RankChanged -= OnRankChanged; _progression.SkillsReset -= Refresh; } } private void OnRankChanged(SkillId id, int oldRank, int newRank) { Refresh(); } public void Refresh() { if (!((Object)(object)_progression == (Object)null) && _definition != null) { int rank = _progression.GetRank(_definition.Id); string value = Localize(_definition.NameToken); string text = _progression.GetBonus(_definition.Id).ToString("0.##", CultureInfo.InvariantCulture); string value2 = ((_definition.Category != SkillCategory.Rare) ? ("+" + text + _definition.Unit) : ((rank > 0) ? Localize("$ls_unlocked") : string.Format(Localize("$ls_cost_points"), _definition.PointCost))); SetText(_nameText, _nameShadow, value); SetText(_bonusText, _bonusShadow, value2); SetText(_levelText, _levelShadow, rank.ToString(CultureInfo.InvariantCulture)); _maxLevelText.text = _definition.MaxRank.ToString(CultureInfo.InvariantCulture); _levelFill.fillAmount = 0.1245f + (float)rank / (float)_definition.MaxRank * 0.75f; Toggle(_addGroup, rank < _definition.MaxRank && _progression.GetAvailablePoints() >= _definition.PointCost); Toggle(_removeGroup, rank > 0); Toggle(_resetGroup, rank > 0); if ((Object)(object)_resetText != (Object)null) { _resetText.SetActive(rank > 0); } } } private void CreateDetailsButton() { //IL_0032: 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_0048: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0129: 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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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) GameObject val = new GameObject("Skill Details Button", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }) { layer = ((Component)this).gameObject.layer }; val.transform.SetParent(((Component)this).transform, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(1f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(1f, 1f); component.anchoredPosition = new Vector2(-5f, -5f); component.sizeDelta = new Vector2(24f, 24f); Image component2 = val.GetComponent<Image>(); component2.sprite = GetDetailsButtonSprite(); ((Graphic)component2).color = Color.white; component2.preserveAspect = true; Color color = default(Color); ((Color)(ref color))..ctor(0.96f, 0.84f, 0.57f, 1f); CreateInfoMarkPart(val.transform, "Info Dot", new Vector2(3.2f, 3.2f), new Vector2(0f, 5.2f), color); CreateInfoMarkPart(val.transform, "Info Stem", new Vector2(3.2f, 8.5f), new Vector2(0f, -2.1f), color); val.AddComponent<SkillDetailsHover>().Initialize(_definition); } private static void CreateInfoMarkPart(Transform parent, string name, Vector2 size, Vector2 position, Color color) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0077: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }) { layer = ((Component)parent).gameObject.layer }; val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = position; component.sizeDelta = size; Image component2 = val.GetComponent<Image>(); ((Graphic)component2).color = color; ((Graphic)component2).raycastTarget = false; } private static Sprite GetDetailsButtonSprite() { //IL_0019: 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) //IL_0029: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_detailsButtonSprite != (Object)null) { return _detailsButtonSprite; } Texture2D val = new Texture2D(48, 48, (TextureFormat)4, false) { name = "SharingXP Details Button", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; Color[] array = (Color[])(object)new Color[2304]; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(24f, 24f); float num = 23f; Color val3 = default(Color); ((Color)(ref val3))..ctor(0.045f, 0.055f, 0.06f, 0.96f); Color val4 = default(Color); ((Color)(ref val4))..ctor(0.79f, 0.63f, 0.34f, 1f); for (int i = 0; i < 48; i++) { for (int j = 0; j < 48; j++) { float num2 = Vector2.Distance(new Vector2((float)j + 0.5f, (float)i + 0.5f), val2); float num3 = Mathf.Clamp01(num + 0.75f - num2); if (!(num3 <= 0f)) { Color val5 = ((num2 >= num - 3f) ? val4 : val3); val5.a *= num3; array[i * 48 + j] = val5; } } } val.SetPixels(array); val.Apply(false, true); _detailsButtonSprite = Sprite.Create(val, new Rect(0f, 0f, 48f, 48f), new Vector2(0.5f, 0.5f), 48f); ((Object)_detailsButtonSprite).name = "SharingXP Details Button Sprite"; ((Object)_detailsButtonSprite).hideFlags = (HideFlags)61; return _detailsButtonSprite; } private T Find<T>(string path) where T : Component { return ((Component)((Component)this).transform.Find(path)).GetComponent<T>(); } private static void SetText(Text text, Text shadow, string value) { text.text = value; shadow.text = value; } private static void Toggle(CanvasGroup group, bool visible) { if (!((Object)(object)group == (Object)null)) { group.alpha = (visible ? 1f : 0.2f); group.interactable = visible; group.blocksRaycasts = visible; } } private static string Localize(string token) { return LocalizationSetup.Translate(token); } private static bool IsShiftPressed() { if (!Input.GetKey((KeyCode)304)) { return Input.GetKey((KeyCode)303); } return true; } } internal sealed class SkillDetailsHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerClickHandler { private SkillDefinition _definition; private bool _hovered; public void Initialize(SkillDefinition definition) { _definition = definition; } public void OnPointerEnter(PointerEventData eventData) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) _hovered = true; ProgressionUiController.Instance?.ShowSkillDetails(_definition, eventData.position); } public void OnPointerExit(PointerEventData eventData) { _hovered = false; ProgressionUiController.Instance?.HideSkillDetails(); } public void OnPointerClick(PointerEventData eventData) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) ProgressionUiController.Instance?.ShowSkillDetails(_definition, eventData.position); } private void OnDisable() { if (_hovered) { ProgressionUiController.Instance?.HideSkillDetails(); } _hovered = false; } } internal static class SkillIconProvider { private const string BundleIconPath = "Assets/_Leveling System/Sprites/Skill Icons/"; private static readonly Dictionary<string, Sprite> Cache = new Dictionary<string, Sprite>(); public static Sprite Load(string iconName) { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) if (Cache.TryGetValue(iconName, out var value)) { return value; } ModResources resources = PluginRuntime.Resources; Sprite val = ((resources != null) ? resources.AssetBundle.LoadAsset<Sprite>("Assets/_Leveling System/Sprites/Skill Icons/" + iconName + ".png") : null); if ((Object)(object)val != (Object)null) { Cache[iconName] = val; return val; } Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string name) => name.EndsWith("Resources.skill_icons." + iconName + ".png", StringComparison.OrdinalIgnoreCase)); if (text == null) { Logger.LogWarning((object)("Skill icon '" + iconName + "' was not found.")); return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text); using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val2 = new Texture2D(2, 2, (TextureFormat)5, false) { name = iconName, filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; MethodInfo methodInfo = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule")?.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, null); if (!(methodInfo != null) || !(bool)methodInfo.Invoke(null, new object[3] { val2, memoryStream.ToArray(), false })) { Object.Destroy((Object)(object)val2); return null; } Sprite val3 = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f), 100f); Cache[iconName] = val3; return val3; } } internal static class SkillVisualEffects { public static void Play(Vector3 position, CombatEffectType effectType) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if (effectType == CombatEffectType.FireFistHit) { RareSkillEffects.PlayFireImpact(position); return; } GameObject val = PluginRuntime.Resources?.CriticalHitEffectPrefab; if ((Object)(object)val == (Object)null) { return; } GameObject val2 = Object.Instantiate<GameObject>(val, position, Quaternion.identity); ((Object)val2).hideFlags = (HideFlags)0; val2.SetActive(true); switch (effectType) { case CombatEffectType.SummonHit: Tint(val2, new Color(0.2f, 0.75f, 1f, 1f)); break; case CombatEffectType.WeakHitBlocked: Tint(val2, new Color(0.1f, 0.95f, 1f, 1f)); if ((Object)(object)GameCamera.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null) { GameCamera.instance.AddShake(((Component)Player.m_localPlayer).transform.position, 4f, 0.12f, false); } break; default: if ((Object)(object)GameCamera.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null) { GameCamera.instance.AddShake(((Component)Player.m_localPlayer).transform.position, 10f, 0.25f, false); } break; } Object.Destroy((Object)(object)val2, 4f); } public static void PlayLevelUp(Player player) { //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) if ((Object)(object)player == (Object)null) { return; } PluginConfig config = PluginRuntime.Config; if (config == null || config.LevelUpVFX.Value) { GameObject val = PluginRuntime.Resources?.LevelUpEffectPrefab; if ((Object)(object)val != (Object)null) { GameObject obj = Object.Instantiate<GameObject>(val, ((Character)player).GetCenterPoint(), Quaternion.identity, ((Component)player).transform); ((Object)obj).hideFlags = (HideFlags)0; obj.SetActive(true); Object.Destroy((Object)(object)obj, 6f); } } } private static void Tint(GameObject effect, Color color) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) ParticleSystem[] componentsInChildren = effect.GetComponentsInChildren<ParticleSystem>(true); for (int i = 0; i < componentsInChildren.Length; i++) { MainModule main = componentsInChildren[i].main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(color); } } } } namespace CharacterProgressionMod.Skills { public enum CombatEffectType { CriticalHit, SummonHit, WeakHitBlocked, FireFistHit } public sealed class PlayerSkillProgression : MonoBehaviour { private const string SaveKeyPrefix = "Cozyheim!Skill!"; private const string LegacySaveKeyPrefix = "LevelingSystem_"; private const string SecondLifeReadyAtKey = "Cozyheim!SecondLifeReadyAt"; private static readonly IReadOnlyDictionary<SkillId, string> LegacySkillNames = new Dictionary<SkillId, string> { [SkillId.Vitality] = "HP", [SkillId.HealthRegen] = "HPRegen", [SkillId.Endurance] = "Stamina", [SkillId.StaminaRegen] = "StaminaRegen", [SkillId.ArcaneCapacity] = "Eitr", [SkillId.EitrRegen] = "EitrRegen", [SkillId.CarryWeight] = "CarryWeight", [SkillId.MovementSpeed] = "MovementSpeed", [SkillId.Woodcutting] = "Woodcutting", [SkillId.Mining] = "Mining", [SkillId.PhysicalDamage] = "PhysicalDamage", [SkillId.ElementalDamage] = "ElementalDamage", [SkillId.PhysicalResistance] = "PhysicalResistance", [SkillId.ElementalResistance] = "ElementalResistance", [SkillId.SlashResistance] = "ResistanceSlash", [SkillId.BluntResistance] = "ResistanceBlunt", [SkillId.PierceResistance] = "ResistancePierce", [SkillId.FireResistance] = "ResistanceFire", [SkillId.FrostResistance] = "ResistanceFrost", [SkillId.LightningResistance] = "ResistanceLightning", [SkillId.PoisonResistance] = "ResistancePoison", [SkillId.SpiritResistance] = "ResistanceSpirit", [SkillId.CriticalChance] = "CriticalChance", [SkillId.CriticalDamage] = "CriticalDamage" }; private readonly Dictionary<SkillId, int> _ranks = new Dictionary<SkillId, int>(); private Player _player; private PluginConfig _config; private bool _loaded; private bool _playerDataLoading; private string _combatEffectRpcId; private float _secondLifeProtectionUntil; public Player Player => _player; public bool IsSecondLifeProtected => Time.time < _secondLifeProtectionUntil; public event Action<SkillId, int, int> RankChanged; public event Action SkillsReset; public event Action<Vector3, CombatEffectType> CombatEffectRequested; private void Awake() { _player = ((Component)this).GetComponent<Player>(); _combatEffectRpcId = RpcId.Generate("CombatSkillEffect"); ZNetView nview = ((Character)_player).m_nview; if (((nview != null) ? nview.GetZDO() : null) != null) { ((Character)_player).m_nview.Register<Vector3, int>(_combatEffectRpcId, (Action<long, Vector3, int>)RPC_CombatEffect); } } private void Start() { Load(); } public void Configure(PluginConfig config) { _config = config; } public int GetRank(SkillId id) { if ((Object)(object)_player != (Object)null && !((Character)_player).IsOwner()) { ZNetView nview = ((Character)_player).m_nview; int? obj; if (nview == null) { obj = null; } else { ZDO zDO = nview.GetZDO(); obj = ((zDO != null) ? new int?(zDO.GetInt(GetNetworkRankKey(id), 0)) : ((int?)null)); } int? num = obj; return Mathf.Clamp(num.GetValueOrDefault(), 0, SkillCatalog.Get(id).MaxRank); } if (_playerDataLoading && !_loaded) { return 0; } EnsureLoaded(); if (!_ranks.TryGetValue(id, out var value)) { return 0; } return value; } public void BeginPlayerDataLoad() { _playerDataLoading = true; _loaded = false; _ranks.Clear(); } public void CompletePlayerDataLoad() { _playerDataLoading = false; _loaded = false; _ranks.Clear(); Load(); } public void PrepareForPlayerSave() { if (_loaded && !_playerDataLoading) { Save(); } } public float GetBonus(SkillId id) { SkillDefinition skillDefinition = SkillCatalog.Get(id); if (!skillDefinition.Enabled) { return 0f; } return skillDefinition.BaseBonus + (float)GetRank(id) * skillDefinition.BonusPerRank; } public float GetMultiplier(SkillId id) { return 1f + GetBonus(id) / 100f; } public int GetSpentPoints() { EnsureLoaded(); return SkillCatalog.Definitions.Where((SkillDefinition definition) => definition.Enabled).Sum((SkillDefinition definition) => GetRank(definition.Id) * definition.PointCost); } public int GetAvailablePoints() { PlayerLevelProgression component = ((Component)this).GetComponent<PlayerLevelProgression>(); int num = Mathf.FloorToInt((float)(((Object)(object)component == (Object)null) ? 1 : Mathf.Max(1, component.GetLevel())) * (_config?.SkillPointsPerLevel.Value ?? 1f)); return Mathf.Max(0, num - GetSpentPoints()); } public bool TryAddRank(SkillId id) { return TryAddRanks(id, 1) > 0; } public int TryAddRanks(SkillId id, int requestedRanks) { EnsureLoaded(); SkillDefinition skillDefinition = SkillCatalog.Get(id); if (!((Character)_player).IsOwner() || !skillDefinition.Enabled || requestedRanks <= 0) { return 0; } int rank = GetRank(id); int num = GetAvailablePoints() / skillDefinition.PointCost; int num2 = Mathf.Min(requestedRanks, Mathf.Min(skillDefinition.MaxRank - rank, num)); if (num2 <= 0) { return 0; } SetRank(id, rank + num2); return num2; } public bool TryRemoveRank(SkillId id) { return TryRemoveRanks(id, 1) > 0; } public int TryRemoveRanks(SkillId id, int requestedRanks) { EnsureLoaded(); if (((Character)_player).IsOwner()) { PluginConfig config = _config; if ((config == null || config.AllowSkillRefunds.Value) && requestedRanks > 0) { int rank = GetRank(id); if (rank <= 0) { return 0; } int num = Mathf.Min(requestedRanks, rank); SetRank(id, rank - num); return num; } } return 0; } public bool HasSkill(SkillId id) { if (SkillCatalog.Get(id).Enabled) { return GetRank(id) > 0; } return false; } public double GetSecondLifeRemainingSeconds() { if ((Object)(object)_player == (Object)null || !_player.m_customData.TryGetValue("Cozyheim!SecondLifeReadyAt", out var value) || !long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return 0.0; } return Math.Max(0.0, new DateTime(resu