using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon.Movement;
using Sparroh.UI;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Sparroh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LevelStatRewards")]
[assembly: AssemblyTitle("LevelStatRewards")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
internal static class BonusStatPatches
{
[HarmonyPatch(typeof(Upgrade), "ApplyRandomStatUpgrade")]
private static class ApplyRandomStatUpgrade_Patch
{
private static bool Prefix()
{
return false;
}
}
[HarmonyPatch(typeof(Upgrade), "GetStatList")]
private static class GetStatList_Patch
{
private static void Postfix(Upgrade __instance, ref string __result)
{
if (!((Object)(object)__instance == (Object)null) && __instance.ApplyStatUpgrades && !string.IsNullOrEmpty(__result))
{
__result = StripBonusColorBlock(__result);
}
}
}
private static string StripBonusColorBlock(string properties)
{
int num = properties.IndexOf("<color=#FFD58D>", StringComparison.Ordinal);
if (num < 0)
{
num = properties.IndexOf("<color=#ffd58d>", StringComparison.Ordinal);
}
if (num < 0)
{
return properties;
}
int num2 = properties.IndexOf("</color>", num, StringComparison.Ordinal);
if (num2 < 0)
{
return properties;
}
num2 += "</color>".Length;
StringBuilder stringBuilder = new StringBuilder(properties.Length);
stringBuilder.Append(properties, 0, num);
stringBuilder.Append(properties, num2, properties.Length - num2);
string text = stringBuilder.ToString();
while (text.Contains("\n\n\n"))
{
text = text.Replace("\n\n\n", "\n\n");
}
return text.Trim();
}
}
[HarmonyPatch(typeof(GearDetailsWindow))]
internal static class GearDetailsWindowPatches
{
[HarmonyPostfix]
[HarmonyPatch("Setup")]
private static void Setup_Postfix(GearDetailsWindow __instance, IUpgradable upgradable)
{
try
{
if (upgradable != null)
{
GearStatButton.SetCurrentGear(upgradable);
}
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogDebug((object)("GearDetails Setup: " + ex.Message));
}
}
}
}
public static class GearStatButton
{
public const string BarId = "levelstatrewards.stats";
public const int Order = 155;
private static IUpgradable _currentGear;
private static bool _registered;
public static IUpgradable CurrentGear => _currentGear;
public static void SetCurrentGear(IUpgradable gear)
{
_currentGear = gear;
}
public static void Tick()
{
if (!GearActionBar.IsGearMenuOpen())
{
if (_registered)
{
GearActionBar.SetSlotVisible("levelstatrewards.stats", false);
}
return;
}
try
{
Menu instance = Menu.Instance;
object obj;
if (instance == null)
{
obj = null;
}
else
{
WindowSystem windowSystem = instance.WindowSystem;
obj = ((windowSystem != null) ? windowSystem.GetTop() : null);
}
GearDetailsWindow val = (GearDetailsWindow)((obj is GearDetailsWindow) ? obj : null);
if (val != null)
{
IUpgradable upgradablePrefab = val.UpgradablePrefab;
if (upgradablePrefab != null)
{
_currentGear = upgradablePrefab;
}
}
}
catch
{
}
if (_currentGear == null)
{
if (_registered)
{
GearActionBar.SetSlotVisible("levelstatrewards.stats", false);
}
}
else
{
EnsureRegistered();
GearActionBar.SetSlotVisible("levelstatrewards.stats", true);
GearActionBar.SetText("levelstatrewards.stats", BuildLabel(_currentGear));
GearActionBar.SetStyle("levelstatrewards.stats", (UIButtonStyle)(StatAllocationStore.GetUnspent(_currentGear) > 0));
}
}
public static void Unregister()
{
try
{
GearActionBar.Unregister("levelstatrewards.stats");
}
catch
{
}
_registered = false;
_currentGear = null;
}
private static void EnsureRegistered()
{
GearActionBar.Register("levelstatrewards.stats", BuildLabel(_currentGear), 155, (Action)OnClicked, (UIButtonStyle)0);
_registered = true;
}
private static string BuildLabel(IUpgradable gear)
{
if (gear == null)
{
return "Level Stats";
}
int unspent = StatAllocationStore.GetUnspent(gear);
if (unspent <= 0)
{
return "Level Stats";
}
return $"Level Stats ({unspent})";
}
private static void OnClicked()
{
try
{
if (_currentGear != null)
{
StatAllocationWindow.Open(_currentGear);
}
}
catch (Exception arg)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogError((object)$"Open allocation UI failed: {arg}");
}
}
}
}
public static class ModBalance
{
public const int LevelsPerPoint = 3;
public const int LevelCapForPoints = 30;
public const int MaxPointsPerGear = 10;
public const float PercentPerPoint = 10f;
public const float PercentPerPointMinBetter = -10f;
}
[BepInPlugin("sparroh.levelstatrewards", "LevelStatRewards", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class LevelStatRewardsPlugin : BaseUnityPlugin
{
public const string PluginGUID = "sparroh.levelstatrewards";
public const string PluginName = "LevelStatRewards";
public const string PluginVersion = "1.0.0";
internal static ManualLogSource Log;
private Harmony _harmony;
private void Awake()
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
try
{
StatAllocationStore.Load();
}
catch (Exception arg)
{
Log.LogError((object)$"Init failed: {arg}");
return;
}
_harmony = new Harmony("sparroh.levelstatrewards");
try
{
_harmony.PatchAll(typeof(LevelStatRewardsPlugin).Assembly);
Log.LogInfo((object)"LevelStatRewards v1.0.0 loaded.");
}
catch (Exception arg2)
{
Log.LogError((object)$"Harmony patch failed: {arg2}");
}
}
private void Update()
{
try
{
GearStatButton.Tick();
StatAllocationWindow.Tick();
}
catch (Exception arg)
{
Log.LogError((object)$"Update error: {arg}");
}
}
private void OnDestroy()
{
try
{
StatAllocationWindow.DestroyUi();
GearStatButton.Unregister();
StatAllocationStore.Save();
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
catch (Exception arg)
{
ManualLogSource log = Log;
if (log != null)
{
log.LogError((object)$"OnDestroy error: {arg}");
}
}
}
}
public static class StatAllocationStore
{
private sealed class EmptyMap : Dictionary<string, int>
{
public static readonly EmptyMap Instance = new EmptyMap();
}
private static readonly Dictionary<string, Dictionary<string, int>> Allocations = new Dictionary<string, Dictionary<string, int>>(StringComparer.Ordinal);
private static string FilePath => Path.Combine(Paths.ConfigPath, "sparroh.levelstatrewards.allocations.json");
public static void Load()
{
Allocations.Clear();
try
{
if (File.Exists(FilePath))
{
Parse(File.ReadAllText(FilePath));
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogInfo((object)$"Loaded allocations for {Allocations.Count} gear entries.");
}
}
}
catch (Exception ex)
{
ManualLogSource log2 = LevelStatRewardsPlugin.Log;
if (log2 != null)
{
log2.LogError((object)("Failed to load allocations: " + ex.Message));
}
}
}
public static void Save()
{
try
{
string directoryName = Path.GetDirectoryName(FilePath);
if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
File.WriteAllText(FilePath, Serialize());
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogError((object)("Failed to save allocations: " + ex.Message));
}
}
}
public static string GetGearKey(IUpgradable gear)
{
if ((Object)(object)((gear != null) ? gear.Info : null) == (Object)null)
{
return null;
}
return gear.Info.ID.ToString();
}
public static int GetPoints(string gearKey, string statId)
{
if (string.IsNullOrEmpty(gearKey) || string.IsNullOrEmpty(statId))
{
return 0;
}
if (!Allocations.TryGetValue(gearKey, out var value))
{
return 0;
}
if (!value.TryGetValue(statId, out var value2))
{
return 0;
}
return Mathf.Max(0, value2);
}
public static int GetSpent(string gearKey)
{
if (string.IsNullOrEmpty(gearKey) || !Allocations.TryGetValue(gearKey, out var value))
{
return 0;
}
int num = 0;
foreach (KeyValuePair<string, int> item in value)
{
num += Mathf.Max(0, item.Value);
}
return num;
}
public static int GetGearLevel(IUpgradable gear)
{
try
{
GearData gearData = PlayerData.GetGearData(gear);
return (gearData == null) ? 1 : gearData.Level;
}
catch
{
return 1;
}
}
public static int GetTotalPoints(IUpgradable gear)
{
int num = Mathf.Min(GetGearLevel(gear), 30);
return Mathf.Min(Mathf.Max(0, num / 3), 10);
}
public static int GetUnspent(IUpgradable gear)
{
string gearKey = GetGearKey(gear);
return Mathf.Max(0, GetTotalPoints(gear) - GetSpent(gearKey));
}
public static bool TryAddPoint(IUpgradable gear, string statId)
{
if (gear == null)
{
return false;
}
string gearKey = GetGearKey(gear);
if (string.IsNullOrEmpty(gearKey) || StatDefinitions.Find(statId) == null)
{
return false;
}
if (GetUnspent(gear) <= 0)
{
return false;
}
if (!Allocations.TryGetValue(gearKey, out var value))
{
value = new Dictionary<string, int>(StringComparer.Ordinal);
Allocations[gearKey] = value;
}
value.TryGetValue(statId, out var value2);
value[statId] = value2 + 1;
Save();
return true;
}
public static bool TryRemovePoint(IUpgradable gear, string statId)
{
if (gear == null)
{
return false;
}
string gearKey = GetGearKey(gear);
if (string.IsNullOrEmpty(gearKey) || !Allocations.TryGetValue(gearKey, out var value))
{
return false;
}
if (!value.TryGetValue(statId, out var value2) || value2 <= 0)
{
return false;
}
value2--;
if (value2 <= 0)
{
value.Remove(statId);
}
else
{
value[statId] = value2;
}
if (value.Count == 0)
{
Allocations.Remove(gearKey);
}
Save();
return true;
}
public static void ResetGear(IUpgradable gear)
{
string gearKey = GetGearKey(gear);
if (!string.IsNullOrEmpty(gearKey) && Allocations.Remove(gearKey))
{
Save();
}
}
public static void ClampToBudget(IUpgradable gear)
{
string gearKey = GetGearKey(gear);
if (string.IsNullOrEmpty(gearKey) || !Allocations.TryGetValue(gearKey, out var value))
{
return;
}
int totalPoints = GetTotalPoints(gear);
int num = 0;
foreach (KeyValuePair<string, int> item in value)
{
num += Mathf.Max(0, item.Value);
}
if (num <= totalPoints)
{
return;
}
List<string> list = new List<string>(value.Keys);
list.Sort(StringComparer.Ordinal);
int num2 = num - totalPoints;
int num3 = list.Count - 1;
while (num3 >= 0 && num2 > 0)
{
string key = list[num3];
int num4 = value[key];
int num5 = Mathf.Min(num4, num2);
num4 -= num5;
num2 -= num5;
if (num4 <= 0)
{
value.Remove(key);
}
else
{
value[key] = num4;
}
num3--;
}
if (value.Count == 0)
{
Allocations.Remove(gearKey);
}
Save();
}
public static IReadOnlyDictionary<string, int> GetMap(string gearKey)
{
if (string.IsNullOrEmpty(gearKey) || !Allocations.TryGetValue(gearKey, out var value))
{
return EmptyMap.Instance;
}
return value;
}
private static void Parse(string text)
{
text = text.Trim();
if (text.Length < 2 || text[0] != '{')
{
return;
}
int i = 1;
while (i < text.Length)
{
SkipWs(text, ref i);
if (i >= text.Length || text[i] == '}')
{
break;
}
if (text[i] == ',')
{
i++;
continue;
}
if (!TryReadString(text, ref i, out var value))
{
break;
}
SkipWs(text, ref i);
if (i >= text.Length || text[i] != ':')
{
break;
}
i++;
SkipWs(text, ref i);
if (i >= text.Length || text[i] != '{')
{
break;
}
i++;
Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
while (i < text.Length)
{
SkipWs(text, ref i);
if (i >= text.Length || text[i] == '}')
{
i++;
break;
}
if (text[i] == ',')
{
i++;
continue;
}
if (!TryReadString(text, ref i, out var value2))
{
break;
}
SkipWs(text, ref i);
if (i >= text.Length || text[i] != ':')
{
break;
}
i++;
SkipWs(text, ref i);
if (!TryReadInt(text, ref i, out var value3))
{
break;
}
if (value3 > 0)
{
dictionary[value2] = value3;
}
}
if (dictionary.Count > 0)
{
Allocations[value] = dictionary;
}
}
}
private static string Serialize()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("{\n");
bool flag = true;
foreach (KeyValuePair<string, Dictionary<string, int>> allocation in Allocations)
{
if (allocation.Value == null || allocation.Value.Count == 0)
{
continue;
}
if (!flag)
{
stringBuilder.Append(",\n");
}
flag = false;
stringBuilder.Append(" \"").Append(Escape(allocation.Key)).Append("\": {\n");
bool flag2 = true;
foreach (KeyValuePair<string, int> item in allocation.Value)
{
if (item.Value > 0)
{
if (!flag2)
{
stringBuilder.Append(",\n");
}
flag2 = false;
stringBuilder.Append(" \"").Append(Escape(item.Key)).Append("\": ")
.Append(item.Value);
}
}
stringBuilder.Append("\n }");
}
stringBuilder.Append("\n}\n");
return stringBuilder.ToString();
}
private static string Escape(string s)
{
return s.Replace("\\", "\\\\").Replace("\"", "\\\"");
}
private static void SkipWs(string t, ref int i)
{
while (i < t.Length && char.IsWhiteSpace(t[i]))
{
i++;
}
}
private static bool TryReadString(string t, ref int i, out string value)
{
value = null;
SkipWs(t, ref i);
if (i >= t.Length || t[i] != '"')
{
return false;
}
i++;
StringBuilder stringBuilder = new StringBuilder();
while (i < t.Length)
{
char c = t[i++];
if (c == '\\' && i < t.Length)
{
stringBuilder.Append(t[i++]);
continue;
}
if (c == '"')
{
value = stringBuilder.ToString();
return true;
}
stringBuilder.Append(c);
}
return false;
}
private static bool TryReadInt(string t, ref int i, out int value)
{
value = 0;
SkipWs(t, ref i);
int num = i;
if (i < t.Length && t[i] == '-')
{
i++;
}
while (i < t.Length && char.IsDigit(t[i]))
{
i++;
}
if (i == num || (i == num + 1 && t[num] == '-'))
{
return false;
}
return int.TryParse(t.Substring(num, i - num), out value);
}
}
public static class StatAllocationWindow
{
private sealed class Row
{
public StatDef Def;
public RectTransform RowRt;
public UIText Label;
public UIText Value;
public UIButton Minus;
public UIButton Plus;
}
private static UIWindow _window;
private static UIText _header;
private static IUpgradable _gear;
private static readonly List<Row> Rows = new List<Row>();
private static bool _pendingLayout;
public static void Open(IUpgradable gear)
{
if (gear != null)
{
_gear = gear;
StatAllocationStore.ClampToBudget(gear);
EnsureWindow();
UIWindow window = _window;
GearInfo info = gear.Info;
window.WithTitle((((info != null) ? info.Name : null) ?? "Gear") + " — Level Stats");
_window.Show();
Rebuild();
ForceFullLayout();
_pendingLayout = true;
}
}
public static void Tick()
{
if (_window == null || !_window.IsVisible)
{
return;
}
if (!GearActionBar.IsGearMenuOpen())
{
_window.Hide(true);
return;
}
if (_pendingLayout)
{
_pendingLayout = false;
ForceFullLayout();
RefreshAllRows();
}
RefreshHeader();
}
public static void DestroyUi()
{
try
{
UIWindow window = _window;
if (window != null)
{
window.Destroy();
}
}
catch
{
}
_window = null;
_header = null;
Rows.Clear();
_gear = null;
_pendingLayout = false;
}
private static void EnsureWindow()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
if (_window == null)
{
_window = UIWindow.Create("LevelStatRewards", (Vector2?)new Vector2(560f, 640f), "Level Stats", true, true, (int?)5200);
_window.OnClose((Action)delegate
{
});
}
}
private static void Rebuild()
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Expected O, but got Unknown
Transform content = _window.Content;
UIHelpers.DestroyChildren(content);
Rows.Clear();
EnsureContentLayout(content);
_header = UIText.Create(content, "Header", "", UITheme.ScaledFontBody, (Color?)UIColors.TextSecondary, (TextAlignmentOptions)514, true);
GameObject gameObject = _header.GameObject;
float? num = UITheme.S(72f);
float? num2 = UITheme.S(56f);
UIHelpers.EnsureLayoutElement(gameObject, (float?)null, num, num2);
UIWindow.CreateSectionHeader(content, "Stats");
foreach (StatDef item in StatDefinitions.ForGear(_gear))
{
Rows.Add(CreateRow(content, item));
}
RectTransform obj = UIFactory.CreateRect("Footer", content);
GameObject gameObject2 = ((Component)obj).gameObject;
num2 = UITheme.S(44f);
num = UITheme.S(40f);
UIHelpers.EnsureLayoutElement(gameObject2, (float?)null, num2, num);
UIFactory.AddHorizontalLayout(((Component)obj).gameObject, UITheme.S(8f), new RectOffset(0, 0, 4, 4), (TextAnchor)4, false, false, true, false);
UIButton.Create((Transform)(object)obj, "Reset All", (Action)OnReset, (UIButtonStyle)2, (string)null, (float?)UITheme.S(32f)).SetWidth(UITheme.S(120f));
UIButton.Create((Transform)(object)obj, "Close", (Action)delegate
{
_window.Hide(true);
}, (UIButtonStyle)0, (string)null, (float?)UITheme.S(32f)).SetWidth(UITheme.S(100f));
RefreshAllRows();
}
private static void EnsureContentLayout(Transform content)
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Expected O, but got Unknown
if (!((Object)(object)content == (Object)null))
{
VerticalLayoutGroup val = ((Component)content).GetComponent<VerticalLayoutGroup>();
if ((Object)(object)val == (Object)null)
{
val = ((Component)content).gameObject.AddComponent<VerticalLayoutGroup>();
((HorizontalOrVerticalLayoutGroup)val).spacing = UITheme.S(6f);
((LayoutGroup)val).padding = new RectOffset(4, 4, 4, 4);
}
((LayoutGroup)val).childAlignment = (TextAnchor)1;
((HorizontalOrVerticalLayoutGroup)val).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)val).childControlWidth = true;
((HorizontalOrVerticalLayoutGroup)val).childForceExpandHeight = false;
((HorizontalOrVerticalLayoutGroup)val).childForceExpandWidth = true;
ContentSizeFitter val2 = ((Component)content).GetComponent<ContentSizeFitter>();
if ((Object)(object)val2 == (Object)null)
{
val2 = ((Component)content).gameObject.AddComponent<ContentSizeFitter>();
}
val2.horizontalFit = (FitMode)0;
val2.verticalFit = (FitMode)2;
}
}
private static Row CreateRow(Transform parent, StatDef def)
{
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Expected O, but got Unknown
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
RectTransform val = UIFactory.CreateRect("Row_" + def.Id, parent);
GameObject gameObject = ((Component)val).gameObject;
float? num = UITheme.S(40f);
float? num2 = UITheme.S(36f);
UIHelpers.EnsureLayoutElement(gameObject, (float?)null, num, num2);
((HorizontalOrVerticalLayoutGroup)UIFactory.AddHorizontalLayout(((Component)val).gameObject, UITheme.S(6f), new RectOffset(4, 4, 2, 2), (TextAnchor)3, true, false, true, false)).childForceExpandWidth = false;
Image obj = ((Component)val).gameObject.AddComponent<Image>();
((Graphic)obj).color = UIColors.WithAlpha(UIColors.PanelBg, 0.35f);
UIFactory.ApplyWhiteSprite(obj);
((Graphic)obj).raycastTarget = false;
UIText val2 = UIText.Create((Transform)(object)val, "Label", def.Label, UITheme.ScaledFontBody, (Color?)UIColors.TextPrimary, (TextAlignmentOptions)513, false);
LayoutElement obj2 = UIHelpers.EnsureLayoutElement(val2.GameObject, (float?)UITheme.S(180f), (float?)null, (float?)null);
obj2.flexibleWidth = 1f;
obj2.minWidth = UITheme.S(100f);
UIText val3 = UIText.Create((Transform)(object)val, "Value", "0", UITheme.ScaledFontBody, (Color?)UIColors.Sky, (TextAlignmentOptions)514, false);
LayoutElement obj3 = UIHelpers.EnsureLayoutElement(val3.GameObject, (float?)UITheme.S(130f), (float?)null, (float?)null);
obj3.minWidth = UITheme.S(100f);
obj3.flexibleWidth = 0f;
float num3 = UITheme.S(28f);
float width = UITheme.S(40f);
UIButton val4 = UIButton.Create((Transform)(object)val, "-", (Action)null, (UIButtonStyle)0, (string)null, (float?)num3);
ConfigureFixedButton(val4, width, num3);
UIButton val5 = UIButton.Create((Transform)(object)val, "+", (Action)null, (UIButtonStyle)1, (string)null, (float?)num3);
ConfigureFixedButton(val5, width, num3);
Row row = new Row
{
Def = def,
RowRt = val,
Label = val2,
Value = val3,
Minus = val4,
Plus = val5
};
val4.OnClick((Action)delegate
{
OnMinus(row);
});
val5.OnClick((Action)delegate
{
OnPlus(row);
});
return row;
}
private static void ConfigureFixedButton(UIButton btn, float width, float height)
{
if (btn != null)
{
btn.SetWidth(width);
LayoutElement obj = UIHelpers.EnsureLayoutElement(btn.GameObject, (float?)width, (float?)height, (float?)height);
obj.minWidth = width;
obj.flexibleWidth = 0f;
obj.flexibleHeight = 0f;
if ((Object)(object)btn.Rect != (Object)null)
{
btn.Rect.SetSizeWithCurrentAnchors((Axis)0, width);
btn.Rect.SetSizeWithCurrentAnchors((Axis)1, height);
}
btn.SetInteractable(true);
btn.ApplyVisualState();
btn.SetActive(true);
}
}
private static void ForceFullLayout()
{
try
{
Canvas.ForceUpdateCanvases();
UIWindow window = _window;
Transform obj = ((window != null) ? window.Content : null);
RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
if (val != null)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(val);
foreach (Row row in Rows)
{
if ((Object)(object)row?.RowRt != (Object)null)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(row.RowRt);
}
}
LayoutRebuilder.ForceRebuildLayoutImmediate(val);
}
UIWindow window2 = _window;
object obj2;
if (window2 == null)
{
obj2 = null;
}
else
{
UIScrollView scrollView = window2.ScrollView;
obj2 = ((scrollView != null) ? scrollView.Rect : null);
}
if ((Object)obj2 != (Object)null)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(_window.ScrollView.Rect);
}
Canvas.ForceUpdateCanvases();
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogDebug((object)("ForceFullLayout: " + ex.Message));
}
}
}
private static void OnPlus(Row row)
{
if (_gear != null && row?.Def != null && StatAllocationStore.TryAddPoint(_gear, row.Def.Id))
{
AfterChange();
}
}
private static void OnMinus(Row row)
{
if (_gear != null && row?.Def != null && StatAllocationStore.TryRemovePoint(_gear, row.Def.Id))
{
AfterChange();
}
}
private static void OnReset()
{
if (_gear != null)
{
StatAllocationStore.ResetGear(_gear);
AfterChange();
}
}
private static void AfterChange()
{
RefreshAllRows();
try
{
StatApplier.RefreshAll();
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("Refresh after allocate: " + ex.Message));
}
}
}
private static void RefreshHeader()
{
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
if (_header != null && _gear != null)
{
int gearLevel = StatAllocationStore.GetGearLevel(_gear);
int totalPoints = StatAllocationStore.GetTotalPoints(_gear);
int spent = StatAllocationStore.GetSpent(StatAllocationStore.GetGearKey(_gear));
int num = Mathf.Max(0, totalPoints - spent);
_header.Text = $"Level {gearLevel} · {totalPoints}/{10} points " + $"(1 per {3} lv, cap {30})\n" + $"Spent {spent} · Unspent {num}";
_header.Color = ((num > 0) ? UIColors.Shamrock : UIColors.TextSecondary);
}
}
private static void RefreshAllRows()
{
//IL_00c9: 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)
RefreshHeader();
if (_gear == null)
{
return;
}
string gearKey = StatAllocationStore.GetGearKey(_gear);
int unspent = StatAllocationStore.GetUnspent(_gear);
foreach (Row row in Rows)
{
if (row?.Def != null)
{
int points = StatAllocationStore.GetPoints(gearKey, row.Def.Id);
float num = row.Def.GetPercentPerPoint() * (float)points;
string arg = ((num >= 0f) ? "+" : "");
row.Value.Text = ((points == 0) ? "0 pts" : $"{points} pts ({arg}{num:0.#}%)");
row.Value.Color = ((points > 0) ? UIColors.Sky : UIColors.TextMuted);
UIButton minus = row.Minus;
if (minus != null)
{
minus.SetActive(true);
}
UIButton plus = row.Plus;
if (plus != null)
{
plus.SetActive(true);
}
UIButton minus2 = row.Minus;
if (minus2 != null)
{
minus2.SetInteractable(points > 0);
}
UIButton plus2 = row.Plus;
if (plus2 != null)
{
plus2.SetInteractable(unspent > 0);
}
UIButton minus3 = row.Minus;
if (minus3 != null)
{
minus3.ApplyVisualState();
}
UIButton plus3 = row.Plus;
if (plus3 != null)
{
plus3.ApplyVisualState();
}
}
}
}
}
public static class StatApplier
{
[HarmonyPatch(typeof(Player), "ApplyUpgrades")]
private static class PlayerApplyUpgrades_Patch
{
private static void Postfix(Player __instance)
{
if (!((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner)
{
ApplyToPlayer(__instance);
}
}
}
[HarmonyPatch(typeof(Gun), "OnUpgradesEnabled")]
private static class GunOnUpgradesEnabled_Patch
{
private static void Postfix(Gun __instance)
{
ApplyToGear((IGear)(object)__instance);
}
}
[HarmonyPatch(typeof(Throwable), "OnUpgradesEnabled")]
private static class ThrowableOnUpgradesEnabled_Patch
{
private static void Postfix(Throwable __instance)
{
ApplyToGear((IGear)(object)__instance);
}
}
private static FieldInfo _playerMoveSpeed;
private static FieldInfo _playerSlideSpeed;
private static FieldInfo _playerFullSlideDuration;
private static FieldInfo _playerMaxHealth;
private static FieldInfo _throwableCooldownData;
private static bool _fieldsResolved;
public static void RefreshAll()
{
try
{
if ((Object)(object)Player.LocalPlayer != (Object)null && ((NetworkBehaviour)Player.LocalPlayer).IsOwner)
{
Player.LocalPlayer.ApplyUpgrades(true);
}
if (!((Object)(object)Player.LocalPlayer == (Object)null))
{
TryRefreshPlayerGear(Player.LocalPlayer);
}
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("RefreshAll failed: " + ex.Message));
}
}
}
private static void TryRefreshPlayerGear(Player player)
{
try
{
PropertyInfo propertyInfo = AccessTools.Property(typeof(Player), "Gear");
object obj = null;
if (propertyInfo != null)
{
obj = propertyInfo.GetValue(player);
}
else
{
FieldInfo fieldInfo = AccessTools.Field(typeof(Player), "Gear");
if (fieldInfo != null)
{
obj = fieldInfo.GetValue(player);
}
}
if (obj is IGear[] array)
{
IGear[] array2 = array;
for (int i = 0; i < array2.Length; i++)
{
SafeApplyGear(array2[i]);
}
}
else
{
if (!(obj is IList<IGear> list))
{
return;
}
{
foreach (IGear item in list)
{
SafeApplyGear(item);
}
return;
}
}
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogDebug((object)("TryRefreshPlayerGear: " + ex.Message));
}
}
}
private static void SafeApplyGear(IGear gear)
{
if (gear == null)
{
return;
}
try
{
gear.ApplyUpgrades();
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogDebug((object)("ApplyUpgrades gear failed: " + ex.Message));
}
}
}
public static void ApplyToPlayer(Player player)
{
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
//IL_024c: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)player == (Object)null || !((NetworkBehaviour)player).IsOwner)
{
return;
}
Character character = player.Character;
if ((Object)(object)character == (Object)null)
{
return;
}
StatAllocationStore.ClampToBudget((IUpgradable)(object)character);
string gearKey = StatAllocationStore.GetGearKey((IUpgradable)(object)character);
if (string.IsNullOrEmpty(gearKey))
{
return;
}
EnsurePlayerFields();
int points = StatAllocationStore.GetPoints(gearKey, "run_speed");
int points2 = StatAllocationStore.GetPoints(gearKey, "slide_speed");
int points3 = StatAllocationStore.GetPoints(gearKey, "slide_duration");
int points4 = StatAllocationStore.GetPoints(gearKey, "max_health");
int points5 = StatAllocationStore.GetPoints(gearKey, "regen_delay");
int points6 = StatAllocationStore.GetPoints(gearKey, "healing");
if (points + points2 + points3 + points4 + points5 + points6 <= 0)
{
return;
}
try
{
if (points > 0 && _playerMoveSpeed != null)
{
float num = (float)_playerMoveSpeed.GetValue(player);
_playerMoveSpeed.SetValue(player, num * StatDefinitions.Find("run_speed").MultiplierForPoints(points));
}
if (points2 > 0 && _playerSlideSpeed != null)
{
float num2 = (float)_playerSlideSpeed.GetValue(player);
_playerSlideSpeed.SetValue(player, num2 * StatDefinitions.Find("slide_speed").MultiplierForPoints(points2));
}
if (points3 > 0 && _playerFullSlideDuration != null)
{
float num3 = (float)_playerFullSlideDuration.GetValue(player);
_playerFullSlideDuration.SetValue(player, num3 * StatDefinitions.Find("slide_duration").MultiplierForPoints(points3));
}
if (points4 > 0)
{
float num4 = StatDefinitions.Find("max_health").MultiplierForPoints(points4);
if (_playerMaxHealth != null)
{
float num5 = (float)_playerMaxHealth.GetValue(player) * num4;
_playerMaxHealth.SetValue(player, num5);
try
{
player.SetMaxHealth(num5);
}
catch
{
}
}
}
FieldInfo fieldInfo = AccessTools.Field(typeof(Player), "upgradeVariables");
if (fieldInfo != null)
{
UpgradeVariableData val = (UpgradeVariableData)fieldInfo.GetValue(player);
bool flag = false;
if (points5 > 0)
{
val.noDamageTimeBeforeHealthRegen *= StatDefinitions.Find("regen_delay").MultiplierForPoints(points5);
flag = true;
}
if (points6 > 0)
{
val.healingMultiplier *= StatDefinitions.Find("healing").MultiplierForPoints(points6);
flag = true;
}
if (flag)
{
fieldInfo.SetValue(player, val);
}
}
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("ApplyToPlayer failed: " + ex.Message));
}
}
}
public static void ApplyToGear(IGear gear)
{
if (gear == null)
{
return;
}
object gear2 = ((object)((IUpgradable)gear).Prefab) ?? ((object)gear);
StatAllocationStore.ClampToBudget((IUpgradable)gear2);
string gearKey = StatAllocationStore.GetGearKey((IUpgradable)gear2);
if (string.IsNullOrEmpty(gearKey))
{
return;
}
try
{
Throwable val = (Throwable)(object)((gear is Throwable) ? gear : null);
if (val != null)
{
ApplyThrowable(val, gearKey);
return;
}
IWeapon val2 = (IWeapon)(object)((gear is IWeapon) ? gear : null);
if (val2 != null)
{
ApplyWeapon(val2, gearKey);
}
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("ApplyToGear failed: " + ex.Message));
}
}
}
private static void ApplyWeapon(IWeapon weapon, string key)
{
//IL_0107: 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_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: 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_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
int points = StatAllocationStore.GetPoints(key, "reload");
int points2 = StatAllocationStore.GetPoints(key, "magazine");
int points3 = StatAllocationStore.GetPoints(key, "ammo_capacity");
int points4 = StatAllocationStore.GetPoints(key, "recoil");
int points5 = StatAllocationStore.GetPoints(key, "spread");
if (points + points2 + points3 + points4 + points5 > 0)
{
ref GunData gunData = ref weapon.GunData;
if (points > 0)
{
gunData.reloadDuration *= StatDefinitions.Find("reload").MultiplierForPoints(points);
}
if (points2 > 0)
{
float num = StatDefinitions.Find("magazine").MultiplierForPoints(points2);
gunData.magazineSize = Mathf.Max(1, Mathf.RoundToInt((float)gunData.magazineSize * num));
}
if (points3 > 0 && gunData.hasLimitedAmmo)
{
float num2 = StatDefinitions.Find("ammo_capacity").MultiplierForPoints(points3);
gunData.ammoCapacity = Mathf.Max(0, Mathf.RoundToInt((float)gunData.ammoCapacity * num2));
}
if (points4 > 0)
{
float num3 = StatDefinitions.Find("recoil").MultiplierForPoints(points4);
ref Vector2 recoilX = ref gunData.recoilData.recoilX;
recoilX *= num3;
ref Vector2 recoilY = ref gunData.recoilData.recoilY;
recoilY *= num3;
ref Vector2 recoilZ = ref gunData.recoilData.recoilZ;
recoilZ *= num3;
ref Vector2 translateZ = ref gunData.recoilData.translateZ;
translateZ *= num3;
gunData.recoilData.maxRecoilZ *= num3;
gunData.recoilData.maxTranslateZ *= num3;
}
if (points5 > 0)
{
float num4 = StatDefinitions.Find("spread").MultiplierForPoints(points5);
ref Vector2 spreadSize = ref gunData.spreadData.spreadSize;
spreadSize *= num4;
gunData.firstShotSpreadMultiplier *= num4;
}
}
}
private static void ApplyThrowable(Throwable throwable, string key)
{
//IL_0099: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
int points = StatAllocationStore.GetPoints(key, "grenade_damage");
int points2 = StatAllocationStore.GetPoints(key, "grenade_cooldown");
int points3 = StatAllocationStore.GetPoints(key, "explosion_radius");
if (points + points2 + points3 <= 0)
{
return;
}
if (throwable != null)
{
ref GunData gunData = ref ((IWeapon)throwable).GunData;
if (points > 0)
{
gunData.damage *= StatDefinitions.Find("grenade_damage").MultiplierForPoints(points);
}
if (points3 > 0)
{
gunData.hitForce *= StatDefinitions.Find("explosion_radius").MultiplierForPoints(points3);
}
}
if (points2 <= 0)
{
return;
}
EnsureCooldownField();
if (!(_throwableCooldownData != null))
{
return;
}
try
{
CooldownData val = (CooldownData)_throwableCooldownData.GetValue(throwable);
float num = StatDefinitions.Find("grenade_cooldown").MultiplierForPoints(points2);
val.rechargeDuration *= num;
_throwableCooldownData.SetValue(throwable, val);
}
catch (Exception ex)
{
ManualLogSource log = LevelStatRewardsPlugin.Log;
if (log != null)
{
log.LogDebug((object)("Cooldown apply: " + ex.Message));
}
}
}
private static void EnsurePlayerFields()
{
if (!_fieldsResolved)
{
_fieldsResolved = true;
_playerMoveSpeed = AccessTools.Field(typeof(Player), "moveSpeed");
_playerSlideSpeed = AccessTools.Field(typeof(Player), "slideSpeed");
_playerFullSlideDuration = AccessTools.Field(typeof(Player), "fullSlideDuration");
_playerMaxHealth = AccessTools.Field(typeof(Player), "maxHealth");
}
}
private static void EnsureCooldownField()
{
if (!(_throwableCooldownData != null))
{
_throwableCooldownData = AccessTools.Field(typeof(Throwable), "cooldownData");
}
}
}
public enum StatCategory
{
Employee,
Weapon,
Grenade
}
public sealed class StatDef
{
public string Id { get; }
public string Label { get; }
public StatCategory Category { get; }
public float PercentPerPoint { get; }
public bool InvertDisplay { get; }
public StatDef(string id, string label, StatCategory category, float percentPerPoint, bool invertDisplay = false)
{
Id = id;
Label = label;
Category = category;
PercentPerPoint = percentPerPoint;
InvertDisplay = invertDisplay;
}
public float GetPercentPerPoint()
{
return PercentPerPoint;
}
public float MultiplierForPoints(int points)
{
if (points <= 0)
{
return 1f;
}
return 1f + PercentPerPoint / 100f * (float)points;
}
}
public static class StatDefinitions
{
public const string RunSpeed = "run_speed";
public const string SlideSpeed = "slide_speed";
public const string SlideDuration = "slide_duration";
public const string MaxHealth = "max_health";
public const string RegenDelay = "regen_delay";
public const string Healing = "healing";
public const string Reload = "reload";
public const string Magazine = "magazine";
public const string AmmoCapacity = "ammo_capacity";
public const string Recoil = "recoil";
public const string Spread = "spread";
public const string GrenadeDamage = "grenade_damage";
public const string GrenadeCooldown = "grenade_cooldown";
public const string ExplosionRadius = "explosion_radius";
private const float P = 10f;
private const float N = -10f;
public static readonly StatDef[] Employee = new StatDef[6]
{
new StatDef("run_speed", "Run Speed", StatCategory.Employee, 10f),
new StatDef("slide_speed", "Slide Speed", StatCategory.Employee, 10f),
new StatDef("slide_duration", "Slide Duration", StatCategory.Employee, 10f),
new StatDef("max_health", "Max Health", StatCategory.Employee, 10f),
new StatDef("regen_delay", "Health Regen Delay", StatCategory.Employee, -10f, invertDisplay: true),
new StatDef("healing", "Healing Received", StatCategory.Employee, 10f)
};
public static readonly StatDef[] Weapon = new StatDef[5]
{
new StatDef("reload", "Reload Speed", StatCategory.Weapon, -10f, invertDisplay: true),
new StatDef("magazine", "Magazine Size", StatCategory.Weapon, 10f),
new StatDef("ammo_capacity", "Ammo Capacity", StatCategory.Weapon, 10f),
new StatDef("recoil", "Recoil", StatCategory.Weapon, -10f, invertDisplay: true),
new StatDef("spread", "Spread", StatCategory.Weapon, -10f, invertDisplay: true)
};
public static readonly StatDef[] Grenade = new StatDef[3]
{
new StatDef("grenade_damage", "Damage", StatCategory.Grenade, 10f),
new StatDef("grenade_cooldown", "Cooldown", StatCategory.Grenade, -10f, invertDisplay: true),
new StatDef("explosion_radius", "Explosion Radius", StatCategory.Grenade, 10f)
};
public static IReadOnlyList<StatDef> ForGear(IUpgradable gear)
{
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Invalid comparison between Unknown and I4
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Invalid comparison between Unknown and I4
if (gear == null)
{
return Array.Empty<StatDef>();
}
if (gear is Character)
{
return Employee;
}
if (gear is Throwable || gear is GrenadeGear)
{
return Grenade;
}
if (gear is IWeapon || gear is Gun)
{
return Weapon;
}
try
{
GearType gearType = gear.GearType;
if ((int)gearType != 3)
{
if ((int)gearType == 5)
{
return Employee;
}
return Weapon;
}
return Grenade;
}
catch
{
return Weapon;
}
}
public static StatDef Find(string id)
{
StatDef[] employee = Employee;
foreach (StatDef statDef in employee)
{
if (statDef.Id == id)
{
return statDef;
}
}
employee = Weapon;
foreach (StatDef statDef2 in employee)
{
if (statDef2.Id == id)
{
return statDef2;
}
}
employee = Grenade;
foreach (StatDef statDef3 in employee)
{
if (statDef3.Id == id)
{
return statDef3;
}
}
return null;
}
}
namespace LevelStatRewards
{
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "LevelStatRewards";
public const string PLUGIN_NAME = "LevelStatRewards";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}